About this book

As businesses are undergoing a digital transformation to keep up with competition, it is now more important than ever for IT professionals to design systems to keep up with the rate of change while maintaining stability.

This book takes you through the architectural patterns that power enterprise-grade software systems and the key architectural elements that enable change (such as events, autonomous services, and micro frontends), along with showing you how to implement and operate anti-fragile systems.

First, you’ll divide up a system and define boundaries so that your teams can work autonomously and accelerate innovation. You’ll cover low-level event and data patterns that support the entire architecture, while getting up and running with the different autonomous service design patterns.

Next, the book will focus on best practices for security, reliability, testability, observability, and performance. You’ll combine all that you've learned and build upon that foundation, exploring the methodologies of continuous experimentation, deployment, and delivery before delving into some final thoughts on how to start making progress.

By the end of this book, you'll be able to architect your own event-driven, serverless systems that are ready to adapt and change so that you can deliver value at the pace needed by your business.

Publication date:
July 2021


Table of Contents


Section 1: Establishing an Architectural Vision

Chapter 1: Architecting for Innovation

Continuously delivering business value

By the skin of our teeth

Through high-velocity teamwork

Taking control of lead time

Risk mitigation

Decision making

Software Development Life Cycle methodology

Hardware provisioning

Software deployment

Software structure

Testing and confidence

Dependencies and inter-team communication

Dissecting integration styles

Batch integration

Spaghetti integration

Real-time integration

Enterprise application integration

Shared database

Service-oriented architecture


Enabling autonomous teams with autonomous services

Autonomous services – creating bulkheads

Event-first – valuing facts

Serverless-first – creating knowledge

Data life cycle – fighting data gravity

Micro frontends – equalizing tiers

Observability – optimizing everything

Organic evolution – embracing change


Chapter 2: Defining Boundaries and Letting Go

Building on SOLID principles

Single Responsibility Principle

Open-Closed Principle

Liskov Substitution Principle

Interface Segregation Principle

Dependency Inversion Principle

Thinking about events first

Event storming

Verbs versus nouns

Facts versus ephemeral messages

Contracts versus notifications

React and evolve

Powered by an event hub

Dividing a system into autonomous subsystems

By actor

By business unit

By business capability

By data life cycle

By legacy system

Creating subsystem bulkheads

Decomposing a subsystem into autonomous services

Context diagram

Micro frontend

Event hub

Autonomous service patterns

Dissecting an autonomous service


CI/CD pipeline and GitOps




Trilateral API



Shared libraries

Governing without impeding

Leveraging observability

Facilitating a culture of robustness

Audit continuously

Securing the perimeter

Elevating TestOps

Automating account creation


Section 2: Dissecting the Software Architecture Patterns

Chapter 3: Taming the Presentation Tier

Zigzagging through time

Client-side versus server-side rendering

Build-time versus runtime rendering

Web versus mobile

Breaking up the frontend monolith

By subsystem

By user activity

By device type

By version

Dissecting micro frontends

The main app


Micro-app activation

Mount points

Manifest deployer

Inter-application communication

Designing for offline-first


Local cache

Live updates

Regional failover

Securing the user experience

OpenID Connect

Conditional rendering

Protected routes

Passing the JWT to BFF services

Observing real user activity




Chapter 4: Trusting Facts and Eventual Consistency

Living in an eventually consistent world



Concurrency and partitions

Order tolerance and idempotence


Publishing to an event hub

Event bus

Domain events

Routing and channel topology

Dissecting the Event Sourcing pattern

Systemwide event sourcing

Event lake

Event streams

Micro event stores

Processing event streams

Batch size

Functional reactive programming

Unit of work

Filtering and multiplexing



Designing for failure

Backpressure and rate limiting

Poison events

Fault events


Optimizing throughput

Batch size

Asynchronous non-blocking I/O

Pipelines and multiplexing


Batching and grouping

Observing throughput

Work metrics

Iterator age

Fault events

Accounting for regional failover

Protracted eventual consistency

Regional messaging channels


Chapter 5: Turning the Cloud into the Database

Escaping data's gravity

Competing demands

Insufficient capacity

Intractable volumes

Embracing data life cycle

Create phase

Use phase

Analyze phase

Archive phase

Turning the database inside out

The transaction log

Derived data

Dissecting the CQRS pattern

Systemwide CQRS

Materialized views

Inbound bulkheads

Live cache

Capacity per reader, per query

Keeping data lean


Time to live

Implementing idempotence and order tolerance

Deterministic identifiers

Inverse optimistic locking

