Post-hoc release branches: hoe en waarom

technisch

Senior software engineer Jeroen Vermeulen was al eerder aan het woord op deze site. Deze keer deelt hij zijn inzichten over een onderwerp dat in ieder serieus software project relevant is: release branches.

Een goede vraag voor elk programmeerproject: Hoe gaat ons branch-model eruit
zien? Wat voor branches houden we bij? Natuurlijk master, maar verder nog
iets?

Wat je hier ziet is een werkend idee, geen kant-en-klare oplossing, voor
relatief kleine projecten. Echt nieuw is het niet. Het ligt enorm voor de
hand eigenlijk, als je het eenmaal doorhebt. Maar daardoor praat niemand
erover, en op die manier krijgt niet iedereen het door: een typische Catch 22.

Het werkt het beste wanneer je veelvuldige releases doet, en weinig met patches
aan oudere versies bezig bent. Is jouw project heel anders? Of heb je een
volledige uitleg nodig, niet alleen maar een idee? Kijk dan vooral eens naar
de bestaande modellen die ik hieronder noem.

Maar het omgekeerde kan ook: Misschien helpt dit ideetje je naar meer
overzicht, vlottere releases en minder patchwerk.

Eisen

Je branch-model hangt altijd af van wat je voor je project wilt.
Bijvoorbeeld:

  • “Als we een feature bouwen, dan doen we dat in een aparte feature branch.
    Wanneer de feature klaar is, nemen we die branch in de hoofdlijn op.”
  • “Vanzelfsprekend maken we voor elke release een release branch, zodat we
    nog patches uit kunnen brengen terwijl we de hoofdlijn doorontwikkelen.”
  • “We willen master stabiel houden, dus het ontwikkelwerk gebeurt in een
    aparte develop-branch.”
  • “Het moet allemaal niet te ingewikkeld worden en niet teveel werk kosten.”

En natuurlijk kun je die dingen niet allemaal tegelijk hebben! Schrijf jij
even een voorstel voor het team? Dan bespreken we het maandag. Fijn weekend.

Release branches

Hierboven zei ik dat je project “vanzelfsprekend” met release branches wil
werken. Zo zien veel ontwikkelaars het.

Waarom? Omdat je nooit weet of je misschien een kleine bugfix voor je laatste
release moet uitbrengen. Of zelfs een oudere release. Tegen die tijd is de
hoofdlijn van je ontwikkeling (meestal master) al gauw helemaal veranderd.
In je release branch wil je alleen de simpelst mogelijke fix. Misschien ga je
het helemaal anders doen in de volgende release, of misschien neem je de fix
daar gewoon letterlijk over.

Dat is trouwens waar een hoop van de overhead van release branches vandaan
komt, en waar je het makkelijkst onnodige foutjes maakt.

Dan is er nog iets. In een modern project volgen de releases elkaar meestal
snel op, en verwacht je dat gebruikers bijblijven. Zoals in een web-applicatie
waar gebruikers vanzelf altijd de nieuwste versie zien. Dan is zo’n release
branch vaak verspilde moeite, achteraf.

Maar als je geen release branch maakt, kun je er later spijt van krijgen.
Er is immers geen groter plezier in het leven van een bug dan om je te
verrassen vlak na je grote release. Daar komen we straks op terug.

Keuzes

Nou, daar sta je dan. Veel mensen duiken Google in en komen uit op een artikel
A Succesful Git Branching Model, door Vincent Driessen: stop ongelukkige!

Ziet er heel professioneel uit. Misschien snap je niet helemaal waar het
allemaal goed voor is, maar dat is een teken van kwaliteit, toch?

Doe het niet. Echt. Er zijn misschien projecten waarvoor het de moeite waard
is, maar die hebben meestal al regels over welk model je volgt.

Wat jij als ontwikkelaar doet heeft geen waarde alleen maar doordat het werkt.
Je moet het ook nog uit kunnen leggen, zodat andere mensen het kunnen
onderhouden. En Driessens model is teveel voor een gewone sterveling. Te
ingewikkeld, teveel rompslomp, te makkelijk fout te doen. Tenminste, als die
sterveling tussendoor ook nog wat nuttig werk wil kunnen doen.

