paint-brush
Как да се справим със сложността при проектиране на софтуерни системиот@fairday
64,464 показания
64,464 показания

Как да се справим със сложността при проектиране на софтуерни системи

от Aleksei23m2024/02/05
Read on Terminal Reader
Read this story w/o Javascript

Твърде дълго; Чета

Сложността е враг! Нека се научим как да се справяме с това!
featured image - Как да се справим със сложността при проектиране на софтуерни системи
Aleksei HackerNoon profile picture

за какво става въпрос?

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


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


В тази статия ще споделя моя опит с някои от проблемите, които срещнах, докато създавах софтуерни програми.

Какво е междусекторна загриженост?

Ако погледнем в Уикипедия, ще намерим следното определение


При разработката на софтуер, ориентирана към аспекти, междусекторните проблеми са аспекти на програма, които засягат няколко модула, без възможност да бъдат капсулирани в някой от тях. Тези опасения често не могат да бъдат ясно отделени от останалата част от системата както при проектирането, така и при изпълнението и могат да доведат до разпръскване (дублиране на код), заплитане (значителни зависимости между системите) или и двете.


Той подробно описва какво представлява, но искам да го разширя и опростя малко:

Междусекторното безпокойство е концепция или компонент на системата/организацията, който засяга (или „пресича“) много други части.


Най-добрите примери за такива опасения са системната архитектура, регистриране, сигурност, управление на транзакции, телеметрия, дизайн на база данни и има много други. По-късно в тази статия ще разгледаме много от тях.


На ниво код междусекторните проблеми често се прилагат с помощта на техники като аспектно-ориентирано програмиране (AOP) , където тези проблеми са модулирани в отделни компоненти, които могат да се прилагат в цялото приложение. Това държи бизнес логиката изолирана от тези опасения, правейки кода по-четим и поддържаем.

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

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


И така, ще разделя аспектите на макро и микро .


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


Междувременно Микро аспектът е много по-близо до нивото на кода и развитието. Например коя рамка се използва за взаимодействие с базата данни, структурата на проекта от папки и класове или дори конкретни шаблони за проектиране на обекти.


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


В тази статия основният ми фокус ще бъде върху макро аспектите.

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

Организационна структура

Когато току-що започнах да научавам за софтуерната архитектура, прочетох много интересни статии за закона на Конуей и неговото въздействие върху организационната структура. Особено тази . Така че този закон гласи това


Всяка организация, която проектира система (дефинирана широко) ще произведе дизайн, чиято структура е копие на комуникационната структура на организацията.


Винаги съм вярвал, че тази концепция наистина е много универсална и представлява златното правило.


Тогава започнах да научавам подхода на Eric Evans, управляван от домейн дизайн (DDD) за моделиране на системи. Ерик Евънс подчертава важността на идентифицирането на ограничен контекст. Тази концепция включва разделяне на сложен модел на домейн на по-малки, по-управляеми секции, всяка със собствен ограничен набор от знания. Този подход подпомага ефективната екипна комуникация, тъй като намалява необходимостта от задълбочени познания за целия домейн и минимизира превключването на контекста, като по този начин прави разговорите по-ефективни. Превключването на контекст е най-лошото и отнемащо най-много ресурси нещо. Дори компютрите се борят с него. Въпреки че е малко вероятно да се постигне пълна липса на превключване на контекста, смятам, че това е, към което трябва да се стремим.


Fantasy about keeping in mind a lot of bounded contexts

Връщайки се към закона на Конуей, открих няколко проблема с него.


Първият проблем, с който се сблъсках със закона на Конуей, който предполага, че дизайнът на системата отразява организационната структура, е потенциалът за формиране на сложни и всеобхватни ограничени контексти. Тази сложност възниква, когато организационната структура не е приведена в съответствие с границите на домейна, което води до ограничени контексти, които са силно взаимозависими и заредени с информация. Това води до често превключване на контекста за екипа за разработка.


Друг проблем е, че организационната терминология изтича на ниво код. Когато организационните структури се променят, това налага модификации на кодовата база, което отнема ценни ресурси.


По този начин, следването на Inverse Conway Maneuver помага за изграждането на система и организация, които насърчават желаната софтуерна архитектура. Заслужава обаче да се отбележи, че този подход няма да работи много добре във вече формирана архитектура и структури, тъй като промените на този етап са продължителни, но е изключително ефективен при стартиращи фирми, тъй като те бързо въвеждат всякакви промени.

Голяма кална топка

Този модел или „анти-модел“ управлява изграждането на система без никаква архитектура. Няма правила, няма граници и няма стратегия за това как да се контролира неизбежната нарастваща сложност. Сложността е най-страшният враг в пътуването на изграждането на софтуерни системи.


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. Редовно споделяне на знания. Никога не забравяйте важността на разпространението на знания във вашата организация. Хората могат да бъдат непредсказуеми и разчитането на един човек е рисковано. Насърчете членовете на екипа да дигитализират знанията си чрез документация. Имайте предвид обаче прекомерното документиране. Използвайте различни AI инструменти, за да опростите този процес.

Заключение

В тази статия разгледахме няколко ключови макро аспекта и как можем да се справим с тяхната сложност.


Благодаря ви, че прочетохте! Ще се видим следващия път!

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

ЗАКАЧВАЙТЕ ЕТИКЕТИ

ТАЗИ СТАТИЯ Е ПРЕДСТАВЕНА В...