Mark van Venrooij

Mark van Venrooij's blog

Tag: TDD (page 2 of 3)

Aanbevolen links

2008-02-10 Today's recommended

Today's recommended by henning, on Flickr

Een week of wat geleden heb ik het idee opgevat om op deze blog aanbevolen links aan de kolom rechts toe te voegen. De blogroll die er nu staat is nogal statisch en ik wil dit veranderen met een klein aantal links die regelmatig veranderen. Probleem is dan wel dat het nogal wat onderhoud vergt om deze interessante links regelmatig te vernieuwen. Zelf verwacht ik daar niet zo goed in te zijn. Het idee zit nu al een tijdje in mijn hoofd. Afgelopen weekend kreeg ik een gaaf idee dat ik wel wil proberen. Eigenlijk ben ik helemaal niet zo slecht in interessante links bijhouden. Via Twitter (re)tweet ik regelmatig links die (naar mijn mening) ook interessant kunnen zijn voor anderen. Als ik die nu op mijn blog kan weergeven ben ik klaar.

De opdracht is dus: verzamel uit je tweets de links die je ge(re)tweet hebt en zet ze op je website. Twitter heeft een mooie API die dit mogelijk maakt. En via @MMz_ begreep ik dat er een java implementatie van de API is: Twitter4j. Na bestudering van de Twitter API blijkt dat ik deze call nodig heb. In Twitter4j is dit geïmplementeerd via deze methode.

Natuurlijk wil ik de software ontwikkelen m.b.v. TDD zoals ik beschreven in dit boek. Hier ontstaan wat probleempjes. Je start altijd met een acceptance test. Het verzinnen van die test was niet zo moeilijk. Haal de laatste x links op uit je Twitter timeline en print ze naar je scherm via aan servlet. Probleempje hier is dat de API altijd andere data laat zien. (Tenminste als je Tweets verstuurt.) Ook wordt je op deze manier je afhankelijk van een webservice van Twitter die een aantal limieten heeft en soms gewoon niet werkt (tijdens het tikken van deze blog heb ik meerdere malen de @failwhale gezien). Verder wil je graag reproduceerbare resultaten hebben in je tests.

Een oplossing voor dit probleem is de Twitter API stubben. Vol enthousiasme begin ik te zoeken hoe ik de Twitter output kon stubben in Twitter4j. Na twee uur ploeteren, javadoc lezen etc. was het me nog niet gelukt. Het probleem zit in de manier in de beschikbaarheid van enkele klassen in de Twitter4j API. Veel van deze klassen zijn final en hebben package access. Ook is de netwerkfunctionaliteit overal tightly coupled aan de rest van de Twitter4j code. Hierdoor wordt het moeilijker om de call te stubben. Door slimme trucjes te gebruiken is het vast wel mogelijk om het voor elkaar te krijgen.

Op de een of andere manier voelde het heel vreemd aan wat ik allemaal het doen was. Eigenlijk wilde ik iets heel simpels, doe deze REST call en filter hier de links uit. Waarom moet ik dan door allerlei hoepels springen om het testbaar te maken. Zelf mijn parser maken voor deze ene API call is makkelijker dan Twitter4j proberen te stubben. Ook de testbaarheid wordt beter bij een (redelijk) slim design. Een eerste inventarisatie levert dit lijstje op: API call doen, result JSON parsen en vervolgens deze outputten om mijn scherm. JSON parsen dat kan niet zo moeilijk zijn. Ik had dit al eerder gedaan met JSON.org maar een tweet van @basvanstratum suggereerde dat er een makkelijker manier was:

Converting my Java objects to Gson using Google’s gson library. Very nice (read: simple) to use. http://j.mp/4fgz1N #geek #work

Ok dan gaan we een uur proberen om GSON te gebruiken. Mocht het niet lukken kan ik nog altijd het alternatief van JSON.org gebruiken. Nu moet ik @basvanstratum volledig gelijk geven in het gemak van GSON. De library heeft een aantal voordelen t.o.v. json.org. Een DTO omzetten naar JSON en omgekeerd is ontzettend makkelijk, de basis is:

