allan ebdrup bloghoved ny

Hurtigere udrulning som forberedelse til C19-vaccinationer

Practio har budt på udbuddet om at skulle vaccinere danskerne mod COVID-19.

Man kan sige, at vi har forberedt os på denne opgave over de sidste mange år; vi har arbejdet med vaccinationer i stor skala, blandt andet på danske apoteker. Vi driver også allerede COVID-19-vaccinationscentre under NHS i samarbejde med vores partnere i UK og har gjort det i et stykke tid.

Det team jeg er en del af, står for Practio’s skræddersyede IT-platform, som bruges til at udføre og journalføre vaccinationer. IT-platformen bliver brugt i Danmark, Tyskland og UK.

Når vi kører for fuld damp med vaccinationer i Danmark, kan en times nedbrud eller fejl på IT-platformen betyde, at 5-10.000 personer bliver påvirket. Det ser vi meget nødigt sker. Derfor er det blandt andet vigtigt, at vi kan rulle en rettelse af en eventuel fejl i systemet ud så hurtigt og sikkert som muligt.

Vi har et kvalitets-princip der dikterer, at hver gang vi ruller en ændring på, så SKAL den køres gennem alle vores automatiserede tests. Kode-formatering, linting, unit-tests, integrationstest, acceptance-tests osv. Det princip har vi for at sikre, at alt stadig virker korrekt, også med den ændring vi ruller ud.

Over de sidste 3 år hvor vi har udviklet IT-platformen, er der kommet flere og flere tests til. Vi tæller dem i tusinder. Derfor er det blevet langsommere og langsommere for os at rulle en ændring ud.

For at sikre, at vi kan reagere hurtigt i tilfælde af problemer, har vi i løbet af den sidste måneds tid arbejdet på at forbedre udrulningstiden. Resultatet af disse forbedringer kan du se for vores forskellige microservices her:

Illustration: Allan Ebdrup

Vi kører stadig nøjagtig lige så mange, og de samme automatiserede tests som før. Testene kører bare hurtigere.

Sådan har vi gjort det

Vi udruller via Circle CI og vi har opnået forbedringerne ved at gøre følgende:

  • Brug store servere med mange CPU cores og meget RAM. Når dit build er 10x hurtigere, og du bruger en pay-per-use -øsning, kan du tillade dig at bruge 10x så meget på en større server og stadig betale det samme som før.
  • Læg alt du overhovedet kan i RAM og på RAM-disk, al source code, alle filer, databasefiler og logs, caches som dine build tools normalt ligger på disk osv.
  • Brug et simpelt basisimage, der kan starte op hurtigt.
  • Brug nøjagtig samme konfiguration til build på alle dine microservices, så du nemt kan rulle en performanceopdatering ud til dem alle. Mens vi har lavet disse optimeringe, har vi udrullet ændringer tusindvis af gange på vores kørende produktionssystemer, så vi har samtidig fået testet, at vores zero-downtime-deploys virker fuldstændigt som de skal.
  • Lad din ene build konfiguration automatisk detektere hvad der er brug for at installere i hvert repository, og installer kun det nødvendige.
  • Installer så meget som muligt fra .tgz filer. Disse installationer kan køre parallelt og er hurtige. Hvorimod apt-get ikke kan køre parallelt og er langsommere. Vi har stadig nogle få ting, som vi installerer via apt-get, da de har så mange dependencies, at det virker som for meget arbejde implementere og vedligeholde installation via .tgz filer. Det gælder for eksempel dependencies til at køre acceptance tests via cypress.
  • Kør alt du overhovedet kan parallelt på den enkelte maskine og koordiner buildet nøjagtig de steder hvor der er behov for det.
  • Prøv at sikre dig, at steps der tager mere end nogle få sekunder udnytter multi-core CPU’er, hvis det kan lade sig gøre. Her er dit build-step specielt vigtigt, men brug fx også --use-compress-program=pigz, hvis du zipper/unzipper tar-filer.
  • Brug flere lag af persistent caching på tværs af dine builds på strategiske steder.
  • Kør tungere builds spredt ud parallelt på flere server. Dette gør vi på cirka en femtedel af vores builds. Når vi vil køre en udrulning parallelt på flere servere, har vi implementeret, at vi bare skal rette et tal med det ønskede antal servere og så virker det. Parallel-eksekvering af builds koordineres via Redis.

