
Enige tijd geleden heb ik een lezing gehouden over Azure Durable Functions. Dit verhaal, wat uiteindelijk 2.5 uur duurde, bevatte eigenlijk alle ins-and-outs over deze technieken. Ik heb daarna van verschillende mensen het verzoek gekregen om dit verhaal nogmaals te houden op andere plekken.
Nu wil ik dat natuurlijk altijd graag doen, maar echt schaalbaar is dat niet. Ik heb dus maar besloten om het hele verhaal op te schrijven en op die manier met iedereen te delen.
Dus… als je wilt weten hoe je met Azure Durable Functions moet beginnen, wat het is, en hoe je je architectuur hiermee schaalbaar kunt maken, dan is dit voor jou.
Aangezien het verhaal erg lang is, heb ik besloten om het op te knippen in een hele reeks van posts. Dit is de eerste daarvan, met de introductie. De rest van de posts zal meer code voorbeelden bevatten en praktische informatie. Maar voor we dat kunnen doen, moeten we het eerst over de theorie hebben.
Once upon a time…
Het web bestond in de jaren 90 uit niet veel meer dan een verzameling losse html pagina’s. Het was niet meer dan een aanplakbord met wat teksten en plaatjes.
Uiteraard duurde het niet lang of de CMS’en kwamen en de pagina’s die we voorgeschoteld kregen waren dynamisch opgebouwd. Maar het basis idee bleef: het meeste was eenrichting verkeer: iemand zocht informatie en kreeg die op het web.
Verbeteringen in de browsers en vooral in de scripting mogelijkheden aan de clientkant, zorgen er al gauw voor dat het web veranderde van een billboard met info naar een systeem voor twee-weg verkeer. De web-apps waren een feit: het verving steeds meer de client-server technologie die in bedrijven al gemeengoed waren. De logge en on-premise servers werden vervangen door web servers en de thick clients werden vervangen door thin, browser based clients.
De systemen die we toendertijd bouwden waren nog erg gebaseerd op dit model. De server deed al het werk. En dat gebeurde vaak in monolytische systemen. De client stuurde informatie naar een webserver en in dat ene request werd al het werk gedaan.
Ik ben betrokken bij Stichting dotNed, een stichting met als doel het verspreiden van kennis rondom het Microsoft development platform. Dat doen we al sinds 2002, in de tijd dat Microsoft met .NET kwam.
Een van de dingen die we doen, is het organiseren van wat tegenwoordig Meetups heet: bijeenkomsten waarin ontwikkelaars bij elkaar komen om iets van elkaar te leren. Voordat iemand naar zo’n bijeenkomst gaat, verwachten we wel dat hij of zij zich inschrijft op onze website.
Die website is een mooi voorbeeld van zo’n systeem. De browser is het invulscherm, de webserver regelt alle zaken er omheen. We registreren wie er komen, we sturen een tweet de wereld in om te zeggen dat deze persoon naar onze bijeenkomst komt, we versturen de nieuwsbrief naar die persoon enzovoorts.

Op een gegeven moment kwam het begrip “micro-services” in zwang. Architecten over de hele wereld grepen dit aan om al hun systemen opnieuw te definiĆ«ren en in te delen. Maar helaas kwamen de meeste architecten niet verder dan het verplaatsen van hun core-functionaliteit naar een of twee services . Met andere woorden: we hebben nu in plaats van een monolitisch systeem meerdere min-of-meer monolitische systemen. Het is niet overzichtelijker geworden; het is zelfs nog minder doorzichtig waar nu wat gebeurt.