Bij JSON.org moet je meer handmatig door je JSON structuur lopen. Het enige dat ik in mijn geval moest doen was de DTO schrijven die een Twitter status voorstelt. Nu was ik eigenlijk alleen geïnteresseerd in de “entities” property en daarbinnen de “urls” property. Het verbaast mij dat GSON er niet over valt als ik alle andere properties niet definieer. De library vult de properties die beschikbaar zijn en negeert de overige data gewoon. Fantastisch! Ongeveer tegelijk met het ontwikkelen kom ik de volgende blog tegen: TollerantReader van @martinfowler . Hierin beschrijft hij een manier om webservices te consumen waar je alleen de properties leest die je nodig hebt. Hierdoor ben je alleen gevoelig voor wijzigingen in de XML die je echt nodig hebt. GSON maakte dit voor mij ontzettend makkelijk.

Hetgeen waarmee het allemaal begon is erg makkelijk nu. Ik heb de output van de echte Twitter API “opgenomen” en deze data gebruik ik nu voor mijn acceptance test. Nu zullen jullie je wel afvragen heb je die links nu al zichtbaar op je blog. Nee helaas nog niet. Ik kan nu wel de links weergeven op mijn scherm, maar voordat ze op mijn blog komen, moet ik er nog dit nog wat netter worden. Dus binnekort op deze blog aanbevolen links.

Growing object-oriented software guided by tests (A.K.A. Goos)

Growing Object-Oriented Software, Guided by Tests

Growing Object-Oriented Software, Guided by Tests

Dit is een review van het boek: Growing object-oriented software guided by tests geschreven door Nat pryce en Steve Freeman. Een aantal maanden geleden heb ik al een eerste blog geschreven over een klein detail van dit boek. Voordat ik het boek ging lezen had ik al enige kennis van TDD, maar deze kennis wilde ik graag uitbreiden.

Het boek

Het boek beschijft een manier om met behulp van TDD OO software te ontwikkelen. Binnen het boek wordt hevig gebruik gemaakt van Mock objecten om de ondeliggende code te testen. Ook wordt er gebruik gemaakt van geautomatiseerde acceptance tests. Deze variant van TDD die ook wel de “London school” wordt genoemd is (mede) bedacht door de schrijvers van het boek.

Het boek heeft 5 delen. Deel 1 is een introductie van TDD is en waarom het te gebruiken. Deel 2 beschrijft het TDD proces dat gebruikt wordt in detail. Deel 3 is een groot voorbeeld waar de theorie in de praktijk wordt gebracht. Deel 4 legt uit hoe je kunt zorgen dat je tests onderhoudbaar worden/blijven en tot slot behandelt deel 5 nog een aantal advanced topics.

Deel 1 en 2

Door het lezen van deel 1 en 2 krijg je een goed idee hoe het proces wordt aangepakt als je deze methodiek volgt. Belangrijke concepten:

Het laatste hoofdstuk van deel 2 is interessant omdat daar een aantal redenen wordt gegeven om nieuwe objecten en value types te introduceren. Waarschijnlijk zijn deze wel bekend, maar de opsomming zorgt voor extra houvast.

Redenen om value types te introduceren:

  • breaking out: te complex object vraagt om opsplitsing
  • budding off: een nieuw type om een Domain concept te vangen. Kan slechts 1 field zijn of zelfs geen enkel.
  • bundling up: als het vaak voorkomt dat we een aantal variabelen samen gebruiken kan het nuttig zijn om ze samen te voegen in een nieuw type.

Objecten ontstaan als:

  • breaking out: opsplitsen van te complex object.
  • budding off: nieuwe functionaliteit past niet in het huidige object en vraagt om een nieuwe class.
  • bundling up: als 2 objecten samen werken is het misschien nodig om de objecten in een nieuwe class te bundelen. The composite is simpler than the sum of his parts.

