Обновить
2
0
Татарков Михаил@herodream

Даю знания для работы middle/senior Кратко|Понятно

Отправить сообщение

Сделал заголовки, читать стало приятнее 👍. Почему-то в редакторе хабра при редактировании статьи требуется добавить строку, нажать del, ввести пробел, вставить текст заголовка, удалить пробел. Иначе форматирование - обычный текст.

Про стиль благодарю за подсказку, поставил вам плюс.

По ошибке уточните, не нашел:

К примеру, в Postgresql дефолтный уровень - read committed, а не read uncommitted, как написано у вас

Вы про это место? Read committed, в статье все верно:

Read committed - Чтение зафиксированных данных.

Уровень изоляции “по умолчанию” для СУБД: MS SQL, PostgreSQL, Oracle

Возможно не внимательно прочитали. Возможно сыграло "у опытных читателей доверия становится меньше".

Если б gpt не врал и мог описать практично без воды. Возможно вы так умеете, я нет. Для набрасывания контента по своим тезисам - использую, но затем чищу и выверяю факты, добавляя опыт. На написание и проверку уходит дня 2 чистого времени. Затем рецензия от знакомых сеньоров, мидлов. Статья должна быть качественная и применимая на практике.

Причем здесь оптимизация? Оптимизация, в нашем контексте - это сокращение потребления ресурсов без потери функциональности, например процессора и памяти. Какое к этому имеют отношение создание каких то интерфейсов?

Соблюдение SOLID влечет увеличение расходов памяти, процессора. Сокращает время на изменение кода и ревью кода. Изменился алгоритм расчета ЗП - изменен класс расчета ЗП. Изменился набор данных для расчета ЗП - модифицируем еще класс для получения данных из БД.

Дели большие интерфейсы на маленькие и специализированные.

Пусть будет так. А где правило согласно которого мы определяем что такое большие а что такое маленькие интерфейсы? Без этого правила принцип - это красивый и бесполезный набор слов.

Правило: "Интерфейсы — как меню: отлично, когда содержат только то, что нужно.". По OCP если класс использует 1 метод другого класса, то нужно выделить "меню\интерфейс" из одного метода.

Добавляй новую функциональность через новые классы/методы не меняя старые.

А если нужно поменять старые?

⚖️ Их меняют, но при этом возникают риски поломать функционал.

Представьте, вы используете opensource библиотеку:

Сделана по SOLID → заменили зависимость, задокументировали и радуетесь.

Если нет → скачиваете репозиторий, меняете, отправляете пулреквест, ждете когда примут изменения, если вообще примут. В это время распространяете в своей команде новую версию библиотеки, дублирующую изначальную. Что порождает трудозатраты, временные затраты и увеличивает риски.

Насчет пользы SOLID приведу примеры.

→   Есть класс расчета ЗП, если его реализацию нужно менять и при смене логики расчета и при смене запросов к БД - принцип SRP нарушен. По SRP класс-обертка на БД должен быть вынесен.

→   Класс, обеспечивающий доступ к таблицам БД, может работать с несколькими таблицами и иметь несколько интерфейсов. Например для CRUD и для получения отчетности по ЗП. Так будет соблюден OCP. Интерфейсы будут использовать разные классы бизнес логики. Так проще понять код, сделать ревью коммита.

Для одной и той же задачи можно получить классы с разным кодом, интерфейсами. Детерминированного критерия "Какую единственную задачу должен решать класс"/"Какую причину для изменения будет иметь класс" - нет, это проектное решение. SOLID говорит, что причина должна быть одна, какая - решаете вы.

Мои источники говорят Барбара Лисков.

https://en.wikipedia.org/wiki/Barbara_Liskov

Класс должен решать только одну проблему.

Пусть будет так. Для того чтобы это сделать нужно правило - как детерминировано определить какую единственную задачу должен решать класс. Где это правило?

