paint-brush
Ako sa vysporiadať so zložitosťou pri navrhovaní softvérových systémovpodľa@fairday
64,370 čítania
64,370 čítania

Ako sa vysporiadať so zložitosťou pri navrhovaní softvérových systémov

podľa Aleksei23m2024/02/05
Read on Terminal Reader
Read this story w/o Javascript

Príliš dlho; Čítať

Zložitosť je nepriateľ! Naučme sa, ako sa s tým vysporiadať!
featured image - Ako sa vysporiadať so zložitosťou pri navrhovaní softvérových systémov
Aleksei HackerNoon profile picture

O čo vlastne ide?

Každý deň, každú chvíľu počas našej inžinierskej kariéry sa stretávame s množstvom rôznych problémov rôznej zložitosti a situácií, kedy potrebujeme urobiť rozhodnutie alebo ho odložiť z dôvodu nedostatku dát. Kedykoľvek budujeme nové služby, budujeme infraštruktúru alebo dokonca formujeme vývojové procesy, dotýkame sa obrovského sveta rôznych výziev.


Je náročné a možno aj nemožné vymenovať všetky problémy. S niektorými z týchto problémov sa stretnete iba vtedy, ak pracujete v špecifickom výklenku. Na druhej strane je veľa vecí, ktoré musíme všetci pochopiť, ako ich vyriešiť, pretože sú kľúčové pre budovanie IT systémov. S vysokou pravdepodobnosťou sa s nimi stretnete vo všetkých projektoch.


V tomto článku sa podelím o svoje skúsenosti s niektorými problémami, s ktorými som sa stretol pri vytváraní softvérových programov.

Čo je to prierezový záujem?

Ak sa pozrieme do Wikipédie, nájdeme nasledujúcu definíciu


V aspektovo orientovanom vývoji softvéru sú prierezové problémy aspektmi programu, ktoré ovplyvňujú niekoľko modulov bez možnosti byť zapuzdrený v niektorom z nich. Tieto obavy sa často nedajú čisto dekomponovať od zvyšku systému pri návrhu aj implementácii a môžu viesť buď k rozptýleniu (duplikácia kódu), zamotaniu (významné závislosti medzi systémami) alebo k obom.


Veľmi to popisuje, čo to je, ale chcem to trochu rozšíriť a zjednodušiť:

Prierezový záujem je koncept alebo komponent systému/organizácie, ktorý ovplyvňuje (alebo „presahuje“) mnoho iných častí.


Najlepšími príkladmi takýchto problémov sú architektúra systému, protokolovanie, bezpečnosť, správa transakcií, telemetria, návrh databázy a existuje mnoho ďalších. Viacerým z nich sa budeme venovať neskôr v tomto článku.


Na úrovni kódu sa prierezové problémy často implementujú pomocou techník, ako je programovanie orientované na aspekty (AOP) , kde sú tieto problémy modularizované do samostatných komponentov, ktoré možno aplikovať v celej aplikácii. To udržuje obchodnú logiku izolovanú od týchto obáv, vďaka čomu je kód čitateľnejší a udržiavateľnejší.

Klasifikácia aspektov

Existuje mnoho možných spôsobov, ako klasifikovať aspekty ich segmentovaním s rôznymi vlastnosťami, ako je rozsah, veľkosť, funkčnosť, dôležitosť, cieľ a iné, ale v tomto článku použijem jednoduchú klasifikáciu rozsahu. Myslím tým, kam smeruje tento špecifický aspekt, či už ide o celú organizáciu, konkrétny systém alebo špecifický prvok tohto systému.


Takže rozdelím aspekty na makro a mikro .


Makro aspektom mám na mysli najmä úvahy, ktoré sledujeme pre celý systém, ako je zvolená architektúra systému a jeho dizajn (monolitický, mikroslužby, servisne orientovaná architektúra), technologický zásobník, organizačná štruktúra atď. Makro aspekty súvisia najmä so strategickými a vysokoúrovňovými rozhodnutia.


Medzitým je aspekt Micro oveľa bližšie k úrovni kódu a vývoju. Napríklad, ktorý rámec sa používa na interakciu s databázou, štruktúra projektu priečinkov a tried alebo dokonca konkrétne vzory návrhu objektov.


Aj keď táto klasifikácia nie je ideálna, pomáha štruktúrovať pochopenie možných problémov a dôležitosti a vplyvu riešení, ktoré na ne aplikujeme.