Din situation er selvfølgelig unik, og I skal finde løsninger, der passer ind i jeres systemers kontekst. Jeg håber alligevel at ovenstående måske kan inspirere.

Måske kører din udrulning allerede super hurtigt? Del gerne dine egne råd til hurtigere udrulning i kommentarerne. Jeg ville ikke have noget imod at vores udrulninger blev endnu hurtigere.

Kommentarer (21)
sortSortér kommentarer
  • Ældste først
  • Nyeste først
  • Bedste først
#2 Klavs Klavsen

Hej Allan,

Du skriver: "Installer så meget som muligt fra .tgz filer. Disse installationer kan køre parallelt og er hurtige. Hvorimod apt-get ikke kan køre parallelt og er langsommere. Vi har stadig nogle få ting, som vi installerer via apt-get, da de har så mange dependencies, at det virker som for meget arbejde implementere og vedligeholde installation via .tgz filer. Det gælder for eksempel dependencies til at køre acceptance tests via cypress."

Jeg formodet der er i jeres docker builds - at du til Cypress acceptance tests skal bruge disse tools.. Men når de kommer fra apt - så er det vel de samme pakker du ender med at installere igen og igen i samme docker image (som en del af din CI).

Var det ikke bedre at lave et docker image til "cypress acceptance test" - der bygger på jeres standard image (bruger FROM) - og så bare installerer disse dependencies via apt - på den måde kan du nemt få rullet opdateringer ud til dine docker images og samtidigt genbruge så meget som muligt ?

  • 0
  • 0
#3 Allan Ebdrup Blogger

Var det ikke bedre at lave et docker image til "cypress acceptance test" - der bygger på jeres standard image (bruger FROM) - og så bare installerer disse dependencies via apt - på den måde kan du nemt få rullet opdateringer ud til dine docker images og samtidigt genbruge så meget som muligt ?

Ja det var også kontraintutivt for mig at det er hurtigere at gøre det på den måde vi gør. Men ihvertfald i vores tests var det langsommere at lave et image med alt det man skal bruge. Det er fordi at buildet er i gang med andre steps parallelt med at cypress installeres, så det har tæt på ingen impact at det installeres hver gang. Hvorimod hvis man ligger det i sit image, så bliver dit image større og din opstartstid på CircleCI bliver derfor større og det gør den samlede build tid langsommere med 10-20 sekunder.

Man kunne godt barbere ca 10 sekunder af vores build tid hvis man havde servere med alt installeret stående klar. Men nogle gange når vi fx ruller on opdatering af et modul ud, og lignende så bruger vi ca 30 servere samtidig, og sikkert flere i fremtiden. Det er nogle ret store maskiner vi bruger, så det ville være alt for dyrt for os at have dem stående klar hele tiden.

  • 1
  • 0
#5 Allan Ebdrup Blogger

Vi har en nem måde at opdatere den ene build config vi har på alle services - så vi kan nemt opdatere versioner osv.

Men hvis du spørger mig, er det en kæmpe design-fejl at CircleCI ikke understøtter en centraliceret konfiguration der gælder for flere repositories. Når hvert repository har sin egen build konfiguration, sander det hele hurtigt til, og det bliver uoverskueligt at optimere, fordi du skal gøre det i 30 unikke microservice-konigurationer. Det har vi lavet fra starten så alle repositories har samme konfiguration, og så ruller vi opdateringer og performanceforbedringer ud til alle på een gang.

Det ville have været et uoverstigeligt arbejde at optimere vores builds, hvis vi ikke havde den samme konfiguration over det hele fra starten.

  • 1
  • 0
#7 Sune Marcher

