Design comes first


It was when I was implementing my personal project. I found myself stuck in front of the editor, opening the test file. It felt strange. I was frozen for a few minutes and then wondered why I was so stuck. I'm just supposed to write the test right now. It should be easy.

But it wasn't. I couldn't even come up with the test name. I wondered what it meant.

TDD only works when you have the design

You might have found yourself confident while you are doing TDD in practice. You declare what you are going to implement in the test file, you implement it and see the test passes. It feels good, right?

But this works only when the requirement is simple enough to write out in seconds. When it comes to complex features that could involve several responsibilities or communication with other components, TDD rather gets in your way.

TDD has an implicit prerequisite that you have a concrete design of the functionality you are implementing. You must be confident enough to write down the test cases quickly. If you find yourself figuring out how to organize the test cases, your design is not organized enough.

Design should come first

I realized what I was wrong about. TDD doesn't make you come up with a better design. If your idea of functionality is still rough and vague, like "It should do A", where A might include B, C and D, you first need to slice it down to some parts that can be easily tested. And your test file is not the right place to do that. Get out of your editor. Grab a pen and paper. Draw a diagram or do whatever that helps your design.

Yes, TDD feels good. But if you are starting to feel it can solve anything, it's a red flag. It expects a testable design before actually starting writing tests. You can write your design in the test file if the feature is simple enough. But if you realize it's complex, you design first. Don't try so hard to write tests forcefully.

Get free of testing obsession and be practical

What TDD actually means is design. The idea of testing encourages you to come up with a cleaner, decoupled, testable organization of code.

Whether it's test first or code first is not a serious matter. What matters is design.

After this realization, I stopped persisting with test-first. I sometimes start by writing the production code and then test it later. Now I'd just take the path that seems faster depending on the situation.

Get free of testing obsession. It can harm your code and productivity. But always remember to design first.