Не люблю, когда в операторе if производиться много проверок, даже если их отсортировали по смыслу. Даже если я знаю, что проверки отсортированы, мне все равно приходиться думать, а что каждая из них делает.
func foo (something) { if (something.isActive && something.StartDate < DateTime.Now && (something.EndDate == null || something.EndDate > DateTime.Now) && User.CurrentUser == something.Creator && canEdit(something)) { } }
Очень много проверок, которые нужно анализировать и думать – а что они делают и для чего они нужны. А если раздробить такие вещи на отдельные составляющие, то можно сделать код на много более понятным. Как минимум можно создать локальные переменные:
func foo (something) { bool isActive = something.isActive && something.StartDate < DateTime.Now && (something.EndDate == null || something.EndDate > DateTime.Now); bool hasAccess = User.CurrentUser == something.Creator && canEdit(something); if (isActive && hasAccess) { } }
Да, строчек кода получилось больше, но if стал простым и понятным, я сразу же глядя на код могу сказать, что происходит две проверки.
А можно создать свойства или методы:
bool isActive(something) { return something.isActive && something.StartDate < DateTime.Now && (something.EndDate == null || something.EndDate > DateTime.Now); } bool hasAccess(something) { return User.CurrentUser == something.Creator && canEdit(something); } func foo (something) { if (isActive(something) && hasAccess(something)) { } }
А этот код получился еще и реюзабельным. Возможно something должно быть свойством класса и тогда код будет еще чуть красивее. Все зависит от ситуации, но в любом случае такой код не нуждается в комментариях.
Я решил написать эту заметку, потому что на прошлой неделе как раз общался с программистом в команде, и он показывал, как он любит писать комментарии и показал как раз проверку, к которой он добавил комментарии:
// check if it is active and if we have access func foo (something) { if (something.isActive && something.StartDate < DateTime.Now && (something.EndDate == null || something.EndDate > DateTime.Now) && User.CurrentUser == something.Creator && canEdit(something)) { } }
И он сказал, что любит комментарии, потому что они дают понять, что происходит в проверках. А я люблю красивый код, который проще в поддержании и не нуждается в комментариях. Мой вариант как раз такой, он в комментариях не нуждается.
Понравилось? Кликни Лайк, чтобы я знал, какой контент более интересен читателям. Заметку уже лайкнули 3 человек
Выделять целую функцию под одну строку кода тоже некрасиво.
Это вызов функции, помещение значений в стэк и т.д.
Громоздкость кода увеличивается.
На мой взгляд в помещение в переменные лучше, если эти условия не переиспользуются. Если они переиспользуются, возможно можно иначе реорганизовать код, а не дергать постоянно функции, которые будут булевые значения проверять.
Ничего страшного, что вызов функции попадает в стек. Если сравнить вариант с функциями и без, то разница две строки - объявление функций. Примерно столько же я потерял когда ввел переменные. Как раз самый первый вариант - это громосткость кода, потому что слишком много кода на одну функцию.
Конечно лучше избавиться от всех этих вложенных проверок. Этой теме Роберт Мартин в своей книге о чистом коде уделяет много места.
И да, выделять целую функцию под одну строчку - это тоже нормально, а в некоторых случаях - почти обязательно для удобочитаемости кода. Например, в одной из старых версий Navision очень мало встроенных средств для форматирования даты. Например, нет даже готовой функции (или параметра), чтобы результат функции TODAY() сразу получить в формате ГГГГММДД. Приходится колхозить в т. ч. и преобразованием через строку. Зачем этот колхоз в общем коде светить?
Хотите найти еще что-то интересное почитать? Можно попробовать отфильтровать заметки на блоге по категориям.