I am planning on giving a talk, tutorial, lecture, rant (take your pick), about my take on the whole test driven development movement, how to do it, the pitfalls to avoid and the improvements in production that can be achieved, so for those that are going to see the talk, this is a sort of primer, over the next few posts I hope to give a taste for where I will be going, and for everyone else, I hope it is helpful, inspirational or at lest interesting.
First up a warning, driving production code from tests is a paradigm shift in thinking and not to be taken lightly. Looking up paradigm in the Oxford English Dictionary it says
“a pattern or model, an exemplar”
So I am going to be messing with your model of programming, its not an easy journey and its not a silver bullet that will solve all your development woes, in fact it can add to them if used incorrectly, but the results can be breath taking and well worth the journey.
Like a lot of systems the rules appear simple, but to implement them successfully takes practice, and discipline, so don’t expect to get it right first time, like all good things it takes practice, practice, practice,
The rules for test driven development were defined by Robert C. Martin some time ago, and work for any of the test driven methodologies.
1. You are not allowed to write any production code, unless it is to make a failing test pass.
2. You are not allowed to write any more of a unit test than is sufficient to fail; and compilation failures are failures.
3. You are not allowed to write any more production code than is sufficient to pass the one failing test.
So what does this actually look like in the real world of programming?
Notice we are not writing the test first that’s important! We are writing the test and production code stubs ( a stub in this context is the outline of a method, function, class, property as required to get code to compile.) along side each other so the test code leads the production code by a very few keystrokes.
Once the test assertion is written, then we have a truly failing test because the production code has no inner core, which we can now fill out in the simplest way possible to make the test pass before moving on to the next test.
Notice I said the simplest way possible, this is also important!
What we want to do is write the smallest, and simplest code that will make the test (and any previously passing tests) work, don’t worry about method size, single responsibility etc. they get sorted in the next stage, we want the test to pass first, and fast.
Watching others and myself work, it is this last stage when things start to go wayward, I have a failing test, and I begin to make it pass using what I know in my mind will be the final version of the code, ( I just know I am going to need that service for login and the logging to record and the service to the database etc. etc.) and before I look around I have been writing code for 30 minutes and the test is still failing!
I actually think it is at this point your coding partner should be shouting YAGNI (You Aren’t Going To Need It) in your ear.
Rule 3 is one of the most difficult to follow successfully. Is adding all that extra stuff the simplest thing? Or am I adding what I think I know I will need?
One of the tenets of test driven development is that the tests drive the design of the code, yes you will have an idea that you will probably need x and y services and the REST schema will help define how the controllers in your MVC application will be laid out.
But these ideas should be born out by the tests. I have found that if the tests are allowed to drive the final design then surprising things happen, the code I arrive at is not the code I would have written! It is cleaner, readable and simpler that my original thoughts, and its always easier to maintain and extend.
What makes this transformation? once a test passes, we pause, we have working code, sit back, review it, read it and then look at the code from a totally different angle, what methods are doing more than one thing? does the class have the correct responsibilities? is the naming correct?
Now dive in and refactor it.
I am a big believer in small methods and the single layer of abstraction within a method, a method should do one thing, so I use the extract method refactoring until essentially I cant do it any more.
The class with all these methods in should have one reason to exist, and only have a single reason to change, if any of the methods don’t conform to this then it’s a clue that I need a new class to handle that responsibility, and so again I refactor, all the time the tests are being run to ensure that I have not broken anything.
During this period of change or moulding I will change the names of methods to reflect what they actually do, ensuring that the public facing method names are small and concise and that the internal private methods are long and descriptive.
For each class and method in my project this refactoring can take place many times, each time a test passes, I can if I want to review the whole of my code base, this refactoring is not just limited to my production code either, the test code can be reviewed and cleaned up as well, here I am aiming for readability above all else and ensuring that any new classes created by the refactoring of the production code are now covered by new or moved tests.
Readability in the test code is paramount, if having some code duplication in the tests improves readability I will have duplication, but in the production code, I will remove any sense of duplication, for production code I am looking for clean, concise, fast code, in the tests I am looking for readability, first and foremost.
This process of writing simple code that with each test provides functionality is what makes test driven development different and difficult to do. Forcing the simplest thing that can possibility work, knowing that the next test will probably change it, can be difficult to grasp, why then am I writing the simple one line? why not write the more complex code that I know is going to be there?
Because I know I am going to change it, the act of writing it, then changing it a few moments later is what makes test driven code so unique, the code is being moulded by the tests and refactoring, code being changed is alive and dynamic, working in the fashion produces code that is simple, easily extendable and productive, and never what you originally thought of.
Like modelling clay, code is kept moving by the process, changing its shape all the time, never settling too long in any one pattern, but improving by design as the product evolves.
This ability to change is what makes the practice special and fit the agile mould. Code is not a static concept, test driven code is not written and left, it is forever being added to, amended and moulded, keeping the code clay moving means change is not only expected but welcomed.
The codes ability to absorb change means the business is not going to expend money re-writing an application to adapt to new conditions, the current application can be changed to match the new business requirements.
Keeping the code moving is the developers job, we are responsible to the businesses for the source code, we should not want the code to “set”, because code that is left, rots and is difficult to change which impedes the business we are employed to support.
It is the use of tests, the practice of refactoring and test driven metrologies that allow a developer to keep the code mobile, meeting the business needs and supporting not preventing growth.
So that’s the advert over, next post we can actually get down to some code