Software Architecture Patterns for Serverless Systems: Architecting for innovation with event-driven microservices [Second Edition] 9781803235448

Delve into the second edition to master serverless proficiency and explore new chapters on security techniques, multi-re

134 4

English Pages 601 Year 2024

Report DMCA / Copyright

DOWNLOAD EPUB FILE

Table of contents :
Preface
Who this book is for
What this book covers
To get the most out of this book
Architecting for Innovation
Continuously delivering business value
By the skin of our teeth
Through high-velocity teamwork
Dissecting lead time
Risk mitigation
Decision making
Software development life cycle methodology
Hardware provisioning
Deployments
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
Asynchronous inter-service communication
Fortified boundaries
Event-first – valuing facts
Inversion of responsibility
Events as first-class citizens
Idempotence and ordered tolerance
Serverless-first – creating knowledge
Self-service
Disposable architecture
Data life cycle – fighting data gravity
Micro frontends – equalizing tiers
Observability – optimizing everything
Organic evolution – embracing change
Summary
Defining Boundaries and Letting Go
Learning the hard way
Building on proven concepts
Domain-driven design
Bounded context
Domain aggregate
Domain event
SOLID principles
Single Responsibility Principle
Open-Closed Principle
Liskov Substitution Principle
Interface Segregation Principle
Dependency Inversion Principle
Hexagonal Architecture
Function-level (nano)
Service-level (micro)
Subsystem-level (macro)
Thinking about events first
Start with event storming
Focus on verbs instead of nouns
Treat events as facts instead of ephemeral messages
Turn APIs inside out by treating events as contracts
Invert responsibility for invocation
Connect services through 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
Separate cloud accounts
External domain events
Dissecting an autonomous subsystem
Context diagram
Micro frontend
Event hub
Autonomous service patterns
Backend For Frontend
External Service Gateways
Control services
Dissecting an autonomous service
Repository
CI/CD pipeline and GitOps
Tests
Stack
Persistence
Trilateral API
Events
API Gateway
Functions
Nano architecture
Micro architecture
Shared libraries
Governing without impeding
Providing automation and cross-cutting concerns
Promoting a culture of robustness
Harnessing the four key team metrics
Summary
Taming the Presentation Tier
Presentation tier innovation – 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
The index file
The importmap file
Micro-app registration
Micro-app
The entry file
Root component
Micro-app activation
Micro-app life cycle
Route-based activation
Manual activation
Mount points
Manifest deployer
Inter-application communication
Designing for offline-first
Transparency
Status indicators
Outbox
Inbox
Local cache
Caching code
Caching data reads
Caching data writes
Live updates
WebSocket
Long polling
Summary
Trusting Facts and Eventual Consistency
Living in an eventually consistent world
Staging
Cooperative
Atomic
Consistency
Transparency
Facts
Chain reaction
Concurrency and partitions
Order tolerance and idempotence
Parallelism
Publishing to an event hub
Event bus
Domain events
Event envelope
Event-carried state transfer
Substitution
Internal versus external
Routing and channel topology
Dissecting the Event Sourcing pattern
System-wide event sourcing
Event lake
Perpetual storage
Indexing events
Replaying events
Event streams
Temporal storage
Stream-first event sourcing
Concurrency control
Micro-event stores
Processing event streams
Micro batching
Choosing a programming paradigm
Imperative programming
Functional reactive programming
Stream processing
Creating a stream
Unit of work
Filtering and multiplexing
Mapping
Connectors
Designing for failure
Backpressure and rate limiting
Poison events
Fault events
Resubmission
Optimizing throughput
Batch size function parameter
Asynchronous non-blocking I/O
Pipelines and multiplexing
Pipeline patterns
Sharding
Batching and grouping
Batching
Grouping
Summary
Turning the Cloud into the Database
Fighting data gravity
Competing demands
Insufficient capacity
Intractable volumes
Embracing the 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
System wide 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
Restaurant service
Customer service
Cart service
Delivery service
Leveraging change data capture
Database-first event sourcing
Soft deletes
Latching
Summary
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
A BFF service is decoupled, autonomous, and resilient
Dissecting the Backend for Frontend pattern
Datastore
API gateway
Query and command functions
Listener function
Trigger function
Dissecting function-level nano architecture
Models
Connectors
Handlers
Choosing between REST and GraphQL
REST
GraphQL
Implementing different kinds of BFF services
CRUD BFF services
List-of-values (Lov) BFF services
Task BFF services
Search BFF services
Action BFF services
Dashboard BFF services
Reporting BFF services
Archive BFF services
Summary
Bridging Intersystem Gaps
Creating an anti-corruption layer
Macro-level ports and adapters
Substitution principle
External bulkhead
Dissecting the External Service Gateway pattern
Connectivity
Semantic transformation
Ingress
Egress
Packaging
Separate cloud accounts
Integrating with third-party systems
Egress – API call
Ingress – webhook
Asynchronous request response
Synchronous ESG/BFF hybrid
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
Providing an open API and SPI
Ingress API – event
Ingress API – command
Egress SPI – webhook
Egress API – query
Tackling common data challenges
Idempotence
Enriching data
Latching and cross-referencing
Slow data resync
Summary
Reacting to Events with More Events
Promoting inter-service collaboration
Choreography’s pros and cons
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 complex event processing (CEP) logic
Decision tables
Missing events
Leveraging machine learning (ML) for control flow
Models
Predictions
Summary
Running in Multiple Regions
Justifying multi-regional deployment
Regional disruptions
Nominal cost
Higher user satisfaction
Choosing a regional topology
Primary/hot-secondary
Active/active
Balanced users
Balanced data processing
Preparing for regional failover
Offline-first
Protracted eventual consistency
Checking regional health
Traditional health checks
Regional health checks
Metrics
Regional health check service
Configuring regional routing
Content Delivery Network (CDN)
API Gateway
Regional endpoints
Global endpoints
CDN plus API Gateway
Global bus
Replicating across regions
Change event vs domain event replication
Multi-master replication
Round-robin replication
Dissecting regional failover
Query failover
Command failover
Trigger failure points
Listener failure points
Addressing intersystem differences
External global endpoints
Legacy regional endpoints
Implementing multi-regional cron jobs
Inserting job records and events
Relying on replication and idempotence
Summary
Securing Autonomous Subsystems in Depth
Shared responsibility model
Securing cloud accounts
Accounts-as-code
Identity access management
Securing CI/CD pipelines
Pipeline permissions
Deployment service permissions
Permission boundaries
Securing the perimeter
Global/edge infrastructure
Encryption in transit
Federated identity
Securing the frontend
OpenID Connect
Conditional rendering
Protected routes
Passing the JWT to BFF services
Securing BFF services
JWT authorizer
JWT assertion
JWT filter
Last modified by
Least privilege
Redacting sensitive data
Envelope encryption
Crypto-shredding
Securing ESG services
Securing shared secrets
Using API keys
Auditing continuously
Build-time and runtime auditing
Change event audit
Summary
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
Natural
Keystone
Artificial
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
Story mapping
Story planning
Task roadmaps
Turning the crank
Task branch workflow
Create task branch
Create draft pull request
Ready for review
Merge to master
Accept canary deployment
Feature flipping
Exploratory testing
Beta users
General availability
Dissecting CI/CD pipelines
Continuous integration pipeline
Serverless testing honeycomb
Unit testing
Integration testing
Contract testing
Transitive end-to-end testing
Continuous deployment pipeline
Regional canary deployments
Synthetics
Summary
Optimizing Observability
Failing forward fast
Turning observability inside out
Leveraging FinOps
Cost is a metric
Dissecting monthly cloud cost
Worth-based development
Collecting resource metrics
The USE method
Capacity and concurrency limits
Throttling, iterator age, and queue depth
Errors and fault events
Tracking system events
Alerting on work metrics
The RED method
BFF service metrics
Domain event metrics
Anomaly detection
Observing real user activity
Real User Monitoring (RUM)
Synthetics
Tuning continuously
Function memory allocation
Cold starts
Timeouts and retries
Cache-control
Summary
Don’t Delay, Start Experimenting
Gaining trust and changing culture
Establishing a vision
Building momentum
Constructing an architectural runway
Seeding and splitting teams
Funding products, not projects
Architecture-driven funding
Team capacity-driven funding
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
Index

Software Architecture Patterns for Serverless Systems: Architecting for innovation with event-driven microservices [Second Edition]
 9781803235448

  • 0 0 0
  • Like this paper and download? You can publish your own PDF file online for free in a few minutes! Sign Up
Recommend Papers