So far in this chapter, you’ve learned how to explore options and make decisions using your understanding of the ASRs. Making significant design decisions is supremely important for having a robust architecture, but if there is one constant in software, it’s change.
All great architectures account for the inevitability of change. We design for change by choosing when to make a decision and by moving design decisions out of the architecture.
Making a decision that cannot be easily reversed—an architectural decision—is a big deal. One strategy for avoiding dead ends and wrong turns is to defer making binding decisions for as long as responsible. Delaying design decisions until they must be decided creates time for research and exploration.
In Lean Software Development: An Agile Toolkit for Software Development Managers [PP03], Mary and Tom Poppendieck introduced the idea of the last responsible moment, the time when a decision must be made to avoid losing important design alternatives. Instead of thinking about the last responsible moment, we want to try to make design decisions at the most responsible moment, the time at which a design decision has the greatest positive impact on the software system.[7]
Ideally, the last responsible moment is also the most responsible moment to decide. In practice, the most responsible moment to make a decision leaves extra time for external dependencies beyond our control, consensus building, education, and design validation. The most responsible moment is often earlier than we think it is.
Here are some questions I use to help me decide whether now is the right time to make a design decision:
Even if we can identify the most responsible moment to decide, that doesn’t mean we’ll always have enough information to make a good decision. Luckily we have a cheat to help us avoid catastrophes when this situation arises. We can move things likely to change out of the architecture.
If a design decision is easy to change later, then it is no longer an architectural concern. When possible, design the architecture so that decisions likely to change are left open for downstream designers to decide.
Many of the design principles we know from programming are just plain good design principles. For example, applying SOLID principles to architecture yields many of the same benefits to architecture as they do to object-oriented design. SOLID is a mnemonic to help remember the single responsibility, open/closed, Liskov substitution, interface segregation, and dependency inversion design principles. When elements in the architecture have a single responsibility it’s easier to isolate changes. Depending on abstractions and creating elements with clean interfaces creates flexibility.
There are many ways to move design decisions out of the architecture, including pluggable architectures, external configuration, self-describing data, and dynamic discovery. In each of these examples, we chose to alter the system’s behavior at design time or runtime without modifying the architecture and, ideally, without adversely affecting essential quality attributes.
3.137.171.114