Thursday 7 March 2019

Observations of Test Driven Development


I was recently recommended the book ‘Test Driven Development: By Examples’ by Kent Beck in order to evaluate the methods engaged when dealing with coding challenges and working methods. Below are my observations on what Test-Driven Development is, its impact on real-life projects and how it might change the way we work. 


Test Driven Development (TDD) is a practice for creating clear, simple and defect/bug free code by writing tests first and then building code that makes the test pass. Tests are written one at a time in order to create the minimum required code but also to improve the reuse of code as thought is put into passing the test and just the one new test being introduced at a time.

In a typical TDD cycle a new test is added, all tests are run (with the new test either passing or failing), a change is made if tests fail, test is run in order to create success before finally refactoring to remove duplication. In this was a series of new tests can be created whilst constantly reusing existing functionality and staying focused on the issue at hand.

The process challenges the way development methods are normally implemented and thought about because of the subtle difference between writing tests for code and writing tests for requirements and writing code that causes the test to pass. It should be noted that TDD is not a replacement for performance, stress or usability testing. 

My first observation was that TDD is a slight move away from the Agile approaches I have seen on real-life Projects, in that many Agile projects have taken too literally the idea that documentation is secondary to building code, which isn’t helped by ‘Agile’ change process which means designs can quickly become obsolete. TDD is reliant on good documentation in order for tests to be written that achieve the goals and objectives of the project. The ‘How’ is agnostic but the ‘What’ isn’t.

An additional benefit in the TDD world is that the tests themselves describe the code better than standard documentation can, and it is factored into the test development. As code changes and test changes we find that the documentation the tests provides is also updated meaning it won’t go out of date.

Another observation when thinking about implementing TDD into real-life projects is that it really will work, especially with Agile as it allows projects to clearly define goals. This can be used to reduce scope creep and to ensure completion falls under the test definition. 

The book itself shows the low-level detail of splitting projects into small bite-size chunks using python and Java as examples. Specifically, it shows very small steps undertaken in order to demonstrate the method. This does help and (sorry to harp on...) works with Agile because tasks can be split into Sprint cycles but also because it makes the work specific and easier to understand, additionally whilst a large task as a whole might be difficult to implement, it may become easier when smaller parts of it have already been completed. Think of it like inserting libraries into a project where you create the small independent libraries yourself before merging them to make the end project.

From this perspective, nobody will ever go quite as slowly as the book shows the implementation, at least, not whilst also delivering at the pace that generates income or delivers targets - which is recognized in the book:
   “TDD is not about taking teeny-tiny steps, it's about being able to take teeny-tiny steps”
   “Am I recommending that you actually work this way? No. I'm recommending that you be able to work this way”

As with every method, the solution should always begin with best intentions. It will perform everything it is intended to, following good practices and standards. The difference is that as tests are being written before the work begins, both the tests and code are evolving at the same time whilst being refactored to remove duplication and obsolete code. In theory, we get quickly to the simplest solution, an increased reuse of code and tests that pass.

In real-life projects prolifically tend to overrun or removes scope or cost more money. Time, Scope and Cost. Unfortunately, as development becomes more rapid towards target deadlines so too does the elimination of anything not very importantwhich often means tests. Not all tests, but coverage gets overlooked as an ‘easy’ thing to disregard. If the happy path is working, we had better move on to the next important thing. 

The book asserts how there is a correlation between fatigue and judgement as well as between stress and testing in that increased stress reduces the number of tests. Anecdotally, when I have worked with development teams at high octanes over short periods of time - including evenings and weekends - I find it takes that extra conversation for things to be understood, or that extra bit of time to find and understand a bug.

The theory is that by applying TDD, tests won’t be disregarded as Time and Cost begin to cut into Scope. Instead, tests will catch the issues regardless of the stress, fatigue or reduced judgement project deadlines bring.

The additional value is that once the tests are written, they become the regression tests for all new feature inclusions which keeps the project on track despite potential side effects of changes in other parts of the environment. 
Throughout reading the book I found I was constantly thinking how TDD could be applied to my existing projects: Chatbot, FootballSimulation, API Development and more. The persistent thought was that actually testing a lot of real-life systems won’t be easy, especially past the unit test level where functional and integration tests come into place. 
Take for example a chatbot, how do I test a chatbots conversation has the relevant output from each input when a good chatbot will have lots of different outputs. How can I use TDD to get conversation direction whilst making the chatbot seamless?
In another example, how might I use TDD in a wider project such as during the deployment of an API Gateway? Do I test that I can make calls? that I can deploy policies? Is this even a valid scenario to use TDD? 
Part of the solution is in the use of mocking to mock parts of the flow. For chatbots there is an existing repository for ‘botkit’ https://github.com/gratifyguy/botkit-mockas an example of how mocks can be used in TDD. This does raise other issues in that creating good and effective mocking can be difficult, especially the more complicated the project and potential outputs become.
There are other concerns that can be raised such as knowing when to stop. In the past there have been test suites which have tested every hour of the day for a year. It took a long time to run as part of the suite, used up vital memory and added very little to the overall code of the project we were running. It’s important to know when to stop making testsby covering a wide range of scenario e.g. edge cases without testing every scenario.
My final thought is that TDD will require a lot of teamwork. Someone working alone to perform TDD will soon find themselves swimming upstream against a river flowing ever faster. The team would need to collectively agree the approach from the start with measures in place to ensure continued acceptance of the approach. There will also be a need for continued understanding of changes to the requirements as they are made and confirmed. 
An architect meeting leads to a change of requirements e.g. all traffic must be secured through mutual authentication. Tickets are raised, developers are informed, and tests updated to reflect the new requirement. 
In current projects, the tickets may become stuck in the backlog, it might be implemented only in some environments or the tests not updated due to time constraints. However, with test-driven development the tests are updated first, and all environments fail until changes are made to match.
There are obviously massive benefits to TDD in order to turn the approaches we make to projects on its head. Bringing tests to the forefront makes sense, gives a clear end goal to reach, gives a clear definition of done, becomes its own documentation and can be as specific or as loose as a project desires in terms of tracking implementation. 
I can see clear benefits in programming, API development and even in wider integration projects. I look forward to using it soon. I would love to hear where you have implemented TDD, the pros and cons and how I might avoid falling into common gotcha’s. 
You can email me here

No comments:

Post a Comment