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 demonstrating how to implement and operate anti-fragile systems. You'll divide up a system and define boundaries so that teams can work autonomously and accelerate the pace of innovation. The book also covers low-level event and data patterns that support the entire architecture, while getting you up and running with the different autonomous service design patterns. As you progress, you'll focus on best practices for security, reliability, testability, observability, and performance. Finally, the book combines all that you've learned, explaining the methodologies of continuous experimentation, deployment, and delivery before providing you with 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
Publisher
Packt
Pages
436
ISBN
9781800207035

 

Table of Contents

Preface

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

Microservices

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

Summary

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

Repository

CI/CD pipeline and GitOps

Tests

Stack

Persistence

Trilateral API

Functions

Micro-app

Shared libraries

Governing without impeding

Leveraging observability

Facilitating a culture of robustness

Audit continuously

Securing the perimeter

Elevating TestOps

Automating account creation

Summary

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

Micro-app activation

Mount points

Manifest deployer

Inter-application communication

Designing for offline-first

Transparency

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

RUM

Synthetics

Summary

Chapter 4: Trusting Facts and Eventual Consistency

Living in an eventually consistent world

Staging

Consistency

Concurrency and partitions

Order tolerance and idempotence

Parallelism

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

Mapping

Connectors

Designing for failure

Backpressure and rate limiting

Poison events

Fault events

Resubmission

Optimizing throughput

Batch size

Asynchronous non-blocking I/O

Pipelines and multiplexing

Sharding

Batching and grouping

Observing throughput

Work metrics

Iterator age

Fault events

Accounting for regional failover

Protracted eventual consistency

Regional messaging channels

Summary

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

Projections

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

Latching

Replicating across regions

Multi-master replication

Round-robin replication

Regional failover, protracted eventual consistency, and order tolerance

Observing resource metrics

Capacity

Throttling and errors

Performance

Redacting sensitive data

Envelope encryption

General Data Protection Regulation (GDPR)

Summary

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

Datastore

API Gateway

Query and command functions

Listener function

Trigger function

Models and connectors

Choosing between GraphQL and REST

REST

GraphQL

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

cache-control

Summary

Chapter 7: Bridging Intersystem Gaps

Creating an anti-corruption layer

Dissecting the External Service Gateway pattern

Connectivity

Semantic transformation

Action versus reaction

Egress

Ingress

Packaging

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

Idempotence

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

Summary

Chapter 8: Reacting to Events with More Events

Promoting inter-service collaboration

Dissecting the Control Service pattern

collect

correlate

collate

evaluate

emit

expire

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

Models

Predictions

Implementing multi-regional cron jobs

Job records and events

Replication and idempotence

Summary

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

Experiments

Story backlog

Task roadmaps

Turning the crank

Task branch workflow

Continuous integration pipeline

Continuous deployment pipeline

Feature flipping

Summary

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

Architecture-driven

Team capacity-driven

Dissecting the Strangler pattern

Event-first migration

Micro frontend – headless mode

Retirement

Addressing event-first concerns

System of record versus source of truth

Duplicate data is good

Avoid false reuse

Poly everything

Polyglot programming

Polyglot persistence

Polycloud

Summary

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 for FREE
Start free trial