Fra Proof of Concept til Stabil Produksjon: En Vei Utenom Testing
Mange vellykkede prosjekter begynner i dag med en Proof of Concept (POC). Dette er en innledende, begrenset vurdering av en idé, hvor man sjekker ut den valgte teknologien og funksjonaliteten. Man ser på hvordan dette kan påvirke brukerne, og dersom ideen er god, settes et fullt team på saken for å utvikle et komplett produkt for produksjon.
Dette passer perfekt for et Scrum-team. Teamet kan raskt utvikle en prototype og legge til nye funksjoner i hver sprint. Brukerne kan se hvordan ideen utvikler seg i løpet av omtrent ti sprinter. Dette gir et godt inntrykk, som er hovedmålet med en POC, men det kommer med en bakside: minimal testing. Å tenke på en testprosess ville nesten være komisk.
I et Scrum-team er testing ikke en favorittaktivitet. Folk liker ofte tanken på å utvikle uten prosesser som sinker dem. Det er jo det testing i bunn og grunn gjør. Og hvem ønsker unødvendig treghet når man skal imponere sluttbrukeren?
Problemet oppstår når prosjektteamet fortsetter på samme måte etter POC-fasen. Da får man det jeg kaller «POC på steroider» – et produksjonssystem som vokser i størrelse og funksjonalitet, men som fortsatt oppfører seg som en POC. Det er et uferdig produkt med skjulte feil og uutforskede hjørnetilfeller, som bare venter på en alvorlig feil.
Teamet vil få det vanskeligere for hver sprint med å holde tritt med stabile utgivelser. Det blir vanskeligere å fikse de stadig tilbakevendende problemene.
Her er noen teknikker som har fungert for meg tidligere, og som jeg mener er god praksis for å implementere solide testprosesser uten å ødelegge utviklingsfremgangen, noe vi alle ønsker i et Scrum-team.
Fordel Ansvaret
Hvor skal vi ellers starte når vi skal håndtere unødvendige problemer, enn å dele på ansvaret? Det jeg mener er å lage en plan som krever litt ekstra innsats fra utviklerne, men som bidrar til fellesmålet over tid, stegvis men konsekvent.
#1. Enhetstester for Hver Nye Kode
Hvis du klarer å overbevise Scrum-teamet ditt om å inkludere utvikling av enhetstester for ny kode i «Definition Of Done», vil det være en stor seier på lang sikt.
Grunnene er ganske klare:
- Det tvinger utviklerne til å tenke på ulike veier for koden.
- Enhetstestene kan kobles til automatiserte DevOps-rørledninger og kjøres ved hver distribusjon til utviklings- eller testmiljøet. Rørledningens resultater kan eksporteres og brukes til å vise testdekningen til brukerne.
Det viktigste er å starte tidlig. Jo senere enhetstestene begynner å utvikles, desto mer vanskelig blir det for utviklerne å legge dem til i en sprint.
- Det vil kreve betydelig innsats å legge til enhetstester for eksisterende kode. Deler av koden kan være skrevet av andre utviklere, og kunnskapen om hvordan den fungerer er ikke like klar for den nåværende utvikleren. I noen tilfeller kan det ta lengre tid å legge til en enhetstest enn å utvikle en funksjonsendring (noe som ikke er regnet med i sprintplanleggingen).
#2. Test Rutinemessig i Utviklingsmiljøet
Før man sender inn en pull-forespørsel for å slå sammen ny kode i hovedgrenen, bør det være standard å teste både funksjonskoden og enhetstestkoden i utviklingsmiljøet. Dette sikrer at:
- Enhetstestkoden faktisk fungerer for hver kodebit. Dette trinnet hoppes ofte over. Man antar at enhetstesten vil bli kjørt et sted i DevOps-rørledningen. Dette fører bare til problemer i senere faser av sprinten, der teamet har mindre tid og mer stress.
- Den nye funksjonskoden er testet av utvikleren for grunnleggende funksjonalitet. Man kan ikke forvente at testen verifiserer forretningsfunksjonaliteten fullt ut, men den vil bekrefte at koden oppfører seg slik utvikleren hadde tenkt.
#3. Enhetstesting Etter Sammenslåing til Hovedgrenen
Det er én ting å ha fungerende kode i den lokale grenen, men en helt annen ting å ha den samme koden fungerende etter sammenslåing til hovedgrenen. Hovedgrenen inneholder endringer fra andre teammedlemmer. Selv om konfliktene er løst, er koden etter sammenslåing uprøvd, og det er risikabelt å sende den videre uten å sjekke at den fortsatt fungerer.
Det som har vist seg effektivt, er å kjøre de samme enhetstestene, som allerede er gjort i utviklingsmiljøet, også i miljøet bygget fra hovedgrenversjonen.
For utviklerne kan det være et ekstra skritt, men det krever ikke mye innsats, siden de bare må utføre noe de allerede har gjort en gang.
Dette trinnet kan hoppes over i ett tilfelle:
Selv om dette er mulig, har jeg aldri sett det i praksis. Det ville nok være for tidkrevende for utviklerne å lage så detaljerte automatiserte enhetstester. Produkteieren vil neppe la teamet bruke så mye tid på det, siden det vil påvirke antall leverte historier i løpet av en sprint.
Men innhold i sprinten skal aldri være en unnskyldning for å droppe enhetstesting. Hvis man gjør det, vil koden mangle enhetstestdekning, og det kan være for sent å ta igjen (jo høyere innsats for å fullføre enhetstesten, enn den faktiske kodeendringen i en sprint).
Derfor anbefaler jeg å kjøre enhetstestene på hovedkodeversjonen. Det er en liten innsats for den verdien det gir.
Det er en siste sjekk av hovedgrenen for testfasen. Det hjelper også med å finne de fleste tekniske feil, slik at neste fase kan fokusere på forretningsfunksjonaliteten.
Forberedelse til Funksjonstesting
Alle de tidligere testaktivitetene skal lede til én konklusjon: Hovedgrenkoden er fri for tekniske feil og kan kjøres uten problemer.
Denne fasen kan enkelt dekkes av én person, som ikke engang trenger teknisk bakgrunn. Det er bedre om dette gjøres av noen som ikke er utvikler, men som forstår hvordan forretningsbrukere forventer at koden skal fungere. Det er to hovedaktiviteter som skal utføres:
#1. Funksjonstesting av Nye Sprinthistorier
Hver sprint skal helst bringe ny funksjonalitet (sprintmål), som må verifiseres. Det er viktig å sikre at den nye programvaren fungerer bra, slik at brukerne er fornøyde med den. Det er trist når den lovede funksjonaliteten ikke fungerer som den skal når den lanseres.
Derfor er riktig testing av ny sprintfunksjonalitet viktig. Det er god praksis å samle testtilfeller fra relevante interessenter (produktets eier eller sluttbrukerne) og lage en liste over alle testtilfellene for sprintens innhold.
Dette kan virke overveldende, men i praksis er det håndterbart for én person. Siden sprintene er korte (to uker), er det ikke for mye nytt innhold, siden sprinten også inneholder teknisk gjeld, dokumentasjon og design.
Testtilfellene utføres for å verifisere funksjonaliteten. Hvis det oppstår et problem, henvender man seg til den aktuelle utvikleren for å løse det raskt. På denne måten vil utviklerne bruke minimalt med tid på funksjonell testing og kan konsentrere seg om det de liker best.
#2. Utførelse av Regresjonstester
Den andre delen av funksjonstesting er å sikre at alt som har fungert frem til nå, også fungerer etter neste utgivelse. Det er det regresjonstester er til for.
Regresjonstesttilfellene bør vedlikeholdes og gjennomgås før hver utgivelse. Basert på prosjektspesifikasjonene, bør de være enkle, men dekke de fleste kjernefunksjonene. Systemer har vanligvis prosesser som berører mange forskjellige områder. Det er de beste kandidatene for regresjonstesttilfeller.
Noen ganger dekker regresjonstester også nye funksjoner i sprinten, hvis den nye historien endrer en del av den eksisterende flyten. Det er ikke komplisert å gjennomføre regresjonstester sammen med funksjonstesting av de nye sprinthistoriene, spesielt hvis det gjøres regelmessig før hver produksjonsutgivelse.
Insister på Kvalitetssikring Før Hver Produksjonsutgivelse
Kvalitetssikring (QA)-testing er siste steget før produksjonsutgivelse, men hoppes ofte over. Spesielt hvis Scrum-teamet er opptatt med nytt innhold.
Selv brukerne sier ofte at de er mer interessert i nye funksjoner enn å opprettholde funksjonalitet eller holde feil lave. Over tid vil dette føre til at utviklerteamet må sakke ned, og brukerne vil ikke få det de ber om uansett.
QA-testing bør utføres av folk utenfor Scrum-teamet, helst av brukerne selv i et dedikert miljø. Produktets eier kan også erstatte brukerne her.
Dette bør være en ren, funksjonell test fra sluttbrukerens perspektiv, uten tilknytning til Scrum-teamet. Det vil gi et endelig syn på produktet og kan avdekke uventet bruk. Det er fortsatt tid til korrigeringer.
Det kan også avdekke at forventningene ikke ble forstått av Scrum-teamet. I så fall kan man avtale en oppfølgingsplan før produksjonsutgivelsen. Det er bedre enn å innrømme feilen etter en vellykket produksjonsutgivelse.
Hva Nå?
Ved å bruke disse metodene vil dere få mer stabile og forutsigbare sprintutgivelser. Uten å forsinke produksjonsutgivelser eller bruke hele sprinten på å forberede neste utgivelse. Uten å tvinge teamet til å gjøre noe de ikke liker eller ikke vet hvordan de skal gjøre.
Men dere trenger ikke stoppe her.
Inkludering av ytelsestester er viktig. De ignoreres ofte, eller ansees som unødvendige. Men jeg har alltid lurt på hvordan man kan forvente at produksjonssystemet skal utvikle seg over tid uten at man sjekker ytelsen jevnlig.
Det neste nivået er å innføre automatisert testing.
Jeg har allerede nevnt automatisert enhetstesting i rørledninger. Man kan utvikle ende-til-ende-regresjonstester som kjøres automatisk etter hver distribusjon til testmiljøet. Det vil frigjøre utviklings-Scrum-teamet enda mer, men krever et dedikert team for å utvikle og vedlikeholde disse testene. Det er en konstant jobb, da produksjonskoden endres, kan noen tester bli ugyldige, og må oppdateres. Det er en kostnad få er villige til å betale, men fordelene for utviklerteamet er store.
Dette er emner som går utover denne artikkelen. Jeg vil gjerne se på tidsplan og timing for hver testtype i et sprintvindu neste gang!