The Discipline:

Architects (who)

Architecting (how)

Architecture (what)

Motivation (why)

Organization (where)

Lifecyle (when)

 

 

Software Architecture and Related Concerns

by Ruth Malan

What is Software Architecture?

"Architecture represents the significant design decisions that shape a system, where significant is measured by cost of change." -- Grady Booch

What follows, uses Grady Booch's characterization of software architecture as a flywheel of sorts, giving impetus to an elaboration of our notion of architecture.

Preamble

How we approach architecture, defines what architecture, in effect, is, at least for our system. That is, no matter what we say architecture is (for), architecture is (an outcome of) what we do. This is a POSIWID (the purpose of a thing is what it does -- Stafford Beer) kind of point, noting that what the thing does, trumps what we may think it is and ought to do.

Still, intentions influence behavior. How we conceive of architecture, influences what we do. If we think software architecture is a set of decisions, say, we're going to try to notice when we're making a decision so we can write it down. If we think architecture is diagrams or maps, we'll direct attention there.

In short, what we do in the name of architecture, shapes what it is; what we think it is, shapes what we do.

At any rate, what follows is an iterative elaboration towards a richer understanding of what software architecture is, to inform how we advocate approaching the architecture of systems we're design-evolving.

An Iterative Elaboration of Software Architecture

Beck

If we go back to 1992, we already see one of the narrative threads that have shaped our conceptualization of, and discourse around, software architecture, architects, and architecting:

“Mr. Beck, what is software architecture?”

“Software architecture?” replied Kent, “well, it is what software architects do.”

“So then, what is an architect?”

“Hum, ‘software architect’ it’s a new pompous title that programmers demand to have on their business cards to justify their sumptuous emoluments.”

[source: What do software architects do? Philippe Kruchten]

Fowler

A (little over a) decade later, in 2003, we have Martin Fowler (in "Who needs an architect?") similarly perplexed, and quoting Ralph Johnson:

"Tell us what is important.” Architecture is about the important stuff. Whatever that is."

Architecture is decisions

Let's sidestep the discomfort we have with someone (else?) doing "the important stuff" and getting "sumptuous emoluments," for a moment anyway, and follow the arc of software architecture to its recurrent destination, namely Grady Booch and

"Architecture represents the significant design decisions that shape a system."

Decisions!

Decisions! We haz template

Decisions?

Michael Nygard's post on Documenting Architecture Decisions presents a useful template. It has echoes of the patterns template used by the Gang of Four, and subsequent, in that it draws attention to the essential elements of Context (presenting forces and demands) and Consequences, not just the Decision itself.

It's a template I and others recommend (though I like to add Alternatives Considered). Still, too much of a good thing sinks itself under its own weight, so an Architecture Decision Record leaves itself begging the question -- which decisions?

Which decisions though

Which decisions?

Architecturally significant decisions! Which are architecturally significant? The architect decides!

[Aside: note that this playful tautology means anyone who makes architecture decisions is in effect an architect, no matter their title or role.]

Architecture is significant decisions

On what basis? Returning to Grady Booch: "significant is measured by cost of change"

If you think good architecture is expensive, try bad architecture

"Bad architecture is expensive" -- paraphrasing Brian Foote, coauthor of the must-read classic "Big Ball of Mud"

Big ball of mude architecture

The opening sentence to that paper observes that the de-facto standard in software architecture is <drum roll> "the big ball of mud" <badum tish>

Big ball of mud

When you have a "big ball of mud," as Michael Stahl vividly put it "you reach for the banana, and get the entire gorilla."

Now that sketch is an idealization...

tangled

in "real life," the degree of entanglement is more like this... [above]

[Image: from Undoing the harm of layers by Bjørn Bjartnes]

Modularity

By contrast, a modular structure reduces cost of change by (and to the extent that it achieves) isolating change, shielding the rest of the system from cascading change.

In a modular approach, parts of the system that are unstable, due to uncertainty and experimentation to resolve that uncertainty, can be shielded from other, better understood and more stable parts of the system.

Parts can be plugged in, but removed if they don't work out, making for reversibility of decisions that don't pan out. They can be replaced with new or alternative parts, with minimal effect on other parts of the system, enabling responsiveness to emerging requirements or adaptation to different contexts.

