Пастка CMS

Кінець 2013 Maxim Chernyak написав чудову статтю в якій підкреслював виняткову важливість підтримки архітектури додатків настільки простий, наскільки це можливо. Здивований що на Хабре досі не було перекладу, пропоную ознайомитися з перекладом цієї статті. Також прошу повідомляти про всі можливі друкарських помилках і неточності перекладу.
 
 
Преамбула
Багато років тому у нас було додаток Ruby on Rails. Все починалося з об'єктів. Деякі виступали прототипами для інших об'єктів. Інші вимагали безліч пов'язаних з ними частин, частин цих частин і т.д. Наскільки багато? Мабуть, одним прототипам відомо. Ці прототипи повинні були мати інтерфейс для адміністрування, але зміна логіки роботи одного прототипу могла призвести до ланцюгової реакції в інших частинах. Будь-яка зміна об'єктів та їх прототипів пролягали через пов'язану мережу з різних моделей. Складність інтерфейсу для адміністрування швидко злетіла до небес. Дійшло до того моменту, коли прототипи мали стати Серіалізуемое, що зберігають фрагменти своєї логіки. З цього моменту кожна фіча ставала предметом дуже важкою реалізації, і, в кінцевому рахунку, додаток скотилося до стану, коли модифікація і доробка стали практично неможливі. Було таке відчуття, ніби CMS нав'язувала себе в якості посередника між фичей та її реалізацією, подібно системам, орієнтованим виключно на бізнес-логіку, з нагромадженням високорівневих абстракцій.
 
Думаєте це була найгірша частина проекту? Це був ще тільки мінімально життєздатний продукт в новому стартапі.
 
 
Незапланована CMS
Природа програмування закликає нас побалувати себе рішенням головоломок і моделюванням абстрактних концепцій. Це пристрасть, яка змушує нас випускати з уваги насувається небезпека. Завдяки нашим невиразним суб'єктивним припущеннями, ми вже знаходимося на шляху до пастці створення надмірно складних систем. Пастці CMS. Ми страждаємо від наслідків потрапляння в цю пастку, таких як «вигорання», втрату ентузіазму, зірвані терміни, невдачі в бізнесі, але, здається, ніколи не будемо говорити про цю помилку безпосередньо. Де то близько кулера, більш досвідчений колега зауважує, що ви ускладнюєте речі. Де то в IRC вас висміюють за питання про складну систему об'єктів для проекту, який, найімовірніше, так і не побачить світла. Тим не менше, ніхто не може чітко пояснити, що лежить в основі цього процесу. Ці зауваження — от і все що ми знаємо про цю проблему, і люди, в кінцевому рахунку, дізнаються про це на своїй шкурі. Ось чому я б хотів пролити трохи світла на це явище. Для початку ось невеликий список ознак, як, на мій погляд, визначити чи перебуваєте ви на шляху до цієї пастці.
 
 Пастка CMS цей стан веб-додатки в якому розробка CMS створює перешкоди для створення контенту цієї CMS.
 
Якщо ви, як і я, створюєте стартап, ви повинні знати, що ця пастка особливо небезпечна на ранній стадії розробки. Тільки невеликий відсоток компаній грає в довгу гру, і з часом, їх проблеми переходять вже в іншу площину. Хоча ці компанії можуть також потрапити в цю пастку, для них, найімовірніше, це буде вже не так критично, навіть якщо вони переслідували цей напрямок навмисно. Тут я б хотів зосередитися в набагато більш різноманітному питанні: саме на невеликих компаніях. Проблема стане очевидною, як тільки ви відкрили двері вашого проекту для клієнтів. Вони починають використовувати ваш продукт і надавати вам реальну аналітику і зворотний зв'язок. З цього моменту проект більше не буде управлятися вашим шостим почуттям, ви повинні будете спиратися на реальні дані, що свідчать про те, як діяти далі, який функціонал реалізовувати в майбутньому. Це час, коли всі ваші архітектурні рішення проходять випробування. Реальність нещадна, вона не позбавить вас від хворобливої ​​істини, коли відбувається захід вашої багатообіцяючою архітектури додатку. Ви могли, ви хотіли б провести рефакторинг, але вже надто пізно, так як вам вже потрібно створювати новий функціонал, а його реалізація стає все складніше і складніше, вниз по спіралі падаючої продуктивності.
 
 
Я скажу собі потім «Спасибі»
 
«Більшість наших припущень пережили свою марність»
 - Marshall McLuhan
 
 
