paint-brush
Kako se nositi sa složenošću prilikom projektiranja softverskih sustavapo@fairday
64,488 čitanja
64,488 čitanja

Kako se nositi sa složenošću prilikom projektiranja softverskih sustava

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

Predugo; Čitati

Složenost je neprijatelj! Naučimo kako se nositi s tim!
featured image - Kako se nositi sa složenošću prilikom projektiranja softverskih sustava
Aleksei HackerNoon profile picture

O čemu se radi?

Svaki dan, svaki trenutak tijekom naše inženjerske karijere susrećemo se s mnogo različitih problema različite složenosti i situacijama u kojima trebamo donijeti odluku ili je odgoditi zbog nedostatka podataka. Kad god gradimo nove usluge, gradimo infrastrukturu ili čak formiramo razvojne procese, dotičemo se golemog svijeta raznih izazova.


Zahtjevno je, a možda i nemoguće, nabrojati sve probleme. Na neke od ovih problema ćete se susresti samo ako radite u određenoj niši. S druge strane, postoje mnogi koje svi moramo razumjeti kako riješiti jer su ključni za izgradnju IT sustava. S velikom vjerojatnošću ćete ih susresti u svim projektima.


U ovom ću članku podijeliti svoja iskustva s nekim problemima na koje sam naišao pri izradi softverskih programa.

Što je međusektorska briga?

Ako pogledamo Wikipediju, pronaći ćemo sljedeću definiciju


U razvoju softvera orijentiranom na aspekte, međusektorski problemi su aspekti programa koji utječu na nekoliko modula, bez mogućnosti da budu zatvoreni u bilo koji od njih. Ovi problemi se često ne mogu jasno razdvojiti od ostatka sustava u dizajnu i implementaciji, i mogu rezultirati raspršivanjem (dupliciranjem koda), petljanjem (značajne ovisnosti između sustava) ili oboje.


Uvelike opisuje što je to, ali želim ga malo proširiti i pojednostaviti:

Međusektorski problem je koncept ili komponenta sustava/organizacije koja utječe (ili 'presijeca') mnoge druge dijelove.


Najbolji primjeri takvih problema su arhitektura sustava, bilježenje, sigurnost, upravljanje transakcijama, telemetrija, dizajn baze podataka i mnogi drugi. Razradit ćemo mnoge od njih kasnije u ovom članku.


Na razini koda, međusektorski problemi često se implementiraju pomoću tehnika kao što je aspektno orijentirano programiranje (AOP) , gdje su ti problemi modularizirani u zasebne komponente koje se mogu primijeniti u cijeloj aplikaciji. Time se poslovna logika drži izoliranom od ovih problema, čineći kod čitljivijim i lakšim za održavanje.

Klasifikacija aspekata

Postoji mnogo mogućih načina za klasificiranje aspekata njihovim segmentiranjem s različitim svojstvima poput opsega, veličine, funkcionalnosti, važnosti, cilja i drugih, ali u ovom ću članku koristiti jednostavnu klasifikaciju opsega. Pod ovim mislim kamo je ovaj specifični aspekt usmjeren, bilo da se radi o cijeloj organizaciji, određenom sustavu ili specifičnom elementu tog sustava.


Dakle, podijelit ću aspekte na makro i mikro .


Pod makro aspektom mislim uglavnom na razmatranja koja slijedimo za cijeli sustav kao što je odabrana arhitektura sustava i njegov dizajn (monolitni, mikroservisi, servisno orijentirana arhitektura), tehnološki stog, organizacijska struktura, itd. Makro aspekti se odnose uglavnom na stratešku i visoku razinu odluke.


U međuvremenu, mikro aspekt je mnogo bliži razini koda i razvoju. Na primjer, koji se okvir koristi za interakciju s bazom podataka, strukturu projekta mapa i klasa ili čak specifične uzorke dizajna objekata.


Iako ova klasifikacija nije idealna, pomaže u strukturiranju razumijevanja mogućih problema te važnosti i utjecaja rješenja koja na njih primjenjujemo.


U ovom članku, moj primarni fokus bit će na makro aspektima.

Makro aspekti

