IT innovation

Wat vorig jaar begon met een brainstorm is in de tussentijd uitgegroeid tot een stevig traject. Je stelt je waarschijnlijk wel de vraag wat dat innovatietraject nu exact is. Om het matchingproces binnen Komma Board vlotter te laten verlopen, zowel voor onze partners als onze consultants is het idee ontstaan om een in-house matchingtool te ontwikkelen. Benieuwd welke technologieën en programmeertalen Kristof allemaal gebruikt heeft, dat check je hieronder👇
Full-stack developer – Kristof

Hoe, wat, waar? 

Voor het innovatietraject ben ik gestart met de backend. De technologieën en grotere lijnen van de architectuur waren al vastgelegd in een voorafgaande meeting met de andere technische profielen binnen het team. We zouden de businesslogica opsplitsen over verschillende microservices die elk hun specifieke aspect van de applicatie behandelen. Elke microservice kan dan, in theorie, geschreven worden in de taal die zich het beste leent voor die microservice, en elke microservice zou ook een eigen database kunnen gebruiken van het type dat zich wederom het beste leent voor die microservice – los van hoe de andere microservices werken of hun data persisten – bijvoorbeeld relationeel, document-oriented, etc.

De backend

In de praktijk dusver zijn alle microservices geschreven in Kotlin, en gebruiken we het robuuste Spring Boot-framework om ofwel REST-endpoints bloot te stellen waarlangs synchroon met de microservice gecommuniceerd kan worden, ofwel een listener te implementeren die asynchroon naar messages op een RabbitMQ luistert – ook weer afhankelijk van welke manier van communiceren zich het beste leent voor die microservice. Een voordeel aan dat tot nu toe alle microservices in eenzelfde taal geschreven zijn, is dat ik elke microservice onderling nog eens heb kunnen opsplitsen in de eigenlijke logica, en een library met alle dataklassen. Deze libraries worden gepusht naar een Maven-repository, waardoor een microservice B de library van microservice A als dependency kan toevoegen, om zo code completion en compiler errors te krijgen wanneer een DTO voor een request naar microservice A niet correct opgebouwd is. Er is uiteraard ook error handling voorzien als een interne request naar een andere microservice faalt, maar beter voorkomen at compile time dan debuggen at runtime.

Dat we, of grotendeels ik, voor Kotlin gekozen hebben, is omdat ik het vlotst programmeer voor de JVM, dankzij mijn opleiding als Java-developer. De Kotlin-syntax is echter een pak moderner en aangenamer om in te schrijven, naar mijn mening. Ze elimineert een hoop boilerplate die je zelfs in modernere versies van Java wel nog moet schrijven, en veel structuren zijn out of the box meer gericht op toepassingen “voor de dag van vandaag”. In the end is het natuurlijk een persoonlijke voorkeur, maar de aangename syntax en volledige interoperability met Java zorgt, als je het mij vraagt, voor een hele aangename programmeerervaring waarin je wel nog gebruik kan maken van alle Java-frameworks en -libraries die zich met de jaren bewezen hebben.

TechOps

Elke microservice runt in een Docker container. Er zijn Docker Compose files voorzien die standaard ook de nodige databases en andere tools opstarten, maar alle connecties naar die andere tools zijn in de microservices gedefinieerd in Spring’s application.yml files. Hierdoor kunnen ze via environment variables overschreven worden. Dit zorgt ervoor dat alles probleemloos lokaal of in Docker kan runnen, op een lokale database of een database in een container of zelfs in de cloud, in productie. Het maakt ook het opspinnen van een tijdelijke environment voor testing een pak gemakkelijker, zonder elke keer configuratiefiles aan te moeten passen.

Als een kers op de taart is er ook code voorzien om, wanneer de microservice in een Kubernetes-cluster runt, de configuratie uit Kubernetes’ ConfigMap met dezelfde name als de service over te nemen. Een configuratiefile zoals Spring’s application.yml file biedt al heel wat flexibiliteit, maar limiteert je om bijvoorbeeld connection strings naar andere microservices of databases te schrijven als een combinatie van protocol, adres en poort. In Kubernetes echter wil je gewoonlijk langs de load balancer gaan, om zo, wanneer er meerdere instances van je microservice runnen, automatisch je request te sturen naar die instance die op dat moment het minst aan het werken is. De Kubernetes API wordt ook nog eens regelmatig gepingd, en changes aan een ConfigMap worden automatisch opgepikt, waardoor de applicatie niet herstart moet worden wanneer haar configuratie wijzigt. Hot reload, om nog een extra buzz word te gebruiken. 🔥

Security

Terwijl Spring Boot uitbreiden met Spring Security je de hele waaier aan opties geeft om je microservice zo goed en zo slecht mogelijk te beveiligen, was dit niet de manier waarop we wilden werken binnen onze grotere architectuur. Security implementeren in elke microservice zelf zou voor een hoop duplicatie en overhead zorgen, en dus meteen een grote extra cost voor maintenance betekenen. De oplossing waarvoor we gekozen hebben is om, in productie, gewoonweg onze microservices niet te exposen naar de buitenwereld, op één na: de gateway-microservice. Zoals de naam al prijsgeeft, is deze microservice het entrypoint voor heel de applicatie. Het is via deze microservice dat de publieke REST API of de frontend bereikbaar is. Deze microservice filtert en forwardt requests, en bepaalt op welke URL’s er welke beveiliging nodig is.