Простіше кажучи, ми любимо проектування системи. Як тільки ми формуємо деяке розуміння проблеми, ми кидаємося до наших
/(?:whiteboards|moleskines|mindmaps|editors)/
і починаємо визначати сутності та взаємодії між ними. Це те, що ми робимо найкраще. Ми беремося за деякі з найбільш фундаментальних рішень про проект. Потім, ретельно виклавши наші припущення, фіксуємо зміни. Нам подобатися думати, що ми сіємо мудрість і гнучкість з наших ранніх рішень, і будемо дякувати себе пізніше. Здавалося б, що може піти не так з усіма цими точками розширення і добре представленими сутностями? Реальність в тому, що, швидше за все, ці ранні рішення швидше обмежать наші майбутні напрацювання, ніж дадуть нам простір. Гряде день, коли ми зустрінемо нашого старого друга, наївного «себе в минулому», що дивиться на нас з редактора, гордо усміхаючись. Цей благонамірений людина провів години, дні і тижні відправляючи всі наші зусилля в безодню передбачуваної архітектури, навряд чи маючи уявлення про реальні проблеми, з якими ми зіткнемося після запуску. В даний час ми застрягли у всьому цьому «корисному» коді. Це як якщо б ви вирішили приготувати салат, але замість окремих інгредієнтів, розкладених перед вами, все що б ви мали — це інше салат, приготований незнайомцем, в якому ви зараз змушені копатися, в надії знайти інгредієнти, які вам потрібні.
 
 У програмуванні, ви минулого — не хто інший, як незнайомець з купою багів.
 
Чи в тому ж дусі — уявіть, що ви тільки що повернулися до комп'ютера і виявили що ваш додаток реорганізовано якимось неосвіченим незнайомцем таким чином, що має мало спільного з реальним призначенням проекту. Це не дуже відрізняється від того, коли ми знаходимо частини системи, змодельовані в минулому. Хіба ви хочете мати справу з усім цим мотлохом, а не просто рухатися вперед, відповідно до того, як це диктується потребами бізнесу?
Якщо застосувати все це до моєї особистої історії, то врешті-решт я зрозумів, що з кожною новою фичей я проводив все більше часу, з'ясовуючи як вписати її в існуючу структуру фреймворка, замість того щоб проектувати фічу. Як ви вже здогадалися, я дуже себе дякував за те, що був так уважний.
 
 
C < RUD
 
«Найважче читати код, ніж його писати»
 - Joel Spolsky
 
 
Говорити про архітектуру, це як говорити про сам коді. Це не зовсім те, що ми не зможемо мати на увазі в майбутньому, просто в цьому питанні, цілком імовірно, шанси не на нашу користь. Код легко писати і важко змінювати або видаляти. Кожен рядок, яку ми з легким серцем кидаємо у справу, в кінцевому рахунку буде дражнити нас: «Вгадай, що піде не так, якщо ти доторкнешся до мене? (: Trollface) ». Архітектурні рішення, так само як і код, легко створювати і дуже важко змінювати. І якщо в коді ця проблема пом'якшується тестуванням, то в архітектурі нас нічого не рятує. Єдина міра якості, яка у нас є, це кількість болю, яке ми відчуваємо, коли працюємо над новою функцією, але щось міняти в архітектурі до того часу, найчастіше, занадто пізно. Погана архітектура може погубити весь бізнес, незважаючи на те, що весь код буде покритий тестами на 100%.
 
 
Сигнал тривоги
Як і в більшості пасток, також і в нашому випадку немає конкретного способу дізнатися, що ви на шляху до неї. Найкраще, на що ви можете розраховувати це коли навколишні речі «попередять» вас про майбутню небезпеку. Нижче я перерахую деякі з них, по своєму досвіду. Якщо ви помічаєте ці ознаки на ранньому етапі розробки, вони повинні, принаймні, викликати у вас підозру.
 
 
Ранній консерватизм
 
«Держава, яка не в силах нічого змінити, не здатне себе зберегти»
 - Edmund Burke
 
 
Припустимо, ви зіткнулися з новою фичей і реалізуєте її, щоб бути реальним yak shave . Ви розумієте, що реалізація вимагає великого рефакторинга, і ви шукайте способи його уникнути. Існує тонка грань між тим, для чого ви робите це — ви робите це з міркувань ефективності або ви робите це, тому що застрягли в накопиченнях legacy-архітектури. Може бути, ваші ранні передбачувані проектні рішення встають на шляху нинішніх реальних потреб бізнесу? Можливо, ви створювали поспіхом занадто багато, і тепер це лише питання часу — коли ви потрапите в пастку, і ваш проект залишиться паралізованим? Не зрозумійте мене неправильно, найчастіше, консерватизм є здоровою захистом від зайвої складності, це стандартна практика досвідченого розробника. Проблема в тому, коли консерватизму занадто багато саме на ранніх етапах розробки проекту. Це точно повинно викликати підозру.
 
 
Синдром Drupal'а
 