Immutable event triggers

Modeling data for operational performance

Nodes, edges, and aggregates

Sharding and partition keys

Single table design examples

Leveraging change data capture

Database-first event sourcing

Soft deletes


Replicating across regions

Multi-master replication

Round-robin replication

Regional failover, protracted eventual consistency, and order tolerance

Observing resource metrics


Throttling and errors


Redacting sensitive data

Envelope encryption

General Data Protection Regulation (GDPR)


Chapter 6: A Best Friend for the Frontend

Focusing on user activities

A BFF service is responsible for a single user activity

A BFF service is owned by the frontend team

Decoupled, autonomous, and resilient

Dissecting the Backend for Frontend (BFF) pattern


API Gateway

Query and command functions

Listener function

Trigger function

Models and connectors

Choosing between GraphQL and REST



Implementing different kinds of BFF services

Task BFF services

Search BFF services

Action BFF services

Dashboard BFF services

Reporting BFF services

Archive BFF services

Securing a BFF in depth

The perimeter

Federated identity

In transit

JWT authorizer

JWT assertion

JWT filter

Last modified by

Least privilege

At rest

Leveraging multiple regions

Latency-based routing

Regional health checks

Regional failover

Observing BFF metrics

Work metrics

Throttling and concurrency limits

Optimizing BFF performance

Function memory allocation

Cold starts

Timeouts and retries



Chapter 7: Bridging Intersystem Gaps

Creating an anti-corruption layer

Dissecting the External Service Gateway pattern


Semantic transformation

Action versus reaction




Separate cloud accounts

Integrating with third-party systems

Egress – API call

Ingress – webhook

Asynchronous request response

Integrating with other subsystems

Egress – upstream subsystem

Ingress – downstream subsystem

Integrating across cloud providers

Integrating with legacy systems

Ingress – Change Data Capture

Egress – Direct SQL

Egress – circuit breaker

Ingress – relay

Egress – relay

Providing an external API and SPI

Ingress – event

Ingress – command

Egress – webhook

Egress – query

Tackling common data challenges


Enriching data

Latching and cross-referencing

Slow data resync

Managing shared secrets

Securing secrets

Using API keys

Addressing multi-regional differences

Egress routing and failover

Ingress routing and failover


Chapter 8: Reacting to Events with More Events

Promoting inter-service collaboration

Dissecting the Control Service pattern







Orchestrating business processes

Entry and exit events

Parallel execution

Employing the Saga pattern

Compensating transactions

Abort events

Calculating event-sourcing snapshots

What is ACID 2.0?

Snapshot events

Implementing CEP logic

Decision tables

Missing events

Leveraging ML for control flow



Implementing multi-regional cron jobs

Job records and events

Replication and idempotence


Section 3: Putting Everything in Motion

Chapter 9: Choreographing Deployment and Delivery

Optimizing testing for continuous deployment

Continuous discovery

Continuous testing

Focusing on risk mitigation

Small batch size

Decoupling deployment from release

Feature flags

Fail forward fast

Achieving zero-downtime deployments

The Robustness principle

Between the frontend and its backend

Between producers and consumers

Between the backend and its data store

Planning at multiple levels


Story backlog

Task roadmaps

Turning the crank

Task branch workflow

Continuous integration pipeline

Continuous deployment pipeline

Feature flipping


Chapter 10: Don't Delay, Start Experimenting

Gaining trust and changing culture

Establishing a vision

Building momentum

Constructing an architectural runway

Seed and split

Funding products, not projects


Team capacity-driven

Dissecting the Strangler pattern

Event-first migration

Micro frontend – headless mode


Addressing event-first concerns

System of record versus source of truth

Duplicate data is good

Avoid false reuse

Poly everything

Polyglot programming

Polyglot persistence



Other Books You May Enjoy

About the Author

  • John Gilbert

    John Gilbert is a CTO with over 30 years of experience in architecting and delivering software systems across many industries. His cloud journey has spanned all the levels of cloud maturity, from lift and shift and software-defined infrastructure to microservices and continuous deployment. He was an early serverless adopter and put his first serverless workloads into production just months after AWS Lambda's introduction. He has also authored Cloud Native Development Patterns and Best Practices and JavaScript Cloud Native Development Cookbook. He finds delivering serverless solutions to be, by far, the most fun and satisfying, as they force us to rewire how we reason about systems and enable us to accomplish far more with much less effort and risk.

    Browse publications by this author
Software Architecture Patterns for Serverless Systems
Unlock this book and the full library FREE for 7 days
Start now