Men ihvertfald i vores tests var det langsommere at lave et image med alt det man skal bruge. Det er fordi at buildet er i gang med andre steps parallelt med at cypress installeres, så det har tæt på ingen impact at det installeres hver gang.

Men... hvis du tænker lidt over hvordan du får lavet layers i din Dockerfile, burde du så ikke netop undgå at skulle installere Cypress/whatever hvergang? – build infra'en bør bruge cachede versioner af dine base layers, og kun rebuilde layer(s) med ændrede applikationsfiler.

Hvis der startes friske CI instanser op for hvert build er der self. ikke en lokal cache i instansen, men der brude bruges et Docker registry "tæt nok på CI infra'en" til at overførsel går hurtigt – plus de enkelte layers i et image mig bekendt hentes parellelt? (med mindre i squasher layers eller bruger noget manuelt tgz import/export, men det ville være kontraproduktivt 😅).

  • 0
  • 0
#8 Allan Ebdrup Blogger

På CircleCI er der ofte ikke en lokal cache eller den er outdated, jeg tror vi har eksperimenteret med alle de indstillinger og features vi kunne. Jeg ved ikke om layers installeres parallelt på CircleCI, det kan faktisk godt være. Ikke desto mindre tager det 10-20 sekunder ekstra i build time at installere via docker layers. Fordi installationen blokerer alt andet indtil den er færdig, hvorimod den måde vi installerer cypress nu tillader andre ting at køre parallelt. Vi brugte også tidligere layers til nodejs og mongodb. De var meget langsommere end tgz filer hvor nodejs stadig er blokerende for os. Men tager ca 2-3 sekunder og mongodb ikke er blokerende og tager ca 6-10 sekunder, men har ingen impact på buildets tid for andre ting på den kritiske vej kører parallelt.

Jeg ved godt at det umiddelbart virker skørt at installere hver gang, men hvis man tænker over det, hvor forskelligt er det så egentligt far at smide et docker layer på hver gang?

Jeg kan kun opfordre til egne eksperimenter i jeres setup, måske gemmer der sig nogle overraskelser? Jeg er ihvertfald meget interesseret i at høre om dine erfaringer - jeg vil gerne lære mere.

  • 0
  • 0
#9 Sune Marcher

Jeg ved godt at det umiddelbart virker skørt at installere hver gang, men hvis man tænker over det, hvor forskelligt er det så egentligt far at smide et docker layer på hver gang?

Det lyder som om der er et eller andet uhensigtsmæssigt i jeres setup – før i skiftede til .tgz filer, blev jeres Docker images så fuldt rebuilt før hver deploy?

Som Klavs også nævner, ville min tilgang være at lave det som en totrins-raket – det lyder som om i har ét base image til alle jeres services? Det burde kunne bygges (og tagges/pushes) separat til jeres registry... og den del kan være vigtig ifht. CI systemer, man kunne måske godt tænke sig bare at bruge en multistage Docker-fil, men så er der netop en god risiko for at man kommer til at spilde tid på at rebuilde layers man egentligt ikke behøver.

Hvad der giver mening kommer naturligvis an på en del ting i jeres setup – men udfra at holde styr på versionering af Linux packages i base image, auditability, og evt. mulighed for at rulle tilbage til præcis systemversion, kan jeg godt lide at have base image sat op på den måde.

Nogle burde forresten sparke Docker-udviklerne hårdt over skinnebenene for ikke at have BEGIN/COMMIT til layers – deres "jamen det ville være en leaky abstraction"-argument er enormt elendigt, eftersom det betyder man er nødt til at have lange &&-chains for at have kontrol over hvad der kommer i ens layers... plus rækkefølgen som de jo også selv nævner er vigtig i forhold til cacheability.

Jeg kan forresten anbefale dive til at inspicere images – der kan gemme sig aha-oplevelser dér.

  • 1
  • 0
#10 Allan Ebdrup Blogger

Som Klavs også nævner, ville min tilgang være at lave det som en totrins-raket – det lyder som om i har ét base image til alle jeres services? Det burde kunne bygges (og tagges/pushes) separat til jeres registry...

