In de afgelopen zestien jaar heeft bol.com de transformatie gemaakt van een winkel voor boeken en entertainment naar een verzameling van speciaalzaken met in totaal zo’n negen miljoen artikelen. Inmiddels heeft bol.com meer dan 5,5 miljoen klanten in Nederland en België. Met deze groei ontstond ook de groeipijn en het kraken van het IT-landschap. De systemen waar we ooit mee waren begonnen, groeiden uit tot grote, logge monolieten met een veelheid aan complexe, verweven functionaliteiten en verantwoordelijk voor evenzoveel domeinen. Niemand had meer echt het overzicht. Daar bovenop kwam de personele groei, waarbij steeds meer Scrum-teams in dezelfde monolieten werkten. We konden niet meer schalen (in de breedste zin van het woord). De wens van de business om nieuwe functionaliteit werd met de dag lastiger te vervullen.
Vanaf 2009 is bol.com gestart met de overgang naar een servicegeorie?nteerde architectuur. We hebben destijds een service gedefinieerd als:
“[E]en logische eenheid die een verzameling taken, bevoegdheden en verantwoordelijkheden heeft. Er moet sprake zijn van een hoge interne samenhang en een lage externe samenhang.”
Daarbij is van belang dat je aan de business kunt uitleggen wat de rol van een service zou zijn. Services moeten immers de business in staat stellen om hun visie en wensen te realiseren. Toen ergens in 2012 dan ook bij een plan door de business zelf om een nieuwe service werd gevraagd, wisten we dat we ze van onze aanpak hadden overtuigd.
Een van de essentiële aspecten van een service is de ontkoppeling. Een service moet bestaansrecht hebben zonder dat het (te) afhankelijk is van andere services. Maar hoe definieer je die functionele afbakening en splits je grote monolieten in de juiste services? Iets als een AccountService of SearchService (oorspronkelijk onderdeel van de monoliet ‘WebShop’) lijken triviaal, maar wat behelst die service dan precies? Wat is een Account en wat kun je allemaal Search’en? Een nieuwe g?reenfield?service is wat dat betreft relatief eenvoudig. Je begint met e?e?n, via een API ontsloten stukje functionaliteit in een losse deploybare eenheid. Maar een bestaande monoliet opsplitsen langs de juiste grenzen en soms ook combineren met iets nieuws is een forse uitdaging. We kiezen dan ook vaak voor een Agile-aanpak, waarbij we trachten een goed onderbouwde visie en keuze te maken voor een service en dan simpelweg te starten met bouwen. Het zal dan wellicht niet helemaal juist of volledig zijn, maar niet kiezen is geen optie en inzicht komt met tijd en ervaring. Als de praktijk anders uitwijst, dan stellen we die visie bij. We erkennen dat we nog veel moeten leren qua servicedesign en zijn al regelmatig tot nieuwe inzichten gekomen.
Op het technisch vlak hebben we ook nog de nodige stappen te zetten. In ons huidige landschap zijn service instanties gekoppeld aan een VM, is er een omvangrijk proces om een nieuwe service te laten ontstaan en duren deployments lang. Dit zijn allemaal barrières voor het creëren van, en snel itereren op, kleine services. Daarnaast hebben we ook nog een uitdaging in onze huidige testomgeving: voor het hele bol.com ITlandschap hebben we momenteel e?e?n testomgeving waar iedereen op werkt. Dit was een logische keuze toen ons landschap uit sterk verweven monolieten bestond, maar inmiddels voldoet deze werkwijze niet meer. Als een service of applicatie in het testlandschap faalt, dan hebben (in potentie) alle Scrum-teams daar last van. Daarom hebben we anderhalf jaar geleden besloten om onze development en productieplatformen zodanig te verbeteren, zodat ze meer geschikt zijn voor een (micro) service-architectuur.
De oplossing voor de development uitdagingen is alweer enkele maanden in gebruik en heet Mayfly. Mayfly biedt Scrum-teams een geïsoleerde testomgeving p?er user story?, die in uitvoering is. Niet alleen de service waaraan het team werkt wordt in deze omgeving geïnstantieerd, maar ook test databases, test properties en een instantie van Critter (een service test tool) worden beschikbaar gesteld. In plaats van een grote, gedeelde testomgeving hebben teams nu de mogelijkheid om een testomgeving per story te creëren, compleet met feature branches, die automatisch worden gemaakt en gemerged door Mayfly. Hierdoor hebben problemen, die geïntroduceerd worden door codewijzigingen van een story, geen impact op andere teams of zelfs andere stories. De oorspronkelijke visie van onafhankelijkheid en ontkoppeling tussen services wordt hierdoor ook werkelijkheid in de dagelijkse ontwikkelervaring van de Scrum-teams.
Ook de deployment kant van de medaille behoefde aandacht. Als bol.com willen we onze 40+ Scrum-teams de vrijheid geven om een fijnmazige service-architectuur te creëren. De oorspronkelijke constructies, die we hanteerden voor het lanceren van een nieuwe service, waren te zwaar en te zeer afhankelijk van IToperations om goed te kunnen schalen. Lijvige nonfunctional requirements documenten, uitvoerige provisiontrajecten van VM’s (met volledig statische configuraties) voor services en tijdrovende deployments kwamen de ontwikkelsnelheid niet ten goede. We zijn momenteel bezig met de evolutie van ons platform naar een meer dynamisch model. We gebruiken nieuwe technologieën, zoals Docker en Mesos om deployment en provisioning van service instanties te versnellen en versimpelen. Statische serviceconfiguratie wordt vervangen door tools, zoals Consul (voor service discovery) en onze eigen property service Kevlar (voor database wachtwoorden etc.) Daarnaast maakt een aantal Scrum-teams inmiddels gebruik van Flyway en myBatis Migrations om te zorgen dat database deployments binnen de service kunnen worden geregeld in plaats van via een apart deploy proces.
Naast de technische oplossingen, die we doorgevoerd hebben om onze service-architectuur te realiseren, zit het serviceconcept inmiddels ook bij de hele IT-afdeling goed tussen de oren. Er wordt zelfs gesproken over het “verservicen” van enkele vroege service,s die op hun beurt weer monolieten dreigen te worden. Het doorvoeren van onze (micro-)service aanpak geeft ons evenwel het vertrouwen dat we de huidige en toekomstige problemen kunnen oplossen.