Microservicii

Niște păreri
Published on May 12, 2020
microservices rants

About 7 minutes of reading.


Acum doi ani, dacă mă întrebai ce părere am despre microservicii, îți voi fi răspuns că nu-mi place ideea. Asta pentru că am fost obișnuit cu monoliți bine construiți, în echipe relativ mici, pe care le „păzeam” de denaturare fiind foarte atent la direcția în care se mergea. După părerea mea - valabilă și azi - multe lucruri care se pot face în baza de date, ar trebui făcute în baza de date. Nu are niciun rost să reinventezi un view. Nu are niciun rost să nu folosești relațiile dintre tabele, regulile de „constrain”.

Cum se naște un monolit?

Atât timp cât echipa e mică, nu se poate numi că lucrează la un monolit. Abia după ce business-ul crește destul de mult, după ce hoarde de ingineri se adaugă proiectului, se poate numi că se lucrează cu un monolit. Înțeleg foarte bine rezistența pe care o are - în general - managementul, atunci când le spui că s-a ajuns la un monolit și e timpul să se migreze spre microservicii. E simplu: vor să scaleze prin adăugarea de noi resurse umane, dar nu au nicio idee despre cum trebuie să crească procesul.

Echipele - în ansamblu - se mișcă mai încet, decât echipa „inițială”, pentru că sunt mult mai conștiente de riscurile implicate de schimbare. De regulă, riscul vine din modalitatea de cuplare a codului („tight coupling”), de unde se poate spune că un monolit scris bine, adică decuplat, nu e chiar un monolit.

Nu e chiar evident, dar pe lângă scăderea nivelului de inovare, de posibilitate de a interveni în cod, scade și nivelul de „fericire” al dezvoltatorilor. Asta implică riscul să-ți plece resursele, pentru că ceea ce dezvolți se face cu sânge și cu lacrimi.

Cum se poate observa că ai ajuns în situația de a lucra cu un monolit:

Spre microservicii

Așa cum am spus, acum doi ani nu-mi plăcea termenul de microservicii. Asta pentru că nu are o definiție unanim acceptată, pentru că de obicei opiniile sunt atât de împărțite încât este necesar un volum imens de muncă de convingere pentru a cădea de acord cu niște chestii.

Ca să nu bat câmpii, o să trec la concret. În decembrie 2018, m-am alăturat unei echipe destul de mari cu scopul de a transforma un monolit într-o serie de microservicii. Problemele, ca întotdeauna, au venit din motive de resurse umane: arhitecți cu „viziuni” inovatoare, plini de orgolii și filme SF în cap, o adunătură de programatori de PHP, care nu făcuseră nici măcar minimul efort de a adopta o serie de convenții sau un Laravel, ceva, orice, un management absolut nepăsător despre procese.

Aproape un an de zile am insistat pe oameni și procese, dar asta e altă poveste.

Înainte să te apuci să spargi un monolit într-o serie de microservicii, cred că ar trebui să ai o părere foarte clară despre:

Probleme

Una dintre cele mai deranjante probleme pentru mine, o reprezintă faptul că sunt folosite tehnologii pe care nu le înțelegem la fel cu toții. O experiență neplăcută am avut cu AWS SQS, în sensul că echipa cu care lucram îl folosea așa cum credea de cuviință, mai exact, după fiecare request, folosea metoda „adormirea” pentru un interval de timp. Deși pot să înțeleg că asta au găsit pe StackOverflow, nu pot să înțeleg de ce, după ce-am scris un proof-of-concept care era capabil să proceseze 6750 de mesaje pe minut, am primit un răspuns de genul „deși soluția ta e bună, nu o putem băga în producție pentru că deja am testat o serie de funcționalități”. Păi frate, trebuia făcut ca lumea de la bun început.

De curând am văzut o prezentare, în care se povestea că au ales Kafka ca event bus și că simt că s-au fraierit. Mi se pare și normal să pățești așa ceva, pentru că înainte de toate trebuie să-ți stabilești nivelul de cunoaștere: oare chiar știu cum funcționează pub-sub? Oare chiar înțeleg ce face Kafka, în scenariul în care îl folosesc drept event bus? Oare n-ar fi mai bun Apache Flink? Sau NATs? Mai ales NATs, că e scris în Go…

Viziunea mea asupra unui microserviciu care expune REST API este că nu trebuie să aibă niciun fel de rute. Fără /users, fără /account/0. Verbele HTTP ar trebui să fie de ajuns pentru un microserviciu care face exact ce spune definiția aia Linuxistă: do one thing and do it well. Că tot vorbim de REST API, m-am tot mirat de ce echipele cu care am lucrat nu au grijă să nu întoarcă null-uri în răspunsurile lor json. Probabil că nu a măsurat nimeni cât bandwidth e folosit aiurea, doar ca să spui că ceva nu există. Să zicem că e 3%, pentru 1GB pe oră de date transferate. Vi se pare puțin? Mie nu.

Probabil că v-ați întrebat, ca și mine, de ce este prezent Elastic Search într-o mulțime de soluții. Păi, să vezi și să nu crezi, atunci când transformi monolitul într-o serie de microservicii, mai și pierzi ceva. Acel ceva se numește posibilitatea de a face search. Adică search items with price range this and that, with color red and produced by producer X s-a dus rândeaua. E foarte greu să scrii acest search folosind microserviciile pe care tocmai le definești. Și-atunci faci ghem toată informația și-o bagi în elastic search, ca să poți să faci căutări.

Am văzut o rezistență la învățare, cam peste tot. Când spui „ar trebui să folosim SAGA drept design pattern” sau „hai să nu reinventăm apa caldă, chestia asta pe care vreți s-o inventați are un nume, și anume event sourcing, command and query responsibility segregation, etc” și nu se întâmplă nimic, ceea ce se produce este în pericol de a fi absolut inutil. Oamenii ăia de le-au dat nume acestor pattern-uri, s-au întâlnit exact cu aceleași probleme pe care tu încerci să le rezolvi.

Apropo de rezistență la învățare, unul dintre cele mai mari pericole este mind-set-ul. De exemplu, un programator de Javascript vine și-ți face un Future în Go. Și-i spui, „Gicule, uite tată aici:”

c := make(chan int)      // future
go func() { c <- f() }() // async
value := <-c             // await

Dar el nu, și nu. Și exemple ca ăsta am o groază.

Întotdeauna mă gândesc întâi la transport. Asta pentru că pierderea de timp îmi pare să aibă drept sursă, modalitatea în care noi, dezvoltatorii de soluții, transformăm continuu ceva în altceva. Deci primești json, transformi în ceva pe care-l înțelege mysql. Și-l transformi și în protobuf, pe care-l înțelege alt microserviciu. Și-l transformi și în ceva pe care-l înțelege elastic search. Aparent, toate sunt necesare. Ei bine, nu sunt. Principalul e să le cauți, iar după ce le-ai găsit, să le eviți.

În loc de concluzie

Să transformi un monolit într-o gașcă de microservicii e un lucru foarte complicat. Și succesul depinde de foarte multe variabile.

comments powered by Disqus