Deel 3

Na het lezen van deel 1 en 2 dacht ik dat ik de materie begreep. Dit bleek echter niet het geval. In deel 3 wordt een voorbeeld uitgewerkt. Dit is in dit geval een “Auction sniper”. Deze auction sniper kan op veilingen bieden tot dat een (ingegeven) maximum bedrag is bereikt. De GUI laat de status van de huidige veilingen zien.

In het voorbeeld wordt er stap voor stap gewerkt naar een volledige applicatie. De schrijvers leggen ook uit waarom ze voor welke stap kiezen. Gedurende Stap voor stap ontstaat een beter design van de applicatie door te luisteren naar de “test smells”. Door het voorbeeld werd mijn inzicht in OO-design in ieder geval vergroot. En ik denk dat TDD helpt bij het verkrijgen van een betere architectuur. (Zie ook mijn eerdere blog hierover.)

Deel 4 en Deel 5

Deel 4 beschrijft hoe slecht design van je applicatie zichtbaar wordt en hoe je jouw (unit)tests onderhoudbaar kan houden. Deel 5 legt uit hoe je persistence frameworks, threaded applicaties en asynchrone code kunt testen.

Conclusie

Als je nog niet ervaren bent in TDD/OO en je wilt meer inzicht verkrijgen is dit een zeer nuttig en praktisch boek om dit te leren. Het is helder en duidelijk geschreven en het voorbeeld geeft groot inzicht. Gedurende het lezen was ik wel af en toe de structuur kwijt van het voorbeeld. Terugbladeren en de schema’s bekijken in het vorige hoofdstuk hielp dan enorm. Graag had ik de schema’s wat vaker zien terugkomen. Het kan er echter ook aan liggen dat ik het boek gedurende een aantal maanden gelezen heb. Als dat binnen een kortere tijdsperiode gedaan wordt verwacht ik dat terugbladeren minder nodig is.

P.S.
Sommigen denken dat je moet kiezen tussen de London school en classic TDD. Jason Gorman heeft daar naar mijn idee een goed antwoord op gegeven. Hij stelt dat ze beide nodig zijn.

Je (unit)testcode hoort niet in een ander package

Growing Object-Oriented Software, Guided by Tests

Growing Object-Oriented Software, Guided by Tests

Afgelopen weekend heb ik twee hoofdstukken van het boek Growing Object-Oriented Software, Guided by Tests gelezen. (Rechts is meer informatie te vinden over dit boek.) In een van deze hoofdstukken staat dat het een goede gewoonte is om je testcode in een ander package te zetten dan je productiecode. En daarvoor worden twee redenen gegeven:

  1. Navigeren in je IDE is makkelijker als je testcode gescheiden wordt van je productiecode.
  2. Je wilt eigenlijk alleen de public methoden / interface van je code testen. Door het in een ander package te zetten test je niet per ongeluk op package level.

Allereerst wil ik het over de eerste reden hebben. In principe ben ik het eens met de reden. Ik denk alleen dat er een andere manier is om dit te bereiken. Ik heb altijd de gewoonte om mijn test code in een andere “source folder” te zetten dan mijn productie code waardoor deze scheiding dus gemaakt wordt.

De tweede reden is wat mij betreft niet waar. Ja je wilt zeker de public interface testen. Maar ik vind het handig om ook de packages als “encapsulation” methode te gebruiken. Laat ik dit proberen uit te leggen met een voorbeeld. Het is gebaseerd op hetzelfde voorbeeld als mijn vorige post: het importeren van transacties in mijn administratie. In dit geval gaat het over het importeren van transacties van een specifieke bank.

Ik wil niet dat er in de rest van de code enige kennis heeft van de interne structuur van de code die verantwoordelijk is voor de import. Om deze abstractie apart te houden heb ik een interface gemaakt die de import voor een willekeurige bank kan aanbieden in termen van mijn domein. Met andere woorden gegeven deze bank en deze import file geef me alle transacties.

