17:45 Як два програміста хліб пекли |
Я працюю програмістом вже багато років, на протязі яких, як це не дивно, я весь час щось програмую. І ось яку цікаву річ я помітив: у коді, написаному мною місяць тому, завжди хочеться щось трохи поправити. У код піврічної давності хочеться поміняти дуже багато, а код, написаний два-три роки тому, перетворює мене в емо: хочеться заплакати і померти. У цій статті я опишу два підходи. Завдяки першому архітектура програми виходить заплутаною, а супровід - невиправдано дорогим, а другий - це принцип ПОЦІЛУНОК . Отже, уявімо собі, що є два програміста. Один з них розумний, прочитав купу статей на Хабре, знає каталог GoFнапам'ять, а Фаулера - в обличчя. Інший же робить все просто. Першого зватимуть, наприклад, Борис Н, а другого -. Маркус П. Само собою, імена вигадані, і всі збіги з реальними людьми та програмістами випадкові. Отже, до них обох приходить проектний менеджер (якщо у вашій всесвіту PM не ходить сам до програмістів, назвіть його якось інакше, наприклад BA або свинцю , суті це не змінить) і каже: - Хлопці, нам потрібно, щоб робився хліб. Саме так, «робився», без уточнення способу виробництва. Як же надійдуть наші програмісти? ![]() Борис створює свою першу абстракцію - клас продуктів, від нього він успадковує клас хліба, а інстанціірует екземпляри цього класу фабричний метод класу ProductFactory - createProduct (). Маркус робить приблизно те ж. Він створює клас Хліб і клас менеджера з фабричним методом createBread (). Поки різниця мінімальна. Проектний менеджер, трохи глибше розібравшись (це йому так тільки здається, так) в потребах замовника, приходить вдруге і каже: - Нам потрібно, щоб хліб не просто робився, а випікався у грубці. А відразу можна було сказати, що хліб печеться не у вакуумі, а в грубці? Ну гаразд, що ж роблять програмісти? ![]() Борис перейменовує клас ProductFactory в печі, і виділяє абстракцію - AbstractOven. Щоб було зовсім красиво, він метод createProduct () перейменовує в bakeProduct (). Тим самим Борис в перший раз виконав рефакторинг, застосувавши «виділення абстракції», а так само реалізував шаблон «абстрактна фабрика» точнісінько як він описаний в літературі. Молодець, Борис. А ось Маркус нічого не робить. З його точки зору все і так добре. Ну може бути, варто злегка поміняє реалізацію createBread (). Фаза місяця змінюється, і менеджер втретє приходить до програмістів. Він говорить: - Нам потрібно, щоб пічки були різних видів. Що ж, справедливо. ![]() Борис, радісно потираючи руки, створює три спадкоємця AbstractOven - ElectricOven, MicrowaveOven і GasOven. А клас Духовка він видаляє за непотрібністю. Маркус теж вносить зміни в програму. Він додає в метод createBread цілочисельний параметр ovenType. У четвертий раз приходить до програмістам менеджер. Він тільки що прочитав одну з книг серії «Я пізнаю світ».Інтерференція нової інформації і PMBoK дала несподіваний результат. Менеджер каже: - Нам потрібно, щоб газова піч не могла піч без газу. ![]() Борис абсолютно безпідставно вважає, що джерело газу може бути тільки один. А ДЛЯ Таких випадків Завжди ЕСТЬ Наш улюблену шаблон . Він створює поодинці GasSourceSingleton, а для зменшення зв'язності впроваджує його через інтерфейс GasSource в GasOven. Ура, він застосував впровадження залежності через сетер! Скромний від природи Маркус створює речовий приватне поле gasLevel в класі Manager. Природно, доведеться трохи поміняти логіку методу createBread, але що поробиш! Але ось пару днів потому менеджер приходить в п'ятий раз, і, сито облизуючись, вимовляє: - Нам потрібно, щоб пічки могли випікати ще й пиріжки (окремо - з м'ясом, окремо - з капустою), і торти. Програмісти теж хочуть їсти, тому беруться за роботу. ![]() Борис вже починає щось таке відчувати, але зупинитися вже не може. Як грубка дізнається, що саме їй потрібно готувати? Очевидно ж - їй потрібен кухар. І Борис, не довго (а може і довго) думаючи, створює клас Кука. У нього буде метод для приготування, приймає на вхід абстрактну піч - кухар (Оуен: AbstractOwen): Product. Адже це логічно - кухар бере піч, і з її допомогою готує. Потім Борис створює ще кілька спадкоємців класу продукт - торт і пастоподібних, а від пастоподібних успадковує MeatPasty і CabbagePasty. А потім для кожного типу продукту створює окремого кухаря - BreadCook, PastyCook і CakeCook. Начебто ще нормально, але часу на це пішло набагато більше, ніж у Маркуса, який просто додав ще один цілочисельний параметр до методу createBread - breadType. У шостий раз приходить менеджер. До речі, те, що він зараз попросить - це не вимога замовника, це його власна ініціатива. Але ж про це ніхто не дізнається, так адже? - Нам потрібно, щоб хліб, пиріжки та торти випікалися за різними рецептами. ![]() «Хм», - вимовляє Борис і згадує про шаблон «будівельник» (разом зі «вільним інтерфейсом» , звичайно ж). Він створює клас рецепт, а до нього - будівельник RecipeBuilder. Рецепт він впроваджує (ВНЕЗАПНО!) в пічку за допомогою сетера setRecipe (рецепт: Рецепт). А Маркус (ви не повірите) додає ще один цілочисельний параметр в createBread - рецепт. Найцікавіше, як завжди, відбувається далеко від комп'ютерів. А саме: менеджер вперше після початку розробки зустрічається із замовником і нарешті розуміє, навіщо тому потрібна була піч. Він (менеджер) в сьомий раз приходить до програмістів і говорить: - Нам потрібно, щоб у печі можна було обпалювати цеглу. ![]() Для Бориса це остання зустріч з менеджером, але все ж він з останніх сил вносить зміни в архітектуру. Він виділяє абстрактний клас AbstractHeatingSmth - абстрактне нагріває щось. Для нього він створює фабрику HeatingFactory.Від AbstractHeatingSmth він успадковує ProductOven і Furance. В останнього є фабричний метод makeBrick, що створює екземпляр об'єкту Brick. Але нічого не працює. Читачеві пропонується самостійно знайти помилку в архітектурі. У Маркуса теж не все так гладко. Йому доводиться створити вже третій (!) По рахунку клас. Він називає його цегла, і додає в свій менеджера метод makeBrick. Звичайно, можна заперечити, що у Маркуса всередині методу createBread твориться пекло І Ізраїль , і це насправді так. Але за допомогою шаблону «шаблонний метод» безлад цілком можна структурувати. А в достатку фабрик і абстракцій розібратися, ну, трохи складніше. Висновки, які я хочу зробити, напевно, трохи передбачувані. Підхід Бориса хороший тим, що практично кожну частину системи можна ізолювати і покрити тестами. Але часу на створення такої кількості класів піде непристойно багато, і кожна зміна вимог обернеться каскадним зміною коду.Спроба ж зробити архітектуру гнучкою, угадавши побажання замовника, зазвичай провалюється - архітектура гнеться зовсім не в тому місці. Адже, як відомо «світ не просто дивніше, ніж ми собі уявляємо, - він дивніше, ніж ми можемо собі уявити ». І, отримавши черговий запит на зміну, програміст переконується в цьому як ніхто інший. Підхід Маркуса, звичайно, не дозволяє використовувати модульне тестування, але зате він дає результат набагато швидше, і зміни даються меншою кров'ю. Цей підхід - той самий швидкий старт, якого так хочуть стартапери всіх мастей. І, як не дивно, в такому коді дійсно легше розібратися, тому що він простіший. |
Переглядів: 1004 | Додав: TeMka | Рейтинг: 0.0/0 |
Всього коментарів: 0 | |