Organizacijska struktura

Kad sam tek počeo učiti o arhitekturi softvera, pročitao sam mnogo zanimljivih članaka o Conwayevom zakonu i njegovom utjecaju na organizacijsku strukturu. Pogotovo ovaj . Dakle, ovaj zakon to kaže


Svaka organizacija koja dizajnira sustav (široko definiran) proizvest će dizajn čija je struktura kopija komunikacijske strukture organizacije.


Uvijek sam vjerovao da je ovaj koncept doista vrlo univerzalan i da predstavlja Zlatno pravilo.


Zatim sam počeo učiti Erica Evansa o pristupu Domain-Driven Design (DDD) za modeliranje sustava. Eric Evans naglašava važnost identifikacije ograničenog konteksta. Ovaj koncept uključuje podjelu složenog modela domene na manje odjeljke kojima je lakše upravljati, a svaki sa svojim ograničenim skupom znanja. Ovaj pristup pomaže u učinkovitoj timskoj komunikaciji jer smanjuje potrebu za opsežnim poznavanjem cijele domene i minimizira promjenu konteksta, čineći razgovore učinkovitijima. Promjena konteksta najgora je stvar koja zahtijeva najviše resursa. Čak se i računala bore s tim. Iako je malo vjerojatno da će postići potpuni izostanak prebacivanja konteksta, smatram da je to ono čemu bismo trebali težiti.


Fantasy about keeping in mind a lot of bounded contexts

Vraćajući se na Conwayev zakon, naišao sam na nekoliko problema s njim.


Prvo pitanje s kojim sam se susreo kod Conwayevog zakona, koji sugerira da dizajn sustava odražava organizacijsku strukturu, je potencijal za formiranje složenih i sveobuhvatnih ograničenih konteksta. Ova složenost nastaje kada organizacijska struktura nije usklađena s granicama domene, što dovodi do ograničenih konteksta koji su u velikoj mjeri međuovisni i krcati informacijama. To dovodi do čestog mijenjanja konteksta za razvojni tim.


Drugi problem je da organizacijska terminologija curi na razinu koda. Kada se organizacijske strukture mijenjaju, to zahtijeva modifikacije baze koda, trošeći vrijedne resurse.


Stoga, slijeđenje inverznog Conwayevog manevra pomaže u izgradnji sustava i organizacije koji potiču željenu softversku arhitekturu. Međutim, važno je reći da ovaj pristup neće dobro funkcionirati u već formiranoj arhitekturi i strukturama budući da su promjene u ovoj fazi dugotrajne, ali je iznimno uspješan u startupima jer oni brzo uvode bilo kakve promjene.

Velika lopta od blata

Ovaj obrazac ili "anti-obrazac" pokreće izgradnju sustava bez ikakve arhitekture. Nema pravila, granica i strategije o tome kako kontrolirati neizbježnu rastuću složenost. Složenost je najstrašniji neprijatelj na putu izgradnje softverskih sustava.


Entertaining illustration made by ChatGPT

Kako bismo izbjegli izgradnju takve vrste sustava, moramo slijediti određena pravila i ograničenja.

Arhitektura sustava

Postoje bezbrojne definicije za softversku arhitekturu. Mnogi od njih mi se sviđaju jer pokrivaju različite aspekte toga. Međutim, da bismo mogli rasuđivati o arhitekturi, moramo prirodno oblikovati neke od njih u našim umovima. I vrijedno je pažnje reći da se ova definicija može razvijati. Dakle, barem za sada, za sebe imam sljedeći opis.


Softverska arhitektura odnosi se na odluke i izbore koje donosite svaki dan, a koje utječu na izgrađeni sustav.


Za donošenje odluka morate imati u svojoj “torbi” načela i obrasce za rješavanje nastalih problema, također je bitno navesti da je razumijevanje zahtjeva ključno za izgradnju onoga što poduzeću treba. Međutim, ponekad zahtjevi nisu transparentni ili čak nisu definirani, u ovom slučaju, bolje je pričekati da dobijete dodatna pojašnjenja ili se osloniti na svoje iskustvo i vjerovati svojoj intuiciji. Ali svejedno, ne možete donositi odluke kako treba ako nemate principe i obrasce na koje se možete osloniti. Tu dolazim do definicije stila softverske arhitekture.


