In an uncharacteristically expletive-light post, Hani talks about the difficulty of defining what good design is:
So what’s the acid test for a good design? I have no idea. The closest I could come up with is A good design allows your code to do things you never expected it to have to do.
I dislike this definition for a few reasons – at least one of which Hani himself touches on:
It’s not about ‘oh I’ll add an interface here so I can plop in different implementations’ when there’s no sane reason you’d ever need more than one implementation, for example.
That is to say using Hani’s definition as a maxim for what makes good design could lead to designs which violate the ever sensible YAGNI principle.
First and foremost, a good design needs to make it easy to do what you are doing right now. There is no point having a design to support future (potential) requirements which makes your current work a pain to do. YAGNI follows from this principle. Second it needs to be easy to change. This can come from having small, loosly coupled, highly-cohesive code. Both of these things require a design that is easy to understand – not just in the sense of “Can I understand the code?” but in terms of all members of the team being able to share a mental picture of the same design.
Good design is inherently contextual. Design that is good today, might not be good for tomorrow. But if your design (which inevitably means your code) is easy to change, it can be made good again.