It’s a trap!

14 augustus 2012 13:31 Lennaert van der Linden Agile, Algemeen, Testen

Een paar maanden terug bezocht ik een Agile Holland meetup waar Jamie Dobson een hands-on sessie verzorgde genaamd The Butterfly Flaps Its Wings. Een erg leuke en interessante sessie waarvan ik mijn ervaringen wil delen.

Tijdens de sessie introduceerde Jamie de Enigma encryptiemachine. Dit apparaat is onder andere tijdens de tweede wereld oorlog gebruikt door het Duitse leger om berichten te versleutelen, zodat deze niet door derden gelezen konden worden. De machine versleuteld een bericht tot een reeks nietszeggende tekens, bijvoorbeeld: “HELLO WORLD” wordt “PJJCM DHDQU”.

Enigma machine

De machine kent drie belangrijke onderdelen: de rotors, de reflector en het display. De rotors zetten volgens een vast patroon het ene teken om in het andere. Omdat de rotors gedraaid worden, verandert de omwisseling. De reflector stuurt het signaal terug over de rotors zodat tekens dubbel omgewisseld worden. Het display toont de huidige stand van de rotors.

De opdracht was om in paren test-first een Enigma machine te implementeren. Geen eenvoudige taak, het kostte mij minstens de helft van de sessie om de werking van de machine een beetje te begrijpen. We hadden een vrije keuze in programmeertaal en voor mij werd het PHP, waar ik snel in kan ontwikkelen en waar de IDE (Netbeans) uitstekende ondersteuning biedt voor het uitvoeren van unit tests. Maar dat was van minder belang. Belangrijker was hoe we opdracht zouden aanpakken, en dat bleek lastig. Er zijn namelijk twee manieren om dit aan te pakken:

  • Bottom up: de rotors, de reflector en het display als aparte objecten ontwikkelen en testen. Daarna samenvoegen in een overkoepelende enigma machine, waarin deze worden geconfigureerd.
  • Top down: uitgaan van de enigma machine en de vraag om een tekenreeks te versleutelen. Hieruit volgen de aanroepen naar componenten als rotors en reflectors.

Gedurende de sessie wisselde ik van aanpak. We begonnen vanuit de machine met een heel eenvoudige test met alleen een reflector.

function testEnigmaWithReflectorOnly() {
  $reflector = $this->getMock('Reflector');
  $reflector->expects($this->once())->method('lookup')
    ->with('P')->will($this->returnValue('Q'));

  $enigma = new Enigma($reflector);
  $this->assertEquals('Q', $enigma->encrypt('P'));
}

De rotor was een ander verhaal. We kwamen niet tot een goede test, omdat we de rotor niet begrepen. We hadden een papieren model gekregen, maar pas na extra uitleg van Jamie werd de werking ons een beetje duidelijk. Een van de observaties die we maakten was dat het systeem index-gebaseerd was en niet op letters. Dit leidde tot de keuze om ons op de rotor en het display te richten. We schreven een paar unit tests op basis van het papieren model en implementeerden de klassen.

Toen we weer verder gingen met de Enigma-klasse, werd duidelijk dat de functies die we gekozen hadden (het gedrag van de rotor) niet aansloten op wat we nodig hadden. We waren bottom-up aan het werken en bedachten een rotor waarvan we dachten dat die goed zou passen in de implementatie van onze Enigma-machine. Pas toen de rotor af was kwamen we erachter dat dat niet zo was. Het ontwikkelen van de rotor had ons veel geleerd over hoe een rotor werkt, maar geen directe waarde geleverd voor het opleveren van een Enigma machine. Alsof je een auto bouwt door de losse onderdelen apart te ontwikkelen (chassis, stuur, motor, wielen) en bij assemblage erachter komt dat de onderdelen niet op elkaar aansluiten.

It’s a trap!

Mijn conclusie tijdens de rondgang was dan ook “It’s a trap!”. Doordat we het systeem uitgelegd kregen in fysieke termen (rotor, reflector en display), werd ook ons domein model hierop ingesteld. De uitleg van de fysieke onderdelen leidde ons naar een bottom-up aanpak. Maar is geen reden om aan te nemen dat de fysieke compositie van de machine ook een goede indeling van het domeinmodel van de software vormt. Uiteindelijk ging het om de implementatie van een algoritme en niet om een simulator.

Een top-down aanpak, waarbij wordt uitgegaan van het gewenste gedrag past beter. Hieruit volgt proefondervindelijk wat aan implementatie nodig is, in plaats van proberen handige losse onderdelen te maken en ervan uit te gaan dat deze wel gaan passen.

Een ander nadeel van van de bottom-up aanpak is dat we niet kunnen spreken van incrementele ontwikkeling. Toen we uitgingen van de Enigma-machine hadden we al snel een werkend systeem, ook al was de versleuteling zonder rotors erg simpel. De functionaliteit wordt continu uitgebreid, waarbij het systeem steeds blijft werken. Dus snel werkend resultaat en continue verbetering.

Dit in tegenstelling tot de aanpak waarbij eerst de rotor, reflector en display apart worden uitgewerkt. Pas als alle componenten gereed zijn kan het systeem worden geassembleerd. En alleen een geassembleerd systeem biedt meerwaarde, want met een rotor kan geen bericht worden versleuteld. Het duurt dus langer voor een ROI en omdat het systeem pas op het einde wordt opgeleverd is er ook minder te leren van voortschrijdend inzicht. Daarnaast blijven integratiekosten lang uit zicht omdat integratie pas laat plaatsvindt.

Het was weer een leerzame sessie, die mij herinnerde om te blijven streven om snel en continu waardevolle software op te leveren.

Be Sociable, Share!

Reageer


acht + 1 =

RSS feed for comments on this post · TrackBack URI