"Jij bent OK - maar je werk, dat is maar de vraag."

Over softwaretesten en inspecties.

Waarom vertrouwen wij wel de loodgieter en niet de software-bouwer? Waarom zijn testen een verplicht ingebouwd en duur onderdeel van de aanpak van softwareontwikkeling? Kan dit anders? Moet dit anders?

Zoals iedere maker van software zal bevestigen, is het schrijven van programma's niet mogelijk zonder testen, veel, heel veel testen. Dit soort testen gebeurt voor een groot deel tijdens de ontwikkeling zelf. Na zeg maximaal een half A4-tje aan programmeertekst (code) te hebben geschreven, gaat de programmeur wat schuiven op zijn stoel. Hij voelt zich ongemakkelijk. Voordat hij verder gaat, is het nodig uit te proberen of de net geschreven code werkt zoals was bedacht. Dus die wordt vertaald in machinetaal (gecompileerd) en de computer mag er aan proeven. De uitkomsten laten aan de programmeur zien of het loopt zoals verwacht. Gerustgesteld kan hij verder, dan wel terug voor verbeteringen.

Dit kort cyclische karakter van programmeerwerk (schrijven, compileren, testen, eventueel aanpassen, compileren, testen, schrijven, ...) is deels afhankelijk van de programmeertaal. Sommige programmeertalen kennen korte statements met veel betekenis voor de computer. Hier zal de programmeur al sneller willen testen. Andere talen kennen een uitgebreidere formulering, met een syntax die lijkt op een natuurlijke taal. In het algemeen geldt: hoe begrijpelijker de taal, hoe meer code wordt geschreven voordat de programmeur zich oncomfortabel gaat voelen en zal gaan testen.

Maar het resultaat is hetzelfde: voor een serieus softwareprogramma dat nieuw ontwikkeld wordt en dus niet gebaseerd is op bestaande, geteste code, wordt deze cyclus niet 10 of 20 keer, maar honderden keren, wellicht een paar duizend keer  herhaald.

Testen of uitproberen? De code is daarmee goed getest. Toch?

Dat valt tegen. Softwarefouten (bugs) zijn zelfs in zeer kostbare, commerciële softwarepakketten aanwezig. Elke bug die optreedt kan potentieel grote schade aanrichten, dus er zijn genoeg belangen om die te vermijden. Blijkbaar is zelfs duizend keer testen niet genoeg.

Een verklaring hiervoor is dat de programmeur alleen kleine stukjes van het programma per keer kan testen. De onderlinge aansluiting en samenwerking van al die stukjes is daarmee niet gegarandeerd. En daar zit vaak de complexiteit.

Een andere verklaring is dat de programmeur de software eigenlijk uitprobeert, kijkt of 'hij het doet'. Testen daarentegen is veel meer dan dat: naast uitproberen, wordt de code ook blootgesteld aan allerlei omstandigheden waar de programmeur helemaal geen rekening mee had kunnen houden. Bijvoorbeeld de bestendigheid van de software tegen aanvallen van buitenaf. Dit soort testen levert vaak de meeste potentiële bugs op.

Externe inspecties: een goed idee?

Dus extra testen van software is nodig. Alleen: hoe organiseren we dat? Als een soort Inspectie?

Recente gebeurtenissen in de gezondheidszorg leren ons dat ook een extern inspectie-instituut niet helemaal de oplossing is. Dit heeft te maken volgens sommigen met de tweeledige taak. Enerzijds houdt men toezicht op naleving, en daarnaast beantwoordt men bij disputen de schuldvraag. Echt onafhankelijk kan men dan niet zijn. De oplossing lijkt eenvoudig: splits deze twee en het probleem is opgelost.

Grenzen aan de formaliteit Een punt waar bij deze oplossing aan wordt voorbij gegaan is Gödels dilemma. Kurt Gödel bewees dat elk formeel systeem per definitie zijn beperkingen heeft.

The smartest guys on the field

Neem wiskunde als voorbeeld: hoe solide dit ook overkomt voor de meeste mensen, er blijken met algebra vergelijkingen te bedenken te zijn, die niet met dezelfde algebra kunnen worden opgelost.

