Mark van Venrooij

Mark van Venrooij's blog

Tag: design

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.

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.

© 2018 Mark van Venrooij

Theme by Anders NorenUp ↑