paint-brush
Kako se nositi sa složenošću prilikom dizajniranja softverskih sistemaby@fairday
64,370 čitanja
64,370 čitanja

Kako se nositi sa složenošću prilikom dizajniranja softverskih sistema

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

Predugo; Citati

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

o čemu se radi?

Svakog dana, svakog trenutka u toku naše inženjerske karijere, susrećemo se s mnogo različitih problema različite složenosti i situacija u kojima moramo donijeti odluku ili je odgoditi zbog nedostatka podataka. Kad god gradimo nove usluge, gradimo infrastrukturu ili čak formiramo razvojne procese, dodirujemo ogroman svijet raznih izazova.


Izazovno je, a možda čak i nemoguće, nabrojati sve probleme. Na neke od ovih problema naići ćete samo ako radite u određenoj niši. S druge strane, postoji mnogo toga koje svi moramo razumjeti kako riješiti, jer su oni ključni za izgradnju IT sistema. Sa velikom vjerovatnoćom ćete ih susresti u svim projektima.


U ovom članku ću podijeliti svoja iskustva s nekim problemima s kojima sam se susreo prilikom izrade softverskih programa.

Šta je međusektorska zabrinutost?

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


U aspektno orijentisanom razvoju softvera, sveobuhvatna pitanja su aspekti programa koji utiču na nekoliko modula, bez mogućnosti da budu inkapsulirani u bilo koji od njih. Ovi problemi se često ne mogu jasno razdvojiti od ostatka sistema iu dizajnu i u implementaciji, i mogu rezultirati ili raspršivanjem (dupliciranje koda), zapetljavanjem (značajne zavisnosti između sistema) ili oboje.


U velikoj meri opisuje šta je to, ali želim da ga malo proširim i pojednostavim:

Međusektorska briga je koncept ili komponenta sistema/organizacije koja utiče (ili 'presijeca') mnoge druge dijelove.


Najbolji primjeri takvih briga su arhitektura sistema, evidentiranje, sigurnost, upravljanje transakcijama, telemetrija, dizajn baze podataka i mnogi drugi. Kasnije ćemo u ovom članku elaborirati mnoge od njih.


Na nivou koda, sveobuhvatni problemi se često implementiraju korištenjem tehnika kao što je Aspect-Oriented Programming (AOP) , gdje su ovi problemi modularizirani u zasebne komponente koje se mogu primijeniti u cijeloj aplikaciji. Ovo drži poslovnu logiku izolovanom od ovih briga, čineći kod čitljivijim i održivijim.

Klasifikacija aspekata

Postoji mnogo mogućih načina kako da klasifikujete aspekte tako što ćete ih segmentirati različitim svojstvima kao što su opseg, veličina, funkcionalnost, važnost, cilj i drugi, ali u ovom članku ću koristiti jednostavnu klasifikaciju opsega. Pod ovim mislim gdje je usmjeren ovaj specifični aspekt, bilo da se radi o cijeloj organizaciji, određenom sistemu ili specifičnom elementu tog sistema.


Dakle, podijelit ću aspekte na Makro i Mikro .


Pod makro aspektom mislim uglavnom na razmatranja koja slijedimo za cijeli sistem kao što su odabrana arhitektura sistema i njegov dizajn (monolitna, mikroservisna, servisno orijentirana arhitektura), tehnološki stack, organizacijska struktura, itd. Makro aspekti se uglavnom odnose na strateški i visoki nivo odluke.


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


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


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

Makro aspekti

Organizaciona struktura

Kada sam tek počeo da učim o softverskoj arhitekturi, pročitao sam mnogo zanimljivih članaka o Konvejevom zakonu i njegovom uticaju na organizacionu strukturu. Posebno ovaj . Dakle, ovaj zakon to kaže


Svaka organizacija koja dizajnira sistem (široko definisan) će proizvesti dizajn čija je struktura kopija komunikacijske strukture organizacije.


Oduvijek sam vjerovao da je ovaj koncept zaista vrlo univerzalan i da predstavlja Zlatno pravilo.


Zatim sam počeo da učim pristup dizajnu vođenom domenom (DDD) Erica Evansa za modeliranje sistema. Eric Evans naglašava važnost identifikacije ograničenog konteksta. Ovaj koncept uključuje podelu kompleksnog modela domena na manje delove kojima se lakše upravlja, svaki sa svojim ograničenim skupom znanja. Ovaj pristup pomaže u efikasnoj timskoj komunikaciji, jer smanjuje potrebu za opsežnim znanjem o cijeloj domeni i minimizira promjenu konteksta, čime razgovore čini efikasnijim. Prebacivanje konteksta je najgora stvar i koja zahtijeva najviše resursa. Čak se i računari bore s tim. Iako je malo vjerovatno da ćemo postići potpuno odsustvo promjene konteksta, mislim 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, našao sam nekoliko problema s njim.