Ja det var også noget af det første vi prøvede. Det er muligt at der er et problem der er CircleCI specifikt. Men det var også langsommere. Vi har snakket med CircleCI en del gange. Og det var først da vi prøvede at lade være med at gøre som alle anbefaler at tingene blev rigtig hurtige.

Som jeg skriver så er blogindlæget overhovedet ikke ment som en opskrift andre skal følge, hvert setup er unikt. Så jeg ved ikke hvor meget vi får ud af at dissektere fremgangsmåden. Pointen er at ved at virkeligt eksperimentere rent faktisk måle og fokusere på build tid at vi fik vores builds meget hurtigere.

  • 0
  • 0
#11 Sune Marcher

Så jeg ved ikke hvor meget vi får ud af at dissektere fremgangsmåden. Pointen er at ved at virkeligt eksperimentere rent faktisk måle og fokusere på build tid at vi fik vores builds meget hurtigere.

Well, det lyder som om jeres konklusion er at "gør en masse arbejde, bare lidt anderledes" er hurtigere end "lad være med at gøre arbejdet igen og igen" – så jeg synes stadig det ville være interessant at vide hvad dælen det er der rent faktisk går galt.

For måske er der noget i har overset, som gør det kunne gå endnu hurtigere, eller også er der en potentielt ret stor "oh fuck, a-ha!" gemt her for os alle sammen. Men det er lidt svært at vurdere uden en egentligt root cause :)

  • 1
  • 0
#12 Allan Ebdrup Blogger

For måske er der noget i har overset, som gør det kunne gå endnu hurtigere, eller også er der en potentielt ret stor "oh fuck, a-ha!" gemt her for os alle sammen. Men det er lidt svært at vurdere uden en egentligt root cause :)

Jeg tror desværre ikke at jeg kommer det meget nærmere end hvad jeg allerede har skrevet, uden at skulle bruge en masse tid på det - og det har jeg desværre ikke lige nu. Min analyse er stadig:

  • Et stort image blokerer meds det downloader
  • Layers blokerer resten af dit build mens de downloader. Selv om de forskellige layers måske kan installeres parallelt med hinanden, (det er er jeg ikke 100% sikker på), så skal alle layers stadig downloades på CircleCI før dit egentlige build starter.

Ovenstående gør den måde vi gør det på 20-30 sekunder hurtigere for vores builds, fordi den del der blokerer selve buildet før det starter næsten er væk (3-10 sekunder tager det). Her er CircleCI faktisk også ustabile, så Layers tager nogle gange et minut at downloade eller mere. Denne voldsomme variation fjerner man også med et simplere setup.

Men som du kan se er den ene detalje du dykker ned i ikke det vigtigste punkt i vores performanceforbedringer. De andre punkter står for langt størstedelen af forbedringen.

Hvis du vil komme det nærmere og hvis du vil lære mere, vil jeg klart opfordre dig til at prøve at eksperimentere med det selv. Jeg hører gerne om hvad du finder ud af :-)

  • 0
  • 0
#13 Allan Ebdrup Blogger

Jeg kan måske forklare at fx cyprress dependencies er ikke nødvendige at have installeret mens dit build laver sit "byg-step" (webpack osv), så cypress installeres i baggrunden mens webpack kører, og sådan er der faktisk en del ting der ikke er nødvendige før tests skal køres, de installeres i baggrunden - jeg ved ikke om det hjælper?

  • 1
  • 0
#14 Sune Marcher

Men som du kan se er den ene detalje du dykker ned i ikke det vigtigste punkt i vores performanceforbedringer. De andre punkter står for langt størstedelen af forbedringen.

Men det er vel alligevel en "betydelig" mængde, når i er villige til det ekstra vedligeholdelses-overhead i manuel installation fra .tgz? Jeg fik indtryk af i selv har pakket disse - hvis i kan grabbe færdige tarballs er det naturligvis mindre vedligehold...

Og så har jeg fokuseret på det fordi det er noget af det der lød mærkeligst at have performance-win på 😅, samtidig med det er en ret generel ting, hvor andre tweaks afhænger en del af specifik setup.

