Every once in a while, I have conversations with people about what really is TDD. Since I built a certain knowledge on the topic in time not only by using it but also by explaining it to others, I decided to write this article that details my definite view on what TDD is. I hope you'll find it useful. As this may be a long article, I will write for Today Software Magazine a series of shorter articles on this matter. Here's the first one.
Design is intentionally conceiving and giving form to artifacts that solve problems
Computer code is such an artifact, therefore any piece of code that intentionally solves a problem is designed
Therefore TDD is a method for obtaining design
Good design means design that has certain qualities. The most common quality we seek today is changeability.
TDD offers some built-in qualities: testability and improved mistake-proofing. The developer has to work to improve other qualities such as changeability. This is why practitioners use SOLID principles to guide their design decisions.
Therefore the qualities of the design obtained through TDD largely depend on the skills of the designer
When doing TDD, the developer designs before starting (eg. because using an MVC web framework) and all throughout the TDD cycles: when writing the test (pick class / method names, decide on types of classes to use etc), when implementing the code (variable names) and when refactoring.
I propose that TDD is a method for incremental design, since the solution grows step by step. This also relates to problem solving, and the circle closes - because design means solving a problem.
Interested? There's much more!
For some reason, the term "design" has become overloaded and confusing. Let's take for a moment the example of a smartphone. What defines its design? How it looks? How it acts? The materials that compose it? Were the older mobile phones "designed" or only the newer, slicker smartphones are "designed"?
It gets more complicated when we talk about software. Is a piece of code "designed" when it follows SOLID principles? Is it "designed" when it's procedural code? Is it "designed" when it has long methods?
I started asking these questions a few years ago because I had no idea about the answer. The only way to find answers was to learn more about design in other domains than software. After all, design is a discipline that's been around for hundreds of years before our industry.
I finally found a definite answer that is satisfactory:
"Design is conceiving and giving form to artifacts that solve problems artifact [is]… any product of intentional creation including … software
Karl T Ulrich, "Design - creation of artifacts in society"
Therefore, any piece of code that solves a problem in an intentional way is design. Older phones were "designed" because they were solving a problem: having phone conversations with other people.
But if design is any piece of code that intentionally solves a problem, why do we use SOLID principles or clean code or other things? Probably for the same reasons that graphical designers use principles such as alignment or emphasis. To make design better.
The most difficult thing to understand about design is that design has certain qualities. For example, one of the qualities of user experience design is "usability" - how easy it is to use the application and how fast a user can solve its problem with it.
These qualities are contextual. For example, a mobile user experience is different from a web user experience. The medium matters in this case.
What about software design? What are some of its qualities? Here's a quick list from the top of my head.
Dynamic qualities (valid at runtime)
The qualities of software design are contextual too. In case of a typical web application, changeability and performance are typically the most important, with scalability and security coming close. For mobile applications, performance and changeability are important. For high volume data-driven web services, performance and scalability are key. And so on.
One thing is constant: changeability is important in about 90% of the applications we build today. We have to change them often, so it's useful if we can change them faster.
Given all that, what is good design? Should be easy:
Good design is a piece of code that intentionally solves a problem and that exhibits the design qualities necessary in the given context.
The reason we keep talking about things like the 4 Principles of Simple Design, SOLID Principles and Clean Code is because we need one quality that these principles offer: changeability. Having tests helps us avoid mistakes when changing the code. SOLID Principles are all about the ease of changing code. Duplication prevents us from making changes fast. Bad names prevent us from understanding code, just making it more difficult to change it.
It's important to note however that this is not the only design quality we should watch for. Technologies like nodejs or vertx favor performance over changeability. Stored procedures or views for creating reports have the same effect.
Balancing design qualities is one of the most difficult things for a programmer. Changeability is however a good start, being such a wide spread concern.
If we understand what design and good design are, what is really TDD?
Stay tuned for the up coming article in the next issue.