Cu ce provocari tehnice v-ati lovit in ultima perioada

Cu ce provocari tehnice v-ati lovit in ultima perioada?
Cum le-ati abordat?

Poate si la ce proiecte interesante ati lucrat?

1 Like

Lucrez pe un proiect relativ complex si imi ia foarte mult pana imi ajunge codul in prod.

Nu la complexitate gen trimis rachete le luna ma refer, ci la faptul ca sunt undeva la 80+ servicii. Fiecare face ceva specific insa limbajul de business a dus la niste denumiri destul de specifice pentru anumite entitati iar mie imi ia foarte mult timp numai pana ma dumiresc.

PS. Aveti mare grija la complexitatea pe care o introduceti in cod cu fiecare feature. Mentenanta costa enorm si in ziua de azi multe sisteme tind sa fie(sa devina) distribuite(ma feresc de cuvantul sacru microservicii). Asta vine cu un overhead foarte mare pe partea de ops, iar daca si business logic-ul e greu de inteles, o sa fie din ce in ce mai ne-fun sa lucrezi acolo.

P.P.S Am ajuns la concluzia ca sa scrii cod simplu este defapt foarte complicat si ai nevoie de niste ani de experienta sa faci asta. Hah…cine ar fi crezut?

3 Likes

complicat e sa nu scrii cod :slight_smile: sau sa stergi cod existent

3 Likes

Si eu m-am complicat. Laun moment dat, chiar am avut trust issues in mine. :frowning:

Sa scrii cod simplu mi se pare si mie complicat.
KISS nu-i chiar asa de usor.

N-au fost create acele servicii pentru a putea fi modificate individual in prod?

Teoria microserviciilor e foarte misto pana cand privesti bestia in ochi.

Mai concret, un use case in aplicatia asta implica mai multe call-uri catre mai multe microservicii. Unele fac RPC(gRPC) calls catre altele, unele au consumeri care citesc informatia de undeva(nici aici nu e single source of truth, avem si kafka si cloud pub/sub). O sa vad daca pot sa fac un prin screen in Kiali ca sa vezi ce “ghem” avem, dar trebuie sa am grija cu informatiile confidentiale… O sa vad cum o sa fac. Daca vii la bere diseara poate imi e mai usor sa iti arat.

Ideea e ca o aplicatie evolueaza in ani. Incepe intr-un fel, se mai schimba developerii, se continua in alt fel, se mai schimba iar developerii, etc. Toate astea inseamna complexitate, fie esentiala fie accidentala, adaugata pe proiect. Si va fii din ce in ce mai greu sa faci ceva acolo.

2 Likes

E una dintre intrebarile mele preferate la interviu. Monolith vs microservices, de ce, ce avantaje si dezavantaje are fiecare paradigma. Acolo vezi cine are experienta si cine stie doar teorie.

Mi-ar fi placut, dar nu-s in tara :slight_smile:

Intrebarea e foarte buna mai ales pentru un nivel de senioritate peste medium. Nu as intreba juniorii desi nu strica sa stie macar putina teorie si aici.

Una peste alta, nu cred ca neaga nimeni faptul ca microserviciile sunt aici ca sa ramana. Bineinteles, si monolitii la fel. Dar ideea e ca trebuiesc separate avantajele folosirii lor de hype-ul din spate. Multa lume nu face asta. Inclusiv lume orientata mai mult spre business decat spre tech.

Cand se ia decizia sa se mearga in directia microservicii, business-ul trebuie sa isi asume asta. Ce am invatat eu in ultimii ani cand am lucrat in paradigma asta:

  • nu te apuca de microservicii in 3 oameni. Overheadul e mult prea mare.
  • nu te apuca daca nu ai devOps/SRE.
  • nu te apuca de microservicii daca nu stii sa faci monoliti cum trebuie prima oara. Adica ai nevoie de niste oameni cat de cat cu experienta in echipa cand pleci la drum. Cu cat mai mullta cu atat mai bine. Eventual experienta chiar in microservicii.
  • e bine sa ai un “sasiu” al microserviciilor. Un template daca vreti. Si fiecare nou microserviciu sa urmeze acelasi template. Reduci mult din complexitate.
  • tot la capitolul sasiu e bine sa pleci din prima cu observability in mind. Adica logs, traces si monitoring(+alerting). Credeti-ma ca e mai bine sa incepi cu ele decat sa le adaugi dupa.
3 Likes

Code coverage in pipeline doar pe fișierele schimbate. (Folosesc Nx.dev si are o comanda de affected)

Nx affected funcționează cu ajutorul lui git, ii dai base-ul și head-ul si cu schimbarile la cod in commiturile dintre ele generează un dependency graph și de aici stie ce a fost afectat sau nu. Îl folosesc să rulez doar unit testele la librăriile afectate.

Totul e frumos local, dar pe gitlab prima problemă e că îți ia doar ultimele 10 commituri la fetch, dacă ai mai multe nu știi de ce nu vrea să meargă. Trebuia să setez strategia la git să ia toate commiturile.

După nx e gândit pentru monorepo, noi folosim git flow pe branchuri de mainline si branchuri de release-uri pe monorepo. (Am sugerat feature flags dar pe moment e în aer) Trebuia spart pipeline-ul în mai multe job-uri pe mainline-uri.

Acum am problema de test coverage pe codul testat, îmi dă și coverage-ul la tot ce nu e testat și desigur că e 0, deci scade la 30-40% coverage-ul și de ai 100% la ce a fost afectat.

Problema e in setarea la jest pe fiecare librarie, by default nu exclude coverage-ul de la celelalte fisiere din afara librariei…

