Thank God TDD is not dead "yet"

Last Friday I attended Geecon TDD conference in Poznań. As the name suggests, it was dedicated to Test Driven Development. I always see a programming conference as an oportunity to refresh your mind and focus (again) on what makes programming such a great experience. It was the same this time.

I see some space for improvements, though. My rule of thumb for attending general-topic conferences (e.g. a "java conference") is that usually it's better to attend talks about something that you are not familiar with (yet). That's because such events very often provide just sneak peeks that encourage you to further explore the topic on your own. On the other hand, for some reason I expected a narrowed-subject conference (in this case TDD-specific) to focus on very detailed/advanced topics. Therefore I was surprised by the introductory nature of some talks. I guess there is always room for both basic and advanced topics, but perhaps it would be a good idea to add presentation levels to the schedule. I think that titles and descriptions are not always precise enough.

Funny thing for me was to see Roman Numerals Kata as one of the presentations. That's because this kata is a part of my own presentation that I give every now and then during smaller events. Perhaps I should have submitted it during the call for papers. Anyway, I invite you to Mobile DeveloperDays where I will talk about TDD – the kata will be there as well ;)

TDD is a simple idea, but the devil is in the details. It is crucial to continously improve TDD skills and techniques. In my opinion a conference dedicated to TDD is like a TDD-kata on a new level. Below you will find some of the ideas presented during Geecon. It's not a talk-by-talk report, but rather my general afterthoughts from the whole conference.

The broader picture

TDD mindset can help to provide quality on different levels. I really liked the extended feedback loop presented by Steve Freeman during the opening keynote. You can find it at the beginning of this presentation. Basically it goes as follows:

  1. Understand the problem.
  2. Broad-brush design (architecture).
  3. Automate: build, deployment, end-to-end tests.
  4. Write a failing end-to-end test.
  5. Follow the red-green-refactor loop to build the functionality that makes the end-to-end test pass.
  6. Go back to 4 if there are any other functionalities to implement. Go back to 3 or 2 if needed.
  7. Production release. Start from 1 with the next problem.

Feedback & confidence

Automated tests allow you to refactor with confidence. I can not stress enough how important it is to me. TDD is a good way to write tests which are developer's safety-net.

(...) it's not about just writing tests, but about (...) the feedback you get from your tests — Nat Pryce, Geecon TDD 2015

That's it. When a test does not give you any real feedback, then it probably has no value. Sometimes it's better not to have a test at all when all that it gives you is just additional code to maintain. Don't write tests just for the sake of doing it. Focus on the stories that you want to tell through your tests.

Refactoring is crucial

Kent Beck in his book wrote a lot about refactoring as removing duplication. While removing duplication (in both production and test codebases) is very important, we can not forget about other techniques (extracting methods and collaborator objects, improving names, etc).

For me TDD is always very close to striving for code quality and real object-orientation. There is a deep synergy between testability and good design. Steeve Freeman pointed it out in another great extension to the red-green-refactor loop:

Hard to write a test? Refactor. — Steeve Freeman Geecon TDD 2015

Behaviours & business value

Behaviour Driven Development was mentioned quite often during the talks. It's more and more popular – there were examples even for UI development. I think that an interesting idea is using the same Gherkin stories for testing system (end-to-end), UI, API and the core domain.

Another thing to remember is that we should focus on business value that our tests cover. Core domain and critical paths of our application need the attention in the first place. Although not fully accurate, the quote "BDD is TDD done right" is in my opinion a good thing to ponder about.

Behaviours (again!) and tests quality

"You should test behaviours, not implementation details". Every TDD practitioner knows this fundamental rule (hopefully), but violations are still very common. Especially in regard to mocking. When you don't know the difference between mocks and stubs, there is a risk that your tests are fragile and tautological. Recognizing commands and queries and using the correct technique when testing them is a lesson that every TDD enthusiast should learn. Martin Fowler's article is a good starting point.

Ports and adapters

Ports and adapters architecture can be beneficial for many reasons. One of them is that you can test the whole domain with a very fast test suite.

Applying this architecture to frontend code is another interesting idea. It basically means that you isolate the UX logic (user's gestures) from the infrastructure (such as DOM manipulation). I think it's great that more and more established engineering practices are being introduced to Javascript development.

Testing in the world of microservices

Microservice oriented architecture is very popular nowadays. New testing techniques are required to support release cycles and assure that services comply with their contracts.

Jakub Kubryński and Marcin Grzejszczak presented a very promising way to achieve that – consumer driven contracts. It is like applying TDD to API on the architectural level. In a nutshell, they use Wiremock to create stubs that are used in consumer tests. Then, with Accurate REST, they create tests for the server to verify that it sticks to the contract described by the stub. Server developers maintain and publish the stubs. The apropriate version of the stub can be fetched from the repository when testing a new version of the consumer service in the delivery pipeline.

Property-based testing and randomized testing

Property-based testing was another popular topic. While TDD puts focus on happy-paths and known exceptions, property-based testing allows us to find unknown unknowns of our code (i.e. unexpected bugs). I agree it might be of great help in some projects.

There are known knowns. These are things we know that we know. There are known unknowns. That is to say, there are things that we know we don't know. But there are also unknown unknowns. There are things we don't know we don't — Donald Rumsfeld

I don't see property-based testing as something contradictory to TDD. On the contrary, I believe that you can combine the two and take advantage from the both of them. I used this approach once when developing Beandiff.

Test automation is a search problem — Nat Pryce, Geecon TDD 2015

Another great quote. With automated tests you can search for the best design in the known area as well as explore the unknown.

Summary

Most of the points above are not anything new, but I think it's important to repeat them. So once again: red, green, refactor, repeat. See you next year at Geecon!


comments powered by Disqus