Prvi problem sa kojim sam se susreo sa Konvejevim zakonom, koji sugeriše da dizajn sistema odražava organizacionu strukturu, je potencijal za formiranje složenih i sveobuhvatnih ograničenih konteksta. Ova složenost nastaje kada organizacijska struktura nije usklađena s granicama domena, što dovodi do ograničenih konteksta koji su u velikoj mjeri međusobno zavisni i opterećeni informacijama. To dovodi do čestog mijenjanja konteksta za razvojni tim.


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


Stoga, praćenje Inverznog Conway manevra pomaže u izgradnji sistema i organizacije koji podstiču željenu arhitekturu softvera. Međutim, važno je napomenuti da ovaj pristup neće dobro funkcionirati u već formiranoj arhitekturi i strukturama jer su promjene u ovoj fazi dugotrajne, ali je izuzetno efikasan u startupima jer brzo uvode bilo kakve promjene.

Velika loptica blata

Ovaj obrazac ili „anti-pattern“ pokreće izgradnju sistema bez ikakve arhitekture. Nema pravila, nema granica i nema strategije kako da kontrolišete neizbežno rastuću složenost. Složenost je najstrašniji neprijatelj na putu izgradnje softverskih sistema.


Entertaining illustration made by ChatGPT

Da bismo izbjegli konstruiranje takvog tipa sistema, moramo slijediti određena pravila i ograničenja.

Arhitektura sistema

Postoji bezbroj definicija za softversku arhitekturu. Mnogi od njih mi se sviđaju jer pokrivaju različite aspekte toga. Međutim, da bismo mogli razmišljati o arhitekturi, moramo prirodno da formiramo neke od njih u svom umu. I vrijedno je napomenuti da se ova definicija može razvijati. Tako da, barem za sada, imam za sebe sljedeći opis.


Arhitektura softvera se odnosi na odluke i izbore koje donosite svaki dan i koji utiču na izgrađen sistem.


Da biste donijeli odluke koje trebate imati u svojoj „torbi“ principe i obrasce za rješavanje nastalih problema, također je bitno navesti da je razumijevanje zahtjeva ključno za izgradnju onoga što je poslovnom potrebno. Međutim, ponekad zahtjevi nisu transparentni ili čak nisu definirani, u ovom slučaju je bolje pričekati da dobijete dodatna pojašnjenja ili se osloniti na svoje iskustvo i vjerovati svojoj intuiciji. Ali u svakom slučaju, ne možete pravilno donositi odluke ako nemate principe i obrasce na koje se možete osloniti. Tu dolazim do definicije stila softverske arhitekture.


Stil softverske arhitekture je skup principa i obrazaca koji određuju kako se pravi softver.


Postoji mnogo različitih arhitektonskih stilova fokusiranih 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 vođen domenom

  3. Komponentni

  4. Mikrousluge

  5. Cijevi i filteri

  6. Događaj-driven

  7. Microkernel

  8. Servisno orijentisan


i tako dalje…


Naravno, oni imaju svoje prednosti i nedostatke, ali najvažnija stvar koju sam naučio je da se arhitektura postepeno razvija ovisno o stvarnim problemima. Počevši od monolitne arhitekture je odličan izbor za smanjenje operativnih složenosti, vrlo je vjerovatno da će ova arhitektura odgovarati vašim potrebama čak i nakon dostizanja faze prilagođavanja tržištu proizvoda (PMI) izgradnje proizvoda. U velikoj mjeri, možete razmisliti o prelasku na pristup vođen događajima i mikrousluge za postizanje neovisne implementacije, heterogenog tehničkog steka okruženja i manje povezane arhitekture (i manje transparentne u međuvremenu zbog prirode pristupa vođenih događajima i pub-sub pristupa ako ovi se usvajaju). Jednostavnost i efikasnost su bliske i imaju veliki uticaj jedna na drugu. Obično komplikovane arhitekture utiču na brzinu razvoja novih karakteristika, podržavajući i održavajući postojeće, i izazivajući prirodnu evoluciju sistema.


