Part I — Software Architecture Fundamentals · Chapter 2

What Software Architecture Is

~40 min read4 interactive widgets4 plates

In this chapter

  1. The power and the limits of the building analogy
  2. Two definitions of software architecture
  3. Three kinds of structures
  4. Functionality is not architecture
  5. Architecture characteristics, NFPs, quality attributes
  6. Quality Attribute Scenarios
  7. Architectural drivers: functionality, concerns, constraints
  8. The architecture lifecycle activities
  9. Thinking like an architect
  10. Check your understanding

1. The power and the limits of the building analogy

The discipline borrowed its name from the architecture of buildings, and the analogy is genuinely instructive on three points:

And it is instructive on a fourth: architectural styles arose in building architecture as the accumulated experience of previous generations of architects and building-dwellers — a set of constraints put upon development in order to elicit particular desirable qualities. Hold on to that definition; Chapter 3 uses exactly the same words for software.

But the module also insists on where the analogy breaks:

Careful — where the analogy fails

The nature of the medium is fundamentally different. Software is far more malleable than physical building materials, offering types of change that are unthinkable in a physical domain. As a follow-up, the building analogy is a poor source of ideas for dealing with change, since buildings accommodate change with difficulty. Every time you hear “you cannot change the foundations once they are poured”, remember that in software you very often can — and the whole of Part III of this course is about making that possible.

2. Two definitions of software architecture

There is no single definition or viewpoint in the literature. The course works with two, and they are complementary rather than competing.

SourceDefinition
[SAP] Bass et al., Software Architecture in Practice“The software architecture of a system is the set of structures needed to reason about the system. These structures comprise software elements, relations among them, and properties of both.”
[FSA] Richards & Ford, Fundamentals of Software Architecture“A software architecture consists of the structure of the system, combined with architecture characteristics or qualities the system must support, architecture decisions, and finally design principles.”

The second definition is the more operational one, because it names four distinct things that you must be able to tell apart.

SOFTWARE ARCHITECTURE STRUCTURE the architecture style(s) the system is implemented in: microservices, layered, microkernel CHARACTERISTICS the success criteria, generally orthogonal to functionality: the "-ilities" DECISIONS RULES for how the system should be constructed; they constrain the teams DESIGN PRINCIPLES GUIDELINES rather than hard-and-fast rules; they orient, they do not forbid
Plate 2.1 — Architecture as four dimensions [FSA]. Answering “it is a microservices architecture” describes only the top-left box: you have given the structure, not the architecture.
For the exam

The book’s own example: if an architect is asked to describe an architecture and answers “it is a microservices architecture”, that architect is only talking about the structure of the system. Knowledge of the architecture characteristics, the architecture decisions and the design principles is also needed to fully understand the architecture. The difference between a decision and a principle is likewise examinable: a decision is a hard-and-fast rule that constrains what is and is not allowed; a design principle is a guideline.

3. Three kinds of structures

[SAP] uses an analogy with the human body: the same organism admits several different physiological structures — skeletal, circulatory, nervous — and no single one of them is the body. Software systems are the same. There are three kinds of software structures.

Runtime view of the system. It focuses on the way the elements interact with each other at runtime to carry out the system’s functions, describing how the system is structured as a set of elements that have runtime behaviour (components) and interactions (connectors).

  • Components are the principal units of computation: services, peers, clients, servers, filters or many other types of runtime element. A component is state + behaviour + interface.
  • Connectors are the communication vehicles among components: call-return, process synchronisation operators, pipes, event bus, and others.

C&C structures answer questions such as: what are the major executing components and how do they interact at runtime? What are the major shared data stores? Which parts of the system are replicated? How does data progress through the system? Which parts can run in parallel? Can the system’s structure change as it executes, and if so how?

By extension, these structures are crucially important for asking questions about the system’s runtime properties — performance, security, availability.

Static view of the system. It describes how a system is structured as a set of modules, where a module is an implementation unit — a code or data unit, including packages, classes and layers. Typically modules are assigned specific computational responsibilities and are the basis of work assignments for programming teams.

Module relations include uses, generalization (“is-a”) and is-part-of; UML notation is the usual vehicle. Module structures answer: what is the primary functional responsibility assigned to each module? What other software elements is a module allowed to use? What does it actually use and depend on? Which modules are related by generalization or specialization?

Examples of module structures: decomposition structure, uses structure, layer structure, generalization structure, data model. In a layer structure a layer is an abstract “virtual machine” providing a cohesive set of services through a managed interface; in a strictly layered system a layer may only use a single adjacent layer.

