Wat is trunk based development? Uitleg voor kleine teams

Samenvatting

Trunk based development is een werkwijze waarbij iedereen kleine wijzigingen minstens één keer per dag samenvoegt in één gedeelde branch, meestal main of trunk genoemd. Onafgemaakt werk zit achter een feature flag, zodat de trunk bij elke commit bruikbaar blijft. Voor solo devs en kleine teams levert dat kleinere diffs, snellere feedback van CI en minder conflicten op. Het vraagt wel goede tests en een snelle manier om terug te draaien.

Donkere werkplek met een monitor die één gloeiende verticale lijn toont, als metafoor voor één gedeelde trunk

Wat is trunk based development? Het is een branching-model waarbij iedereen kleine wijzigingen minstens één keer per dag samenvoegt in één gedeelde branch, meestal main of trunk genoemd. Branches, als je ze gebruikt, leven uren en niet weken. Onafgemaakt werk wordt verstopt achter een feature flag, zodat de trunk bij elke commit uitrolbaar blijft. Dat is het hele idee, en het is minder exotisch dan de naam doet vermoeden.

Dit is de situatie die het concreet maakt. Je opent een side project dat je drie weken geleden liet liggen. De feature branch staat 41 commits achter main, twee bestanden hebben conflicten, en wat je aan het bouwen was past niet meer bij de code eromheen. Trunk based development is de gewoonte die voorkomt dat dit gebeurt.

Wat trunk based development echt betekent

De referentiesite trunkbaseddevelopment.com beschrijft het als een source-control-model waarin ontwikkelaars samenwerken op één gedeelde branch en andere langlevende ontwikkelbranches vermijden. Directe commits naar de trunk zijn prima voor heel kleine teams. Pull requests kunnen ook, zolang de feature branches kortlevend blijven en uit het werk van één werkstation komen.

Drie regels dragen het grootste deel van het gewicht.

Let op wat er ontbreekt. Er is geen develop-branch, geen lange releasebranch per feature en geen integratiefase aan het eind, waarin iedereen ontdekt dat de code niet bij elkaar past. Bij de oudere modellen doet het pijn omdat de rekening zich opstapelt en in één keer betaald moet worden.

Een hoge boom met één dikke stam en maar een paar korte takken

Waarom het langlevende branches meestal verslaat bij kleine teams

Een langlevende branch is een lening. Elke dag dat een branch bestaat, drift hij iets verder van main af, en de rente komt terug als mergeconflicten, verouderde aannames en reviews die niemand kan afmaken omdat de diff 60 bestanden raakt.

De capability-pagina van DORA over trunk-based development koppelt drie praktijken aan betere snelheid, stabiliteit en beschikbaarheid van levering, op basis van het onderzoek uit de State of DevOps-rapporten. Houd maximaal drie actieve branches in de repository. Merge minstens één keer per dag naar de trunk. Vermijd code freezes en integratiefasen. Dat zijn concrete, meetbare doelen, en dat is zeldzaam in dit vakgebied.

Voor een solo dev of een team van drie is het argument nog eenvoudiger. Kleine merges zijn makkelijk te reviewen, makkelijk terug te draaien en makkelijk te begrijpen over zes maanden, als je om 22 uur met git blame zit te puzzelen wat je vroegere zelf in godsnaam bedoelde.

Drie redenen om het te doen, één reden om het niet te doen. De redenen: kleinere diffs, snellere feedback van CI en een main-branch die je op een vrijdag kunt deployen zonder te zweten. De reden om het niet te doen: als je tests dun zijn, verspreidt dagelijks mergen de breuk alleen sneller. Daar komen we verderop op terug.

Korte branches of direct naar main committen?

Beide tellen als trunk based development. Het verschil zit in hoeveel veiligheid je wilt hebben voordat code landt.

