Arhitectura datelor și a sistemelor, de la zero Lecția 73 / 80

Microservices: când da, când nu, revenirea monolitului

Boom-ul microservices din 2015-2020, contraofensiva de după 2021 și modular monolith ca drum de mijloc. Legea lui Conway, taxa pe sisteme distribuite și cum alegi în funcție de mărimea echipei și profilul de scalare.

Modulul 10 deschide cu pattern-ul arhitectural care a definit un deceniu de discuții inginerești și apoi s-a întors discret pe propriile sale urme. Cam din 2015 până în 2020, răspunsul implicit la întrebarea „cum ar trebui să ne structurăm backend-ul?” era „microservices, evident”. Până în 2021, exact aceleași companii care fuseseră cei mai zgomotoși evangheliști publicau articole despre cum se reîntorc la monoliți, sau la un hibrid pe care industria a început să-l numească modular monolith. Pendulul nu s-a întors pentru că argumentele inițiale erau greșite. S-a întors pentru că niște costuri pe care nimeni nu le măsurase complet s-au dovedit a fi mai mari decât beneficiile pentru majoritatea echipelor.

Lecția asta e despre arcul acela, despre pentru ce e bună fiecare formă și cum decizi în care ar trebui să fie echipa ta. E lecția de deschidere a Modulului 10 pentru că fiecare lecție ulterioară din modul (event-driven architecture în lecția 74, multi-region în lecția 75 și restul) se construiește peste o strategie de descompunere în servicii deja aleasă. Dacă alegi forma greșită, te blochezi în setul greșit de compromisuri pentru ani de zile.

Ce înseamnă de fapt „microservices”

Dacă scoți branding-ul, o arhitectură microservices este una în care un singur produs e împărțit în multe servicii mici, deployabile independent, care comunică prin rețea, fiecare cu propriul data store, propriul pipeline de deploy și, ideal, propria echipă.

Contrastul e cu monolith-ul: o singură codebase mare, un singur artefact deployabil, o singură bază de date (sau un set mic), un singur pipeline de deploy. Monolith-ul este forma implicită de pornire din lecțiile 1-6. Microservices sunt ce încearcă echipele când monolith-ul începe să doară.

Argumentul pentru microservices la mijlocul anilor 2010 era un mănunchi de beneficii reale. Deployabilitate independentă: echipa A își livrează serviciul fără să se coordoneze cu echipa B. Scalabilitate independentă: serviciul cu multe citiri rulează pe o flotă diferită față de cel intensiv pe calcul. Polyglot persistence (lecția 24): serviciul de utilizatori folosește Postgres, serviciul de căutare folosește Elasticsearch, serviciul de coș folosește Redis. Polyglot programming languages: echipa de ML scrie Python, echipa de plăți scrie Java, echipa front-of-the-stack scrie Go. Serviciile mai mici sunt mai ușor de deținut end-to-end de o singură echipă.

Fiecare beneficiu e real. Versiunea cinstită a poveștii e că fiecare beneficiu are și un cost pe care marketing-ul nu l-a anunțat.

Legea lui Conway și organigrama

Cel mai clar predictor al felului în care va arăta o arhitectură nu e diagrama de design, ci organigrama. Legea lui Conway, dintr-o lucrare din 1967 a lui Melvin Conway, o spune direct: orice organizație care proiectează un sistem va produce un design a cărui structură e o copie a structurii de comunicare a organizației.

În boom-ul microservices, asta a funcționat în ambele direcții. Companiile mari de tech cu sute de echipe chiar aveau nevoie de multe servicii deținute independent, pentru că organigrama lor avea multe echipe independente. Companiile mai mici care copiau pattern-ul ajungeau cu treizeci de servicii deținute de doisprezece ingineri, iar arhitectura nu se potrivea cu organizația. Rezultatul era o taxă perpetuă de coordonare: fiecare schimbare atingea cinci servicii, fiecare cinci servicii erau deținute de două persoane, iar cele două persoane își petreceau timpul în ședințe în loc să livreze.

Manevra Conway inversă, populară în perioada 2018-2020, era să reproiectezi organigrama ca să se potrivească cu arhitectura dorită. Uneori funcționa. Mai des producea o organigramă plină de echipe de doi care nu puteau în mod realist să dețină un serviciu end-to-end, iar arhitectura suferea la fel ca înainte. Legea lui Conway e descriptivă, nu prescriptivă: îți spune ce se va întâmpla, nu spre ce ar trebui să țintești.

Contraofensiva de după 2021

Începând cam cu 2021, o serie de articole publice din partea companiilor care înainte susțineau microservices au început să dea înapoi. Cele trei cele mai citate:

Shopify rula un monolith Rails de peste un deceniu și a scris o serie de articole („Deconstructing the Monolith”, Shopify Engineering, 2019, https://shopify.engineering/deconstructing-monolith-designing-software-maximizes-developer-productivity, consultat 2026-05-01) despre cum l-au menținut gestionabil pe măsură ce compania a crescut. Pattern-ul Shopify e ceea ce ei numesc componentizare: granițe interne clare între module în interiorul unui singur deployable, cu reguli stricte despre ce modul poate apela ce modul. Argumentul e că au obținut majoritatea beneficiilor microservices fără să plătească costul operațional.

Basecamp a rulat un argument similar într-un limbaj mai zgomotos. David Heinemeier Hansson a inventat termenul „majestic monolith” și a susținut, în scris și la conferințe, că o echipă mică nu ar trebui să se împartă niciodată în microservices, pentru că costul operațional al coordonării e mai mare decât orice beneficiu.

Amazon Prime Video a publicat un articol în 2023 („Scaling up the Prime Video audio/video monitoring service and reducing costs by 90%”, AWS Open Source Blog, martie 2023, https://www.primevideotech.com/video-streaming/scaling-up-the-prime-video-audio-video-monitoring-service-and-reducing-costs-by-90, consultat 2026-05-01) care descria cum serviciul lor de monitorizare fusese construit ca un pipeline serverless de microservices, a lovit un perete de scalare și cost și a fost reconstruit ca un singur serviciu monolitic care rula pe EC2. Costurile au scăzut cu 90 la sută. Articolul a fost remarcabil pentru că venea din interiorul Amazon, compania cea mai asociată cu impulsul inițial pro-microservices.

Pattern-ul transversal nu e „microservices au fost o greșeală”. E „microservices au un cost pe care l-am subestimat, iar multe echipe care le-au adoptat n-aveau nevoie de ele de la bun început”.

Când microservices câștigă

Lista cinstită de cazuri în care arhitectura se merită:

Deținere independentă a echipei la scară. Când ai zece echipe care au nevoie de cadențe diferite de deploy, rotații diferite de on-call și stack-uri tehnice diferite, împărțirea în zece servicii e arhitectura care le permite să lucreze în paralel. Sub acel prag de scară, coordonarea e mai ieftină decât împărțirea.

Profile de scalare diferite per componentă. Când serviciul de citire face un milion de citiri pe secundă și serviciul de analytics face o mie de agregări lungi, dacă le pui în același deployable înseamnă că scalarea serviciului de analytics îți cumpără capacitate de citire de care n-ai nevoie, sau invers. Împărțirea permite fiecărei flote să se potrivească cu sarcina ei.

Polyglot persistence per serviciu. Când serviciul de utilizatori e fundamental relațional, feed-ul de activitate e fundamental un stream, iar serviciul de recomandări e fundamental un vector store, împărțirea permite fiecărei echipe să aleagă data store-ul potrivit pentru problemă.

Polyglot programming languages. Când o parte a sistemului are cerințe dure de performanță care necesită un limbaj compilat și o parte a sistemului are cerințe de iterație rapidă care necesită un limbaj de scripting, împărțirea permite fiecărei echipe să facă alegerea locală fără să forțeze aceeași alegere asupra tuturor.

Izolarea defecțiunilor pe căi critice. Când o defecțiune în serviciul de căutare nu trebuie să dărâme serviciul de checkout, granița de rețea devine o graniță de defecțiune. Un bug într-un serviciu nu prăbușește celălalt.

Pattern-ul transversal acestor cazuri e că se referă la scară: scara echipei, scara sarcinii, scara complexității. Sub această scară, câștigurile sunt mici și costurile sunt reale.

Când microservices pierd

Lista complementară, trasă din modurile de eșec care au alimentat contraofensiva de după 2021:

Echipă mică, multe servicii. Când cinci ingineri dețin doisprezece servicii, fiecare schimbare transversală e un rollout pe mai multe servicii, iar atenția echipei e fragmentată între servicii pe care nimeni nu le înțelege complet.

Taxa pe sisteme distribuite. Fiecare apel cross-service introduce moduri de eșec ale rețelei. Cele opt erori din lecția 9 (rețeaua e fiabilă, latența e zero, banda e infinită și așa mai departe) revin toate ca incidente de producție în jurul cărora echipa trebuie să facă inginerie. Timeout-uri, retry-uri, circuit breakers, idempotență, dead-letter queues. Niciunul nu e necesar într-un monolith pentru că apelul de funcție în interiorul unui proces nu eșuează în acele moduri.

Debugging pe mai multe servicii. Un utilizator raportează „pagina e lentă”. Într-un monolith, citești request log-ul și slow query log-ul. În microservices, request-ul traversează șase servicii și ai nevoie de un sistem de distributed tracing ca să vezi unde s-a dus timpul. Sistemul de tracing în sine e infrastructură pe care trebuie s-o construiești și s-o rulezi.

Complexitatea dezvoltării locale. „Pornește treizeci de servicii ca să rulezi aplicația pe laptop” e un mod real de eșec. Echipele ajung cu fișiere Docker Compose elaborate, straturi de mocking sau configurări tilt-and-skaffold, doar ca să facă dezvoltarea posibilă. Inginerii noi își petrec prima săptămână cu setup-ul de mediu.

Versionare și drift de contract. Serviciul A și serviciul B împart un API. Când A schimbă API-ul, B trebuie actualizat. Înmulțește cu N servicii și costul de coordonare crește pătratic.

Cost operațional. Fiecare serviciu are propriul deployment, propriul dashboard de monitorizare, propria agregare de log-uri, propriul alerting, propriul on-call. Costul fix per serviciu nu e neglijabil.

Expresia care a surprins asta la sfârșitul anilor 2010 a fost „you must be this tall to ride the microservices ride”, atribuită în diverse forme lui Martin Fowler și altora. Ideea era că microservices presupun un nivel de maturitate a platformei (CI/CD, observability, container orchestration, service discovery, secrets management, tooling de API intern) pe care echipele mici nu îl au și nu îl pot construi ieftin.

Drumul de mijloc: modular monolith

Arhitectura care a ieșit din contraofensiva de după 2021 ca implicit nou pentru majoritatea echipelor e modular monolith. Un singur deployable, o singură bază de date (sau un set mic), un singur pipeline de deploy. Granițele interne între module sunt puternice: fiecare modul își deține domeniul, expune o interfață definită și nu poate ajunge în interiorul altui modul. Compilatorul sau runtime-ul aplică granițele.

Implementările variază în funcție de limbaj și framework. Componentele Shopify folosesc granițe de gem Ruby cu tooling custom care aplică dependențele. Rails engines partiționează o aplicație Rails în sub-aplicații montate. Pachetele Java și modulele Maven dau aceeași formă cu aplicare mai puternică la compile-time. Proiectele .NET, pachetele internal Go și pachetele de namespace Python joacă același rol.

Beneficiile pe care le păstrează modular monolith:

  • Un singur deployable, un singur pipeline de deploy, un singur stream de log-uri, un singur trace, o singură sesiune de debugger.
  • Refactorizarea peste granițele de modul e o schimbare de cod normală, nu o migrare pe mai multe servicii.
  • Performanța e oricât costă un apel de funcție, nu oricât costă un round-trip de rețea.
  • Echipa poate muta tot codul deodată când designul trebuie să se schimbe.

Beneficiile pe care le pierde modular monolith, comparativ cu microservices reale:

  • Deployabilitate independentă între echipe (fiecare schimbare se livrează în același deploy).
  • Scalare per modul (întregul monolith scalează împreună).
  • Polyglot persistence per serviciu (poți folosi în continuare mai multe data store-uri, dar sunt cuplate la același deployable).
  • Polyglot programming languages.

Portița de scăpare e calea pe care modular monolith o face ieftină: când un modul are nevoie cu adevărat de cadență de deploy independentă sau de scalare independentă, îl extragi într-un serviciu. Nu înainte. Disciplina e să ții opțiunea deschisă și să nu plătești costul preventiv.

Alegerea după formă

Arborele de decizie care iese din toate astea:

flowchart TD
    A[Are you a small team less than 20 engineers?] -->|Yes| B[Modular monolith]
    A -->|No| C[Do teams need independent deploy cadence?]
    C -->|No| B
    C -->|Yes| D[Do components have very different scaling profiles?]
    D -->|No| E[Modular monolith with selective extraction]
    D -->|Yes| F[Microservices for the components that need it]
    F --> G[Keep everything else in the modular monolith]

Aceeași idee pe o axă a mărimii echipei: la un inginer până la cinci ingineri, monolith. Cinci la cincizeci, modular monolith. Cincizeci la câteva sute, modular monolith cu o mână de servicii extrase pentru componentele care îl justifică. Câteva sute în sus, microservices devin implicitul și întrebarea se inversează.

Trimiterile încrucișate închid bucla. Lecția 8 a acoperit trei companii (Stripe, Shopify, Basecamp) care au rămas mai simple decât se aștepta industria și au livrat la scară pe un monolith. Lecția 56 a acoperit pipeline-ul de deployment de la Stripe, unde un singur monorepo cu servicii interne le permite să livreze de sute de ori pe zi fără să plătească costul complet de coordonare al microservices. Ambele cazuri arată spre aceeași lecție: arhitectura care câștigă e de obicei cea care se potrivește echipei și sarcinii, nu cea care câștigă războiul de pe blogurile de arhitectură.

Citations

  • “Deconstructing the Monolith”, Shopify Engineering, 2019, https://shopify.engineering/deconstructing-monolith-designing-software-maximizes-developer-productivity, retrieved 2026-05-01.
  • “Scaling up the Prime Video audio/video monitoring service and reducing costs by 90%”, Amazon Prime Video Tech, March 2023, https://www.primevideotech.com/video-streaming/scaling-up-the-prime-video-audio-video-monitoring-service-and-reducing-costs-by-90, retrieved 2026-05-01.
  • David Heinemeier Hansson, “The Majestic Monolith”, Signal v. Noise, https://m.signalvnoise.com/the-majestic-monolith/, retrieved 2026-05-01.
  • Martin Fowler, “Microservices”, https://martinfowler.com/articles/microservices.html, retrieved 2026-05-01.
  • Sam Newman, “Building Microservices, 2nd Edition”, O’Reilly, 2021. Standard reference for the trade-offs.
  • Conway, M. E. “How Do Committees Invent?”, Datamation, 1968. The original Conway’s law paper.
Caută