The Discipline:

Architects (who)

Architecting (how)

Architecture (what)

Motivation (why)

Organization (where)

Lifecyle (when)

Software Architecting

How is Software Architecture Created?

by Ruth Malan

The what and the how of software architecture interact, and we recommend reading "What is Software Architecture?" There, in showing what architecture is, we're also giving a sense of how we go about it, and it lays a foundation for the discussion here.

To recap, software architecture "represents the significant design decisions that shape a system, where significant is measured by cost of change" (Grady Booch). This puts the emphasis on decisions, and Architecture Decision Records, and "shape of the system" and "cost of change," which takes us in the direction of modularity and components. Indeed, other definitions focus on "high level structures of the system, where those structures comprise software elements and the relations between them" (Clements et al, wikipedia, etc.). And if we look, for example, at C4 (Context, Containers, Components, Code) from Simon Brown, structure is a focal concern.

All this may give one with the impression that software architecting starts with the boundaries of the system and moves inwards, in a progression of decisions about structures, relationships and interactions. Well, why not start at the system boundary? This insight is salient:

"Always design a thing by considering it in its next larger context — a chair in a room, a room in a house, a house in an environment, environment in a city plan." — Eliel Saarinen [1]

Architecture and architecting across

As we design a system, we need to consider that it will reshape contexts — whether we take this into account or not, we're reshaping containing/collaborating systems. So we ought to take it into account! In use, the system takes on capabilities on behalf of users, and extends or augments their capabilities in some way; it places demands on them, while offering something in turn. It changes supply chains and value flows. The development organization forms around the system, to build, deploy and operate it, as it evolves and scales. And so forth. We're talking about sociotechnical systems, but more — sociotechnical systems in various dimensions: the system in the context of those using and interacting with it (people and other (sociotechnical) systems); the development and operations teams as sociotechnical systems within broader ecosystems of technologies and organizations. Further, systems last — if they're successful, generally longer than we expect; years and decades even. So we seek to understand value networks, opportunities and obstacles, and the systems and ecosystems that will be impacted, and how. All of this raises questions of agility (so that we can respond and adapt as we learn more), integrity, resilience and sustainability. Integrity raises questions of conceptual integrity, structural integrity, design integrity and organizational integrity (or ethics). These are not just matters of what we build, but also how we build it.

Too often, strategy and design of the system from the perspective of use (product design, capabilities, user experience, etc.), is partitioned from architecture and design of the system from the perspective of development, and further partitioned from operations. However, architecture needs to be informed by understanding of context. What the system is and does, impacts the (internal) design intimately. Decisions entails tradeoffs. And these tradeoffs are informed not just by technical considerations and impacts, but organizational and user impact. On the other hand, we're designing technical or software-intensive systems because technology brings something to the table. For both of these reasons, we urge that designers (product designers, product owners, architects) partner across these ecosystem, system-in-context (of use, development and operation) and within-the-system boundaries in design.

That said, we'll return our focus to what we generally think is the remit of architects (known variously as architects, tech leaders, devs), and architectural decision making.

A Word About Models and Views

We use sketches, diagrams, models, views to conceive and convey design ideas, express design intent, and to reflect (visualize) and reflect on design as built. They help us externalize our mental models, so that we can: think more deeply about the design; collaborate together, bringing different perspectives to bear; create sufficient common ground to bring coherence to subsequent work; probe and explore different design ideas, and "exercise" them, by running "thought experiments" and scenarios (experience led anticipatory awareness) across them. Further, as we're design-building the system, they (visualizations or visual models of facets of the system) allow us to share understandings of the nature of the system and where we see demands from its evolutionary path having an impact. They help us get ideas, share them, and probe and stress-test them, evaluating alternatives even before (more) code is written. More here: Visual Agility: Why We Model.

Software Architecture: Structural Views

The Architecture Decision model in Visual Architecting, is organized along the following lines:

Conceptual Architecture describes at a broad brushstrokes conceptual level the significant design ideas of the system. It includes diagrams and text which identify, explicate, rationalize and contextualize the key structures and mechanisms of the system, and the relationships among them.

