TDD vs. after-the-fact

You can write automated tests at any point in time. Developers like to pretend that it doesn’t matter when you write those tests. That pretension is 100% incorrect.

This isn’t a value judgement. You can debate the effectiveness of each approach, but they’re different.

I don’t know everything, but I hope that by sharing my experience and understanding you can benefit from something that has helped me write higher quality software in safer systems of work than before I adopted this practice.

Writing tests after-the-fact takes a design you came up with and then solidifies it (or makes it harder to change, depending on how cynical you’re feeling). But you had to come up with that design without the benefit of something using that design.

In test-driven development (TDD), you don’t start with your production code or a design. You start with “here’s the next step I want to take.” You want to be able to do something with your production code, so you write some code that would use it how you would like to use it. Your production code doesn’t exist yet, but you focus on what you would do with if it did. You focus on the interface.

I find this a much faster way to get going. I don’t need to come up with an entire design or any implementation details to get started.

This also suggests that we’re dealing with a development activity. Testing is the science of taking a produced thing and inspecting it. It’s a post-production activity.

TDD, as the name suggests, is a development activity. “Test-driven” is an adjective. It happens to use tests to drive that development but it is a development activity. You could also argue that it’s a design activity, but if design isn’t part of our development, well, <insert jab at your favorite framework/language to make jabs at>.

So you start with enough test code to get a failure or a test that doesn’t pass (two different conditions), and then you write the simplest code possible to get the test to pass. Seriously. Even if you’re pretty sure that returning a literal 2 from your add function that a 1+1 test calls, you start with that.

With a passing test, you can then analyze the design of your code and see if it makes sense, making changes where needed to support your ability to make changes to the system in the future. Developers call this refactoring. The tests you wrote help you know that you didn’t break your functionality.

And then you rinse and repeat until you’ve delivered the value you’re after.

A neat perk of this process, you then have some tests that might help you find regressions later. That’s a perk and not the point. The point was to help you design your software.

Which means that you’ll still have testing to do after you’ve done TDD. You haven’t tested your code when you engage in TDD. You developed your code.

We do this process when writing microservices too, and over the next few days we’ll walk through how to leverage TDD to write autonomous components in Eventide.

And a big thanks to Scott Abbott, who presented at the Utah Microservices Meetup on this topic. It blew my mind.


Like this message? I send out a short email each day to help software development leaders build organizations the deliver value. Join us!


Get the book!

Ready to learn how to build an autonomous, event-sourced microservices-based system? Practical Microservices is the hands-on guidance you've been looking for.

Roll up your sleeves and get ready to build Video Tutorials, the next-gen web-based learning platform. You'll build it as a collection of loosely-coupled autonomous services, developing a message store interface along the way.

When you're done, you'll be ready to contribute to microservices-based projects.

In ebook or in print.