Agile Decompiled: Test Driven Development
The Agile Zone is brought to you in partnership with JetBrains. Learn how Agile Boards in YouTrack are designed to help teams plan, visualize and manage their work in an efficient manner, with support for both Scrum and Kanban processes.
Many people associate Test Driven Development, usually referred to as TDD with agile programming, but in fact TDD is more a practice of the Extreme Programming movement. Unit testing pre-dates TDD but TDD reverses the idea of testing your units of code and says you should start with a test, and that test should fail, and then you should write the code to make the test pass.
The obvious advantage to this is that when you subsequently make a change you can see if the change has broken anything else in the system, which will give you greater confidence in your code.
However there is a more subtle effect that using TDD has.
So what else does TDD give you? A TDD approach lends itself to coding using SOLID principles. Let me expand on that.
S – Single Responsibility
A method or class should be responsible for one task, and one task only. This leads to smaller methods which are easier to understand, have fewer lines of code and fewer bugs and side effects.
A good unit test will test one method or one unit of work. In order for this to work well the method must do one thing well or have a single responsibility.
O – Open/Closed
The Open/Closed principle, at the method level, suggests that the method you are testing should be open to bug fixes but closed to modification. If your method is doing more than it should to fulfill it’s responsibilities then there is a greater chance of higher coupling and side effects.
L – Liskov Substitution Principle(LSP)
The idea behind the Liskov Substitution principle is that it should be possible to substitute different subclasses of a class without a consumer of the base class needing to know about the substitution.
When a TDD approach is taken, artifacts such as queues and databases should have test doubles to shorten the code-test-fix cycle, which means subclasses are more likely to follow the LSP.
I – Interface Segregation
Interface segregation refers to creating tightly focused interfaces so that classes which implement the interface are not forced to depend on parts of the interface they do not use. This is single responsibility again but from an interface point of view, and as with single responsibility for classes and methods a unit test will be more effective when only the salient part of the interface is included in the test.
Having a cohesive interface, much like having a cohesive class, leads to a much cleaner contract and less likelihood of bugs and side effects.
D – Dependency Injection
Let’s say you have object A and object B. Object A depends on object B to work, but rather than creating object B within object A, you pass a reference to object B into object A’s constructor or a property of object A. This is dependency injection.
When coding using TDD you will often want to create any dependent objects outside of the class you are testing. This allows you to pass different types of test double into the object under test as well as real objects when the class has been integrated into an application.
More on the SOLID principles can be found over at Black Wasp.
So as you can see from above, TDD does lend itself to a more SOLID approach to coding.
But is using TDD necessary or important? After all there were many millions of lines of code written before TDD came on the scene? And much of this code can still be found today. Good quality code written without TDD and unit tests.
If you read Bob Martins posts over at 8th Light he suggests that TDD is linked to professionalism, but as we saw from the previous article the agile manifesto does not proscribe any particular process.
So in theory you could be agile without TDD. However TDD, like Object Orientated Programming, does lend itself to producing code with fewer couplings and fewer side effects, so even though you can be agile without it, you should probably be using TDD anyway to increase the likelihood of developing more robust code.