Continuous Delivery

 
08 april 2013

Het Continuous Delivery seminar van 13 maart j.l. was er vooral op gericht om een overzicht te geven van de belangrijkste principes, zoals; alleen werken in trunk, het verschil tussen unit testen en scenario testen en natuurlijk de hoofdzaak done = released.

Voor de lezers die dit seminar hebben bijgewoond en de gebruikte slides nog een keer rustig door willen nemen, klik hier.

Voor wie nog geen kennis heeft van of ervaring met continuous delivery als principe, zal ik in deze post een korte samenvatting geven van het doel van continuous delivery. Ook zal ik de belangrijkste onderdelen bespreken die je in acht moet nemen wanneer je dit principe wilt implementeren binnen jouw bedrijf.

Reduce the cost, time and risk of delivering incremental changes to users
Jez Humble
Author of Continuous Delivery

Bovenstaande uitspraak legt uit waar je als software leverancier je voordeel kan behalen.. Je hebt een idee, je ontwikkelt hiervoor de bare minimum functionaliteit en de gebruikers kunnen ermee werken en het wordt daarmee gelijk getest. Dus, hoe kleiner de verandering, des te sneller kan de klant het geleverde werk testen.

Het grootste probleem wat ik zelf heb meegemaakt bij het projectmatig bouwen van software voor een klant, is de tijd die zit tussen het bouwen van de software, de oplevering van de software (iedere sprint, dus twee weken) en het moment dat je de feedback krijgt, vaak enige weken later. Mijn inziens zorgen de kleine veranderingen er dan ook voor dat de klant sneller zal testen en minder hoeft te testen. Hierdoor krijg je de feedback vrijwel meteen terug. Als de verandering in minder dan 2 minuten te testen is door de klant, zal deze dat ook eerder doen.

Je moet hierbij er wel voor zorgen dat de klant de rest van de applicatie niet door hoeft om oudere functionaliteit te testen.

Automatisch acceptatie testen

Om de klant het vertrouwen te geven dat de toegevoegde functionaliteit de enige wijziging is, dienen er een aantal tests voor iedere release afgevuurd te moeten worden.
Hierin zijn een aantal te onderscheiden niveaus, met eigen doelstellingen en implementaties.

Unit Tests

Ten eerste zijn er de Unit Tests, deze tests krijg je gratis als je test gedreven ontwikkeld (TDD). Mocht je dit nog niet doen, leer hem je dan snel aan, dit is namelijk volgens mij een van de krachtigste principes van o.a. extreme programming. Het geeft je geen garantie voor mooie code, maar het dwingt je wel na te denken over wat je aan je code wilt vragen en je bouwt er direct zinnige code coverage mee op, wat bij het achteraf bouwen van de tests (om coverage te verhogen) minder het geval hoeft te zijn. Ik ben meerdere keren testen tegen gekomen die achteraf gebouwd zijn die de foutieve werking van een stuk code als ‘goed’ markeerden, een veel voorkomend gevolg van achteraf testen.
Het doel van de Unit Tests is niet zozeer de samenwerking tussen de componenten te testen, maar vooral de werking van de losse componenten te garanderen.

Specification Tests

Een volgende stap zijn de Specification Tests, deze tests dekken de specifieke ‘use cases’ af die in de bijbehorende features gedefinieerd zijn. Deze tests zijn dus in eerste instantie gericht op de functionele eisen die aan de applicatie gesteld zijn. Bij de specification tests wordt als eerste gesteld wat er vooraf gebeurd is (de ‘pre’ conditie), vervolgens komt de actie die gewenst is en tot slot wordt het gewenste resultaat gedefinieerd en geverifieerd. Deze tests zijn vaak ‘leesbaar’:

Feature: Course progress
   Course progress should be kept track of automatically

Scenario: someone starts a course
   Given a user with id 37
   Given a course translation with id 13
   When user 37 starts with course translation 13
   Then his current progress is at module 0

Voor meer informatie over specflow (en een specificatie test variant die ook Java aankan, Cuke4Duke) verwijs ik je graag naar Leesbare unit tests met SpecFlow/Cuke4Duke

Met deze twee test strategieën kunnen we met een redelijk goed gevoel automatisch deployen naar een test server, maar we zijn er nog niet helemaal, voor acceptatie zijn er nog een paar hobbels te nemen.

Wat te doen met bestaande data?

