1. Критерії поганого дизайну
Життя влаштоване досить просто: щоб бути розумним, найчастіше достатньо просто не робити дурні речі. Це також стосується і розробки ПЗ: щоб щось зробити добре, в більшості випадків достатньо просто не робити погано.
Більшість програмістів мали досвід роботи з фрагментами системи з поганим дизайном. Але що ще сумніше, у більшості з вас буде сумний досвід усвідомлення того, що саме ви були автором такої системи. Хотіли якнайкраще, а вийшло як завжди.
Більшість розробників не прагне поганої архітектури, втім для багатьох систем настає момент, коли починають говорити, що її архітектура жахлива. Чому так відбувається? Чи був дизайн архітектури поганим із самого початку чи став таким із часом?
Коренем цієї проблеми є відсутність визначення "поганого" дизайну.
Мені здається, що саме розуміння якості дизайну та причин його "загнивання" є найважливішими якостями для будь-якого програміста. Як і в більшості інших випадків, головне — ідентифікувати проблему, а вирішити її буде справою техніки.
Визначення "поганого дизайну"
Якщо ти вирішиш похвалитися своїм кодом перед колегою-програмістом, то швидше за все отримаєш у відповідь глузування: "Хто ж так робить?", "А чому саме так?" і “Я зробив би все по-іншому”. Таке дуже часто трапляється.
Всі люди різні, але код ти пишеш все-таки для своїх колег-програмістів, тому в процесі розробки кожної фічі завжди потрібна фаза review, коли на твій код дивляться інші люди.
Але навіть якщо безліч речей можна зробити різними способами, є набір критеріїв, з яким погодилися б усі розробники. Будь-який шматок коду, який задовольняє твої вимоги, але виявляє одну (або кілька) характеристик, має поганий дизайн.
Поганий дизайн:
- Важко змінити, оскільки будь-яка зміна впливає на занадто багато інших частин системи (Жорсткість, Rigidity).
- Під час внесення змін зненацька ламаються інші частини системи (Крихкість, Fragility).
- Код важко використовувати повторно в іншій програмі, оскільки його занадто важко "виокремити" з поточної програми (Нерухомість, Immobility).
А найсмішніше те, що практично неможливо знайти шматок системи, який не містить жодної з цих характеристик (тобто є гнучким, надійним і повторно використовується), відповідає вимогам, і водночас дизайн його поганий.
Таким чином, ми можемо використовувати ці три характеристики для чіткого визначення, чи є дизайн "поганим" або "хорошим".
2. Причини "поганого дизайну"
Що робить дизайн жорстким, крихким та нерухомим? Жорстка взаємозалежність модулів.
Дизайн є жорстким (rigid), якщо його неможливо легко змінити. Ця жорсткість пов'язана з тим, що єдина зміна шматка коду переплетеної системи призводить до каскадних змін в залежних модулях. Це завжди відбувається, коли над кодом працює одна людина.
Це одразу ж ускладнює весь процес комерційної розробки: коли проєктувальник або розробник не може передбачити кількість каскадних змін, оцінити вплив такої зміни також неможливо. Тому такі зміни намагаються відкладати на потім.
І це, у свою чергу, робить вартість змін непередбачуваною. Менеджери, які зіткнулися з такою невизначеністю, неохоче погоджуються на внесення змін, таким чином дизайн офіційно стає жорстким.
Якоїсь миті ваш проект проходить "горизонт подій" і приречений на звалювання в "чорну діру" жорсткої архітектури.
Крихкість (fragility) – це схильність системи до поломок у багатьох місцях після єдиної зміни. Зазвичай нові проблеми виникають у місцях, які концептуально не пов'язані з місцем змін. Така крихкість серйозно підриває віру в дизайн та супровід системи.
Таке зазвичай траплялося, коли не було приватних методів. Досить зробити всі методи публічними – і система буде приречена на виникнення крихкої архітектури. Інкапсуляція допомагає боротися із цим на мікрорівні. Але на макрорівні тобі потрібна модульна архітектура.
Коли проєкт має крихку архітектуру, розробники не можуть гарантувати якості продукту.
Прості зміни в одній частині програми призводять до помилок в інших незв'язаних частинах. Виправлення цих помилок призводить до ще більшої кількості проблем, і процес супроводу перетворюється на відомого пса, що ганяється за власним хвостом.
Дизайн є нерухомим (immobile), коли потрібні частини системи сильно зав'язані інші небажані подробиці. Забагато свого коду, своїх унікальних підходів та рішень.
Пам'ятаєш логер JUL, розробники якого без вагомих на те підстав вигадали свої рівні логування? Це саме той випадок.
Щоб проєктувальник уявив, наскільки легко використати дизайн повторно, достатньо подумати про те, наскільки просто його буде використовувати в новому застосунку.
Якщо дизайн сильно пов'язаний, то цей проєктувальник жахнеться від кількості роботи, необхідної для відокремлення необхідних частин системи від непотрібних подробиць. У більшості випадків такий дизайн не використовується повторно, оскільки вартість його відділення перевищує його розробку з нуля.
3. Актуальність
Все змінюється, але все залишається незмінним. (Китайське прислів'я)
Вище ми підняли дуже добрі питання. Чим небезпечні крихкі та жорсткі системи? Тим, що процес управління подібним проєктом стає непередбачуваним та некерованим. А ціна — захмарною.
Як менеджер може давати чи не давати добро на додавання певної фічі, якщо він не знає, скільки насправді на це потрібно часу? Як пріоритезувати завдання, якщо не можна адекватно оцінити час та складність їх виконання?
А як розробникам виплачувати той самий технічний борг, коли при його виплаті нам добряче дістанеться, причому зрозуміти, скільки саме ми не можемо, поки остаточно з усім не розберемося?
Проблеми з повторним використанням коду або тестування теж дуже актуальні. Юніт-тести потрібні не лише для перевірки деяких припущень щодо модуля, але й для визначення ступеня його зв'язаності і можуть служити показником повторного використання.
Ось тобі цитата Боба Мартіна з цього приводу: “Для того, щоб використовувати ваш код повторно, потрібно щоб витрати на його повторне використання були меншими, ніж вартість розробки з нуля”. В іншому випадку ніхто з цією штукою навіть не морочитиметься.
Використання принципів і патернів проєктування є однією метою – зробити дизайн хорошим. Якщо їхнє використання не дає жодної вигоди (або навпаки, порушує принципи “хорошого дизайну”), значить щось у твоїй консерваторії не те й, можливо, інструмент почали використовувати не за призначенням.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