V tomto článku sa zameriam predovšetkým na makro aspekty.

Makro aspekty

Organizačná štruktúra

Keď som sa práve začal učiť o softvérovej architektúre, čítal som veľa zaujímavých článkov o Conwayovom zákone a jeho vplyve na organizačnú štruktúru. Najmä tento . Tak to hovorí tento zákon


Akákoľvek organizácia, ktorá navrhuje systém (všeobecne definovaný), vytvorí návrh, ktorého štruktúra je kópiou komunikačnej štruktúry organizácie.


Vždy som veril, že tento koncept je skutočne veľmi univerzálny a predstavuje Zlaté pravidlo.


Potom som sa začal učiť prístup Erica Evansa Domain-Driven Design (DDD) pre modelovanie systémov. Eric Evans zdôrazňuje dôležitosť identifikácie ohraničeného kontextu. Tento koncept zahŕňa rozdelenie komplexného modelu domény na menšie, lepšie spravovateľné časti, z ktorých každá má svoj vlastný obmedzený súbor znalostí. Tento prístup pomáha pri efektívnej tímovej komunikácii, pretože znižuje potrebu rozsiahlych znalostí o celej doméne a minimalizuje prepínanie kontextu, čím sa konverzácie zefektívňujú. Prepínanie kontextu je najhoršia a najnáročnejšia vec vôbec. Dokonca aj počítače s tým zápasia. Hoci je nepravdepodobné, že sa dosiahne úplná absencia prepínania kontextu, myslím si, že o to by sme sa mali snažiť.


Fantasy about keeping in mind a lot of bounded contexts

Keď sa vrátim ku Conwayovmu zákonu, našiel som v ňom niekoľko problémov.


Prvým problémom, s ktorým som sa stretol pri Conwayovom zákone, ktorý naznačuje, že návrh systému odráža organizačnú štruktúru, je potenciál na vytváranie zložitých a komplexných ohraničených súvislostí. Táto zložitosť vzniká, keď organizačná štruktúra nie je zosúladená s hranicami domény, čo vedie k ohraničeným kontextom, ktoré sú navzájom silne závislé a nabité informáciami. Vedie to k častému prepínaniu kontextu pre vývojový tím.


Ďalším problémom je, že organizačná terminológia uniká na úroveň kódu. Keď sa zmenia organizačné štruktúry, vyžadujú si to úpravy kódovej základne, čo spotrebúva cenné zdroje.


Nasledovanie Inverse Conway Maneuver teda pomáha vybudovať systém a organizáciu, ktoré podporujú požadovanú softvérovú architektúru. Je však pozoruhodné povedať, že tento prístup nebude fungovať veľmi dobre v už vytvorenej architektúre a štruktúrach, pretože zmeny v tejto fáze sú predĺžené, ale výnimočne funguje v startupoch, pretože rýchlo zavádzajú akékoľvek zmeny.

Veľká guľa blata

Tento vzor alebo „anti-vzor“ poháňa budovanie systému bez akejkoľvek architektúry. Neexistujú žiadne pravidlá, žiadne hranice a žiadna stratégia, ako kontrolovať nevyhnutnú rastúcu zložitosť. Zložitosť je najväčším nepriateľom na ceste budovania softvérových systémov.


Entertaining illustration made by ChatGPT

Aby sme sa vyhli konštrukcii takéhoto typu systému, musíme dodržiavať špecifické pravidlá a obmedzenia.

Architektúra systému

Existuje nespočetné množstvo definícií softvérovej architektúry. Mnohé z nich sa mi páčia, pretože pokrývajú rôzne aspekty. Aby sme však mohli uvažovať o architektúre, musíme si niektoré z nich prirodzene vytvoriť v mysli. A je pozoruhodné povedať, že táto definícia sa môže vyvíjať. Tak aspoň zatiaľ mám pre seba nasledujúci popis.


Softvérová architektúra je o rozhodnutiach a rozhodnutiach, ktoré robíte každý deň a ktoré ovplyvňujú vybudovaný systém.


Aby ste sa mohli rozhodovať, musíte mať vo „vreci“ princípy a vzorce riešenia vznikajúcich problémov, je tiež nevyhnutné uviesť, že pochopenie požiadaviek je kľúčom k budovaniu toho, čo podnik potrebuje. Niekedy však požiadavky nie sú transparentné alebo dokonca nie sú definované, v tomto prípade je lepšie počkať na ďalšie objasnenie alebo sa spoľahnúť na svoje skúsenosti a dôverovať svojej intuícii. Ale aj tak sa nemôžete správne rozhodovať, ak nemáte zásady a vzorce, na ktoré sa môžete spoľahnúť. Tu sa dostávam k definícii štýlu softvérovej architektúry.


