Torsdag kväll, releasetåget går. Nio förändringar har väntat i två veckor på att få åka med: en ny betalsida, en ändrad sökning, ett par buggfixar och några saker ingen riktigt minns. Allt går ut samtidigt. Vid tiotiden börjar felen i sökningen, och vid elva rullas hela releasen tillbaka — betalsidan och buggfixarna också, fast de fungerade. På måndagen är sökningen lagad. Den får åka med nästa tåg, om två veckor. Att driftsätta är en teknisk händelse: ny kod börjar köra på en server. Att släppa är ett beslut: användare får se något nytt. När de två sitter på samma knapp kostar varje release lika mycket som den största förändringen i den.
Mönstret är vanligt i organisationer som är duktiga på att bygga men försiktiga med att släppa: releasetåg, releasefönster, frysperioder i december. Försiktigheten är rimlig. Det är kopplingen som är fel. Idén att skilja deploy från release är inte ny — Jez Humble och David Farley skrev om den i Continuous Delivery redan 2010 — men den är fortfarande det billigaste sättet vi vet att göra releaser mindre dramatiska.
Två beslut som fått dela knapp#
Deploy och release svarar på olika frågor, ställs av olika personer och går fel på olika sätt:
- Deploy är en teknisk fråga. Startar den nya artefakten, svarar den på hälsokontrollen, ser felkurvan ut som förut? Den frågan kan pipelinen svara på, och den bör ställas ofta — helst varje gång bygget är grönt.
- Release är en produktfråga. Vilka ska se det här, från när, och vem behöver veta det innan? Den frågan hör hemma hos den som äger produkten, tillsammans med support och marknad. Den besvaras i en kalender, inte i en loggfil.
- När de delar knapp väntar deployen på releasebeslutet. Färdig kod samlas på hög tills någon vågar. Högen växer, risken växer med den, och därför växer försiktigheten. Nästa release blir större än den förra, vilket var problemet från början.
- Och releasen väntar på deployen. En buggfix kan inte gå ut utan att halvfärdiga funktioner följer med, så de får gömmas i långlivade grenar i stället för att mergas. Det är så trunk-based development dör i praktiken: inte av princip, utan för att main inte går att driftsätta när som helst.
- Rollback blir allt eller inget. Det enda sättet att ta bort en förändring är att ta bort alla. De åtta som fungerade betalar för den nionde.
Flaggan är där beslutet flyttar in#
En feature flag är en brytare i koden som läses vid körning. Det är ingen avancerad teknik — en if-sats och en källa till sanning utanför artefakten — men den flyttar releasebeslutet från pipelinen till den som ska fatta det:
- Koden går ut avstängd. Betalsidan mergas till main när den är klar nog att inte störa, driftsätts på tisdag bakom en flagga, och ingen utanför teamet ser den. Deployen kan ske när bygget är grönt, oavsett vad kalendern säger.
- Släppet är en konfigurationsändring. På torsdag klockan tio slår produktägaren på flaggan. Ingen pipeline, ingen releasekväll, ingen utvecklare i beredskap. Ångra är samma brytare åt andra hållet, och det tar sekunder.
- Släppet kan vara partiellt. Först de egna anställda, sedan en liten andel av användarna, sedan alla. Det är grunden i progressive delivery, och poängen är inte procentsatsen utan att det finns ett läge där ni kan titta innan ni bestämmer er.
- Rollback blir riktad. Sökningen stängs av, betalsidan och buggfixarna ligger kvar. Att rulla tillbaka själva deployen finns fortfarande som verktyg, men det blir undantaget för ”tjänsten startar inte”, inte svaret på ”användarna gillade inte knappen”.
- Alla flaggor är inte samma sorts flagga. Pete Hodgsons artikel om feature toggles skiljer på releaseflaggor som ska bort efter lanseringen, driftflaggor som är permanenta nödbromsar, experimentflaggor för A/B-test och behörighetsflaggor per kund. Ett och samma system kan hålla alla fyra, men varje flagga behöver veta vilken sort den är — det avgör om den får leva i veckor eller i år.
Releasekalendern överlever — den styr bara något annat#
Det här tar inte bort releasekalendern. Det tar bort dess grepp om pipelinen:
- Marknad väljer dag. Lanseringen kan ligga en tisdag förmiddag när supporten är bemannad, i stället för torsdag kväll när det råkar vara deployfönster.
- Frysperioden blir en flaggfrysning. I december fortsätter deployerna av buggfixar och säkerhetsuppdateringar som vanligt. Det som fryser är nya funktioner som slås på — och det var det man egentligen menade.
- Release notes beskriver det användarna ser. Inte det som råkade ligga i samma bygge. Deployloggen och releaseloggen blir två olika dokument, och båda blir läsbara.
Där det brukar gå sönder#
- Flaggan som aldrig tas bort. Varje flagga är en if-sats med två vägar, och efter lanseringen är den ena död kod som ingen vågar röra. Efter ett år finns det hundra sådana. Ge varje flagga en ägare och ett sista datum när den skapas, och räkna städningen som en del av att releasen är klar.
- Flaggan som bara testats i ett läge. CI kör med flaggorna i standardläge, så vägen som ska slås på möter verkligheten först i produktion. Kör testsviten i båda lägena för releaseflaggor, eller åtminstone i det läge ni är på väg att slå på.
- Flaggor som beror på varandra. Flagga B förutsätter att flagga A är på, och med tjugo flaggor är kombinationerna fler än någon testat. Håll flaggorna oberoende. Måste två alltid slås på tillsammans är de en flagga.
- Schemaändringen som inte går att flagga. Migreringen av databasen går ut med deployen och kan inte stängas av med en brytare. Mönstret som löser det är expand/contract: lägg till den nya kolumnen, skriv till båda, flytta läsningen bakom flaggan, och ta bort den gamla först när flaggan är borta. Flaggan styr läsningen, aldrig schemat.
- Flaggan som kräver en deploy för att ändras. Ligger flaggans värde i en konfigfil som bakas in i bygget har ni inte skilt på någonting — ni har bara bytt namn på knappen. Värdet måste bo utanför artefakten: i en flaggtjänst, en konfigurationsdatabas eller åtminstone en miljövariabel som går att ändra utan ombyggnad.
- Släppet som ingen loggar. Klockan tio slogs en flagga på, klockan tio och fyrtio fördubblades felen, och ingen kopplar ihop dem eftersom flaggändringar inte syns där deployerna syns. Varje ändring av en flagga är en händelse med vem, när och vad, och den hör hemma på samma tidslinje som deployerna.
Så börjar du#
Det här kräver inget nytt verktyg på dag ett. Det kräver en flagga och ett beslut om vem som får röra den:
- Ta er senaste release och skriv ner hur många förändringar som gick ut samtidigt — och hur många av dem som faktiskt behövde gå ut just då. Skillnaden är priset för att de delade knapp.
- Välj nästa funktion som tar mer än en dag att bygga. Lägg den bakom en flagga från första commiten och merga till main varje dag, avstängd. Driftsätt den avstängd minst en gång innan den är klar.
- Börja enkelt: en flagga som läses från en miljövariabel eller en rad i den konfigurationstjänst ni redan har. Byt till ett riktigt flaggsystem när ni har fler än en handfull flaggor och vill styra på målgrupp och andel — Unleash är öppen källkod, LaunchDarkly är det stora kommersiella alternativet, och OpenFeature är den leverantörsneutrala SDK:n som gör ett senare byte billigare.
- Ge varje flagga tre fält från start: ägare, sort och sista datum. Visa utgångna flaggor på samma ställe som gamla pull requests, så att de skaver.
- Låt produktägaren slå på nästa release själv, utan att någon utvecklare sitter bredvid. Det är testet på att beslutet faktiskt har flyttat.
- Logga varje flaggändring där ni loggar deployer. Nästa incidentutredning kommer att tacka er.
Allt det här förutsätter att det som ligger avstängt i produktion är samma artefakt som ni testade — annars slår ni på något ni aldrig har sett köra. Den grunden skrev vi om i Bygg en gång. Tillsammans är de två principerna kärnan i det vi kallar Delivery Engineering: en väg från commit till produktion där det tekniska sker ofta och tråkigt, och det affärsmässiga sker när någon har bestämt sig.
Vårt korta svar#
Deploy är en teknisk händelse och release är ett beslut. Låt pipelinen sköta det första så ofta den vill, och låt den som äger produkten fatta det andra med en brytare. När de sitter på samma knapp betalar varje liten ändring för den största.
Driftsätt när bygget är grönt. Släpp när ni är redo. Det behöver inte vara samma dag.
