Gids naar clean code

Inleiding
Clean code verwijst naar code die gemakkelijk te begrijpen, te onderhouden en te wijzigen is. Het is code die duidelijkheid biedt voor ontwikkelaars en die voldoet aan best practices en conventies. Het belang ervan in softwareontwikkeling is groot, het zorgt voor een efficiënt ontwikkelingsproces, minimaliseert bugs en verbetert de samenwerking binnen teams.
Single Responsibility Principle (SRP):
" Every class should have a single responsibility: It should have a single purpose in the system, and there should be only one reason to change it. "
- Michael Feathers
Kritiek
Sommige programmeurs bekritiseren het Single Responsibility Principle (SRP) vanwege de subjectiviteit van het concept 'verantwoordelijkheid', waardoor het definiëren van een enkele verantwoordelijkheid voor een klasse of functie soms vaag kan zijn en tot overmatige splitsing van code kan leiden.
Dit kan resulteren in een overmaat aan kleine, onsamenhangende klassen die de leesbaarheid en het begrip van de code kunnen verminderen.
Maar wat is goede code? “Goede code” of “clean code” zijn vaak subjectieve begrippen. Wat voor de ene als goed wordt beschouwd, kan voor de andere minder wenselijk zijn. Hangt af van persoonlijke voorkeuren, teamnormen en projectvereisten en zelfs trends die evolueren.
Als we het over "clean code" hebben, verwijzen we meestal naar code die gemakkelijk te begrijpen, te onderhouden en te wijzigen is. Dit kan betekenen dat de code goed gedocumenteerd is, duidelijke variabelen en functienamen heeft, geen overtollige complexiteit bevat en voldoet aan best practices en conventies.
Abstractie

Ik heb het boek "Clean Code" zelf niet gelezen maar in dit boek van Robert C. Martin staat in hoofdstuk 3 over het schrijven van goede functies.
Het idee van het niet vermengen van abstractieniveaus in functies is cruciaal voor het behouden van codeleesbaarheid en begrijpelijkheid. Functies moeten zich concentreren op een specifiek abstractieniveau van taken en operaties, zonder af te dwalen naar details op andere niveaus.
Bijvoorbeeld, als een functie stappen uitvoert om een pizza te maken, moet deze zich alleen richten op de algemene stappen, zoals het kneden van het deeg, het toevoegen van saus en toppings, en het bakken van de pizza. Als de functie afdwaalt naar details zoals het recept voor de saus of het precieze bakproces, vermengt het verschillende abstractieniveaus, waardoor de leesbaarheid wordt verminderd.
Door functies consistent te houden op één abstractieniveau, wordt de code gemakkelijker te begrijpen en te onderhouden.
Single Responsibility Principle (SRP)

Het concept van 'single responsibility' is een kernprincipe van het schrijven van goede code. Het houdt in dat een functie (of een klasse) één specifieke taak of verantwoordelijkheid zou moeten hebben. Dit bevordert niet alleen de splitsbaarheid en herbruikbaarheid van code, maar maakt het ook gemakkelijker om bugs op te sporen, de code te begrijpen en wijzigingen aan te brengen zonder onbedoelde bijwerkingen te veroorzaken.