I forhold til apt-get pakkestyring, har i så givet afkald på signature verification, eller gør i det manuelt for jeres tarballs?

så cypress installeres i baggrunden mens webpack kører, og sådan er der faktisk en del ting der ikke er nødvendige før tests skal køres, de installeres i baggrunden - jeg ved ikke om det hjælper?

Jo, helt bestemt! Men ville Cypress ikke kunne være en del af base-image, eller er det noget der kræver projekt-specifik tilpasning / bleeding-edge versioner af moduler?

Her er CircleCI faktisk også ustabile, så Layers tager nogle gange et minut at downloade eller mere. Denne voldsomme variation fjerner man også med et simplere setup.

Og denne del synes jeg lyder ret interessant! Så CircleCI er ustabil i forhold til lige specifikt image pulls, men ikke når i grabber tarballs? Hvilket registry bruger i – standard DockerHub, har CircleCI deres eget, ...?

Jeg vil generelt (ikke så meget dig, Anders, som andre der følger tråden) råde til ikke at bruge DockerHub, men løber forholdsvist hurtigt ind i deres rate limits, og hvis man er afhængig af images for at kunne levere sin software, giver det god mening at betale for et registyr man selv har kontrol over, hvor man så proxyer offentlige images. Jeg ved ikke hvor hverken pris eller performance er bedst, men Amazon, Google og JFrog er tre bud på managed løsninger.

Og peering mellem CI infra og registry lader til at betyde noget... kunne være jeg skulle høre vores folk om de har målt på Google vs Amazon.

Med hensyn til parallel pull af layers kiggede jeg en smule, og standard er tre - det kan tweakes med --max-concurrent-downloads hvis man har adgang til dockerd config på sit build infra.

Der er igen en kraftig opfordring til andre: kig hvordan i styrer jeres layers. Det kan have kæmpe betydning både for om i konstant rebuilder layers, i ikke behøver at rebuilde, og hvor store jeres images ender med at blive. Vi fik vist skåret ~500meg af et image med et par facepalm-åbenlyse ændringer.

Et tip til folk i JVM-verdenen: cache jeres dependencies. Travis kan fx gøre det ret nemt... og det er noget hurtigere at få unpacked cached repo end at re-resolve alle depencies ved hvert build. (Jeg er løbet ind i et par enkelte issues på grund af det, ligesom med ca. alt andet caching, men det er normalt dét værd).

  • 1
  • 0
#15 Allan Ebdrup Blogger

Du stiller mange spørgsmål, tak for det. Noget kunne tyde på at at jeg har sat nogle tanker igang hos dig. Hvis de tanker primært går i retningen af: “Bah humbug, det er en forkert måde at gøre det på og vil aldrig virke hos os”, fair nok, så lad os bare hver især komme videre med vores liv.

Jeg har ikke skrevet blogindlægget for at overbevise nogen om noget, for at sige at nogen skal gøre som os, eller for at sige at det vi har gjort er bedre end andre måder. Jeg har skrevet blogindlægget for at inspirere nogle få af dem der læser det og fordi jeg selv var overrasket over at det kunne lade sig gøre at forbedre vores ulrulningstider så meget.

Hvis min mission derimod er lykkes, og du tænker at du måske vil prøve nogle ting af i jeres setup, så vil jeg anbefale at du går i gang med at eksperimentere - du skal alligevel finde dine egne svar på hvordan I gerne vil gøre i jeres unikke kontekst.

Du er også kommet med mange råd i tråden her, også tak for det. Det kunne da også være interessant at vide: Hvor lang tid tager udrulning af microservices hos jer? Kører I også alle tests hver gang? Har i også lavet en intensiv omgang optimering af ulrulningstiden, og hvis ja, hvad var så i overskrifter de ting der gjorde den største forskel?

  • 0
  • 0
#16 Sune Marcher

vis de tanker primært går i retningen af: “Bah humbug, det er en forkert måde at gøre det på og vil aldrig virke hos os”, fair nok, så lad os bare hver især komme videre med vores liv.

