A couple years ago, I started a book on “continuous design” after landing a contract with The Pragmatic Bookshelf. It’s based on my learnings from the past many decades doing software development, key of which is that software design is a continuous process of making choices that range from large and architectural to small and code-expression level. I set aside the book a while back (pre-covid), but I intend on returning to it–perhaps in a less-frustrating language than JavaScript. Elixir maybe?
As I wrote the book, I realized I had a lot of design concepts spinning through my head, deriving from things like SOLID, DRY, Martin Fowler’s code smells, Beck’s simple design, and design patterns. These collections of perspectives on design generally lead to the same place, for the most part, and thus are in accordance. Small modules and small functions are good, and software that clearly describes its intent to the maintainer is good. But each perspective is also somehow incomplete. Yes, I love the four simple design rules, but does the most maintainable design emerge? It is possible, for example, to create rather long functions that remain expressive and duplication free.
Also, peppering readers with dozens of concepts and principles from a pile of varied design perspectives would likely confuse them. So I decided, hubris and all, that I’d create my own experience-based perspective on design. After taking a look at the various individual design recommendations I’d sprinkled throughout the few chapters of the Continuous Design book, I found that they all fit within one of four categories:
-
Clarity… because unclear code creates unnecessary complexity for code maintainers.
-
Conciseness… because redundant or unnecessary code creates additional effort and risk for code maintainers.
-
Cohesion… because conflated concepts create unnecessary complexity and additional effort for code maintainers.
-
Confirmability… so code maintainers can easily describe unit behavior, with tests that verify units behave as expected. With such tests, maintainers can safely craft and change code that supports the other three concepts. One way to achieve confirmability is via unit-test-first development (TDD).
Thus C4D (“the four C’s of design”). Each principle is rooted on the impact to interests in changing the software–which is ultimately what software design is about. As JB Rainsberger recently Tweeted: “The only reason to care about software design is to reduce the cost of changes.”
I hope to return to the book and C4D in the next year or so. There’s really a 5th “C” that has an important bearing on design, and that’s C for Collaboration.
You can devise and code what you believe to be the most elegant, expressive, and flexible design possible… which tomorrow causes another developer to start C for Crying, as they fruitlessly try to first understand it, then force a new feature into it. So, Collaborate, with a capital C. Mob programming is the best technique I know for collaborating and producing designs that we’re all happy to move forward with.
And speaking of which, I’d love a collaborator for that time when I un-mothball Continuous Design. Ping me if interested and serious.