По-задълбочени прозрения за това, което научих за добрите и лошите условни изрази и как

Един ден, когато партньорски разработчик на софтуер дойде при мен и ме попита дали искам да реша ката, нямах представа какво е ката - поне името звучеше доста готино и вероятно щях да науча нещо. Така че отговорът ми беше: „разбира се!“.

Задачата за ката се отнасяше изцяло за мъж на име Боб, който не е от най-красноречивите. Така че в разговорите отговорите му обикновено са много ограничени. Той отговаря с:

„Пич, успокой се!“ – ако му се извика
„Разбира се.“ – ако го попитат нещо
„Спокойно, знам какво правя!“ – ако някой извика въпрос
br /> „Добре, тогава нека мълчим.“ – ако другият не казва нищо
„Каквото и да е.“ – в противен случай

Тази ката дойде заедно с модулни тестове, така че единствената ми работа ще бъде да внедря метода Отговор. Задачата не изглеждаше много трудна, но тогава моят колега добави неочаквано ограничение:

„Решението трябва да избягва всякакви условни изрази.“

Целта на това ограничение не ми стана ясна веднага, но обичам предизвикателствата, какво от това?

Не ако изявления? Няма изявления за превключване? Възможно ли е изобщо това?

Много въпроси кръжаха в претоварения ми мозък, когато моето любопитно аз седна и започна да се изправя пред предизвикателството. Бързо разбрах, че е по-трудно от очакваното и след известно разочарование първата ми мисъл беше: „По дяволите, той ме измами, трябва да използвам троичния оператор“. За съжаление и това не беше разрешено. Бях объркан и не знаех какво да правя по-нататък; какво хубаво време за кафе.

След като не успях да разреша проблема с избягването на условни изрази, поне исках да го направя с тях. Така че първото ми решение изглеждаше така:

Дори ако решаването на задачата с помощта на условни изрази не беше желаното решение, то поне беше бърз и лесен начин да получите по-задълбочено разбиране на изискванията и зелените тестове на единици.

Накрая, след като помислих допълнително и прочетох нещо за полиморфизма (и пих повече кафе), стигнах до следното решение, което не изисква никакво използване на (самостоятелно написани) условни изрази:

Новото решение изисква повече редове и някакъв шаблонен код за различните класове Отговори. Въпреки това, това е по-чист и по-мащабируем подход поради следните причини:

  1. Добавянето на повече възможни отговори към първото решение би раздуло метода Отговор. Разбира се, че е възможно кодът да се намали частично чрез методи за влагане, но има и други бързи причини.
  2. Класът Bobна първото решение зависи от промените в текстовете на отговорите. Това е знак за лош дизайн, тъй като класът трябва да знае само класовете Answer, а не каквито и да е подробности за изпълнението. Докато второто решение капсулира тези подробности за изпълнението в подходящи типове домейни (като YellingAnswer, QuestionAnswer, DefaultAnswer, …). Това не само улеснява промяната или разширяването на отговорите по време на изпълнение. Освен това обектите Answer стават многократно използвани и поведението им е централизирано в ясни класове без шумния код на другите типове Answer.
  3. Освен това кодът на втория подход е по-разбираем, защото разделя кода на по-малки части и също така предоставя декларативен и свободно четим код.

Заключение

Знам, че под капака методът First (ред 15), който използвах в моето решение, изисква използването на условни елементи, за да се провери дали предаденото условие се прилага към елемент от изброимото. Поради следните причини все пак е добър навик да избягвате възможно най-много условни изрази. Дори полиморфният код изисква условни изрази на по-високо ниво, за да определи кое поведение е правилното да се използва. Не можем да държим условните изрази напълно далеч от нас, тъй като изходните кодове, които пишем, в крайна сметка ще станат машинен код. Не става въпрос само за избягване на условни изрази, а по-скоро за разбиране, че има добри и лоши.

Лошите условни изрази не са тези, които оценяват стойност. Вместо това те се използват за странични ефекти, които водят до повишена сложност на кода, което прави по-трудно тестването и поддържането на отделни функции.

От друга страна, добрите условни изрази обикновено оценяват стойност. В примера по-горе един от тях е отговорен за определянето кое полиморфно поведение от няколко да се избере. Повечето от нас не пишат машинен код, който обикновено разчита на GOTO изрази. Обикновено програмираме с езици от по-високо ниво, които предоставят разбираема за човека абстракция от тези много технически машинни кодове. Така че трябва да използваме тези абстракции (напр. метода First в .NET LINQ), за да поддържаме нашия код четим за нас и нашите колеги.

PS: Не на последно място...

Искам да отбележа, че концепцията за кодиране на ката ме убеди, тъй като ката е добра възможност да се отдръпнете от ежедневните проекти и да се потопите дълбоко в проблемния контекст, като същевременно се концентрирате върху тренирането на конкретно умение. В моя случай ограничаването на условните изрази доведе до творчески процес в ума ми и това беше наистина приятно изживяване.

Това преживяване беше толкова приятно, че ме накара да напиша първата си медийна история за него. На този етап благодаря на всички, които прочетоха тази статия до края. Очаквам вашите отзиви и ще прочета за вашия опит по тази тема!

Приятен ден.
Йоханес