microservices_patterns_by_chris_richardson

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

Detailed Table of Contents

  • Copyright
  • Brief Table of Contents
  • Preface
  • Acknowledgments
  • About this book
  • About the cover illustration

Chapter 1. Escaping monolithic hell

Chapter 2. Decomposition strategies

  • 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.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.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.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.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.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:“

“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

microservices_patterns_by_chris_richardson.txt · Last modified: 2024/04/28 03:20 by 127.0.0.1