Cover image by Matthew T Rader on Unsplash
Here is an interesting article about test anti-patterns.
Mostly excellent, although it misses the point of TDD, casting it in a largely negative light in anti-pattern 11.
As is often the case, I feel called to rectify this misunderstanding. :)
In my opinion producing some code without TDD is fine.
However, by some I mean a little.
Also by some I mean non-critical code, by which I'm referring to exactly the same context succinctly described by the author in anti-pattern 4.
Next, the author writes:
Writing tests before the implementation code implies that you are certain about your final API, which may or may not be the case.
This is plainly false. TDD is a great discipline because by writing tests when you don't know how the APIs look like, you are informed as to how they should look like.
According to the author, TDD is justified when
you have a clear specification document in front of you and thus know the exact signatures of the code methods that need to be implemented,
but not when
you might want to just experiment on something, do a quick spike and work towards a solution instead of a solution itself.
This is one of many mentions of two extreme cases where one apparently justifies TDD and the other makes it a suicide attempt. The problem is, the vast majority of cases in between those two extremes is not discussed at all.
The reality is that most cases justify TDD.
If you work in a startup company you might write code that will change so fast that TDD will not be a big help.
This is yet another indicator of a misconception about TDD.
TDD does not mean writing tests before code.
It means writing the code by writing tests.
Actually a more correct meaning of the abbreviation is Test-Driven Design where TDD's benefits are not just functional correctness and a regression safety net but guiding (not dictating) the design of the software itself.
Imagine replacing some of the time which developers spend on reading through surrounding code and thinking of a solution (then re-reading, re-thinking, etc.) with time spent writing tests (forcing the developer to think about interactions between components instead). The same process is being done, only now the developer is better at getting the APIs right. Also, when writing a test is hard - stop and zoom out. Maybe there's a problem in the design. Used in this way, tests act as a canary in the mine and help developers see and fix design problems first before implementing the feature.
In summary, TDD is a good idea but you don’t have to follow it all the time. If you work in a fortune 500 company, surrounded by business analysts and getting clear specs on what you need to implement, then TDD might be helpful.
In reality almost no software has clear and correct specs. TDD (BDD in particular) is an excellent tool to remedy that. Instead of being declared a wrong tool for that environment, TDD is exactly what's needed.
On the other hand if you are just playing with a new framework at your house during the weekend and want to understand how it works, then feel free to not follow TDD.
I agree, but would also add that it's very valuable to explore how would TDD slow you down if you did follow it, and what would need to change in the way you design software so that it doesn't.
The author gives a bad reputation to TDD seemingly out of ignorance (surely not malice). It would benefit us all that we heeded the author's own advice given in anti-pattern 13, and not hastily dismiss our attempts at baseball.