Een beetje tegennatuurlijk voelt dit wel.  Het betekent in wezen dat wij niet in staat  zijn om met onze bedachte systemen perfectie te bereiken en dat is toch vaak een uitgangspunt in ons denken.

Wie maakt hier er nog chocolade van? Ook organisatie-inrichting ontsnapt niet aan deze regel. We produceren iets of we leveren een dienst. Iemand controleert dat. Maar wie controleert haar? Wie bepaalt of de regels die moeten zorgen dat de Inspectie zich houdt aan zijn taak, goed worden nageleefd? En wie controleert die Inspectie op het Naleven van de Regels door Inspecties?

Voor we het weten zitten we in een Droste-blik, een recursief probleem: controle is nodig, testen is nodig, maar wie controleert de controleurs, wie test de testers? En wie test de methode die wordt toegepast?

Dit alles vormt ook een wezenlijk vraagstuk bij softwareontwikkeling. Pogingen om code te maken die inherent geen bugs meer bevat, bijvoorbeeld door formele wiskunde te gebruiken, hebben in de afgelopen jaren niet opgeleverd wat de belofte was. Wel is veel gedaan aan hergebruik van al beproefde software, aan bepaalde ontwerpmethoden die het effect van bugs verkleinen, en aan specifieke opleiding en training van programmeurs. Hiermee kan een aantal van de meest voorkomende 'standaard' fouten in software worden voorkomen.

Toch, foutloos programmeren is nog niet mogelijk, en vermoedelijk ook niet haalbaar.

Dat een loodgieter in de praktijk overigens veel minder (externe) controle van zijn werk nodig heeft wordt veroorzaakt door aspecten als herhaalbaarheid, standaardisatie van componenten en een geringere oplossingsruimte.

Oftewel, de variatie van wat door een loodgieter geleverd wordt en het gebruik van voorgedefinieerde onderdelen maakt de kans op een water of gasbug veel kleiner - gelukkig maar.

Boeiend, en wat nu? Betekent dat we de programmeur dan maar helemaal moeten ontslaan van zijn testwerk? Of juist voor alles verantwoordelijk moeten maken? Waar leidt dit alles heen, als meer formele controles alleen maar meer vragen oproepen?

Een oplossingsrichting komt uit een andere hoek: Kijk naar professionele organisaties en naar risicomanagement.

Als je die twee combineert dan ontstaat een hybride model waar in elke professional in de keten van softwareontwikkeling zijn eigen verantwoordelijkheid voor kwaliteit heeft en invult. Het totaalrisico van de uitkomst (te beschouwen als het uiteindelijk aantal bugs) is dan minimaal.

Dit betekent in de praktijk dat we de programmeur (en iedere andere creative) vooral zijn eigen testen moeten laten doen. Laat hem vooral overtuigd zijn dat het programma technisch werkt. De samenhang en werking van de losse onderdelen kan door de volgende functionaris binnen de keten van softwareontwikkeling worden gedaan, bijvoorbeeld de systeemintegrator of applicatiearchitect.

Vaak wordt juist deze fase uitbesteed aan een tester of testteam, maar hier zou men voorzichtig mee moeten zijn. Dit zijn in wezen externe controleurs, natuurlijk vakmensen op hun gebied, maar niet verantwoordelijk voor de bouw van het product.  En dat is toch van belang, zoals een chefkok zijn eigen culinaire resultaat zal moeten proeven.

Deze richting is overigens wel een breuk met de zogenaamde software-factories, die uitgaan van een soort lopende bandsysteem, met een grote finale test aan het einde. Softwareontwikkeling kan beter gebeuren in korte, netjes afgesloten fasen, die elk bewijsbaar goede producten hebben opgeleverd.

Zoals Kurt Gödel aantoonde: formaliseren heeft ook zo z'n beperkingen. Laten we daar gebruik van maken door het verstandig, dus terughoudend, inzetten van externe controles.

-----------------------------------------------------------------------------------------------------------------