«Хмм, у нас різні правила ціноутворення для різних продуктів, ми повинні знайти рішення для адміністратора, щоб він міг задавати ці правила в адмінці. Може бути, ми повинні зберігати код в базі даних і потім запускати його? »
 
 
Це класична ознака того, що ви на шляху до пастці. Ви намагаєтеся придумати спосіб, щоб задавати через адмінку якусь логіку, яка потім повинна бути збережена в базі даних. Якщо це не стосувалося інтерфейсу адмінки, можливо це було зроблено за допомогою всього лише кількох рядків коду. Тим не менш, зараз ми говоримо про створення моделей цін, асоційованих з правилами та про складність цього. Для розширення можливостей цін, які раніше, можливо, були реалізовані за допомогою однієї-двох рядків коду, тепер доведеться створювати міграції, форми, валідацію і все інше. Вам дійсно потрібен інтерфейс для правил ціноутворення в адмінці, зараз?
 
 
Seed'и слабкі
Як би ви реалізували 10 категорій для розміщення в них ваших товарів? Типова відповідь передбачає створення моделі Category, а потім написання сценарію (seed), який розгорне 10 запропонованих категорій, які будуть асоційовані з продуктами. Потім вам необхідно буде переконатися, що кожен розробник розгорнув цей сценарій. Звичайно, крім того, не забувайте про запуск його в продакшені. При кожному Деплой. При кожному оновленні. І при налаштуванні нової машини. І при виконанні тестів. І, природно, якщо ви внесли зміни в цей самий сценарій.
Якщо на ранній стадії ваш додаток покладається на безліч таких сценаріїв, ви вже на слизькому шляху. Речі, які на даний момент можна описати константою, не повинні бути змодельовані як сутності баз даних, але я повернуся до цього пізніше.
 
 
Всі дороги ведуть в Мордор
 
«Один — не просто реалізація бізнес-логіки»
 - Boromir
 
 
Цей пункт дещо схожий на ранній консерватизм, але різниця все ж є. Чи бували ви коли не будь налякані тривіальним завданням? Запитайте себе: чи буде це завдання настільки ж лякаючою, якщо буде реалізована як окремий компонент, поза проектом? Якщо відповідь так, дивіться під ноги, тому що ви можете потрапити в пастку. Реалізація функціоналу в добре спроектованих системах не повинна бути більш важкою, ніж її реалізація в ізоляції — як окремого компонента.
 
 
«Фантомні болі»
Іноді пастку CMS можна дізнатися за присутності «фантомних болів», які випливають з прихованих наслідків розвивається CMS. Наприклад, насправді, вам ніколи і не потрібно було видаляти реалізовані вами категорії, але тому що ви реалізували їх як редаговані адміністратором записи в базі даних, ви раптом думаєте, що буде, якщо ці категорії видалять з бази даних? Ваша архітектура взяла на себе сміливість змусити думати вас про сценарій, робота якого насправді не потрібна і не реальна. У кінцевому рахунку це і називається «фантомними болями».
 
 
Запобігання
У всіх перерахованих вище симптомах є що те загальне. Вони всі є результатом ранніх припущень, які призводять до складності системи. У цьому випадку корисно відповісти на питання «Що таке складна система?» І «Як писати програми, не роблячи помилкових ранніх припущень?».
У контексті даної статті, скажімо, що складна система являє собою мережу вузлів, яка складається з більшої кількості вузлів, ніж ви зазвичай можете тримати у своїй голові. Очевидно, щоб отримати систему з низьким рівнем складності, потрібно скоротити кількість вузлів і з'єднань. Щодо останнього питання, то це якраз те, що привело мене до його вирішення. Щоб писати програми без подібних проблем ви повинні в першу чергу уникати динамічної генерації даних під час runtime'а.
Дозвольте мені пояснити. Будучи наляканим складністю системи, я виявив, що існує принцип, який повинен стати основоположним, у всіх прийнятих рішеннях. Давайте назвемо цей принцип keep it static, stupid (роби це статичним) , що представляється доцільним, тому що насправді це не більше ніж архітектурно-відомий риф, на шляху до створення простих речей.
 
 Створення незмінних речей — архітектурний еквівалент уникнення передчасної оптимізації.
 