Štýl softvérovej architektúry je súbor princípov a vzorov, ktoré určujú, ako vytvárať softvér.


Existuje veľa rôznych architektonických štýlov zameraných na rôzne strany plánovanej architektúry a aplikácia viacerých z nich naraz je normálna situácia.


Napríklad ako:

  1. Monolitická architektúra

  2. Dizajn riadený doménou

  3. Na báze komponentov

  4. Mikroslužby

  5. Potrubie a filtre

  6. Riadené udalosťami

  7. Mikrokernel

  8. Orientovaný na služby


a tak ďalej…


Samozrejme, majú svoje výhody a nevýhody, ale najdôležitejšia vec, ktorú som sa naučil, je, že architektúra sa vyvíja postupne v závislosti od skutočných problémov. Počnúc monolitickou architektúrou je skvelá voľba na zníženie prevádzkovej zložitosti, veľmi pravdepodobne bude táto architektúra vyhovovať vašim potrebám aj po dosiahnutí fázy Product-market Fit (PMI) pri zostavovaní produktu. Vo väčšom rozsahu môžete zvážiť prechod na prístup riadený udalosťami a mikroslužby na dosiahnutie nezávislého nasadenia, heterogénneho prostredia technologického zásobníka a menej prepojenej architektúry (a medzičasom menej transparentnej kvôli povahe prístupov riadených udalosťami a pub-sub prístupov, ak tieto sú prijaté). Jednoduchosť a efektívnosť sú si blízke a majú na seba veľký vplyv. Zložité architektúry zvyčajne ovplyvňujú rýchlosť vývoja nových funkcií, podporujú a udržiavajú existujúce a spochybňujú prirodzený vývoj systému.


Komplexné systémy však často vyžadujú komplexnú a komplexnú architektúru, čo je nevyhnutné.


Je to skutočne veľmi široká téma a existuje veľa skvelých nápadov o tom, ako štruktúrovať a budovať systémy pre prirodzený vývoj. Na základe mojich skúseností som sa dopracoval k nasledovnému postupu:

  1. Takmer vždy sa začína štýlom monolitickej architektúry, pretože odstraňuje väčšinu problémov, ktoré vznikajú v dôsledku povahy distribuovaných systémov. Tiež má zmysel sledovať modulárny monolit a zamerať sa na stavebné komponenty s jasnými hranicami. Aplikácia prístupu založeného na komponentoch im môže pomôcť komunikovať medzi sebou pomocou udalostí, ale priame volania (známe ako RPC) zjednodušujú veci na začiatku. Je však dôležité sledovať závislosti medzi komponentmi, pretože ak komponent A vie veľa o komponente B, možno má zmysel ich zlúčiť do jedného.
  2. Keď sa priblížite k situácii, keď potrebujete škálovať svoj vývoj a systém, môžete zvážiť postup podľa vzoru Stangler , aby ste postupne extrahovali komponenty, ktoré je potrebné nasadiť nezávisle alebo dokonca škálovať podľa špecifických požiadaviek.
  3. Teraz, ak máte jasnú víziu budúcnosti, čo je trochu neuveriteľné šťastie, môžete sa rozhodnúť pre požadovanú architektúru. V tejto chvíli by ste sa mohli rozhodnúť pre prechod na architektúru mikroslužieb tým, že použijete aj prístupy Orchestration a Choreography, začleníte vzor CQRS pre operácie nezávislej mierky zápisu a čítania, alebo sa dokonca rozhodnete zostať pri monolitickej architektúre, ak to vyhovuje vašim potrebám.


Je tiež dôležité porozumieť číslam a metrikám, ako sú DAU (denní aktívni používatelia), MAU (mesační aktívni používatelia), RPC (požiadavka za sekundu) a TPC (transakcia za sekundu), pretože vám môžu pomôcť pri výbere, pretože architektúra pre 100 aktívnych používateľov a 100 miliónov aktívnych používateľov sú rozdielne.