Further, it's a mechanism to cope with, and hence harness, complexity. Partitioning the system, reduces how much complexity must be dealt with at once, allowing focus within the parts with reduced demand to attend (within the part) to complexity elsewhere in the system. We give a powerful programmatic affordance a handle with minimal understanding to invoke it, and can selectively ignore (not all the time, but for a time), or may never even need to know (it depends), its internals. Modularity is a way we cope with our "bounded rationality" (Herbert Simon) and limit "cognitive load" placed on teams (Team Topologies, Skelton and Pais).

Fowler concedes

So modularity and parts, or components, is key to managing change and associated costs. Returning to Martin Fowler's paper, indeed software architecture is acknowledged to include how the system is divided into components, and how they interact.

 

Perry and Wolf definition of sw architecture

Going back to 1992, when Kent Beck was giving the architecture-architects thing a ¯\_(ツ)_/¯, Perry and Wolf were defining (software) architecture as being concerned with "the selection of architectural elements, their interactions, and the constraints on those elements and their interactions."

[Hopefully those who are excited about Alicia Juarrero's work on constraints (1999), are tingly at the foreshadowing in Perry and Wolf's characterization (1992).]

software architecture is elements and relations

And, indeed, the contemporary go-to reference definition for software architecture (that being the definition in wikipedia which, in this case, derives from that of the Clements et al team from the SEI, which dates back to the mid-90's), is in terms of the high level structures of the system, where those structures comprise software elements and the relations between them.

 

Everything's already been said, but no-one was listening

We're holding these two ideas about architecture in creative suspension -- architecture is decisions about "the important stuff" where important is distinguished by cost of change, and architecture is about the structure of the system, which has something to do with (lowering) the cost of change.

Now we're going to take another pass at our conception of architecture (where how we conceive of architecture is being used in its double sense), and this quote (above) is my permission slip.

Architecture is design

Architecture is design. Not all design, but importantly, architecture is design.

Herbert Simon: We're doing design when

What is design? In The Sciences of the Artificial," Herbert Simon ("ground zero in design discourse" -- Jabe Bloom) notes "Everyone designs who devises courses of action aimed at changing existing situations into preferred ones." This characterization is profound, for all its straightforward simplicity.

We design to get more what we want

Design is what we do, when we want to get more of what we want than we'd get by "just doing it."

How do we design better boxes?

Now, if architecture is design, and architecture is, or at least includes, the shaping structure, the elements and relations -- the boxes and lines -- and design is about creating a better structure, how do we do that?

The tale of the dextrous butcher

As one does, in contemplating life's profound questions, we might turn to the Tao. And in this case, the story of the dextrous butcher. In one translation, the master cook tells us:

“It goes according to natural laws, Striking apart large gaps, Moving toward large openings, Following its natural structure.

“A good cook goes through a knife in a year, Because he cuts. An average cook goes through a knife in a month, Because he hacks.

“I have used this knife for nineteen years. It has butchered thousands of oxen, But the blade is still like it’s newly sharpened.

“The joints have openings, And the knife’s blade has no thickness. Apply this lack of thickness into the openings, And the moving blade swishes through, With room to spare!

“That’s why after nineteen years, The blade is still like it’s newly sharpened.

“Nevertheless, every time I come across joints, I see its tricky parts, I pay attention and use caution, My vision concentrates, My movement slows down.”

Where natural features like rivers and mountains oblige, states have boundaries along them, but software doesn't have natural topology. Or does it?

Design things to be insensitive to outside

The system boundary is an obvious candidate. In the founding classic of system architecture, Eberhardt Rechtin presents heuristics gleaned from his amazing career as a system architect in aerospace, and master teacher of system architects in the seminal program he created at USC. One of these heuristics (is a "turtles all the way down" sort of thing, but applies also at the system level):

"Design things to make their performance as insensitive to the unknown or uncontrollable external influence as practical."

That, for me anyway, has echoes of fort design and Ambrose Bierce' Devil's Dictionary definition of abatis:

"rubbish in front of a fort, to prevent the rubbish outside from molesting the rubbish inside"

Hexagonal architecture

Which visually, and in intent, has echoes of Alistair Cockburn's hexagonal architecture (pattern). Here, adapters at the system boundary, shield the (core) application (code) from interactions with the outside, keeping business logic uncontaminated by the peculiarities of external agents or systems and their states, interactions and interaction paradigms, and keeping business logic from leaching into user, or other system, interface code. Moreover, ports and adapters are a first mechanism of address for cost of change, partitioning the system boundary into plug-and-play access points.

Abstractions

But what about the boundaries within the boundary? These abstractions we use to give our system internal form, must, as Michael Feathers points out, be invented. They are conceits. In every sense of the word, perhaps. At least, when asked about the granularity of microservices, I point to the WELC master going "about so big." Obviously a joke, the joke being on us, the right answer of course being "the right size, and no bigger." Which is not an answer, but where can we look, for a better answer?

Bounded contexts

One place to go, in looking for the natural topology, to find the natural shape to follow in creating internal system boundaries, is the "problem" domain -- that is, the domain(s) being served by the system(s) we're evolve-building. And indeed, we're broadly using bounded contexts in Domain-Driven Design to suggest microservice boundaries. And when we get to the tricky parts, like "customer" or "product" that have potentially overlapping, yet different, meanings in different domains, we slow down, and move more carefully. A customer, after all, experiences themselves to be one person through all touchpoints with "the system," and doesn't want to feel like the system cleaved them brutalistically. So we separate domains, but the architect is noting this point of articulation, this tricky part, where we have to move more carefully.

Components and responsibilities

Another place to go is back to 1989 and Ward Cunningham and Kent Beck's CRC cards, but repurposed for components. We work with components and responsibilities in both directions -- start with a first cut notion of components the system will need, and identify and allocate responsibilities to them; or start with responsibilities evident from what the system needs to do, and factor to find components. Continue to update the responsibilities for each component, as more is learned as the system is explored and built out. We're looking, as Rebecca Wirfs-Brock points out, for lively, cohesive centers:

'But modularity, which helps to define and separate code “centers” is really important. Not only does it strengthen a “center” by making it more defined (and encapsulated), it makes it more easily integrated with other code."

Factor and Refactor

These lists of responsibilities are a powerful and largely overlooked/underused tool in the architect's toolbelt. If the responsibilities don't cohere within an overarching responsibility, or purpose, that should trip the architect's boundary bleed detectors. We may need to refactor responsibilities, and discover new components in the process. We think that "naming things" is the big problem of software development, but "places to put things" is the proximate corollary.

"The responsibility of architecture is the architecture of responsibility." ~ Tom Graves

We forgive a line for what it doesn't capture, when it does capture so much of the very essence of a thing!

the architect's SCARS

Grady Booch notes that, for all that changes, there are "fundamentals that remain fundamental." I took the liberty of rearranging Grady's fundamentals (identified in his keynote at SATURN 2016 and elsewhere), to create a mnemonic handle: SCARS*. You know, what we get from experience.

Separation of concerns plays a role widely and variously -- we've already talked about separating interactions at the system boundary from the application core, looking to bounded contexts (domains of concern) to suggest abstractions, and separating responsibilities to create crisp and resilient abstractions.

Resilience can be tested by doing thought experiments with anticipated changes -- assessing the impact against the responsibilities of current components, to see how well we're doing in isolating change. And as the system evolves, we can visualize and track changes to see how well our abstractions hold up.

Having identified component responsibilities comes in handy in assessing balance as well as cohesion. It is readily evident if we're conceiving of a "god" component, or even demigods, with aspirations.

As the story goes, to Thoreau's "simplify, simplify," Ralph Waldo Emerson retorted "One "simplify" would have sufficed." Which nicely indicates a key strategy for simplifying -- do less.

Disorder is the most likely thing

Returning to Dijkstra: "we know we have to keep it crisp, disentangled, and simple if we refuse to be crushed by the complexities of our own making."

Having (named!) places to put things, is a nice idea. But code is a matter of mind -- many minds even. Entropy is hard to work against, especially when the effects are hard to notice (until it is hard not to notice).

 

Conway's Law

Conway's Law asserts that the structure of the organization, and the communication paths it facilitates and inhibits, are powerful, even determining, shapers of the system. I paraphrase it thusly: "if the architecture of the system and the architecture of the organization are at odds, the architecture of the organization wins." Recognizing that's a law*, like gravity, then, we can play along with it, and use team boundaries to maintain component or microservice boundaries, by lining them up. [* not formally a law, but there's empirical support.]

But. There is a but. We do have to remain vigilant, lest we get played by the very law we're using to game entropy. The forces we're using to protect and reinforce boundaries, increase inertial forces at the boundary. If we use boundaries to decouple, to give teams more indepedence and high communication bandwidth within the team, we narrow communication across the boundaries, then it's harder to notice when change is needed (proactively; we do notice once it bites back), and harder to change, at or across the boundary.

Moreover, given what the communication paths foster and inhibit, we're going to have to put in explicit work, to ensure that we don't get scope creep within the component (microservice, etc.), and to manage duplication (with concomitant inconsistency) across components.

Short-cuts within teams to avoid co-ordination overhead between teams (trying to create sync points in schedules, negotiate differing priorities, etc.), become erosion of cohesion and accommodations within components. Slippery slope to a growing constellation of balls of mud, unless work is put in, not just to maintain order, but to create new order as context and understanding shifts and evolves, and raises new needs, challenges and forces that must be addressed within the system -- the organization and the code.

We need to talk about systems

So far we've been talking about boundaries, and designing crisp and resilient abstractions and keeping them that way. But if we swing by Grady Booch's characterization of software architecture once more, we might notice that while system hasn't been absent in what we've covered so far, it also hasn't been the focus.

Russ Ackoff on systems

Russell Ackoff is one of the pioneers of systems thinking and design. In 1974 he was writing papers with titles like "Systems, Messes, and Interactive Planning" -- how very 2017!

In this roughly 10 minute (starting at 1:12) talk, Russ Ackoff covers and illustrates the key characteristics of systems. Notably,

a system has properties that none of its parts have, on their own. "You can write. Your hand can't write. To see this, imagine your hand is cut off; can it write?" [narrator: gruesome image, but it makes the point]

when we take a system, decompose it into its parts, optimize the parts, and put them back together, we don't even necessarily get a working system. To see this, imagine you have the best automotive engineers in the world pick the best carburettor, the best fuel pump, distributor, and so on. Now ask them to assemble those best parts into a car. Most likely they can't because the parts don't fit, but even if they do, in all likelihood it doesn't work very well.

Parts flying in formation, trying to be an airplane

Returning to Eb Rechtin:

"The only thing added to the parts to make the whole greater than the sum of its parts is the interrelationships among them."

Without interrelationships, we have, as Wim Roelandts put it (back when we were working at HP): "parts flying in formation, trying to be an airplane."

Obvious? Surely. Yet we need to act on this understanding. It is not enough to decompose a system into components or microservices or whatever the chunking du jour, minimizing interdependence, and proceed as if coherent systems will gracefully emerge from independent "two pizza" teams.

Minimalist architecture

So we arrive at another characterization of architecture, one that we owe to Dana Bredemeyer: architecture decisions are those that must be made from a system perspective to achieve system outcomes (capabilities and properties of the system).

A minimalist architecture uses this heuristic to filter for significance. If a decision can be made at local scope (within a microservice, say) without negatively impacting system outcomes, it is made there. Architecture decisions, on the other hand, are those that need to be made across boundaries (the system boundary, or across boundaries within the system), in order to get more the system properties we want, and to build desired system capabilities. They are decisions that enable us to build more than just an aggregation of parts.

We're addressing fit among the parts, and their interaction, to yield a coherent system. And addressing, as we do that, the complexity we've moved to interactions, when we shield and focus attention within the parts, to increase organizational and cognitive tractability.

Structure and behavior

The system takes a different kind of attention: we're reasoning about the interaction among architectural elements to yield capabilities (and related value to stakeholders) with desired properties (impacting user-, operations-, and developer-experience, and impacting system integrity and sustainability), addressing the inherent challenges and tradeoffs that arise as we do so.

Which means that we're exploring behavior, to direct discovery as we're exploring how to build the system, not just its parts. But this impacts how we conceive of and design the parts.

Ask questions

So we're positing structure, and asking "what is this system made of?," but also -- and soon -- exploring behavior, asking "how will this work?" and "how does this approach contribute to or inhibit the desired system properties and yield needed system behaviors?"

Remember to update responsibilities

As we do this, we're going to learn more about the responsibilities of the components or architectural elements. And we need to be disciplined about updating the responsibilities and refactoring components/responsibilities to try out alternative structurings, or to improve the current one.

Visual models are sketch prototypes, they are ways to test ideas cheaply

Design of complex systems is hard -- wickedly hard! And wicked problems take all the cognitive assist we can muster. Tradeoffs must be made because there is interaction -- not just interaction among components to create a capability, but interaction among properties.

We draw diagrams or model (some aspect of the system) to think, alone, and to create a shared thoughtspace where we can think together (and across time) about the form and shape and flow of things, considering how-it-works both before we have code and when the very muchness of the code obfuscates and it is all too much to hold in our head, yet we need to think, explore, reason about interactions, cross-cutting concerns, how things work together, and such. [That long sentence reifies how soon too much becomes cognitively intractable.]

Models help us test our ideas -- in an exploratory way when they are just sketches, and thought experiments, where we "animate" the models in mind and in conversation. Drawing views of our system, helps us notice the relationships between structure and function, to reason about relationships that give rise to and boost or damp properties. We pan across views, or out to wider frames, taking in more of the system and what it does where and how and why (again, because we must make tradeoffs we need to weigh value/import and risk/consequences and side effects).

We sketch-prototype alternatives to try them out in the cheapest medium that fits what we're trying to understand and improve. We seek to probe, to learn, to verify the efficacy of the abstractions we're considering, under multiple simultaneous demands. We evolve the design. We factor and refactor; we reify and elaborate. We test and evolve. We make trade-offs and judgment calls. We bring what we can to bear, to best enable our judgment, given the concerns we're dealing with.

Software is a highly cognitive substance with which to build systems on which people and organizations depend. So. We design-test our way, with different media and mediums to support, enhance, stress and reveal flaws in our thinking.

Along the way -- early, and more as fits the moment -- we're "model storming" "out loud" "in pairs" or small groups. And all that agile stuff. Just in the cheapest medium for the moment, because we need to explore options quick and dirty. Hack them -- with sketches/models, with mockups, with just-enough prototypes. We use diagrams and models to see what we can't, or what is hard to see and reason about, with (just) code. Enough early. And enough along the way so that we course correct when we need to. So that we anticipate enough. Put in infrastructure in good time. Avoid getting coupled to assumptions that cement the project into expectations that are honed for too narrow a customer need/group. And suchness.

Years ago I saw a cartoon where there's an architecture diagram on a door, and everyone is throwing darts at it, and the caption read "at least they're looking at it." I couldn't find the original, so unfortunately I can't give proper attribution and had to redraw it, or at least the gist I remember.

Self-repairing egos

Architecture decisions entail tradeoffs. We try for "and" type solutions, that give us more of more. More of the outcomes we seek, across multiple outcomes. Still, there are tradeoffs -- "[architecting] strives for fit, balance and compromise among the tensions of client needs and resources, technology, and multiple stakeholder interests" (Rechtin and Maier).

Compromises mean not everyone is getting what they want (for themselves, or the stakeholders they see themselves beholden to serving) to the extent they want. Seeing the options and good ideas to resolve (only) the forces from the perspective of (just) a part, may.... lead to questioning design decisions ("throwing darts", in the terms of the cartoon) made from the perspective of the system. It can be hard to see why anyone would give up a good thing at a local level to benefit another part of the system, or to avoid precluding a future strategic option or direction. Sometimes those questions lead to a better resolution. Sometimes they just mean compromise.

Further, complex systems are, well, complex. Many, many! parts, in motion. In dynamic, and changing, contexts (of use, operations, evolutionary development). So there's uncertainty. And ambiguity. And lots of room for imperfect understanding. And mistakes. Will be made. Wrong turns taken. Reversed. Recovered from. We're fallible. So. More darts. Which is humbling -- more so, if we're not humble enough to stay fleet, to try to learn earlier and respond to what we're learning.

All of which means we need to notice what is hard to notice from inside the tunnel of our own vision -- where what we're paying attention to, shapes what we perceive and pay attention to.

We need to move forward with confident humility. That is, the confidence to make decisions, knowing that we bring judgment and experience to bear. Our own -- and our, because we work participatively, including others and hence their perspectives and experience. And humility, because we are willing to discover where we were wrong.

“essential elements of human wisdom at its best is humility, knowing that you don’t know everything” -- Mary Bateson

Change in perspective us worth

"A change of perspective is worth 80 IQ points" reminds us to take a different vantage point, to see from a different perspective. Consider the system from different points of view; use the lens of various views. This can play out multiple ways, but includes considering the design (structure, dynamics and implications) from the perspective of security, and from the perspective of responsiveness to load spikes, etc.

Another way to get a change of perspective, is to get another person's perspective. Invite peers working on other systems, say, to share what's been learned and seek out opportunities and weaknesses, things we missed. Our team can miss the gorilla, so to speak, when our attention is focused on the design issues of the moment. Fresh perspective, and even just naive questions about what the design means, can nudge an assumption or weakness into view. And merely telling the story, unfolding the narrative arc of the architecture to fit this person or audience, then that, gets us to adopt more their point of reference, across more perspectives -- in anticipation, and when we listen, really listen, to their response and questions.

We need to adopt the discipline of not just accepting our initial understanding, but rather seeking different understandings. We investigate alternative views, to probe further, to better understand the system and its likely and possible stresses and strains. Doing so, gives us design options, and fall-backs. These are the significant design decisions, decisions about the important stuff, after all.

We can understand the system as code, and building up mental models of the structure and "how it works." And we can understand the system (as we envision it, and as we build-evolve it) through sketches or visual models along with reasoned arguments, explaining, exploring and defending the design. And we can understand the system through visualization of the system behavior, or through simulation or instrumentation (of prototypes, earlier, and the system in production, soon and then later, as the system is evolved). We can understand the system as perceived by someone new to the system, and as someone comfortable with the mental models we've imbued it with. We can understand the system directly and through the lens of an analogy (or hybrid blend of analogies). Understand it as loss and as gain. As a system we break down into parts, and as a system, or whole.

Let's return, one more time, to the characterization of software architecture that's provided the organizing motif so far:

Architecture is significant decisions

This focus on change as a driving force in architecting, gets us a long way: some decisions are significant for they are hard to reverse, and bear high cost of change, so we need to pay close attention to them and act while still reversible; others are significant because, drawing on experience, anticipatory judgment and technical leadership, we reduce the cost and impact or ramifications of changes that would otherwise destabilize the system or slow its evolution. It's important for systems that endure, to be evolvable, as their contexts shift. And with agile and CI/CD, it's all the more important to have the capacity to extend the system and to respond to change (in our understanding of what the system needs to be and become, and in the context itself). Indeed, this is a reason we put so much emphasis on architecting for change resilience: change is a future consequence and cost, and it takes anticipatory awareness and organizational leadership to invest attention, expertise and wisdom in being proactive about change (early, and as we evolve the system) in balance with current pressures.

“This leads to v. Foerster’s ethical imperative: Act always so as to increase the number of choices.” -- Christiane Floyd

But the most important thing, is that we are designing a system -- yes, we said that! Still, if, given that architecture is design, but not all of design, and we're teasing out which decisions are architecturally significant, then our foremost answer is: those that we need to make to ensure desired system outcomes. That is, not only may architectural significance be determined by cost of change, but by strategic impact. What is make or break? For developers? For operations? For users? For the business team and other stakeholders? For the broader social good? That is, what, at the system level do we need to ensure, to be successful (in the terms our various stakeholders care about)? In order for the system to be the kind of system it is, and uniquely so, what capabilities and properties does it need to have? What does this mean in terms of technical priorities? And architectural mechanisms we need to design and provision? What needs technical focus across teams, to ensure? What needs deep system expertise? But more. What is changing in the ecosystem, and what does that mean for us? What impact are we having on the various ecosystems we interact within, including, and importantly, the social and biological environment?

strategicall significant

Further, architecture decisions are those that we need to make, to ensure the integrity of the system being built. Where integrity includes:

  • structural integrity: design to make the system hold up under anticipated forces (staying within the operating safety boundary), and limit, and limit the consequence of, failures (so matters like security and discovering and limiting breaches; etc); matters of robustness (detecting component failure and fast restart with limited impact; etc) and resilience (supporting adaptive capacity),
  • design integrity: conceptual integrity and requisite coherence (for example, developing sufficient common ground and understanding to work within more independent teams yet build a coherent system), and
  • organizational integrity: making decisions consonant with our shared values; navigating by a moral compass that we build and update together, as we learn more what we value, and what impact we have, and want to have.

Architecture is essential to creating common ground, so that's worth a moment's elaboration:

“Joint activity depends on interpredictability of the participants’ attitudes and actions. Such interpredictability is based on common ground—pertinent knowledge, beliefs and assumptions that are shared among the involved parties. Joint activity assumes a basic compact, which  is  an  agreement  (often  tacit)  to  facilitate  coordination  and  prevent  its  breakdown. One aspect  of  the  Basic  Compact  is  the  commitment  to  some  degree  of  aligning  multiple  goals.  A second aspect is that all parties are expected to bear their portion of the responsibility to establish and sustain common ground and to repair it as needed.” — Gary Klein et al.

"Actively interweaving multiple strands of thought
Creates common ground”
— Nick Sousanis, Unflattening, pg 37

"Whatever time the team members spend re-establishing a common view of the universe is the incoherence penalty.” — Michael Nygard

Architecture interprets the identity of the system in technical terms, and sets direction for and makes key system design decisions to enable that identity. It informs and is informed by design for users (determining capabilities the system offers users and other systems), and fit to context and to purpose. And it sets context for further (technical) design decisions. Since these decisions shape -- shape system identity, shape teams, shape context for further decisions -- they become harder to reverse. So it's important to notice which decisions are of this nature (yes, judgment factors). As discussed, getting other perspectives and running thought experiments to find alternatives worth exploring further. And to prioritize what we prototype, and what we build in early increments, to probe further (while still reversible).

Martin Fowler's description of the LMAX architecture makes these points superbly. The system identity (a retail financial trading platform) raises stringent demands on performance (trades must be fast, for the market changes rapidly) and scale (retail, so large numbers of users and transactions). The performance demands in turn have consequences for the programming model. The architecture's event sourcing model is an elegant solution to these demands. The system's unique identity or role it plays in the trading ecosystem, raises technical priorities and challenges. These are the target of design -- design experience with other systems, design experiments to asses approaches, and design work and design tuning, to meet these challenges.

To the extent that architecture is "the stuff that's hard to change" (Martin Fowler), it is in good part because the very identity of the system becomes interwoven with, and due to, these decisions. Again, this is worth recognizing, because users and other systems come to depend on our system, setting down tracks of expectation and assumption, like use habits and dependencies on capabilities (and APIs, for external systems). Further, our mental models of the system (its purpose and our "theory of the problem" and "theory of the solution"), settle in and become background understandings. It all becomes harder to change, because the system *is* -- mostly a good thing, which is why we're still developing and evolving it. But it becomes harder to change at a deep level.

With respect to change then, our architecture makes some things easier to change, to adapt and evolve, but other things harder. Hence we often find that systems sustain incremental change for periods of time, but from time to time, over the years and decades, need a more fundamental "re-architecting" to adapt to a new realm of challenges that have emerged (new kinds of capabilities or uses; orders of magnitude shifts in scale that stretch past the design tolerances or boundaries of our design envelope; etc.).

One might say:

"Software architecture is the set of design decisions which, if made incorrectly, may cause your project to be cancelled." -- Eoin Woods

The truth there sheds light on a more active framing: architecture focuses our attention on what is make or break, and is design to ensure that we do what we need to, to create a successful system. In the context of multiple teams, complexity and uncertainty, and ongoing shifts in various ecosystems (users, operations, development), architecture decisions focus on the tradeoffs that must be made, and the relationships that must be maintained, to do so.

This is not to say that architecture is static or determined "upfront." As the system evolves, its design evolves -- more intentionally, if we continue to explicitly make and (re)assess architecture decisions.

Early, and along the way, architecture: establishes (the technical underpinning of) system identity and (technical design) focus, and sets priorities, direction and context; identifies driving forces, and (internal) capabilities the system needs to have to deliver user-visible capabilities, with (more the) properties users, our business, devs and ops care about. Architecture is design, but it is those aspects of design that need to be done at the system level, to achieve significant (make or break) system outcomes. It addresses cross-cutting concerns, and resolves trade-offs that impact various stakeholders, so that decisions need that system perspective and purview.

 

Acknowledgments: Thank you to Nivia Henry, Stephen Owens and Grady Booch for encouraging me to say more, resulting in my adding the last several sections of this essay.

 

Other Reading

 

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 © 2017 by Bredemeyer Consulting
URL: https://www.bredemeyer.com
Page Created: November 1999
Last Updated: November 1, 2021