In a rational world, we’d fully define the problem before designing a perfect architecture to solve it. Too bad we don’t live in a perfect, rational world. In The Sciences of the Artificial [Sim96], Herbert Simon coined the term bounded rationality to describe the theoretical barrier created by limits in time, money, skills, and knowledge that make rational design challenging for complex problems such as software architecture.
Instead of rationally seeking an optimal design, our goal is to find an architecture that satisfices. A satisficing design is both satisfactory and sufficient—good enough—for our needs.
Instead of thinking of software architecture as a design optimization problem, we’ll look for a satisficing design by emphasizing the following activities.
Architects are not omniscient sages of technology who know all things. Think of every potential solution as an experiment to be validated. The sooner, faster, and cheaper we can validate (or invalidate) our hypotheses, the sooner we’ll find the right combination of structures that will help our stakeholders and the sooner our stakeholders will gain value from our designs.
Value is only one variable that must be considered. Architecture is the foundation of the software system. If it fails, then everything fails. Architects must constantly worry about what could go wrong and design for these scenarios. We can use risk to help us decide what to design next.
Simple problems often have simple solutions. There are many ways to simplify the problem. Reducing the number of stakeholders will decrease the variety of competing perspectives influencing the system. Adding or removing constraints, or focusing on a subset of the problem can reduce complexity. Identifying the routine problems makes it easier to focus on redesign. Routine problems have a known solution so we can start with pattern catalogs and apply our collective experience when exploring solutions.
The faster we learn, the more we can explore, and the greater confidence we’ll have in our solutions. If we’re wrong, let’s find out as quickly as possible. Failing fast means learning fast. Favor short, tight design iterations with concrete outcomes over longer design iterations that only focus on abstract goals.
In Notes on the Synthesis of Form [Ale64], Christopher Alexander shows how problems are always defined with a solution in mind. The boundary around a problem is created by the solutions that could potentially solve it. To understand the problem, we must explore solutions. To do a better job of exploring solutions, we must improve our understanding of the problem. Designing software architecture requires us to think about problems and solutions simultaneously. Writing some code early in the design process is one strategy for dealing with the reciprocal relationship between problems and solutions.
Avoiding rational design does not mean we suddenly become irrational architects. Architecture is the foundation of every software system, so we still need do some design work up front. We’ll need to decide how much of the architecture we’ll design up front and how much we’ll allow to emerge over time. Selecting a design strategy early in a software system’s life tells our team how we want to grow the architecture and instills confidence in our stakeholders.
18.188.142.218