Als je een klant en/of gebruiker mee wil nemen richting continuous delivery, dan zal deze niet bij iedere deploy zijn data kwijt willen zijn. Dit houdt dus in dat er een strategie moet zijn voor een automatische upgrade van de data.

Vaak ben ik tegen gekomen dat in de definition of done was opgenomen dat de ontwikkelaar bijhield welke data er aangepast was en wat de ‘change’ voor de database betekende. In andere omgevingen waar bijvoorbeeld (N)Hibernate als framework wordt gebruikt, wordt deze verantwoordelijk gesteld voor de updates van de database.

Deze twee benaderingen hebben als grootste nadeel dat ze geen garantie geven voor een werkende nieuwe versie, aangezien er pas na deploy achterhaald kan worden of de aanpassing die vooraf bedacht is, of door (N)Hibernate gegenereerd, wel tot een werkende situatie leidt. Om dit te ondervangen zal het upgrade proces dus vaker herhaald moeten worden en hier ligt een leuke kans voor virtualisatie.
De strategie wordt namelijk om na succesvol doorlopen van de unit en specificatie testen (en natuurlijk andere analyses op de code los te laten), de applicatie automatisch te deployen naar een (gevirtualiseerde) test omgeving (deploy often). Op deze test omgeving worden automatisch de upgrades toegepast die nodig zijn, waarna (een subset van) de specificatie tests op deze omgeving losgelaten kunnen worden. Als deze tests niet slagen en de data die voor de upgrade beschikbaar was, is niet meer benaderbaar, dan dient er terug gegaan te worden naar de situatie van voor de deploy.
Als de tests wel succesvol zijn, kan de volgende stap in het deploy proces gezet worden.
In deze stap is virtualisatie een ‘must’, door voor de deploy een snapshot te nemen van de omgeving, kan bij een falende upgrade eenvoudig en snel via die snapshot terug gegaan worden naar de vorige situatie.
Een andere optie is om een backup van de data en de applicatie te maken en hiernaar terug te gaan, maar dit is wel een omslachtiger pad.
Bij falen van de upgrade wordt overigens weer het team gewaarschuwd (fail fast).
Als je als ontwikkelteam bij dit punt aangekomen bent, heb je Continuous Integration en Continuous Testing op een goede manier voor elkaar.

Performance constraints

Voor veel applicaties zal er een minimale acceptabele performance vooraf gedefinieerd zijn, of op z’n minst nadat performance voor het eerst een probleem blijkt te zijn. Gezien we in de vorige stappen een succesvolle deploy en upgrade voor elkaar hebben gekregen, kunnen we nu op een load-testing omgeving dezelfde deploy uitvoeren en hier load-tests en dergelijke op los laten. Wederom, blijft de performance na deze deploy niet binnen de marges, meld de failure aan het team en stop de verdere deploy.

Acceptatie door klant/gebruikers

Na alle voorgaande tests doorlopen te hebben, wil je als ontwikkelteam feedback krijgen en de klant en/of gebruiker verwacht een verandering te zien. Je hebt hierbij twee opties: deployen naar een acceptatie omgeving of deployen naar de live omgeving. Bij het deployen naar de acceptatie omgeving heb je een tussen stadium waarbij je kunt kijken of dit is wat er verwacht wordt en of er een akkoord voor is. Deze omgeving staat helemaal los van de productie en dat is zowel het grootste voordeel als het grootste nadeel, de omgeving draait niet met dezelfde data en/of actieve gebruikers als de live omgeving, waardoor er vaak ten dele gekeken kan worden of de feature voldoet. Daarnaast zitten eindgebruikers er niet op te wachten een test te doen in bijvoorbeeld een acceptatie omgeving als de data die ze bewerken niet op de live omgeving terecht komt. Bij het testen van nieuwe mail-functionaliteit van Google wil je ook niet dat je mailtjes die je in die tijd typt alleen op een test omgeving beschikbaar zijn.

Bij een directe deploy heb je de nieuwe feature direct draaien op je live omgeving. Gezien je wellicht niet wilt dat iedereen deze feature gaat gebruiken tot deze wat verder uitgerijpt is, zul je deze selectief moeten kunnen aanzetten d.m.v. zogenaamde ‘feature flags’, hetzij voor de hele omgeving of voor selectieve gebruikers (door bijvoorbeeld de gebruikers de rol niet te geven die nodig is om de feature te gebruiken). Op deze manier kun je monitoren wat het gedrag is van de nieuwe feature en kun je de impact van het aantal gebruikers ervan op je server load ook daadwerkelijk meten.

