Programmeren is een vak, al lijkt dat standpunt steeds moeilijker te verdedigen. Programmeertalen hebben namelijk een ontwikkeling doorgemaakt van basaal, platform- en besturingssysteemgebonden naar intuïtief, niet-platformgebonden. Moderne talen bezitten ‘bruggen’ tussen de taal en de omgeving, en andere kant-en-klare functies. Bijna iedereen die aanvoelt hoe een functie in elkaar zit, kan er een programma voor bouwen. Maar net zo min als iedereen die een hamer vasthoudt een vakkundig timmerman is, is nu iedereen met een beetje ict-kennis een programmeur geworden.
Programma’s mogen dan in een mum van tijd geschreven zijn, er is ook een keerzijde: de kwaliteit ervan is merkbaar achteruit gegaan. Dus ontstaat de roep om vakkundige programmeurs die foutvrije codes kunnen schrijven. Foutvrij? Jazeker, dankzij acp en siblr!
Gezien eenieders ervaringen van de afgelopen jaren lijkt het misschien onmogelijk om foutvrije applicaties te bouwen. ‘Application control programming’ (acp) biedt echter wel degelijk de mogelijkheid om deze schijnbare utopie te realiseren. Acp levert een applicatieontwerp voor elke objectgeoriënteerde omgeving die volledige controle geeft over transacties. Een waardevolle aanvulling op acp is ‘slim implementation of business logic requirements’ (siblr), wat voorziet in een sterk vereenvoudigd functieverloop. Deze combinatie maakt foutvrij programmeren mogelijk.
Problematisch
Acp is mogelijk dankzij het bestaan van objecten: bijna alle applicaties bestaan uit functies die elkaar aanroepen en waardes doorgeven. In traditionele omgevingen is dit altijd problematisch geweest, aangezien functies een vrijwel onbeperkte hoeveelheid parameters kunnen krijgen, maar er slechts één terug kunnen geven. Dit is te vergelijken met het stellen van de vraag ‘Hoe gaat het?’ terwijl je weet dat je maar twee mogelijke antwoorden kunt krijgen: ‘Goed’ of ‘Slecht’.
Met referentie (het doorgeven van geheugenadressen van variabelen in plaats van de variabelen zelf) werd het mogelijk dit probleem op te lossen: een invoervariabele werd opeens ook een uitvoervariabele, doordat de aangeroepen functie bij het wijzigen van die variabele, door de referentie ernaar, ook de waarde van de variabele zelf veranderde. Referentie werd geïntroduceerd door de programmeertaal C.
Objecten hebben een prettige eigenschap: zij worden ook via referentie doorgegeven, maar zijn feitelijk een verzameling van variabelen: een object kan ‘krimpen’ of ‘uitzetten’ al naar gelang de behoefte. Een eigenschap (‘object property’) aan een object toekennen of eraf halen is net zo eenvoudig als een simpele variabele wijzigen. Het is alsof een nieuwe referentievariabele ontstaat in de aanroepende functie!
Acp maakt dankbaar gebruik van deze eigenschap: alleen objecten worden doorgegeven van de ene functie, en het liefst slechts één object. Dit object wordt aangemaakt aan het begin van een transactie en bevat alle werkelijke globale variabelen voor de hele transactie – dat wil zeggen: globaal gezien de functionaliteit van de transactie.
Functionaliteit en techniek kunnen zo worden uitgebreid door in willekeurig welke functie eigenschappen aan het object toe te kennen en op een compleet andere plek te hergebruiken.
Foutafhandeling
Hierdoor behoudt een transactie zijn compleetheid. Op elk punt van de transactie bevat het object waarden die de hele transactie beslaan van begin tot (dat) eind: dit maakt het mogelijk om ’terug te gaan’ en gebruikersvriendelijke meldingen samen te stellen. Daarnaast verschaft het de totale informatie voor foutafhandeling: alle operationele waardes van variabelen zijn bekend.
Om in het geval van technische uitzonderingen ‘error logging’ te perfectioneren, moeten alle variabelen die op dat moment lokaal zijn (slechts bekend in de functie zelf) ook als eigenschappen aan het object worden toegekend, waardoor alle operationele waardes van variabelen bekend zijn.
Dit object kan worden weggeschreven of ‘gedumpt’ in een centrale plek (bijvoorbeeld databank of centraal bestand), maar dat is niets nieuws: geforceerde dumps maken het welbekende ‘debuggen’ (stapje voor stapje door een programma lopen om te kijken wat het doet en wat de waarde van de globale en lokale variabelen is) overbodig: alle globale en lokale waardes zijn immers al bekend.
Siblr
‘Slim implementation of business logic requirements’ (siblr) is enerzijds ontworpen om de complexe ‘business logic requirements’ waaraan soms tegemoet gekomen moet worden, te vereenvoudigen. En anderzijds om de leesbaarheid van programma’s te optimaliseren: het is daarom perfect voor acp.
In figuur 1 ziet u een voorbeeld van een klassiek functieverloop. Siblr zorgt ervoor dat programma’s ‘in lijn lopen’: de unieke eigenschap is het feit dat niet wordt gecontroleerd of aan ‘business logic requirements’ wordt voldaan, maar dat er vanuit wordt gegaan dat dit juist n�et zo is: het ‘if’-statement wordt omgekeerd. Als er niet aan wordt voldaan, wordt het programma afgebroken en als dit wél het geval had moeten zijn, kan een foutboodschap worden samengesteld.
Het afbreken van een programma sluit niet uit dat ‘if’-statements op elkaar moeten worden gestapeld, maar de manier waarop dit gebeurt, doet dat wél. Door een ‘break’-opdracht te geven, wordt een zogenaamde ‘loop’ verlaten die de hoofdcode van het desbetreffende programma omsluit. Deze ‘loop’ heeft geen andere functionaliteit dan het bieden van de mogelijkheid om dit te doen: het is een zogenaamde ‘dummy do-while loop’, die slechts één keer wordt doorlopen. De ‘while’-conditie voldoet namelijk nooit, waardoor de ‘loop’ aan het eind automatisch wordt verlaten.
In figuur 2 vindt u een voorbeeld van een siblr-ontwerp. Het omgekeerde ‘if-statement’ wordt dus nooit gevolgd door een ‘else’-statement: als aan het omgekeerde ‘if’-statement wordt voldaan (dat wil dus zeggen dat niet wordt voldaan aan het ‘if’-statement) is er mogelijk een fout opgetreden die kan worden vertaald naar een foutboodschap. De ‘break’-opdracht wordt gegeven, de ‘loop’ wordt verlaten en de hoofdlijn van het programma houdt simpelweg op. De uitvoering gaat daarna door, waardoor een mogelijkheid wordt geboden om tijdelijke bestanden op te ruimen, geheugen vrij te geven, of een database-transactie terug te draaien of te voltooien.
Als n�et aan het omgekeerde ‘if’-statement wordt voldaan (dat wil dus zeggen dat wordt voldaan aan het eigenlijke ‘if’-statement) wordt gewoon de volgende regel code uitgevoerd, waardoor impliciet het ‘else’-statement wordt uitgevoerd (dat er echter niet is). Op deze manier kunnen talloze controles worden uitgevoerd, zonder dat de leesbaarheid van een programma wordt aangetast: de code blijft ‘in lijn’ met de voorgaande regels.
Code wordt open boek…
Siblr bewerkstelligt eenvoudig een mechanisme dat een einde maakt aan het op-en-neer-springen binnen een functie, het aan- en uitzetten van switches die op andere plaatsen weer worden gecontroleerd en aan- of uitgezet worden. Dat gedrag bemoeilijkt de toegankelijkheid van programma’s bij nieuwbouw en onderhoud. Bijna elk functioneel of technisch ontwerp kan zo worden ‘platgeslagen’ en vertaald naar een paar duidelijk leesbare controles.
Bovendien wordt code zo een open boek: het leest van boven naar beneden, zonder voortdurend in te springen.
De clou van acp en siblr ligt in het feit dat elke functie, module, applicatie of systeem een waarde teruggeeft, en dat er vanuit wordt gegaan dat die waarde altijd ‘goed’ is. Hiervoor bestaat een systeembrede globale variabele (die bij voorkeur de naam ‘output’ heeft) met een bepaalde waarde. Deze waarde kan in principe van alles zijn, maar heeft liefst een positieve connotatie, bijvoorbeeld ‘Succes!’.
Elke transactie moet beginnen met het initialiseren van de uitvoervariabele met deze waarde. Alle onderliggende functies moeten hetzelfde doen. Deze waarde kan gedurende het verloop van een programma veranderen, doordat er een functionele of technische fout is opgetreden.
Aangezien alle componenten van een systeem op een gegeven moment tegen systeemgrenzen kunnen oplopen, moet deze waarde complete informatie verschaffen over de aard van de fout: het type fout moet samengaan met de foutboodschap zelf. Op deze manier worden alle functies verondersteld dezelfde waarde terug te geven, wat inhoudt dat alle functies aangeroepen kunnen (en moeten) worden via een systeembrede functie die de uitvoer van deze functies controleert. Als deze gelijk is aan de globale variabele ‘output’, dan is de functie succesvol verlopen! Zo niet, dan moet de waarde gecontroleerd worden voor type en inhoud van de fout.
Als er een fout is opgetreden, dan moet de controlefunctie de fout in zijn geheel als eigenschap toekennen aan de variabele ‘output’ van het object, en het klassieke ’true’ of ‘false’ teruggeven om aan te geven dat die fout is opgetreden. De aanroepende functie kan dan besluiten om al of niet door te gaan met de transactie. Het is van groot belang dat aangeroepen functies slechts een waarde teruggeven en de aanroepende functie laten beslissen over het verloop van de transactie: het wijzigen van transactiecontrolewaardes ‘bottom-up’ corrumpeert elke transactie!
Aan het eind van elke transactie controleert de transactie zelf haar eigen ‘output’-variabele, die inmiddels veranderd kan zijn, via een systeembrede controle die foutafhandeling, foutopslag en gebruikersinteractie voor zijn rekening neemt.
Blauwdruk
Als de transactie zelf een waarde terug moet geven (indien hij bijvoorbeeld zelf aangeroepen is), is dit uiteraard weer de variabele ‘output’. Zo kan elke transactie worden opgebroken en ergens anders weer worden voortgezet, terwijl de status te allen tijde integer blijft. De component die de transactie heeft aangeroepen, gebruikt natuurlijk ook weer de systeembrede controlefunctie om allereerst de variabele ‘output’ te controleren…
Wat nu nog mist is een blauwdruk van de applicatie als er géén fouten optreden: dit kan worden afgedwongen door foutafhandeling te forceren (‘dumping’) op het eind van elke transactie. Deze ‘dumping’ kan gefaciliteerd worden door een – uiteraard systeembrede en globale – ‘debug’-switch te controleren in de foutafhandeling, waardoor een dump wordt geforceerd: hierdoor eindigt elke transactie met een complete dump van het transactieobject.
Zoiets komt van pas tijdens ontwikkeling, maar kan ook worden afgedwongen tijdens productie: zolang de ‘output’-variabele van de transactie niet wordt beïnvloed door de dump, loopt het systeem gewoon door.
Minstens zo snel
Siblr en acp samen maken een applicatie perfect: siblr verlaagt de drempel van een applicatie door de leesbaarheid van programma’s aanzienlijk te verbeteren en maakt gebruik van acp: elke fout die optreedt op enige plek kan op elk moment leiden tot een onmiddellijke beëindiging van de transactie op een nette en gecontroleerde manier. Dit maakt dat applicaties minstens zo snel worden gerealiseerd als applicaties die niet met siblr en acp zijn gerealiseerd. Functies hoeven niet langer complexe en moeilijk te ontwarren ‘if’-statements, ‘goto’-labels of ‘gosubs’ te bevatten, evenmin als een veelvoud aan switches of plaatselijke foutafhandeling. Het testen van een applicatie wordt kinderspel dankzij een dump van de complete transactie die wordt meegestuurd bij elke fout.
Interactie met de gebruiker is gegarandeerd gebruikersvriendelijk, dankzij het feit dat op elk moment de complete historie van de transactie toegankelijk is. De exacte reden van een fout kan vertaald worden naar een procesgerichte melding. Er is daarom geen reden tot paniek als er een onverwachte fout optreedt tijdens productie. Immers, een complete blauwdruk van het systeem ligt dan al klaar, met daarin de waarden van alle lokale en globale variabelen die op dat moment actief waren. Reproductie van dezelfde fout in bijvoorbeeld een ‘bugfix’-omgeving is dan ook niet meer nodig.
Het kunnen doorgronden en gebruiken van acp en siblr vereist echter wel specialistische kennis, die niet bij de eerste de beste programmeur aanwezig is. Door degenen met programmeergevoel is het wel te leren. Zij kunnen op deze manier voortaan foutvrije applicaties maken.< BR>
Martijn Linssen, senior consultant Cap Gemini Ernst & Young