Wat dat betreft zou je zeggen maak een class en implementeer deze interface. Problem solved. Nu heb ik in mijn vorige post aangegeven dat ik meerdere classes gemaakt heb omdat dit het (import) probleemdomein beter omschrijft. Ik wil niet dat de rest van mijn code toegang heeft tot deze classes. Alleen de publieke interface moet gebruikt worden. Ik gebruik een package om deze classes te omsluiten.

Als ik dan de testcode in een apart package zou zetten kan ik de code alleen via de public interface testen. Dit zou inhouden dat ik testen kan schrijven die lijken op een integratietest. Mijn design zou dan veel minder beïnvloed zijn door de unittesten. Door de unittestcode echter in hetzelfde package (in de test source folder) te zetten was het mogelijk om de code voor de import te testen in veel kleinere stappen. Integratie en/of acceptatietesten kunnen dan de public interface testen om te zien of de eigenlijke public interface een goede “API” is. Dus unittestcode moet wat mij betreft niet in een ander package zitten dan de productiecode, wel in een andere “source folder”.

TDD is a design technique

Die zehnte Design // My Oh My by principia aesthetica, on Flickr

Die zehnte Design // My Oh My by principia aesthetica, on Flickr

When I read Mark Seemann’s blog post stating “TDD is not a design technique” I agreed. Now I don’t anymore. Let me tell you why.

During Christmas I was writing some code with TDD. (Yeah I know I should socialize with my friends and family, but they were just like most other people still asleep around 6 am.) The codebase basically tracks my finances. I can import my bank transactions and categorize them. I wrote the first version of this program some years ago until I found that paying for a working solution is a lot easier. Since then I use the program for experimenting with new techniques, tools and programming languages.

This time I was trying to find out how the new IntelliJ IDEA worked for me while using TDD. To get a real life example I decided to (re)write the import functionality for my finances application. The banks import format is basically a text-file containing fixed length records with my transaction information. The real difficult herein lies in the fact that a transaction is splitted in 2, 3 or 4 lines in the input file. This depends on the length of the description associated with it.

Two sample transactions in file:

The old code used a single class with a 200 line method, which extracts every variable needed to construct a list of transactions. This worked and there was a test available to validate the results. But I couldn’t understand the code anymore. Using some mysterious/magical constructions I managed to get it done. A particularly good example of this so called magic was that I actually fast forwarded a few lines within the loop that was iterating over all the lines.

I decided to rewrite the code using TDD. Since I wrote the first version of the parser some years ago, I did not have a clue about the import format. However I did have a sample file and the file specification. Hence it was relatively easy to write some tests. I started to write tests which determined whether the variables were parsed correctly. So the first tested whether I could retrieve the account number correctly. Then I created the code to make the test pass. The next test checked retrieving the amount and so on. All the information could be found in the first line of a single transaction in the file.

Finally I came to the difficult part of the file. In the best case the description can be found in the second line of a single transaction. In the worst case it is splitted across line 2,3 and 4. To make it more difficult the description is at different positions in the line depending on the type of the line. There were three line types: Line 1 is always of type 1, line two is of type 2, and line 3 and 4 are type 3. Writing some tests per type made it a lot easier for me to eventually retrieve the complete description of the transaction. Along the way I created three classes resembling the line type and encapsulating the problems per line. The new code design was much better than the old code design was.

TDD-ing through the code made it possible for me to do everything step by step.  With each step I understood more of the actual problem domain. Together with the ability to refactor the code quite easily without being afraid that the code correctness was going to be compromised, I was able to get a better design. This design resembled the problem domain much closer than my old code did. For me this is all related to TDD. So I’m sorry I have to disagree with Mark Seemann. TDD is a design technique, maybe not directly but it does enable you to create better designs.

