Hackers News

What TDD is ACTUALLY Good For – Axol’s Blog

In an earlier article, I tore through some terrible arguments used to advocate for TDD that I see all too often (even by experienced engineers). I said in that piece that I would eventually go through what I think are better arguments for TDD, so that’s what I’m gonna do now.

TDD encourages writing tests for edge cases

Notice that I use the word “encourages” here instead of “ensures” like most advocates do. Here’s a rule of thumb I follow. If I comment out a line of code in your module (assuming it still compiles and runs), and ALL your tests still pass, something’s wrong. I see this too often. There’s a strong case to be made that TDD brings attention to this, because you’re only supposed to write just enough code to pass the existing tests. If you want to implement handling for an edge case, you have to write a test for that first.

It’s not a cure-all, though. Obviously someone has to notice the edge case first. This can be hard to do without having written most of the code already. Then you have to ensure your developers are rigorously adhering to TDD, even if it requires more work from them, which is its own challenge.

TDD can be used as guardrails when outsourcing implementation

Sometimes you want the actual implementation to be done by another developer, whether or not they’re part of your team, or even part of your company. Written documentation only communicates requirements, but tests enforce the shape of the interface and the data types involved.

If you want to test your implementation as you write, you’d have to repeatedly run manual tests with traditional development, which wastes a lot of time. Whereas if you write tests beforehand, you can quickly run a suite any time

This is a very good point that isn’t talked about enough. Unless you’re a god-tier developer, you’re gonna need to “check in” at some points throughout development to see how correct your implementation is. If you don’t have tests, then you’ll have to do this manually. I don’t know about you, but testing so many cases manually is such a chore. I’m guilty of this sometimes. It’s an easy trap to fall into, being so entrenched in traditional development that you’re afraid of “wasting time” writing tests, when you could be making stuff. It’s boring, but it can save you time and frustration in the long run.

TDD can be used to train people who aren’t accustomed to writing good tests

This is the “training wheels” argument. The idea is that some people haven’t learned to write good tests because they’re lazy, resistant to change, slave to coverage metrics, addicted to mocks, unable to think of interfaces without implementation details, or otherwise failed by their education.

Regardless of the cause, I have to agree that some people indeed need a…boot the backside to get their act together. If you can somehow enforce this in your team of “testing-deficient” developers, and not supremely piss them off, more power to you. But they must have a genuine desire to improve, proper training, and support, or else this won’t work. They’ll just write terrible tests first, then fall back into their usual ways.

TDD is best when your API/class/function structure has crystallized

There are roughly 3 kinds of programming work:

  • Greenfield: This is when you develop a brand new project from scratch
  • Brownfield: When you add features to an existing project
  • Maintenance: Bug fixing, refactoring, performance improvements, etc

Maintenance lends itself well to TDD. Changing the tests before you change the functionality of a method does no harm (assuming your change isn’t monstrous in scope). Writing a test first to prove out a bug before you fix it is pretty neat. You’re most likely not making sweeping changes to the interfaces of your components, so the big drawback of TDD (time wasted rewriting tests as your code structure changes) doesn’t apply.

Brownfield work also lends itself well to TDD, but less so. It depends on the complexity of the new feature, and the extendibility of the codebase. You have to use your best judgment. If it seems like a feature requires significant changes to existing modules, I’d lean on traditional development. However, if you see a gentle path to implementing this new feature, you might reap more benefits with TDD.

Greenfield development is a big no-no for TDD (at first). I don’t care how confident you are in what your interfaces will be. You’re not that good. Everything you think you know will change in the exploratory phase of a new project as you code, and you’ll strain your sanity by rewriting tests over and over again. Don’t do this, no matter how much your TDD idol pontificates its benefits.

BuT iF yOuR’e ReWrItInG yOuR tEsTs So MuCh, YoU’rE nOt PrAcTiSiNg TdD pRoPeRlY.” I don’t wanna hear it. If your initial tests are such that you barely end up having to rewrite them while mapping out the unknowns of a new project, then one or more of the following is true:

  • This project is very similar to something you’ve done or seen before, in which case I’d hardly call it “greenfield”.
  • This project is stupid simple, and the interfaces and tests are trivial to come up with. You can use TDD for this if you want, but it’ll be more of an exercise than a fruitful application.
  • Your tests are so high level and far removed from any deeper modules, which means you’re not leveraging the benefits of TDD. You could write these tests in any order and it wouldn’t make much of a difference.
  • You got lucky this time that your exploration yielded results similar to your initial guess
  • You’re a god-tier developer, in which case you shouldn’t even bother with paradigms

Instead, you should wait until your APIs have crystallized before you start writing tests. That’s when the above benefits of TDD become reapable, and the drawbacks are minimized. You might balk and say this isn’t really TDD. To that, I just want you to know that you’ve been deceived. Anyone who says they work on greenfield projects following true TDD are either extremely inefficient programmers, or lying through their teeth.

Phew! I think that’s it. I had to get this off my chest because there’s so much polarization on this topic. This probably won’t change that, but I want people to understand their opposition before dismissing them.

Naysayers think TDD is just some fringe paradigm not be taken seriously. Some see it as a cult, which it can appear to be sometimes, but every paradigm has its dogmatists. Programming is in its infancy, so don’t discount unconventional methodologies until you’ve given them serious consideration.

Advocates often downplay the drawbacks and don’t honestly engage with the objections they face. They’ll retreat to theory and make their arguments there, instead of arguing from experience and making specific practical prescriptions.

Y’all are smarter than that (I hope). And maybe one day, you’ll be as smart as me.

admin

The realistic wildlife fine art paintings and prints of Jacquie Vaux begin with a deep appreciation of wildlife and the environment. Jacquie Vaux grew up in the Pacific Northwest, soon developed an appreciation for nature by observing the native wildlife of the area. Encouraged by her grandmother, she began painting the creatures she loves and has continued for the past four decades. Now a resident of Ft. Collins, CO she is an avid hiker, but always carries her camera, and is ready to capture a nature or wildlife image, to use as a reference for her fine art paintings.

Related Articles

Leave a Reply