Stil arhitekture softvera je skup principa i obrazaca koji određuju kako izgraditi softver.


Postoji mnogo različitih arhitektonskih stilova usmjerenih na različite strane planirane arhitekture, a primjena više njih odjednom je normalna situacija.


Na primjer, kao što su:

  1. Monolitna arhitektura

  2. Dizajn usmjeren na domenu

  3. Na temelju komponenti

  4. Mikroservisi

  5. Cijev i filteri

  6. Vođen događajima

  7. Mikrojezgra

  8. Orijentiran na usluge


i tako dalje…


Naravno, imaju svoje prednosti i nedostatke, ali najvažnije što sam naučio jest da se arhitektura razvija postupno ovisno o stvarnim problemima. Započinjanje s monolitnom arhitekturom odličan je izbor za smanjenje operativnih složenosti, vrlo vjerojatno će ova arhitektura odgovarati vašim potrebama čak i nakon dostizanja faze prilagođavanja proizvoda tržištu (PMI) u izgradnji proizvoda. U razmjeru, možete razmisliti o prelasku na pristup vođen događajima i mikroservisima za postizanje neovisne implementacije, heterogenog okruženja tehnološkog skupa i manje povezane arhitekture (i manje transparentne u međuvremenu zbog prirode pristupa vođenih događajima i pub-sub pristupa ako te se usvajaju). Jednostavnost i učinkovitost su bliske i imaju veliki utjecaj jedna na drugu. Obično komplicirane arhitekture utječu na brzinu razvoja novih značajki, podržavaju i održavaju postojeće i osporavaju prirodnu evoluciju sustava.


Međutim, složeni sustavi često zahtijevaju složenu i sveobuhvatnu arhitekturu, što je neizbježno.


Iskreno, ovo je vrlo široka tema i postoji mnogo sjajnih ideja o tome kako strukturirati i izgraditi sustave za prirodnu evoluciju. Na temelju svog iskustva razradio sam sljedeći pristup:

  1. Gotovo uvijek počinje s monolitnim stilom arhitekture budući da eliminira većinu problema koji nastaju zbog prirode distribuiranih sustava. Također ima smisla slijediti modularni monolit kako bi se usredotočili na građevne komponente s jasnim granicama. Primjena pristupa temeljenog na komponentama mogla bi im pomoći u međusobnoj komunikaciji korištenjem događaja, ali izravni pozivi (aka RPC) pojednostavljuju stvari u početku. Međutim, važno je pratiti ovisnosti između komponenti jer ako komponenta A zna mnogo o komponenti B, možda ima smisla spojiti ih u jednu.
  2. Kada dođete bliže situaciji kada trebate skalirati svoj razvoj i sustav, mogli biste razmisliti o praćenju Stangler obrasca za postupno izdvajanje komponenti koje je potrebno samostalno implementirati ili čak skalirati s određenim zahtjevima.
  3. Sada, ako imate jasnu viziju budućnosti, što je nevjerojatna sreća, mogli biste se odlučiti za željenu arhitekturu. U ovom trenutku možete odlučiti o prijelazu na arhitekturu mikroservisa također primjenom pristupa orkestracije i koreografije, uključivanjem CQRS obrasca za nezavisne operacije pisanja i čitanja skale ili čak odlučiti da se držite monolitne arhitekture ako odgovara vašim potrebama.


Također je bitno razumjeti brojke i metrike kao što su DAU (Dnevni aktivni korisnici), MAU (Mjesečni aktivni korisnici), RPC (Zahtjevi po sekundi) i TPC (Transakcije po sekundi) jer bi vam to moglo pomoći u donošenju odluka jer arhitektura za 100 aktivnih korisnika i 100 milijuna aktivnih korisnika razlikuju se.


