paint-brush
Як боротися зі складністю під час проектування систем програмного забезпеченняза@fairday
64,488 показання
64,488 показання

Як боротися зі складністю під час проектування систем програмного забезпечення

за Aleksei23m2024/02/05
Read on Terminal Reader
Read this story w/o Javascript

Надто довго; Читати

Складність – ворог! Давайте навчимося з цим справлятися!
featured image - Як боротися зі складністю під час проектування систем програмного забезпечення
Aleksei HackerNoon profile picture

Про що йдеться?

Кожен день, кожну мить протягом нашої інженерної кар'єри ми стикаємося з багатьма різними проблемами різної складності та ситуаціями, коли нам потрібно прийняти рішення або відкласти його через брак даних. Щоразу, коли ми будуємо нові сервіси, будуємо інфраструктуру чи навіть формуємо процеси розробки, ми торкаємося величезного світу різноманітних викликів.


Перелічити всі проблеми складно, а можливо, навіть неможливо. Ви зіткнетеся з деякими з цих проблем, лише якщо працюєте в певній ніші. З іншого боку, є багато проблем, які ми всі повинні розуміти, як вирішити, оскільки вони мають вирішальне значення для створення ІТ-систем. З високою ймовірністю ви зустрінете їх у всіх проектах.


У цій статті я поділюся своїм досвідом щодо деяких проблем, з якими зіткнувся під час створення програмного забезпечення.

Що таке міжсекторальна проблема?

Якщо ми заглянемо у Вікіпедію, то знайдемо таке визначення


У аспектно-орієнтованій розробці програмного забезпечення наскрізні проблеми — це аспекти програми, які впливають на декілька модулів, без можливості бути інкапсульованими в будь-якому з них. Ці проблеми часто неможливо чітко відокремити від решти системи як при проектуванні, так і при реалізації, і це може призвести до розпорошення (дублювання коду), заплутування (значних залежностей між системами) або обох.


Це детально описує, що це таке, але я хочу трохи розширити та спростити це:

Наскрізне занепокоєння – це концепція або компонент системи/організації, який впливає (або «перетинає») багато інших частин.


Найкращими прикладами таких проблем є архітектура системи, журналювання, безпека, керування транзакціями, телеметрія, дизайн бази даних та багато інших. Далі в цій статті ми розглянемо багато з них.


На рівні коду наскрізні проблеми часто реалізуються за допомогою таких методів, як аспектно-орієнтоване програмування (AOP) , де ці проблеми поділяються на окремі компоненти, які можна застосовувати в усій програмі. Це зберігає бізнес-логіку ізольованою від цих проблем, роблячи код більш читабельним і зручним для обслуговування.

Класифікація аспектів

Існує багато можливих способів класифікації аспектів шляхом їх сегментації за різними властивостями, такими як обсяг, розмір, функціональність, важливість, ціль та інші, але в цій статті я використовуватиму просту класифікацію обсягу. Під цим я маю на увазі, куди спрямований цей конкретний аспект, незалежно від того, чи це вся організація, окрема система чи окремий елемент цієї системи.


Отже, я збираюся розділити аспекти на макро та мікро .


Під макроаспектом я маю на увазі в основному міркування, яких ми дотримуємося для всієї системи, як-от обрана архітектура системи та її дизайн (монолітна, мікросервіси, сервіс-орієнтована архітектура), технологічний стек, організаційна структура тощо. Макроаспекти пов’язані в основному зі стратегічним і високорівневим рішення.


Між тим, мікроаспект набагато ближчий до рівня коду та розробки. Наприклад, який фреймворк використовується для взаємодії з базою даних, структура проекту папок і класів або навіть шаблони проектування конкретних об’єктів.


Хоча ця класифікація не є ідеальною, вона допомагає структурувати розуміння можливих проблем, а також важливості та впливу рішень, які ми застосовуємо до них.


У цій статті моя основна увага буде зосереджена на макроаспектах.

Макро аспекти

Організаційна структура

Коли я тільки почав вивчати архітектуру програмного забезпечення, я прочитав багато цікавих статей про закон Конвея та його вплив на організаційну структуру. Особливо цей . Отже, цей закон говорить про це


Будь-яка організація, яка розробляє систему (у широкому значенні), створить проект, структура якого є копією комунікаційної структури організації.


Я завжди вважав, що ця концепція справді дуже універсальна і представляє золоте правило.


