0% found this document useful (0 votes)
9 views

Fundamentals of Software Architecture (for Wold Dingo)

The document is a publication of 'Fundamentals of Software Architecture' by Mark Richards and Neal Ford, detailing the structure and content of the book, including various architectural styles and concepts. It emphasizes the distinction between architecture and design, highlighting the importance of strategic decision-making in software architecture. The book aims to provide insights into architectural thinking, modularity, and the trade-offs involved in architectural decisions.

Uploaded by

igvieira
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
9 views

Fundamentals of Software Architecture (for Wold Dingo)

The document is a publication of 'Fundamentals of Software Architecture' by Mark Richards and Neal Ford, detailing the structure and content of the book, including various architectural styles and concepts. It emphasizes the distinction between architecture and design, highlighting the importance of strategic decision-making in software architecture. The book aims to provide insights into architectural thinking, modularity, and the trade-offs involved in architectural decisions.

Uploaded by

igvieira
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 64

978-1-098-17545-0

Fundamentals of Software Architecture

by Mark Richards and N eal Ford Copyright © 2025 M ark Richards and N eal Ford. All righ ts reserved.

Printed in the U nited States of America.

Published by O ’Reilly M edia, Inc., 1005 Gravenstein High way North, Sebastopol, CA 95472.

O ’Reilly books may be purchased for educa tional, business, or sales promotional use. Online editions are also available for most titles (h ttp://oreilly .co m). For more informa tion, contact our corporate/institutional

sales department: 800-998-9938 or co rpora te@oreill y .com.

Acquisitions Editor: Louise Corrigan Development Editor: Sarah Grey Production Editor: Christopher Fa ucher Interior Designer: David F utato Cover Designer: Karen Mon tgomer y Illustrator: Kate Dullea Jan uar y 2020: First Edition March 2025: Second Edition Revision History for the Early Release 2024-08-23: First Release See http://o reil ly .com/c at alog/erra ta.csp?isbn=9781098175511 for release details.

The O ’Reilly logo is a registered trademark of O ’Reilly Media, Inc. Fu nda men tals of Soware Ar chit ectur e ,

the cover image, and related trade dress are trademarks of O ’Reilly Media, Inc.

The views expressed in this work are those of the authors and do not represen t the publisher’ s views.

While the publisher and the authors ha ve used good faith efforts to ensure that the informa tion and instructions contained in this work are accura te, the publisher and the authors disclaim all responsibility for errors or omissions, including without limitation responsibility for damages resulting from the use of or reliance on this work. U se of the information and instructions contained in this work is a t your own r
08 Comp onen t-Based

19 Choos in g

Brief Table of Contents (Not Yet Final) 00 Pref ace (una vaila ble) 01 I ntr oduction (u nava ila ble) 02 Architectural Thinking (available) 03 M odularity (available) 04 Arc hitect ur e Chara cteristics Dened (una vaila ble) 05 I dentifying Ar chit ectura l Chara cteristics (u na vaila ble

inking (una vaila ble)09Foundations(unavailable)10LayeredArchitectureStyle(unavailable)11ModularMonolith(unavailable)12PipelineArchitectureStyle(unavailable)13MicrokernelArchitectureStyle(unavailable)14Service-BasedArchitectureStyle(unavailable)15Event-DrivenArchitectureStyle(unavailable)16Space-BasedArchitectureStyle(unavailable)17Orchestration-DrivenService-OrientedArchitecture(available)

e Appr opriat e Arc hite ctur e Style (una vaila ble)iii

20 Arc hitect ur al Pa tterns (una vai la ble) 21 Architecture Decisions (available) 22 Anal yzing Arc hite ctur e Risk (un a vai la ble) 23 Diagr am min g Soware Arc hi tectur e (unav ail ab le) 24 M ak ing T e ams Eective (una vaila ble) 25 N ego tia tion an d Leaders hip Sk ills (un a vai la ble) 26 Arc hitect ur al I n tersecti ons (u na va ila ble) 27 Laws Revisi ted (u na vaila ble) 28 Develop ing a Car eer Pa th (una vai la ble) 29 Append ix A: S e lf-As sess men t Quest ions (una vaila ble) 30 Append ix B: Arch it ectur e Ka ta: Mo
1.

2.

Table of Contents Brief Table of Contents (Not Yet Final). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . iii Part I. Foundations

Architectural Thinking. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9

Architecture V ersus Design 10

Strategic versus T actical Decisions 11

Level of Effort 11

Significance of T rade-offs 12

T echnical Breadth 12

Analyzing T rade-Offs 17

U nderstanding Business Drivers 21

Balancing Architecture and H ands-On Coding 21

There ’ s More to Architectural Thinking 23

Modularity. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25

M odularity V ersus Granularity 26

Defining M odularity 26

M easuring modularity 29

Cohesion 29

Coupling 32

M etrics: A bstractness, Instability , and Normalized Distance from the M ain Sequence 33

Distance from the Main Sequence 34

Connascence 37

4.

From M odules to Componen ts 41

Part II. Architecture Styles 3. Orchestration-Driven Service-Oriented Architecture. . . . . . . . . . . . . . . . . . . . . . . . . . . . 45

T opolog y 45

T axonomy 46

Reuse… and coupling 49


Style specifics 52

Data topologies for orchestra tion-driven SOA 53

Cloud considerations for orchestra tion-driven SOA 54

Governing orchestration-driven SO A 54

Common risks for orchestration-driven SO A 55

T eam topologies considerations 55

Style characteristics 56

Examples and use cases 58

Part III. Techniques and Soft Skills

Architectural Decisions. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63

Architectural Decision Antipa tterns 63

The Covering Y our Assets an tipattern 64

Groundhog Day an tipattern 65

Email-Driven Architecture antipa ttern 66

Architectural Significance 67

Architectural Decision Records 67

Basic Structure 68

Example 74

Storing ADRs 76

ADRs as Documenta tion 78

U sing ADRs for Standards 78

U sing ADRs with Existing Systems 79

Leveraging Generative AI and LLMs in Architectural Decisions 79

vi | Table of Contents
PART I

Foundations

T
o understand important trade-offs in architecture, developers must understand

some basic concepts and terminolog y concerning components, modularity, coupling,

and connascence.
CHAPTER 1

Architectural Thinking

A Note for Early Release Readers W ith Early Release ebooks, you get books in their earliest form—the author’ s raw and unedited conten t as they write—so you can take advantage of these technologies long before the official release of these

This will be the 2nd chapter of the final book. Please note tha t the GitHub repo will be made active later on.

If you have commen ts about how we might improve the con tent and/or examples in this book, or if you notice missing material within this cha pter , please reach out to the editor at s grey@or eilly .com.

Architectural thinking is about seeing things with an architect ’ s eye— in other words, from an architectural point of view . U nderstanding how a particular change might impact overall scalability , paying atten tion to how different parts of a system interact, and knowing which third-party libraries and frameworks would be most appropria te for a given situation are all exam ples of thinking architecturally .

Being able to think like an architect first involves understanding what software archi‐

tecture is and the differences between architecture and design. I t then involves ha ving a wide breadth of knowledge to see solutions and possibilities that others do not see; understanding the importance of business drivers and how they transla te to architec‐

tural concerns; and understanding, analyzing, and reconciling trade-offs between various solutions and technologies.

In this chapter we explore these aspects of thinking like an architect.

9
Architecture Versus Design T ake a moment and picture your dream house in your mind. H ow many floors does it have? I s the roof flat or peaked? I s it a big sprawling, single-story ranch house or a multistory contem porar y house? H ow many bedrooms does it ha ve? All of these things define the overall structu re o

take a moment to picture the inside of the house. Does it ha ve carpeting or hardwood floors? What color are the walls? Are there floor lam ps or lights hanging from the ceiling? All of these things relate to the de sign of the house.

Similarly , software architecture is less about a system ’ s appearance and more about its structure, whereas design is more about a system ’ s appearance and less about its structure. For exam ple, the choice to use microser vices defines the structure and shape of the system (its architecture), whereas the look and feel of the user -interface (UI) screen define the design of the system.

But what about decisions such as whether to break a part a ser vice into smaller parts or deciding on a UI framework? U nfortunately , most decisions such as these fall somewhere on a spect rum between architecture and design, making it difficult to

determine what should be considered architecture.

Leveraging the following criteria can help determine whether something is more about architecture or more about design: • Is it more stra tegic in nature or more tactical?

• H ow much effort will it take to change or construct?

• H ow significant are the trade-offs?

These factors are shown in Figure 1-1 , illustra ting the spectrum between architecture and design to help determine where a decision lies and who should have the respon‐

sibility for it.

Fi gur e 1-1. e spectru m between a rch itectu re a nd design 10 | Chapter 1: Architectural Thinking

Strategic versus Tactical Decisions The more strategic a decision, the more architectural it becomes. Con versely , the more tactical a decision, the more it ’ s likely to be about design. Str at egic decisions are

generally long term, whereas tacti cal decisions are generally short term and usually

independent of other actions or decisions.

One good way to determine whether a decision is more stra tegic or tactical is to con‐

sider the following questions: H ow much t hough t and p lann ing is in volved i n the decisio n?

A decision that takes a couple of min utes is more likely to be tactical and hence more about design, whereas a decision requiring weeks of planning is likely to be more strategic and hence more about architecture.
H ow man y people a re in volved i n the decision?

A decision made alone or with a colleague is likely more tactical and on the design side of the spectrum, whereas a decision requiring lots of meetings with many differen t stakeholders is likely more strategic and on the architectural side of the spectrum.

I s the de cision a lo ng-term vi s ion o r a sho rt-term action?

A decision that is likely to change soon is usually tactical in na ture and would be more about design, whereas one that will last a very long time is typically more strategic and more about architecture.

While these questions are a bit subjective, they nevertheless help in determining whether something is strategic or tactical, and th us more about architecture or design.

Level of Eort In his famous paper “Who needs an architect?”, software architect Martin F owler writes that architecture is “ the stuff that ’ s hard to change. ” The harder something is to change, generally , the more effort is required, placing that decision or activity towards the architectural side of the spectrum. Conve

trum.

For exam ple, moving from a monolithic layered architecture to microser vices would require significant effort, so it would be more about architecture. Rearranging fields on a screen would require minimal effort, and therefore be more about design.

Architecture Versus Design | 11


Signicance of Trade-osAnalyzingthetrade-offsofaparticulardecisioncanhelpalotindeterminingwhetheritismoreaboutarchitectureordesign.Themoresignificantthetrade-offsare,themorearchitecturalthedecisiontendstobe.Forexample,choosingtousethemicroservicesarchitecturestyleprovidesbetterscalability,agility,e

tectural side of the spectrum than design.

Even design decisions ha ve trade-offs. For example, breaking a part a class file pro‐

vides better maintainability and readability–a t the cost of managing more classes.

These trade-offs are not overly significant (especially com pared to microser vices ’

trade-offs), so this decision is more on the design side of the spectrum.

Technical Breadth U nlike developers, who must ha ve a significant amoun t of tech ni cal de pth to perform

their jobs, software architects must ha ve a significant amount of t ech nica l br ead th to

see things from an architectural point of view . T echnical depth is all about having deep knowledge of a particular programming language, platform, framework, prod‐

uct, and so on, whereas technical breadth is all about knowing a little bit about a lot of things.

T o better understand the difference, consider the knowledge pyramid shown in Figure 1-2. I t encapsulates all the technical knowledge in the world, which can be bro‐

ken down into three levels: stu you k now, stu you k now y ou do n ’t kno w, and stu

you do n ’t kno w you don ’t kno w.

12 | Chapter 1: Architectural Thinking


Fi gur e 1-2. e pyra mid rep resen tin g all kno wledge Stu you k now includes the technologies, frameworks, languages, and tools technolo‐

Ruby on Rails, that expertise won ’ t last if they ignore Ruby on Rails for a year or two .

K eeping things at the top of the pyramid requires a time in vestment to main tain expertise. This top part represents the individual ’ s tec hnica l depth: the things they

gists use on a daily basis to perform their jobs (such as a J ava programmer knowing J ava). They’ re good, or even expert, at all these things. N otice that this level of knowl‐

know really well.

edge (represented by the top part of the pyramid) is the smallest and con tains the fewest things. This is because most technologists ha ve to pick and choose the areas in which we develop expertise—no one can be an expert at everything.

Stu you k now you do n ’t kno w (the middle part of the pyramid) includes things a

technologist knows a little about or has heard of but in which they have little or no experience or expertise. For exam ple, most technologists have hea r d of Clojure and

know it ’ s a programming language based on Lisp, but can ’t write source code in Clo‐

jure. This level of knowledge is much bigger than the top level. This is beca use people can become familiar with many more things than we can develop expertise in.

Stu you do n ’t kno w you don ’t kno w is the largest part of the knowledge pyramid. It

includes the entire host of technologies, tools, frameworks, and languages tha t would be the perfect solution to a problem, if only the technologist tr ying to solve the prob‐

lem knew that these solutions exist. The goal in an y individual’ s career should be to move things from the stu you do n ’t kno w you don ’t kno w into the second area of the

pyramid, the stu you k now you do n ’t kno w--and, when expertise becomes necessar y ,

to move things from the middle part of the pyramid to the top: the stu you k now.

Early on in a developer’ s career , expanding the top of the pyramid (Figure 1-3) means

Fi gur e 1-3. Develop ers mus t ma in tain expertise to r etai n it H owever , the nature of knowledge changes as developers transition into the architect role. A large part of the value of an architect is that they ha ve a broad understanding
gaining valuable expertise. H owever , the stu you k now is also stuff you must ma in‐

ta in—nothing is sta tic in the software world. If a developer becomes an expert in Technical Breadth | 13

of technolog y and how to use it to solve particular problems. F or example, it ’ s better for an architect to know that five solutions exist for a particular problem than to ha ve singular expertise in only one. The most importan t parts of the pyramid for architects are the top and middle sections; how far the middle section penetra tes into the bot‐

tom section represents an architect ’ s technical br eadth, as shown in Figure 1-4.

14 | Chapter 1: Architectural Thinking


Technical Breadth | 15

Fi gur e 1-4. H ow m uch someo ne k nows a bout a t opic is t ech nical d ept h, an d how m an y top ics some one k nows is tec hn ical br ead th For an architect, b re ad th is more importan t than depth. Because architects m ust make

decisions that ma tch capabilities to technical constraints, a broad understanding of a wide variety of solutions is valuable. Thus, for an architect, the wise course of action is to sacrifice some hard-won expertise and use that time to broaden their portfolio , as shown in Figure 1-5. Some areas of expertise will remain, probably in particularly enjoyable technology areas, while others usefully atroph y .

Fi gur e 1-5. En han ced b re adt h and sh rink ing dep th fo r the a rch it ect ro le Our knowledge pyramid illustrates how fundamen tally different the roles of ar chi tect and developer are. Developers spend their whole careers honing expertise. T ransition‐

ing to the architect role means a shift in that perspective, which man y individuals find difficult. This in turn leads to two common dysfunctions: first, an architect tries to maintain expertise in a wide variety of areas, succeeding in none of them and working themselves ragged in the process. Second, it manifests as sta le exper tise—the

mistaken sensation tha t your outdated information is still cutting edge. W e see this often in large companies where the developers who founded the com pany ha ve moved into leadership roles, yet still make technology decisions using ancient criteria (see “Frozen Caveman an tipattern ” on page 16).

Architects should focus on technical breadth so that they ha ve a larger quiver from which to draw arrows. Developers transitioning to the architect role ma y have to change the way they view knowledge acquisition. Balancing their portfolio of knowl‐

edge regarding depth versus breadth is something ever y developer should consider throughout their career .

Frozen Caveman antipattern A behavioral an tipattern commonly obser ved in the wild, the F rozen Ca vema n anti‐

pattern, describes architects who revert to their pet irra tional concern for ever y archi‐

tecture. For exam ple, one of Neal ’ s colleagues worked on a system that featured a 16 | Chapter 1: Architectural Thinking
centralized architecture. Each time they delivered the design to the clien t architects, the persistent question was “But wha t if we lose Italy?” Several years before, a freak communica tion problem had prevented the client ’ s headquarters from communica t‐

ing with its stores in I taly , causing grea t inconvenience. While the chances of this recurring were extremely small, the architects had become obsessed with this particu‐

lar architectural characteristic.

Generally , this antipattern manifests in architects who ha ve been burned in the past by a poor decision or unexpected occurrence, making them particularly cautious about anything rela ted. While risk assessment is importan t, it should be realistic as well. U nderstanding the difference between genuine and perceived technical risk is part of the ongoing learning process. Thinking like an architect requires overcoming these Frozen Cav

Analyzing Trade-Os Thinking like an architect is about seeing trade-offs in ever y solution, technical or other wise, and analyzing those trade-offs to determine the best solution. The reason this is one of the critical activities of an architect (and hence part of architectural thinking) is exemplified through the following

—Mark Richards E ver ythi ng in architecture is a trade-off, which is wh y the famous answer to ever y architecture question in the universe is “ it depends. ” While this answer might be annoying, it is unfortunately true. Y ou cannot Google the answer or ask an AI engine or large language model (LLM) whether REST or messaging would be better for your system or whether microser vices is the righ t architecture style for your new product, because the answer do es de

ness drivers, compan y culture, budgets, timeframes, developer skill set, and dozens of other factors. Everyone ’ s environment, situa tion, and problem will be different. That ’ s why architecture is so hard. T o quote Neal, your other author: There are no right or wrong answers in architecture—only trade-offs.

—Neal F ord Analyzing Trade-Os | 17

Fi gur e 1-6. Auction s yst em exam ple o f a trade-o—queues or to pics?


For exam ple, consider an item auction system (Figure 1-6) where online bidders bid on items up for auction. The Bid Producer service generates a bid from the bidder and then sends that bid amoun t to the Bid Capture, Bid Tracking, and Bid Analyt

ics ser vices. The architect could do this using queues in a poin t-to-point messaging fashion, or by using a topic in a publish-and-subscribe messaging fashion. Which one should they choose? They can ’ t Google the answer . Architectural thinking requires them to analyze the trade-offs associated with each option and select the best (or least worst) option given the specific situation.

The two messaging options for the item auction system are shown in 2-8 which illus‐

trates using topics in a publish-and-subscribe messaging model, and 2-9, with Figure 1-7, which depicts using queues in a point-to-poin t messaging model.

Fi gur
Fi gur ee 1-8.
1-7. U
U sing
sing qa ueues
t opi c for
for co
c om munic
mmu nica tio nbbetwe
a tion enservices
etween ser vicesThe
18 clear
| Chapter 1: Architectural
advantage Thinking
(and seemingly obvious solution) to this problem in Figure 1-7 is

ar chit ectura l extensibi li ty. The Bid Producer service only requires a single connection to a topic. Compare tha t to the queue solution in Figure 1-8 , where the Bid Producer

needs to connect to three different queues. If a new service called Bid History were

to be added to this system (to provide each bidder with a histor y of all of their bids), no changes would be needed to the existing ser vices or infrastructure. The new Bid History ser vice could sim ply subscribe to the topic that already contains the bid information.

H owever , with the queue option shown in Figure 1-8 , the Bid History ser vice would require a new queue, and the Bid Producer would need to be modified to add an additional connection to the new queue. The point here is tha t using queues means that adding new bidding functionality requires significan t changes to the ser vices and infrastructure, whereas with the topic approach, no changes to the existing infra‐

structure are needed. Also , the Bid Producer is less coupled in the topic option, where the Bid Producer doesn ’ t know how the bidding information will be used or by which ser vices. In the queue option, the Bid Producer knows exactly how the bid‐

ding information will be used (and by whom), and hence is more coupled to the sys‐

tem.

So far , this trade-off analysis seems to make it clear that the topic approach using the publish-and-subscribe messaging model is the obvious and best choice. H owever , to quote Rich Hickey, the creator of the Clojure programming language: Analyzing Trade-Os | 19

Programmers know the benefits of ever ything and the trade-offs of nothing. Architects need to understand both.

—Rich Hickey Thinking architecturally means not only looking at the benefits of a given solution, but also analyzing the associated nega tives, or trade-offs. Continuing with the a uction system example, a software architect would analyze the nega tives of the topic solution as well as the positives. In Figure 1-7, you can see that with a topic, an yone can access
bidding data, which in troduces a possible issue with data access and data security .

H owever , in the queue model illustrated in Figure 1-8, the data sen t to the queue can onl y be accessed by the specific consumer receiving that message. If a rogue ser vice was to listen in on a queue, the corresponding ser vice would not receive those bids, and a notification would immedia tely be sent about the loss of data (and possible security breach). In other words, it is ver y easy to wireta p a topic, but not a queue.

In addition to the security issue, the topic solution in Figure 1-7 only supports homo‐

geneous contracts. All services that receive the bidding da ta must accept the same data con tract and set of bidding data. In the queue option, each consumer can have its own contract, specific to the da ta it needs. For example, suppose the new Bid His tory ser vice requires the current asking price along with the bid, but no other service

needs that informa tion. In this case, the contract would need to be modified, impact‐

ing all other ser vices using tha t data. In the queue model, this would be a separate channel, and thus a separa te contract that does not im pact any other service.

Another disadvantage of the topic model is tha t it does not support monitoring the number of messages in the topic, so it can ’ t support auto-scaling ca pabilities. How‐

ever , with the queue option, each queue can be monitored individually and program‐

matic load balancing a pplied to each bidding consumer so that each can be automa tically scaled independently . Note tha t this trade-off is technolog y-specific: the A dvanced M essage Queuing Protocol (AMQP) can support programmatic load bal‐

ancing and monitoring because of the separa tion between an exchange (what the pro‐

ducer sends to) and a queue (what the consumer listens to).

Given this fuller trade-off analysis, which is the better option?

I t depends! T able 1-1 summarizes these trade-offs.

T able 1-1. Trade-os for t opi csTopicadvantagesTopicdisadvantagesArchitecturalextensibilityDataaccessanddatasecurityconcernsServicedecouplingNoheterogeneouscontractsMonitoringandprogrammaticscalability20|Chapter1:ArchitecturalThinking


Again, every th ing in software architecture has trade-offs: advantages and disadvan‐

tages. Thinking like an architect means analyzing these trade-offs, then asking ques‐

tions like, “Which is more importan t: extensibility or security? ” An architect ’ s choice

will always depend on the business drivers, en vironment, and a host of other factors.

Understanding Business Drivers

Thinking like an architect also means understanding the business drivers required for

the success of the system and translating those requiremen ts into architecture charac‐

teristics such as scalability , performance, and availability . This is a challenging task

that requires the architect to ha ve some business-domain knowledge and healthy , col‐

laborative rela tionships with key business stakeholders. W e ’ ve devoted four chapters

in the book to this specific topic: in ???, we define various architecture characteristics.

In ???, we describe wa ys to identify and qualify architecture characteristics. In ???, we

describe how to measure each characteristic to ensure the business needs of the sys‐

tem are met. And finally , in ??? we discuss the scope of architectural characteristics

and how they relate to coupling.

Balancing Architecture and Hands-On Coding

One of the difficult tasks an architect faces is how to balance hands-on coding with

software architecture. W e firmly believe that ever y architect should code and should

maintain a certain level of technical depth (see “T echnical Breadth ” on page 12).

While this may seem like an easy task, it is sometimes ra ther difficult to accomplish.

Our first tip for anyone striving to balance hands-on coding with being a software

architect is avoiding the Bo ttlene ck T rap. The Bottleneck T rap an tipattern occurs

when an architect takes ownership of code within the critical path of a system (usu‐

ally the underlying framework code or some of the more complica ted parts) and

becomes a bottleneck to the team. This happens beca use the architect is not a full-

time developer and therefore must balance developmen t work (like writing and test‐

ing source code) with the architect role (drawing diagrams, a ttending meetings, and

well, attending more meetings).

One way to a void the B ottleneck T rap is for the architect to delega te the critical parts

of the system to others on the development team and then focus on coding a minor

piece of business functionality (such as a ser vice or UI screen) one to three itera tions

down the road. This has three positive effects. First, the architect gains hands-on

experience by writing production code, while avoiding becoming a bottleneck on the

team. Second, the critical path and framework code are distributed to the develop‐

ment team (where they belong), giving the team ownership and a better understand‐

ing of the harder parts of the system. Third, and perhaps most im portant, the

architect is writing the same business-related source code as the developmen t team.

Balancing Architecture and Hands-On Coding | 21

This helps them better identify with the development team ’ s pain points around pro‐

cesses, procedures, and the development en vironment (and hopefully work to

improve those things).

Suppose, however , that the architect can ’ t develop code with the development team.

H ow can they still remain hands-on and maintain some level of technical depth? The

following are some tips and techniques for architects who want to con tinue deepen‐

ing their technical abilities:

F req uent pr oofs of c once pt

Doing frequent proofs-of-concept (POCs) requires the architect to write source

code; it also helps validate an architecture decision by taking the im plementation


details into accoun t. For example, suppose an architect gets stuck trying to

choose between two caching solutions. One effective way to help make this deci‐

sion is to develop a working example in each caching product and com pare the

results. This allows the architect to see firsthand the implemen tation details and

the amount of effort required to develop the full solution. I t also allows them to

better compare architectural characteristics between the differen t caching solu‐

tions, such as scalability , performance, and overall fault tolerance.

Whenever possible, the architect should write the best production-quality code

they can. W e recommend this practice for two reasons. First, quite often, “throw‐

awa y” proof-of-concept code goes into the source code repositor y and becomes

the reference architecture or guiding example for others to follow . The last thing

any architect would wan t is for their sloppy throwaway code to be trea ted as rep‐

resenting their typical quality of work. Second, writing production-quality proof-

of-concept code means getting practice at writing quality , well-structured code,

rather than con tinually developing bad coding practices by creating quick, sloppy

POCs.

T ackle t ech nical d eb t

Another way architects can remain hands-on is to tackle some technical debt,

freeing the development team to work on the critical functional user stories. T ech

debt is usually low priority , so if the architect doesn ’ t get the chance to complete a

technical debt task within a given iteration, it ’ s not the end of the world and gen‐

erally won ’ t impact the success of the iteration.

Fix b ugs

Similarly , working on bug fixes within an iteration is another wa y of maintaining

hands-on coding skills while helping the development team. While certainly not

glamorous, this technique allows the architect to identify issues and weaknesses

within the code base and possibly the architecture.

22 | Chapter 1: Architectural Thinking


Aut oma te Leveraging automa tion by creating simple command-line tools and analyzers to help the development team with their da y-to-day tasks is another great wa y to maintain hands-on coding skills while making the developmen t team more effec‐

tive. Look for repetitive tasks the development team performs and a utomate them. They’ll be grateful for the automa tion. Some examples are automa ted source validators to help check for specific coding standards not found in other lint tests, a utomated checklists, and repetitive manual code-refactoring tasks.

A utomation in the form of architectural analysis and fitness functions to ensure the vitality and compliance of the architecture is another grea t way to stay “hands-on. ” For exam ple, an architect can write Ja va code in ArchU nit in the Java

platform to a utomate architectural compliance, or custom fitness functions to

ensure architectural compliance while gaining hands-on experience. W e talk about these techniques in ???.

Do code r eviews A final technique to remain hands-on as an architect is to do frequent code reviews. While the architect is not actually writing code, this at least keeps them in volved in the source code. F urther benefits of code reviews include ensuring compliance with the architecture and iden tif ying men toring and coaching opportunities on the team.

There’s More to Architectural Thinking This chapter forms the founda tional aspects of beginning to think like an architect.

H owever , there ’ s much more to thinking like an architect than wha t is described in this chapter . Thinking like an architect involves understanding the overall structure of a system (we cover that topic next in Cha pter 2), understanding business needs

concerns and translating those concerns to architectural characteristics (we ha ve four chapters on tha t topic), and finally , seeing a system through its logical componen ts— the building blocks of a system (we discuss that topic in ???).

There’s More to Architectural Thinking | 23


CHAPTER 2

Modularity

A Note for Early Release Readers W ith Early Release ebooks, you get books in their earliest form—the author’ s raw and unedited conten t as they write—so you can take advantage of these technologies long before the official release of these

This will be the 3rd chapter of the final book. Please note tha t the GitHub repo will be made active later on.

If you have commen ts about how we might improve the con tent and/or examples in this book, or if you notice missing material within this cha pter , please reach out to the editor at s grey@or eilly .com.

Architects and developers have struggled with the concept of modularity for quite some time, as is evident from the following quote: 95% of the words [written about software architecture] are spent extolling the benefits of “ modularity” and little, if anything, is said about how to achieve it.

—Glenford J . Myers, _Com posite/Structured Design_ (V an Nostrand Reinhold Different pla tforms offer different reuse mechanisms for code, but all support some way of grouping rela ted code together into modules. While this concept is universal in software architecture, it has proven slipper y to define. A casual in ternet search yields dozens of definitions, with no consistency (and some contradictions). As men tioned earlier , this isn ’t a new problem. H owever , because no recognized definiti

25
U nderstanding modularity and its many incarna tions in the developmen t platform of choice is critical for architects. Man y of the tools we have to analyze architecture (such as metrics, fitness functions, and visualizations) rely on modularity and rela ted concepts. M odularity is an organizing principle. If an architect designs a system without paying a ttention to how the pieces wire together , that system will present myriad difficulties. T o use a physics analogy , software systems model complex

tems, which tend toward entropy (or disorder). In a ph ysical system, energ y m ust be added to preser ve order . The same is true for software systems: architects must con‐

stantly expend energy to ensure structural soundness, which won ’ t happen by acci‐

dent.

Preser ving good modularity exem plifies our definition of an impl icit architecture

characteristic: virtually no project requirements explicitly ask the architect to ensure good modular distinction and communica tion, but sustainable code bases do require the order and consistency that this brings.

Modularity Versus Granularity Developers and architects often use the terms mod ulari ty and gra nulari ty inter‐

changeably , yet their meanings are ver y different. M odularity is about breaking sys‐

tems apart in to smaller pieces, such as moving from a monolithic architecture style (like the traditional n-tiered layered architecture) to a highly distributed architecture style like microser vices. Gran ularity , on the other hand, is about the size of those pieces–how big a particular part of the system (or ser vice) should be. H owever , as stated in the following quote by one of your a uthors, it’ s with gran ularity where archi‐

tects and developers get into trouble: Embrace modularity , but beware of granularity .

—Mark Richards Granularity ca uses ser vices or componen ts to be coupled to one another , creating complex, hard-to-main tain architecture antipatterns like S paghetti Ar chi tectur e, Dis‐

trib ute d M onoli ths, and the famous Big Bal l of Distri bu ted M ud. The trick to avoiding these architectural antipa tterns is to pay atten tion to granularity and the overall level of coupling between ser vices and com ponents.

Dening ModularityMerriam-Websterdefinesamodule as “ each of a set of standardized parts or inde‐

pendent units tha t can be used to construct a more complex structure. ” By contrast, in this book, we use mod ulari ty to describe a logical grouping of related code, which

could be a group of classes in an object-oriented language or a group of functions in a structured or functional language. Developers typically use modules as a way to group related code together . For exam ple, the com.mycompany.customer package in 26 | Chapter 2: Modularity

J ava should con tain things related to customers. Most languages provide mechanisms for modularity (package in J ava, namespace in .NET , and so on).

M odern programming languages feature a wide variety of packaging mecha‐

nisms,and many developer’ s find it difficult to choose between them. F or example, in many modern languages, developers can define beha vior in functions/methods, classes, or packages/namespaces, each with different visibility and scoping rules.

Some languages complica te this further by adding programming constructs, such as the metaobject protocol, to provide even more extension mechanisms.

Architects must be a ware of how developers package things, because packaging has importan t implications in architecture. F or example, if several packages are tightly coupled, reusing one of them for related work becomes more difficult.
Modular reuse before classes Developers who trained in the days before object-orien ted languages may puzzle over why there are so man y different separa tion schemes. M uch of the reason has to do with backward compa tibility–not o

In March 1968, the journal Com mun ica tions of th e Associa tion fo r Comp ut in g M ach i‐

importan t.) For example, lum ping a large number of classes together in a monolithic applica tion may be con venient; however , when it comes time to restructure the archi‐
nery (ACM) published a paper from computer scien tist Edsger Dijkstra entitled “ Go T o Statement Considered H armful. ” H e denigrated the common use of the GOTO state‐

tecture, the coupling encouraged by loose partitioning can impede efforts to break the monolith apart. Tha t’ s why it ’ s useful to talk about modularity as a concept, sepa‐
ment, common in programming languages a t the time, because it allowed nonlinear leaping around within code, making reasoning and debugging difficult.

rate from the ph ysical separation tha t a particular platform forces or im plies.

Dijkstra ’ s paper helped usher in the era of s tructu red programming languages, exem‐

I t is worth discussing
plified by the generaland
Pascal concept
C, of awhich
names pace, which isdeeper
encourage separate thinking
from the about how things fit together . Developers quickly realized that most programming languages offered no good way to group like things together logically . Thus, the short era of m odu lar lan‐

technical implemen tation in the .NET platform tha t is also called a namespace.

Developers often need precise, fully qualified names for different software assets (componen ts, classes, and so on) to separate them from each other . The most obvious example tha t people use ever y day is the in ternet, which relies on unique, global iden‐

guages was born, such as M odula (Pascal crea tor Niklaus W irth ’ s next language) and A da. These languages embraced the programming construct of the modu le, much as

we think about packages or namespaces today (but without the classes).


tifiers tied to IP addresses.

However , the modular programming era was short-lived because object-orien ted lan‐
M ost languages have some modularity mechanism tha t doubles as a namespace to organize things like variables, functions, or methods. Sometimes the module struc‐

guages became popular and offered new ways to enca psulate and reuse code. Still, language designers realized the utility of modules and retained them in the form of packages and namespaces. Man y languages still contain compa tibility features that seem odd today but were in troduced to support these different paradigms. For exam‐

ture is reflected physically: Ja va package structures, for example, must reflect the director y structure of the ph ysical class files.

ple, J ava supports modular paradigms (via packages and package-level initializa tion using static initializers), as well as object-orien ted and functional paradigms, each with its own scoping rules and quirks.

A language with no name conicts: Java 1.0

The original designers of J ava had extensive experience dealing with name conflicts and clashes, which were common in programming platforms a t the time. Ja va 1.0

used’ asclever
In this book hack to about
discussions avoid ambiguity when
architecture, wetwo
useclasses
moduhad
lari the same
ty as name–such
a general as to
term if the problem domain included a catalog o rd er and an installation o rder, both named

denote a related grouping of code: classes, functions, or an y other grouping. This doesn ’ t imply a physical separa tion, merely a logical one. (The difference is sometimes Dening Modularity | 27

or der but with very different connotations (and classes). The J ava designers ’ solution was to create the package namespace mechanism, along with a requiremen t that the physical directory structure must ma tch the package name. Because filesystems won ’ t allow two files with the same name to reside in the same director y , this leveraged the operating system ’ s inherent fea tures to ambiguity and name conflicts. Thus, the origi‐

nal classpath in J ava con tained only directories.

However , as the language designers discovered, forcing ever y project to ha ve a fully formed director y structure was cumbersome, especially as projects became larger .

Plus, building reusable assets was difficult: frameworks and libraries had to be “ explo‐

ded ” into the directory structure. In the second major release of J ava (1.2, but called J ava 2), designers added the jar mechanism, which allows an archive file to act as a director y structure on a classpa th. For the next decade, Ja va developers struggled with getting the classpath exactly right, as a combina tion of directories and JAR files.

Their original inten t had been broken: now two JAR files co uld create conflicting

names on a classpath. This is wh y Ja va developers of that era tend to ha ve numerous war stories about debugging class loaders.

28 | Chapter 2: Modularity
Measuring modularity Since modularity is so importan t, architects need tools to help them better under‐

stand it. Fortuna tely , researchers have crea ted a variety of language-agnostic metrics for this purpose. W e ’ ll focus here on three key concepts: co hes ion, c oup li ng, and c on‐

nascenc e.

Cohesion Cohes ion refers to the extent to which a module ’ s parts should be contained within the same module. In other words, it measures how related the parts are to one another .

An ideal cohesive module is one where all parts are packaged together ; breaking them into smaller pieces would require coupling the parts together via calls between mod‐

ules to achieve useful results. The cautionary tale of modularity as it relates to cohe‐

sion are exemplified in the following quote by Larry Constantine: A ttempting to divide a cohesive module would only result in increased coupling and decreased readability .

—Larr y Constan tine, Structured Design (2008) Computer scien tists have defined a range of cohesion, measured from best to worst: F uncti ona l coh esi on Every part of the module is related to the other , and the module contains every‐

thing essential it needs to function.

Sequen tial co hes ion T wo modules interact: one outputs da ta that becomes the in put for the other .

Com mu ni ca tio nal c ohe sion T wo modules form a communica tion chain in which each operates on informa‐

tion and/or contributes to some output. F or example, one adds a record to the database and the other genera tes an email based on that information.

Pro ced ur al cohes ion T wo modules must execute code in a particular order .

T empor al cohes ion M odules are related based on timing dependencies. F or example, man y systems have a list of seemingly unrela ted things that must be initialized a t system startup; these different tasks are t empo rall y coh esi ve.

Logical co hes ion The data within modules is rela ted logically but not functionally . For exam ple, consider a module that con verts information from text, serialized objects, or streams into some other forma t. Its opera tions are related, but the functions are Measuring modularity | 29

quite different. A common exam ple of this type of cohesion exists in virtually ever y J ava project in the form of the StringUtils package, a group of static methods that opera te on String but are other wise unrelated.

Coin ciden tal cohe sio n The elements in a module are unrela ted other than being in the same source file.

This represents the most nega tive form of cohesion.

Despite its many varian ts, cohes ion is a less precise metric than cou pl in g. Often, a par‐

ticular module ’ s degree of cohesion is determined at the discretion of a particular architect. Consider this module definition: Customer Maintenance • add customer •
update customer • get customer • notify customer • get customer orders •

0, otherwise

1
cancel
• Does Order customer orders
Maintenance require Should theknowledge
so much last two entries reside
of Customer in this
informa tion module? Orting
that separa should themodules
the two developer
wouldcrea te atwo
require highseparate
degree ofmodules? H make
coupling to ere ’it sfunctional?
what that(This
would look
relates like:
back Customer
to the Maintenance
prior Larry Constantine•quote.)
add customer • update
These questions customer
represent • get
the kind of customer •
trade-off analysis tha t lies at the heart of a soft‐

ware architect ’ s job.

Computer scien tists have developed a good structural metric to determine cohe‐

sion–] specifically , Lack of Cohesion (which is a bit surprising, given how subjective this characteristic is). A well-known set of metrics named the Chidamber and K emerer Object-Oriented M etrics Suite measures particular aspects of object-

notify customer Order Maintenance • get customer orders • cancel customer orders Which is the correct structure? As always, it depends: • Are these the only two operations for Order Maintenance? If so , it may make sense to collapse those opera tions back into Customer Maintenance.

oriented software systems. I t includes man y common code metrics, such as Cyclo‐

matic Com plexity (see ???) and several important coupling metrics, discussed in “ Coupling” on page 32.

Chidamber and K emerer have also developed a Lack of Cohesion in M ethods (LCOM) metric, which measures the structural cohesion of a module. The initial ver‐

sion appears in Equa tion 2-1.

Equa tion 2-1. L COM, versi on 1

• Is Customer Maintenance expected to grow m uch larger? If so, perha ps develop‐

P − Q , if P > Q

LCOM
ers= should look for opportunities to extract behavior in to a different (or new) module.

In this equation, P increases by 1 for an y method that doesn ’t access a particular shared field; Q decreases by 1 for methods that do share a particular shared field. If you find this formula tion confusing, we sympathize–and it ’ s gradually become even more elaborate. The second varia tion, introduced in 1996 (thus the name L C O M96B),

30 | Chapter 2: Modularity

appears in Equa tion 2-2.

Equa tion 2-2. L COM96B

a m − μ A j m W e won ’t bother un tangling the variables and operators in Equation 2-2 beca use the

LCOM 96b =

j=1

following written explanation is clearer . Basically , the LCOM metric exposes inciden‐

tal coupling within classes. A better definition of LCOM would be “ the sum of sets of methods not shared via sharing fields. ”

Consider a class with private fields a and b. M any of the methods only access a, and

many other methods only access b. The s um of the sets of methods not shared via

sharing fields (a and b) is high; therefore, this class incurs a high LCOM score, indi‐

cating a significan t lack of c ohe sion i n methods.

Measuring modularity | 31
32 | Chapter 2: Modularity

Fi gur e 2-1. e LCOM m etric, wher e elds are o ctago ns and met hods ar e squar es Consider the three classes shown in Figure 2-1. H ere, fields appear as single letters inside octagons and methods appear as blocks. In Class X, the LCOM score is low , indicating good structural cohesion. Class Y , however , lacks cohesion; each of the field/method pairs in Class Y could appear in its own class without affecting the sys‐

tools for virtually ever y pla tform that allow architects to analyze the coupling charac‐

tem ’ of scode.
teristics behavior . Class Z shows mixed cohesion; the last field/method combination could be refactored into its own class.

The LCOM metric is useful to architects who are analyzing code bases in order to assist in restructuring, migrating, or understanding a code base. Shared utility classes are a common headache when moving architectures. U sing the LCOM metric can help architects find classes that are inciden tally coupled and should never have been a single class to begin with.
Why such similar names for coupling metrics?

Why are two critical metrics in the architecture world tha t represent opp osi te co ncep ts named virtually the same thing, differing in only the vowels that sound the most alike? These terms originate from the book S tructu red Des ign. B orrowing concepts

from mathema tics, Y ourdon and Constantine coined the now-common terms aerent and eerent coupling. They should really have been called inco ming and out going cou‐

Man y software metrics have serious deficiencies, and LCOM is not immune. All this metric can find is structu ral lack of cohesion; it has no wa y to determine if particular

pling, but the authors leaned toward ma thematical symmetr y ra ther than clarity .

Developers
pieces fit together have. This
logically come
reflectsupbackwith
on ourseveral
Second mnemonics to Archi‐
Law of Software help out. F or instance, a appears before e in the English alphabet, just as inco mi ng a ppears before out going. The

tecture: prefer wh y over how.

letter e in eerent ma tches the initial letter in exit, which helps in remembering tha t it represents outgoing connections.

Coupling Fortuna tely , we have better tools to analyze coupling in code bases. These are based in part on graph theory : because the method calls and returns form a call gra ph, it can be analyzed mathema tically . Edward Y ourdon and Larr y Constantine ’ s book Struc‐

Metrics: Abstractness, Instability, and Normalized Distance from the Main Sequence While componen t coupling has raw value to architects, several other derived metrics allow for deeper evaluation. The metrics discussed in this section were crea ted by software engineer Robert C. Martin, and a pply widely to most obj

tur ed Design: F undamen tals of a Discip li ne of Co mp ut er Pr ogra m an d S ystems Des ign (Prentice-H all, 1979), which defined many core concepts, including the metrics Aer‐

ent Coup li ng and Eerent Cou plin g. Aerent Coupling measures the number of

inc om in g connections to a code artifact (componen t, class, function, and so on). Eer‐

entCouplingmeasurestheou tgo in g connections to other code artifacts. There are

guages.

Abst ra ctnes s is the ra tio of abstract artifacts (abstract classes, interfaces, and so on) to concrete artifacts (implemen tations). The A bstractness metric measures a code base ’ s degree of abstractness versus implemen tation. For exam ple, on one end of the scale would be a code base with no abstractions, just a huge, single function of code (as in a single main() method). The other end of the scale would be a code base with too many abstractions, making it difficult for developers to understand how things wire together . (F

Equa tion 2-3. Abs tr actne ss A =

∑ m a ∑ m c + ∑ m a Architects calculate A bstractness by calculating the ra tio of the sum of abstract arti‐

facts to the sum of the concrete and abstract ones. In the equation, m a represents Measuring modularity | 33
C

C
ab str act elements (in terfaces or abstract classes) with the module, and m c represents con cre te elemen ts (non-abstract classes). This metric looks for the same criteria. The easiest way to visualize this metric is to consider an a pplication with 5,000 lines of code, all in one main() method. I ts Abstractness n umerator would be 1, while the denominator would be 5,000, yielding an A bstractness score of almost 0. That ’ s how this metric measures the ratio of abstractions in code.

Another derived metric, I nsta bil ity, is defined as the ra tio of efferent coupling to the

sum of both efferent and afferen t coupling, as shown in Equation 2-4.

Equa tion 2-4. I nsta bility I =

e+C a In the equation, c e represents efferen t (or outgoing) coupling and c a represents affer‐

ent (or incoming) coupling.

The Instability metric determines the vola tili ty of a code base. A code base that exhib‐

its high degrees of instability breaks more easily when changed, because of high cou‐

pling. For exam ple, if a class calls to many other classes to delega te work, the calling class will show high susceptibility to breakage if one or more of the called methods changes.

Distance from the Main Sequence One of the few holistic metrics architects have for architectural structure is Dist an ce from t he M ain Seq uence, a derived metric based on _Instability and A bstractness, shown in Equation 2-5.

Equa tion 2-5. Dista nce from t he ma in sequenc e D =

A+I−1

In the equation, A = A bstractness and I = Instability .

N ote that both A bstractness and Instability are fractions whose results will always fall between 0 and 1 (except in some extreme cases). Thus, gra phing the relationship pro‐

duces the graph in Figure 2-2.

34 | Chapter 2: Modularity
Fi gur e 2-2. e mai n sequence denes t he idea l rela tionsh ip between Abs tr actness a nd I nsta bil ity The Distanc e metric imagines an ideal relationship between abstractness and instabil‐

ity ; classes tha t fall near this idealized line exhibit a health y mixture of these two com‐

lower left-hand corner , as illustrated in Figure 2-4, enters the Zon e of P ain: code with

peting concerns. For exam ple, graphing a particular class allows developers to calculate the Distance from the M ain Sequence metric, illustrated in Figure 2-3.

too much im plementation and not enough abstraction becomes brittle and hard to maintain.

Fi gur e 2-3. N ormal ized Di s ta nce fr om th e M ain Sequ ence f or a pa rticular c lass The Figure 2-3 metric graphs the candidate class, then measures its distance from the idealized line. The closer to the line, the better balanced the class. Classes that fall too far into the upper righ t-hand corner enter what architects call the Zo ne of U sele ssn ess:

Fi gur e 2-4. e zones o f u se les sne ss a nd pa in Man y platforms provide tools to calculate these measures, which assist architects when analyzing code bases to get familiar with them, prepare for a migration, or assess technical debt.

code that is too abstract becomes difficult to use. Con versely , code that falls into the Measuring modularity | 35

The limitations of metrics While the industr y has a few code-level metrics tha t provide valuable insight, our tools are extremely blunt com pared to analysis tools in other engineering disciplines.

Even metrics derived directly from the structure of code require in terpretation. For example, Cycloma tic Complexity_ (see ???) measures complexity in code bases, but this metric cannot distinguish between essen tial complexity (the code is com plex

because the underlying problem is com plex) and accident al comp lexity (the code is

more complex than it should be). V irtually all code-level metrics require interpreta‐

tion, but it is still useful to establish baselines for critical metrics such as Cyclomatic Complexity so tha t architects can assess which type the codebase exhibits. W e discuss setting up just such tests in ???.

Y ourdon and Constantine ’ s Structur ed Design, published in 1979, predates the popu‐

larity of object-oriented languages. I t focuses instead on structured programming constructs, such as functions (not methods). I t also defines other types of coupling that are outda ted because of modern program language design. Object-oriented pro‐

36 | Chapter 2: Modularity

gramming introduced additional concepts tha t overlay afferent and efferen t coupling, including a more refined vocabular y to describe coupling called co nn ascence.

Connascence M eilir Page-J ones ’ s book What E very Progra mmer Sho uld K now a bout Object-Orien ted Design (Dorset H ouse, 1996) created a more precise la ngua ge to describe different

types of coupling in object-oriented languages. Connascence isn ’ t a coupling metric like afferent and efferen t coupling— rather , it represents a language that helps archi‐
tects describe different types of coupling more precisely (and understand some com‐

mon consequences of types of coupling).

T wo componen ts are con nascent if a change in one would require the other to be

modified in order to maintain the overall correctness of the system. H e distinguished two types of connascence: sta tic and dyna mic.

Static connascence Sta tic con nascence refers to source-code-level coupling (as opposed to execution-time

coupling, covered in “Dynamic connascence ” on page 38). Architects view static con‐

nascence as the degr ee to which something is coupled via either afferen t or efferent

languages to consider defining somewhere that int TRUE = 1; int FALSE = 0.

coupling. There are several types of static connascence: Con nascence o f Na me M ultiple components m ust agree on the name of an entity .
Imagine the problems that would arise if someone flipped those values.

Con nascence o f Posi tion M ultiple components m ust agree on the order of values.

M ethod names and method parameters are the most common way tha t code bases are coupled and the most desirable, especially in light of modern refactor‐
This is an issue with parameter values for method and function calls, even in lan‐

guages that fea ture static typing. For exam ple, if a developer creates a method void updateSeat(String name, String seatLocation) and calls it with the values updateSeat("14D", "Ford, N"), the semantics aren ’ t correct, even if the types are.

ing tools that make system-wide name changes trivial to im plement. For exam‐

ple, developers no longer change the name of a method in an active code base but rather r efactor the method name using modern tools, affecting the change

throughout the code base.

Con nascence o f Algorith m M ultiple components m ust agree on a particular algorithm.

Con nascence o f T ype M ultiple components m ust agree on the type of an entity .

A common case for Con nascence o f Algorith m occurs when a developer defines a

This type of connascence refers to the common tendency in many sta tically typed languages to limit variables and parameters to specific types. H owever , this capa‐

security hashing algorithm that m ust run and produce identical results on both the ser ver and clien t to authentica te the user . Obviously , this represents a high degree of coupling— if an y details of either algorithm change, the handshake will no longer work.

bility isn ’ t purely for statically typed languages— some dynamically typed lan‐

guages also offer selective typing, notably Clojure and Clojure Spec.

Con nascence o f Mea ning M ultiple components m ust agree on the meaning of particular values. It is also called Con nascence o f Conven tion.

Dynamic connascence The other type of connascence Page-J ones defines is dynam ic co nn ascence, which

analyzes calls at run time. The types of dynamic connascence include: Con nascence o f E xecut ion The order of execution of multiple com ponents is importan t.
The most common obvious case for this type of connascence in code bases is hard-coded numbers ra ther than constants. For exam ple, it is common in some Measuring modularity | 37

Consider this code: email = new Email(); email.setRecipient("[email protected]"); email.setSender("[email protected]"); email.send(); email.setSubject("whoops"); I t won ’t work correctly beca use certain properties must be set in a specific order .

Con nascence o f T imin g The timing of the execution of multiple com ponents is importan t.

The common case for this type of connascence is a race condition caused by two threads executing at the same time, affecting the outcome of the join t operation.

Con nascence o f V alue s Several values depend on one another and must change together .

Consider a case where a developer has defined a rectangle by defining four points to represent its corners. T o main tain the integrity of the da ta structure, the devel‐

38 | Chapter 2: Modularity
oper cannot randomly change one of the points without considering the im pact on the other points to preserve the shape of the rectangle.

A more common and problematic case in volves transactions, especially in dis‐

tributed systems. In a system designed with separate da tabases, when someone needs to update a single value across all of the da tabases, the values must either all change together or not change at all.

Con nascence o f Iden tity M ultiple components m ust reference the same entity .

A common example of Co nn ascence o f I denti ty in volves two independent com po‐

nents tha t must share and update a common da ta structure, such as a distributed queue.

Connascence Properties Connascence is an analysis framework for architects and developers, and some of its properties help ensure that we use it wisely . These connascence properties include: Str ength

Architects determine the str ength of a system ’ s connascence by the ease with

which a developer can refactor its coupling. Some types of connascence are demonstrably more desirable than others, as shown in Figure 2-5. Refactoring

toward better types of connascence can improve the coupling characteristics of a code base.

Architects should prefer static connascence to dynamic beca use developers can determine it by simple source-code analysis, and beca use modern tools make it trivial to improve sta tic connascence. For example, Co nn ascence o f M eani ng could be improved by refactoring to Co nn ascence o f N ame,creating a named con‐

stant ra ther than a magic value.

Measuring modularity | 39
Fi gur e 2-5. Conn ascence s trength ca n be a good refa ctorin g g u ide Local ity

The local ity of a system ’ s connascence measures how proximal (close) its modules

are to each other in the code base. Pro ximal co de (code in the same module) typi‐

cally has more and higher forms of connascence than more separated code (in separate modules or code bases). In other words, forms of connascence tha t would indicate poor coupling when the com ponents are far apart are fine when the componen ts are closer together . For exam ple, if two classes in the same mod‐

ule have Co nnasc ence o f M eani ng, it is less damaging to the code base than if

those classes were in different modules.

Architects were largely unaware of the im portance of this obser vation when the author first published it. In modern terms, he is suggesting tha t architects should limit the scope of implemen tation details (high coupling) as narrowly as practical, which is the same advice derived from Domain-driven design ’ s bounded context idea.

The architectural obser va tion is the same— limit implementa tion coupling. Meilir -

Page described a good design principle which was rein troduced more fully via DDD .

+ I t’ s a good idea to consider strength and locality together . Stronger forms of connas‐

cence within the same module represent less “ code smell” than the same connascence spread apart.

40 | Chapter 2: Modularity
Degree The degree of connascence relates to the size of the im pact if changing a class in a particular module— does that change im pact a few classes or man y? Lesser degrees of connascence require fewer changes to other classes and modules and hence damage code bases less. In other words, having high dynamic connascence isn ’ t terrible if an architect only has a few modules. However , code bases tend to grow , making a small problem correspondingly bigger in terms of change.

In Wha t Every Pr ogra mm er Sho uld K now a bou t Object-Orien ted Des ign (Dorset

H ouse, 1996), Page-J ones offers three guidelines for using connascence to improve system modularity : • Minimize overall connascence by breaking the system into enca psulated elements • Minimize any remaining connascence tha t crosses encapsula tion boundaries • Maximize connascence within enca psulation boundaries The legendar y software architecture innova tor Jim W eirich, who repopularized the

concept of connascence, offers two great rules from his talk on Co nn escenc e Exam‐

ine d during the Emer gin g T echn ologies f or the En terpri se conference in 2012:

Rule of Degree: Con vert strong forms of connascence into weaker forms of connas‐

cence.

Rule of Locality: As the distance between software elements increases, use weaker forms of connascence.

Architects benefit from learning about connascence for the same reason it ’ s beneficial to learn about design patterns— connascence provides more precise language to describe different types of coupling. F or example, an architect can tell someone “we need a ser vice and there can only be one instance, ” or they can tell someone, “we need a Singleton ser vice"--the Singleton design pa ttern nicely encapsulates the con text and solution to a common problem with a simple name.

Similarly , when performing a code review , an architect can instruct a developer , “Don ’ t add a magic string constant in the middle of a method declaration. Extract it as a constant instead. ” Or they could sa y “Y ou have Con nascence of M ean in g; refactor

it to Con nascence o f Na me. ”

From Modules to Components W e use the term module throughout this book as a generic name for bundles of related code. H owever , most architects refer to modules as com pon ents, the key build‐

ing blocks for software architecture. This concept of a com ponent, and the corre‐

sponding analysis of logical or physical separa tion, has existed since the earliest days From Modules to Components | 41

of computer science, yet developers and architects still struggle to achieve good out‐

comes.

W e ’ ll discuss deriving com ponents from problem domains in ???, but we must first discuss another fundamental aspect of software architecture: architectural character‐

istics and their scope.


42 | Chapter 2: Modularity
PART II

Architecture Styles

The difference between an architecture style and an architecture pattern can be con‐

fusing. W e define an arc hite ctur e style as the overarching structure of how the user

interface and backend source code are organized (such as within la yers of a mono‐

lithic deployment or separa tely deployed ser vices) and how that source code in teracts with a datastore. Ar chi tectu re pa tterns, on the other hand, are lower -level design

structures that help form specific solutions within an architecture style (such as how to achieve high scalability or high performance within a set of operations or between sets of ser vices).

U nderstanding architecture styles occupies much of the time and effort for new architects because they share im portance and abundance. Architects must under‐

stand the various styles and the trade-offs encapsula ted within each to make effective decisions; each architecture style embodies a well-known set of trade-offs that help an architect make the right choice for a particular business problem.
CHAPTER 3

Orchestration-Driven Service-Oriented

Architecture A Note for Early Release Readers W ith Early Release ebooks, you get books in their earliest form—the author’ s raw

This will be the 17th chapter of the final book. Please note tha t the GitHub repo will be made active later on.

If you have commen ts about how we might improve the con tent and/or examples in this book, or if you notice missing material within this cha pter , please reach out to the editor at s grey@or eilly .com.

Architecture styles make sense to architects in the context of the era when they evolved, but lose relevance in later eras, m uch like art movements. Orc hes tr ation-

driven service-orien ted a rch ite ctur e (SOA) exem plifies this tendency . The external forces that often influence architecture decisions, combined with a logical but ulti‐

mately disastrous organiza tional philosophy , doomed this architecture to irrelevance.

H owever , it provides a great example of how a particular organiza tional idea can make logical sense yet hinder the most importan t parts of the development process. I t illustrates one of the dangers of ignoring our First La w : ever yth in g in soware ar chi‐

tectu re is a trade-o.

Topology The topolog y of orchestra tion-driven SOA is shown in Figure 3-1.

45
Fi gur e 3-1. T opology of or chestr atio n-driven serv ice-o rient ed a rc hitect ur e N ot all examples of this style of architecture ha ve the exact layers illustrated in Figure 3-1, but they all follow the same idea of establishing a taxonomy of services within the architecture, each layer with a specific, well-defined responsibility .

these ser vices? If so , then the ser vice is at the a ppropriate level of granularity . How‐

ever , while a developer might need a method like CreateCustomer to carr y out a busi‐

ness process like ExecuteTrade, CreateCustomer is at the wrong level of abstraction for a business ser vice. The com pany isn ’ t in the busines s of creating customers, but it

Ser vice-orien ted architecture is a distributed architecture. The exact demarcation of boundaries isn ’ t shown in Figure 3-1 because it varies based on organization and tools: some of the parts of the taxonomy ma y exist inside an applica tion ser ver .
needs to create customers in order to execute trades.

These ser vice definitions con tain no code—just input, output, and sometimes schema information. Business users and/or analysts define these service signatures, hence the name busi nes s serv ice s.

Orchestration-driven SO A centers on a specific taxonom y of ser vices, with different technical responsibilities within the architecture and roles dedicated to specific la yers.

Enterprise
Taxonomy Services Thephilosophy
The driving ent erprise s ervices
behind contain fine-grained
this architecture shared
is a specific type im plementations.
of abstraction T ypically
and enterprise-level , aany
reuse. M team
large companies were annoyed a t how much they had to contin ually rewrite software. They arrived at a strategy that seemed to solve tha t problem gradually by creating a strict service taxon

of developers builds atomic beha vior around particular business domains, such as CreateCustomer or CalculateQuote, and transactional entities, such as Customer, Order, and Lineitem. These enterprise services are the building blocks that make up the business ser vices, tied together via the orchestra tion engine.

corresponding responsibilities. Each layer of the taxonom y supports the dual goals of ultimate abstraction and reuse.

I t is worth noting the abstraction differences between business and enterprise ser v‐

ices. While business ser vices are quite coarse-grained, en terprise ser vices are fine-

trained and meant to ca pture different types of abstractions, workflows, and entities.
Business services Busi ness serv ice s sit at the top of this SO A and provide the entr y poin t for business processes. For exam ple, ser vices like ExecuteTrade or PlaceOrder represent the cor‐

The architect ’ s goal in creating enterprise services is to create perfectly enca psulated building blocks of isolated business functionality tha t can be freely composed into more complex business workflows.

rect scope of behavior for these services. One litmus test common a t the time was: can an architect answer “yes ” to the question “ Are we in the business of…” for each of 46 | Chapter 3: Orchestration-Driven Service-Oriented Architecture

While that ’ s a laudable goal, architects find tha t the ideal sweet spot of abstraction between all these forces is elusive at best and likely im possible because of numerous competing trade-offs. Ultima tely , like other technically partitioned architectures, this architecture attem pts a strict separation of responsibility , from which flows from the impera tive of reuse. The idea is that if developers can build fin

U nfortunately , the dynamic nature of reality and the evolutionary impact of the soft‐

ware development ecosystem defy these attem pts. Business components aren ’ t like construction materials, where solutions last decades. M arkets, technolog y changes, engineering practices, and a host of other factors confound attem pts to impose stabil‐

ity on the software world.

Application services N ot all ser vices in the architecture require the same level of gran ularity or reuse as the enterprise services. Appli ca tio n serv ice s are one-off, single-implemen tation ser vices.

For exam ple, perhaps one applica tion needs geolocation, but the organization doesn ’ t Topology | 47

want to take the time or effort to make tha t a reusable ser vice. An applica tion ser vice, typically owned by a single applica tion team, solves that problem.

Infrastructure services I nfrast ructur e s ervices supply operational concerns, such as monitoring, logging, authen tication, authoriza tion, and so on. These ser vices tend to be concrete imple‐

menta tions, owned by a shared infrastructure team that works closely with opera‐

ti A hit t ’ hil h i b ildi thi hit t l d t h i l titi i it k th t th ld b ild t i f t t i


tions. Architects ’ philosophy in building this architecture revolves around technical partitioning, so it makes sense that they would build separa te infrastructure ser vices.

Orchestration engine and message bus The or che st ra tion engi ne forms the heart of this distributed architecture, stitching
48 | Chapter 3: Orchestration-Driven Service-Oriented Architecture

together the business service implemen tations using orchestra tion, including features like transactional coordination and message transforma tion. The orchestration engine defines the relationship between the business and en terprise ser vices, how they map together , and where transaction boundaries lie. I t also acts as an integration hub , allowing architects to integra te custom code with package and legacy software systems. This combination of fea tures highlights the modern-day use of tools like enterprise se

Message ow All requests go through the orchestration engine, where this architecture ’ s logic resides. Thus, message flow goes through the engine even for in ternal calls, as shown in Figure 3-2.

tant skill to develop as an architect— how to discern the true uses of tools, separate from the hype, both good and bad.) Because the message bus forms the heart of the architecture, Conwa y’ s Law (see ???)

correctly predicts that the team of in tegration architects responsible for this engine tends to become a political force within an organization–and even tually a bureau‐

cratic bottleneck.

While this centralized, taxonomized a pproach might sound appealing, in practice it has mostly been a disaster . Offloading transaction behavior to an orchestration tool sounds good, but architects struggle to find the correct level of granularity . While they can build a few ser vices wra pped in a distributed transaction, the architecture becomes increasingly complex. Developers m ust figure out where the appropriate transaction boundar

cessfully build transactional building blocks as enterprise services, it has proved diffi‐

cult in practice.

Fi gur e 3-2. M essa ge ow w it h s ervice-orient ed arc hi tectur e In Figure 3-2, the CreateQuote business-level ser vice calls the service bus, which defines the workflow . The workflow consists of calls to CreateCustomer and Calcula

teQuote, each of which also makes calls to applica tion ser vices. The ser vice bus acts as the intermediary for all calls within this architecture, ser ving as both an integra tion hub and orchestra tion engine.

Reuse… and coupling One of the primar y goals of the architects who first utilized this architecture was reuse at the service level— the ability to gradually build business behavior that they could incrementally reuse over time. They were instructed to find reuse opportunities as aggressively as possible.

Topology | 49
Fi gur e 3-3. Seek ing reuse o pportu ni ties in serv ic e-orien ted a rch it ectu re For exam ple, consider the situation illustrated in Figure 3-3. An architect realizes tha t each of six divisions within an insurance compan y contains a notion of Customer.

Therefore, the proper SO A strategy entails extracting the Customer parts into a reusa‐

ble ser vice and then allowing the original services to reference the canonical Cus tomer ser vice. This is shown in Figure 3-4: here the architect has isolated all customer

behavior in to a single Customer ser vice, achieving the obvious reuse goals.

50 | Chapter 3: Orchestration-Driven Service-Oriented Architecture


Fi gur e 3-4. Bu ild in g can on ical rep resent atio ns in serv ic e-orien ted a rch it ectu re Architects only slowly realized the negative trade-offs of this design. First, when a team builds a system primarily around reuse, it also incurs a huge amoun t of cou‐

pling between componen ts. After all, reuse is implemented via coupling. F or exam‐

ple, in Figure 3-4, a change to the Customer ser vice ripples out to all the other ser vices. This makes even incremen tal change risky : each change has a potentially huge ripple effect. Tha t in turn requires coordinated deployments, holistic testing, and other drags on engineering efficiency .

Another negative side effect of consolida ting behavior into a single place: consider the case of auto and disability insurance in Figure 3-4. T o support a single Customer ser‐

vice, each division must include all the details the organiza tion knows about its cus‐

tomers. A uto insurance requires a driver’ s license, which is a property of the person, not the vehicle. Therefore, the Customer ser vice will ha ve to include details about driver’ s licenses that the disability insurance division cares nothing about. Y et the dis‐

ability insurance team must deal with the extra com plexity of a single customer defi‐

nition. In many wa ys, Domain-Driven Design ’ s insistence on av oid in g holistic reuse

derives from experiences with these kinds of architectures.

P erhaps the most damaging revelation about orchestra tion-driven SOA is the im prac‐

ticality of building an architecture so focused on technical partitioning. While this makes sense from a separation and reuse philosoph y standpoint, it is a practical nightmare.

For exam ple, developers commonly work on tasks like “ add a new address line to CatalogCheckout. ” Domain concepts like CatalogCheckout are spread so thinly

Topology | 51
throughout this architecture that they were virtually ground to dust. In an SO A, this task could involve dozens of services in several different tiers, plus changes to a single database schema. Wha t’ s more, if the current en terprise ser vices aren ’ t defined at the correct transactional granularity , the developers will either have to change their design or build a nearly identical new service to change the transactional behavior . So much for reuse.

Style specics Orchestration-driven SO A is mostly of historical interest to curren t-day architects; the lessons learned from building these architectures are an importan t part of the field ’ s evolution. However , architects still find parts of it relevant in some in tegration architecture scenarios.

Ser vice-orien ted architecture appeared in the late 1990s, just as small com panies of all kinds were growing into en terprises at a breakneck pace, merging with smaller com‐

panies, and requiring more sophisticated IT to accommoda te this growth. However , computing resources were scarce, precious, and commercial. Distributed com puting had just become possible and necessar y , and man y companies needed its scalability and other beneficial characteristics.

Man y external drivers forced architects in this era toward distributed architectures with significant system constrain ts. B efore open source opera ting systems were thought reliable enough for serious work, opera ting systems were expensive and licensed per machine. Similarly , commercial database servers came with Byzantine licensing schemes, which sometimes caused a pplication-ser ver vendors (which offered dat

Given that so man y resources were expensive at scale, architects adopted a common philosophy of reusing as m uch as possible.

These technical concerns wedded with organizational concerns about duplica tion of both information and workflows— because of frequent mergers and growth, organi‐

zations struggled with the variety and inconsistencies between core business en tities.

This made the goals of SO A attractive. Consequently , architects embraced reuse in all

forms as the dominant philosoph y in this architecture, the side effects of which we cover in “Reuse… and coupling” on page 49. This style of architecture also exem pli‐

fies how far architects can push the idea of technical partitioning, which can have good motivations but leads to bad consequences when taken to extremes.

Why so many service names?

Architects are often confused by the multitude of things in software architecture called ser vices. W e cover three different “ ser vices ” styles even in this book: SO A in this chapter , microser vices in ???, and service-based architectures in ???. Part of the prob‐

52 | Chapter 3: Orchestration-Driven Service-Oriented Architecture


lem is the inflexibility of language to describe architectures. The other part lies in the constant evolution of the software-developmen t ecosystem. S ervice is a nice generic name for something that provides a, well, service, so architects tend to reuse the name. As styles evolve, we change what we mean by service. For exam ple, an en tity serv ice in an orchestra tion-driven SOA is differen t in virtually ever y way from a ser‐

vice in a microser vices architecture (which is distinct from a service-based architec‐

ture). As annoying as it is, architects must often parse the con text when the word serv ice a ppears in a name; the term itself has suffered from semantic diffusion.

Data topologies for orchestration-driven SOA U nlike many of the architecture styles we discuss in this book, the da ta topologies for orchestration-driven SO A aren ’ t ver y interesting, given this style ’ s historical origins.

Even though it is a distributed architecture consisting of man y parts, it generally uses a single (or a few) relational da tabases, which was the common practice in all dis‐

tributed architectures in the late 1990s. E ven transactionality was generally relegated to this architecture and awa y from databases: the message bus often included declara‐

tive transactional interactions for each of the en tities within the topolog y , allowing developers, architects, or others to determine transactional behavior independen tly of the database or even the situa tional reuse of the entity .

Architects in this era considered data a foreign coun tr y . While it is an inevitable part of the plumbing in both SO A and event-driven architectures, back then, they treated it more as an integra tion point than as part of the problem domain.

Really? Declarative Transactions?!?

Y es, really . One of the “fea tures ” of many a pplication ser vers in the heyda y of orchestration-driven SO A was allowing configuration managers to change the trans‐

actional scope of individual entities, depending on the transactional con text within which they wanted to opera te. (This was declared, of course, in XML, given the era and its love for verbose but easy-to-parse configuration forma ts.) A portion of the declaration of an en tity (called EntityBeans, a specialized type of Ja vaBean) deter‐

mines transactional scope as it participates in workflows, which architects themselves declare to be transactional or not. In turn, the applica tion ser ver interacts with the database to crea te and manage database transactions that ma tch the desired behavior of the entities and/or workflows.

This has largely failed, for two reasons. First, if a developer doesn ’ t know what the transactional behavior will be a t runtime, it adds considerable complexity to en tities and dependencies. This forces developers to create almost iden tical versions of the entities, differing only in their transactional scope. Second, no ma tter how much sophistication vendors build in to their message buses, edge cases consta
where the myriad failure modes preven t the system from cleanly managing transac‐

tions, creating tangled messes of inconsistency for h umans to untangle. Some com‐

plex, multifaceted fea tures of systems (like transactions) cannot be cleanly abstracted awa y . T oo many leaks in the abstraction prevent it from achieving reliability .

Cloud considerations for orchestration-driven SOA Orchestration-driven SO A predates the cloud by several decades, so no considera tion exists for building this architecture (in its original incarnation) in the cloud.

H owever , the current-day use of this style makes it a good in tegration architecture for cloud and on-premises ser vices tha t must integra te and participate in workflows. As primarily an integra tion architecture, it works well with cloud-based ser vices and facilities.

Governing orchestration-driven SOA When this architecture was popular , modern-day holistic testing was uncommon.

T eams rarely tested SOA outside of formal quality-assurance-level testing, so tool and framework creators ga ve little consideration to facilitating testing the individual parts. Some testing frameworks emerged to create mocks and stubs for the massive machiner y of the message bus and its rela ted moving parts, but they were always cumbersome and inconsistent.

Governance suffered from the same limitations. The idea of a utomating architectural governance was even more foreign than automa ting testing. In this era, “ governance ”

meant hea vyweight frameworks, meetings, and code reviews–all manual.

H owever , architects still use ESBs strategically within organizations tha t need the par‐

ticular mix of capabilities they offer . In particular , many companies ha ve legacy sys‐

tems that m ust interact with more modern systems, often combining results and aggregating beha vior–all of which describes the cen tral functionality of an ESB. In these scenarios, fitness functions can ser ve a critical role in preven ting data or boun‐

ded contexts from “leaking ” across parts of the ecosystem where they shouldn ’t appear .

For exam ple, consider a system that uses an ESB to coordinate between an en terprise resource planning (ERP) package, an online sales tool, and more modern microser vices-based Accounting services. In this scenario, the system should only read from the ERP and sales systems and should write to the Accounting microser‐

vices. Architects can first build a fitness function that ensures tha t all communication is written consistently to logs, then write something like the following fitness function (given here in pseudocode): 54 | Chapter 3: Orchestration-Driven Service-Oriented Architecture
READ logs for ERP into ERP-logs for past 24 hours READ logs for Sales into Sales-logs for past 24 hours FOREACH entry IN ERP-logs IF 'operation' is 'update' and 'target' != 'accounting' THEN

raise fitness function violation "Invalid communication between integration points"

END IF

FOREACH entry IN Sales-logs IF 'operation' is 'update' and 'target' != 'accounting' THEN

raise fitness function violation "Invalid communication between integration points"

END IF

This fitness function reads the log entries from both in tegration points to ensure tha t no update opera tions take place whose target isn ’t the Accounting system.

U sing such fitness functions, architects can use tools like ESBs strategically while building guardrails around the places where teams typically misuse them.

Common risks for orchestration-driven SOA A t the end of the last century and the beginning of this one , the big risks for this architecture were primarily about how much it cost, how long it took to im plement, and (a shocking surprise) how difficult these systems are to maintain and upda te.

Man y of these projects were ver y expensive multiyear endea vors, with critical deci‐

sions made high in the compan y hierarchy . Rather than call these projects “ failures, ”

companies mostly just transformed them in to integration architectures with better boundaries, more closely aligned with the ideas of DDD .

When architects use an ESB in a modern system as an integra tion facility , the biggest risk is the slipper y slope of allowing the ESB to gradually enca psulate the entire archi‐

tecture. This is called the Acciden tal SOA an tipattern: where an architect gradually

and uninten tionally builds a fully orchestration-driven SO A without realizing it. T o avoid A ccidental SO A, an architect must ensure reasonable enca psulation boundaries for orchestration and pa y close attention to issues like transactional boundaries.

Team topologies considerations J ust as architects did not consider data topologies for orchestration-driven SO A, the same is true for team topologies, which was an unknown topic when this architecture style was popular .

In fact, the strict taxonomy of this style serves as a communica tion antipattern tha t led architects to develop the principles of team topologies. The goa l in this architec‐

ture is extreme separation of responsibilities, with a corresponding separa tion of team members. Among the companies tha t adopted it, it was rare indeed for some‐

one building busi nes s serv ice s to chat with someone building en terpri se services. They

Team topologies considerations | 55


were expected to communica te through technical artifacts, such as contracts and interfaces. The level of abstraction in this style crea tes many in tegration la yers, each implemen ted by different teams, using enterprise-level ticketing tools to comm uni‐

cate. I t should be easy to see wh y developers find it time-consuming to build features in this style.

Style characteristics Man y of the criteria we now use to evaluate architecture styles were not priorities when orchestration-driven SO A was popular . The Agile software movement had just started and had not yet penetrated the large organiza tions likely to use this architec‐

ture.

A one-star rating in the characteristics ra tings table in Figure 3-5 means the specific architecture characteristic isn ’ t well supported in the architecture, whereas a five-star rating means the architecture characteristic is one of the style ’ s strongest features.

Definitions for the characteristics identified in the scorecard can be found in ???.

SO A is perhaps the most technically partitioned general-purpose architecture ever attem pted! In fact, the backlash against its disadvantages of this structure led to more modern architectures, such as microser vices. SO A has a single quantum, even though it is a distributed architecture, for two reasons. First, it generally uses a single data‐

base or just a few , creating coupling poin ts across man y different concerns. Second,

and more importan tly , the orchestration engine acts as a gian t coupling point— no part of the architecture can have differen t characteristics than the mediator that orchestrates all beha vior . Thus, this architecture manages to find the disadvan tages of both monolithic and distributed architectures.

56 | Chapter 3: Orchestration-Driven Service-Oriented Architecture


Fi gur e 3-5. Ra tin gs for ser vice-orien ted ar chi tectu re M odern engineering goals such as deployability and testability score disastrously in this architecture, both because they are poorly supported and beca use those were not importan t (or even aspirational) goals when it was developed.

This architecture does support some goals, such as elasticity and scalability , despite the difficulties in implemen ting them. T ool vendors poured enormous effort into making these systems scalable by building session replication across a pplication ser vers and other techniques. H owever , this being a distributed architecture, perfor‐

mance has never been a highlight, beca use each business request is split across so much of the architecture.

Because of all these factors, simplicity and cost ha ve the inverse of the relationship most architects would prefer . Orchestration-driven SO A was an important milestone because it ta ught architects the practical limits of technical partitioning and how dif‐

ficult distributed transactions can be in the real world.

Style characteristics | 57
Examples and use cases The primar y exam ples of this architecture existed in the late 1990s and early 2000s in many large en terprises. They have gradually been displaced by more agile and domain-based distributed architectures, like microser vices. E ven large enterprises have realized tha t change is inevitable and

Architects built orchestration-driven SO A architectures to tr y to achieve effective reuse across large organizations, but even tually realized how difficult their strict and elaborate taxonom y makes implemen ting common changes and updates. F or exam‐

ple, a common domain change might be to upda te details about a single entity . On a lucky day , developers might only need to change componen ts in the Enterprise Ser v‐

ices layer to do the job . However , on a bad day (one where en terprise architects and/or business stakeholders didn ’ t anticipate this type of change), developers migh t have to upda te four or five layers in the architecture, making highly coupled changes in each. Architects working in this style dread hearing the word cha nge because it

requires deep analysis and the scope of the work is so variable.

As we mentioned in “ Governing orchestration-driven SO A ” on page 54, architects

still use the building blocks of orchestration-driven SO A (such as the ESB), particu‐

larly for integra tion architectures. For example, an ESB includes both an in tegration hub (to facilita te communication, protocol, and con tract transformation) and an orchestration engine (to allow architects to build workflows between various in tegra‐

tion endpoints). Because the orchestra tion-driven SOA includes man y layers of indi‐

rection, it allows architects to implemen t enterprise ser vices as in tegration points, as package software, or as bespoke code, among other possibilities, as illustrated in Figure 3-6.

58 | Chapter 3: Orchestration-Driven Service-Oriented Architecture


Fi gur e 3-6. e la yers of a bstr action in t his a rc hite ctur e style allo w for im plemen tat ion exibility.

In Figure 3-6, client requests use the message bus to determine which enterprise serv‐

ices to call, in what order to call them, and wha t information to aggregate. The en ter‐

prise ser vices, in turn, comm unicate via APIs to custom code, old systems, or package software, and so on.

Orchestration-driven SO A represents an in teresting innovation for how architects handle problems of integra tion at scale within the constraints of their ecosystem. F or example, since most organiza tions weren ’t using open source opera ting systems when this architecture was popular , alternative architectures like microser vices were im pos‐

sibly expensive. Architects should learn from past approaches. W e can con tinue using the parts that still make sense, while in ternalizing the lessons of what failed and wh y .

Examples and use cases | 59


PART III

Techniques and Soft Skills

An effective software architect must not only understand the technical aspects of soft‐

ware architecture, but also the primar y techniques and soft skills necessary to think

like an architect, guide development teams, and effectively comm unicate the architec‐

ture to various stakeholders. This section of the book addresses the key techniques

and soft skills necessar y to become an effective software architect.


CHAPTER 4

Architectural Decisions

A Note for Early Release Readers W ith Early Release ebooks, you get books in their earliest form—the author’ s raw and unedited conten t as they write—so you can take advantage of these technologies long before the official release of these

This will be the 21st chapter of the final book. Please note tha t the GitHub repo will be made active later on.

If you have commen ts about how we might improve the con tent and/or examples in this book, or if you notice missing material within this cha pter , please reach out to the editor at s grey@or eilly .com.

One of the core expectations of an architect is to make architectural decisions. Archi‐

tectural decisions usually involve the structure of the a pplication or system, but they may in volve technolog y decisions as well, particularly when those technology deci‐

sions impact architectural characteristics. Wha tever the context, a good architectural decision is one that helps guide developmen t teams in making the right technical choices. Making architectural decisions in volves gathering enough relevant informa‐

tion, justifying the decision, documenting the decision, and effectively communica t‐

ing that decision to the righ t stakeholders.

Architectural Decision Antipatterns The programmer Andrew K oenig defines an an tip att er n as something that seems like

a good idea when you begin, but leads you into trouble. Another definition of an antipa ttern is a repeatable process that produces nega tive results. The three most common architectural decision antipa tterns that can (and usually do) emerge when 63

an architect makes decisions are the Covering Y our Assets antipattern, the Ground‐

hog Day an tipattern, and the Email-Driven Architecture antipa ttern. These three antipa tterns usually follow a progressive flow : overcoming the Covering Y our Assets antipa ttern leads to the Groundhog Day antipa ttern, and overcoming that leads to the Email-Driven Architecture antipa ttern. Making effective and accurate architectural decisions requires overcoming

The Covering Your Assets antipattern The Covering Y our Assets antipa ttern occurs when an architect avoids or defers mak‐

ing an architectural decision out of fear of making the wrong choice. There are two ways to overcome this. The first is to wait un til the last res ponsib le mom en t to make
an importan t architectural decision: that is, when there ’ s enough information to jus‐

tify and validate the decision, but not so long that it holds up developmen t teams or sends the architect into the An al ysis P ar alysis an tipattern, where they are stuck for‐

ever in analyzing the decision. A good way to determine the last responsible momen t is to ask when the cost of deferring the decision exceeds the risk associated with deciding. As illustrated in Figure 4-1, notice tha t in the early stages of the decision-

making time scale, the cost (denoted by the solid line) is low because there ’ s less time spent on making the decision, but the risk (denoted by the dotted line) is high because less is known about the problem or solution. Spending more time deferring the decision increases the cost, but also reduces risk because the architect can make a more complete analysis of the problem and possible alterna tives. The time to make a decision is where these two factors intersect and the cost increa

architect can respond quickly , gain more insight, and reduce the risk of the decision being the incorrect one.

T o illustrate this poin t: Suppose you, as the architect, decide that all product-rela ted reference data (such as product description, weigh t, and dimensions) should be cached in all ser vice instances needing tha t information. Y ou decide tha t this will be done using a read-only replicated cache, with the primary cache owned by the Cata log ser vice. (A r eplica ted cac he (or in-m emory cach e) means tha t if there a

changes to product information or new products added, the Catalog service updates

its cache, which is then replicated to all other services requiring that da ta through a replicated cache product.) Y our justification for this decision is to reduce coupling between the ser vices and to share da ta effectively without having to make an interser‐

vice call. H owever , the development teams implemen ting this architectural decision find that, due to some services ’ scalability requirements, this decision would require more in-process memor y than is a vailable. Because you are closely collaborating with these teams, you quickly become aware of the issue and adjust your architectural decision accordingly .

Fi gur e 4-1. Last Res pons ibl e M oment Another way to a void this antipattern is to collabora te with development teams to ensure that the decision can be im plemented as expected. This is vitally importan t because no architect can possibly know every single detail about any issue associa ted with a particular technolog y . By closely collaborating with development teams, the 64 | Chapter 4: Architectural Decisions

Groundhog Day antipattern The Groundhog Day an tipattern occurs when people don ’ t know why an architect made a particular decision, so the keep discussing it over and over and over , never coming to a final resolution or agreement. I t gets its name from the 1993 movie Gr oundhog Da y, in which Bill Murra

This antipa ttern occurs because architects fail to justify their decision (or fail to jus‐

tify it completely). I t’ s importan t to provide both technical and business justifications for an architectural decision.

For exam ple, say you decide to break apart a monolithic a pplication into separa te ser vices. Y our justification is to decouple the functional aspects of the a pplica tion, so that each part of the a pplication uses fewer virtual machine resources and can be maintained and deployed separa tely . While this is a good technical justification, what ’ s missing is the busi ness justification—in

pay for this architectural refactoring? A good business justifica tion for this decision might be to deliver new business functionality faster , thereby improving time to mar‐

ket. Another might be to reduce the costs associa ted with developing and releasing new features.

Providing the business value is vitally importan t when justif ying an architectural decision. I t is also a good litmus test for determining whether the architectural deci‐

sion should be made in the first place. If it doesn ’ t provide any business value, per‐

haps the architect should reconsider the decision.

Architectural Decision Antipatterns | 65

Four of the most common business justifica tions are cost, time to market, user satis‐

faction, and strategic positioning. Consider wha t’ s importan t to the business stake‐

holders. J ustif ying a particular decision based on cost savings alone migh t not be the right call if the business stakeholders are more concerned about time to market.

Email-Driven Architecture antipattern Once an architect makes and fully justifies their decisions, another architecture anti‐
pattern often emerges: Email-Driven Architecture . This an tipattern occurs when people lose or forget an architectural decision, or don ’ t even know that it ’ s been made and therefore cannot possibly implemen t it. O vercoming this an tipattern is all about communica ting architectural decisions effectively . Email is a great tool for comm uni‐

66 | Chapter 4: Architectural Decisions

cation, but it makes a poor documen t repositor y system.

Fortuna tely , an architect can easily avoid the Email-Driven Architecture an tipattern by learning how to communica te architectural decisions effectively . First, be sure not to include the decision in the body of an email. Doing so creates m ultiple systems of record for that decision, beca use each email contains a copy of the decision rather than having it in only one place. M any such emails leave out im portant details about

cult to know whether all the relevant people receive the revised decision.

A better approach is to men tion only the nature and context of the decision in the body of the email and provide a link to the single system of record, where the archi‐

tectural decision and corresponding details are stored (whether that ’ s a link to a wiki page or a reference to a document in a filesystem).

Consider the following email about an architectural decision: “Hi Sandra, I’ ve made an important decision regarding comm unication between ser vices tha t directly impacts you. Please see the decision using the following link…”

N otice, in the phrasing of the beginning of the first sentence, tha t the context is men‐

tioned (communica tion between ser vices), but not the actual decision itself. The sec‐

ond part of the first sentence is also im portant: If an architectural decision doesn ’ t directly impact the person, then wh y bother that person with it? This is a grea t litmus test for determining which stakeholders (including developers) should be notified directly of an architectural decision. The second sentence in this exam ple provides a link to the single location of the architectural decision, providing a
Architectural Signicance Man y architects believe that if a decision in volves a specific technology , then it’ s not an architectural decision, but rather a technical decision. This is not alwa ys true. If an

architect decides to use a particular technolog y beca use it directly supports a particu‐

lar architecture characteristic (such as performance or scalability), then it ’ s still an architectural decision.

Michael N ygard, a well-known software architect and author of R ele ase I t! (2nd edi‐

tion, Pragmatic Bookshelf, 2018), addresses the problem of what decisions an archi‐

tect should be responsible for (and hence what constitutes an architectural decision) by coining the term ar chit ectura lly signicant. A ccording to Michael, architecturally

significant decisions are those tha t affect a system ’ s structure, non-functional charac‐

teristics, dependencies, interfaces, or construction techniques.

Structu re, in this context, refers to decisions tha t affect the architecture patterns or styles being used. For exam ple, a decision by an architect to share code between a set of microser vices im pacts the bounded context of the microser vice, and th us affects the structure of the system.

The system ’ s non-functio nal c ha ra cteristics are the architectural characteristics tha t are

importan t for the system being developed or maintained. For exam ple, if a choice of technolog y affects performance, and performance is an im portant aspect of the appli‐

cation, tha t choice becomes an architectural decision, even though it may specify a particular product, framework, or technolog y .

Dependencie s refers to the coupling points between componen ts and/or ser vices within the system. Dependencies can affect architecture characteristics such as scala‐

bility , modularity , agility , testability , reliability , and so on, so decisions about depen‐

dencies become architectural decisions.

I nterface s refer to how ser vices and com ponen ts are accessed and orchestrated: usu‐

ally through a gatewa y , integra tion hub , ser vice bus, adapter , or API proxy . Making decisions about interfaces usually in volves defining contracts, including versioning and deprecation stra tegies. Interfaces impact others using the system and hence are architecturally significant.

Finally , constructio n tec hniq ues refers to decisions about platforms, frameworks, tools,

and even processes that, although technical in na ture, might impact some aspect of the architecture.

Architectural Decision Records One of the most effective ways of documen ting architectural decisions is through Arc hitect ur al Decision Rec or ds (ADRs). Michael N ygard first evangelized ADRs in a Architectural Decision Records | 67

2011 blog post, and in 2017, ThoughtW orks T echnolog y Radar recommended the

technique for widespread adoption.

An ADR consists of a short text file (usually one to two pages long) describing a spe‐

cific architectural decision. While ADRs can be written using plain text or in a wiki page templa te, they are usually written in some sort of text document format, like AsciiDoc or Markdown.

T ooling is also available for managing ADRs. N at Pr yce, coa uthor of Gr owing Object-

Oriente d Soware, Gu ided b y T ests (A ddison-W esley , 2009), has written an open

source tool called ADR T ools that provides a command-line in terface to manage

ADRs, including numbering schemes, loca tions, and superseded logic. Micha K ops, a software engineer from Germany , provides some great examples of using ADR tools to manage architectural decision records.
Basic Structure The basic structure of an ADR consists of five main sections: T itl e, Sta tus, Cont ext,

Decision, and Co nsequen ces. W e usually add two additional sections as part of the basic structure: Comp lianc e and N ot es. The Com pliance section is a space to think

about and document how the architectural decision will be governed and enforced (manually or through a utomated fitness functions). The N otes section is a space to include metadata about the decision, such as the a uthor , who approved it, when it was created, and so on.

I t’ s fine to extend this basic structure (as illustrated in Figure 4-2) to include any other needed section. J ust keep the template consisten t and concise. A good example of this might be to add an Al ternati ves section analyzing all the other possible solutions.

Fi gur e 4-2. Basic ADR s tructure Title ADR titles are usually numbered sequen tially and contain a short phrase describing the architectural decision. For exam ple, an ADR title describing a decision to use asynchronous messaging between the Order Ser vice and the P ayment Service might read: “42. U se of Asynchronous M essaging Between Order and Paymen t Ser vices. ”

68 | Chapter 4: Architectural Decisions

The title should be short and concise, but descriptive enough to remove any ambigu‐

ity about the nature and con text of the decision.

Status Every ADR has one of three statuses: Pr oposed, Accep ted, or S uperseded. Proposed

status means the decision must be a pproved by a higher-level decision maker or some sort of architectural governance body (such as an architecture review board).

A ccepted means the decision has been approved and is ready for im plementation.

Superseded means the decision has been changed and superseded by another ADR.

Superseded status alwa ys assumes that the prior ADR ’ s status was A ccepted; in other words, a Proposed ADR would never be superseded by another ADR; it would be modified until A ccepted.

The Superseded status is a powerful wa y of keeping historical records of what deci‐

sions have been made, wh y they were made at tha t time, what the new decision is, and Architectural Decision Records | 69

ST ATUS

why it was changed. U sually , when an ADR has been superseded, it is marked with the number of the decision tha t superseded it. Similarly , the decision that supersedes another ADR is marked with the number of the ADR it superseded.

For exam ple, let’ s say ADR 42 (“U se of Asynchronous Messaging Between Order and Pa yment Ser vices ”) is in A pproved status. Due to la ter changes to the implemen tation and location of the P ayment Service, you decide that REST should now be used between the two ser vices. Y ou therefore create a new ADR (n umber 68) to documen t this changed decision. The corresponding statuses look as follows: ADR 42. U se of Asynch ro nous M essagin g Between Or der an d
ADR 68. U se of REST Betwe en Order a nd Pa yment Services Status: A ccepted, supersedes 42

The link and histor y trail between ADRs 42 and 68 lets you a void the inevitable “wha t about using messaging?” question regarding ADR 68.

ADRs and Request for Comments (RFC) Sending a draft ADR out or comments can help an architect valida te their assump‐

ever yone to agree tha t, for example, the cost of the architectural decision exceeds a certain amount, then it m ust be set to Proposed status and approved by someone else.

tions and assertions with a larger audience of stakeholders. An effective wa y of engag‐

If the architectural decision impacts other teams or systems or has an y sort of security implica tions, then it must be approved by a higher -level governing body or lead architect.
ing developers and initiating collabora tion is creating a new kind of status called Requ est f or Com ments (RFC) and specifying a deadline for reviewers to complete their feedback. Once that da te is reached, the architect can analyze the comments, make any necessary adjustments to the decision, make the final decision, and set the sta tus to Proposed (or A cc

Once the team establishes and agrees on the criteria and corresponding limits (such as “ costs exceeding $5,000 must be a pproved by the architecture review board”), document it well so tha t all architects creating ADRs will know when they can and cannot approve their own architectural decisions.

An ADR with RFC status would look as follows:

Requ est F or Com men ts, Deadl ine 09 J AN 2026

Context The Context section of an ADR specifies the forces a t play . In other words, “What situation is forcing me to make this decision?” This section of the ADR allows the architect to describe the specific circumstances and concisely elaborate on the possi‐

Another significant aspect of the Sta tus section of an ADR is that it forces the archi‐

tect and their boss or lead architect to discuss the criteria for approving an architec‐

tural decision and determine whether the architect can do so on their own, or whether it must be a pproved through a higher-level architect, architecture review board, or some other governing body .
ble alternatives. If the architect is required to documen t the analysis of each alterna‐

tive in detail, add an Alternatives section ra ther than including that analysis in the Context section.

Three good starting places for these conversa tions are cost, cross-team impact, and security . Cost should include software purchase or licensing fees, additional hardware costs, and the overall level of effort to implemen t the architectural decision. T o esti‐
The Context section also provides a place to documen t a specific area of the architec‐

ture itself. By describing the context, the architect is also describing the architecture.

U sing the example from the prior section, the Con text section might read as follows: “ The order service must pass informa tion to the paymen t ser vice to pay for an order currently being placed. This could be done using REST or asynchronous messaging. ”

mate this, m ultiply the estimated number of hours to im plement the architectural decision by the compan y’ s standard full-ti me eq ui valen cy (FTE) rate. The project

owner or project manager usually has the FTE amount. This con versation migh t lead 70 | Chapter 4: Architectural Decisions

N otice that this concise sta tement specifies not only the scenario , but also the alterna‐

tives considered.

Decision The Decision section of the ADR contains a description of the architectural decision, along with a full justification. N ygard recommends stating architectural decisions in an affirmative, commanding voice ra ther than a passive one. For example, the deci‐

sion to use asynchronous messaging between ser vices would read, “W e will use asyn‐

chronous messaging between ser vices. ” This is m uch better than "I th in k asynchronous messaging between ser vices would be the best choice, ” which does not make clear what the decision is or even if a decision has even

One of the most powerful aspects of the Decision section of ADRs is that it lets the architect emphasize the justifica tion for the decision. U nderstanding wh y a decision

was made is far more importan t than understanding how something works. This

helps developers and other stakeholders better understand the rationale behind a decision, and therefore makes them more likely to agree with it.

Architectural Decision Records | 71


T o illustrate this poin t, let ’ s say you decide to use Google ’ s Remote Procedure Call (gRPC) to communica te between two particular ser vices to reduce network latency due to ver y high responsiveness needs. Several years la ter , a new architect on the team decides to use REST instead of gRPC to make communica tions between ser vices more consistent. Because the new architect doesn ’t

in the first place, their decision ends up having a significan t impact on latency , caus‐

ing timeouts in upstream systems. If the new architect had access to an ADR, they would have understood tha t the original decision to use gRPC was meant to reduce latency (a t the cost of tightly coupled ser vices) and could ha ve prevented this prob‐

lem.

Consequences Every decision an architect makes has some sort of impact, good or bad. The Conse‐

quences section of an ADR forces an architect to describe the overall impact of an architectural decision, allowing them to think about whether the negative im pacts outweigh the benefits.

This section is also a good place to document the trade-off analysis performed during the decision making process. For exam ple, let’ s say you decide to use asynchronous (fire-and-forget) messaging for posting reviews on a website. Y our justification for this decision is to improve responsiveness (from 3,100 milliseconds down to 25 milli‐

seconds) because users wouldn ’ t have to wait for the actual review to be posted—only for the message to be sent to a queue. One member of your developmen t team argues that this is a bad idea due to the com plexity of the error handling associated with an asynchronous request: “What ha ppens if someone posts a review with some bad words?” What this team member doesn ’ t know is that you discussed that very prob‐

lem with the business stakeholders and other architects when analyzing the trade-offs of this decision, and decided together that it was better to im prove responsiveness and deal with complex error handling ra ther than increase the wait time and provide feedback as to whether the review post was successful or not. If this decision was doc‐

umented using an ADR, you could ha ve provided this trade-off analysis in the Conse‐

quences section, preventing this sort of disagreemen t.

Compliance The Compliance section is not one of the standard sections of an ADR, but it ’ s one we highly recommend adding. The Com pliance section states how the architectural deci‐

sion will be measured and governed. W ill the compliance check for this decision be manual or can it be a utomated using a fitness function? If it can be automa ted, the architect can specify how the fitness function will be written, along with any other changes to the code base needed to measure this architectural decision for compli‐

ance.

72 | Chapter 4: Architectural Decisions

For exam ple, suppose you make the decision within a traditional n-tiered layered architecture (as illustrated in Figure 4-3) tha t all shared objects used by business objects in the Business layer m ust reside in the Shared Ser vices layer to isola te and contain shared functionality .
• Original author • A pproval date • A pproved by • Superseded date • Last modified date •

Fi gur e 4-3. An exam ple o f an a rch it ectur al decisio n This architectural decision can be measured and governed using a host of automa tion tools, including ArchU nit in Ja va and NetArch T est in C#. W ith ArchU nit in Ja va, the

M odified by • Last modification Even when storing ADRs in a version-con trol system (such as Git), it’ s useful to have additional metadata beyond wha t the repositor y can support. W e recommend adding this section regardless of how and where the architect stores ADRs.

automa ted fitness-function test for this architectural decision might look like this: @Test public void shared_services_should_reside_in_services_layer() {

classes().that().areAnnotatedWith(SharedService.class)

.should().resideInAPackage("..services..") .check(myClasses); }

Example Our example of the ??? a uction system includes dozens of architectural decisions.

This automa ted fitness function would require writing new stories to create a J ava annotation (@SharedService) and add it to all shared classes to support this method of governance.

Splitting up the bidder and auctioneer user in terfaces, using a hybrid architecture consisting of event-driven and microservices, leveraging the Real-time T ransport Protocol (R TP) for video capture, using a single API gatewa y , and using separate queues for messaging are just a few of the architectural decisions an architect would make. Every architectural decision an architect makes, no m

Notes Another section that is not part of a standard ADR but tha t we highly recommend adding is a N otes section. This section includes various metadata about the ADR, such as: Architectural Decision Records | 73

Figure 4-4 illustrates one of the architectural decisions within the Going, Going, Gone auction system: using separa te point-to-point queues between the bid ca pture, bid streamer , and bid tracker ser vices rather than a single publish-and-subscribe topic (or even REST , for that ma tter).

74 | Chapter 4: Architectural Decisions

ST A TUS

CONTEXT

DECISI ON
CONSEQUEN CES Fi gur e 4-4. U se of pub/s ub be tween serv ic es W ithout an ADR to justif y this decision, others in volved with designing and develop‐

COMPLI ANCE ing this system might disagree and decide to im plement it in a different wa y .

slower and might require back pressure. U sing a dedicated Bidder Tracker queue pro‐

The following is an example of an ADR for this architectural decision: ADR 76. Separate Queu es f or B id Streamer and B i dder T racker Ser vices

vides this dedicated back-pressure poin t.

NO TES
W e will require clustering and high availability of the message queues.

Accepted
This decision will require the Bid Capture ser vice to send the same informa tion to multiple queues.

Internal
The bidBidevenCapture
ts will bypass
ser security
vice, checks
upon done
receiving
in the API
a layer
bid,. m ust for ward that bid to the Bid

UPDATE:
Streamer Userponvice
r eview
and atthetheBidder
J anua rTracker
y 14, 2026, ARB mee
service. Thistincould
g, th ebeARB decided
done usingt ha t th is was an a ccep ta ble tradeo
a single and t ha t no add it iona l security c hecks ar e needed for b id events be tween th ese serv ic es.

topic (pub/sub), separate queues (poin t-to-point) for each ser vice, or REST via the Online A uction API layer .

W e will use periodic manual code reviews to ensure tha t asynchronous pub/sub mes‐
W e will use separate queues for the Bid Streamer and Bidder Tracker services.

saging is being used between the Bid Capture ser vice, Bid Streamer service, and Bid

The Bid Capture ser vice does not need an y information from the Bid Streamer ser‐

der Tracker ser vice.

vice or Bidder Tracker ser vice (comm unication is only one-way).

The Bid Streamer ser vice m ust receive bids in the exact order they were accepted by the Bid Capture ser vice. U sing messaging and queues automatically guaran tees the bid order for the stream by leveraging first-in, first out (FIFO) queues.

A uthor : Subashini N adella A pproved: ARB Meeting M embers, 14 J AN 2026

Last U pdated: 14 J AN 2026

M ultiple bids come in for the same amount (for exam ple, “ do I hear a hundred?”). The Bid Streamer ser vice only needs the first bid received for tha t amount, whereas the Bidder Tracker needs all bids received. U sing a topic (pub/sub) would require the Bid

Storing ADRs Once an architect creates an ADR, they need to store it somewhere. Regardless of where that is, each architectural decision should ha ve its own file or wiki page. Some architects like to keep ADRs in the same Git repositor y as the source code, allowing the team to version and track ADRs as they would so

Streamer to ignore bids that are the same as the prior amoun t, forcing the Bid

Streamer to store shared state between instances.

The Bid Streamer ser vice stores the bids for an item in an in-memory cache, whereas the Bidder Tracker stores bids in a database. The Bidder Tracker will therefore be Architectural Decision Records | 75

H owever , for larger organizations, we caution against this practice for several reasons.

First, ever yone who needs to see the architectural decision migh t not have access to the Git repositor y con taining the ADRs. Second, the application ’ s Git repositor y is not a good place to store ADRs that ha ve a context outside of it (such as integra tion architectural decisions, enterprise architectural decisions, or decisions tha t are com‐

mon to ever y a pplication). For these reasons, we recommend storing ADRs in a dedi‐

cated ADR Git repository to which ever yone has access, a wiki (using a wiki templa te), or a shared director y on a shared file ser ver tha t can be accessed easily by a wiki or other document-rendering software.

Figure 4-5 shows what this directory structure (or wiki page naviga tion structure) might look like.

76 | Chapter 4: Architectural Decisions


Fi gur e 4-5. Exampl e di re ctory structu re f or storin g ADRs The app lic a tion directory contains architectural decisions tha t are specific to some

sort of applica tion (or product) context. This director y is subdivided in to further directories: Com mon The com mon subdirector y is for architectural decisions tha t apply to all a pplica‐

tions, such as “ All framework-rela ted classes will contain an annota tion (@Framework in J ava) or a ttribute ([Framework] in C#) identifying the class as belonging to the underlying framework code. ”

Appl icatio n Subdirectories under the app lic a tion director y correspond to the specific a pplica‐

tion or system context and con tain architectural decisions specific to that appli‐

cation or system (in this exam ple, the A TP and PSTD applica tions).

I nte gra tion The in tegra tion director y con tains ADRs that involve comm unication between

applica tion, systems, or ser vices.

En ter p rise Enterprise architecture ADRs are con tained within the enterprise director y , indi‐

cating tha t these are global architectural decisions impacting all systems and applica tions. An example of an enterprise architecture ADR would be “ All access to a system database will only be from the owning system, ” preventing databases from being shared across multiple systems.

Architectural Decision Records | 77

When storing ADRs in a wiki, the same structure applies, with each directory struc‐

ture representing a na vigational landing page. Each ADR is represented as a single wiki page within each naviga tional landing page (Applica tion, Integra tion, or Enter‐

prise).

The director y and landing-page names indica ted in this section are only recommen‐

dations and exam ples. Choose whatever names fit the compan y’ s situation, as long as those names are consistent across teams.

ADRs as Documentation Documenting software architecture has alwa ys been difficult. While some standards are emerging for diagramming architecture (such as software architect Simon Brown ’ s C4 Model or The Open Group ArchiM ate standard), no agreed-upon stan‐
dard exists for documenting software architecture. Tha t’ s where ADRs come in.

ADRs can be an effective means to document a software architecture. The Con text section provides an excellent opportunity to describe the specific area of the system that requires an architectural decision to be made, as well as to describe the alterna‐

tives. M ore importan tly , the Decision section describes the reasons wh y a particular decision is being made, which is by far the best form of architectural documenta tion.

Using ADRs with Existing Systems Man y architects question the usefulness of ADRs for existing systems. After all, archi‐

The Consequences section adds the final piece of the puzzle by describing the trade-

off analysis for the decision—-for example, the reasons (and trade-offs) for choosing performance over scalability .

tectural decisions have already been made and the system is in production. Do ADRs ser ve an y real purpose at this point? In fact, they do . Remember , ADRs are more than just documenta tion—-they help architects and developers understand why a decision was made and if it was the most appropria te one.

Using ADRs for Standards V er y few developers like standards. U nfortunately , standards are sometimes more about control ra ther than providing a useful purpose. U sing ADRs for standards can change this bad practice. For exam ple, the Context section of an ADR describes the situation tha t is forcing the organizatio

Start by writing some ADRs for the more significant architectural decisions made and questioning whether those decisions are the right ones or not. F or example, maybe a group of services are sharing a single database. Wh y? Is there a good reason?

Should the data be broken a part?


sion section of an ADR can thus indica te not only what the standard is, but more importan tly , wh y it needs to exist.

Part of the journey of incorpora ting ADRs into an existing system is doing a little investiga tive work to uncover these why questions. U nfortunately , the person who made the original decision might ha ve left the compan y a long time ago , so no one knows the answer . In these cases it’ s up to the architect to identify and analyze the alternatives and the trade-offs of each option and a ttem

This is a great wa y to qualif y whether a particular standard should even exist in the first place. If an architect can ’ t justif y it, then perhaps it isn ’ t a good standard to set and enforce. Furthermore, the more developers understand wh y a particular standard

exists, the more likely they are to follow it (and, correspondingly , not challenge it).

The Consequences section of an ADR is another great place to qualify whether a standard is valid: it requires the architect to think about and document the standard ’ s implica tions and consequences, and whether the particular standard should be imple‐

sions starts to build up the justifications and ra tionales (and brain trust) for the sys‐

tem and can help identify architectural inefficiencies and incorrect system design.

mented or not.

Leveraging Generative AI and LLMs in Architectural Decisions One of the many in triguing aspects of generative AI is whether architects can use it to help make and validate decisions. Should services use messaging, streaming, or event sourcing when sending downstream data? Should the da tabase remain as a single

78 | Chapter 4: Architectural Decisions

each paymen t type?

M ost architects already know the answer to these questions—-it depends! Coming back to our first law of software architecture, everythin g in soware ar chit ecture is a trade-o. Decisions like these depend on a lot of factors, including the specific con‐

text in which the decision is applied. E ver y situation and every environmen t is differ‐

ent, which is wh y there are no “best practices ” for these sorts of structural questions.

M ost LLMs base their results largely on probability . In other words, what is the most probable answer given the context of the prom pt, and what is the “best practice ” for this problem? H owever , probability and “best practices” ha ve no place in making architectural decisions. Answering architectural questions requires a careful analysis of the trade-offs involved and a pplying a specific business and technical context to identify the most appropria te choice. For example, i

Architectural Decision Records | 79

and will drive most of the decision-making process towards optimizing maintainabil‐

ity .

Architectural decisions require translating business concerns (such as time-to-market or sustained growth) into architectural characteristics (such as main tainability , testa‐

bility , deployability , and so on). This translation is not always obvious, and getting it right requires years of experience. Once com pleted, it ser ves as a basis for trade-off analysis. For exam ple, deciding whether to have a single ser vice for pa yment process‐
ing or a ser vice per pa ymen t type boils down to a trade-off between maintainability and performance: a single ser vice provides better performance, but m ultiple ser vices provides better maintainability . If the business is primarily concerned about time-to-

80 | Chaptermaintainability
market, 4: Architectural Decisions
is far more im portant than performance, so separate services would be the appropria te choice for this specific context.

Because of the ver y specific and individualistic na ture of analyzing trade-offs and business context, it is difficult for genera tive AI as it currently exists to arrive at the most appropria te architectural decision. The best-case scenario, based on recen t experiments your a uthors have done, is to have a genera tive AI model outline the possible trade-offs of a decision, to assist in

the most appropria te architectural decision.


About the Authors

Mark Richards is an experienced hands-on software architect in volved in the archi‐

tecture, design, and implemen tation of microser vices and other distributed architec‐

tures. H e is the founder of Develop erT oArch itect.co m, a website devoted to assisting

developers in the journey from developer to a software architect.

Neal F ord is director , software architect, and meme wrangler at Though tW orks, a global IT consultancy with an exclusive focus on end-to-end software development and deliver y . Before joining ThoughtW orks, Neal was the chief technology officer at The DSW Group , L td., a nationally recognized training and developmen t firm.

You might also like