Красою цього принципу є те, що він застосовний на кожному рівні абстракції, незалежно від того про що ми говоримо — уявлення, код або бази даних. Сама по собі ідея проста — якщо є сумніви — зробіть це статичним. Це легше зрозуміти на конкретному прикладі, на різних рівнях типового Rails-додатки.
 
 
Це може бути вирішено за допомогою класу?
Раніше в цій статті я згадував правила ціноутворення. Це загальна проблема, де кожен продукт може обчислюватися за різними правилами ціноутворення. Ціна може залежати від кількості, поточного користувача (програми лояльності), історії замовлення, купонів і багатьох інших речей. Щоб уникнути попадання в пастку CMS я застерігаю вас уникати побудови цих видів на ранній стадії під час виконання. Напишіть клас схеми ціноутворення. Використовуйте шаблон Strategy . Зробіть ваш алгоритм замінним на рівні коду. Визначте правила ціноутворення на вашій мові програмування. Таким чином, складність цієї логіки буде відображена безпосередньо в коді, і не потягне цілий шар абстракції.
 
Мови програмування вже мають такі чудові інструменти як умови і цикли. Навіщо перевизначати їх на більш високому рівні абстракції? Цих інструментів більш ніж достатньо, щоб побудувати складну цінову логіку безпосередньо, шляхом написання коду. Якщо у вас є декілька алгоритмів ціноутворення записаних у вигляді підключаються об'єктів, не соромтеся — дайте адміністратору вибрати один з них, може бути навіть «заповнити прогалини», додаючи ключові особливості в ваш алгоритм, але розвивати цю функціональність поступово, в міру необхідності. Створити свій інтерфейс адміністрування з часом, додавати все більше і більше гнучкості під час виконання у ваші об'єкти-стратегії. Пам'ятайте, ви завжди можете зробити статичні / жорстко закодовані речі динамічними, але навпаки — далеко не завжди. Все, що регулюється в момент виконання, вводить складність в кожному рішенні, з цього моменту, і збільшує шанси на помилки, які ви не можете передбачити, навіть у, здавалося б, не пов'язаних між собою частинах вашої програми.
 
 
Це може бути вирішено за допомогою статичної сторінки?
Припустимо, ви перераховуєте на деякій сторінці об'єкти, які повинен бачити клієнт. Цими об'єктами можуть бути продукти, фотографії, файли, або щось ще, що ви робите. Тепер ви, напевно, вирішили, що на кожному елементі має бути назва, опис, фото, можливо автор або бренд. Ви розділили свої сутності на поля з даними, і вирішили створити моделі, підтримувані базою даних. Це якраз той момент, де я хотів би запропонувати зупинитися і подумати, чи є у вас достатній привід, чому це має бути не статична сторінка. Статичний шаблонне уявлення означає, що для того щоб змінити стан речей, ви повинні змінити уявлення і розгорнути його, так, але це також означає що вам не доведеться писати контролери, міграції, форми, інтерфейс для адміністрування і т.д. Насправді, почасти, у вас вже є інтерфейс для адміністрування, якщо ви використовуєте GitHub. Це не редагування в режимі реального часу, але краще ніж нічого. Користувачі спокійно можуть редагувати подання через форму на GitHub'e.
 
Це стає ще більш важливою проблемою, якщо вас просять перерахувати категорії на основі певних правил. При динамічному підході, це відразу змусить вас створити мережу пов'язаних моделей, просто для того щоб отрендеріть шаблон. Зауважимо, як мало ви знаєте в цей момент про майбутні потреби бізнесу, і як ви будете їх припускати. Зауважимо так само, як швидко і легко просто сісти і захардкодіть цю сторінку. Так само як і у випадку з патерном «стратегія» — ми завжди зможемо надати цій сторінці динамічний зміст у майбутньому, коли на то виникнуть реальні потреби. Якщо ви будуєте динамічну систему прямо зараз, швидше за все ви їй і обмежитеся.