Međutim, složeni sistemi često zahtevaju složenu i sveobuhvatnu arhitekturu, što je neizbežno.


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

  1. Gotovo uvijek počinje sa monolitnim stilom arhitekture jer eliminira većinu problema koji nastaju zbog prirode distribuiranih sistema. Takođe ima smisla pratiti modularni monolit kako bi se fokusirali na komponente izgradnje sa jasnim granicama. Primjena pristupa zasnovanog na komponentama mogla bi im pomoći da međusobno komuniciraju korištenjem događaja, ali direktni pozivi (aka RPC) pojednostavljuju stvari na početku. Međutim, važno je pratiti zavisnosti između komponenti jer ako komponenta A zna mnogo o komponenti B, možda ima smisla spojiti ih u jednu.
  2. Kada se približite situaciji kada trebate skalirati svoj razvoj i sistem, mogli biste razmisliti o praćenju Stanglerovog obrasca kako biste postepeno izdvajali komponente koje treba samostalno implementirati ili čak skalirati prema specifičnim zahtjevima.
  3. Sada, ako imate jasnu viziju budućnosti, što je malo nevjerovatne sreće, možete se odlučiti za željenu arhitekturu. U ovom trenutku, možete odlučiti da pređete na arhitekturu mikroservisa primjenom pristupa orkestracije i koreografije, uključivanjem CQRS šablona za nezavisne operacije pisanja i čitanja, ili čak odlučivanjem da se držite monolitne arhitekture ako to odgovara vašim potrebama.


Također je od vitalnog značaja razumjeti brojeve i metriku kao što su DAU (Dnevno aktivni korisnici), MAU (Mjesečno aktivni korisnici), RPC (Zahtjev u sekundi) i TPC (Transakcija u sekundi) jer bi vam to moglo pomoći da donesete odluke jer arhitektura za 100 aktivnih korisnika i 100 miliona aktivnih korisnika se razlikuju.


Kao završnu napomenu, rekao bih da arhitektura ima značajan uticaj na uspeh proizvoda. U skaliranju je potrebna loše dizajnirana arhitektura za proizvode, što vrlo vjerovatno dovodi do neuspjeha jer kupci neće čekati dok skalirate sistem, već ć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ć skalirani sistem. S druge strane, posjedovanje vrlo komplikovanog i već skaliranog sistema bez kupaca ili planova da dobijete mnoge od njih koštat će vas novca za vaše poslovanje uzalud.

Izbor tehnologije

Odabir tehnološkog steka je također odluka na makro nivou jer utiče na zapošljavanje, perspektive prirodne evolucije sistema, skalabilnost i performanse sistema.


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

  • Zahtjevi i složenost projekta. Na primjer, jednostavna web aplikacija može se napraviti sa Blazor frameworkom ako vaši programeri imaju iskustva s njim, ali zbog nedostatka zrelosti WebAssembly-a, odabir Reacta i Typescripta za dugoročni uspjeh mogao bi biti bolja odluka
  • Skalabilnost i potrebe za performansama. Ako očekujete da ćete primati veliku količinu saobraćaja, odabir ASP.NET Core umjesto Djanga mogao bi biti mudar izbor zbog njegovih superiornih performansi u rukovanju istovremenim zahtjevima. Međutim, ova odluka ovisi o obimu prometa koji očekujete. Ako trebate upravljati potencijalno milijardama zahtjeva s malim kašnjenjem, prisustvo prikupljanja smeća može biti izazov.
  • Zapošljavanje, vrijeme razvoja i cijena. U većini slučajeva, ovo su faktori o kojima moramo voditi računa. Vrijeme do tržišta, troškovi održavanja i stabilnost zapošljavanja pokreću vaše poslovne potrebe bez prepreka.
  • Stručnost i resursi tima. 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 nema jakih razloga za ulaganje u učenje novog steka.
  • Zrelost. Jaka zajednica i bogat ekosistem biblioteka i alata mogu uvelike olakšati proces razvoja. Popularne tehnologije često imaju bolju podršku zajednice, što može biti od neprocjenjive važnosti za rješavanje problema i pronalaženje resursa. Tako možete uštedjeti resurse i fokusirati se uglavnom na proizvod.
  • Dugotrajno održavanje i podrška. Uzmite u obzir dugoročnu održivost tehnologije. Tehnologije koje su široko prihvaćene i podržane su manje vjerovatno da će zastarjeti i općenito dobijaju redovna ažuriranja i poboljšanja.


Kako bi višestruka tehnologija mogla uticati na rast poslovanja?

Iz jedne perspektive, uvođenje još jedne grupe može povećati vaše zapošljavanje, ali s druge strane, to donosi dodatne troškove održavanja jer morate podržati oba steka. Dakle, kao što sam već rekao, po mom mišljenju, samo dodatna potreba bi trebala biti argument za uključivanje više tehnoloških stekova.


Ali šta je sa principom odabira najboljeg alata za određeni problem?

Ponekad nemate drugog izbora osim da donesete nove alate za rješavanje određenog problema na osnovu istih gore navedenih razmatranja, u takvim slučajevima ima smisla odabrati najbolje rješenje.


