just enough architecture - Software architecture

Why is software architecture important?

  • Architecture acts as the skeleton of a system: Every system has an architecture, whether its developers consciously chose it or not. There is no single right architecture, but there are more or less suitable skeletons for the job.
  • Architecture influences quality attributes: Quality attributes are externally visible properties, such as security, usability, latency, or modifiability. Metaphorically speaking, different skeletons are better or worse at handling different burdens, so choosing the right architecture can make achieving desired qualities easier.
  • Architecture is (mostly) orthogonal to functionality: It is possible to build the same system as a 3-tier architecture or as a peer-to-peer system. When the architecture is poorly matched to the functionality, however, developers will struggle against it.
  • Architecture constrains systems: Architecture is the art of imposing just enough constraints so that the system has the quality attributes you want. For example, a design that ensures scalability may require some components to be stateless in order to achieve that scalability.
    • Embody judgment: Constraints are a means to transfer wisdom or understanding from one developer to another. Senior engineers have a detailed and nuanced understanding of the domain they work in, and it takes time to convey this knowledge to others. Through constraints on the design, they can guide other engineers to acceptable solutions without fully transferring their knowledge.
    • Promote conceptual integrity: Fred Brooks argues that conceptual integrity of a system is an important goal of system design, and that a single good idea consistently applied is better than several brilliant ideas scattered across a system. Desmond D’Souza taps into the same idea when he argues that architectural constraints “reduce needless creativity” of developers, enabling them to use that creativity in places where it is needed.
    • Reduce complexity: As a corollary to conceptual integrity, constraints can factor out complexity, yielding a system with evident underlying principles. In contrast, an unconstrained system can do similar things in arbitrarily different ways in different places, hindering its comprehensibility until you master its fussy details. A constraint can cut through that complexity, giving you something that you can count on. For example, if data can be saved only to a database, then you know where to look for it.
    • Understand runtime behavior: Source code can be inspected directly, yet it can be difficult to predict how it behaves at runtime. You can write tricky code whose runtime behavior is nearly impossible to understand, or you can constrain it so that its runtime behavior is evident.

When is architecture important?

Architecture is likely to require more attention in systems with large scale or high complexity. Here are five specific cases with high architecture risk.

  • Small solution space: Architecture is important when the solution space is small or it is hard to design any acceptable solution. Consider the difficulty of creating a human powered airplane compared to creating a faster car. The airplane will require that everything is just right, including low weight and high efficiency. Conversely, up to a point, making a faster car is often no harder than adding a bigger engine.
  • High failure risk: Any time your failure risks are high, it is probably important to get your architecture right. People might die if your hospital system fails, and your company might never recover its reputation after a serious security failure.
  • Difficult quality attributes: Architecture influences your ability to satisfy quality attributes, so while making another email system seems easy, making one with quick performance that supports millions of users is hard.
  • New domain: You will need to pay more attention when the domain is new, or at least new to you. If you are building your tenth interactive desktop application, you will instinctively avoid poor designs, but if you are building your first then the architecture deserves your attention.
  • Product lines: Some sets of products share a common architecture. Their product-line architecture will make some kinds of product variations easy and others hard to build.

Presumptive architectures

A presumptive architecture is a family of architectures that is dominant in a particular domain. Rather than justifying their choice to use it, developers in that domain may have to justify a choice that differs from the presumptive architecture. Incurious developers may not even seriously consider other architectures or may have the misapprehension that all software should conform to the presumptive architecture.

Presumptive architectures are similar to reference architectures. A reference architecture is a family of architectures that describes an architectural solution to a problem and it is usually written down as a specification. You can find reference architectures for high-reliability embedded systems or for using a particular vendor’s technology to build web-based systems. A publisher of a reference architecture may hope that it becomes a presumptive architecture, but that may never happen. That is, a reference architecture is often an aspirational standard, while a presumptive architecture is a de facto standard.

Architecture approaches

Architecture-indifferent design

You pay little attention to architecture. Your system may become a big ball of mud, a distinct architecture may emerge without your conscious choice, or you may be guided by norms in your domain to a presumptive architecture.

Architecture-focused design

You deliberately choose your software architecture. You design an architecture that is suitable to achieve your goals, which include functionality and quality attributes.

Architecture hoisting

A kind of architecture-focused design in which developers design the architecture with the intent of guaranteeing a goal or property of the system. Once a goal or property has been hoisted into the architecture, developers should not need to write any additional code to achieve it.

Architecture-indifferent design

Tip

Architecture-indifferent design is most suited to low-risk projects.

