Most architects and developers are familiar with this fork in the road:
|Your system needs to do X now, but in the future it may need to do Y as well. Knowing that X and Y are closely related, do you spend a little extra time now and design X in such a way that adding Y in the future would be easy? Or do you keep things simple, focus on the more pressing X now, and ignore Y until the day when you really need it?|
Advocates of the first path are in the Big Design Up Front (BDUF) camp, and would argue that an investment in up-front design will pay dividends in maintainability, extensibility, quality in the future.
Proponents of the latter path are in the Agilist camp, and argue for keeping things as simple as possible, since you're probably not going to need Y in the future anyway (YAGNI) – or if you do need it, by that time things will probably have changed such that Y will really be more like Z, and your up-front design will still be for naught.
Most of us, however, realize the truth is somewhere in the middle. Some things obviously must be designed up-front since they're just too tough to refactor later, but other things can wait. Unfortunately though, in practice, this middle-of-the-road sagacity isn't very helpful, because it still doesn't tell us which things are which. When exactly should we design up-front? And when is it just better to wait?
Whether to design something up front of course depends on what that thing is. Cross-cutting concerns (e.g. transactions, exception handling, etc), database schemas, infrastructure choices, and core IP - all these things are good candidates for big up-front design.
But doesn't the context of the project also matter? A start-up with 6 months of funding left can't spend precious hours designing up front in the same way that a Fortune 500 company can, right? The start-up needs to release the product or it won't be around.
And what about the complexity of the system? How much up-front design is needed for a simple, static web site?
And while we're at it, what about the size or experience of the team? Or the maturity of the domain? Or the competitiveness of the market? And on and on and on...
Wow. What seemed like a simple this-path-or-that-path decision, is actually a very complex, multi-attribute, decision under uncertainty. And with such a complex decision, it's very easy to overlook some important factor, or get lured by a spurious goal. In other words, bad decisions are easy to make.
I've found that trying to make sense of this type of problem without knowing how to frame it in a way that takes into account these different factors and risks, is a recipe for a bad decision. To that end, white-boarding a simple decision tree can go a long way – it makes the decision easier to think about, easier to talk about, and extracts features that you might have overlooked otherwise. And it doesn't take a whole lot of time.
Let me be clear though: I'm not proposing this as some new silver-bullet methodology for making all architecture decisions, just a helpful technique for thinking about a non-trivial decision.
Ok, here's a simple decision tree for the YAGNI vs. BDUF decision.
The top node in the tree is the actual decision to be made: "design for change or don't design for change". This is the fork in the road – either you go one way or you go the other.
The next node is a possibility of the world; a state of reality that is out of your control. For example, in the YAGNI vs. BDUF scenario, either the business changes in such a way that feature Y is necessary, or the business doesn't change and Y is irrelevant, or the business changes but Y is now Z. On each of these branches, assign a probability to the possibility – you're degree of belief that that possibility will become a reality. For instance, what do you think the chance is that the business will need Y (and exactly Y) in 6 months? 80%? 50%? The sum of each branch should be 100%, since it's a certainty that one of those things will happen.
Lastly, the boxes at the leaves of the tree are the outcomes – i.e. what happens if that particular path in the tree became a reality. The better you can quantify these outcomes, the better decision you will make. In the world of software development, however, assigning cardinal values (e.g. time, $$, etc.) to the outcomes is a stretch – you'd have to know how much the feature would cost to implement, how much it would add to the bottom line, etc. Giving it an ordinal value, however, can be a good approximation. On a scale of 1-10, how well off would the organization be if you didn't consider Y up front, but it turned out that you did need it in 6 months? Would massive refactoring be required? On the other hand, how well off would the organization be if it spent time designing for Y, but it turned out that Y was unnecessary? Would you have missed a critical market window?
Once you have both the probabilities for the branches and ordinal values for the outcome you can calculate the expected value of the tree. For each outcome, multiply the utility times the branch probability. Then, sum the leaves for each decision, and compare.
For example, for the YAGNI vs. BDUF decision described above, I've assigned the following probabilities and utilities:
Design up front or not?
| | | | |
.50 .50 .50 .25 .25
| | | | |
8 5 3 10 2
YAGNI = (.50 * 8) + (.50 * 5) = 6.5
BDUF = (.50 * 3) + (.25 * 10) + (.25 * 2) = 4.5
Decision: Don't design up front!!
Initially, without using this decision tree, I might have invested the time up-front to design for Y, so if I needed it, it'd be easy implement. However, taking a few minutes to sketch out the tree has shown me that even though this outcome is highly desirable (10 on a 1-10 scale, by my estimates), there's only a small chance (~25%) that I'll need exactly Y, and a larger chance (~75%) that some other bad possibility will come true (i.e. either I'll never need Y and have over-designed, or I'll need not Y but Z, and will have to refactor). Because of this, it'd be much wiser (i.e. higher expected value) if I just focused on X now, and worried about Y later.
Like all good decision making techniques, the value isn't in the actual calculation as much as in the process of using the technique itself. In this case, making this tree forces you as the decision maker to think about the options open to you, the probabilities of certain events happening, and the relative utilities of all possible outcomes. Considering all of these things will hopefully lead to a better decision, but will definitely lead to a more defensible and more informed decision. Good luck!