Тоді я почав вивчати підхід Еріка Еванса до моделювання систем, орієнтований на домен (DDD). Ерік Еванс підкреслює важливість ідентифікації обмеженого контексту. Ця концепція передбачає поділ складної моделі предметної області на менші, більш керовані секції, кожна з яких має власний обмежений набір знань. Цей підхід сприяє ефективній командній комунікації, оскільки зменшує потребу в глибоких знаннях усієї області та мінімізує перемикання контексту, що робить розмови ефективнішими. Перемикання контексту — це найгірша і найбільш ресурсозатратна річ. Навіть комп'ютери борються з цим. Хоча навряд чи вдасться досягти повної відсутності перемикання контексту, я вважаю, що це те, до чого ми повинні прагнути.


Fantasy about keeping in mind a lot of bounded contexts

Повертаючись до закону Конвея, я знайшов у ньому кілька проблем.


Перша проблема, з якою я зіткнувся у зв’язку із законом Конвея, який припускає, що дизайн системи відображає організаційну структуру, — це потенціал для формування складних і всеохоплюючих обмежених контекстів. Ця складність виникає, коли організаційна структура не узгоджується з межами домену, що призводить до обмежених контекстів, які сильно взаємозалежні та завантажені інформацією. Це призводить до частого перемикання контексту для команди розробників.


Інша проблема полягає в тому, що організаційна термінологія просочується на рівень коду. Коли організаційні структури змінюються, це вимагає модифікації кодової бази, споживаючи цінні ресурси.


Таким чином, дотримання інверсного маневру Конвея допомагає побудувати систему та організацію, які заохочують бажану архітектуру програмного забезпечення. Однак варто зазначити, що цей підхід не дуже добре працюватиме у вже сформованій архітектурі та структурах, оскільки зміни на цьому етапі тривають, але він винятково ефективний у стартапах, оскільки вони швидко вносять будь-які зміни.

Великий куля бруду

Цей шаблон або «антишаблон» створює систему без будь-якої архітектури. Немає ні правил, ні меж, ні стратегії, як контролювати неминучу зростаючу складність. Складність є найстрашнішим ворогом на шляху створення програмних систем.


Entertaining illustration made by ChatGPT

Щоб уникнути побудови такого типу системи, нам потрібно дотримуватися певних правил і обмежень.

Архітектура системи

Існує безліч визначень архітектури програмного забезпечення. Мені подобається багато з них, оскільки вони охоплюють різні його аспекти. Однак, щоб мати можливість міркувати про архітектуру, нам потрібно природно сформувати деякі з них у своїй свідомості. І варто зазначити, що це визначення може розвиватися. Тож, принаймні на даний момент, я маю для себе такий опис.


Архітектура програмного забезпечення — це рішення та вибір, які ви робите щодня, які впливають на побудовану систему.


Щоб приймати рішення, необхідно мати в «сумці» принципи та шаблони для вирішення виникаючих проблем, також важливо зазначити, що розуміння вимог є ключовим для побудови того, що потрібно бізнесу. Однак інколи вимоги є непрозорими або навіть невизначеними, у цьому випадку краще почекати з отриманням додаткових роз’яснень або покладатися на свій досвід і довіряти своїй інтуїції. Але в будь-якому випадку ви не можете правильно приймати рішення, якщо у вас немає принципів і шаблонів, на які можна спиратися. Ось де я підходжу до визначення стилю архітектури програмного забезпечення.


Стиль архітектури програмного забезпечення — це набір принципів і шаблонів, які визначають, як створювати програмне забезпечення.


Існує багато різних архітектурних стилів, орієнтованих на різні сторони запланованої архітектури, і застосування декількох з них одночасно є нормальною ситуацією.


Наприклад, такі як:

  1. Монолітна архітектура

  2. Дизайн, орієнтований на домен

  3. На основі компонентів

  4. Мікросервіси

  5. Труба і фільтри

  6. Керований подіями

  7. Мікроядро

  8. Сервісно-орієнтований


і так далі...


Звичайно, вони мають свої переваги та недоліки, але найголовніше, що я дізнався, це те, що архітектура розвивається поступово, залежно від реальних проблем. Початок роботи з монолітної архітектури є чудовим вибором для зменшення операційних складнощів, дуже ймовірно, що ця архітектура відповідатиме вашим потребам навіть після досягнення етапу відповідності продукту ринку (PMI) створення продукту. У масштабі ви можете розглянути можливість переходу до підходу, керованого подіями, і мікросервісів для досягнення незалежного розгортання, гетерогенного середовища стеку технологій і менш зв’язаної архітектури (і тим часом менш прозорого через характер підходів, керованих подіями та pub-sub, якщо вони прийняті). Простота і ефективність близькі і мають великий вплив один на одного. Зазвичай складні архітектури впливають на швидкість розробки нових функцій, підтримку та підтримку існуючих і викликають природну еволюцію системи.


Однак складні системи часто вимагають складної та комплексної архітектури, що є неминучим.


