zaterdag 15 januari 2011

Code verbeteringen, minder bugs!

Ik wil eigenlijk een reeks blogs maken over het verbeteren van je code om zo minder bugs te laten ontstaan.
Deze reeks van blogs zullen gaan over het gebruik van design patterns en over het aantonen dat een bepaalde manier van coderen beter te gebruiken is.

Deze eerste gaat over het schrijven van functies...

Er zijn een aantal factoren waar je rekening mee moet houden wanneer je een functie codeert.

1. Geef de functie een goede beschrijvende naam.
2. Een functie is verantwoordelijk voor 1 ding.
3. Houdt de functie zo kort mogelijk qua aantal regels; geen 50 regels code bijvoorbeeeld.
4. Beperk het aantal parameters tot maximaal 2 a 3.
5. Wees consequent in de opzet van je code in de functies.

Door de juiste naam te gebruiken voor de functie weet de persoon die het leest waar het om gaat zonder direct de inhoud te weten. Indien je code verandert controleer dan of de functienaam nog klopt bijvoorbeeld.

Wanneer de body van de methode te lang wordt, dan is de kans groot dat de methode ook verantwoordelijk is voor meerdere dingen, het vraagt iets op, schrijft iets weg en verandert wat eigenschappen van de klasse bijvoorbeeld. Ik kom het vaak tegen.
Zo'n functie is dan moeilijk te testen door de afhankelijkheid die je hebt met andere delen van je code.
Voor het aantal parameters geldt eigenlijk hetzelfde, hoe meer parameters des te groter is de kans dat de inhoud van de functie te complex wordt. Denk aan het aantal if of switch statements wat hierbij ontstaat. Vooral variabelen die elkaar uitsluiten zijn gevaarlijk.
Regelmatig kom je tegen dat er een functie is waarbij je ziet dat er 2 integers worden doorgegeven en er wordt gecontroleerd of 1 van deze 2 een waarde groter heeft dan 0.
Voorbeeld:
function void Foo(int i, int j)
{
 if (i > 0 && j > 0)
 {
  if (i >0)
  {
   ...//1
  }
  else if (j > 0)
  {
   ...//2
  }
 }
 else
 {
  ...//3
 }
}

Als lezer van de code moet je dus sowieso al 3 scenario's controleren/testen om te zien wat deze functie doet. Bovendien zul je sommige mensen horen zeggen dat er zelfs bij scenario 3 nog weer 2 controles zullen zijn of een ontwikkelaar breidt scenario 1 of 2 zelfs uit indien er een bug is geconstateerd. Al met al dus niet de juist opzet naar mijn mening.

Bij het schrijven van de functie wil je code uitvoeren indien de parameters binnen het juist bereik vallen.
Ik hanteer altijd de volgende codestijl in mijn functie:

function Foo(object param1, object param2)
{
1. Check inkomende parameters op juiste waarde
if (param1 == null)
throw new FooException("param1 is null, goede omschrijving");
if (param2 == null)
throw new FooException("param2 is null, goede omschrijving")
2. doe functionele controles
if (param1.Date> param2.Date) // voorbeeld...
throw new FooException("einddatum ligt voor startdatum")

3. voer normale code uit in goed scenario
...
}

Met dit voorbeeld dwing ik voor mezelf af dat ik op consequente wijze de inhoud van mijn functies schrijf.