Dus in plaats van alle code in de website te plaatsen, hebben we nu alle code in 1 of 2 losse stukken gezet die we aanroepen vanuit de website. Dit helpt niet echt.
Helaas zie ik dit als consultant nog steeds vaak gebeuren bij bedrijven, zeker in het midden- en kleinbedrijf. De architecten daar willen wel graag gebruik maken van een goede architectuur maar hebben of niet de kennis, of krijgen niet de ruimte van het management om dit voor elkaar te krijgen. Het gevolg: slecht onderhoudbare en slecht schaalbare systemen.
Micro-services
Een architectuur gebaseerd op micro-services werkt anders. Dit is gebaseerd op het maken van kleine, zelfstandige, discrete functies die slechts een ding doen, onafhankelijk van de rest van het systeem. Op die manier kunnen we deze functies in parallel ontwikkelen, testen en deployen. Later kunnen we deze functies onafhankelijk van elkaar aanpassen, uitbreiden, opschalen en vervangen door iets nieuws.
Stel je nog even onze dotNed website voor. In dit (fictieve!) voorbeeld hebben we een aantal functies die we moeten doen als iemand zich inschrijft. In dit voorbeeld zijn dat de volgende stappen:
- Het valideren van de input die de gebruiker ons geeft
- We melden het geplande bezoek aan andere usergroups
- We controleren het bestuur van dotNed of ze akkoord zijn met deze bezoeker
- We plaatsen een tweet op het net om te melden dat deze persoon inderdaad langs komt.
Het is fictief: we melden het geplande bezoek niet bij andere usergroups (mag ook niet in het kader van de AVG wetgeving), we controleren het ook niet bij het bestuur. Ook zetten we de bezoeker wel in onze database, een stap die we hier overslaan. Ik zal later stap voor stap zien hoe we dit zouden kunnen implementeren, en dan leg ik ook uit wat ik precies bedoel.

De data komt binnen vanuit de website en zal al deze stappen moeten doorlopen voor we over een geslaagde inschrijving kunnen spreken. Hoe we deze functies bouwen, implementeren en testen is op dit niveau niet belangrijk. Maar je kunt je voorstellen dat niet zo moeilijk is om een module te schrijven die input valideert en dan true of false terug geeft. Je snapt ook dat dat niet afhangt van de stappen daarna. Net zoals het versturen van de tweet een module is die we los en in parallel kunnen bouwen . Het enige wat we moeten afspreken is hoe de data tussen de functies er uit ziet.

De data die we versturen gaat over een message bus of via http triggers. Onze website heeft de data verzamelt en doet een REST Post naar de eerst functie. Deze valideert de data, en plaats vervolgens een message op de message queue dat er goedgekeurde data beschikbaar is. De volgende stap zal dan de data die relevant is voor deze stap (dus niet alle data!) verzamelen en de andere gebruikersgroepen informeren. Als dat gebeurt is, komt er weer een bericht in de queue wat de volgende stappen aan het werk zet.
Nu is dit natuurlijk een enorm versimplificeerde weergave. Want: wat gebeurt er als de input niet geldig is? Of als het bestuur deze bezoeker afkeurt? En over die goedkeuring van het bestuur gesproken: wat als het bestuur niet tijdig reageert?
Dat is ook wel weer op te lossen. We voegen gewoon wat messages toe, wat extra events maar dit keer op timers gebaseerd (als die afgaat en er is nog geen goedkeuring, wat doen we dan?)

Je ziet: het aantal messages en controle flows neemt sterk toe. En het is ook niet eenvoudig om dit te bouwen: veel van de structuren hier hebben niets te maken met het primaire proces maar alles met de controles er om heen. Dit kost vaak een hoop tijd en voegt geen echte waarde toe.
No plumbing architecture
Ik ben van mening dat bedrijven geen frameworks moeten bouwen, behalve als ze framework-leverancier zijn. Buy before build, noemen we dat in goed Nederlands. De meeste organisaties zijn niet toebedeeld om dit soort systemen te bouwen en kunnen dat beter inkopen. Plumbing, het werk dat we moeten doen om timers, checks, fault-handling en dat soort dingen te doen, moeten we zo veel mogelijk aan een framework overlaten.
Begrijp me niet verkeerd: ik ben dol op het bouwen van frameworks,tools, utilities en dat soort dingen. Maar dat zijn hobby projecten. Een gemiddelde organisatie zit daar niet op te wachten. Dus laten we voortaan afspreken dat we dat in de tijd van de baas niet meer doen (behalve als iets echt niet voorhanden is…)
We hebben gelukkig de beschikking over een leverancier die die plumbing al voor ons geschreven heeft. Microsoft en de Azure Durable Functions geven ons de kans om de hoeveelheid plumbing enorm naar beneden te krijgen en ons te laten concentreren op dat waar het om gaat: waarde toevoegen. En dat kan verrassend eenvoudig
De volgende stappen
In de volgende artikelen gaan we bovenstaand systeem van scratch af aan opbouwen. We gaan alles vanaf de website (dus niet de site zelf) schrijven. En hoewel we hier en daar wat hoekjes afsnijden in het kader van leesbaarheid, zullen we een volledige functioneel systeem maken. Vanaf nu dus veel code en samples…
Tot dan!
3 gedachten over “Azure Durable functions”