Na záver by som povedal, že architektúra má významný vplyv na úspech produktu. Pri škálovaní je potrebná zle navrhnutá architektúra produktov, čo s veľkou pravdepodobnosťou vedie k zlyhaniu, pretože zákazníci nebudú čakať, kým škálujete systém, ale vyberú si konkurenta, takže musíme predbehnúť potenciálne škálovanie. Aj keď pripúšťam, že niekedy to nemôže byť štíhly prístup, myšlienkou je mať škálovateľný, ale ešte nie škálovaný systém. Na druhej strane, mať veľmi komplikovaný a už škálovaný systém bez zákazníkov alebo plánov na získanie mnohých z nich vás bude stáť peniaze na vašom podnikaní zadarmo.

Výber technologického zásobníka

Výber technologického zásobníka je tiež rozhodnutím na makroúrovni, pretože ovplyvňuje prijímanie zamestnancov, perspektívy prirodzeného vývoja systému, škálovateľnosť a výkon systému.


Toto je zoznam základných úvah pri výbere technologického zásobníka:

  • Požiadavky a zložitosť projektu. Napríklad jednoduchá webová aplikácia môže byť zostavená s rámcom Blazor, ak s ním vaši vývojári majú skúsenosti, ale kvôli nedostatočnej vyspelosti WebAssembly môže byť výber React a Typescript pre dlhodobý úspech lepším rozhodnutím.
  • Škálovateľnosť a požiadavky na výkon. Ak očakávate, že budete prijímať veľké množstvo návštevnosti, voľba pre ASP.NET Core cez Django by mohla byť rozumnou voľbou kvôli jeho vynikajúcemu výkonu pri spracovávaní súbežných požiadaviek. Toto rozhodnutie však závisí od rozsahu návštevnosti, ktorú očakávate. Ak potrebujete spravovať potenciálne miliardy žiadostí s nízkou latenciou, prítomnosť funkcie Garbage Collection môže byť výzvou.
  • Nájom, čas vývoja a náklady. Vo väčšine prípadov sú to faktory, o ktoré sa musíme starať. Čas uvedenia na trh, náklady na údržbu a stabilita náboru riadia vaše obchodné potreby bez prekážok.
  • Odbornosť tímu a zdroje. Zručnosti vášho vývojového tímu sú kritickým faktorom. Vo všeobecnosti je efektívnejšie používať technológie, ktoré váš tím už pozná, pokiaľ neexistuje pádny dôvod investovať do učenia sa nového zásobníka.
  • Zrelosť. Silná komunita a bohatý ekosystém knižníc a nástrojov môžu výrazne uľahčiť proces vývoja. Populárne technológie majú často lepšiu podporu komunity, ktorá môže byť neoceniteľná pri riešení problémov a hľadaní zdrojov. Môžete tak ušetriť zdroje a zamerať sa hlavne na produkt.
  • Dlhodobá údržba a podpora. Zvážte dlhodobú životaschopnosť technológie. Je menej pravdepodobné, že technológie, ktoré sú široko prijímané a podporované, zastarajú a vo všeobecnosti dostávajú pravidelné aktualizácie a vylepšenia.


Ako môže mať viacero technologických balíkov vplyv na rast podnikania?

Z jednej perspektívy by zavedenie jedného ďalšieho balíka mohlo rozšíriť váš nábor, no na druhej strane to prináša dodatočné náklady na údržbu, pretože musíte podporovať oba balíky. Takže, ako som už povedal, z môjho pohľadu by argumentom pre začlenenie viacerých technologických balíkov mala byť len dodatočná potreba.


Aký je však princíp výberu najlepšieho nástroja pre konkrétny problém?

Niekedy nemáte inú možnosť, ako priniesť nové nástroje na vyriešenie konkrétneho problému na základe rovnakých úvah, ako je uvedené vyššie, v takýchto prípadoch má zmysel vybrať to najlepšie riešenie.


Vytvorenie systémov bez vysokej väzby na špecifickú technológiu môže byť výzvou. Napriek tomu je užitočné usilovať sa o stav, keď systém nie je pevne spojený s technológiou a nezomrie, ak sa zajtra konkrétny rámec alebo nástroj stane zraniteľným alebo dokonca zastaraným.


Ďalšie dôležité hľadisko súvisí so závislosťami open-source a proprietárneho softvéru. Proprietárny softvér vám poskytuje menšiu flexibilitu a možnosť prispôsobenia. Najnebezpečnejším faktorom je však zablokovanie predajcu, pri ktorom sa stávate závislými od produktov, cien, podmienok a plánu predajcu. To môže byť riskantné, ak predajca zmení smer, zvýši ceny alebo prestane vyrábať produkt. Softvér s otvoreným zdrojovým kódom toto riziko znižuje, pretože ho nekontroluje jediný subjekt. Odstránenie jediného bodu zlyhania na všetkých úrovniach je kľúčom k vybudovaniu spoľahlivých systémov pre rast.

