Giving Up on TDD
Well, to start with, I never really did TDD and probably never will. This is merely a response post to Uncle Bob's post bearing the same name from a few weeks ago.
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.
Interesting view. Most of the time I coded that way. You were a core developer of RavenDB, in that project, you did that way as well? What did the other people in the team say? Such as Ayende? Btw, thank you for your RavenDB In Action book. Still working on reading it.
First of all, let me say that there are lots of situations in which I don't practice pure TDD. For example, if I am writing a lot of event driven GUI code with a framework like "Processing", it's just simpler, and faster, to write two lines, run the code, and see the result. While this is not pure TDD, it has a very similar edit/test loop; so I find it similarly productive.
Now, as to your actual argument: You admit you've never done TDD and never will. It therefore surprises me that you would claim any authority to argue either for or against the practice. But since you have, I shall refute the argument you made.
Your main point is:
"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."
You go on to say:
"...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."
My response to this argument is that you've vastly overstated the time invested in TDD, and vastly underestimated the time savings in debugging and refactoring. In other words your reasoning is based on neither experience, nor data; and is entirely speculative -- and your speculation is false.
I advise you to try TDD (and that means really try it -- like, for several weeks) before writing about it. Indeed, it's generally a good idea, when blogging, to know something about the topic you are discussing.
I want world peach, let me know when you can bring that. I bet it'll be juicy.
TDD is the only method, as far as I know, which produces code in a systematically way. When looking on TDD produced code I know how the code is set up and how it is going to behave. Where as spaghetti produced code I will never know and I don't know the quality of the code since I won't know how it's produced. Combining it with BDD I can combine it with customers requirements which means I can work faster whenever I change those because I know exactly which ones who does change. Which is crucial for fast developing.
No it doesn't cure cancer, but it definitely cure spaghetti code.