Clean code

Naamgeving variabelen en functies

- Functienamen zijn altijd werkwoorden;
- Namen van classes zijn altijd zelfstandige naamwoorde;
- Publieke functies hebben hebben kleine namen (die hebben een grote scope);
- Private functies mogen lange namen hebben (die hebben een kleine scope);
- Variabelen in een kleine scope mogen korte namen hebben;
- Variabelen in een grote scope mogen geen korte namen (afkortingen) hebben, grote namen zijn prima;
- Variabelen moeten beschrijvend zijn en uitspreekbaar;

Functies

- Hebben maximaal drie parameters. Meer dan drie parameters kunnen gebundeld worden in een object;
- Hebben geen bool als parameter. Als een functie een bool accepteert dan doet hij twee dingen en functies mogen altijd maar één ding doen. Dus mocht een functie een boolean nodig hebben, zijn dit twee functies;
- Zijn klein max 4-5 regels;
- In grote functies zitten zeer waarschijnlijk een of meerdere classes verborgen;
- Functies doen maar 1 ding. Hoe bereik je dit? Door 'extract till you drop'. Blijf net zo lang functies uit functies halen totdat het echt niet meer kan. Functies opereren altijd op één niveau / abstraction level.

Function structure

Stepdown principle

Dit principe betekent dat functies die bij elkaar horen ook in de code bij elkaar staan. Hierbij begin je met de public methode, met daaronder de private methods. Als een private method een andere private method aanroept, dan staat de aanroepende functie er onder. Op deze manier krijg je een bepaalde hierarchie waarbij de meest globale functies bovenaan staan en de meest gedetailleerde functies ondereen.
Bij meerdere publieke functies wordt dit principe herhaalt. De tweede public functie staat onder de laatste private method van de vorige publieke functie. 
Doel van deze opzet is zodat de code van boven naar beneden te lezen is en dat er geen backwards references zijn. 

Switch statements

Deze zijn vaak te vermijden door polymorfisme toe te passen.

Tell, don't ask

Vertel een object wat te doen. Het is niet de bedoeling dat je eerst informatie van het object verzamelt en dat dan vervolgens bepaald wordt wat te doen. Het object zelf heeft immers al deze informatie al. Laat het object zelf deze informatie verzamelen.

Command Query Separation

Een functie kan een command of een query zijn. Als een functie een command is, dan veranderd hij de state van de applicatie, maar geeft nooit resultaten terug. De return value van een command is dus altijd void. 
Als een functie een query is, dan retourneert hij data, maar veranderd niet de staat van de applicatie.

Temporal Coupling

Dit betekent dat functies in een bepaalde volgorde aangeroepen moeten worden. Een bekend voorbeeld hiervan is 'Open()' en 'Close()'. Open en Close zijn duidelijke en herkenbare situaties, maar vaak zijn ze niet zo duidelijk. Het nadeel is dat het systeem in een onstabiele state komt en dat zorgt voor meer foutgevoeligheid. Het beste is dus om dit soort structuren te voorkomen. In het geval van Open en Close is dit te verhelpen door een command (object) mee te geven aan Open. Open opent vervolgens datgeen wat die moet openen, voert vervolgens het comando (object) uit en roept vervolgens Close aan. Dit zorgt er ook voor dat het systeem in dezelfde state blijft als voordat de Open werd aangeroepen. Deze techniek wordt 'Passing a block' genoemd.

Law of Demeter

De Law of Demeter stelt dat functies alleen mogen worden aangeroepen als het object
- meegegeven is als een parameter;
- lokaal aangemaakt is;
- een instance variabele is van de class van de methode;
- een global is.

Er mogen geen functies worden aangeroepen op een object als dat object geretourneerd is door een vorige functie-aanroep. Hiermee voorkom je 'train wrecking': o.getX().getY().getZ(). In dit voorbeeldje wordt getY() aangeroepen op een object dat wordt geretourneerd door een vorige functie-aanroep. Dit is dus niet toegestaan.

Exception handling

Het is beter om exceptions op te gooien dan om return values te checken op geldigheid.

Classes en data structures

Classes kennen enkel public methods en mogen geen properties hebben. Als een class properties heeft, dan geeft de class implementatiedetails bloot. Als een class toch implementatiedetails bloot moet geven, dan zo abstract mogelijk. Stel dat je een class 'Car' heb. Dan zou je een property 'GallonsOfGassoline' kunnen hebben. Vervolgens is er een wens voor een electrische auto, dus komt er een nieuwe class 'ElectricCar' die erft van'Car'. Probleem is nu alleen dat een electrische auto niet op gas rijd, Beter zou dus zijn om 'GallonsOfGas' te hernoemen naar 'Fual'.Het doel van een class is om de buitenwereld zo 'dom' mogelijk te houden. 

Een data structure is het tegenovergestelde van een class. Een data structure kent alleen maar properties, maar geen functies. 

Reacties

Populaire posts van deze blog

[SQL Server] varchar vs nvarchar

MS Sql 70-461: Chapter 5

[C#] Class serialiseren en deserialiseren