"Good Design" Means ...?
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?
Designing is all about Learning
C. Keith Ray
I think we can conclude that one of the ways we can design code is by test-driving it -- tests help us learn where our design needs to go, and when writing a programmer-test becomes hard, that is a signal that we can learn from.
Designing is also about clearly communicating ideas
Any design that is in some way incomplete, vague or ambiguous can quickly lead to a break down in communication, and, as an outcome, allows for poor quality in implementation, maintenance and tests. This is why it is so important that software developers and architects not only have the technical chops but also have training to clearly communicate complicated ideas both in verbal and written form.
Clearly communicating design is no easy task for any sizable system, but it should be seen as a primary goal for any project to become truly successful.
From the conclusions;
"... structure of classes and packages that keeps the software application flexible, robust, reusable, and developable."
Re: Designing is all about Learning
As for your second assertion (pun intended) about learning from the tests (what I personally like to call "listening to your tests"), the post by Scott Bellware also stresses that point. Albeit, he does appear to go to great lengths not to explicitly say "test-drive" or "TDD", which I did find interesting. ;-)
Re: Design principles
J. B. Rainsberger
It is easy to persuaded by good design
My universal properties of good design are (from the top of my head):
- names and terms wisely chosen
- provokes very few misunderstandings
- easy to communicate
- concepts are clearly separated by concerns and not wildly interconnected
- often, symmetry and beauty of shape (Gestalt) are indications of good design. For example, you can very often identify code that stinks only by its shape, without exactly knowing what it does.
Good design has a lot to do with aesthetics. Not measurable, of course. That's where experience comes in. "I know it when I see it" fits here nicely.
And, oh yes, please do reference also THIS nugget by Jim Shore
Well worth a print out, read, and posting on the team room wall.