Allocation structures establish the mapping from software structures to the system’s non-software structures — such as its organisation, or its development, test and execution environments.

  • Deployment structure — which software runs on which hardware/execution environment. This is the structure that carries performance, data integrity, security and availability concerns in distributed systems.
  • Implementation structure — how software elements are mapped onto the file structures in the system’s development environment.

Note that the third structure is the one that becomes decisive in Part III: whether two pieces of code are in the same deployment unit or on opposite sides of a network is an allocation fact, and it changes everything about the qualities of the system.

MODULE (static) ui.web order.domain order.persistence packages, classes, layers relations: uses, is-a, part-of C & C (runtime) client service worker event bus components = units of computation connectors = communication vehicles ALLOCATION (deploy) node: app-server-1 client service node: db-cluster database software mapped onto non-software structures ONE system, THREE structures. None of them alone is "the architecture". Module answers: who is allowed to use what? Which team owns this code? C&C answers: what runs in parallel? Where does data flow? What is replicated? Allocation answers: what fails together? What can be scaled independently? Chapter 5: the architecture quantum is defined precisely on the allocation structure ("independently deployable") plus the C&C one ("synchronous dynamic coupling").
Plate 2.2 — The three structures side by side. Reading a system through only one of them is the commonest source of architectural blind spots.

4. Functionality is not architecture

Functionality is the ability of the system to do the work for which it was intended — the system’s capabilities, services and behaviour, defined by functional properties or requirements.

Software architectures can help satisfy functional requirements through effective compositions of well-defined components and connectors. But the module states the crucial negative claim twice, and it is worth reading slowly:

Key idea

Functionality per se does not determine architecture. Given a set of required functionality, there is no end to the architectures you could create to satisfy it. Functionality is independent of any particular structure — but it is achieved by assigning responsibilities to architectural elements. In terms of architectural design, therefore, it is the allocation of functionality to elements, rather than the functionality per se, that matters.

Module 1.3 sharpens this into a design criterion. We can have all the functionality of a system coded in a single enormous module, or neatly distributed across many smaller, highly cohesive modules; externally the system will look and work the same way if you consider only functionality. What matters is what happens when we want to change it: in the first case changes will be difficult and costly, in the second much easier and cheaper. Hence:

A good architecture is one in which the most common changes are localised in a single or a few elements, and hence easy to make.

Primary functionality

When designing an architecture we need to consider at least the primary functionality: functionality that is critical to achieve the business goals that motivate the development of the system. Other criteria for primary functionality: it implies a high level of technical difficulty, or it requires the interaction of many architectural elements. As a rule of thumb, approximately 10 per cent of your use cases or user stories are likely to be primary.

5. Architecture characteristics, NFPs, quality attributes

Three names circulate for closely related notions, and the course uses them near-interchangeably while noting their nuances.

TermDefinition used in the course
Architecture characteristic [FSA]Defines the success criteria of a system, generally orthogonal to the functionality. The characteristics do not require knowledge of the functionality of the system, yet they are required for the system to function properly. Colloquially: the “-ilities”.
Non-functional property (NFP)A constraint on the manner in which the system implements and delivers its functionality. Important NFPs include security, reliability, availability, efficiency, scalability and fault tolerance.
Quality attribute (QA) [SAP]A measurable or testable property of a system used to indicate how well the system satisfies the needs of its stakeholders beyond the basic function of the system.

The three criteria of an architecture characteristic

An architecture characteristic meets three criteria [FSA]:

  1. It specifies a non-domain design consideration — it is domain independent.
  2. It influences some structural aspect of the design.
  3. It is critical or important to application success — and deciding which ones are is a key responsibility of the architect.

Methodologically, the point of naming them early is traceability: software engineering methodology stresses doing the correct things from the very beginning of the process in order to curb development and maintenance costs — codifying NFPs such as availability, security and fault tolerance early on in the architectural models, and maintaining their traceability across the system’s artefacts and throughout its lifespan.

Ways of categorising qualities

There are multiple ways to characterise or categorise qualities:

The last split is the one the course uses operationally:

RuntimeDevelopment time
Availability · Performance · Safety · Energy efficiency · Security · Usability · Efficiency · Adaptability · Scalability and heterogeneity · Dependability · ComplexityDeployability · Integrability · Modifiability · Testability