Zoals je ziet, is de code hier gerefactoriseerd, waardoor de Employee tabel niet langer de methodes isPromotionDueThisYear en calcIncomeTaxForCurrentYear heeft, waardoor deze nu voldoet aan SRP.
Algemene regel
Hier is een eenvoudige richtlijn voor het schrijven van functies: elke functie moet zich richten op slechts één specifieke taak of verantwoordelijkheid.
Door dit te doen, wordt de code gemakkelijker te begrijpen, te onderhouden en te wijzigen. Ontwikkelaars kunnen zich concentreren op de specifieke actie of taak die elke functie moet uitvoeren, zonder afgeleid te worden door details op een ander abstractieniveau.
Als bepaalde onderliggende concepten herhaaldelijk voorkomen in verschillende delen van de code, kan het nuttig zijn om deze concepten naar aparte functies te isoleren.
Op deze manier voorkom je duplicatie van code en bevorder je herbruikbaarheid en splitsbaarheid. Kortom, elke functie moet zich bezighouden met één duidelijk omschreven concept of actie binnen het grotere geheel van het programma, waardoor de code gemakkelijker te begrijpen, te onderhouden en te wijzigen is.
Buigen van de regels
Verder geeft Martin het boek het advies dat functies ofwel commando's (die iets doen) ofwel queries (die iets beantwoorden) moeten zijn, maar niet beide. Dit helpt bij het scheiden van verantwoordelijkheden en het bevorderen van duidelijkheid in de code.
Bij het bouwen van complexe systemen zoals UI's kan het soms nodig zijn om functies te hebben die meerdere taken uitvoeren, zoals het bijwerken van de gebruikersinterface en het ophalen van gegevens van de server. Dit kan resulteren in functies die zowel commando's als queries bevatten.
Het kan redelijk zijn om deze regel te buigen, vooral in situaties waarin het moeilijk is om strikt te voldoen aan het scheiden van commando's en queries zonder de leesbaarheid of de efficiëntie van de code in gevaar te brengen. Soms is pragmatisme belangrijk, vooral bij het werken aan snel itererende projecten of prototyping.
Het is echter belangrijk om in gedachten te houden dat het doel van deze regel is om de code begrijpelijk en onderhoudbaar te houden. Als het doorbreken van de regel leidt tot complexe, moeilijk te begrijpen code, kan het de moeite waard zijn om te heroverwegen en manieren te vinden om de codebasis te verbeteren.
Boolean vlagargumenten
Boolean vlagargumenten zijn een punt van discussie binnen de softwareontwikkelingsgemeenschap omdat ze suggereren dat een functie meer dan één ding doet, volgens Martin.
Het probleem hiermee is dat ze vaak niet duidelijk maken wat de intentie van de functie is. Door expliciete argumenten te gebruiken, zoals IS_SUITE of IS_NOT_SUITE, wordt de bedoeling van de functie duidelijker en verbetert de leesbaarheid en onderhoudbaarheid van de code.
Dit is van belang omdat het principe van single responsibility stelt dat een functie slechts één specifieke taak moet hebben. Wanneer een functie verschillende paden volgt op basis van een boolean vlagargument, kan dit aangeven dat de functie eigenlijk twee verschillende taken probeert uit te voeren, wat in strijd is met dit principe.
Bijvoorbeeld, als een functie een boolean vlagargument "isPremium" accepteert, en afhankelijk van de waarde premium of standaard e-mails verstuurt, dan heeft deze functie eigenlijk twee taken. In plaats daarvan is het beter om twee aparte functies te hebben: één voor het versturen van premium e-mails en één voor het versturen van standaard e-mails, waardoor elke functie zich bezighoudt met slechts één specifieke taak, wat de code begrijpelijker, onderhoudbaarder en flexibeler maakt.
"Don't Repeat Yourself" (DRY) discussie
Het idee van "Don't Repeat Yourself" (DRY) was lang een belangrijke regel in de softwareontwikkelingswereld. Het betekende dat we herhaling in code moesten vermijden omdat het problemen kon veroorzaken.
We wilden duplicatie verminderen door code samen te voegen en herbruikbare stukjes code te maken. Dat hield onze code netjes en efficiënt.
Maar nu begrijpen we meer dat een beetje herhaling niet altijd slecht is. Soms maakt het dingen juist duidelijker, vooral als het alternatief is om te veel abstracte concepten te gebruiken, wat de code ingewikkelder maakt.
We moeten een balans vinden tussen het verminderen van herhaling en het zorgen dat de code begrijpelijk blijft. Het belangrijkste doel is om code te schrijven die makkelijk te onderhouden is, zelfs als dat betekent dat er af en toe wat herhaling is.
Kleine functies
Het idee dat functies klein moeten zijn, is een veelgehoorde suggestie in de softwareontwikkelingswereld. Kleine functies zijn over het algemeen gemakkelijker te begrijpen, te onderhouden en te testen dan langere functies. Ze bevorderen ook de modulariteit van de code en maken het eenvoudiger om specifieke functionaliteit te isoleren en te hergebruiken.
Echter, zijn er situaties waarin het niet praktisch is om functies extreem klein te houden. Voorbeeld is van een functie die een complex type crashrapport weergeeft in een CLI-toepassing, hier kan het nodig zijn om meerdere regels code te gebruiken om de nodige logstatements te genereren en eventuele benodigde controles uit te voeren.
Conclusie
De kern van effectieve softwareontwikkeling ligt in het schrijven van code die gemakkelijk te begrijpen, te onderhouden en te wijzigen is. Praktijken zoals het Single Responsibility Principle, het scheiden van commando's en queries, en het verminderen van duplicatie vormen de basis van dit streven naar kwaliteit.
Het is van belang om conceptuele taken en verantwoordelijkheden te isoleren in aparte functies en deze te richten op een specifiek doel. Hierdoor wordt niet alleen duplicatie voorkomen, maar wordt ook de leesbaarheid en onderhoudbaarheid van de code verbeterd.
Hoewel flexibiliteit belangrijk is, blijft het ultieme doel altijd het produceren van code die duidelijk, begrijpelijk en betrouwbaar is. Hoewel sommige regels en principes in bepaalde situaties kunnen worden aangepast, is het cruciaal om het doel van clean code nooit uit het oog te verliezen: het leveren van hoogwaardige software die voldoet aan de behoeften van gebruikers en ontwikkelaars.