This post is second in a series about a group TDD experiment to build an application in 5 days using only tests. Read the beginning here.
Today is the pitch. We'll talk about what we're going to build and how we're going to do it, but first we need to understand the motivation behind our methodology. We need to understand why we test.
Kent Beck's TDD by Example was one of the first books I read about TDD and to this day it's still one of my favourites. I know many prefer Roy Osherove's Art of Unit Testing (which I also highly recommend) because it's newer and has .net examples, but in comparison they are very different books. Roy's book represents the evolved practice of Unit Testing and it provides a solid path to understand testing and the modern testing frameworks that have taken shape since Kent's book was written in 2002. Kent's book is raw, the primordial ooze that walked upon land and declared itself sentient, it defines the methodology as an offshoot of extreme programming and is the basis for the frameworks Roy explains how to use. If you're looking for a book on how to start and the mechanics of TDD, this is it.
As an offshoot of extreme programming, the core philosophy of TDD is:
- Demonstrate working software at all times
- Improve confidence while making changes
- Build only the software you need
My experiment is based on the strategies defined in Kent's book – the premise is to demonstrate working software and get early feedback – but in a nutshell, you make incredibly small incremental changes and compile and run tests a lot (30-50 times per hour). I sometimes refer to this rapid code/test cycle as the Kent Beck Method or Proper TDD. I don't necessarily follow this technique when I code, but it's a great way to start until you learn how to find your balance. Eventually, running tests becomes instinct or muscle memory – you just know when you should.
For our experiment, we followed these rules:
1. Tests must be written first.
This means that before we do anything, we start by writing a test. If we need to create classes in order to get the test to compile, that is a secondary concern: create the test first, even if it doesn’t compile, then introduce what you need.
2. Code only gets written to satisfy a test.
This means that we write only the code that is needed to make a test pass. If while writing the code you're tempted to add additional functionality that you might need, don't succumb to writing that code now. Instead, focus on the current test and make a note for additional tests. This ensures that we only write the code that is needed.
3. Code must always compile (at least within 30 seconds of making a change)
This may seem like a difficult practice to adopt, but it is extremely valuable. To follow this rule, make small changes that can be corrected easily and compile frequently to provide early feedback. If you find yourself breaking a contract that takes twenty minutes to fix, you're doing it wrong.
4. Time between red/green must be very short (<1 minute, meaning rollback if you're not sure.)
This is also a very difficult rule to keep, but it forces you to recognize the consequences of your changes. You should know before you run the test whether it's going to pass or fail. Your brain will explode when you're wrong (and that’s a good thing).
As mentioned in the first post, my current project uses NDepend to perform static analysis as part of our build process. The build generates a static image. As our solution analyzes over 80 assemblies, the text becomes illegible, and its somewhat difficult to read (image text has been blurred to hide assembly names).
The two primary use cases I wanted the application to have:
- Allow the user to select an NDepend AssembliesDependencies.xml file and display it as a graph
- Once the graph has been rendered, provide an option to choose which assemblies should be displayed
The graph would be implemented using Graph#, and we could borrow much of the presentation details from Sacha Barber’s post. Using Graph# would provide a rich user-experience, all we’d need to do is implement the surrounding project framework. Piece of cake!
I asked the team if there were any additional considerations that they would like to see. We would take some of these considerations into account when designing the solution. Some suggestions were made:
- Multi-tab support so that more than one graph can be open at a time
- Ability to color code the nodes
- Ability to save a project (and load it presumably)
With the few remaining minutes in the lunch hour, we set up the project:
- Create a new WPF Project. Solution Name: DependencyViewer, Project Name: DependencyViewer.
- Create a new Test Project, DependencyViewer.Tests
- Added a reference from the Test Project to the WPF Project.
- Deleted all automatically generated files:
- Renamed the default namespace of the Test Project to match the namespace of the WPF Application. For more info, read this detailed post which explains why you should.
While I have some preferences on third-party tools, etc – we’ll get to those as they’re needed.
Next: Day Two