→  Ваш вопрос за пределами Шпаргалки по SOLID. Он про объединения данных и кода работающего с этими данными в класс. Есть разные подходы:

1) Отражение объектов реального мира - классы имитируют (отражают) реальные объекты. Странно, когда человек имеет функцию распечатать, а вот секретарь может иметь такую функцию.

2) Договоренности команды, терминологический словарь.

3) Статистический - если данные и код встречаются вместе, то стоит их выделить в класс, скорей всего вы позже поймете что это за объект и назовете его (Рефакторинг, выделение граничного объекта Мартин Фаулер).

💡 Важно, чтобы меньше дискуссий возникало в команде опираться на знакомые определения и фиксировать их в документации. Слово "Клиент" в коде может значить разное: посетителя в офлайн магазине или покупателя на сайте. От этого иметь разные данные и код. Клиент может быть программа вызывающая API. Без ясности — путаница и ошибки.

Детерминированного критерия не существует. В команде можно спокойно договориться построить "Дом в верх дном". И команде будет понятно. Просто для новых участников и остального мира код будет странно и не понятно.

Интересные вопросы. Предлагаю разделить их на отдельные треды, чтоб можно было точно понимать, что обсуждаем. Также сегодня уезжаю на неделю в горы, буду отвечать по мере возможностей.

Благодарю за предложение, действительно возможны разные трактовки. В определения что такое задача, что такое одна ответственность или зона ответственности для краткости не хочу идти. Замечание считаю важным, поправил.

Предлагаю не давать пример читателю нарушения DRY и переписать код

       public AccountManagementController()
          :this(
             OrderManagerFactory.GetOrderManager(),
             UserManagerFactory.Get()
        )
        {
        }

        /// <summary>
        /// For testability
        /// </summary>
        /// <param name="accountData"></param>
        /// <param name="userManager"></param>
        public AccountManagementController(
            IAccountData accountData,
            IUserManager userManager)
        {
            _accountData = accountData;
            _userManager = userManager;
            _disabledAccountsFilter = new FilterParam("Enabled", Expression.Eq, true);
        }
С серьезным покрытием. Все тесты проходят.
...
Система надежно протестирована и сама рассказывает о себе путем тестов.

Думаю больше чем тесты важно бизнес-описание системы, какую ценность она приносит. И часто по проверкам функциональности нельзя точно восстановить почему сделано так, а зная бизнес-цель уже легче. В том числе написать с нуля. Документация и тесты не исключают, а дополняют друг друга. Имея только тесты придется восстанавливать бизнес-правила по ним и коду, догадываясь что здесь имелось в виду и что в бизнесе за этим скрывается.
Думаю 2 и 5 являются блоком arrange

class CalculatorTests
{
	public void Sum_2Plus5_7Returned()
	{
		// arrange
		var calc = new Calculator();
                var arg1 = 2;
                var arg2 = 5;
	
		// act
		var res = calc.Sum(arg1, arg2);

		// assert
		Assert.AreEqual(7, res);	
	}
}

Возможно для данного примера это излишне, но когда в метод передается объект в определенном состоянии, он будет предварительно дан, как и 2 и 5 по идее результаты предварительных вычислений.
Посмотрите внимательно 1-ый случай

1) Если группы равны, то фальшивая монета находится в третьей группе. Необходимо найти фальшивую монету из 4 монет за два взвешивания.

image
Авторское, но все хорошее изобретено до нас. Друзья сказали что подобные правила есть в «Совершенном» или в «Чистом» коде. Возможно видели там.
Решения имеют свои + и -. Это не догма. Если цель упростить за счет снижения уровня вложенности — return помогает. Если нет условий, которые можно явно отделить, лучше один return.
Если вы про второе правило, то в коде должен присутствоват возврат управления, например return.
1

Информация

В рейтинге
Не участвует
Откуда
Россия
Зарегистрирован
Активность

Специализация

Технический директор, Архитектор программного обеспечения
Старший