Direct naar main committen werkt als je alleen werkt of met één tweede persoon, je lokale build in minder dan een minuut klaar is en je je tests vertrouwt. Het is de snelste loop die er bestaat. De meeste solo builders doen dit al zonder het zo te noemen.

Korte branches met een pull request zijn zinvol zodra een tweede of derde persoon meedoet, of wanneer je wilt dat CI draait op een schone checkout voordat je merget. De discipline zit in het woord kort. Een branch die de volgende dag nog bestaat, drift al richting het model dat je wilt verlaten.

Een praktische routine die standhoudt:

Als een wijziging niet in één dag past, is het antwoord niet een langere branch. Het antwoord is de wijziging dunner snijden.

Hoe lever je half afgemaakt werk op zonder main te breken?

Dit is de vraag waar de meeste mensen op stuklopen. Als je dagelijks merget, merge je code voor features die nog niet bestaan. Twee technieken lossen dat op.

De eerste is de feature flag. Het nieuwe codepad wordt gemerged maar uitgeschakeld, zodat gebruikers het nooit zien. Een flag kan zo simpel zijn als een boolean in een environment variable:

const showNewCheckout = process.env.FEATURE_NEW_CHECKOUT === "true";

export function Checkout() {
  return showNewCheckout ? <NewCheckout /> : <OldCheckout />;
}

Dat is genoeg voor een side project. Heb je targeting nodig, gefaseerde uitrol of een kill switch zonder redeploy, dan verdient een beheerde dienst zijn plek.

De tweede techniek is branch by abstraction, voor grotere wijzigingen zoals het vervangen van een databaseclient of een betaalprovider. Je zet een interface voor de oude implementatie, bouwt de nieuwe achter dezelfde interface, verhuist de callers stukje voor stukje en verwijdert daarna de oude. Elke stap is een kleine merge naar de trunk, en niets blijft ooit op een lange branch staan.

Een paneel met fysieke schakelaars, sommige aan en andere uit, als feature flags

Eén eerlijke kanttekening bij flags: het is schuld. Een flag die een jaar in de code blijft staan, is een branch in vermomming. Geef elke flag een eigenaar en een verwijderdatum, en haal hem weg zodra de feature volledig is uitgerold.

Wat je CI nodig heeft voordat je hiermee begint

Trunk based development zonder vangnet is gewoon snelle breuk. Je hebt drie dingen nodig voordat je je vastlegt op een dagelijkse mergegewoonte.

Statische analyse is een goedkope extra laag. Die vangt een klasse van problemen, zoals voor de hand liggende bugs, security-geurtjes en gedupliceerde code, voordat een mens de diff leest.

Als jij de enige reviewer bent, helpt tooling die wijst op risicovolle hotspots nog meer, want niemand anders vertelt je dat het bestand dat je steeds aanraakt aan het verrommelen is.

Denk niet dat je op dag één een zware pipeline nodig hebt. Een enkel workflowbestand dat main installeert, linted, test en deployt, is een prima start. Getest, niet optimaal, en het waard om te doen: het is de eerste versie die werkt, en je kunt hem later aanscherpen.

Releasebranches, hotfixes en de dingen die nog steeds aandacht vragen

Trunk based development verbiedt geen releasebranches. Sommige teams snijden vlak voor een release een branch van de trunk af, harden die, shippen hem en verwijderen hem daarna. Anderen releasen rechtstreeks van de trunk en fixen vooruit zodra er een bug opduikt. Voor een webapp die meerdere keren per week wordt gedeployd, is vooruit fixen bijna altijd het eenvoudigst.

Mobiele apps en alles met een trage store-review is een ander verhaal. Daar kun je een kortlevende releasebranch per versie aanhouden, zodat je patches kunt uitrollen voor wat al bij gebruikers staat. Ook dan geldt de regel: fixes landen eerst op de trunk en worden daarna gecherry-picked, nooit andersom.

Hotfixes volgen dezelfde logica. Fix op de trunk, deploy, klaar. Een aparte hotfixbranch die nooit wordt teruggemerged, is hoe teams eindigen met twee uiteenlopende geschiedenissen.