The broader catalogue of software qualities from [FSA] adds: correctness, reliability, robustness, verifiability, maintainability, reparability, evolvability, reusability, portability, understandability, interoperability, productivity, timeliness, visibility.

6. Quality Attribute Scenarios

Identifying the driving quality attributes is one of the first steps in creating an architecture, or in determining the validity of an existing one. It requires the architect not only to understand the domain problem but to collaborate with problem-domain stakeholders to determine what is truly important from a domain perspective: an architect uncovers architecture characteristics by extracting them from domain concerns, requirements and implicit domain knowledge.

Two problems that made this hard

Quality attributes have been studied since the 1970s, with a variety of taxonomies and definitions published. Two problems persisted:

  1. The definitions provided for an attribute are not testable. “The system shall be highly available” cannot be checked.
  2. Each attribute community has developed its own vocabulary. The performance community has “events” arriving at a system, the security community has “attacks”, the availability community has “faults”, the usability community has “user input”. All of these may actually refer to the same occurrence, described in different terms.

Quality Attribute Scenarios (QAS) are the principled approach introduced to tackle both. A QAS introduces a common form to specify all QA requirements as scenarios that are testable and unambiguous, not sensitive to whims of categorisation, and that provide regularity in how we treat all quality attributes.

The six parts

SOURCE who/what emits STIMULUS the event hits ARTIFACT whole system, or one precise piece ENVIRONMENT normal / overload / dev / test / recharging yields RESPONSE what happens RESPONSE MEASURE makes it TESTABLE SAMPLE AVAILABILITY SCENARIO (from the module): source: a server in a server farm | stimulus: fails | artifact: the system environment: during normal operation | response: informs the operator and continues to operate | response measure: with no downtime Same six slots for performance, security, modifiability, testability. That is the point.
Plate 2.3 — The anatomy of a Quality Attribute Scenario. Every quality attribute, whatever its community’s jargon, is forced into the same six slots.
PartDefinitionNotes from the module
StimulusAn event arriving at the system or the projectAn event to the performance community, a user operation to the usability community, an attack to the security community. For developmental qualities: a stimulus for modifiability is a request for a modification; for testability, the completion of a unit of development.
Stimulus sourceSome entity — a human, a computer system, any other actor — must have generated the stimulusThe source may affect how the stimulus is treated by the system.
ArtifactThe target the stimulus arrives atOften captured as just “the system”, but it is helpful to be more precise: a failure in a data store may be treated differently from a failure in the metadata store; modifications to the UI may have faster response times than modifications to the middleware.
EnvironmentThe set of circumstances in which the scenario takes placeOften a runtime state — overload condition, normal operation, a specific mode. But it can also refer to states in which the system is not running at all: in development, in testing, refreshing its data, recharging its battery between runs.
ResponseThe activity that occurs as a result of the arrival of the stimulusThe responsibilities that the system (runtime qualities) or the developers (development-time qualities) should perform.
Response measureThe response must be measurable so that the scenario can be testedFor performance: latency or throughput. For modifiability: the labour or wall-clock time required to make, test and deploy the modification.

Performance scenarios are about time and the system’s ability to meet timing requirements: when events occur — interrupts, messages, requests from users or other systems, clock events marking the passage of time — the system, or some element of it, must respond in time. Performance is often linked to scalability, that is, increasing the system’s capacity for work while still performing well.

7. Architectural drivers: functionality, concerns, constraints

Architectural design starts by gathering architectural drivers. Quality attributes are one class of driver; the module names three more.

Architecturally Significant Requirements (ASRs)

Among all the requirements, ASRs are those that have particular importance with respect to the software architecture: the most important functionality and the constraints that need to be taken into account, defining the main quality attributes. Put sharply: the set of properties that, if not satisfied by your system, will cause the system to be a failure. ASRs are gathered from requirements documents, by interviewing stakeholders, and by understanding the business goals.

Architectural concerns

Concerns encompass additional aspects that must be considered as part of architectural design but that are not expressed as traditional requirements. Four types:

TypeExamples
General concernsBroad issues: establishing an overall system structure, allocation of functionality to modules, allocation of modules to teams, organisation of the code base, startup and shutdown, supporting delivery, deployment and updates
Specific concernsMore detailed system-internal issues common across large numbers of applications: exception management, dependency management, configuration, logging, authentication, authorization, caching
Internal requirementsRequirements usually not specified explicitly in requirement documents, because customers seldom express them: aspects that facilitate development, deployment, operation or maintenance
IssuesResults of analysis activities such as a design review, so they may not be present initially — e.g. an architectural evaluation may uncover a risk requiring changes to the current design