Nej – min tanke her er at der (måske!) er nogle grundlæggende problemer der kunne løses, som ville resultere i endnu bedre buildspeed og reduceret kompleksitet. Men jeg ved også godt at vi i det virkelige liv nogle gange er nødt til, for en periode, at acceptere workarounds i stedet for root cause fixes, fordi de virker godt nok og andre ting har højere prioritet.

Men jeg kan godt lide at løse problemer, og bliver nysgerrig når noget ikke virker som forventet :)

Du er også kommet med mange råd i tråden her, også tak for det. Det kunne da også være interessant at vide: Hvor lang tid tager udrulning af microservices hos jer? Kører I også alle tests hver gang? Har i også lavet en intensiv omgang optimering af ulrulningstiden, og hvis ja, hvad var så i overskrifter de ting der gjorde den største forskel?

Alt for lang tid! :)

Vi har et forholdsvist stort og kompliceret servicelandskab, med alt fra microservices til monolit(ter). Nogle har en hel del år på bagen, og kan være ret tunge at danse med.

Jeg har ikke en liste med konkrete tal (og hvis jeg havde var jeg nok nødt til lige at cleare om jeg måtte dele :)), men for en af de services jeg ofte arbejder med er 10+ minutter fra Git -> Build/Test -> k8s desværre ikke ualmindeligt.

Der er hele tiden arbejde med forbedringer, men det er som altid en balance mellem features, bugfixes og maintenance/improvements.

Det er helt klart tests der dominerer vores buildtid, og vi ville kunne vinde en del hvis vi fik paralleliseret dem – det er dog ikke trivielt pga. legacy testsuites... og der er naturligvis også dele der ikke kan paralliseres, fx service flows i integrationstest.

Nogle af de ting vi har gjort er...

Image size reduktion - det giver ikke super meget når buildtime domineres af test, men der er nogle forholdsvist lavthængende frugter i fx at bruge Alpine images og tænke over sin layering. Plus det kan føre til ikke at gentage arbejde igen og igen, hvilket kan være et stort win. (Og efter build, når pod shuffles rundt eller skaleres på et k8s cluster kan der self. være noget at vinde på 200meg vs 1gig images).

At lave en stor del af de automatiske test mod mocks, i stedet for at skulle deploye hele servicelandskabet. Der er pros/cons, test mod mocks kan naturligvis ikke stå alene, og der er en lang og spændende diskussion her. For os har det også betydet vi har kunne vinke farvel til dyre, langsomme og ustabile individuelle Google stacks per udvikler, og kan arbejde med enkelte services på lokale maskiner - det er der mange wins i.

Flyt fra DockerHub til andet repo, og lad helt være med at bruge DockerHub i build infra. Stabilitet, hastighed, sikkerhed... plus min personlige mening er det er uetisk med mindre du har en paid plan. I den forbindelse: der kan være DH referencer mange sjove steder... Fx kubernetes service liveness check der bruger et curl image, eller TestContainers der bag om din ryg hiver images ned.

I "der er nok et underlæggende problem der kan fixes"-kategorien (😉) har vi fx set at build parallelisation kan ende med at blive langsommere – ved en service brugte vi længere tid på at Jenkins skulle schedule del af build til ny node, end vi vandt ved paralleliseringen.

Og pt. kigger vi lidt på Java native image building – det vil sløve buildtime gevaldigt ned, for til gengæld at få nogle performance gains. Der ligger nogle interessante overvejelser, det er fx klart at hvis man vil deploye en native compiled app skal den testes med native build... men kan man fx acceptere at de enkelte Pull Requests tests med ikke-native?

  • 2
  • 0
#18 Sune Marcher

Tak for at du deler erfaringer, der er interessant 👍🏻

I lige måde :)

Forresten, du skriver:

men brug fx også --use-compress-program=pigz, hvis du zipper/unzipper tar-filer.

