Through an above-average display of ineptness, I managed to overwrite my first version of this post with a response I wrote to the comments. Since I'm too lazy to try to reconstruct it, I'm going to go a different direction. In a recent talk about design, I told the attendees that I was going to insult them during the talk, and it worked pretty well, so I'm going to try the same thing here:
You don't know how to do design. You would not know a good design if it came up and bit you.
To explain this, I feel it necessary to talk a bit about ignorance. I will loop back to the topic at hand sometime in the future.
In a really cool article written back in 2000, Phillip Armour wrote about 5 orders of ignorance, which I'll summarize here:
- Oth Order Ignorance (0OI) – Lack of ignorance, or in other words, knowledge. I have 0OI about skiing.
- 1st Order Ignorance (1OI) – Known lack of knowledge. I have 1OI about how to knit, but I can think of a number of ways to convert this to 0OI.
- 2nd order Ignorance (2OI) – Lack of awareness. I have 2OI when I don't know that I don't know something. I cannot – and this is the point – give examples here.
- 3rd order Ignorance (3OI) – Lack of process. I have 3OI when I don't know a suitably efficient way to find out that I don't know that I don't know something.
- 4th order ignorance (4OI) – Meta ignorance. I don't know about the 5 orders of ignorance.
Like any model, this is a simplification of what is really going on, but it's a useful model.
Back to the insult, but this time I'll reword it using the orders of ignorance:
You have 20I about design; the code that you are writing has obvious problems with it but you do not see them because you are 2OI about these problems and therefore cannot see the problems yourself.
It's a little less catchy, and that's why this series is named "You suck at TDD", not "Systemic influences and limitations in human knowledge acquisition have limited your effectiveness at TDD in interesting ways".
You can probably think back when you learned something about coding – for example, there was probably a time when you learned it was good not to repeat code. Before you learned that, you had 2OI ignorance about it, and now you no longer do.
We *all* have at least some 2OI about design; it's just a feature of how knowledge acquisition works. That is not the real problem.
The real problem is that most developers have both 3OI and 4OI when it comes to design. They don't understand how 2OI works and therefore think that they have good design skills, and – probably more importantly – they don't have an efficient way of identifying specific instances of 2OI and converting them to 1OI and ultimately 0OI.
Or, to put it more concisely, most developers think they are good at design because they can't see the problems in their designs, they don't really understand that this is the case, and they don't have any plan to improve.
If you couple this with our industry's typical focus on features, features, features, it is no longer surprising that there is so much bad code out there; it becomes surprising that there is code that works at all.
So, tying this whole thing back to TDD, the reason that TDD does not work for a lot of people is that they don't have sufficient design skills to see the feedback that TDD is giving to them. They get to the refactor step, shrug, and say, "looks good to me; let's write the next test". And these 2OI issues add up, and they make it harder to do TDD on the code, and it gets hard to do.
This is not surprising. TDD is about evolutionary design, and if you aren't very good at design, it's not going to work very well.
Improving your design skills
The remainder of this series is about improving your design skills. I will probably focus on specific patterns that I find especially useful in the TDD world, but I'd like to provide some general advice here. These are things that will help you move from 2OI to 1OI in specific areas of design. And please, if you have other ideas, add them in the comments:
- Pair with somebody who cares about design. They will be 1OI or 0OI in areas where you are 2OI, and by having discussions you will learn together.
- Read and study. There is a *ton* of useful information out there. If you like abstract, read – and then re-read Fowler's book on Refactoring. If you like more specificity, go read information about a single code smells, and then find it – and fix it – in your code. If you want a bigger example, just search for refactoring, and you'll find examples like this.
- Share and teach. You may think that you know something about a specific area of design, but when you go to teach it to others, that is when you really learn it.
- Practice refactoring skills. If you are lucky enough to work in a language with good refactoring tools, train yourself to use them instead of hand-editing. Not only will this speed you up and reduce the errors you make, it will train you to think differently about code.
- Practice TDD and experiment with different approaches. What does "tell, don't ask" do to your code? Can a more functional programming approach have benefits?