Architectural constraints

The design process must consider the list of possible constraints on development: the decisions over which architects have little or no control. Mandated technologies; other systems your system must interoperate or integrate with; laws and standards that must be complied with; the abilities and availability of your developers; non-negotiable deadlines; backward compatibility with older versions.

Constraints can be technical (“the use of open source technologies”) or non-technical (“the system must be compliant with GDPR”, “the system must be delivered by 22 November”).

Design concepts: the reusable answers

The community has evolved, over decades of dealing with quality attributes in practice, a body of generally accepted design principles that guide us towards high-quality designs with predictable outcomes. These abstract principles lead to concrete reusable realisations — design concepts, the building blocks from which the structures that make up the architecture are created:

8. The architecture lifecycle activities

Software architecture life-cycle activities are part of the software project life cycle: they are the translation of requirements into a design into an implementation.

ARCHITECTURAL REQUIREMENTS precedes ARCHITECTURAL DESIGN precedes ARCHITECTURAL DOCUMENTATION ARCHITECTURAL EVALUATION ARCHITECTURAL IMPLEMENTATION influences evaluation feeds back
Plate 2.4 — The five life-cycle activities. Evaluation does not sit at the end as a rubber stamp: it influences implementation and can send you back to requirements.

Architectural documentation

Some level of preliminary documentation (or sketches) of the structures is created as part of architectural design; architectural documentation refers to the creation of a more formal document from those sketches — UML-based or other views such as C4 or 4+1.

How much? If the project is small and has a precedent, documentation may be minimal. If it is large, if distributed teams are collaborating, or if significant technical challenges exist, then architectural documentation will repay the effort invested. The module adds a pointed remark: while documentation is often avoided in software, it is a standard, non-negotiable deliverable in almost every other engineering discipline — in other disciplines a “blueprint” is an absolutely essential step before committing resources.

Implementation and evaluation

9. Thinking like an architect

Eight core expectations [FSA]

  1. Make architecture decisions
  2. Continually analyze the architecture
  3. Keep current with latest trends
  4. Ensure compliance with decisions
  5. Diverse exposure and experience
  6. Have business domain knowledge
  7. Possess interpersonal skills
  8. Understand and navigate politics

Note that only the first four are technical, and even those include ensuring compliance — which Chapter 5 will mechanise as governance and fitness functions. The remaining four are the reason the introductory module quotes the “architect elevator” image: the architect rides between the penthouse where strategy is decided and the engine room where code is written.

Four aspects of architectural thinking

Architectural thinking is more than “thinking about the architecture”: it is seeing things with an architectural eye. Four aspects:

  1. Understanding the difference between architecture and design, and knowing how to collaborate with development teams to make architecture work.
  2. Having a wide breadth of technical knowledge while still maintaining a certain level of technical depth, allowing the architect to see solutions and possibilities that others do not see.
  3. Understanding, analysing and reconciling trade-offs between various solutions and technologies.
  4. Understanding the importance of business drivers and how they translate to architectural concerns.

Breadth versus depth

The nature of knowledge changes as developers transition into the architect role. A developer is characterised by technical depth; an architect by technical breadth. What someone knows is technical depth; how much someone knows is technical breadth. As the module puts it: as an architect, it is more beneficial to know that five solutions exist for a particular problem than to have singular expertise in only one.

Architects and development: traditional versus modern view

In the traditional view, the architect analyses business requirements to extract and define the architecture characteristics, selects which patterns and styles fit the problem domain, and creates components; those artefacts are then handed off to the development team, which creates class diagrams, designs UI screens and writes and tests source code.

Careful — why this model fails

The problem is the unidirectional arrow passing through the virtual and physical barriers that separate the architect from the developer. Decisions an architect makes sometimes never make it to the development teams, and decisions development teams make that change the architecture rarely get back to the architect. In this model the architect is disconnected from the development teams — and as such the architecture rarely provides what it was originally set out to do.

In the modern view, both the physical and virtual barriers between architects and developers must be broken down, forming a strong bidirectional relationship. Unlike old-school waterfall approaches to static and rigid architecture, the architecture of today’s systems changes and evolves every iteration or phase of a project. A tight collaboration between the architect and the development team is essential for the success of any software project.

Check your understanding

Give the [SAP] definition of software architecture, and say what the [FSA] definition adds.

