Table of Contents
Microservices Patterns by Chris Richardson
About the Book
About this book
The goal of this book is to teach you how to successfully develop applications using the microservice architecture.
Not only does it discuss the benefits of the microservice architecture, it also describes the drawbacks. You’ll learn when you should consider using the monolithic architecture and when it makes sense to use microservices.
Who should read this book
The focus of this book is on architecture and development. It’s meant for anyone responsible for developing and delivering software, such as developers, architects, CTOs, or VPs of engineering.
The book focuses on explaining the microservice architecture patterns and other concepts. My goal is for you to find this material accessible, regardless of the technology stack you use. You only need to be familiar with the basics of enterprise application architecture and design. In particular, you need to understand concepts like three-tier architecture, web application design, relational databases, interprocess communication using messaging and REST, and the basics of application security. The code examples, though, use Java and the Spring framework. In order to get the most out of them, you should be familiar with the Spring framework.
Chapter Summary
Roadmap
This book consists of 13 chapters:
Chapter 1 describes the symptoms of monolithic hell, which occurs when a monolithic application outgrows its architecture, and advises on how to escape by adopting the microservice architecture. It also provides an overview of the microservice architecture pattern language, which is the organizing theme for most of the book.
Chapter 2 explains why software architecture is important and describes the patterns you can use to decompose an application into a collection of services. It also explains how to overcome the various obstacles you typically encounter along the way.
Chapter 3 describes the different patterns for robust, interprocess communication in a microservice architecture. It explains why asynchronous, message-based communication is often the best choice.
Chapter 4 explains how to maintain data consistency across services by using the Saga pattern. A saga is a sequence of local transactions coordinated using asynchronous messaging.
Chapter 5 describes how to design the business logic for a service using the domain-driven design (DDD) Aggregate and Domain event patterns.
Chapter 6 builds on chapter 5 and explains how to develop business logic using the Event sourcing pattern, an event-centric way to structure the business logic and persist domain objects.
Chapter 7 describes how to implement queries that retrieve data scattered across multiple services by using either the API composition pattern or the Command query responsibility segregation (CQRS) pattern.
Chapter 8 covers the external API patterns for handling requests from a diverse collection of external clients, such as mobile applications, browser-based JavaScript applications, and third-party applications.
Chapter 9 is the first of two chapters on automated testing techniques for microservices. It introduces important testing concepts such as the test pyramid, which describes the relative proportions of each type of test in your test suite. It also shows how to write unit tests, which form the base of the testing pyramid.
Chapter 10 builds on chapter 9 and describes how to write other types of tests in the test pyramid, including integration tests, consumer contract tests, and component tests.
Chapter 11 covers various aspects of developing production-ready services, including security, the Externalized configuration pattern, and the service observability patterns. The service observability patterns include Log aggregation, Application metrics, and Distributed tracing.
Chapter 12 describes the various deployment patterns that you can use to deploy services, including virtual machines, containers, and serverless. It also discusses the benefits of using a service mesh, a layer of networking software that mediates communication in a microservice architecture.
Chapter 13 explains how to incrementally refactor a monolithic architecture to a microservice architecture by applying the Strangler application pattern: implementing new features as services and extracting modules out of the monolith and converting them to services.
Brief Table of Contents
- Preface
- Acknowledgments
- About this book
- About the cover illustration
- Chapter 1. Escaping monolithic hell
- Chapter 2. Decomposition strategies
- Chapter 4. Managing transactions with sagas
- Chapter 8. External API patterns
- Chapter 9. Testing microservices: Part 1
- Chapter 10. Testing microservices: Part 2
- Chapter 11. Developing production-ready services
- Chapter 12. Deploying microservices
- Chapter 13. Refactoring to microservices
- Index
- List of Figures
- List of Tables
- List of Listings
Detailed Table of Contents
- Copyright
- Brief Table of Contents
- Preface
- Acknowledgments
- About this book
- About the cover illustration
Chapter 1. Escaping monolithic hell
- 1.1. The slow march toward monolithic hell
- 1.1.1. The architecture of the FTGO application
- 1.1.2. The benefits of the monolithic architecture
- 1.1.3. Living in monolithic hell
- 1.2. Why this book is relevant to you
- 1.3. What you’ll learn in this book
- 1.4.1. Scale cube and microservices
- 1.4.4. The FTGO microservice architecture
- 1.6.1. Microservice architecture is not a silver bullet
- 1.6.3. Overview of the Microservice architecture pattern language
- 1.7.3. The human side of adopting microservices
- Summary
Chapter 2. Decomposition strategies
- 2.1. What is the microservice architecture exactly?
- 2.1.1. What is software architecture and why does it matter?
- 2.1.2. Overview of architectural styles
- 2.1.3. The microservice architecture is an architectural style
- 2.2. Defining an application’s microservice architecture
- 2.2.1. Identifying the system operations
- 2.2.2. Defining services by applying the Decompose by business capability pattern
- 2.2.3. Defining services by applying the Decompose by sub-domain pattern
- 2.2.4. Decomposition guidelines
- 2.2.5. Obstacles to decomposing an application into services
- 2.2.6. Defining service APIs
- Summary
Chapter 3. Interprocess communication in a microservice architecture
- 3.1. Overview of interprocess communication in a microservice architecture
- 3.1.1. Interaction styles
- 3.1.2. Defining APIs in a microservice architecture
- 3.1.3. Evolving APIs
- 3.1.4. Message formats
- 3.2. Communicating using the synchronous Remote procedure invocation pattern
- 3.2.1. Using REST
- 3.2.2. Using gRPC
- 3.2.3. Handling partial failure using the Circuit breaker pattern
- 3.2.4. Using service discovery
- 3.3. Communicating using the Asynchronous messaging pattern
- 3.3.1. Overview of messaging
- 3.3.2. Implementing the interaction styles using messaging
- 3.3.3. Creating an API specification for a messaging-based service API
- 3.3.4. Using a message broker
- 3.3.5. Competing receivers and message ordering
- 3.3.6. Handling duplicate messages
- 3.3.7. Transactional messaging
- 3.3.8. Libraries and frameworks for messaging
- 3.4. Using asynchronous messaging to improve availability
- 3.4.1. Synchronous communication reduces availability
- 3.4.2. Eliminating synchronous interaction
- Summary
Chapter 4. Managing transactions with sagas
Managing transactions with sagas:
- 4.1.1. The need for distributed transactions in a microservice architecture
- 4.1.2. The trouble with distributed transactions
- 4.1.3. Using the Saga pattern to maintain data consistency
- 4.2. Coordinating sagas
- 4.2.1. Choreography-based sagas
- 4.2.2. Orchestration-based sagas
- 4.3. Handling the lack of isolation
- 4.3.1. Overview of anomalies
- 4.3.2. Countermeasures for handling the lack of isolation
- 4.4. The design of the Order Service and the Create Order Saga
- 4.4.1. The OrderService class
- 4.4.2. The implementation of the Create Order Saga
- 4.4.3. The OrderCommandHandlers class
- 4.4.4. The OrderServiceConfiguration class
- Summary
Chapter 5. Designing business logic in a microservice architecture
business logic in a microservice architecture
- 5.1. Business logic organization patterns
- 5.1.1. Designing business logic using the Transaction script pattern
- 5.1.2. Designing business logic using the Domain model pattern
- 5.1.3. About Domain-driven design
- 5.2. Designing a domain model using the DDD aggregate pattern
- 5.2.1. The problem with fuzzy boundaries
- 5.2.2. Aggregates have explicit boundaries
- 5.2.3. Aggregate rules
- 5.2.4. Aggregate granularity
- 5.2.5. Designing business logic with aggregates
- 5.3. Publishing domain events
- 5.3.1. Why publish change events?
- 5.3.2. What is a domain event?
- 5.3.3. Event enrichment
- 5.3.4. Identifying domain events
- 5.3.5. Generating and publishing domain events
- 5.3.6. Consuming domain events
- 5.4. Kitchen Service business logic
- 5.4.1. The Ticket aggregate
- 5.5. Order Service business logic
- 5.5.1. The Order Aggregate
- 5.5.2. The OrderService class
- Summary
Chapter 6. Developing business logic with event sourcing
- 6.1.1. The trouble with traditional persistence
- 6.1.2. Overview of event sourcing
- 6.1.3. Handling concurrent updates using optimistic locking
- 6.1.4. Event sourcing and publishing events
- 6.1.5. Using snapshots to improve performance
- 6.1.7. Evolving domain events
- 6.1.8. Benefits of event sourcing
- 6.1.9. Drawbacks of event sourcing
- 6.2. Implementing an event store
- 6.2.1. How the Eventuate Local event store works
- 6.2.2. The Eventuate client framework for Java
- 6.3. Using sagas and event sourcing together
- 6.3.1. Implementing choreography-based sagas using event sourcing
- 6.3.2. Creating an orchestration-based saga
- 6.3.3. Implementing an event sourcing-based saga participant
- 6.3.4. Implementing saga orchestrators using event sourcing
- Summary
Chapter 7. Implementing queries in a microservice architecture
- 7.1. Querying using the API composition pattern
7.1.1. The findOrder() query operation
7.1.2. Overview of the API composition pattern
7.1.3. Implementing the findOrder() query operation using the API composition pattern
7.1.4. API composition design issues
7.1.5. The benefits and drawbacks of the API composition pattern
7.2. Using the CQRS pattern
7.2.1. Motivations for using CQRS
7.2.2. Overview of CQRS
7.2.3. The benefits of CQRS
7.2.4. The drawbacks of CQRS
7.3. Designing CQRS views
7.3.1. Choosing a view datastore
7.3.2. Data access module design
7.3.3. Adding and updating CQRS views
7.4. Implementing a CQRS view with AWS DynamoDB
7.4.1. The OrderHistoryEventHandlers module
7.4.2. Data modeling and query design with DynamoDB
7.4.3. The OrderHistoryDaoDynamoDb class
Summary
Chapter 8. External API patterns
8.1. External API design issues
8.1.1. API design issues for the FTGO mobile client
8.1.2. API design issues for other kinds of clients
8.2. The API gateway pattern
8.2.1. Overview of the API gateway pattern
8.2.2. Benefits and drawbacks of an API gateway
8.2.3. Netflix as an example of an API gateway
8.2.4. API gateway design issues
8.3. Implementing an API gateway
8.3.1. Using an off-the-shelf API gateway product/service
8.3.2. Developing your own API gateway
8.3.3. Implementing an API gateway using GraphQL
Summary
Chapter 9. Testing microservices: Part 1
9.1. Testing strategies for microservice architectures
9.1.1. Overview of testing
9.1.2. The challenge of testing microservices
9.1.3. The deployment pipeline
9.2. Writing unit tests for a service
9.2.1. Developing unit tests for entities
9.2.2. Writing unit tests for value objects
9.2.3. Developing unit tests for sagas
9.2.4. Writing unit tests for domain services
9.2.5. Developing unit tests for controllers
9.2.6. Writing unit tests for event and message handlers
Summary
Chapter 10. Testing microservices: Part 2
10.1. Writing integration tests
10.1.1. Persistence integration tests
10.1.2. Integration testing REST-based request/response style interactions
10.1.3. Integration testing publish/subscribe-style interactions
10.1.4. Integration contract tests for asynchronous request/response interactions
10.2. Developing component tests
10.2.1. Defining acceptance tests
10.2.2. Writing acceptance tests using Gherkin
10.2.3. Designing component tests
10.2.4. Writing component tests for the FTGO Order Service
10.3. Writing end-to-end tests
10.3.1. Designing end-to-end tests
10.3.2. Writing end-to-end tests
10.3.3. Running end-to-end tests
Summary
Chapter 11. Developing production-ready services
11.1. Developing secure services
11.1.1. Overview of security in a traditional monolithic application
11.1.2. Implementing security in a microservice architecture
11.2. Designing configurable services
11.2.1. Using push-based externalized configuration
11.2.2. Using pull-based externalized configuration
11.3. Designing observable services
11.3.1. Using the Health check API pattern
11.3.2. Applying the Log aggregation pattern
11.3.3. Using the Distributed tracing pattern
11.3.4. Applying the Application metrics pattern
11.3.5. Using the Exception tracking pattern
11.3.6. Applying the Audit logging pattern
11.4. Developing services using the Microservice chassis pattern
11.4.1. Using a microservice chassis
11.4.2. From microservice chassis to service mesh
Summary
Chapter 12. Deploying microservices
12.1. Deploying services using the Language-specific packaging format pattern
12.1.1. Benefits of the Service as a language-specific package pattern
12.1.2. Drawbacks of the Service as a language-specific package pattern
12.2. Deploying services using the Service as a virtual machine pattern
12.2.1. The benefits of deploying services as VMs
12.2.2. The drawbacks of deploying services as VMs
12.3. Deploying services using the Service as a container pattern
12.3.1. Deploying services using Docker
12.3.2. Benefits of deploying services as containers
12.3.3. Drawbacks of deploying services as containers
12.4. Deploying the FTGO application with Kubernetes
12.4.1. Overview of Kubernetes
12.4.2. Deploying the Restaurant service on Kubernetes
12.4.3. Deploying the API gateway
12.4.4. Zero-downtime deployments
12.4.5. Using a service mesh to separate deployment from release
12.5. Deploying services using the Serverless deployment pattern
12.5.1. Overview of serverless deployment with AWS Lambda
12.5.2. Developing a lambda function
12.5.3. Invoking lambda functions
12.5.4. Benefits of using lambda functions
12.5.5. Drawbacks of using lambda functions
12.6. Deploying a RESTful service using AWS Lambda and AWS Gateway
12.6.1. The design of the AWS Lambda version of Restaurant Service
12.6.2. Packaging the service as ZIP file
12.6.3. Deploying lambda functions using the Serverless framework
Summary
Chapter 13. Refactoring to microservices
13.1. Overview of refactoring to microservices
13.1.1. Why refactor a monolith?
13.1.2. Strangling the monolith
13.2. Strategies for refactoring a monolith to microservices
13.2.1. Implement new features as services
13.2.2. Separate presentation tier from the backend
13.2.3. Extract business capabilities into services
13.3. Designing how the service and the monolith collaborate
13.3.1. Designing the integration glue
13.3.2. Maintaining data consistency across a service and a monolith
13.3.3. Handling authentication and authorization
13.4. Implementing a new feature as a service: handling misdelivered orders
13.4.1. The design of Delayed Delivery Service
13.4.2. Designing the integration glue for Delayed Delivery Service
13.5. Breaking apart the monolith: extracting delivery management
13.5.1. Overview of existing delivery management functionality
13.5.2. Overview of Delivery Service
13.5.3. Designing the Delivery Service domain model
13.5.4. The design of the Delivery Service integration glue
13.5.5. Changing the FTGO monolith to interact with Delivery Service
Summary
List of Patterns
Application architecture patterns
Decomposition patterns
Messaging style patterns
Reliable communications patterns
Service discovery patterns
Transactional messaging patterns
Data consistency patterns
Business logic design patterns
Querying patterns
External API patterns
Testing patterns
Security patterns
Cross-cutting concerns patterns
Observability patterns
Deployment patterns
Refactoring to microservices patterns
Index
List of Figures
List of Tables
List of Listings
Preface
Preface
One of my favorite quotes is
“The future is already here — it’s just not very evenly distributed. – William Gibson, science fiction author
“The essence of that quote is that new ideas and technology take a while to diffuse through a community and become widely adopted. A good example of the slow diffusion of ideas is the story of how I discovered microservices. It began in 2006, when, after being inspired by a talk given by an AWS evangelist, I started down a path that ultimately led to my creating the original Cloud Foundry. (The only thing in common with today’s Cloud Foundry is the name.) Cloud Foundry was a Platform-as-a-Service (PaaS) for automating the deployment of Java applications on EC2. Like every other enterprise Java application that I’d built, my Cloud Foundry had a monolith architecture consisting of a single Java Web Application Archive (WAR) file.”
“Bundling a diverse and complex set of functions such as provisioning, configuration, monitoring, and management into a monolith created both development and operations challenges. You couldn’t, for example, change the UI without testing and redeploying the entire application. And because the monitoring and management component relied on a Complex Event Processing (CEP) engine which maintained in-memory state we couldn’t run multiple instances of the application! That’s embarrassing to admit, but all I can say is that I am a software developer, and, “let he who is without sin cast the first stone.””
“Clearly, the application had quickly outgrown its monolith architecture, but what was the alternative? The answer had been out in the software community for some time at companies such as eBay and Amazon. Amazon had, for example, started to migrate away from the monolith around 2002 (https://plus.google.com/110981030061712822816/posts/AaygmbzVeRq). The new architecture replaced the monolith with a collection of loosely coupled services. Services are owned by what Amazon calls two-pizza teams—teams small enough to be fed by two pizzas.”
“Amazon had adopted this architecture to accelerate the rate of software development so that the company could innovate faster and compete more effectively. The results are impressive: Amazon reportedly deploys changes into production every 11.6 seconds!”
“In early 2010, after I’d moved on to other projects, the future of software architecture finally caught up with me. That’s when I read the book The Art of Scalability: Scalable Web Architecture, Processes, and Organizations for the Modern Enterprise (Addison-Wesley Professional, 2009) by Michael T. Fisher and Martin L. Abbott. A key idea in that book is the scale cube, which, as described in chapter 2, is a three-dimensional model for scaling an application. The Y-axis scaling defined by the scale cube functionally decomposes an application into services. In hindsight, this was quite obvious, but for me at the time, it was an a-ha moment! I could have solved the challenges I was facing two years earlier by architecting Cloud Foundry as a set of services!”
“In April 2012, I gave my first talk on this architectural approach, called “Decomposing Applications of Deployability and Scalability” (www.slideshare.net/chris.e.richardson/decomposing-applications-for-scalability-and-deployability-april-2012). At the time, there wasn’t a generally accepted term for this kind of architecture. I sometimes called it modular, polyglot architecture, because the services could be written in different languages.”
“But in another example of how the future is unevenly distributed, the term microservice was used at a software architecture workshop in 2011 to describe this kind of architecture (https://en.wikipedia.org/wiki/Microservices). I first encountered the term when I heard Fred George give a talk at Oredev 2013, and I liked it!”
“In January 2014, I created the https://microservices.io website to document architecture and design patterns that I had encountered. Then in March 2014, James Lewis and Martin Fowler published a blog post about microservices (https://martinfowler.com/articles/microservices.html). By popularizing the term microservices, the blog post caused the software community to consolidate around the concept.”
“The idea of small, loosely coupled teams, rapidly and reliably developing and delivering microservices is slowly diffusing through the software community. But it’s likely that this vision of the future is quite different from your daily reality. Today, business-critical enterprise applications are typically large monoliths developed by large teams. Software releases occur infrequently and are often painful for everyone involved. IT often struggles to keep up with the needs of the business. You’re wondering how on earth you can adopt the microservice architecture.”
“The goal of this book is to answer that question. It will give you a good understanding of the microservice architecture, its benefits and drawbacks, and when to use it. The book describes how to solve the numerous design challenges you’ll face, including how to manage distributed data. It also covers how to refactor a monolithic application to a microservice architecture. But this book is not a microservices manifesto. Instead, it’s organized around a collection of patterns. A pattern is a reusable solution to a problem that occurs in a particular context. The beauty of a pattern is that besides describing the benefits of the solution, it also describes the drawbacks and the issues you must address in order to successfully implement a solution. In my experience, this kind of objectivity when thinking about solutions leads to much better decision making. I hope you’ll enjoy reading this book and that it teaches you how to successfully develop microservices.”
Why this book is relevant to you
”…be familiar with the basics of enterprise application architecture and software design. In particular, you need to know the following:“
- How to develop business logic using object-oriented design
“The code examples in this book are written using Java and the Spring framework. That means in order to get the most out of the examples, you need to be familiar with the Spring framework too.
What you’ll learn in this book
“By the time you finish reading this book you’ll understand the following:”
You’ll also be able to do the following:
- Architect an application using the microservice architecture pattern
- Develop the business logic for a microservice
- Refactor an existing monolithic application to services”