Sommige URL’s zijn helemaal publiek, bijvoorbeeld het login enpoint op de API of URL’s die naar de frontend wijzen, die gewoon via de browser beschikbaar moet zijn. Daarnaast is er tot nu toe één filter geschreven die de overige endpoints beveiligt via JWT. Voor de authenticatie zelf is er overigens een aparte microservice geschreven, om zo, in de toekomst, snel te kunnen wisselen tussen implementaties. Momenteel werken we met eigen gebruikers (verzorgt door een aparte user-microservice) met username en password, maar het is niet onrealistisch in de toekomst 3rd party login providers te willen toevoegen.

Krijgt de gateway een nope terug van de authenticatie-microservice, dan wordt de request hier al afgehandeld met de juiste HTTP error status en response. Lukt de authenticatie wel, dan zet de gateway, alvorens de request te forwarden naar de juiste microservice, enkele interne HTTP headers die door de ontvanger gebruikt worden voor die andere auth: authorization. 👮‍♀️

De hele applicatie werkt met verschillende user roles en user statuses: bepaalde dingen kan je enkel doen met de juiste privileges, andere dingen kan je alleen doen met de juiste status (bijvoorbeeld met geverifieerd e-mailadres, of niet geblokkeerd door een admin). En bepaalde endpoints zijn ook gewoonweg enkel voor intern gebruik, tussen bepaalde microservices. Voor deze endpoints wordt een key gebruikt die elke microservice meegeeft met en uitleest na een request. Matcht de key niet, dan is er iets mis en wordt de request ook afgebroken. En uiteraard: de hele authorization-logica is ook weer afgesplitst in een aparte library, zodat elke microservice deze als dependency kan toevoegen. Geen duplicatie

De frontend

De frontend is het jongste deel van de applicatie. Hiermee zijn we een maand geleden gestart, zo’n twee maanden na de start van de backend. In een eerste fase is de frontend een webapplicatie. Hiervoor hebben gekozen om het Nextjs-framework te gebruiken, om de flexibiliteit en vloeiende flow van React te kunnen aanbieden in de user interface, maar toch ook van de optimalisaties van bijvoorbeeld het statisch renderen van pagina’s te kunnen genieten, waar dat mogelijk is. Vanzelfsprekend gebruiken we TypeScript.

Heel veel is er nog niet, na een maandje, maar de look en feel van de applicatie ligt wel al vast. Omdat we meer voor de “dashboard app” aesthetic gaan, werken we met een eigen design en component library die elke dag een beetje groter wordt. Een van de grotere dependencies die we al gebruiken om “slimme” tabellen te tonen (paginatie, filtering etc zonder het wiel opnieuw uit te vinden), is TanStack’s React-Table. Om de eigenlijke data te fetchen gebruiken we dan weer de SWR-hook, ook om weer het slimme caching niet opnieuw uit te moeten vinden.

React-Table is bring-your-own styles, dus dat doen we ook. Om het vormgeven van de UI wat sneller te laten verlopen en omdat grotere reusable CSS classes minder belangrijk zijn als je je UI al netjes opsplitst in verschillende React-componenten, gebruiken we TailwindCSS. Een andere grotere library die we gebruiken is Next-Auth, om de authenticatie en beveiliging van bepaalde pagina’s te verzorgen en handige hooks te kunnen gebruiken om bijvoorbeeld snel aan de data van de huidige gebruiker te kunnen. We gebruiken dan wel niet Next-Auth’s JWT-implementatie, maar de JWT’s die onze eigen backend genereert.

TO DO

En dat zijn de grote lijnen van hoe ver development voor de tool van het innovatietraject staat! Ik kan niet beschrijven hoe ongelofelijk interessant en leerrijk het is om een project zo uit het niets te kunnen opstarten, zowel de eerste stappen mbt development als de stappen ervoor: het brainstormen met de collega’s en losse ideeën zien groeien tot een coherent concept en de analyse die daarbij komt kijken. Zeker als consultant denk ik dat het zeldzaam is niet op een project te komen dat al enkele jaren in productie draait.

En er is zeker nog werk aan de winkel. De frontend doet nog geen 10% van wat is vastgelegd voor de eerste scope, met deadline eind dit jaar. Het is ook zonde maar testing is gaandeweg wat verloren gegaan: gestart met veel enthousiasme, maar na latere changes aan het domain die de tests braken, vaker uitgecomment dan bijgewerkt. Gelukkig zitten we wel nog op schema en is tijd om ons 100% op testing te focussen, voorzien. Anderzijds runnen de testen die er nog zijn, en linting, ook volautomatisch via CI/CD pipelines. En een eigen Slack-bot die een berichtje stuurt als iets kapot is. 🤖

IT innovation

12 oktober 2022|0 Comments

BLOG Wat vorig jaar begon met een brainstorm is in de tussentijd uitgegroeid tot een stevig traject. Je stelt je waarschijnlijk wel de vraag wat dat innovatietraject nu exact is. [...]

Missionme @ Komma Board

10 augustus 2022|0 Comments

BLOG WE BELIEVE IN THE FULL POTENTIAL OF ALL PEOPLE, NO MATTER THE AGE. PEOPLE ARE FAR MORE CAPABLE AND BRAVER THAN THEY THINK; WE LIKE TO HELP UNLEASH THIS [...]