Stvaranje sistema bez visoke povezanosti sa specifičnom tehnologijom može biti izazov. Ipak, korisno je težiti stanju u kojem sistem nije čvrsto povezan s tehnologijom i neće umrijeti ako sutra određeni okvir ili alat postane ranjiv ili čak zastario.


Još jedno važno pitanje odnosi se na ovisnosti o otvorenom kodu i vlasničkim softverima. Vlasnički softver vam daje manju fleksibilnost i mogućnost prilagođavanja. Ipak, najopasniji faktor je zaključavanje dobavljača, gdje postajete ovisni o proizvodima, cijenama, uvjetima i planovima dobavljača. Ovo može biti rizično ako dobavljač promijeni smjer, poveća cijene ili prekine proizvod. Softver otvorenog koda smanjuje ovaj rizik, jer ga ne kontrolira jedan entitet. Eliminacija jedne tačke kvara na svim nivoima je ključ za izgradnju pouzdanih sistema za rast.

Jedna tačka kvara (SPOF)

Pojedinačna tačka kvara (SPOF) se odnosi na bilo koji dio sistema koji će, ako zakaže, uzrokovati da cijeli sistem prestane funkcionirati. Eliminacija SPOF-ova na svim nivoima je ključna za svaki sistem koji zahteva visoku dostupnost. Sve, uključujući znanje, osoblje, sistemske komponente, cloud provajdere i internet kablove, može propasti.


Postoji nekoliko osnovnih tehnika koje možemo primijeniti da eliminišemo pojedinačne točke kvara:

  1. Redundantnost. Implementirajte redundantnost za kritične komponente. To znači da imate rezervne komponente koje mogu preuzeti ako primarna komponenta ne uspije. Redundantnost se može primijeniti na različite slojeve sistema, uključujući hardver (serveri, diskovi), umrežavanje (linkovi, prekidači) i softver (baze podataka, serveri aplikacija). Ako sve hostirate u jednom Cloud Provideru, pa čak i tamo imate sigurnosne kopije, razmislite o izgradnji redovne dodatne sigurnosne kopije u drugom kako biste smanjili svoje izgubljene troškove u slučaju katastrofe.
  2. Data Centers. Distribuirajte svoj sistem na više fizičkih lokacija, kao što su centri podataka ili regioni u oblaku. Ovaj pristup štiti vaš sistem od kvarova specifičnih za lokaciju kao što su nestanci struje ili prirodne katastrofe.
  3. Failover. Primijenite pristup nadilaženja greške za sve svoje komponente (DNS, CDN, balanseri opterećenja, Kubernetes, API pristupne mreže i baze podataka). Budući da problemi mogu nastati neočekivano, ključno je imati rezervni plan za zamjenu bilo koje komponente njenim klonom po potrebi brzo.
  4. Usluge visoke dostupnosti. Osigurajte da su vaše usluge izgrađene tako da budu horizontalno skalabilne i visoko dostupne od samog početka pridržavajući se sljedećih principa:
    • Prakticirajte uslugu bez državljanstva i izbjegavajte pohranjivanje korisničkih sesija u keš memorije. Umjesto toga, koristite distribuirani keš sistem, kao što je Redis.
    • Izbjegavajte oslanjanje na hronološki redoslijed potrošnje poruka prilikom razvoja logike.
    • Minimizirajte izmjene kako biste spriječili ometanje API potrošača. Gdje je moguće, odlučite se za promjene kompatibilne s prethodnim verzijama. Takođe, uzmite u obzir trošak jer ponekad implementacija prelomne promjene može biti isplativija.
    • Uključite izvršenje migracije u cevovod za implementaciju.
    • Uspostavite strategiju za rukovanje istovremenim zahtjevima.
    • Implementirajte otkrivanje usluga, praćenje i evidentiranje kako biste poboljšali pouzdanost i vidljivost.
    • Razvijte poslovnu logiku da budete idempotentni, priznajući da su kvarovi na mreži neizbježni.
  5. Pregled zavisnosti. Redovno pregledajte i minimizirajte vanjske zavisnosti. Svaka eksterna zavisnost može uvesti potencijalne SPOF-ove, tako da je neophodno razumjeti i ublažiti ove rizike.
  6. Redovna razmjena znanja. Nikada ne zaboravite na važnost širenja znanja unutar vaše organizacije. Ljudi mogu biti nepredvidivi, a oslanjanje na jednog pojedinca je rizično. Potaknite članove tima da digitaliziraju svoje znanje kroz dokumentaciju. Međutim, vodite računa o pretjeranom dokumentovanju. Koristite različite AI alate da pojednostavite ovaj proces.

Zaključak

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


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