Summary
Uncertainty is normally seen as something you must either suppress or avoid. Of this many people appear, well, certain. That you should embrace it and use it to help determine schedule and design is not immediately obvious.
Advertisement
Confronted with two options, most people think that the most important thing
to do is to make a choice between them. In design (software or otherwise), it
is not. The presence of two options is an indicator that you need to consider
uncertainty in the design. Use the uncertainty as a driver to determine where
you can defer commitment to details and where you can partition and abstract
to reduce the significance of design decisions. If you hardwire the first
thing that comes to mind, you're more likely to be stuck with it, so that
incidental decisions become significant and the softness of the software is
reduced.
One of the simplest and most constructive definitions of architecture comes
from
Grady Booch: "All architecture is design but not all design is
architecture. Architecture represents the significant design decisions that
shape a system, where significant is measured by cost of change." What follows
from this is that an effective architecture is one that generally reduces the
significance of design decisions. An ineffective architecture will amplify
significance.
When a design decision can reasonably go one of two ways, an architect needs
to take a step back. Instead of trying to decide between options A and B, the
question becomes "How do I design so that the choice between A and B is less
significant?" The most interesting thing is not actually the choice between A
and B, but the fact that there is a choice between A and B (and that the
appropriate choice is not necessarily obvious or stable).
An architect may need to go in circles before becoming dizzy and recognizing
the dichotomy. Standing at a whiteboard (energetically) debating options
with a colleague? Umming and ahhing in front of some code, deadlocked over
whether to try one implementation or another? When a new requirement or
a clarification of a requirement has cast doubt on the wisdom of a current
implementation, that's uncertainty. Respond by figuring out what separation
or encapsulation would isolate that decision from the code that ultimately
depends on it. Without this sensibility the alternative response is often
rambling code that, like a nervous interviewee, babbles away trying to
compensate for uncertainty with a multitude of speculative and general
options. Or, where a response is made with arbitrary but unjustified
confidence, a wrong turn is taken at speed and without looking back.
There is often pressure to make a decision for the decision's sake. This is
where options thinking can help. Where there is uncertainty over different
paths a system's development might take, make the decision not to make a
decision. Defer the actual decision until a decision can be made more
responsibly, based on actual knowledge, but not so late that it is not
possible to take advantage of that knowledge.
Architecture and process are interwoven, which is a key reason that architects
should favor development lifecycles and architectural approaches that are
empirical and elicit feedback, using uncertainty constructively to divide up
both the system and the schedule.
I think I have done some of this, unconsciously, for some time. Now that you've written it out, and I can see it consciously, I'll be able to make better use of it. Thanks. :)