1 juni 2023
An introduction into vertical slicing 2

Ray Wijshake
Software Engineer

Inleiding
In het eerste deel is er conceptueel bekeken wat Vertical Slicing inhoudt. In dit deel zal de technische invulling worden toegelicht. In de basis is Vertical Slicing een invulling op een functionaliteit in een applicatie. Elke functionaliteit heeft z’n eigen slice in de code stack, beginnend in een frontend oplossing en eindigend in een backend. Voor de HappyShop app zijn er ter illustratie de volgende gebieden gedefinieerd:
Een productcatalogus
Een productpagina
Een winkelwagen
Het bestelproces
Laten we eerst even kijken naar de frontend.
Frontend
Kijkend naar frontend op het web is de basis jaren geleden gelegd: een combinatie van HTML, CSS en JavaScript maakt het mogelijk om dynamische pagina’s op te bouwen. Waarbij het traditioneel aparte lagen waren ziet het landschap er tegenwoordig anders uit. Kijk bijvoorbeeld naar React: hierbij is het gebruikelijk om in componenten te denken. Elk component vormt een bouwblok waarmee een website wordt opgebouwd. Grappig genoeg is het concept van Vertical Slicing hierin van toepassing: elk component heeft z’n eigen HTML, CSS en JavaScript. De componenten zijn vervolgens gesorteerd per functionaliteit waardoor je een kleine vertaalslag hebt tussen de functionele werking en technische implementatie.
Neem bijvoorbeeld de productpagina van de HappyShop app:
Het is opgebouwd uit een aantal componenten:
• Een component voor het tonen van productinformatie
• Een knop voor het toevoegen van het product aan de winkelwagen
• Een knop voor het markeren van een product als favoriet
In feite losse slices die onderling geen raakvlakken hebben, maar allemaal wel de verschillende lagen hebben om een werkende functionaliteit op te leveren:
Het mooie hiervan is dat de componenten hun eigen slice in de backend hebben door de requests die de buttons in dit voorbeeld uitvoeren.
Backend
In de basis gaat het om de manier waarop requests worden afgehandeld. Het idee is dat een request wordt afgehandeld in één slice zonder in aanraking te komen met andere slices, vergelijkbaar met een component in React. In de basis ziet dat er als volgt uit:
- Een request komt binnen op een endpoint
- Het wordt doorgestuurd naar de onderliggende handler voor afhandeling
- Een response wordt samengesteld en teruggestuurd
That’s it! Ok, dat is iets te kort door de bocht 😜. Laten we iets verder inzoomen. Voor de technische invulling staat er een ASP.NET Core backend voor het ophalen van data en afhandelen van bestellingen. Met Vertical Slicing in gedachte laat dit zich vertalen in de onderstaande projectstructuur:
Hierbij is dezelfde structuur gehouden als de frontend oplossing. Hierbij blijft het dicht bij de functionele werking en ontstaat er een structuur dat eenvoudig meegroeit met de applicatie. In dit voorbeeld heeft elke functionaliteit z’n eigen map gekregen met daaronder de desbetreffende endpoints. Zoomen we iets dieper in dan zien we dat er voor de producten een aantal endpoints zijn:
• Het ophalen van een specifiek product
• Het ophalen van afbeeldingen
• Het markeren van favorieten
Vergelijkbaar met componenten in React zijn dit losse slices:
Per endpoint is er één bestand aangemaakt. Dit maakt dat als de hoeveelheid functionaliteiten groeien (er komen meer slices bij) je in één oogopslag kunt zien wat er functioneel wordt gebruikt. In dit voorbeeld bevat een bestand meerdere classes (dit zul je hieronder zien), al is dit overigens voorkeur. Je kunt er bijvoorbeeld ook voor kiezen om per bestand een aparte class aan te maken.
Zoomen we verder in op één van de slices dan zien we het volgende:
- Een endpoint voor de app om aan te roepen
- Een query om intern de informatie op te vragen
- Een ViewModel voor het teruggeven van de informatie
- De handler voor het daadwerkelijk ophalen van de informatie
Wat je ziet zijn twee zaken:
Scheiding tussen endpoint en handler
Het idee hierachter is om de code simpel te houden. In essentie is een endpoint slechts een ingang in het systeem. Het enige wat het hoeft te doen is het ontvangen van requests en deze intern door te sturen naar de juiste handler. Om hierin een scheiding te houden en de orchestration te regelen wordt er gebruik gemaakt van de Mediator pattern, ingevuld door de Mediatr package. Dit houdt de afhandeling simpel: • Bij het ontvangen van een externe request wordt er intern een query ingeschoten d.m.v. Mediatr. • Een handler vangt de query op en voert deze uit.
Scheiding in request en reponse
Aanvullend is de query en ViewModel specifiek voor deze class geïmplementeerd d.m.v. de static modifier op class niveau. Gebruik makend van de CQRS pattern blijft de query / command en response behouden tot de specifieke functionaliteit (slice). Dit maakt dat elke functionaliteit zijn eigen response heeft om mee te werken en aan te passen is zonder impact op andere slices. Dit maakt tevens dat het maken van abstracties minder noodzakelijk is omdat je simpelweg minder lagen hebt om doorheen te gaan.
Hoe verder?
Naar mate een applicatie groeit blijven het aantal slices toenemen. De kans is groot dat er op den duur gemene delers ontstaan in de code. Dit is natuurlijk in het verloop van een project aangezien concepten steeds meer concreet en uitgekristalliseerd worden. Houdt dit in gedachten tijdens het ontwikkelen en wees flexibel hierin: begin simpel met het bouwen van een enkele functionaliteit. Op het moment dat je een vergelijkbare functionaliteit bouwt, houdt deze dan in zijn eigen slice. Dit maakt dat er geen impact is op andere code. Wanneer een bepaalde functionaliteit vaker nodig blijkt te zijn, dan wordt het tijd voor een stukje refactoring om te kijken wat de gedeelde business logica is en hoe je deze dieper in het systeem kunt vastleggen. Tot slot nog een stuk over de gedeelde infrastructuur. Afhankelijk van de applicatie is de kans groot dat er één vorm van dataopslag is. Wat Vertical Slicing met zich meebrengt is dat je hier niet afhankelijk van bent. Zo kun je er voor kiezen om voor de ene slice bijvoorbeeld een relationele database te gebruiken om vervolgens voor een andere slice een NoSQL database te gebruiken. Voel je vrij om hierin te experimenteren om te kijken wat het beste bij de slice en het project past.
Take aways
- Vertical slicing is functioneel van aard en gebaseerd op de behoefte in de business. Hoe gedetailleerder de behoefte, hoe concreter de user stories zijn en hoe simpeler de slices worden.
- Naamgeving is een belangrijk gegeven. Blijf dicht bij de functionaliteit en houdt het simpel.
- Let op code smells. Herken wanneer slices gedeelde functionaliteiten gaan delen en refactor pas op dat moment.

Ray Wijshake