In samenwerking met SD Worx ontwikkelt Teal Partners een applicatie die hr-departementen van kmo’s ondersteunt. Met dit softwarepakket beheren kmo’s alle hr-gerelateerde informatie voor hun medewerkers. De nieuwe loonmotor berekent onderliggend de lonen, de sociale zekerheidsbijdragen en de inhouding van belastingen.
Een loonmotor kan vandaag veel meer dan rekenen en afrekenen (het uitbetalen van de lonen). Werkgevers willen hun werknemers graag een interessant pakket van extralegale voordelen bieden om het verschil te maken in de ‘war for talent’. Ook de mogelijkheid om deeltijds of van thuisuit te werken voor een betere werk-privébalans maken deel uit van zulk pakket.
Met de nieuwe loonmotor willen we bedrijven toelaten om loonkostvoorspellingen te maken tot een jaar vooruit. Hij moet simulaties mogelijk maken van diverse verloningspakketten of tewerkstellingsscenario’s, en hun impact op de kost en nettolonen.
Om die opties in het softwarepakket van de loonmotor te verwerken, kozen we voor een modulaire aanpak. Er zijn drie redenen om te kiezen voor een modulaire aanpak: (1) verschillende teams kunnen gelijktijdig features opleveren, (2) de oplossing kan gradueel geïntroduceerd worden in een nieuwe markt, en (3) de modules kunnen apart geschaald worden. We gaan er dieper op in.
Een modulaire aanpak laat toe om gelijktijdig nieuwe features te ontwikkelen in verschillende teams. Zo kunnen softwareontwikkelaars zich focussen op hun kerntaak.
De oplossing is opgebouwd volgens de principes van een ’microservices architectuur’ met vier modules.
Elke module heeft een eigen domeinmodel en een aparte databank. De data wordt tussen de modules op een asynchrone manier uitgewisseld. In de databank wordt een onderscheid gemaakt tussen
Een voorbeeld vanuit het perspectief van de payroll module:
Van bij de start kozen we ervoor om de ‘definition dataset’, de relevante set aan parametrisatiedata, in elke databank te bewaren. Dit laat ons toe de referentiële integriteit te garanderen.
Onderstaande tekening verduidelijkt de opzet van de softwareoplossing in modules.
Het bepalen van de juiste grenzen tussen de modules is cruciaal in een modulaire architectuur.
Volgende drivers hebben ons geholpen om de juiste opdeling te kiezen:
Het opsplitsen van de software in modules is dus anders dan het opsplitsen van de software in services. Terwijl we bij services kijken naar de technische verantwoordelijkheid kijken we bij modules naar het splitsen van het domein in functionele entiteiten met een beperkte onderlinge afhankelijkheid.
Naast het opsplitsen van de modules hebben we een aantal technische patronen gedefinieerd om ze doorgedreven te ontkoppelen zonder de consistentie van de data te verliezen.
Elke module bewaart de relevante data van de andere modules in de eigen database. Dit noemen we de ‘referentiedata’. Deze werkwijze biedt drie voordelen bij het ontkoppelen van de software.
Nadat de software in modules is opgesplitst, is de weg vrij om te ontwikkelen. De teams kunnen in hun eigen tempo en met een eigen aanpak hun module ontwikkelen. Cruciaal voor de duurzaamheid van een modulaire aanpak is het uitwisselen van data tussen de modules. Wij kozen voor een inbox/outbox-patroon.
Om het concept van het inbox/outbox-patroon uit te leggen, doorlopen we de verschillende stappen van een datawijziging.
Stap 1. De data wordt gewijzigd in module A
Elke request in een module (bijvoorbeeld het opslaan van een invulformulier op de UI) wordt behandeld door een unit of work en een bijhorende databasesessie. Dat wil zeggen dat de verwerking atomair is: de data wordt in zijn geheel bewaard of verworpen.
Elke wijziging van de database resulteert in één bericht per externe module met de gewijzigde data. Het bericht wordt echter niet onmiddellijk verstuurd maar eerst weggeschreven in de outbox. De outbox is een tabel die de uitgaande data van een module bevat. Door de outbox te vullen in dezelfde sessie als degene waarin de ‘owned data’ wordt gewijzigd is het bericht in de outbox deel van de atomaire actie. Met andere woorden; er is geen wijziging van de owned data zonder record(s) in de outbox en vice versa.
Stap 2. De berichten worden verstuurd van module A naar module B
Na het afwerken van de request wordt een achtergrondproces in gang gezet dat alle onbehandelde berichten in de outbox oppikt en doorstuurt naar de correcte modules. Dit achtergrondproces heeft zijn eigen unit of work en wordt volledig asynchroon uitgevoerd. De ontvangende module heeft een inbox API voor het ontvangen van de berichten.
De ontvangende module bewaart het bericht in een Inbox-tabel. Het is niet meer dan een log van alle inkomende berichten van de andere modules.
Stap 3. Het inbox-bericht wordt verwerkt in module C
Na het ontvangen van een inbox-bericht zal de ontvangende module een nieuw proces starten, opnieuw met een eigen unit of work, voor het verwerken van dit inkomende bericht. De impact van de inkomende data wordt weggeschreven in de referentiedata, en de impact op de owned data wordt al dan niet asynchroon verwerkt.
Dit patroon brengt een aantal eigenschappen met zich mee.
In dit artikel hebben we de voordelen zijn van een modulaire aanpak besproken.
(1) We kunnen verschillende teams gelijktijdig features laten opleveren;
(2) De oplossing kan gradueel geïntroduceerd worden in een nieuwe markt;
(3) De modules kunnen apart geschaald worden.
De grootste uitdaging is om een doorgedreven ontkoppeling tussen de modules te realiseren en toch de consistentie van data tussen de modules te garanderen. Dit realiseren we door de keuze van de grenzen van de modules, het gebruik van referentiedata en het outbox/inbox patroon.
Herkennen jullie in dit artikel concepten uit ‘Domain Driven Design’ of ‘Microservices’? Dat kan kloppen. We zijn in dit artikel bewust de hype rond deze technologieën uit de weg gegaan door ze niet expliciet zo te benoemen. De concepten uit de literatuur hebben ons op weg gezet. Wij passen ze in de praktijk toe, vertrekkende vanuit de probleemstelling. Met dit artikel wilden we graag de spotlight zetten op de pragmatische aanpak.
We hopen jullie iets te hebben bijgebracht door onze ervaring te delen. Het zou leuk zijn om reactie te krijgen op deze blog. Elke feedback is welkom. Wat vinden jullie van deze oplossing?