[SAP]: “the set of structures needed to reason about the system; these structures comprise software elements, relations among them, and properties of both.” [FSA] adds three further dimensions beyond structure: the architecture characteristics (qualities the system must support), the architecture decisions (rules for how the system should be constructed) and the design principles (guidelines rather than hard rules).

What are the three kinds of software structures, and what question does each answer?

Component-and-Connector — the runtime view: which components execute, how they interact, what is replicated, what runs in parallel, how data progresses, whether the structure can change while executing. Module — the static view: what functional responsibility each implementation unit carries, what it is allowed to use, what it actually depends on, inheritance relations. Allocation — the mapping from software structures to non-software structures such as the organisation and the development, test and execution environments (deployment structure, implementation structure).

Why does the module say that functionality does not determine architecture?

Because given a set of required functionality there is no end to the architectures that could satisfy it: functionality is independent of any particular structure. What matters architecturally is the allocation of functionality to elements. The test is change: the same functionality in one enormous module and in many cohesive modules looks identical from outside, but the cost of changing it differs enormously. Hence a good architecture is one in which the most common changes are localised in one or a few elements.

What three criteria must something meet to count as an architecture characteristic?

(1) It specifies a non-domain design consideration, i.e. it is domain independent; (2) it influences some structural aspect of the design; (3) it is critical or important to application success. Selecting which characteristics matter is a key responsibility of the architect.

Which two problems do Quality Attribute Scenarios solve?

First, that the definitions provided for quality attributes are not testable (“the system shall be highly available” cannot be checked). Second, that each attribute community developed its own vocabulary: performance speaks of events arriving, security of attacks arriving, availability of faults arriving, usability of user input — possibly all referring to the same occurrence. A QAS gives one common, testable, unambiguous form for all of them.

List the six parts of a QAS and give the modifiability instance of each of the first two.

Stimulus, stimulus source, artifact, environment, response, response measure. For modifiability the stimulus is a request for a modification, and its source is whoever raised it (a stakeholder, a regulation, an internal team). Note that for developmental qualities the response is performed by the developers, not the system, and the response measure is typically the labour or wall-clock time needed to make, test and deploy the modification.

Can the environment part of a scenario describe a system that is not running?

Yes, explicitly. The environment is the set of circumstances in which the scenario takes place; often a runtime state (normal operation, overload, a specific mode) but it can also refer to states in which the system is not running at all: when it is in development, in testing, refreshing its data, or recharging its battery between runs. The environment sets the context for the rest of the scenario.

Distinguish architecturally significant requirements, concerns and constraints.

ASRs are the subset of requirements with particular importance for the architecture — the properties that, if unsatisfied, make the system a failure. Concerns are aspects that must be considered in design but are not expressed as traditional requirements: general concerns (overall structure, allocation of modules to teams, startup/shutdown, delivery), specific concerns (exception management, logging, caching, authorization), internal requirements (things customers never state) and issues (findings from reviews). Constraints are the decisions over which architects have little or no control — mandated technologies, laws and standards, deadlines, backward compatibility — and can be technical or non-technical.

What is “primary functionality” and how much of the requirements is it, as a rule of thumb?

Functionality that is critical to achieve the business goals motivating the development of the system; other criteria are a high level of technical difficulty or the need for interaction among many architectural elements. As a rule of thumb, approximately 10 per cent of use cases or user stories are likely to be primary.

Name the five architecture life-cycle activities in order, and the relation between the last two.

Architectural requirements precede architectural design, which precedes architectural documentation, which precedes both architectural evaluation and architectural implementation. Evaluation influences implementation — it is “testing the design”, performed by architects and stakeholders before the implementation stage, to ensure the decisions taken are appropriate for the critical requirements.

What distinguishes an architect from a developer in terms of knowledge?

A developer is characterised by technical depth (what someone knows); an architect by technical breadth (how much someone knows). For an architect it is more beneficial to know that five solutions exist for a problem than to have singular expertise in only one — because the architect’s job includes understanding, analysing and reconciling trade-offs between solutions.

Why does the traditional architect/developer model fail, and what replaces it?

It fails because of the unidirectional hand-off: the architect defines characteristics, patterns and components and throws them over a virtual and physical barrier to the development team. Decisions the architect makes never reach the teams, and decisions the teams make that change the architecture never get back to the architect, so the architecture rarely provides what it set out to do. The modern view breaks both barriers and builds a bidirectional relationship: today’s architectures change and evolve every iteration, so tight collaboration is essential.