Laptop met een donkere code-editor op een cafétafel 's nachts

Een realistische eerste week

Dag één: kijk hoe je repo nu met branches werkt. Zet de open branches op een rij en noteer de leeftijd van elke branch. Alles ouder dan een paar dagen is een kandidaat om te mergen of te verwijderen. Alleen dit toont vaak al waar de wrijving zit.

Dag twee: voeg het flagmechanisme toe. Zelfs een environment variable is prima. Kies één lopende feature, zet het startpunt erachter en merge wat je hebt.

Dag drie tot vijf: verander de gewoonte. Knip elke taak in stukken die in één dag kunnen landen en merge elk stuk zodra CI slaagt. Verwacht dat de eerste stukken te klein aanvoelen. Dat zijn ze niet. Een commit die een slapende databasekolom of een ongebruikte functie toevoegt, is een prima eenheid van voortgang, want hij is veilig, gereviewd en al geïntegreerd.

Aan het eind van de week weet je twee dingen: of je tests betrouwbaar genoeg zijn, en welke delen van je code zich verzetten tegen kleine wijzigingen. Allebei zijn nuttig, en geen van beide komt naar boven terwijl je op lange branches werkt.

Je hebt geen dashboard nodig om het te zien. Kijk hoe lang je branches leven, hoe vaak main rood staat en hoe lang een wijziging erover doet van de eerste commit tot productie. Als de leeftijd van branches afneemt en deploys saai worden, loont de gewoonte.

Wil je cijfers over het effect op gebruikers van wat je achter flags uitrolt, dan kan een experimentatietool een uitrol koppelen aan echte metrics in plaats van aan onderbuikgevoel.

Voor een team van één werkt een gewoon schrift ook. Noteer elke week de tijd van merge tot deploy, een maand lang. De trend vertelt je meer dan elk afzonderlijk getal.

Overstappen of wachten?

Stap over als je alleen werkt, met z'n tweeën bent, of in een klein team zit met tests die je half vertrouwt en een CI die je kunt verbeteren. De prijs van het proberen is een week lichtelijk ongemakkelijke kleine commits. De prijs van blijven zitten op lange branches betaal je in conflicten en trage reviews, en die groeit met elke medewerker.

Wacht als je helemaal geen geautomatiseerde tests hebt en geen manier om terug te draaien. Los dat eerst op, want dagelijks mergen in een ongeteste trunk verplaatst de pijn alleen maar.

Het is geen perfecte methode. Het is wel een werkbare. Kies de volgende kleine wijziging in je huidige project, merge hem vandaag en kijk hoe het voelt. Wat is het kleinste stuk van je huidige feature dat je vanavond nog zou kunnen shippen?

Veelgestelde vragen

Wat is trunk based development in één zin?
Een werkwijze waarbij iedereen kleine wijzigingen minstens één keer per dag samenvoegt in één gedeelde branch, meestal main of trunk genoemd.
Hoe vaak moet je naar de trunk mergen?
Minstens één keer per dag, volgens de capability-pagina van DORA. Branches leven idealiter uren en niet dagen.
Mag je direct naar main committen?
Dat kan, zeker als je alleen werkt of met één tweede persoon en je tests vertrouwt. Met een groter team zijn korte branches met een pull request gebruikelijk.
Wat is het verschil met GitFlow?
GitFlow gebruikt langlevende develop- en releasebranches. Trunk based development houdt alles op één gedeelde branch en verbergt onafgemaakt werk met feature flags.
Heb je feature flags nodig?
Voor een eenvoudige app niet verplicht. Maar bij dagelijks mergen van onafgemaakt werk zijn ze de gebruikelijke manier om main uitrolbaar te houden.
Wat heb je nodig voordat je begint?
Een snelle build, betrouwbare tests en een manier om snel terug te draaien, via een revert of door een flag uit te zetten.