Za kraj bih rekao da arhitektura ima značajan utjecaj na uspjeh proizvoda. U skaliranju je potrebna loše dizajnirana arhitektura za proizvode, što vrlo vjerojatno dovodi do neuspjeha jer korisnici neće čekati dok skalirate sustav, oni će izabrati konkurenta, tako da moramo biti ispred potencijalnog skaliranja. Iako priznajem da ponekad to ne može biti lean pristup, ideja je imati skalabilan, ali ne već skaliran sustav. S druge strane, posjedovanje vrlo kompliciranog i već skaliranog sustava bez kupaca ili planova za njihovo pridobijanje neće vas koštati novca za vaše poslovanje uzalud.

Odabir tehnološkog skupa

Odabir tehnološkog skupa također je odluka na makrorazini budući da utječe na zapošljavanje, perspektive prirodne evolucije sustava, skalabilnost i performanse sustava.


Ovo je popis osnovnih razmatranja za odabir tehnološkog skupa:

  • Zahtjevi i složenost projekta. Na primjer, jednostavna web aplikacija može se izgraditi s okvirom Blazor ako vaši programeri imaju iskustva s njim, ali zbog nedostatka zrelosti WebAssemblija, odabir Reacta i Typescripta za dugoročni uspjeh mogla bi biti bolja odluka
  • Skalabilnost i potrebe za performansama. Ako očekujete da ćete primiti veliku količinu prometa, odabir ASP.NET Core umjesto Djanga mogao bi biti mudar izbor zbog njegovih vrhunskih performansi u rukovanju istodobnim zahtjevima. Međutim, ova odluka ovisi o opsegu prometa koji očekujete. Ako trebate upravljati potencijalno milijardama zahtjeva s malom latencijom, prisutnost Garbage Collectiona mogla bi biti izazov.
  • Zapošljavanje, vrijeme razvoja i trošak. U većini slučajeva to su čimbenici o kojima trebamo voditi računa. Vrijeme do tržišta, troškovi održavanja i stabilnost zapošljavanja pokreću vaše poslovne potrebe bez prepreka.
  • Timska stručnost i resursi. Skup vještina vašeg razvojnog tima je kritičan faktor. Općenito je učinkovitije koristiti tehnologije s kojima je vaš tim već upoznat osim ako ne postoji jak razlog za ulaganje u učenje novog skupa.
  • Zrelost. Snažna zajednica i bogat ekosustav knjižnica i alata mogu uvelike olakšati proces razvoja. Popularne tehnologije često imaju bolju podršku zajednice, što može biti neprocjenjivo za rješavanje problema i pronalaženje resursa. Tako možete uštedjeti resurse i fokusirati se uglavnom na proizvod.
  • Dugoročno održavanje i podrška. Razmotrite dugoročnu održivost tehnologije. Manje je vjerojatno da će tehnologije koje su široko prihvaćene i podržane zastarjeti i općenito se redovito ažuriraju i poboljšavaju.


Kako bi višestruki tehnološki paketi mogli utjecati na rast poslovanja?

Iz jedne perspektive, uvođenje još jednog skupa moglo bi povećati vaše zapošljavanje, ali s druge strane, donosi dodatne troškove održavanja budući da morate podržavati oba skupa. Dakle, kao što sam već rekao, s moje točke gledišta, samo bi dodatna potreba trebala biti argument za uključivanje više tehnoloških skupova.


Ali što je s principom odabira najboljeg alata za određeni problem?

Ponekad nemate drugog izbora nego donijeti nove alate za rješavanje određenog problema na temelju istih prethodno navedenih razmatranja, u takvim slučajevima ima smisla odabrati najbolje rješenje.


Stvaranje sustava bez visoke sprege s određenom tehnologijom moglo bi biti izazov. Ipak, korisno je težiti stanju u kojem sustav nije usko povezan s tehnologijom i neće umrijeti ako sutra određeni okvir ili alat postane ranjiv ili čak zastario.


Još jedno važno razmatranje povezano je s ovisnostima o otvorenom i vlasničkom softveru. Vlasnički softver daje vam manje fleksibilnosti i mogućnost prilagodbe. Ipak, najopasniji čimbenik je vezanost dobavljača, gdje postajete ovisni o proizvodima dobavljača, cijenama, uvjetima i planu. To može biti rizično ako prodavač promijeni smjer, poveća cijene ili ukine proizvod. Softver otvorenog koda smanjuje ovaj rizik jer ga ne kontrolira jedan entitet. Uklanjanje jedne točke kvara na svim razinama ključ je za izgradnju pouzdanih sustava za rast.