Jediný bod zlyhania (SPOF)

Jediný bod zlyhania (SPOF) označuje akúkoľvek časť systému, ktorá, ak zlyhá, spôsobí, že celý systém prestane fungovať. Odstránenie SPOF na všetkých úrovniach je rozhodujúce pre každý systém vyžadujúci vysokú dostupnosť. Všetko, vrátane znalostí, personálu, systémových komponentov, poskytovateľov cloudu a internetových káblov, môže zlyhať.


Existuje niekoľko základných techník, ktoré môžeme použiť na odstránenie jednotlivých bodov zlyhania:

  1. Redundancia. Implementujte redundanciu pre kritické komponenty. To znamená mať záložné komponenty, ktoré môžu prevziať kontrolu, ak primárny komponent zlyhá. Redundanciu možno použiť naprieč rôznymi vrstvami systému vrátane hardvéru (servery, disky), siete (odkazy, prepínače) a softvéru (databázy, aplikačné servery). Ak všetko hosťujete u jedného poskytovateľa cloudu a dokonca tam máte zálohy, zvážte vytvorenie pravidelnej dodatočnej zálohy v inom, aby ste znížili svoje stratené náklady v prípade katastrofy.
  2. Dátové centrá. Distribuujte svoj systém na viacerých fyzických miestach, ako sú dátové centrá alebo cloudové oblasti. Tento prístup chráni váš systém pred poruchami špecifickými pre dané miesto, ako sú výpadky prúdu alebo prírodné katastrofy.
  3. Failover. Použite prístup prepnutia pri zlyhaní pre všetky vaše komponenty (DNS, CDN, nástroje na vyrovnávanie zaťaženia, Kubernetes, brány API a databázy). Keďže problémy môžu nastať neočakávane, je dôležité mať záložný plán na rýchle nahradenie akéhokoľvek komponentu jeho klonom.
  4. Služby vysokej dostupnosti. Zaistite, aby boli vaše služby od začiatku horizontálne škálovateľné a vysoko dostupné, a to dodržiavaním nasledujúcich zásad:
    • Precvičte si stav služby a vyhnite sa ukladaniu používateľských relácií do vyrovnávacej pamäte v pamäti. Namiesto toho použite distribuovaný systém vyrovnávacej pamäte, ako je napríklad Redis.
    • Pri vývoji logiky sa vyhnite spoliehaniu sa na chronologické poradie spotreby správ.
    • Minimalizujte prerušujúce zmeny, aby ste zabránili narušeniu používania API. Ak je to možné, rozhodnite sa pre spätne kompatibilné zmeny. Zvážte aj náklady, pretože niekedy môže byť implementácia zlomovej zmeny nákladovo efektívnejšia.
    • Zahrňte vykonávanie migrácie do procesu nasadenia.
    • Vytvorte stratégiu na spracovanie súbežných požiadaviek.
    • Implementujte vyhľadávanie, monitorovanie a protokolovanie služieb na zvýšenie spoľahlivosti a pozorovateľnosti.
    • Rozvíjajte obchodnú logiku tak, aby bola idempotentná a uznávajte, že zlyhania siete sú nevyhnutné.
  5. Preskúmanie závislosti. Pravidelne kontrolujte a minimalizujte externé závislosti. Každá externá závislosť môže predstavovať potenciálne SPOF, takže je nevyhnutné pochopiť a zmierniť tieto riziká.
  6. Pravidelné zdieľanie vedomostí. Nikdy nezabudnite na dôležitosť šírenia vedomostí vo vašej organizácii. Ľudia môžu byť nepredvídateľní a spoliehať sa na jedného jednotlivca je riskantné. Povzbudzujte členov tímu, aby digitalizovali svoje znalosti prostredníctvom dokumentácie. Dávajte si však pozor na prílišnú dokumentáciu. Na zjednodušenie tohto procesu použite rôzne nástroje AI.

Záver

V tomto článku sme sa venovali niekoľkým kľúčovým makro aspektom a tomu, ako sa môžeme vysporiadať s ich zložitosťou.


Ďakujem za prečítanie! Uvidíme sa nabudúce!