Sådan struktureres kodelager: Multi, Mono eller Organic?

Foto af Joren på Unsplash

Den nyeste debat i byen er, om du skal opbevare dine tjenester i et enkelt depot eller flere små depoter.

Ideen med flere små opbevaringssteder er, at koden til hver af din apps mikrotjeneste opbevares i en egen opbevaring. Med en mono-repo opbevarer du al koden i et enkelt depot og distribuerer koden som mikroservices.

Så hvad skal du bruge? At være for stiv med hensyn til en enkelt tilgang - uden at overveje formålet og anvendelsen af ​​hver tilgang - kan føre til negative resultater på lang sigt. Hvis du er opmærksom på, hvornår du skal bruge hver, kan det øge din produktivitet og forbedre dit projekt.

For at bøje reglerne skal vi først forstå, hvorfor de findes.

En fælles anbefaling er at have et uafhængigt arkiv for hver app / tjeneste. Men hvorfor? Fordi vi har et arkiv for hver mikrotjeneste, opnår vi:

  • Frihed til at skrive kode forskelligt og uafhængigt af alle andre tjenester.
  • Hastighed i at foretage kodeændringer, mens rettelse af fejl, foretage opdateringer, test og installation. Da ændringer kun skal testes i et enkelt arkiv, er implementeringen af ​​koden hurtigere og mere pålidelig.
  • Adskillelse af kode som uafhængige enheder, der forhindrer bug lækager og ydelse flaskehalse mellem tjenester.
  • Klart ejerskab af hver depot og service, hvilket er især nyttigt for store teams.

Men hvorfor opstod behovet for mono-repos?

Det er klart, at multirepo-tilgangen har sine fordele. Men det kommer også med sine egne udfordringer, især i projekter med et stort antal mikroservices, der bruger de samme rammer, sprog, tech-stacks osv.

Et par af disse udfordringer er:

  • Håndhæver standarder og bedste praksis på tværs af alle lagre. Med en multi-repo skal ændringer i kodestandarder og bedste praksis replikeres på tværs af lagre. Med en mono-repo kan alle ændringerne udføres ét sted.
  • Arbejdet med at vedligeholde delte eller fælles komponenter. Sikkerhedsrettelser, versionopgraderinger og fejlrettelser involverer at sikre, at disse ændringer foretages på tværs af alle lagre, og at de fungerer problemfrit overalt. (På en side-note oppustes den gentagne kode i hver tjeneste også dens størrelse.) I en mono-repo kan vi foretage opdateringer ét sted, hvilket sparer både tid og hovedpine.
  • Ende-til-ende-test i tandem med tæt beslægtede eller afhængige tjenester lige fra udviklerens maskine. Ved at have al koden ét sted letter vi processen med at starte alle de relaterede tjenester og køre ende-til-ende tests.
  • Lokal implementering af kode til andre virksomheder. Ved at implementere en mono-repo som mikroservices sparer vi tid og reducerer den overflødige indsats med at starte opstrimling af hvert arkiv.

Der er helt klart fordele og ulemper ved begge tilgange, og hver fremgangsmåde vil have sine egne fordele under forskellige omstændigheder.

Derfor har vi vedtaget den tilgang til at forblive fleksibel og bruge både multirepos og mono-repos, men først efter fuldstændig forståelse af, hvorfor vi har valgt at bruge hver til hver service. Dette har ført til, at vi har flere repos, der indeholder flere mikroservices, adskilt på en måde, der har gjort:

  • Vedligeholdelse og opdateringer både let og hurtigt.
  • Placering af koden til fejlfinding eller ændring meget mere struktureret.
  • At ombordstille nye holdkammerater lettere.

Hvordan vi beslutter, hvilken type depot, der skal bruges

Følgende overvejelser har hjulpet os med at beslutte, hvornår vi skal bruge mono-repos kontra multirepos.

1. Tænk på den kode, der vil tjene som grundlaget for tjenesten.

Begynd med at identificere ligheder i kode, vedligeholdelse og opdateringer. Hvis flere lagre har identisk kode, ville det være bedre at klubbe dem i et enkelt depot.