P.S. This is my first blog post in English. This is because it was a reaction to an English blog. As I’m not a native English speaker it is possible that there are some grammar/spelling mistakes. Please leave a reaction with the correct spelling if you find a mistake.

Scrum als introductie tot agile

scrum

Scrum by darkmatter, on Flickr

Ongeveer drie jaar geleden kwam ik in aanraking met Scrum. Ik was op zoek naar een vervanging van het waterval model om software te ontwikkelen. Ik wilde het proces rondom een hobbymatig project niet te groot maken en Scrum leek een geschikte kandidaat. Toentertijd hechtte ik nog veel waarde aan een proces omdat het de (valse) belofte gaf dat de goede software vanzelf kwam. Ondertussen weet ik wel beter. Een tijd later kwam ik in een organisatie waar er op dat moment geen ontwikkelproces aanwezig was. Iedereen deed daar verschrikkelijk zijn best om iets voor elkaar te krijgen, maar door verschillende omstandigheden lukte dat niet echt. Één van de redenen was dat de requirements regelmatig veranderden. Een tijdje later heb ik voorgesteld om scrum te introduceren en verrassend snel werd het geadopteerd als nieuwe manier van ontwikkelen. Binnen dit project kreeg ik dus mijn eerste echte ervaring met directe klant betrokkenheid, Iteratief ontwikkelen, planning poker, zelf organiserende teams en dagelijkse stand-ups. Ik kwam erachter dat directe betrokkenheid van de uiteindelijke klant cruciaal was. Helaas was dit voor ons op dat project niet altijd mogelijk en een product owner proxy/delegate werkte op dat moment niet ideaal.

Na de eerste ervaringen kwam ik geïnteresseerd door de effecten in aanraking met andere agile methoden en technieken. Met lean/Kanban kwam ik in aanraking door de workshop georganiseerd door @freekl, @mamersfo en @MMz_. (Na lange tijd mochten we weer met LEGO® spelen.) Verder kwam ik ook in aanraking met enkele technieken die gebruikt worden in XP, zoals TDD, Pair Programming, Continuous Integration en Refactoring (misschien niet exclusief van XP maar wel onmisbaar).

Even terug naar de situatie hier. Op dit moment wordt er nog op een waterval manier gewerkt. De requirements analist praat met de verantwoordelijke klant om de requirements te bepalen. Daarna kunnen de developers gaan bouwen. De frontend developer bouwt een mooie frontend en de backend wordt door een ander ontwikkeld. Resources worden gezocht naargelang de behoefte. Niet geheel verwonderlijk is er een sterke wij/zij tegenstelling en wordt er veel geklaagd over de business. Ook horen we vaker dat projecten binnen IT te duur en/of nooit op tijd af zijn. Gelukkig zijn deze problemen gesignaleerd en is men op zoek naar een oplossing. De voorlopige oplossingrichting lijkt te zijn in meer agile te gaan werken. De “silver bullet” Scrum wordt ingezet en er heersen heel grote verwachtingen dat deze manier de meeste pijnpunten worden opgelost. Ik denk dat ondertussen wel bekend mag zijn dat processen geen problemen oplossen, maar mensen. Een proces kan wel helpen om de problemen op te lossen. Er is een pilotproject gestart om te kijken of Scrum de oplossing is.

Scrum heeft mij de agile wereld ingetrokken. Ik hoop dat alle betrokkenen vergelijkbare positieve ervaringen hebben na afloop van de pilot als ik. Scrum alleen heeft wat mij betreft één groot hiaat. Er is geen enkele aandacht geschonken aan de technische uitvoering. Dus wat mij betreft is Scrum alleen niet genoeg. Scrum gaat niet alle problemen hier oplossen, maar kan wel als katalysator dienen. Ik hoop van harte dat na een succesvolle pilot men verder kijkt dan alleen naar scrum voor de agile projecten hier.

Older posts Newer posts

© 2018 Mark van Venrooij

Theme by Anders NorenUp ↑