The Conceptual Architecture Diagram (variously termed: component diagram; "box and line" diagram; etc.) renders the formative architectural abstractions (named boxes; may include a brief statement of the component's purpose or role in the system) and their interrelationships (lines). For complex systems, there may be a set of such diagrams. This (set of) view(s) addresses system decomposition (or modularity) -- so that we can cope with complexity, allow teams a degree of independence and focus, bring expertise to bear, shield parts of the system that are understood and stable from areas of experiment and volatility, allow independent evolution and replaceability, etc. And addresses system composition, to yield the capabilities of the system.

Along with the Conceptual Architecture Diagram(s), we encourage, at a minimum, keeping lists of responsibilities for each architectural element (subsystem, architectural component, microservice, etc.). This provides a start at interface design (further detailed in Logical Architecture), but importantly, these responsibilities are an key (conceptual) tool, helping us to find components, and to assess cohesion of responsibilities within a component, balance of responsibilities across components, and address the conceptual integrity of the system. DDD's Domain Model is a shaping influence for the Conceptual Architecture.

Further, the Conceptual Architecture may include design sketches and descriptions for key architectural mechanisms, addressing specific core design challenges for the system in question. Again, if more design detail is needed, we may work that out in a (set of) Logical Architecture view(s).

Logical Architecture is focused on interfaces, reminding us that API design isn't only important for external users of our services.

“It is inadequate to architect up to the boundaries or interfaces of a system; one must architect across them.” — Robert Spinrad (as reported in Rechtin and Maier)

Execution Architecture views take the physical topology or technology environment and distribution into account, considering what will be deployed, where, so that runtime implications such as remote invocation and latency, are factored into the architectural design. The cohesion and coupling considerations that are shaping concerns in Conceptual Architecture, are revisited, in view of Execution Architecture judgments, and there is an essential interaction across these views.

Behavioral Views

Software is dynamic, and while code habitability (and properties like code understandability, evolvability, team independence, etc.) is a driving force in determining shaping structure, code structures must support and enable dynamic behaviors with properties various stakeholders care about.

"We design to get more what we want" (h/t Herbert Simon), and since considerations of behavior, properties, and structure interact, we work across behavioral views and structural views. Any decomposition is not simply structural (impacting change, via cohesion and coupling and decoupling); it partitions behavior and responsibility for that behavior. We can think of it in terms of flows and transformations (i.e., processes) with realms where we've (raised or) lowered interaction barriers and created zones of responsibility focus; in terms of theory of the operation (how this design works) and theory of organization.

Key dynamic views include interaction diagrams like sequence diagrams or communication diagrams, which help us identify, and evaluate our thinking about, component responsibilities, coupling, and interface design, and think through different architectural alternatives and their implications for various capabilities, properties and tradeoffs. State(-chart) diagrams are another important modeling tool, especially useful for modeling responses to events, and state dependent considerations (eg, expressing message protocols in interface design). Timing diagrams combine sequence diagram and state diagram aspects. Activity diagrams are sometimes used to express components as agents with roles and responsibilities or commitments, and interactions or responses. I wouldn't use all of these for they overlap — sequence diagrams can be translated into communication diagrams; I'd use either timing diagrams or state diagrams. And only use them as needed, to either explore behavior (in making design decisions) or to express and convey the design (in conversations and documents). Moreover, while UML and sysML are very useful (give us a visual language we can use as we need), ad hoc diagrams increase our expressive range. Event Storming also bridges "problem" and "solution" exploration, understanding and design, with an emphasis on exploring the domain of the system (the business process and activities that the system in operation and use supports, and domain events), which have implications for conceptual design (looking for natural internal system boundaries and co-ordinating events).

One response to "how?" then, is iterating across structural and behavioral views, and between conceptual and execution (deployment and process) architecture views. Using modeling to think through, and work collaboratively on, these shaping decisions.

Heuristics

Another response to "how?" is that we bring judgment to bear. We develop, through direct and indirect experience, "a considerable body of contextual sense" -- that is, "a knowledge of what is reasonable within a given context" (Rechtin, 1991). Engineering heuristics, or rules of thumb, are "statements of common, or contextual, sense that aid in concept development, problem solving, decision making, or judgment"(Rechtin, 1991). They can be descriptive (what is the situation) or prescriptive (what to do about it) (Rechtin, 1991).

"Heuristics offer plausible approaches to solving problems, not infallible ones." — Rebecca Wirfs-Brock

In talks on software architecture, Grady Booch points [minute 43+] to what he characterizes as "the fundamentals that remain fundamental":

which I resequenced as shown above, to give us the mnemonic, SCARS. Which is appropriate, since SCARS are what we get from experience. SCARS is used to organize sets of heuristics specifically related to architecture structuring here: Architecture Clues: Heuristics, Part i. SCARS

Top Down? No, Not Like That

But! We must caution: the short answer to "How?" is "Non-linearly." There is no step a to z. Decisions interact. We backtrack, as we learn more. Sure, we need to have sufficient experience to suspend discomfort with the ambiguities and uncertainties that come with complex system design and evolution, while judiciously making decisions to resolve some uncertainty so we can move forward.

Why?

Simply put, design is about making things more the way we want them to be:

"everyone designs who devises courses of action aimed at changing existing situations into preferred ones" — Herbert Simon, 1988 [2]

And this is non-obvious and non-trivial to the extent that we are making tradeoffs, and these tradeoffs interact with other decisions we're making or have made — and (others) will make.

'For me, "engineer" means knowing that all decisions are tradeoffs. It means considering both upsides & downsides of each technical choice, and doing so with explicit consideration of the larger system context.' — Sarah Mei (2019)

To surface and understand constraints we need to take into account, tradeoffs we're making, and the impact, effects and side-effects of these tradeoffs, we need to understand context:

"Design quality is not a property of the code. It's a joint property of the code and the context in which it exists." — Sarah Mei (2017)

Further! There are multiple contexts we need to take into account. While the development context is a source of shaping forces (for example: team in(ter)dependence and changeability/evolvability of the code), the operations context (system health as load varies; etc), the various contexts of use, and the broader value flows in the ecosystem context, also factor.

“We're trying to find habitable zones in a large multidimensional space, in which we're forced to make regrettable, but necessary, tradeoffs” — Robert Smallshire (2018)

Hence, (whether we're starting out on a "greenfields" initiative, or seeking to make architecture more intentional, for an existing system) we encourage starting with sufficient exploring and understanding of the strategic context to inform strategy (at the scope of the system), and sufficient capability design to inform and shape system identity and inform and make architecture decisions.

That is, we’re not only seeking to define architectural elements and make other significant technical decisions, we’re co-designing and co-evolving complex systems — of systems — and our "theory" (in the Peter Naur sense, where we build up our "theory," or mental models, of the system and how it relates to demands on it) of the context and system as intended and as built.

A (software-intensive) system (so its design) changes the larger social and sociotechnical systems it interacts within (so its context). We need to take this co-learning (symmathesy) into account in design (of design).

"the problem itself is grasped in the course of the design process." — Christiane Floyd [3]

"We do not analyze requirements; we construct them from our own perspective. This perspective is affected by our personal priorities and values, by the methods we use as orientation aids, and by our interaction with others” — Christiane Floyd [3]

"The installation of the program together with its associated system [..] change the very nature of the problem to be solved. The program has become a part of the world it models, it is embedded in it. Analysis of the application to determine requirements, specification, design, implementation now all involve extrapolation and prediction of the consequences of system introduction and the resultant potential for application and system evolution." — Meir Lehman [4]

"Software development is an activity of overall design with an experimental attitude" — Peter Naur [5]

"Design designs." — Tony Fry

What is being argued here, is that the "how" of architecting is bound up with (influences and is influenced by) the "how" of strategy and the "how" of design of what the system is (purpose and identity, and capabilities and properties), not just the "how" of shaping the system internals and dynamics, and technology choices. We advocate design across boundaries, not just to bring understanding of sought capabilities and properties to the design of the system (internals), but to bring understanding of technical capabilties to design of the system capabilities and properties, and to strategy setting.

Back to the Focal How

Still, returning to architecting the system: we're crafting structures and interactions, and mechanisms, iterating between the domain (bounded contexts and event storming) and what the domain structure and dynamics suggests in terms of identifying components; between design of system capabilities and design of components and responsibilities; and iterating between structure and behavior, exploring how components interact or collaborate to yield those capabilities with more the properties we want. And exploring how the topology of the compute infrastructure interacts with our design choices (for example: impacts latency, coordination mechanisms, scaling). That is, we're iterating across boundaries within the system, considering cohesion (of responsibilities within) and coupling (aiming, generally, for loose); considering constraints and tradeoffs (among impacted system properties); considering outcomes sought and side-effects or consequences of different design alternatives or approaches. And all these decisions are impacting the systems our system interacts within (dev, ops, use). Design means taking that impact into account, learning as we progressively design and deliver the system.

It's a learning (feedback and rethinking) intensive process. We're learning what the system is becoming as we're designing how (better) to build it. This sounds alarming. Too hard. Too much uncertainty. Too much to hold in mind — and it's all changing! First. That's real. But also, we progressively shape our systems. We add complexity over time, and shield much of it by building with and on abstractions. And incrementally learn, respond to feedback, and get new ideas. Further, our system, and its architecture, goes through eras of relative stability, between larger more disruptive architectural changes (driven by significant shifts in forces, due, for example, to increases in users/use and reaching the limits of the design fitness or performance envelope of our current architecture).

Back to Modeling

Yet it remains a lot, and make-or-break to boot, so we're not, or shouldn't, be doing this without giving ourselves a cognitive boost. For emphasis (especially for those who dropped visual modeling when UML became "uncool"): we use sketches, diagrams, models of (facets of) the system (capabilities and properties; structure and behavior; key challenges and architectural mechanisms), to observe and better understand, to think and reason about, to think and explore together bringing more perspectives and experience to bear, and to probe and test.

the architecting process is iterative

We use sketches and modeling as a way to be agile — to learn in the cheapest medium that will uncover key issues, alternatives, and give us a better handle on our design approach. This may be code, but there's much we can learn, bringing different perspectives and experiences to the table, with a marker and some modeling.

“Perspectivity necessarily entails blindness. I cannot see what I cannot see from my perspective.” — Christiane Floyd [3]

Not to do this as Big Modeling Upfront, but to have and apply our modeling skills early, to understand and shape strategic opportunity, and to set design direction for the system. And to return to modeling whenever that is the cheapest way to explore a design idea, just enough, just in time, to get a better sense of design bets worth investing more in, by building the ideas out and deploying at least to some in our user base, to test more robustly.

As we explore options and implications, we're drawing on experience and contextual sense. Alternately put, we draw on and apply design sense we've developed directly, and through patterns and heuristics or rules of thumbs we've learned from others.

But What About .. Architecture Patterns?

Architecture patterns address architecturally significant concerns. There are those that guide the architecture or organizing structure of the system (e.g., hexagonal architecture pattern, microservices, etc.), and those that address specific (architecturally significant) mechanisms (e.g., circuit breaker pattern). Design patterns (including architecture patterns) articulate design reasoning addressing a well-identified (framed in terms of outcome, forces and constraints) challenge. They can form useful starting points, but also serve to prompt thinking into view, by considering trade-offs exposed by the established pattern. Design patterns are argued/reasoned/explained structural elements or mechanisms — recorded to move understanding, not substitute for it.

And What About .. Technical Strategy?

We've given a brief overview of the core of the architecture decision model, but what about technical strategy? In short, it expresses strategic technical direction. That is, while the software architecture expresses design decisions — those that are architecturally significant — technical strategy guides those architecture and other design decisions. This is where, for example, Wardley Maps play a prominent role. We also consider technology and market trends, and what we see shaping up in the user and technology space, in context maps and technology radars. And we express architectural guidance in the form of architecture principles, and architecture patterns.

More on Visual Architecting

In our work on Visual Architecting, we integrate what we have learned from effective architects, and good as well as failed architectures, to help you create a software architecture that is:

The last [successful], is speaking to the organizational dimension of the architect's role that is missing from "right system [right], built right [good]”. It is very much about ensuring that conversations that need to be happening are happening — not always initiating them, nor always helping to focus or navigate them, but ensuring they do happen and guiding when needed.

Visual Architecting covers the techniques, including architecture modeling and architecture trade-off analysis, used in creating a technically sound architecture. It covers understanding stakeholders and design of system capabilities and properties and prioritization to create the right architecture, together with stakeholder feedback to create/evolve a more right architecture. And it includes what we do organizationally to help ensure that, ultimately, the system (and hence its architecture) is successful.

For an overview of our approach to architecting systems, see Visual Design and Architecture (2019) and our chapbook on Decisions and Technical Leadership (pdf) (2020).

More on Architects: Role? Responsibilities Everyone Holds? Both?

So we're talked about architecture and architecting, but is "architect" a hat everyone wears, or a role (and if so, that title)? That is explored in the Architect (who) section.

 

References

[1] Eero Saarinen (in interview), "The Maturing Modern," Time Magazine, 7/2/56, pp-50-57.

[2] Herbert A. Simon, The Science of Design: Creating the Artificial, (pdf) 1988

[3] Christiane Floyd, “Software Development as Reality Construction,” (pdf) 1992

[4] Meir Lehman, "Programs, Life Cycles, and Laws of Software Evolution." (pdf) 1980

[5] Peter Naur, "Programming as Theory Building," ("Software development is an activity of overall design with an experimental attitude" — Peter Naur [4]) 1992

[6] Eberhardt Rechtin, Systems Architecting: Creating and Building Complex Systems, 1991

 

Other Reading

See also:

Restrictions on Use: If you wish to quote or paraphrase fragments of our work in another publication or web site, please properly acknowledge us as the source, with appropriate reference to the article or web page used. Any commercial use must be authorized by Bredemeyer Consulting.

Written by: Ruth Malan

Copyright © 2020 by Bredemeyer Consulting
URL: https://www.bredemeyer.com
Page Created: November 1999
Last Updated: July 18, 2020