Jedna točka kvara (SPOF)

Jedna točka kvara (SPOF) odnosi se na bilo koji dio sustava koji će, ako zakaže, uzrokovati prestanak rada cijelog sustava. Uklanjanje SPOF-ova na svim razinama ključno je za bilo koji sustav koji zahtijeva visoku dostupnost. Sve, uključujući znanje, osoblje, komponente sustava, cloud providere i internetske kablove, može zakazati.


Postoji nekoliko osnovnih tehnika koje bismo mogli primijeniti za uklanjanje pojedinačnih točaka kvara:

  1. Redundancija. Implementirajte redundanciju za kritične komponente. To znači imati rezervne komponente koje mogu preuzeti ako primarna komponenta zakaže. Redundancija se može primijeniti na različite slojeve sustava, uključujući hardver (poslužitelje, diskove), umrežavanje (veze, sklopke) i softver (baze podataka, aplikacijski poslužitelji). Ako hostirate sve u jednom Cloud Provideru i čak imate sigurnosne kopije tamo, razmislite o izradi redovite dodatne sigurnosne kopije u drugom kako biste smanjili izgubljene troškove u slučaju katastrofe.
  2. Podatkovni centri. Distribuirajte svoj sustav na više fizičkih lokacija, kao što su podatkovni centri ili regije u oblaku. Ovaj pristup štiti vaš sustav od kvarova specifičnih za lokaciju poput nestanka struje ili prirodnih katastrofa.
  3. Failover. Primijenite failover pristup za sve svoje komponente (DNS, CDN, balanseri opterećenja, Kubernetes, API pristupnici i baze podataka). Budući da se problemi mogu pojaviti neočekivano, ključno je imati pričuvni plan za brzu zamjenu bilo koje komponente njezinim klonom.
  4. Usluge visoke dostupnosti. Osigurajte da su vaše usluge horizontalno skalabilne i visoko dostupne od samog početka pridržavajući se sljedećih načela:
    • Vježbajte uslugu bez stanja i izbjegavajte pohranjivanje korisničkih sesija u predmemorije u memoriji. Umjesto toga, koristite distribuirani sustav predmemorije, kao što je Redis.
    • Izbjegavajte oslanjanje na kronološki redoslijed potrošnje poruka prilikom razvijanja logike.
    • Minimizirajte prijelomne promjene kako biste spriječili ometanje API potrošača. Gdje je to moguće, odlučite se za promjene kompatibilne unatrag. Također, uzmite u obzir trošak jer ponekad implementacija prijelomne promjene može biti isplativija.
    • Uključite izvršenje migracije u cjevovod za implementaciju.
    • Uspostavite strategiju za rukovanje istodobnim zahtjevima.
    • Implementirajte otkrivanje usluga, praćenje i bilježenje kako biste poboljšali pouzdanost i vidljivost.
    • Razvijte poslovnu logiku da budete idempotentni, priznajući da su mrežni kvarovi neizbježni.
  5. Pregled ovisnosti. Redovito provjeravajte i smanjite vanjske ovisnosti. Svaka vanjska ovisnost može uvesti potencijalne SPOF-ove, stoga je bitno razumjeti i ublažiti te rizike.
  6. Redovito dijeljenje znanja. Nikada ne zaboravite važnost širenja znanja unutar vaše organizacije. Ljudi mogu biti nepredvidivi, a oslanjanje na jednog pojedinca je riskantno. Potaknite članove tima da digitaliziraju svoje znanje kroz dokumentaciju. Međutim, imajte na umu pretjerano dokumentiranje. Upotrijebite razne AI alate za pojednostavljenje ovog procesa.

Zaključak

U ovom smo članku pokrili nekoliko ključnih makroaspekata i kako se možemo nositi s njihovom složenošću.


Hvala vam na čitanju! Vidimo se sljedeći put!