creșterea adoptării microserviciilor a provocat o renaștere a popularității unor modele de proiectare software trecute cu vederea anterior. Multe dintre aceste modele au fost extrase din designul condus de domenii al lui Eric Evans, o carte care este la fel de mult despre structura echipei ca și despre arhitectura software.și dintre aceste tipare, contextul delimitat este probabil cel mai important de înțeles. Ca ingineri, am ajuns să considerăm contextul delimitat ca fiind un model de proiectare a arhitecturii software. Dar asta pentru că l-am cooptat puțin din utilizarea sa inițială. Așa cum este folosit de Evans, contextul delimitat este la fel de mult un model organizațional pe cât este unul tehnic.
De aceea am ajuns să văd tiparul contextului delimitat ca un punct de sprijin în înțelegerea microserviciilor. Nu doar cum să le construim, ci de fapt de ce le construim în primul rând și cum pot face organizațiile noastre mai de succes. Dacă înțelegem ce sunt contextele delimitate — dacă adoptăm mentalitatea contextului delimitat atât din punct de vedere tehnic, cât și organizațional — atunci putem avea cu adevărat succes în construirea arhitecturii noastre de microservicii.
De ce trece la microservicii?
pentru a începe, să facem un mic exercițiu. Puneți-vă această întrebare: De ce construim microservicii în primul rând?
ia un moment să se gândească la asta. Care sunt beneficiile care vin în minte pentru prima dată? Care sunt principalele probleme pe care ar trebui să sperăm să le rezolvăm? Notați câteva răspunsuri, doar pentru a vă menține sincer.
…
ai răspunsul? Bun. Citește-l înapoi la tine. Ați atins beneficiile tehnice standard? Livrare continuă, scalabilitate, medii poliglot, containere și nori și toate acele lucruri bune? Grozav.
dar răspunsul dvs. de top a inclus ceva despre a permite organizației dvs. să funcționeze mai eficient? Ar trebui. Deoarece construirea microserviciilor nu înseamnă realizarea beneficiilor tehnice. Într-adevăr, este vorba despre obținerea de beneficii organizaționale. Orice altceva este un detaliu de implementare.
monoliți = Cod cuplat și echipe cuplate
pe măsură ce monoliții noștri cresc din ce în ce mai mult, productivitatea începe să scadă. Există cel puțin două motive majore pentru asta.
frânând viteza noastră
În primul rând, fiecare echipă de ingineri contribuie la o bază de cod gigantică. Ca atare, echipele se confruntă cu o probabilitate din ce în ce mai mare ca codul lor să intre în conflict cu codul altora. Pentru a ajuta la atenuarea potențialelor probleme pe care le — ar putea cauza, instituim proceduri-înghețarea codurilor, perioade de testare a calității, eliberarea trenurilor etc. – care sunt literalmente concepute pentru a încetini productivitatea noastră.desigur ,aceste proceduri împiedică implementarea în timp util a caracteristicilor și îmbunătățirilor. De asemenea, fac ravagii asupra capacității inginerilor de a se concentra asupra priorităților echipelor lor. Dacă o eroare este găsită în timpul unei perioade de testare, echipa responsabilă trebuie să schimbe contextul și să se concentreze pe rezolvarea acelei erori. Dacă se găsește o eroare severă în producție, echipa trebuie nu numai să remedieze eroarea, ci și să sară prin cercuri pentru a o implementa de următorul tren de lansare.
serviciul de gardă devine un boondoggle. Dacă ceva nu merge bine cu monolitul nostru, cineva trebuie să fie disponibil — zi sau noapte — pentru a rezolva problema. Dar cine? Organizațiile mari cu monoliți mari se confruntă, în general, cu două opțiuni:
- o echipă de gestionare a incidentelor a cărei sarcină unică, tristă și regretabilă în cadrul organizației este să răspundă problemelor cauzate de codul altor ingineri și să-și dea seama cum să le rezolve.
- un program rotativ de gardă, prin care în fiecare săptămână unui inginer arbitrar i se atribuie tristul și regretatul loc de muncă de a deveni responsabil pentru rezolvarea problemelor care sunt cel mai probabil cauzate de codul scris de un alt inginer, în altă echipă de ingineri.
(Mis)organizarea echipelor noastre
monoliții se încurcă cu organizațiile noastre într-un alt mod. Întreaga noastră organizație lucrează la același produs mare. Dar trebuie să împărțim organizația în Echipe gestionabile. Așa că avem tendința de a căuta roluri funcționale pentru a găsi limitele echipei:
este, de asemenea, plină de blocaje. Când ne organizăm echipele pe zone funcționale, atunci vom avea în mod natural o aliniere greșită a priorităților. Să presupunem că echipa de gestionare a produselor a decis că procesul de plată al monolitului nostru trebuie reînnoit. Ei vor programa timp cu echipa de proiectare pentru a pune împreună unele batjocura. La un moment dat, batjocurile vor fi terminate și înmânate echipei frontend pentru a le implementa. Desigur, echipa frontend va avea nevoie de API-uri pentru a fi implementate de echipa backend, astfel încât acestea vor fi blocate până la finalizarea acestora. Odată ce echipa backend își prioritizează activitatea pe noile servicii de plată, constată că are nevoie de ajutor din partea echipei de administrare a bazelor de date (DBA). Care, desigur, are propriile priorități. Deci, echipa backend va fi blocată până când un DBA este eliberat.
într-un fel, această structură organizațională pare un pic ca o arhitectură software slab proiectată, prea cuplată… nu-i așa?
Microservices = Cod decuplat, Echipe decuplate
în schimb, o arhitectură microservices permite autonomia echipei. Devine mult mai ușor să formezi echipe care sunt autonome, care lucrează eficient împreună și care nu sunt blocate în mod constant de dependențele de alte echipe.
echipele își pot asuma responsabilitatea deplină asupra muncii lor, de la proiectare la dezvoltare până la implementare. Fiecare membru împărtășește responsabilitatea pentru atingerea obiectivului echipei sale, astfel încât să devină stimulați să participe la mai mult decât la „partea lor”. Am lucrat cu Echipe în care managerii de produse, designerii, front-end-ul, back-end-ul și inginerii mobili s-au reunit pentru a proiecta caracteristicile produsului, obținând rezultate mult mai bune decât ar fi putut fi obținute de o singură persoană.
echipa câștigă responsabilitatea pentru propriile artefacte odată ce sunt implementate în producție. Acest lucru duce, în general, la un cod de calitate superioară, care este mai ușor de depanat. De ce este asta? Spre deosebire de un monolit, echipele tind să aibă o viziune holistică asupra microserviciilor pe care le dețin. Așadar, este mult mai ușor pentru echipă să anticipeze problemele, să adauge înregistrări și valori bune pentru a depana problemele atunci când apar și să utilizeze corect modelele de rezistență (de exemplu, încercări, întrerupătoare de circuit și fallback-uri etc.) pentru a ajuta la evitarea problemelor în primul rând.
Mai mult, deoarece echipele au un sentiment deplin de proprietate asupra muncii lor, menținerea serviciilor lor sănătoase și funcționarea în producție devine mai puțin despre un program de lansare de coșmar și mai mult despre cultivarea creației lor.
în cele din urmă, echipele lucrează spre același scop, pe aceeași cronologie. Asta înseamnă că nu mai blocați o persoană, deoarece așteaptă ca cineva dintr-o altă zonă funcțională să se elibereze.
trebuie să fim intenționați cu privire la autonomie
dar nu obținem aceste beneficii gratuit pur și simplu prin ruperea monolitului nostru în microservicii. Să aruncăm o privire la prima noastră viziune naivă a unei arhitecturi de microservicii:
dacă suntem ca majoritatea inginerilor, ideea noastră inițială a unei arhitecturi microservice este, Ei bine, o grămadă de microservicii. Fiecare expune un fel de API (ReST, probabil) pentru a permite oricărui alt serviciu să citească din el și să-i scrie.
pe măsură ce câștigăm experiență, învățăm că nu toate microserviciile servesc aceluiași scop — sau, cel puțin, nu ar trebui. Și de aceea, la fel ca monolitul nostru a fost aranjat în straturi, așa că ne aranjăm microserviciile:
rețineți că aceste două contexte delimitate sunt în cele din urmă consistente. Aceasta înseamnă că vor exista perioade scurte de timp în care o anumită bucată de date ar putea fi inconsistentă între introducerea produsului și căutarea produsului. De exemplu, dacă prețul widgeturilor Wombat alb este ridicat de la 1,99 USD la 2 USD.49, va exista o scurtă perioadă de timp (de multe ori o chestiune de secunde, dacă nu milisecunde), în cazul în care există o diferență de 50 la sută în prețul Widget Alb Wombat în cele două contexte delimitate.
Acest lucru duce la cazurile din lumea reală atunci când nu avem altă alternativă decât la contexte limitate în cuplu. În unele cazuri, eventuala coerență nu este acceptabilă. De exemplu, înainte ca un client să își poată finaliza achiziția online, este posibil să fie necesar să ne asigurăm că fiecare articol din coșul de cumpărături este, de fapt, disponibil în acel moment. Chiar și atunci, putem minimiza adesea cuplarea dintre cele două contexte delimitate.
interacțiunile noastre ar putea arăta astfel:
- deoarece clientul folosește interfața de căutare a produsului pentru a găsi produse, bazele de date de căutare a produsului sunt utilizate pentru a prelua informații (cum ar fi stiluri, recenzii ale clienților, prețuri etc.) despre produse
- chiar și atunci când clientul începe procesul de plată, folosim în continuare bazele de date de căutare a produselor pentru a prelua informațiile care trebuie afișate.
- în cele din urmă, atunci când clientul face clic pe acel buton final „achiziție completă”, efectuăm un singur apel sincron către contextul delimitat de intrarea produsului pentru a valida disponibilitatea articolelor înainte de finalizarea achiziției.
Un alt exemplu comun care necesită consecvență imediată legată de autorizare. În multe sisteme, jetoanele de securitate trebuie preluate sau validate la fiecare solicitare. În aceste cazuri, probabil că trebuie să permitem contextelor noastre mărginite să numească un alt Context mărginit orientat spre securitate.
structuri org din viața reală
Ce zici de echipe autonome, inter-funcționale? Cât de posibile sunt acestea în lumea reală?
în realitate, este un proces de mișcare continuă către Echipe complet independente. Rareori vom ajunge vreodată la o autonomie de 100% cu echipele noastre. Dar dacă începem prin organizarea inteligentă a echipelor noastre și recunoaștem și răspundem la blocajele care apar, ne putem apropia.
pentru început, ar trebui să maximizăm echipele noastre verticale, inter-funcționale și să minimizăm numărul de echipe orizontale, cu o singură funcție. Asta înseamnă să rezistăm dorinței de a forma așa — numitele echipe „de bază”-a căror misiune este de a construi servicii comune de date care sunt consumate de alte echipe orientate spre produse — și, în schimb, să formăm echipele noastre în jurul valorii de afaceri pe care o vor oferi.
multe organizații se îndreaptă spre acest obiectiv, formând mai întâi Echipe orientate spre domeniu de manageri de produse și ingineri front-end și back-end. E un început. Dar cine altcineva ar trebui să includă aceste echipe? Calitatea de membru exactă poate diferi între diferite echipe cu nevoi diferite. Dar ar trebui să luăm în considerare lucruri precum:
- dacă echipa noastră are ingineri front-end, atunci șansele sunt că ar trebui să lucreze îndeaproape cu un designer grafic dedicat domeniului.
- inginerii mobili — adesea sechestrați în propria zonă a organizației — ar trebui să fie incluși pentru domenii cu o componentă mobilă.
- în articolul său edificator despre rețelele de date, Zhamak Dehghani se plânge că inginerii de date sunt adesea excluși din echipele inter-funcționale — în detrimentul inginerilor de date și al echipelor inter-funcționale.
odată ce am stabilit componența echipelor noastre, ar trebui să fim atenți la blocaje. Există alte echipe care blochează în mod obișnuit productivitatea echipelor noastre inter-funcționale?
de exemplu, multe organizații au o echipă dedicată de securitate. Aceasta este o bună practică, desigur; organizațiile au nevoie de o strategie de securitate coerentă și de o modalitate de a asigura guvernarea asupra acestei strategii. Cu toate acestea, este, de asemenea, obișnuit ca echipele să-și oprească activitatea în diferite etape pentru a permite revizuirea securității muncii lor. Chiar și în cele mai bune situații, acest lucru stabilește obstacole pentru echipele noastre ca o rutină o practică de afaceri. În plus, aceasta va duce adesea la Echipe care trebuie să renunțe la toate sau o parte din munca lor și să înceapă din nou, deoarece descoperă cerințe de securitate care nu au fost îndeplinite.
acesta este în mod clar un miros urât. Dar, cum putem impune standardele de securitate ale organizației noastre, permițând în același timp echipelor să rămână autonome și productive?
putem face acest lucru prin adăugarea de ingineri de securitate la echipele noastre inter-funcționale. Există trei abordări pe care le putem lua:
- dacă avem norocul să avem o echipă de securitate relativ mare, putem atribui fiecărei echipe inter-funcționale un inginer de securitate cu normă întreagă (SE).
- cu echipe de securitate mai mici, fiecare SE poate fi atribuit unui număr de echipe inter-funcționale într-un mod part-time. Acest lucru ar permite în continuare SEs să înțeleagă obiectivele și proiectele echipelor și să lucreze cu echipa pentru a adera la standardele de securitate ale org pe tot parcursul procesului.
- dacă nu avem suficiente resurse de securitate pentru oricare dintre ele, ne putem deplasa în direcția opusă. În loc să aducem membrii echipei de securitate în echipele noastre inter-funcționale, putem aduce membrii echipelor inter-funcționale în echipa de securitate. Fiecare echipă inter-funcțională ar desemna unul sau doi reprezentanți ai securității. Reprezentanții se vor întâlni periodic cu securitatea și vor fi ținuți la curent cu cerințele și standardele de securitate ale organizației. Este posibil să nu fie ei înșiși experți în securitate. Dar vor putea servi rolul unui inginer de securitate, asigurându-se că echipele lor aderă la practicile de securitate ale organizației.
bresle
Acest lucru se împletește într-un alt model organizațional care a câștigat tracțiune: bresle. Modelul breslei s-a născut din modelul echipei inter-funcționale. Prin natura lor, aceste echipe sunt populate cu membri care se specializează în diferite funcții. Cu toate acestea, de multe ori are sens pentru oameni care se specializează într-o funcție specifică pentru a întâlni împreună, precum și; de exemplu, pentru a:
- perfecționa abilitățile lor și să învețe unii de la alții
- descoperi și de a stabili cele mai bune practici pentru funcția lor special
- în funcție de funcția, de a crea standardele companiei și cerințele
ultima noastră soluție de securitate a format în mod eficient o „breasla de securitate”. Membrii echipei lucrau în primul rând cu echipele lor verticale; dar periodic, unii dintre ei se întâlneau cu „breasla” de securitate pentru a discuta practicile și standardele de securitate ale organizației.
modelul guild funcționează, de asemenea, deosebit de bine atunci când vine vorba de arhitectura software. În special cu o arhitectură microservices, este necesar un anumit nivel de guvernanță tehnică la nivel de organizație. Cu toate acestea, a avea un grup de arhitecți care stau într-un turn de Fildeș metaforic, împărțind reguli echipelor, este în general contraproductiv. În schimb, inginerii seniori/lideri din echipele noastre inter-funcționale se pot întâlni periodic într-o breaslă de arhitectură. Acolo, ei pot ridica probleme de la echipele lor și pot elabora soluții și pot stabili pattens și standarde.
Exemple de echipe inter-funcționale, completate de bresle orizontale
breslele pot fi, de asemenea, extinse la aproape toate celelalte funcții. La urma urmei, vrem ca designerii să dezvolte și să lucreze dintr-un ghid comun de stil UI. Vrem ca inginerii noștri frontend să utilizeze aceleași elemente UI. Inginerii QA ar trebui să fie aliniați cu modul în care se efectuează testarea în organizațiile noastre. Și managerii de produse ar trebui să fie sincronizați cu foaia de parcurs generală a produsului organizației.
aduceți totul împreună
trecerea la microservicii poate îmbunătăți dramatic productivitatea echipelor noastre. Dar trebuie să înțelegem cum să profităm de o arhitectură microservices pentru a ne duce acolo. Dintre toate modelele și conceptele de proiectare care se referă la microservicii, contextul delimitat este, fără îndoială, cel mai important pentru a ne oferi această înțelegere.
cu o înțelegere solidă a contextului delimitat, înțelegem că:
- structura noastră organizatorică și arhitectura noastră tehnică merg mână în mână
- echipele noastre orientate spre produse ar trebui să aibă dependențe minime de alte echipe, la fel cum sistemele pe care le construiesc ar trebui decuplate de alte sisteme
în general, îmbrățișarea contextului delimitat pune în mentalitatea că trebuie să avem succes cu arhitectura microserviciilor noastre. Asigurați-vă că înțelegeți acest model important înainte de a vă îmbarca în călătoria dvs. de microservicii!