1 Like

N-a fost foarte provocator, dar a fost foarte misto de implementat.

In joc primesc un byte array de la un websocket server. Data asta e comprimata.
Godot are nevoie de marimea originala a datei ptr. a decomprima. Nu pot sa pun informatia asta in data comprimata (duh).

Ce-am facut?
SERVER:
Am adaugat un nullbyte dupa data comprimat. Dupa aceea am adaugat data care descrie marimea datei necomprimate (in format necomprimat).

CLIENT:
Cauta nullbyte-ul incepand de la sfarsit-ul byte array. Citeste de acolo pana la sfarsitul array-ului. Converteste acei bytes intr-un int (din bytes in str, din str in int).

Alte moduri la care m-am gandit:

  • fixed size byte subarray la sfarsitul byte array cu data comprimata (dar e wasteful cand marimea e mica).
  • Trimis data asta separat, inainte de a trimite data comprimata (dar pare mai complex de implementat + posibile erori in network pot rezulta in pachete pierdute).

Sunt curios daca exista metode mai bune de a face asta, dar functioneaza ok asa si a parut cel mai simplu mod.
:smiley:

3 Likes

Mi se pare cam pe dos să pui la sfârșit datele despre mărimea blocului de date. Nu știu ce protocol ai tu acolo, dar dacă e un stream, nu prea există un sfârșit. E cam riscant să cauți un null într-un stream de date random, este foarte posibil să întâlnești un zero chiar în datele comprimate. Sau serverul închide conexiunea după ce a terminat de transferat datele?

Mult mai natural mi se pare să ai un header (unde să fie metadate și ce mai ai tu pe acolo), urmat de payload-ul binar. În fel ăsta știi cu precizie ce mărime are blocul de date care urmează. Legat de pierderi de pachete… asta nu prea e posibil într-o conexiune TCP.

6 Likes

Nu stiu exact contextul dar nu ar fi mai usoara prelucrarea daca ai folosi un format standard pentru data exchange cum ar fi JSON? Exista constrangeri care sa te faca sa lucrezi la nivel de pachete si headere? Inteleg ca ai facut si serverul si clientul deci poti folosi un protocol de nivel mai inalt care ti-ar da ulterior si o mai mare flexibilitate.

Lucrez la un proiect in care am integrat acum vreo 2 ani o librărie.
Intre timp libraria a fost abandonată de autor, iar eu nu puteam să fac update la restul librăriilor din cauză că cea abandonată nu era compatibilă cu cele noi.

Am mai scrîs despre asta. Cum că autorul care a abandonat librăria este probabil pe front.
Și că as vrea să ii copiez o parte din cod si publica o nouă librărie.

Am rezolvat prin a copia o parte din codul librăriei.

1 Like

Cu JSON probabil overhead-ul ar fi enorm, degeaba ai comprimat datele dacă binarul rezultat trebuie să-l encodezi in base64 sau altă encodare care sa poata fi reprezentata in json. Nu mai zic de overhead-ul de procesare, ca JSON-ul mai trebuie și parsat.

O idee ar fi BJSON, dar probabil e mai mare daraua. Mi se pare mult mai simplu să prefixezi pachetele de date cu un integer care sa simbolizeze dimensiunea pachetului care urmează.

Singura chestie e să ai grijă ce fel de integer transmiți, pe 32 de biti, 64 de biti, little endian sau big endian. Dar pentru asta există funcții de genul htonl/ntohl.

1 Like

Interesant. Eu folosesc doar un mock server, urmeaza ca cel final sa fie facut de un backend dev.
Am folosit python websockets. Am avut senzatia ca trimite tot pachetul din prima, nu intr-un stream, ci intr-un blob de date din prima.
Deci daca am primit un pachet, ala-i tot pachetul. (cica-i 1MB default ptr. un frame trimis de websocket)

Folosind aceasta premiza (ca datele vin intr-un pachet complet) si protocolul intre client si server e ca serverul adauga nullbyte-ul dupa streamul comprimat parea o solutie decenta.

1 Like

Prin TCP se trimite un stream, trebuie avut grija cum delimitezi bucatiile de informatie.

Websocket (ce ruleaza peste TCP) are un mecasism propriu de message framing prin care simplifica treaba. Trimiti un mesaj, asa ajunge si la client. Ca websocket il sparge si reasambleaza din bucati, e un detaliu de implementare cu care nu-si bate capul clientul.

Acum, abordarea ta mi se pare eronata din start:

  • Din moment ce websocket abstractizeaza deja message framing, cand trimiti un byte array intr-un mesaj stii ca-l primesti pe client cu aceeasi dimensiune. Daca vrei sa adaugi 4 bytes in plus la inceput/final, acei 4 bytes il gasesti la inceput/final, nu mai trebuie cautati.
  • Ce algoritm de compresie e asta care trebuie sa stie marimea originala a datei? Daca e un detaliu atat de important, de ce nu e informatia stocata in datele comprimate de catre biblioteca de compresie?
  • De ce e nevoie de compresia explicita a datelor daca Websocket suporta deja compresie la nivel de mesaje?
2 Likes

Nu eu, dar un coleg nu înțelegea de ce unele teste unde nu seta autentificarea la un API intern continuau să funcționeze. La debug pas cu pas, imediat după apelarea lui httpx.get în obiectul returnat putea să vadă că header-ul Authentication era setat cumva.

Turns out că httpx, la fel ca curl, citește fișierul ~/.netrc :slight_smile:

Apache cannot read webroot/.htaccess

Solution: Disable SELinux :smiley:

Am creat o librarie de tip ANGULAR Element care imi da batai de cap