Reading through some of the writing on agile development it is easy to be left with a sense that architecture is unimportant, a dirty word, or something that just emerges serendipitously. This article clarifies the significance of architecture and what it means in a development lifecycle, how it relates to developers, and what it means for the cost of a system over time.
Architecture is what, exactly?
It is a common observation that people seem to be quite happy to debate conflicting points of view without agreeing on common terms. Once clarified, many such debates are either diffused or able to move on to topics of substance. In the context of software development, architecture is one such term.
So, what do we mean by architecture? It turns out that, based on explicit definitions and styles of usage, there are several possible meanings, most of which complement more than they contradict. Martin Fowler identifies a common core in Patterns of Enterprise Application Architecture:
"Architecture" is a term that lots of people try to define, with little agreement. There are two common elements: One is the highest-level breakdown of a system into its parts; the other, decisions that are hard to change.
In a blog entry, Grady Booch further emphasizes the second point:
All architecture is design, but not all design is architecture. Architecture represents the significant design decisions that shape a system, where significant is measured by cost of change.
It is this idea of ease or difficulty of change that is relevant to development process. Retaking a decision involves a change, whether the decision made was intentional or accidental, explicit or tacit. All changes involve some work, but the issue is whether the amount of work involved is in proportion to the change. This is what distinguishes the quality of one architecture from that of another. A good architecture is one in which the general significance of design decisions is reduced. A poor architecture amplifies the cost and consequences of otherwise minor decisions.
It is most obviously the process of change that exposes the decision-significance quality of an architecture. From the perspective of change, the role of architecture in agile development becomes quite clear: a good architecture is responsive and will support agility; a poor architecture will resist it and reduce it.
With a clearer understanding of what we mean by architecture — as well as what we want from it — it is easy to see how very wrong claims along the lines of "We're agile; we don't need architecture!" are, as well as how harmful they can be in practice. What is not needed are lots of unreadable documents, long phases in a lifecycle dedicated to building infrastructure to the exclusion of all other development, and elite roles divorced from developers and their work. But although these associations exist in the minds and practices of many, none captures what architecture is about.
Architecture involves the critical decisions for a system and a shared understanding of internal structure and development style. Architecture, in essence, captures the day-to-day (and today–tomorrow) communication between members of a development team. It is a medium for collaboration and work definition. Architecture constrains or enables different development approaches. Thus, architecture is more than just some optional consideration for agile development; it is essential.
A brief aside: If it seems a little odd or jargonistically fashionable to be talking about agile architecture and the agility of code, keep in mind that the words agile and agility had well-defined meanings centuries before the Manifesto for Agile Software Development was written. Ordinarily, agile is treated as an adjective — it names an attribute of something — and means being able to move quickly and easily. When we apply this adjective to architecture it makes perfect sense, just as it makes sense when applied to process. Many teams rushing blindly to embrace 'Agile' development would be well advised to focus instead on being agile — favor an attribute over a branding.
Design in the continuous present tense
Coming up with an agile architecture is not about making fixed predictions of the future; a lot of considerations that make working in the here and now easier also have long-term benefits. Much of what makes an architecture agile is the ability to isolate dependencies and change, following the time-honored (but often breached) qualities of low coupling and high cohesion. Code that is sufficient rather than speculative, that communicates clearly, and that has low technical debt contributes to the habitability and ease of working within an architecture. An integral part of what makes an architecture agile is the process surrounding it.
There is a strong temptation and a long history of trying to pack all architectural effort into an early phase — big, up-front design (BUFD, the project slayer) — with the well-intentioned aim of reducing risk further down the line. Unfortunately, this approach places all the significant decisions at the point of least knowledge (or greatest ignorance) in a project's lifecycle. The result is an increase rather than a decrease in risk, as well as a loss of ability to respond to change — you've planned the work, so now you've got to work the plan.
Risk needs to be amortized across the development lifecycle. A process that is based on providing feedback provides plenty of opportunity to highlight uncertainty, clarify speculation, flag emerging issues, and reset direction. Agile processes have these mechanisms in place, and they apply equally to the state of the architecture as they do to other aspects of a project. There are many techniques that can be applied:
- Using architectural retrospectives to spot trends and qualities, both good and bad, in the system. This can be supported with details of where defects most commonly occur and with what code appears to change most frequently.
- Making technical debt explicit as development progresses, such as marking issues in a regular and easily searchable way in code or posting them on information radiators. Ensure that the debt has a threshold and that it is worked on, not merely noted.
- Where a metric corresponds to an architectural problem, such as poorly managed dependencies, target that value as something to change. It can even become part of the acceptance criteria for a build, but be careful not to become wed to the metric — it has value only while it correlates with an actual problem and while it makes it visible in a way that invites fixing. Once it becomes a distraction or has served its purpose, stop focusing on it and move on.
More information on agile software development Iterative and incremental development explained
Using iterations to help balance priority and risk
Making agile software development work for distributed teams
- Uncertainty can be used to partition the code. When there is a choice between one option and another, there is more significance in there being a choice than in what choice is actually taken. The question becomes not "Which one do I choose?" but "How do I design so that the choice is not significant?" Encapsulating uncertainty reduces the significance of adopting one choice only to have to change it later in the light of new information or a changed situation.
- Uncertainty can also be used constructively with respect to schedule. Where uncertainty comes from insufficient information, rather than taking an early decision in haste, it is possible to defer the decision to the point where there is enough information to make a responsible decision but before the decision becomes critical, i.e., the last responsible moment.
These techniques and others allow a team to experiment, adapt, and make concrete progress. The architecture is the result of an empirical process, starting with a clear vision and responding to new information as it becomes available. A naïve approach ignores the architecture, pinned on the hope that a good architecture will just emerge or that it is irrelevant in the face of good tools and a motivated team.
As with other forms of emergence, there is no magic involved. Without awareness, guidance, and nurturing, a tooled-up, motivated team may find itself increasingly skilled at churning and fixing faster, all the while running up technical debt and failing to understand and solve the root cause of the churn-and-fix cycle. Such accidental architectures lack conceptual integrity, described as follows by Mary and Tom Poppendieck in Lean Software Development:
Conceptual integrity means that a system's central concepts work together as a smooth, cohesive whole. The components match and work well together; the architecture achieves an effective balance between flexibility, maintainability, efficiency, and responsiveness.
The value of a good architecture is not so much in its direct business value, but in reducing the costs against business value. The value is found in its ability to reduce waste and common sources of waste in development.
About the author: Kevlin Henney is an independent consultant and trainer based in the UK. His work focuses on software architecture, patterns, development process and programming languages. He is a coauthor of A Pattern Language for Distributed Computing and On Patterns and Pattern Languages, two recent volumes in the Pattern-Oriented Software Architecture series. You may contact him at firstname.lastname@example.org.