Прошу помощи с пониманием single responsibility principle на примере метода и класса

  1. Есть метод, который возвращает лист с именами csv файлов, найденных в папке с программой:

     public static List<string> GetListOfTables()
     {
         var tables = new List<string>();
    
         do
         {
             tables = Directory.GetFiles(".", "*.csv").Select(file => Path.GetFileName(file)).ToList();
    
             if (tables.Count == 0)
             {
                 Output.Invoke("\nNo .csv files are found, " +
                     "please put a table csv file in the program folder and press <Enter> to continue");
    
                 while (Console.ReadKey(true).Key != ConsoleKey.Enter) { }
             }
         }
         while (tables.Count == 0);
    
         return tables;
     }
    

В нем встроенна валидация (вместо исключения), что если файлов не найдено, юзеру нужно скопировать файл в папку и нажать на клавишу.

У данного метода единственная отвественность (в итоге возвращает лист, а проверка - это всего лишь проверка) или множественная (возвращает лист и проверяет корректность действий пользователя)?

Ведь можно создать отдельный метод ValidationCsvFiles с блоком проверки и затем включить или делегировать его в основной метод?

  1. Есть класс, который возвращает лист с данными из конкретного файла
static class CsvParser
    {
        public static List<string> GetListOfTables() { }

        public static List<List<object>> GetTable(string tableName) { }
    }

У данного класса единственная ответственность (в итоге возвращает лист с данными, а лист со списком файлов - это вспомогательный инструмент) или множественная (возвращает лист с данными и лист с файлами)

Ведь лист с файлами можно реализовать в другом классе?


Ответы (1 шт):

Автор решения: Uranus

В книге "Чистая Архитектура ..." Роберт Мартин утверждает что традиционно принцип единственной ответственности описывается так:

Модуль должен иметь одну и только одну причину для изменения

Программное обеспечение изменяется для удовлетворения нужд пользователей и заинтересованных лиц. Пользователи и заинтересованные лица как раз и есть та самая "причина для изменения", о которой говорит принцип. Фактически принцип можно перефразировать так:

Модуль должен отвечать за одного и только за одного пользователя или заинтересованное лицо.

Стоит сразу оговориться что пользователь это не "ну такая тетенька которая ...". Чтобы не раздувать ответ переписыванием всей главы, рекомендую приобрести книгу и прочитать дальнейшие пояснения что подразумевается под пользователем (или актором) и модулем в данном случае.

Признаки нарушения принципа единственной ответственности по Мартину:

  • Непреднамеренное дублирование. Например, класс имеет несколько методов, в которых используются похожие фрагменты кода. Можно эти фрагменты привести к общему виду и вынести в отдельный метод, чтобы избежать дублирования. Но с другой стороны, теперь стало труднее вносить изменения в один из методов, не затрагивая другие. Это признак того, что класс возможно нарушает принцип единственной ответственности. Нарушает или нет, зависит от того используются ли эти методы одним актором или многими.
  • Конфликты при слиянии рабочих веток в Git. Обычно в команде каждый человек работает над своей задачей (если конечно команда не практикует парное программирование). Если изменения двух программистов затрагивают один и тот же файл, то может возникнуть необходимость разрешать конфликты при слиянии веток. Это тоже признак того, что возможно нарушается принцип единственной ответственности.

Подытожим: принцип единственной ответственности не о том, можно ли или нет разбить модуль на еще более мелкие модули, отвечающие за еще более узкую область. Такое дробление не всегда улучшает код, а порой приводит к смешным последствиям. Таким как эта нашумевшая история: NPM и left-pad: мы разучились программировать?.

Принцип единственной ответственности о том, как избежать трудностей при изменении кода в будущем.

→ Ссылка