Kent Beck in his Patterns Enhance Craft Step 3: A Few Good Solutions highlights an important fact about software development:
We encounter repeating configurations of forces/constraints that have only a handful of “solution families” and the optimal solution(s) depend on the relative weights of these constraints.
For example when deciding what error handling style we should choose when calling an unreliable rutine:
Depending on whether readability, reliability, automated analysis, performance, or future maintenance are most important you could reasonably choose any one of:
- Return value plus errno
- Exceptional value (e.g. Haskell’s Maybe)
- Success and failure callbacks
So there is no single perfect error handling style to rule them all.
Kent further explains that the forces shaping most design decisions are generated internal to the process of design, not by external constraints: whether we’re building a barn or an airport, the list of forces influencing the roofing decision is the same – snow, wind, etc. – but their relative strengths may be different. Internal forces in SW development include use of the same bits of logic repeatedly, code made for/by people, etc.. F.ex. the forces influencing naming a variable do not depend on what SW we are building but on its purpose, lifetime, etc. We encounter some configurations of these constraints again and again and a catalogue of design patterns representing the “solution families” mentioned above can guide us towards the most suitable solution for given weights.
When designing a solution, it is helpful to think in terms of these forces and their relative strengths. There is no single superior solution (a.k.a. silver bullet) as different configurations of forces and their weights might be best suited by radically different solutions. Keeping this on our minds might prevent design discussions from dengenerating into an argument.