Wat is het controleren aansluiting ontwerp?
Als developer zorg je ervoor dat de code goed aansluit bij het oorspronkelijke ontwerp en de gestelde requirements. Het is belangrijk dat de code de gewenste functionaliteit biedt zonder onbedoelde afwijkingen van het ontwerp en dat het onderhoud en de uitbreidbaarheid op lange termijn gewaarborgd blijven. Het toepassen van design reviews, testen, feedback en het naleven van code standaarden zorgt voor kwaliteit en consistentie tussen ontwerp en implementatie.
Casus
Stel, het oorspronkelijke ontwerp beschrijft een “UserService” die verantwoordelijk is voor het beheren van gebruikersgegevens, maar tijdens de implementatie werd de service uitgebreid met logica die ook bestellingen beheert. Dit zou in strijd zijn met het ontwerp en kan leiden tot een ongewenste complexiteit en moeilijk onderhoudbare code. Dit werd duidelijk tijdens een code review. Het beheren van bestellingen werd verplaatst naar een aparte service.
Hoe zit het controleren van de aansluiting op het ontwerp in elkaar?
Bij de controle op aansluiting op het ontwerp wordt op drie zaken gelet:
- Volgt de code het ontwerp en de architectuur?
- Zijn de gebruikte taalconcepten passend voor de gestelde requirements?
- Is de code modulair, testbaar en uitbreidbaar?
- Zijn er overbodige afhankelijkheden of componenten toegevoegd die niet in het ontwerp stonden?
1. Volgt de code het oorspronkelijk gedefinieerde ontwerp en de architectuur?
Het ontwerp en de architectuur zijn de blauwdrukken van de software. Ze beschrijven hoe de verschillende componenten met elkaar communiceren, hoe de functionaliteit wordt opgesplitst, en hoe verschillende lagen van de applicatie samenwerken. Het is essentieel om te controleren of de geïmplementeerde code het ontwerp volgt om een robuuste en consistente applicatie te garanderen.
Wat je moet controleren
- Architecturale consistentie: Zijn de gekozen ontwerpprincipes (zoals MVC, Layered Architecture, Clean Architecture) correct toegepast? Zijn de verschillende lagen zoals presentatie, logica en data gescheiden?
- Modules en componenten: Komt de implementatie overeen met de gedefinieerde modules en componenten in het ontwerp? Zijn de componenten logisch verdeeld over verschillende modules, zoals beschreven in de architectuur?
- Verantwoordelijkheden: Bevat de code dezelfde verantwoordelijkheden als die in het ontwerp zijn beschreven? Zijn er geen nieuwe, onbedoelde verantwoordelijkheden toegevoegd aan klassen of componenten?
2. Zijn de gebruikte taalconcepten geschikt voor de gestelde requirements?
Elk taalconcept (zoals object-georiënteerd programmeren, functionele programmeerprincipes, etc.) heeft sterke en zwakke punten afhankelijk van de aard van de vereisten. Het is belangrijk om te controleren of de juiste concepten en patronen worden gebruikt die de vereiste functionaliteit op een efficiënte en onderhoudbare manier ondersteunen.
Wat je moet controleren
- Kies het juiste paradigma: Is object-georiënteerd programmeren (OOP) toegepast waar dat logisch is, bijvoorbeeld voor het modelleren van entiteiten met inherente eigenschappen en gedragingen? Of is een functionele benadering beter geschikt voor de vereiste (bijv. pure functies voor berekeningen)?
- Gebruik van design patterns: Zijn er geschikte design patterns gebruikt om veelvoorkomende problemen op een gestructureerde manier op te lossen? Bijv. het gebruik van de Factory Pattern voor objectcreatie of Singleton Pattern voor het beheren van gedeelde resources.
- Taal-specifieke features: Zijn de taal-specifieke concepten optimaal benut? Bijvoorbeeld, het gebruik van async/await in JavaScript of C# voor asynchrone processen, of de toepassing van interfaces in C# voor het abstraheren van implementaties.
3. Is de code modulair, testbaar en uitbreidbaar?
Code die goed gestructureerd is en bestaat uit modulaire, herbruikbare componenten is makkelijker te testen, onderhouden en uitbreiden. Het voorkomt dat je grote, monolithische stukken code krijgt die moeilijk te begrijpen en te testen zijn.
Wat je moet controleren
- Modulariteit: Is de code opgedeeld in duidelijke, kleine eenheden die één verantwoordelijkheid hebben (zoals volgens het Single Responsibility Principle)? Zijn deze eenheden goed gescheiden, bijvoorbeeld door interfaces of abstracties?
- Testbaarheid: Is de code ontworpen met testbaarheid in gedachten? Zijn er voldoende eenheidstests (unit tests) en integratietests geschreven? Kunnen de tests eenvoudig worden uitgevoerd zonder dat er te veel afhankelijkheden zijn?
- Uitbreidbaarheid: Is de code geschreven op een manier die toekomstige uitbreiding gemakkelijk maakt? Zijn de interfaces en abstracties duidelijk, zodat nieuwe functionaliteit kan worden toegevoegd zonder bestaande code te breken? Is er gebruik gemaakt van extensiepunten zoals interfaces of abstracte klassen?
4. Zijn er overbodige afhankelijkheden of componenten toegevoegd die niet in het ontwerp stonden?
Het toevoegen van onnodige afhankelijkheden of componenten die niet in het oorspronkelijke ontwerp staan, kan de applicatie onnodig complex maken, de onderhoudskosten verhogen en de prestaties beïnvloeden. Het is belangrijk om ervoor te zorgen dat alles wat in de code wordt geïntroduceerd, relevant is voor de gestelde vereisten.
Wat je moet controleren
- Overbodige afhankelijkheden: Zijn er externe bibliotheken, pakketten of services toegevoegd die niet nodig zijn voor de functionaliteit? Dit kan leiden tot een zwaardere applicatie, moeilijkheden met updates en een grotere kans op bugs.
- Ongebruikte componenten: Hebben de geïmplementeerde klassen of methoden daadwerkelijk een rol in de beoogde functionaliteit? Zijn er dode of overbodige klassen die geen waarde toevoegen?
- Naleving van het ontwerp: Als het ontwerp simpelweg niet vraagt om een bepaalde functie, maar je hebt die toch geïmplementeerd, dan kan dat duiden op een verkeerde afweging of misinterpretatie van de requirements.
Casus
Stel dat je een nieuwe, externe bibliotheek toevoegt voor het genereren van grafieken, terwijl het oorspronkelijk ontwerp simpelweg zei dat een tabel met data volstaat. Dit voegt onnodige complexiteit toe en verhoogt het aantal afhankelijkheden, terwijl het ontwerp zelf het probleem veel eenvoudiger oplost.
Hoe gebruik je het controleren van de aansluiting op het ontwerp?
Het uitvoeren van controles om te bepalen of de code aansluit bij het oorspronkelijk gedefinieerde ontwerp en de architectuur kan op verschillende momenten in de Secure Software Development Life Cycle (SSDLC) en binnen een SCRUM proces plaatsvinden. Elk van deze momenten biedt een kans om vroegtijdig problemen te identificeren en te corrigeren, wat de kwaliteit en onderhoudbaarheid van de code waarborgt. Het is aan het team om de momenten te kiezen en de intensiteit te kiezen.
SSDLC
Vanuit het perspectief van de SSDLC is het belangrijk om gedurende verschillende fasen van het proces regelmatig te controleren of de code in lijn blijft met het oorspronkelijk gedefinieerde ontwerp en de architectuur. Deze controles moeten beginnen in de vroege fasen van de SSDLC en doorlopen worden tijdens de implementatie en het testen, zodat problemen zo vroeg mogelijk kunnen worden geïdentificeerd en gecorrigeerd.
In de requirementsanalyse is het belangrijk om te zorgen dat de vereisten en het ontwerp volledig en duidelijk zijn. Dit vormt de basis voor de rest van de ontwikkeling. Gedurende de ontwerpfase wordt het technische ontwerp uitgewerkt. Het is cruciaal om te controleren of dit ontwerp consistent is met de architectuur en of het de gewenste modulariteit en uitbreidbaarheid biedt.
Zodra de implementatiefase start, moet er regelmatig worden gecontroleerd of de geschreven code het ontwerp volgt en of de taalconcepten die worden gebruikt geschikt zijn voor de gestelde vereisten. Dit gebeurt vaak via peer reviews en code reviews, waarbij niet alleen naar de functionaliteit wordt gekeken, maar ook naar de structuur en kwaliteit van de code.
Tijdens de testfase is het van belang om te verifiëren of de code werkt volgens de acceptatiecriteria en of deze voldoet aan de oorspronkelijke specificaties. Hier wordt ook gecontroleerd of de code modulair, testbaar en uitbreidbaar is.
Uiteindelijk, wanneer de code in de release- of deployfase komt, wordt een laatste controle uitgevoerd om er zeker van te zijn dat de code werkt zoals gedefinieerd in het ontwerp, zonder dat er ongewenste componenten of afhankelijkheden zijn toegevoegd die niet in het oorspronkelijke ontwerp stonden.
SCRUM
Vanuit het SCRUM-perspectief is het belangrijk om gedurende de verschillende fasen van een sprint regelmatig te controleren of de ontwikkelde code in lijn blijft met het oorspronkelijk gedefinieerde ontwerp en de architectuur. Dit gebeurt iteratief tijdens de sprints, waarbij de code steeds verder wordt ontwikkeld, getest en verfijnd, met als doel het leveren van werkende software die voldoet aan de acceptatiecriteria.
Tijdens de sprint planning wordt het werk gedefinieerd op basis van de product backlog en de prioriteiten van de klant. Het is in deze fase belangrijk dat het team zorgt voor een duidelijk begrip van de vereisten en het ontwerp. Dit vormt de basis voor de rest van de sprint. Gedurende de ontwikkeling moeten teamleden regelmatig controleren of de code aansluit bij het oorspronkelijke ontwerp en de architectuur.
In de daily standups wordt de voortgang besproken en kunnen obstakels die betrekking hebben op de architectuur of het ontwerp naar voren komen. Het team kan dan snel reageren en eventuele afwijkingen van het ontwerp of de gekozen taalconcepten tijdig bijsteken.
Tijdens de sprint review worden de opgeleverde functionaliteiten gepresenteerd aan de stakeholders en de Product Owner. Dit is het moment om te verifiëren of de opgeleverde code voldoet aan de gedefinieerde acceptatiecriteria en of de code voldoet aan de oorspronkelijk geformuleerde vereisten. Dit is ook het moment om te beoordelen of de code modulair, testbaar, en uitbreidbaar is.
In de retrospective wordt besproken wat goed ging, wat beter kan en hoe het team haar processen kan verbeteren. Dit kan ook inzichten opleveren in de vraag of het team de juiste keuzes heeft gemaakt qua ontwerp, afhankelijkheden en taalconcepten, en hoe dit het ontwikkelingsproces kan verbeteren in de volgende sprints.
Gedurende de hele SCRUM-cyclus, vooral in de tussentijdse review-momenten en retrospectives, moet het team ervoor zorgen dat er geen overbodige afhankelijkheden of componenten in de code zijn gekomen die niet in het oorspronkelijke ontwerp stonden. Hierdoor kan het team blijven voldoen aan de oorspronkelijk gestelde doelen en kwaliteitsnormen van het project.
Volgende stap: Uitleg peerreviewen code