Giver pigz hastighedsfordel ved dekomprimering? De skriver i manpage at selve dekomprimeringen ikke kan paralleliseres, men at der er nogle tråde til read/write/check-calculation. Men kan det mærkes, specielt hvis det bruges i en tgz unpack pipeline?

  • 0
  • 0
#19 Allan Ebdrup Blogger
  • 1
  • 0
#21 Sune Marcher

Du skulle vel ikke lige have et par gode links til diskussioner på området?

Desværre ikke på stående fod, men jeg har lige spurgt vores Mock-It arbejdsgruppe om de fandt noget godt materiale, mens de fik sparket initiativet i gang - jeg vender tilbage, hvis de kommer med noget :)

Hvad der virker kommer nok an på ret mange faktorer, ikke mindst hvor mange services samt udviklere man har. Men her er lidt overvejelser, der også rækker lidt ud over mocks:

  • Det virker sandsynligvis bedst at de enkelte teams laver egne mocks af de services de bruger, fremfor at man prøver at centralisere opgaven, eller påligger service owners også at lave mocks.

  • Sørg for at få developer buy-in fra start, der ligger en del arbejde i at lave og vedligeholde mocks. Det skulle dog helst opvejes af fordelene, så præsentér det ærligt mens i planlægger, unlad at komme med "Så, nu har vi lagt en plan, og her er dekretet om i skal bruge mocks fra næste måned". Vi havde en arbejdsgruppe og fik tovholdere i de enkelte teams, og startede med en fokuseret indsats på et par teams, hvor læringerne derefter kunne bruges til resten af organisationen. Derudover blev der arbejdet på en intern cookbook (wiki format) med tips, tricks og recipes.

  • Mocks kan naturligvis ikke stå alene, så der skal suppleres med andre former af test. Til webapplikationer kunne det fx være automation helt ude fra frontend, så får man det meste med... men man skal også lige huske APIer og integrationer.

  • Det er superlækkert at kunne lave størstedelen af udviklingen på lokale maskiner, men der er naturligvis også behov for at kunne teste op mod det rigtige servicelandskab. Det her er nok ret afhængigt af størrelse, men for os har det virket rigtigt godt at vi udover der typiske miljøer også har multi-team (basically forretningsområde) environments som vi har fuld råderet over, som kører permanent. Det koster naturligvis noget, men det kan gøres med mindre instanser end de "rigtige" environments, og vi kan så lave superhyppige deployments af eksperimentel kode med så lille blast radius ifht. at forstyrre andre teams som muligt.

  • Feature flags. Det er en rigtigt god idé at kunne trykprøve nye features mod en begrænset målgruppe, eller kunne slå det helt fra hvis uheldet er ude. Det er heller ikke dumt i forhold til de overvejelser man kommer til at gøre sig i forhold til testability og kodestruktur. Hvis man ikke vil bruge en managed service, er Flagr et godt bud.

  • Der er en del muligheder ifht. at skrive mocks. I mit tidligere arbejde havde vi glæde af jeg smækkede nogle Kotlin mocks/microservices sammen, mens vi ventede på leverancer fra langsommelige leverandører til togverdenen. Nu her bruger vi bl.a. WireMock, som er ret fin og fleksibel. Til de simplere services kan du basically pattern-matche requests og servere json/xml/whatever, og ellers er den fuldt programmérbar. Jeg vil anbefale at man kun bruger de filbaserede mappings til meget trivielle ting – til større mængder testdata, eller data med mange referencer, er det nemmere at bruge kodenavigering i et IDE end at søge på tekststrenge på tværs af json/xml filer.

  • Vi har også haft glæde af MinIO. Både lokal udvikling og integrationstest (og evt. test-clusters) kan laves mod de rigtige S3 APIer, hvilket både er lidt mere realistisk end fx. at gøre det mod in-memory repositories, samt billigere og hurtigere end S3. God performance og supernemt at sætte op.

Og der er helt sikkert en masse mere, det her var off top of my head. Jeg hører rigtigt gerne hvad du eller andre har af overvejelser og erfaringer :)

  • 2
  • 0
Log ind eller Opret konto for at kommentere