It's not news that at the heart of successful software projects (and, frankly, fulfilling software careers) is good design. Also not news is that defining what "good design" really means has been at the heart of an infinite array of debates, papers, talks, books, discussions, and more for ages. To help, J.B. Rainsberger and Scott Bellware offer some advice to follow until that one true definition comes along.
Recently, well-respected Agilist and TDD-thought-leader J.B. Rainsberger was commenting on how over the years he has "witnessed a number of attempts to develop a complete, constructive definition of good design". His primary observation and personal revelation:
Some people lament the lack of a complete, constructive definition of good design. I don’t, and today I finally articulated why I don’t think we particular need to worry about this.
He continues with a disclaimer that he doesn't disagree having a "clear test for a design's 'goodness'" would be a useful thing (with examples as to why), but then expands on why he's not terribly concerned that we may not yet have [in this editor's words] "that one true way". He points to his experience, to what he thinks we do have to help us optimize our chances of ending up with a "good design":
In the past ten years I have learned some incredibly useful things about design:I have learned these things through my own practice, through pairing with others, and through observing other programmers at work. I find it more significant to note that even with only these three observations, we have improved the value of software design considerably.
- When programmers write design tests, they tend to find more of their own defects more quickly, which reduces the overall cost of realizing their design.
- When programmers duplicate code, defect rates increase, and when they reduce duplication, defect rates decrease.
- When programmers first start to change unfamiliar code, they tend to start by clarifying unclear names in the code: variable names, method names, class names. This practice helps them change code more safely and less expensively.
J.B. closes with a thought about what he often uses to identify a good design, "I get by with the Miller Test: I know it when I see it."
Interestingly, one of the key themes in what J.B. is saying has to do with an idea that for a design to be good, it should "look good" to someone new to it; (paraphrased) "..unfamiliar code? Clarify names so you can better understand it..", "I know it when I see it". Not to stretch J.B.'s message beyond what he means, but some might take this to imply that a good design will at a minimum be one which is "easily learned", and idea written about recently by Scott Bellware. In his words:
The essence of "good design" is it's ability to be absorbed by a human mind. Design is "good" when it can be easily-learned.
...
Good design is about knowledge. We wrap it up in all kinds of terminology, but in the end it's about making smallish bits of software that are easy to understand on their own, and that fit together exquisitely to make things bigger than themselves, and that can still be as easily understood.
Bellware goes quite deeply into how the term "testability" relates to the idea of good design, but not necessarily in the way it is often used. He stresses that code's "testability" is not about "whether it can be tested", but rather if it "is [currently being] easily tested", and that "testing" is all about learning:
Remember, testing is about making observations, and observations are about learning.
...
If it's hard to set up an object in order to learn what it does and whether it does it right, then you've probably got a poorly-designed object. This suggests that you can use test code to prove that you've got the right design. And this is what testability means.
...
No matter how good I become in object-oriented design, the only proof that a design is good is [example/test] code that proves concretely that I have achieved the highest level of ease of setting up an object for use.
So, as J.B. points out, unambiguously defining "good design" may just be one of those golden carrots; it's always one step in front of us, no matter how many steps we take forward. But also as he highlights, and as Bellware seems to suggest, there are tools we have right at our disposal today to help guide us towards designs that keep us productive and keep us happy, enjoying our day jobs as programmers. What do you think?