In architecture-indifferent design, developers are oblivious to their system’s architecture and do not consciously choose an architecture to help them reduce risks, achieve features, or ensure qualities. The developers may simply ignore their architecture, copy the architecture from their previous project, use the presumptive architecture in their domain, or follow a corporate standard.

Indifference to the architecture does not mean that the architecture is unsuitable, only that an opportunity to choose a suitable architecture was passed up. If the architecture is suitable, it is only by accident. If the architecture is unsuitable, the developers must struggle against it, but they may succeed if they are diligent and resourceful.

Drawbacks

  • can degrade over time into an unsuitable one when the team of developers lacks a shared architectural vision
  • opens the door to complexity, and once complexity has joined the party, it can be difficult to send it home
  • can be partly mitigated by mature and powerful off-the-shelf connectors and components, such as service buses and relational databases

Architecture-focused design

At a minimum, the architecture is suitable and does not impede the goals. Developers are aware of their system’s software architecture and they have chosen it deliberately so that their system can achieve its goals.

Architecture-focus design often entails reasoning about your problems using architectural abstractions (e.g. components and connectors) and architectural views (e.g. module, runtime and allocation views).

Warning

Architecture-focused design means you must be on the lookout for requirements that will influence your architecture choices, but theses requirements are rarely state clearly. They may be hidden in a cryptoc statement from a stakholder or be common to other systems in your domain.

Architecture hoisting

Architecture hoisting is a stricter kind of architecture-focused design: developers design the architecture with the intent of guaranteeing a goal or property of the system. Guarantees are difficult to com by in any kind of software design, but architecture hoisting strives to guarantee a goal or property through architecture choice.

The shift to architecture hoisting can be more subtle. Developers will notice the difference in that instead of simply choosing an architecture that lets them to do their work, they are asking the architecture to do work for them, or make their work easier.

Example

When developers are writing the code to process messages, they must be aware of the performance requirement. In the architecture-indifferent and architecture-focused designs, developers are entirely responsible for satisfying the requirement. In the architecture hoisting case, sloppy code could still result in failure (i.e., there are no guarantees), but the architecture is shouldering part of the burden through active recruitment of additional servers.

Notice that in the architecture-indifferent or architecture-focused designs there was no code that you could point to and say, “This is the code that ensures our 50ms response time.”

In contrast, with architecture hoisting you could point to the code that regulated the number of servers. When you hoist a goal or a property into the architecture, you will either find (1) code that manages it, or (2) a deliberate structural constraint (often with reasoning or calculations) that ensures it.

Examples of structural constraints would be putting sensitive data behind a firewall, or communicating via an event bus that has durability and performance guarantees.

Architecture in large organizations

Enterprise architects

Enterprise architects are developers who are responsible for many applications. Enterprise architects do not control the functionality of any one application. Instead, they design an ecosystem inside which individual applications contribute to the overall enterprise. How well the enterprise architects cultivate the ecosystem will help or hinder the enterprise in achieving its goals, usually things like integrating applications, enabling variability across regions or markets, and standardizing deployment environments.

Enterprise architects are like movie producers in that they influence the outcome only indirectly. Since they cannot directly influence qualities in the software, i.e., they cannot write code or design individual applications, enterprise architects exert influence by applying architecture-focused design or architecture hoisting.

Enterprise architects constrain the application architects by choosing architectures and constraints with the intent of achieving their desired qualities and goals.

Application architects

Application architects are developers who are responsible for a single application. It is possible for them to understand and manage thousands of objects that comprise their application. Application architects are like movie directors whose daily actions create the shape of the product. Application architects can be successful in using an architecture-indifferent approach because they design an application’s functionality in addition to its architecture. They can also apply architecture-focused design for their application, or architecture hoisting.

Pros and cons

The separation of enterprise architecture from application architecture helps a company avoid the heterogeneity and resulting chaos that would happen without a deliberate effort to standardize. This benefit comes with some challenges.

The first is the multiple-bosses problem. Developers, application architects, and enterprise architects rarely report to the same boss, which means their priorities may be different. Conflicts may arise, often regarding schedules, integration, architectural constraints, and platforms. The second problem is choosing suitable architectural constraints. Enterprise architects may over-constrain the architecture because they do not fully understand the needs of individual applications. Programmers may undervalue the benefit of standardizing across applications, believing their application should be exempted from onerous enterprise architecture constraints.

Since no organization structure is without flaws, the best you can hope for is to understand the tradeoffs and anticipate the problems. Knowing why enterprise architecture groups exist separately from development and knowing the kinds of trouble that can arise means that everyone can watch out for early warning signs and work to mitigate them

Seealso