Clojure Tip 💡
is software design worthless?
Okay, I admit it’s kind of a trolling question. But it’s at the center of what I’m thinking about these days. With Grokking Simplicity on the downward slope, I’ve been thinking about whether to write another book. The book would be about software design. But I’m wondering whether there’s a market for it.
Of course, as programmers, we all have an opinion about software design. Once you get past the basic mechanics of programming, everything seems like a design question. That is, each choice you make opens and closes future choices. It’s like a game of chess. Each move changes the board, and hence changes the moves available on the next turn. Taken far enough, there are enough possibilities that you can’t see to the end. Design is like a strategy that helps you organize your choices.
But is software design valuable to a business? Of course it is. Because with good design choices, you can minimize the cost of maintenance and modification. The business can respond to changing requirements more quickly. And it can reduce its expenses over time.
And yet, will companies pay for design? Now that’s a question that gets right at the heart of the matter. Sure, we pay lip service to good design, but how much are you willing to spend on it? If you aren’t willing to put cash on the table (or some close proxy, like developer time dedicated to it), it’s not really valuable economically. And largely, that’s what I’ve found to be the case.
Sure, there are some examples of teams getting totally stuck (velocity near zero) and calling in a software design expert. And there are some anecdotes of companies failing because of poor software design. But as much as I’d like design to be valued more, in real terms, it isn’t very high on the list.
Companies still value development speed over software design. Speed is important because companies need to survive in the short term before they can even think of the long term. If design is about the moves twenty turns ahead, you can’t focus on those if you need to avoid certain death in the next three moves.
Companies still value product design over software design. Many companies are still building things that customers don’t want and will never use. A lot of those things are experiments. If the experiment doesn’t catch on, the code is thrown away. So thinking of design only slows down your experimental feedback loop. And if you can improve your product design process so you never build the unused half of your product, that’s worth way more than designing the code for that unused half. It’s better to optimize at the higher level.
Yet, I still think software design is valuable. It’s just that companies get it for free. The main way they get it for free is by outsourcing it to open source libraries. Most product programming happens pretty high on the stack. That stack is a curated selection of well-designed open source products. The vast majority of code in a product is designed and written by someone else. Just imagine the software design that went into Rails, Ruby, Apache, Postgres, etc., that forms a very common stack. Likewise, think of the Ring, Clojure, JVM, etc., stack at the heart of many Clojure backends. Your code is tiny in comparison.
In effect, you are borrowing the design of millions of lines of code. The design of your code, which sits on top of that stack, is not as important as the code nearer the bottom. Your code only starts to matter as it gets bigger and stuff is built on top of it.
And as things are built on top, often those lower layers are pulled out into libraries. Those libraries are given more design attention. Sometimes they are open sourced themselves. And that’s one way design gets paid for.
Of course, software design does happen all the time in the course of normal programming. This is probably what companies think they are paying for anyway, even while there are many pressures incentivizing poor design.
The other way companies eventually pay for design is with the Big Rewrite. I think of rewrites as political failures. The development team couldn’t politically manage to incrementally improve the current software, but they could manage to start over. The big question is why they think their software’s design will improve if nothing else changes.
I think software design is important. I think it reduces bugs and makes software that is more maintainable. But the cost of design is largely externalized to open source software or to a future that may never come. The question is, are the decision makers right? All things being equal, would the same company prioritizing software design eat their lunch? These are the questions I wrestle with. And I’d love to hear your thoughts.
Awesome book 📖
As part of my research on software design, I read this book. It was suggested by friend of the newsletter Drew Verlee.
Much of software design is about choosing your abstractions. That is, picking what aspects you represent and how to represent them, and in so doing, choose what you won’t represent. An abstraction is something that ignores particular details in order to simplify a problem. For example, in classical mechanics, Force is an abstraction. It is a vector quantity that ignores the source. Is it due to contact between two objects? Or gravity? Or magnetic fields? In mechanics, the detail of what caused the force is ignored so that all of those forces can be treated equally. We do the same in software.
This presents a design problem: how do we construct good abstractions? What are the consequences of choosing one abstraction over another? The fear of Big Upfront Design, in my opinion, is due to poor processes for choosing abstractions.
The ideas in the book are a part of an emerging movement in software design. It’s optimistically asserting that we can choose good abstractions up front. But to do that, we need to be able to evaluate the abstractions. Can they represent the important situations in our domain? Do they avoid complicated corner cases? How elegantly can we express ourselves?
These questions may seem like navel gazing, but they get at the heart of software cost. If you can’t represent a situation, you’re going to need to write yet more code to hack around it. If you have difficult corner cases, your code will be more complex. And if you can’t express yourself elegantly, it will be hard to read your code.
Algebra-Driven Design presents two designs of abstractions in two separate domains—MC Escher drawings and scavenger hunts. It’s based on using types and algebraic properties to guide the design. I would recommend it to anyone who is serious about this approach to software design. The approach to design is good, and if I were to write a book on this topic, it would be inspired heavily by the ideas in it.
However good the ideas are, the book isn’t a good introduction. Even though I was well-versed in the Haskell type system and even the design process ideas, I had trouble following the case study about scavenger hunts. It was a big domain and the author fails to help the reader understand it enough to really follow the design decisions.
Further, I think there’s a lot of room for developing the process a lot more.
The author has obviously thought a lot about how to build algebras for the domains. He then presents the fruits of all of that thought. He fails to bring the reader along on the journey, with all of its twists and dead ends. Design is iterative and we can’t always see very far ahead. What we get is good exposition of how and why the final things works. What a reader needs is the building blocks for how to make a things themselves.
In the end, the book is good if you’re already there. If you’re already wrestling with these ideas, but maybe need some slightly new perspectives on them, read the book. If you’re looking to get into this area, I don’t have a recommendation for you. I can only wish you good luck.
Quarantine update 😷
I know a lot of people are going through tougher times than I am. If you, for any reason, can’t afford my courses, and you think the courses will help you, please hit reply and I will set you up. It’s a small gesture I can make, but it might help.
I don’t want to shame you or anybody that we should be using this time to work on our skills. The number one priority is your health and safety. I know I haven’t been able to work very much, let alone learn some new skill. But if learning Clojure is important to you, and you can’t afford it, just hit reply and I’ll set you up. Keeping busy can keep us sane.
Also, if you just want to subscribe for a paid membership, I have opened them back up for the moment. Register here.
Stay healthy. Wash your hands. Stay at home. Wear a mask. Take care of loved ones.
Book update 📖
You can buy Grokking Simplicity and use the coupon code TSSIMPLICITY for 50% off.
I’ve completed the content for the book. There are still a few rounds of revisions left, but the book is written. And the layout and other finalizations for print are still pending. No promises, but the publisher is optimistic that it will be published before the end of they year.
It would really help me out if you could let Manning know how important this book has been for you, if you’ve read the early access version. A good way to do that would be to Tweet at them. The best is if you write it yourself. Or you can click here for a pre-written Tweet.
Clojure Challenge 🤔
Last week’s challenge
Please do participate in the discussion at the submission links above. It’s active and it’s a great way to get comments on your code.
This week’s challenge
RGB Color Mixing
Here’s an algorithm for mixing multiple RGB colors to create a single color.
- Separate the colors into Red, Green, and Blue components.
- Average all the Reds together, average all the Greens together, average all the Blues together.
- Put the average values back together into a resulting RGB.
Is this the right way to do it? I don’t know! But it’s the way we’re going to implement in this problem. Your task is to take a collection of RGB strings of the form
"#FF021A", mix them like the algorithm above, and return the resulting RGB string.
Note that each RGB string contains two hexadecimal digits for each component. You can round the averages to integers however you want.
(mix ["#FFFFFF" "#000000"]) ;=> "#7F7F7F" or "#808080" depending on how you round (mix ["#FF0000" "#00FF00" "#0000FF"]) ;=> "#555555"
Please submit your solutions as comments to this gist. Discussion is welcome.