Я слышал выражение, что для того, чтобы стать программистом, нужно быть ленивым.
Но иногда лень в программировании приводит к ужасному техническому долгу.
В своей заметке про SRP я упоминал, что нарушение этого принципа может привести к увеличению сложности или даже умножению.
Один из моих коллег привел интересный пример, и я решил использовать его, чтобы продемонстрировать, как это выглядит.
Давайте определим, что это за избыточная сложность.
Но сначала давайте поговорим о противоположности — о сложности, возникающей из требований.
Например, есть требования рассчитывать зарплату сотрудника исходя из почасовой ставки и отработанного времени.
А, если сотрудник проработал в компании более пяти лет, начисляется премия.
Это «если» вытекает из требований, и его невозможно избежать.
В той или иной форме он станет элементом сложности кода приложения, скорее всего, в виде условного оператора «if».
Но иногда сложность исходит не из требований, а из подхода разработчика к решению проблемы.
Оператор «if», такие шаблоны, как «стратегия», полиморфные методы — это не полный список методов программирования, которые могут сдержать эту избыточную сложность.
Лично я, кстати, всегда против использования разработчиками паттернов просто потому, что они могут, а не для решения конкретной задачи.
Вот простой пример.
Это может показаться фикцией, но это не так.
Это даже не упрощенно, именно так я наткнулся на это во время ревью кода пару лет назад. В двух местах кода были вызовы одной и той же функции, но с разными логическими параметрами:
Такие конструкции всегда выглядят подозрительно и эта особенность меня не разочаровала.// first place doSomething(true); // second place doSomething(false);
Этот параметр был передан с единственной целью проверки внутри этой функции: doSomething(flag: boolean): void {
if(flag) {
// do first thing
} else {
// do second thing
}
}
Эту проверку можно описать так: «если мне позвонили из места А, делаем одно, иначе мне позвонили из места Б, делаем другое».
Этот флаг, это «если» — вот о чем вся эта заметка.
Сложность не связана с бизнес-требованиями.
Естественно, я рекомендовал изменить код следующим образом: // first place
doFirstThing();
// second place
doSecondThing();
//method is split into 2 parts each having their own responsibility
doFirstThing(): void {
// do first thing
}
doSecondThing(): void {
// do second thing
}
Всё, лишней сложности больше нет. Именно здесь разработчику следует потратить время на написание еще одной сигнатуры функции.
Здесь можно воскликнуть: «Но это всего лишь одно «если»» или: «Это нарушение очевидно, кто вообще такой код пишетЭ» И здесь на сцену выходит второй пример.
Это показывает, что увидеть нарушение может быть заметно сложнее, а также что цена этого нарушения может быть больше, чем одно «если».
Как и в первом примере, функция используется в двух местах: // first place
checkValidity(obj);
// second place
checkValidity(arrayOfObjs);
Метод, как следует из названия, проверяет достоверность объекта.
Однако не было очевидно, что он также может проверять достоверность массива объектов.
Я изменил имена переменных, чтобы подчеркнуть это нарушение.
Метод выглядит следующим образом: checkValidity(parm: MyType | MyType[]): void {
if(Array.isArray(parm)) {
parm.forEach(p => checkValidity(p));
} else {
// here the object gets checked
// and conditional exception is thrown
}
}
Вот. Одно «если» превращается в множество «если».
Если в массиве 100 объектов, то это «если» будет выполнено 101 раз.
Но на реальных данных у нас там могло быть 30 тысяч объектов, а это уже впечатляющий удар по производительности.
Очевидно, что, следуя принципу единой ответственности, этот метод необходимо реорганизовать, чтобы появилось 2 метода: checkItemsValidity(parms: MyType[]): void {
parms.forEach(p => checkItemValidity(p));
}
checkItemValidity(parm: MyType): void {
// here the object gets checked
// and conditional exception is thrown
}
Точки вызова также необходимо соответствующим образом отрегулировать.
Интересно, что примеры, которые я привел в заметке про SRP, привели к увеличению SLOC, эти же примеры, наоборот, приводят к небольшому его снижению вместе с ожидаемым улучшением качества кода.
Вот и все.
Всего пара простых примеров, демонстрирующих наиболее важные принципы хорошего кода.
Теги: #программирование #Идеальный код #солид #srp #сложность
-
Все О Asus N61 Series N61Jq-X2-08
19 Oct, 24 -
Миграция Windows Между Bios <-> Uefi
19 Oct, 24 -
Жизнь Как Услуга (Laas)?
19 Oct, 24 -
Стартовал Конкурс На Лучшие Обои
19 Oct, 24 -
Sna Hackathon 2019 – Итоги
19 Oct, 24 -
Merry Network, Или 1 Апреля В Uanet
19 Oct, 24