Чесно кажучи, це дуже широка тема, і є багато чудових ідей про те, як структурувати та будувати системи для природної еволюції. На основі свого досвіду я виробив такий підхід:

  1. Майже завжди починається зі стилю монолітної архітектури, оскільки він усуває більшість проблем, які виникають через природу розподілених систем. Також має сенс дотримуватися модульного моноліту, щоб зосередитися на будівництві компонентів із чіткими межами. Застосування підходу на основі компонентів могло б допомогти їм спілкуватися один з одним за допомогою подій, але прямі виклики (він же RPC) спрощують речі на початку. Однак важливо відстежувати залежності між компонентами, оскільки якщо компонент А знає багато про компонент Б, можливо, має сенс об’єднати їх в один.
  2. Коли ви підходите ближче до ситуації, коли вам потрібно масштабувати свою розробку та систему, ви можете розглянути можливість слідувати шаблону Stangler , щоб поступово вилучати компоненти, які потрібно розгортати незалежно або навіть масштабувати відповідно до конкретних вимог.
  3. Тепер, якщо у вас є чітке бачення майбутнього, а це трохи неймовірна удача, ви можете визначитися з бажаною архітектурою. На даний момент ви можете прийняти рішення про перехід до архітектури мікросервісів, також застосувавши підходи оркестровки та хореографії, включивши шаблон CQRS для незалежних масштабних операцій запису та читання, або навіть вирішивши дотримуватися монолітної архітектури, якщо вона відповідає вашим потребам.


Також важливо розуміти цифри та показники, такі як DAU (активні користувачі за день), MAU (активні користувачі за місяць), RPC (запит за секунду) і TPC (транзакція за секунду), оскільки це може допомогти вам зробити вибір, оскільки архітектура для 100 активних користувачів і 100 мільйонів активних користувачів різні.


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

Вибір стека технологій

Вибір стека технологій також є рішенням на макрорівні, оскільки воно впливає на наймання, перспективи природного розвитку системи, масштабованість і продуктивність системи.


Ось список основних міркувань для вибору технологічного стека:

  • Вимоги та складність проекту. Наприклад, простий веб-додаток можна створити за допомогою фреймворку Blazor, якщо ваші розробники мають досвід роботи з ним, але через недостатню зрілість WebAssembly вибір React і Typescript для довгострокового успіху може бути кращим рішенням
  • Потреби в масштабованості та продуктивності. Якщо ви очікуєте отримання великого обсягу трафіку, вибір ASP.NET Core замість Django може бути розумним вибором через його чудову продуктивність у обробці одночасних запитів. Однак це рішення залежить від масштабу трафіку, який ви очікуєте. Якщо вам потрібно керувати потенційно мільярдами запитів з низькою затримкою, наявність Garbage Collection може стати проблемою.
  • Наймання, час розробки та вартість. У більшості випадків це ті фактори, про які ми повинні дбати. Час виходу на ринок, витрати на технічне обслуговування та стабільність найму забезпечують безперешкодні потреби вашого бізнесу.
  • Експертиза та ресурси команди. Набір навичок вашої команди розробників є критичним фактором. Як правило, ефективніше використовувати технології, з якими ваша команда вже знайома, якщо немає вагомих причин інвестувати у вивчення нового стеку.
  • Зрілість. Сильна спільнота та багата екосистема бібліотек та інструментів можуть значно полегшити процес розробки. Популярні технології часто мають кращу підтримку спільноти, що може бути неоціненним для вирішення проблем і пошуку ресурсів. Таким чином, ви можете заощадити ресурси та зосередитися переважно на продукті.
  • Довгострокове технічне обслуговування та підтримка. Розглянемо довгострокову життєздатність технології. Технології, які широко застосовуються та підтримуються, мають меншу ймовірність застаріти та зазвичай регулярно оновлюються та покращуються.


Як наявність кількох стеків технологій може вплинути на розвиток бізнесу?

З одного боку, запровадження ще одного стека може збільшити ваші найми, але з іншого боку, це принесе додаткові витрати на обслуговування, оскільки вам потрібно підтримувати обидва стеки. Отже, як я вже казав раніше, з моєї точки зору, тільки додаткова потреба повинна бути аргументом для включення більшої кількості стеків технологій.


Але як щодо принципу вибору найкращого засобу для конкретної проблеми?

Іноді у вас немає іншого вибору, окрім як запровадити нові інструменти для вирішення конкретної проблеми на основі тих самих міркувань, які згадані вище, у таких випадках має сенс вибрати найкраще рішення.


Створення систем без високого зв'язку з конкретною технологією може бути проблемою. Тим не менш, корисно прагнути до умов, коли система не буде тісно пов’язана з технологіями, і вона не помре, якщо завтра певний фреймворк або інструмент стане вразливим або навіть застарілим.


