In het SDN-magazine zie je veel auteurs vertellen over microservices, maar ook op onze SDN-events of andere conferenties zijn er veel sessies over. Ze vertellen dan altijd dat het belangrijk is om naar microservices over te stappen, want daarmee wordt het leven een stuk eenvoudiger. De voorbeelden die ze geven zijn dat altijd de standaardvoorbeelden van een product-order systeem of ze komen met voorbeelden vanuit een greenfield situatie. De presentaties gaan bijna altijd uit van het niet aanwezig zijn van legacy code of legacy systemen. Maar onze werkelijkheid is vaak veel weerbarstiger.
Veel bedrijven hebben een monoliet en een monoliet is niet iets waar je voor hoeft te schamen. Er zijn maar weinig omgevingen waar niet een vorm van monolithische code of omgeving is ontstaan. Zelfs bij startups begint het altijd met een redelijk puristische manier van ontwikkelen, maar na enkele weken/maanden wint de tijdsdruk van de schoonheid en raakt de software langzaamaan vervuild. Op zichzelf hoeft dat ook helemaal niet erg te zijn. Mits je tijdig refactor-slagen uitvoert en bij iedere volgende aanpassing/verbetering/bugfix je code weer beter achterlaat (incheckt) dan dat je hem gevonden hebt: de Boyscout rule, laat het kampeerterrein schoon achter voor de volgende gebruiker en liefs nog iets schoner. Ook hier voer je dus verbeteringen uit stapje voor stapje, hapje voor hapje. Ik ben een groot voorstander van “Make-it-work-then-make-it-better-then-make-it-pretty”.
“Make it work then make it better then make it pretty”
Want hoe migreer je vanuit een bestaande omgeving naar een service georiënteerde omgeving of microservices. Het antwoord is heel simpel zoals je ook een olifant eet, hapje voor hapje. “Haha wat leuk, neem je ons niet serieus of zo?”. Jazeker wel en ik zal jullie uitleggen hoe ik dat bedoel.
Door de conferenties en artikelen (waar Microservice behoorlijk gehypet worden) hebben veel bedrijven de wens om over te stappen naar een service georienteerde architectuur en bij voorkeur naar een Microservices architectuur. Maar natuurlijk moet de winkel wel open blijven en dat betekent dat support en bigfixes wel gewoon moeten door blijven gaan. Tenslotte betalen de huidige klanten de rekeningen en organisaties hebben niet de mogelijkheid om voor een paar maanden of soms jaren onder een steen te kruipen om orde op zaken te stellen. Natuurlijk kan dat niet, tenslotte zijn klanten de reden waarom het bedrijf bestaat en zij betalen niet voor een product dat niet verbetert, wordt onderhouden en gewoon stilstaat. Ander risico is dat er een andere partij opstaat en jouw plekje inneemt.
Ik denk ook niet dat je dicht hoeft om tijdens het rijden een wiel te verwisselen. Alleen moet je dan als bedrijf wel een behoorlijke tijd uittrekken om te migreren. Je zult dat wel dubbel onderhoud en dubbele code moeten accepteren. Wat vaak in jaren is opgebouwd, is niet in een paar weken terug te draaien. En doordat je niet alles vanaf de grond opnieuw bouwt, zul je meerdere refactor slagen moeten maken en Projects/files/classes/code meerdere malen zult aanpassen. Het is pas af als jullie puntje op de horizon gehaald is.
Ja, dat is niet exclusief voor Service Oriëntatie! Klopt, want het begint bij het ontrafelen van de kluwen van code en zorgen dat alle onbedoelde maar ingeslopen afhankelijkheden weer ongedaan gemaakt worden. Pas als je de basis op orde hebt, dan kun je de stap voorwaarts maken en nieuwe dingen toevoegen. Ook microservices (hoe hip ook) zijn niet perse nodig. Wel wil je dat verantwoordelijkheden goed verdeeld zijn over de verschillende servers, computer systemen of code.
Eerst moeten we voor ons zelf bepalen, wat de reden is om te migreren naar Service Oriëntatie. Wat zijn de huidige uitdagingen met je applicatie, platform of service? Is het dat het testen niet meer te doen is? Of dat het aanpassen van code op de ene plek betekent dat er op een andere plek code / functionaliteit omvalt? Er te veel afhankelijkheden tussen verschillende onderdelen bestaan? Of dat het deployen een probleem is geworden en gewoon te lang duurt? Of wil de organisatie van het ASP (Application Serivice Provider) model af en omvormen naar overstappen naar een SAAS (Software As A Service) model? Is de applicatie, service of platform eigenlijk niet geschikt voor multi users omgeving? Of is je oplossing niet of nauwlijks in staat op te schalen bij meer gebruik? Is in het algemeen reageren op gewijzigde wensen van je klanten gewoon lastig, omdat er te vlug andere functionaliteit omvalt.
Belangrijk is, dat de reden niet moet zijn omdat iedereen het doet of dat services of erger microservices zo belangrijk lijken in de business. Op zichtzelf hoeft er niks mis te zijn aan een monoliet. Er moeten andere redenen zijn om aan te passen. Ik heb liever een goede monoliet dan een slecht uitgevoerde Service Oriëntatie. Technology is een middel en moet nooit een doel op zichzelf zijn.
Technology is een middel en niet een doel
De formele beschrijving van een Service Orientation Architecture service: “A SOA service is a discrete unit of functionality that can be accessed remotely and acted upon and updated independently, such as retrieving a credit card statement online. SOA is also intended to be independent of vendors, products and technologies.”. Microservices zijn opzichzelf niet heel anders, maar waar we de definitie van een op zichzelf staande eenheid van functionaliteit wel iets strakker wordt neergezet. In een minder goed uitgevoerde Service Oriëntatie omgevingen zijn de services vaak te klein, waardoor de services elkaar aanroepen en eigenlijk niet meer los van elkaar gebruikt worden. Dat resulteert meestal in een Chatty systeem, waarbij services elkaar herhaaldelijk aanroepen en allesbehalve onafhankelijk van elkaar zijn. Iedere aanroep van een service levert weer vertraging op en als het een losse service is. Soms zijn de services dan ook nog eens zo gebouwd, dat ze niet verwachten dat de aanroepende service stuk of niet aanwezig is. En dat gebeurt juist als het zo losgekoppeld is. Waarmee de “updated independently” uit de definitie eigenlijk niet meer kan, andere services rekenen op elkaar en feitelijk heb je dan een monoliet in stukjes.
Belangrijkste in de definitie is volgens mij ook op zichzelf staande functionaliteit. Er staat nergens hoe groot de “op zichzelf staande functionaliteit” moet zijn. Wat er wel staat, alles wat de service nodig heeft om volledig autonoom te kunnen werken onafhankelijk van de rest van de systemen. Even heel gechargeerd, een monoliet is in deze beschrijving dus ook een goede service. Een monoliet herbergt misschien te veel verschillende functionaliteiten. Zoals een ordersysteem, een productsysteem, een klantsysteem etc. Ik schrijf expliciet systeem om aan te geven dat het losse onderdelen moeten zijn. Maar het ordersysteem heeft informatie nodig van de producten en de klanten! Ja, dat klopt, maar het ordersysteem zal niet het adres van de klant updaten in de database. Ieder systeem heeft zijn eigen verantwoordelijkheden. Het ordersysteem gebruikt de data van het klantsysteem. Verandert het adres in het ordersysteem? Dan maakt het ordersysteem een werkbon voor het klantsysteem om dit aan te passen. Voor hier gaat het te ver om hier dieper op in te gaan, lees het artikel van Dennis van der Stelt uit ons vorige magazine eens over het Starbucks model. Vuistregel is, maak je functionaliteit niet te klein en let goed op welke verantwoordelijkheden de functionaliteit heeft. Services zijn ook een middel en niet een doel. Keep it simple, maar om met Einstein te spreken; maak het niet simpeler dan dat.
Terug naar ons initiële probleem. We zien de monoliet als een samengeklonterde functionaliteit, maar feitelijk bestaat deze toch ook uit losse stukken en op zichzelf staande functionaliteit. Echter de functionaliteit is alleen te veel op de achtergrond geraakt door gebruik van technology. Vaak zijn databases te ver uitgenormaliseerd (8st normaalvorm) of is object Oriëntatie te strict doorgevoerd. Heel vaak is door technologische overload de functionaliteit teveel door elkaar heen gaan lopen. De technologie geeft de mogelijkheid en de druk om snel nieuwe functionaliteit er uit te sturen neemt dat ook toe.
Maar als je het goed doet, dan kun je het best weer naar zijn oorsprong ontrafelen. Je zult dan strict bezig moeten zijn met de functionaliteit en de technologie weer een middel laten zijn.
Maak een vertical slice van je functionaliteit
De volgende stappen kunnen dan gedaan worden. Bepaal een stuk functionalitieit dat op zichzelf staat of had moeten staan. Beschrijf het dan van de user interface tot aan de kern (de dataopslag of de servicebus of wat ook het eindpunt is). En zodra je een afhankelijkheid spot, bedenk dan steeds of deze afhankelijkheid noodzakelijk is en of er andere oplossingen zijn. Als er geen eindpunt is, dan is er misschien een uitdaging met de functionaliteit zelf. Poplulair gezegd maak een verticale doorsnede (vertical slice) van je applicatie. Zie het als de taart met die vele gekleurde laagjes, beschrijf alles van dat ene stuk uitgesneden staart en alleen wat bij dat stuk hoort. Bouw dan dat stuk opnieuw en hergebruik zo min mogelijk eerdere code. Anders word je te vlug weer in de rabbithole getrokken. Bereid je voor op het herhaaldelijk refactoren van de code. Er lijkt geen einde aan te komen, maar uiteindelijk zal het beter worden.
Deze strategie maakt het ook mogelijk om de oude flow van de functionaliteit nog beschikbaar te houden en de nieuwe er echt los van te laten. Uiteindelijk is dat ook je doel in Service Oriëntatie. Als je dan volledig tevreden bent met de nieuwe implementatie, dan zet je de wissel om.
Soms kan de aanpassing ook aan de buitenkant gemaakt worden, waardoor bepaalde werkvoorraad niet eens je platform/applicatie of omgeving bereikt. Controle aan de deur. Beschrijf deze functionaliteit zo onafhankelijk mogelijk en als je of het team de behoefte voelt om andere functionaliteit toe te voegen of samen te voegen, stel dan de waarom vraag zo vaak mogelijk. Als je dan nog steeds niet zonder kunt, dan moet je het samenvoegen niet laten.
Maar iedere andere wijziging verstoort het proces. Dus probeer niet gelijk ook volledig nieuwe functionaliteit toe te voegen of bestaande functionaliteit volledig te veranderen. Niet omdat het niet zou kunnen, maar als we technologie of functionaliteit wijzigingen gaan doorvoeren dan worden we afgeleid en wij mensen kunnen helaas niet teveel multitasken. Het onafhankelijk en losgeweken van het stukje functionaliteit is al moeilijk genoeg. Daarom moet je de eenheid ook zo klein mogelijk maken. Dat voorkomt dat de rest van de applicatie/omgeving op slot zit voor aanpassingen of wijzigingen.
Het is te doen, maar je zult wel heel gericht door moeten gaan en je niet laten afleiden. En als je eenmaal begonnen ben, dan kun je eigenlijk niet meer stoppen. Meer dan eens zullen verschillende stukken software door je handen gaan en meer dan eens zal je code aanpassen om deze later weer ongedaan te maken. Dat geeft niet, je doel is op zichzelf staande stukken software/services. Niets is onmogelijk. Maar laat technologie niet de reden zijn! En blijf refactoren.