Friheden til at skrive kode forskelligt og uafhængigt af en tjeneste er en af ​​fordelene ved flere små oplagringssteder. Men ofte vil tjenester have en masse identiske stilladser, hvis de bruger det samme sprog, rammer, logning, bootstrap-scripts, mellemvarer osv. Genbrug af disse delte stilladser sparer tid.

For eksempel har Collect - vores primære dataindsamlingsværktøj - flere mikrotjenester, der er bygget på en identisk ramme. Disse tjenester er bygget på Node.js, Express og Parse Server. De deler en masse biblioteker som Winston, Mongoose og andre tredjepartsintegrationer. Tidligere, når hver af disse tjenester havde et eget oplagringssted, opdaterede eller rettede en fejl i nogen af ​​disse delte moduler betød opdatering og testning af hver opbevaring separat. Dette var langsomt og besværligt.

Men når vi klubede dem sammen i en mono-repo, blev test og opdatering af de delte moduler lettere og hurtigere. Det blev lettere at anvende sikkerhedsrettelser og håndhæve standarder, da udviklere kan udføre alle ændringer på et sted.

Den potentielle risiko for en mono-repo er, at en udvikler kan genbruge kode, der oprindeligt var skrevet til et ikke-relateret modul. Når de to moduler deler kode, kan ændring i denne fælles kode føre til fejl. Hvis disse fejl ikke markeres, kan de påvirke CI / CD (kontinuerlig integration og levering) rørledninger for ikke-relaterede mikrotjenester. For at undgå sådanne problemer er det vigtigt at have en stærk testsuite på plads.

2. Kontroller, om du har nogen moduler, der er meget forskellige fra resten.

Udvikler du et modul, der kræver en meget anden teknologi, sprog, rammer eller vedholdenhed? Derefter vil det være bedre at adskille det ud i et separat arkiv.

I Collect er der tjenester, der håndterer behandling af begivenheder i bulk. De opretholder køer, udfører tilpassede scripts og har en helt anden fejlhåndteringsmekanisme. Disse tjenester er skrevet i Python, og ofte har de brug for at udføre CPU-intensive opgaver.

Så da vi tænkte på omstrukturering af koden for Collect, blev disse tjenester i en separat repo mødt som selvindlysende. Disse tjenester var meget forskellige fra Collect's hovedlager (beskrevet ovenfor). Mens hovedopbevaringsstedet var til brugervendte anmodninger, handlede denne repo om baggrundsopgaver og henrettelser. Forandringsstyringen i disse tjenester ville også være anderledes og isoleret fra hovedlageret.

At tænke på vedligeholdelse af koden og hvordan det vil udvikle sig over tid førte til, at vi klubede disse tjenester i et separat depot. Ved at gøre det var vi i stand til at oprette et helt andet ændringsstyringssystem, som viste sig at være meget nyttigt og mere produktivt.

3. Overvej usikkerheden og derfor hyppigheden af ​​ændringer, som en tjeneste kan gennemgå.

Når du begynder at arbejde på noget, der er meget usikkert (enten hvad angår omfanget af problemet eller selve implementeringen), kan det at have et andet arkiv give dig den hastighed og frihed, du har brug for til at teste ting.

Sig f.eks., At du vil teste en ny måde at behandle billeder til at identificere objekter. Du vil fortabe med maskinlæring, men du er stadig usikker på, hvordan den vil udvikle sig, eller om problemklaringen vil ændre sig dramatisk. I dette tilfælde ville det være klart bedre at have et separat lager og derefter komme til et punkt med sikkerhed. Omvendt, hvis du mener, at API'en har nået stabilitet og vil forblive uændret i en lang periode, kan du tage et opkald for at flette det med et af dine hovedlager.

Bloggen blev oprindeligt offentliggjort på blog.socialcops.com. Ovenstående er, hvordan vi håndterer vores depotbeslutninger. Jeg håber, det kan hjælpe dig med at tænke ud fra de første principper, hvis du nærmer dig dette problem. Abonner på vores nyhedsbrev for flere opdateringer fra SocialCops Engineering and Data Science Team.