Ще один важливий аспект пов’язаний із залежностями програмного забезпечення з відкритим кодом і пропрієтарного програмного забезпечення. Власне програмне забезпечення дає вам меншу гнучкість і можливість налаштування. І все ж найнебезпечнішим фактором є прив’язка до постачальника, коли ви стаєте залежними від продуктів, цін, умов і плану постачальника. Це може бути ризиковано, якщо постачальник змінить напрямок, підвищить ціни або припинить випуск продукту. Програмне забезпечення з відкритим кодом зменшує цей ризик, оскільки окрема організація не контролює його. Усунення єдиної точки відмови на всіх рівнях є ключем до створення надійних систем для зростання.

Єдина точка відмови (SPOF)

Єдина точка відмови (SPOF) відноситься до будь-якої частини системи, яка, якщо виходить з ладу, призведе до припинення функціонування всієї системи. Усунення SPOF на всіх рівнях має вирішальне значення для будь-якої системи, яка вимагає високої доступності. Все, включаючи знання, персонал, системні компоненти, хмарні провайдери та інтернет-кабелі, може вийти з ладу.


Є кілька основних методів, які ми можемо застосувати для усунення окремих точок відмови:

  1. Надмірність. Запровадити резервування критичних компонентів. Це означає наявність резервних компонентів, які можуть взяти на себе роботу в разі збою основного компонента. Надлишковість може бути застосована на різних рівнях системи, включаючи апаратне забезпечення (сервери, диски), мережу (зв’язки, комутатори) і програмне забезпечення (бази даних, сервери додатків). Якщо ви розміщуєте все в одному хмарному провайдері та навіть маєте там резервні копії, подумайте про те, щоб створити регулярну додаткову резервну копію в іншому, щоб зменшити втрати в разі аварії.
  2. Центри обробки даних. Розподіліть свою систему між кількома фізичними розташуваннями, такими як центри обробки даних або хмарні регіони. Цей підхід захищає вашу систему від збоїв, пов’язаних із певним місцем, як-от відключення електроенергії чи стихійні лиха.
  3. Перехід після відмови. Застосуйте підхід відновлення після відмови для всіх своїх компонентів (DNS, CDN, балансувальники навантаження, Kubernetes, шлюзи API та бази даних). Оскільки проблеми можуть виникнути несподівано, дуже важливо мати резервний план, щоб швидко замінити будь-який компонент на його клон, якщо це необхідно.
  4. Сервіси високої доступності. Переконайтеся, що ваші сервіси створені таким чином, щоб вони були горизонтально масштабованими та високодоступними з самого початку, дотримуючись таких принципів:
    • Практикуйте службу без збереження стану та уникайте зберігання сеансів користувачів у кеш-пам’яті. Замість цього використовуйте систему розподіленого кешу, таку як Redis.
    • Уникайте опори на хронологічний порядок споживання повідомлення під час розробки логіки.
    • Зведіть до мінімуму критичні зміни, щоб запобігти перешкоджанню споживачам API. Якщо це можливо, вибирайте зміни із зворотною сумісністю. Крім того, враховуйте вартість, оскільки інколи впровадження критичних змін може бути економічно ефективнішим.
    • Включіть виконання міграції в конвеєр розгортання.
    • Створіть стратегію обробки одночасних запитів.
    • Запровадження виявлення, моніторингу та журналювання служб для підвищення надійності та спостережуваності.
    • Розвивайте бізнес-логіку, щоб бути ідемпотентним, визнаючи, що збої мережі неминучі.
  5. Огляд залежності. Регулярно переглядайте та мінімізуйте зовнішні залежності. Кожна зовнішня залежність може створити потенційні SPOF, тому важливо розуміти та зменшувати ці ризики.
  6. Регулярний обмін знаннями. Ніколи не забувайте про важливість поширення знань у вашій організації. Люди можуть бути непередбачуваними, і покладатися на одну людину ризиковано. Заохочуйте членів команди оцифровувати свої знання за допомогою документації. Однак пам’ятайте про надмірне документування. Використовуйте різні інструменти ШІ, щоб спростити цей процес.

Висновок

У цій статті ми розглянули кілька ключових макроаспектів і те, як ми можемо впоратися з їх складністю.


Дякую за читання! До зустрічі наступного разу!

L O A D I N G
. . . comments & more!

About Author

Aleksei HackerNoon profile picture
Aleksei@fairday
Hey, I am Alex, a dedicated Software Development Engineer with experience in the .NET environment and architecture

ПОВІСИТИ БИРКИ

ЦЯ СТАТТЯ БУЛА ПРЕДСТАВЛЕНА В...