Oké, dus je wilt iets simpelers. Wat dacht je van het “Cactus-model”? Het
staat onder vele namen bekend, met kleine variaties.

Stukken begrijpelijker. Je doet je werk steeds in een feature branch, en die
wordt daarna opgenomen in master. Aan het begin van een nieuwe release maak
je een feature branch aan, waarin je alleen nog klein onderhoud doet.

Nog een pluspunt: er is veel tooling die dit model ondersteunt. Maar het gaat
nog steeds niet vanzelf.

Wacht eens even…

Maar sta hier eens bij stil: Je gebruikt Git, of een ander revision control
system. Daarmee kun je in de tijd reizen! Je kunt elke eerdere versie van
de code terughalen. Dat is macht. Dat is vrijheid. Daar kunnen we vast meer
mee.

Wat dacht je bijvoorbeeld hiervan? Als je in de tijd kunt reizen, hoef je
nooit ergens spijt van te krijgen. Verkeerde beslissing gemaakt? Stap in je
tijdmachine en doe het over. In het verleden.

Dus wat stel je voor?

Soms is luiheid een deugd.

Mijn suggestie: ga er simpelweg van uit dat je geen release branch nodig gaat
hebben!

In een groter project wil je misschien wel je release testen in een aparte
branch, die je vlak vóór de release weer in master binnenhaalt. In een
kleiner project hoeft zelfs dat niet. Maar de essentie is dat je release
geen branch krijgt, alleen maar een tag. Gewoon in master. Gebruik het
versienummer als je tag-naam, bijvoorbeeld “2.1.0”.

Een tag is een soort boekenlegger. Het is een naampje dat je op een specifieke
revisie in je repo plakt. Het is niet eens echt nodig, maar met een tag kun je
een revisie later makkelijk terugvinden. Als je met Git werkt moet je wel even
weten dat git push je tags niet naar de server stuurt, tenzij je ook de optie
–tags meegeeft.)

Maar wat doe je als je al een release hebt gedaan en er later achter komt dat
er tòch een patch nodig is?

Soms heb je geluk. Soms duikt de bug onmiddelijk op, voordat er nieuwe commits
aan master zijn toegevoegd. Dan is het makkelijk: Je hebt net 2.1.0 van je
project uitgegeven, je verhelpt de bug met de eerstvolgende commit, en nu tag
je die commit gewoon als 2.1.1. Presto: de update is klaar!

Of soms moet je terug in de tijd. Dan ga je terug naar de release-revisie,
bijvoorbeeld met git checkout 2.1.0. En daar maak je een release branch,
in het verleden als het ware: git checkout -b 2.1. Ik laat het laatste
cijfer hier weg, want je wilt niet alleen 2.1.1 in die branch zetten, maar ook
een mogelijke 2.1.2 enz.

En daar ben je: Een gewone klassieke release branch, maar alleen wanneer je er
een nodig hebt. Kon je vooraf niet weten, maar het kan altijd nog achteraf.
Oftewel “post hoc” in het Latijn.

Maar werkt het echt?

Ja! 😀

Ik doe mijn release branches post-hoc in een succesvol open-sourceproject,
libpqxx. Dat project draait al twintig jaar,
maar het is lange tijd “vastgeroest” geweest. Releases werden teveel gedoe.
Ik raakte het overzicht kwijt, en het plezier ging eruit. Geen gezonde
situatie, want talloze projecten bouwen op libpqxx en verwachten dat het met
zijn tijd meegaat.

Het plezier kwam weer terug toen ik de releases stroomlijnde, en zo kwam ik op
“post-hoc” uit. Alles kwam weer op gang. En als gebruikers tegen bugs in oude
versies aanlopen, geeft het me een reden om te zeggen: “Ik kan een patch voor
je uitbrengen als je dat echt wilt, maar ik zou je aanbevelen om gewoon op een
nieuwere versie over te gaan.” Als dat lukt zijn we allebei beter af.

Daarnaast heb ik het post-hoc-model een paar jaar terug geïntroduceerd in een
klein project in een grote bank. Tot nu toe hebben we geen moment spijt gehad.
Kortom: al dat werk met de release branches was eigenlijk… “YAGNI”.