In de afgelopen jaren heb ik bij verschillende opdrachtgevers in diverse branches mogen werken, zo ook bijvoorbeeld voor de overheid. Vanuit een van deze opdrachtgevers was de wens om een nieuw platform te bouwen en beschikbaar te stellen aan meerdere doelgroepen en moest deze diverse functionaliteiten ondersteunen. De keuze stond vooraf al vast dat deze applicaties en API’s via een microservices architectuur ontwikkeld zouden gaan worden.
Kort gezegd bestaat een landschap van microservices uit applicaties die ontwikkeld zijn als een verzameling van applicaties (dus functionaliteiten). Elke applicatie kan je zelfstandig ontwikkelen, implementeren en onderhouden zonder afhankelijkheden van andere applicaties.
Om een idee te geven hoe het platform is ontwikkeld doe ik in deze net alsof wij een pizzeria genaamd “De CINQeria” zijn met soortgelijke vraagstukken, namelijk:
Op basis van deze wensen kom je tot een landschap van vier applicaties (de blauwe blokken) met overeenkomende functionaliteiten (de grijze blokken), zie de afbeelding:
Naast de applicaties zullen er ook vier backend services nodig zijn, zie de afbeelding:
Sommige functionaliteiten maken gebruik van meerdere services, maar er is vanuit de functionaliteit gezien altijd maar één ingang/startpunt. Voor de functionaliteit “overzicht” zal enkel de “pizza service” benaderd worden, eveneens voor de functionaliteit “samenstellen” welke de “topping service” gebruikt. Bij de functionaliteit “bestellen” wordt het al een stuk interessanter. Om de pizza’s te kunnen bestellen zal dit via de “order service” verlopen. Omdat je natuurlijk eerst moet betalen, zal er vanuit de “order service” een beroep gedaan worden op de “payment service” zodat de betaling gedaan en geverifieerd kan worden. De functionaliteit “bestelstatus” zal via de “order service” verlopen.
Voor de consumenten zijn de ingangen naar de services voornamelijk via de “pizza service” en “topping service” om vervolgens te bestellen via de “order service”. Vanuit de CINQeria is de ingang voornamelijk de “order service”. Deze laat ons namelijk weten welke orders er zijn geweest. In een order staat onder andere informatie welke pizza’s er zijn samengesteld en of de betaling succesvol is gedaan. Om de functionaliteit “orders” en “bereiden” te kunnen doen zal de “order service” als startpunt worden genomen. Deze haalt vervolgens weer informatie op uit de andere services. Voor de consument als de CINQeria ziet het er dan ongeveer zo uit:
De communicatie van en naar services kan je op allerlei manieren optuigen. De belangrijkste regel die je moet onthouden is dat elke service zijn eigen doel heeft. De “order service” heeft (data)-afhankelijkheden van alle andere services, maar het doel is nog steeds het geven van informatie over de order. Je kunt het zien dat elke service een contract heeft voor input en output. Dat wil zeggen dat de inhoudelijke informatie van de order wordt opgehaald uit de andere services. In de “order service” staat informatie over welke pizza ID’s en bijhorende topping ID’s. Idem van de betalingstatus. Door middel van contractbeheer (schema’s definiëren, contracttesting, etc) hou je grip op wat erin en uitgaat. De data kan je bijvoorbeeld laten lopen via message queuing en het ophalen van data via GraphQL. Ook wil ik gelijk benadrukken dat alleen dit al een vak apart is tussen services.
Naast de services weten wij ook dat De CINQeria meerdere applicaties gaat gebruiken. Zo heeft elke applicatie zijn eigen gebruikers, zijn eigen doel en eigen platform. Door hier zo slim mogelijk over na te denken kom je tot een wens om een aantal dingen vast te leggen, dit zijn een Design System en Styleguide, gedeelde componenten en gedeelde functionaliteiten. Omdat allemaal te bereiken maak ik een keuze die wel toekomst vast is, maar waarin je nog wel de mogelijkheid om keuzes te maken.
Voor de CINQeria wil ik zo min mogelijk ontwikkelen en een zo groot mogelijk bereik hebben via verschillende platforms. Daarom kies ik voor een Design System uit Webcomponents (gemaakt via StencilJS) en een gedeelde library waarin ik dezelfde (deel)-functionaliteiten heb. Dan kan je ongeveer op zoiets uit:
De gedeelde library wil ik ontwikkelen met Angular, zodat de meeste applicaties hier slim gebruik van kunnen maken. De mobiele applicaties wil ik bijvoorbeeld ontwikkelen met Ionic in combinatie met Angular. Op deze manier heb ik samenwerking tussen het Design System, de gedeelde library en de applicatie zelf.
De blauwe blokken zijn nog steeds de applicaties en de oranje blokken beschrijven op welke manier. Binnen deze applicaties wordt gebruik gemaakt van de donkergrijze blokken, wat dus gedeelde functionaliteiten zijn die op hun beurt weer gebruik maken van het Design System. De lichtgrijze blokken zijn ook functionaliteiten, maar binnen de applicatie zelf. Ook deze componenten maken weer gebruik van het Design System.
Door middel van dit artikel hoop ik jullie een klein beetje meegenomen te hebben in de wereld van microservices in combinatie met Micro Frontends. Zogezegd, zo gedaan. Ten tijde van dit artikel wist ik natuurlijk op voorhand al ongeveer wat ik wilde gaan schrijven. Toch heb ik hier en daar wat moeten aanpassen in de blokjes van functionaliteiten en services om het verhaal beter over te brengen. De belangrijkste conclusie die ik kan meegeven is keep it simple en hou vast aan het doel van de service of applicatie. Hoort dat echt bij die service of wordt het op nog meer plekken gebruikt? Is het daarom reden voor een eigen service? Maar let op; blijf bij de les. Het landschap aan services groeit snel, dus zorg altijd dat je het onder controle hebt met contractbeheer en testing. Een gewaarschuwd mens telt voor twee.