Drifting into a test-averse culture
In the many conversations I’ve had with front end JavaScript developers about testing, of of the most frequent assertions (natch) is that writing unit tests just isn’t useful when a product is in its early stages of development.
The argument / thinking goes something like this:
“We’re still experimenting with different ideas and getting lots of feedback. In fact, much of what we’re doing is probably going to be thrown away. So there isn’t much point writing tests at all, let alone doing test-driven development (TDD). We’ll write tests later for the stuff that stays around, and do some refactoring at the same time.”
This seem logical, right? Why waste timing writing tests for code that we don’t intend to keep around for long?
I had this attitude myself for a long time. But then I worked in a team that fully embraced Extreme Programming (XP) practices.
If you’re not familiar with XP, you can get a quick feel for it by looking at its rules. Some example rules include:
- No functionality is added early
- Refactor whenever and wherever possible
- All code must have unit tests
- Code must be written to agreed standards
- Code the unit test first
- All production code is pair programmed
- Create spike solutions to reduce risk
Early in the project, when the product design was being explored, we created a lot of spikes. Some were short technical experiments to test out technologies or system design concepts. Others were UI prototypes for user testing.
But all the spikes were thrown away, because none had unit test coverage.
We had an additional rule in the team: do not write unit tests post-hoc. In other words, do not write unit tests to cover code you have already written, just so that it can be made ‘production-ready’.
This rule implicitly recognises and important point about TDD that is easily forgotten.
Unit tests guard against regressions and bugs, sure. But writing unit tests before production code has other positive benefits. Most notably, they have a positive impact on system design, because we must write code that it is highly testable by default.
You can’t guarantee testable code when writing the code first. If you’ve ever tried to write a unit test suite post-implementation, you’ll know it can be extremely challenging. You might even give up, or throw away the implementation. Either way, not a great outcome.
It might seem that writing unit tests for potentially disposable code is a waste. But untested code has a habit of growing. Set an early precedent for skipping tests, and you can easily end up sleep walking into an engineering culture where tests are optional. And this is extremely difficult to rectify later on.
All the best,
– Jim