Це може бути вирішено за допомогою константи?
Повертаючись до питання про сценарії, це питання досить простий. Ви створюєте категорії. Ці категорії зумовлені. Замість додавання моделі, таблиці і сценарію для деплоя, чому б просто не зробити ці категорії константою з масивом? Код дозволяє зберігати статичні дані без участі бази даних. Використовуйте це, і чекайте того моменту, коли вам дійсно буде необхідно редагування категорій під час виконання. Коли це настане, ви завжди зможете витягувати категорії з бази даних. Якщо у вас є категорії, які ніколи не змінюються і деякі, які повинні змінюватися в адмінці, ви можете не чіпати попередні категорії. Ви можете залишити їх в константі, читати їх звідти, і таким чином уникати seed'ов. Насправді це мій маленький секрет. Я не люблю даних таких сценаріїв. Зараз наш додаток працює «з коробки» на машині будь-якого нового розробника. Якщо ви завантажте наш код на свій dev-комп'ютер, програма просто запуститься і буде працювати. Ось чому я завжди кажу: якщо не знаємо — хардкодім.

Це може бути вирішено за допомогою рядка в базі даних?
Припустимо, на даний момент додаток працює дуже добре і у вас є всі необхідні моделі для бази даних. Вам потрібно відобразити у вільній формі текст, який може відрізнятися від однієї сутності до іншої (наприклад, різний текст для кожного продукту), а також може містити різні інтерполяції з різних джерел. Відповідно до принципу ви не повинні думати про моделювання цього тексту через класи. По-перше, запитайте себе — чи можна просто дозволити адміністратору задавати текст для кожного продукту. Але почекайте, сказали б ви. Якщо значення отримано з інших джерел, чому адміністратор повинен заповнювати їх вручну? Чи повинен він шукати і вводити їх щоразу? Здається, ми що то упустили. Що-ж, розслабимося і розглянемо включення можливості додавати сніпети. Можливо, варто додати просто текстове поле вільної форми, яке надає деякий заздалегідь заповнений текст для адміністратора. Коли ви думаєте що вам потрібно структурувати дані для збереження чого то дуже «гнучкого», то краще використовуйте звичайну рядок з canned snippets.

Підводячи підсумок
«У кожної складної проблеми є просте, всім зрозуміле неправильне рішення»
— H. L. Mencken

У той час як текст вище представляє з себе хороший базовий принцип, він не може бути рішенням всіх проблем, які виникають з CMS-подібними рішеннями. Коли вам доручили розробку дуже гнучкою CMS, природно, ви намагаєтеся робити щось подібне. Коли вас просять розробити додаток з чимось на зразок Drupal, ви перебуваєте в зовсім іншій області, де пастка CMS може загрожувати постійно. Проте, навіть у цих випадках виникатимуть питання, чи слід робити щось більш-менш динамічним, і я закликаю кожного розробника схилятися до менш динамічному варіанту. Ви будете робити послугу не тільки для себе ж самого в майбутньому, але і для наступного розробника, який набагато продуктивніше нарізуватиме шматок статичного HTML і додасть якийсь динамічний контент, ніж буде намагатися зрозуміти димлячу купу передбачуваної архітектури, з великою кількістю «рухомих» частин.
Важливо також відзначити, що я не засуджую розширення архітектури. Це добре, до певної міри, це лінія яку ми малюємо на піску від випадку до випадку. Я закликаю вас подумати про те, де провести цю лінію кожен раз при реалізації чогось.

Повертаючись до моєї історії, вона закінчилася річним застоєм і наступними дуже неохочими оновленнями всього програми. Зрештою, вищезгадані «прототипи» були знижені до незмінних класів і з плином часу стали носити декларативний характер, завдяки природно розвивається внутрішньої DSL. Дивлячись на ці файли сьогодні, важко уявити як би я реалізовував інтерфейс для адміністрування з усіма цими «рухомими» частинами під час виконання. Не дивлячись на те що ми витратили рік, я до сих пір радий, що ми стиснули зуби і провели рефакторінг. Було боляче, але тепер ця помилка далеко позаду.

Якщо ви не знаєте точно, що ви робите (а зворотне малоймовірно), віддавайте перевагу незмінюваність. Спробуйте докласти додаткових зусиль, для визначення того, які частини вашої бізнес логіки можна залишити в коді. Якщо сумніваєтеся — залишайте в коді. Роблячи це, переконайтеся, що ви дотримувалися порад і рекомендацій: ніколи не повторюйте постійні дані, використовуйте композицію, впровадження залежностей, спадкування — все, щоб переконатися, що ви дотримуєтеся єдиний принцип відповідальності і підтримуєте єдність управління.
І найголовніше, не заплутайтеся в занадто довгих міркуваннях — нехай історія розгортається природним шляхом.

Оригінал статті: hakunin.com / cms-trap
 
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.