De vragen die zijn artikel ‘Foutvrij programmeren’ (Computable, 12 maart 2004) heeft opgeroepen, hoopt Martijn Linssen hier te beantwoorden.
De genoemde wijzigingen op het ‘if-statement’ zijn voor mij onder andere aanleiding om nogmaals te reageren: er is een fundamentele wanverhouding tussen het optimaliseren van code vanuit programmeeroogpunt en gebruiksvriendelijkheid van foutmeldingen.
Als niet aan de voorgestelde conditie wordt voldaan, krijgen we het volgende:
IF A AND B AND C
THEN DO D
ELSE ERROR: NOT A OR NOT B OR NOT C (ER GING IETS MIS)
Het is op deze wijze niet af te leiden wat de fout is. Het is alsof je aan het pinnen bent en op de display verschijnt ‘kaart ongeldig of pin onjuist of onvoldoende saldo’. Het is dus juist noodzakelijk om die drie de condities op te splitsen:
IF KAART LEESBAAR
THEN IF PIN JUIST
THEN IF VOLDOENDE SALDO
THEN GEEF GELD
ELSE ERROR: ONVOLDOENDE SALDO
ELSE ERROR: PIN ONJUIST
ELSE ERROR: KAART ONLEESBAAR
Dit soort code heeft als nadeel dat het vrij onleesbaar wordt. Niet alleen verschuift het steeds meer naar rechts, ook de afstand tussen de ‘if’ en de ‘else’ wordt steeds groter, waardoor de samenhang tussen de vereiste en de foutmelding onduidelijker wordt. Door gebruik te maken van siblr is er helemaal geen else-tak meer nodig, en krijg je het volgende:
DO
IF NOT KAART LEESBAAR
THEN ERROR: KAART ONLEESBAAR
BREAK
IF NOT PIN JUIST
THEN ERROR: PIN ONJUIST
BREAK
IF NOT VOLDOENDE SALDO
THEN ERROR: ONVOLDOENDE SALDO
BREAK
GEEF GELD
WHILE FALSE
Op deze wijze maakt siblr het mogelijk om stap voor stap door een proces te lopen en dat op elk gewenst moment met een heldere foutboodschap richting de gebruiker af te breken, terwijl de leesbaarheid van code optimaal blijft.
Als er een fout optreedt, wordt deze doorgegeven naar de aanroepende functie of module. Op dat moment is het wenselijk om zoveel mogelijk achtergrondinformatie te krijgen: welke functies zijn al aangeroepen, wat was de invoer daarvoor, de uitvoer daarvan enzovoort. Het in de context kunnen plaatsen van een fout helpt de ontwikkelaar om de fout te kunnen isoleren, reproduceren, en oplossen.
Anticiperen
Een module geeft invoer door aan functies en krijgt er uitvoer van terug. Deze (invoer en) uitvoer kan (her)gebruikt worden om andere functies aan te roepen. Alle invoer en uitvoer van functies bevindt zich weliswaar in de module, maar niet op één plek in die module. Door nu alle in- en uitvoer van en naar functies te groeperen in één object, wordt dit probleem opgelost: dit ene object bevat dan de complete context van de in- en uitvoer van alle aangeroepen functies binnen een module op het moment dat een fout optrad.
Als er een uitzondering optreedt in een functie, kan de complete context van die functie overgeheveld worden door de lokale variabelen (en de exception zelf) ook aan het acp-object door te geven. Op deze wijze verschaft acp-achtergrondinformatie over elke fout: onder welke omstandigheden trad hij op; wie, wat, waar, wanneer? Het ‘waarom’ is dan meestal snel gevonden.
Acp faciliteert het vergaren van context die waardevol is als er een fout optreedt. Siblr stuurt de ontwikkelaar om te anticiperen op fouten en zinvolle foutmeldingen te maken. Samen zorgen zij bovendien voor een gecontroleerd afbreken van het proces. Ik ben zo’n twee jaar geleden hiermee begonnen, en het heeft zich geleidelijk ontwikkeld tot wat ik nu acp en siblr noem. Sinds een klein jaar beschouw ik het als volwassen. Daarom wil ik deze kennis delen met andere ontwikkelaars, ook buiten mijn eigen bedrijf. Ik denk dat het zoveel mogelijk voorkomen, correct afhandelen en snel oplossen van fouten een waardevolle bijdrage kan leveren aan ons vakgebied.< BR>
Martijn Linssen, senior consultant Cap Gemini Ernst & Young