I’ve been thinking about software design for a long time. I started because I despised the term. But about a year ago, I realized my book was about software design. That really shook me and got me searching for a good definition.
Software design as decision-making is the best I have found. Software design is decision-making at all levels of programming, from the choice between for and while loops to how we structure modules to how we abstract our domain into concepts.
I like the definition because software design is multi-dimensional and interdependent. We cannot rely on rules of thumb and principles. However, if we define software design as decision-making, several practical corollaries fall out. And because they ring true, I think I’m onto something. Here are some corollaries of software design as decision-making.
Improve your decisions by considering more options
When playing chess, the more moves we can evaluate, the better move we will make. Software design is similar. At each decision point, we have many options to choose from. Evaluate more options to make better decisions. Too often, we plow forward, writing whatever code comes to mind without thinking about our options.
Improve your decisions by evaluating each option better
When considering a chess move, the better we can evaluate the quality of the option relative to the other options, the better move we will make. Don't dismiss a move out of hand! There may be a checkmate just past it. It works the same in software design. Consider the options and their consequences.
Improve your evaluation with more and better information
Although chess is a complete information game (unlike poker), competitive players use information from outside the game to make better moves. They study the opponent's past games. They try to read their emotional state. Sometimes, software engineers decide with too little information, even when information is readily available if only we looked. Can we research? Can we experiment? Often, the best source of information is the domain.
Gain more information by seeing from different perspectives
A single point of view can limit you. A good player looks at a move from different angles. How does it relate to their strategy? And from a tactical point of view? How does control of the board look after this move? Does the move attack? Defend? After looking from many angles, the player synthesizes it all into a decision.
Similarly, look at a software decision from multiple points of view. How does the data structure look from this perspective? What operations are now easy to implement? How does this model deal with change? The domain modeling book I’m writing now teaches how to look from a handful of perspectives.
Handle more information by externalizing it
This statement doesn't work too well with a chess game. However, we can use whiteboards and paper notes to keep more information readily available when designing software. Rich Hickey documents his design process in this talk. He shows how he uses spreadsheets to manage the design process.
Measure decision quality by the expected cost of being wrong
Being wrong is a lagging indicator. We may decide to use a set to store email addresses, but weeks after it's in production, we realize we sometimes need duplicates. We may only know if a decision is wrong after it's evident.
But also, some decisions are more challenging to change than others. It could be easy to change from a set to a list. But it could also be expensive if our code assumes a set-shaped value and using a list requires significant reworking.
Since it's a lagging indicator, we have to consider probabilities. What's the likelihood that we'll need duplicates? We also need to consider the cost of being wrong. When we multiply those together (probability of being wrong x cost of being wrong), we get the expected cost of being wrong.
Unfortunately, we can't really measure this number. And I am worried people will take this idea a little too seriously and try to quantify the expected cost. That's not what I'm suggesting. Instead, breaking it into two factors helps guide our intuition. We can decrease the probability of being wrong (by gaining better information) and lower the cost of being wrong (for example, by isolating the decision, that is, modularity).
Remember to compare it to the cost of gaining that advantage. If the cost of being wrong is one hour, but it takes one hour today to reduce that cost to 20 minutes, we are net negative. In other words, never write ten lines of code today to save ten lines of code tomorrow.
Satisfice instead of searching for an optimal decision
If the expected cost of being wrong is low enough, we should feel confident deciding without exploring more options.
Avoid discussing trivial changes
If two expected costs of being wrong are similar, toss a coin and choose one. Don't waste time on the decision.
Conclusion
Software design as decision-making gives us a practical way to improve our design skills. We need to evaluate more options better. We should take into account the cost of being wrong. These ideas can help us more than rules of thumb. But further, decision-making has been studied for years. We can look to that field for guidance.
Thanks for sharing Eric! This is a super interesting line of thinking.
This also reminds me of decision making in psychology:
We often struggle with making decisions. If there is an obvious right choice, it's not really you making the decision, but the world makes the decision for you.
Decisions are a form of risk taking. It's crucial we know what the risks are. Ideally we can make decisions that lower the risk going forward. Then the decision is easier to make. We can move fast and don't have to be afraid.
In life it's often more crucial what you make out of the decision than what you decide:
You can learn from the oath you are going. You can change directions if needed.
But to be successful, it takes some commitment to the decision. You have to believe in it and you have to put in the work.
I can this as a parallel to software design, where often the choice is less relevant than the commitment of the team. Think monolith vs Microservices or the choice of programming language.