Book Review: “Software Systems Architecture” (Second Edition)
This book is by Nick Rozanski and Eoin Woods.
I am not a software architect, but I really enjoy studying about software architecture. This book does a great job of breaking down such a huge topic into clear, digestible, and actionable pieces.
One of the biggest benefits this book’s approach has given me so far is a way of drawing my attention to specific aspects of the architecture and giving me specific places to record (and later look for) architectural decisions. This is a huge help if you ever feel overwhelmed when facing a large architecture. By making different areas of focus explicit, the book helps you find missing parts of your architecture. This is invaluable.
This book covers working with stakeholders, identifying business goals and drivers and tracing goals and drivers throughout the system but I'm just going to jump into the middle of the book.
Have you ever worked on a project where someone showed you “the architectural diagram”? You know the one, with hundreds of boxes, actors, databases, and nodes? Not to mention hundreds of lines connecting all the pieces? Sure, it’s complete, but who cares if you can’t read it.
Like other approaches to architecture, this book breaks the single architecture into pieces. This book uses two kinds of pieces: Viewpoints and Perspectives.
A Viewpoint is one aspect of the architecture that has its own purpose, concerns, and models.
I'll briefly describe each Viewpoint (some viewpoints will be very brief).
This viewpoint describes how the system you're building is connected to its environment. It lists the actors that interact with the system, the dependencies on other systems that the system has, as well as the systems dependent on the system.
No one wants to build a system and find out that they've missed an important intersystem dependency. This viewpoint helps with that especially if you can get the stakeholders to help you identify those other systems.
For each system you identify in your context, you can classify them as data producers or consumers, service providers or consumers, or event providers or consumers. Once you’ve classified all the other systems your system will interact with, you can add to your architectural design class-specific properties that will flesh out what kinds of interactions you expect with the other systems. This also helps identify what systems may need to be changed if your system is replacing another system.
As with most viewpoints, the work you do to develop the viewpoint will help you later on.
This viewpoint identifies the major modules in your system and assigns responsibilities to them and shows how they interact with each other. Here is where you can start getting an idea about the design quality of your system: cohesion, coupling, separation of concerns, etc.
The model you build for the functional viewpoint is typically a UML component diagram where each module is rendered as a component and dependencies between components are drawn and given some detail. You might have a shopping cart module, a checkout module, a shipping module, and a billing module. In this case the model would list those four modules and show how they interacted with each other.
Once you identify the modules, you specify their interfaces, contracts, preconditions, postconditions, semantics, exception cases, and invariants. This is all done at a high level so as to give developers freedom in the way they implement the modules and their internals.
Your system probably operates on data in some form or another. This viewpoint helps you focus on three aspects of your data: its shape, its flow and its lifecycle.
You describe the shape of the data using either UML class diagrams or Entity Relationship Diagrams. This will help you find missing connections, unspecified multiplicities between entities, and missing properties. It will also help make sure that you have a consistent data model.
You describe the flow of the data using data flow diagrams. You can go back to your Context viewpoint and examine all of the system dependencies to make sure that you've handled the types of data that flow between systems and what systems the data flows between.
Sometimes your data has an interesting life cycle. You describe the lifecycle of the data using either UML state machines or using an entity life history diagram (here’s an example).
This viewpoint details the processes and threads that make up the system along with which processes or threads various modules are assigned to. It also details coordination between the processes and threads. This viewpoint also details the states of some of the critical elements of the system. This viewpoint will help identify resource contention, deadlock conditions, excessive complexity, race conditions and other concurrency problems.
This viewpoint focuses on the construction of the system, its modules, necessary utility modules, testing, instrumentation and configuration management approaches. This viewpoint also guides you as you organize modules into layers of your architecture. It helps you concentrate on cross-cutting concerns like internationalization, error reporting, data conversions, etc.
The deployment viewpoint documents the hardware you need, the networking configuration you need, and the software to be installed on your various nodes. When you overlay the Context and Information Viewpoints you can make estimates about the bandwidth/latency you'll need between nodes. You can also make sure that every process identified in the Concurrency Viewpoint is allocated to a collection of nodes.
This viewpoint describes how the system will be monitored, administered and supported in production. It covers data migrations, software releases, configuration management, monitoring, and more.
By looking at two viewpoints together you can perform consistency checks. The book lists a number of viewpoint combinations that offer useful consistency checks. For example, by examining the Context and Information viewpoints, you can make sure that you've accounted for all of the kinds of data flowing between all of your system’s dependencies. By examining the Functional and Concurrency viewpoint you can ensure that all of the modules in your system are running in one or more processes.
The book also covers a number of perspectives that cross-cut the architecture so broadly, they cannot be limited to a single Viewpoint. For example Security, Scalability, Availability, Usability. The book lists a number of perspectives and lists activities to help you ensure that each perspective is applied to the right places.
For example, it shows you how you can apply the Security perspective to the Context viewpoint to make sure that you identify and mitigate security risks that might originate from other systems. It can also guide you to focus on making sure that the correct security protocols are in place for any intersystem communication.
This book helps you be more organized in your reasoning about an architecture by giving you places to focus (Viewpoints), ways of reasoning about how those focus points relate to each other (Viewpoint Consistency), and how to ensure that cross-cutting concerns are applied in the correct places (Perspectives).
I would recommend this book to anyone interested in developing system architectures. It has plenty of references, great diagrams, and it’s well-structured.