Why No TDD for Me?
Let's start with one observation that should be obvious to all: like everything in software development — no development method is a guarantee for good software, and neither is lack thereof a guarantee for failure. TDD never really made sense to me, and to the way I iterate when writing software.
It takes time to write tests, design test infrastructure, make sure your code is designed in a way it can be tested with your infrastructure, compose test data, etc etc.
All of that takes time. And it's a waste of time doing all that while your software, your code base and your ideas are still all in a very fluid form. You should let the ideas bake, let the codebase form a shape and stabilize, then write tests to validate and refactor where needed to make things more testable. We need to build stuff and ship stuff. We can refactor later when we have something basic working, and we can get ready to ship to production. And we need to test, but why waste efforts on testing immature software.
This is how I usually (read: always) write code:
- I open a new file, with one class (or even without any, depending on the language) and write a lot of awful spaghetti code that gets more and more awful by the minute. Exactly the type of code everyone will preach against.
- At a certain point where there's enough logic I can run, I start initial probing runs to validate the concept, usually with test data and stub methods that return nonsense values instead of approaching data sources.
- As the concepts become clear, and structure starts to form, I start extracting out methods and classes.
- The code reaches production grade when I can call things in it by name, and draw (in my mind) interactions between the parts.
- This is when I start writing tests. Never before.
- Sometimes in the end I find that some of that code is actually usable elsewhere, and then I may start the
Call this Spaghetti Driven Design. Register this as a trademark under my name. This works for me, and allows me to iterate fast. Like, really fast. And as long as I design and write tests around my code before shipping it, I can guarantee its correctness and quality.
I never over-engineer at the beginning. I never assume a code base structure. I just let it flow, and refactor heavily only once I have a working prototype.
Uncle Bob goes in length in criticizing Sommerville's code and design, during which he says:
Compose your system out of independent layers that communicate through well defined interfaces.We isolate modules. WE. DESIGN.
Yes, we design. However, there is engineering and there is over-engineering. Independent layers? There we go again into that world of pain that is onion layering. Remember that 3-tier data access pattern with BLL/DAL? the repository pattern? anyone still thinks any of those are good examples for good engineering?
Layering isn't the solution. Just like TDD isn't the solution. Both are possible solutions, and yeah - sometimes layering helps with testing, but not every layering approach makes sense and worth the cost.
TDD — Test Driven Development — tells you to write tests before code. For some people, in some projects it can prove helpful. I personnaly never saw the benefit of it — it just adds a lot of ceremony before the actual real work begins, and prevents agility and quick iterations. I prefer to iterate fast, test later.
I'm happy to see Uncle Bob finally admitting that TDD will not cure cancer nor it will bring world peach. Now let's also accept the fact that it's not necessarily the best development methodology that everyone should adapt. It's a methodology. And people can give up if it doesn't work for them. It never did for me.