En verder…

In deze post heb ik een aantal hoofdpunten van continuous delivery de revue laten passeren, hierbij ben ik vooral ingegaan op de hoofdlijn hoe je van code tot draaiende software komt. Er zijn nog een aantal aspecten die hierbij van belang zijn, die ik nog niet heb belicht, zoals de ’single repository’ en dergelijke. Hier zal ik later op terug komen, maar het belangrijkste om te beseffen is het volgende: Continuous Delivery is een ingrijpend principe, waar iedereen die bij het project betrokken is achter moet staan. Verder is het goed om te kijken naar het continuous delivery maturity model, kijk waar je nu staat en probeer sprint voor sprint een klein stapje te maken richting continuous delivery. Heb je geen code-repository, begin dan daar. Heb je geen build server, kijk dan eens naar JenkinsCruise Control of andere ci-tools. Zo krijg je stapje voor stapje meer controle over je code en deploys.


Werken met ?
Kijk dan bij onze mogelijkheden voor starters en/of ervaren IT'ers.


Categorieën: Development, Deployment, Professionele vaardigheden

Tags: , ,


Reacties (3)

  • Hoi Léon,

    Ik denk dat we het eens zijn, maar een ietwat verschillende definitie van ‘project’ hebben. Helemaal eens dat C-* wenselijk is als je ‘continu’ gaat leveren. Da’s in contradictie met projectmatig werken (met een kop en een staart). In principe zou je complexe software dus nooit projectmatig maar procesmatig moeten bouwen (maar de praktijk vraagt anders).
    Bottom-line: als de oplossing dermate simpel is dat het projectmatig gebouwd kan worden (dus zonder uitloop en vernieuwde opstart) zou je dus C-* niet nodig hebben.

    De motivatie waarom ik deze discussie start is dat CD weer zo’n vakbrede ‘golden hammer’ lijkt te worden zoals Cloud en SCRUM, en dat iedereen het weer overal en altijd wil toepassen. Vandaar dat ik graag discussieer wanneer je dit soort dingen juist *niet* moet doen :).

    Geplaatst op 08 april 2013 om 19:43 Permalink

  • Hoi Léon,

    Fraaie uiteenzetting. Ik lees er misschien overheen, maar wanneer zou je in jouw ervaring CD minder snel toepassen? Het geheel aan ‘Continuous-*’ technieken is bijzonder nuttig, maar minder lonend als je bijvoorbeeld in korte projecten werkt voor (maatwerk) oplossingen. Met andere woorden, hoe minder projectmatig je werkt, hoe meer dit van toepassing is – met name voor productontwikkelaars. Of zie jij dat anders?

    Geplaatst op 08 april 2013 om 9:23 Permalink

    • Hallo André,

      Ik ben nog weinig kort lopende projecten tegen gekomen die ook kort bleven, meestal komt er namelijk na een maandje of een jaar weer een extra wens bij (vaak al eerder) en heb je dus zekerheid nodig dat je de volgende keer ook veilig kunt deployen, wat handig is als een andere collega deze nieuwe wens moet implementeren en deployen.

      Maar als je naar projecten in het algemeen kijkt, dan is het nuttig om snel te deployen, hoe eerder je er achter bent dat de klant zijn vraag eigenlijk heel anders bedoeld had, hoe eerder je kunt bijsturen.
      Ik zou dus zelfs willen stellen dat je als project-bedrijf Continuous Delivery (en de onderliggende Continuous-* varianten) nodig hebt om risico’s voor het project-bedrijf zelf en voor de klant tot een minimum te kunnen beperken. Kort gezegd, hoe eerder de klant kan werken met het product, hoe eerder de klant aangeven wat men van het opgeleverde vindt. Daarnaast heeft de klant eerder een omgeving om zijn eventuele sales team mee op pad te sturen.

      Verder is het inregelen van een continuous delivery infrastructuur voor een project-bedrijf (heb ik binnen Sogyo gemerkt) een eenmalige actie, die je vervolgens voor alle projecten kunt gebruiken, de investering in tijd en middelen is dus niet slechts voor dat ene korte project.

      Geplaatst op 08 april 2013 om 9:59 Permalink