This article provides an overview of some techniques and patterns for developing applications in service-oriented architecture, together with external resources for more detail explanations. This is not a comprehensive references for all available techniques and patterns, I selected only some patterns that I find useful and have already been applied or will be applied in my projects, I use this article as a quick reminder. For more comprehensive resources, please visit the further readings section.
Application modelling
Domain Driven Design
Summary:
Domain-Driven Design is an approach to software development that centers the development on programming a domain model that has a rich understanding of the processes and rules of a domain. [1]
External resources:
Service decomposition techniques
Decomposition by subdomain
Summary:
Define services corresponding to Domain-Driven Design (DDD) subdomains. DDD refers to the application’s problem space — the business — as the domain. A domain is consists of multiple subdomains. Each subdomain corresponds to a different part of the business. [1]
External resources:
Strangler pattern
Summary:
Modernize an application by incrementally developing a new (strangler) application around the legacy application. [1]
External resources:
Martin fowler’s article on the origin of the name of the pattern: Branch By Abstraction
Summary
Co-exist two implementations of the same functionality in the same running process at the same time. [1]
External resources:
Data management patterns
Database per service
Summary
Keep each microservice’s persistent data private to that service and accessible only via its API. A service’s transactions only involve its database.
External resources:
Change data capturer
Summary
Change data capture (CDC) is a set of software design patterns used to determine and track the data that has changed so that action can be taken using the changed data.CDC is an approach to data integration that is based on the identification, capture and delivery of the changes made to data sources.[1]
External resources:
Saga pattern
Summary
Implement each business transaction that spans multiple services is a saga. A saga is a sequence of local transactions. Each local transaction updates the database and publishes a message or event to trigger the next local transaction in the saga. If a local transaction fails because it violates a business rule then the saga executes a series of compensating transactions that undo the changes that were made by the preceding local transactions. [1]
External resources:
Transactional outbox pattern
Summary
How to reliably/atomically update the database and publish messages/events?
A service that uses a relational database inserts messages/events into an outbox table (e.g. MESSAGE) as part of the local transaction. A separate Message Relay process publishes the events inserted into database to a message broker. [1]
External resources:
Synchronous communication patterns
API Gateway
Summary:
An API gateway is a service which is the entry point into the application from the outside world. It’s responsible for request routing, API composition, and other functions. [1]
External resources:
Retry
Summary
Enable an application to handle transient failures when it tries to connect to a service or network resource, by transparently retrying a failed operation. This can improve the stability of the application.[1]
External resources:
Circuit breaker
Summary
A circuit breaker acts as a proxy for operations that might fail. The proxy monitors the number of recent failures that have occurred, and use this information to decide whether to allow the operation to proceed, or simply return an exception immediately.[1]
External resources:
Back pressure & Throttling
Summary
Back pressure: When one component is struggling to keep-up, the system as a whole needs to respond in a sensible way. It is unacceptable for the component under stress to fail catastrophically or to drop messages in an uncontrolled fashion. Since it can’t cope and it can’t fail it should communicate the fact that it is under stress to upstream components and so get them to reduce the load. [1]
Throttling: The system should monitor how it’s using resources so that, when usage exceeds the threshold, it can throttle requests from one or more users. This will enable the system to continue functioning and meet any service level agreements (SLAs) that are in place. [3]
External resources:
Service mesh
Summary
Service mesh is a dedicated infrastructure layer for facilitating service-to-service communications between microservices, often using a sidecar proxy. [1]
External resources:
Istio, Shopee’s SPEX and Hashicorp’s Consul are some implementation of service mesh. Asynchronous communication patterns
Publish-Subscribe
Summary:
Publish–subscribe is a messaging pattern where senders of messages, called publishers, do not program the messages to be sent directly to specific receivers, called subscribers, but instead categorize published messages into classes without knowledge of which subscribers there may be. Similarly, subscribers express interest in one or more classes and only receive messages that are of interest, without knowledge of which publishers there are.
External resources:
Dead-letter channel
Summary:
What will the messaging system do with a message it cannot deliver? When a messaging system determines that it cannot or should not deliver a message, it may elect to move the message to a Dead Letter Channel. [1]
External resources:
Competing consumers
Enable multiple concurrent consumers to process messages received on the same messaging channel.
External resources:
Idempotent consumers
Implement an idempotent consumer, which is a message consumer that can handle duplicate messages correctly. Some consumers are naturally idempotent. Others must track the messages that they have processed in order to detect and discard duplicates. [1]
External resources:
Event message:
Use an Event Message for reliable, asynchronous event notification between applications.
External resources:
Command message:
Use a Command Message to reliably invoke a procedure in another application.
External resources:
Application Design & Development
Twelve factors applications
Summary: [1]
The twelve-factor app is a methodology for building software-as-a-service apps that:
Use declarative formats for setup automation, to minimize time and cost for new developers joining the project; Have a clean contract with the underlying operating system, offering maximum portability between execution environments; Are suitable for deployment on modern cloud platforms, obviating the need for servers and systems administration; Minimize divergence between development and production, enabling continuous deployment for maximum agility; And can scale up without significant changes to tooling, architecture, or development practices. Twelve factors:
Codebase: One codebase tracked in revision control, many deploys Dependencies: Explicitly declare and isolate dependencies Config: Store config in the environment Backing services: Treat backing services as attached resources Build, release, run: Strictly separate build and run stages Processes: Execute the app as one or more stateless processes Port binding: Export services via port binding Concurrency: Scale out via the process model Disposability: Maximize robustness with fast startup and graceful shutdown Dev/prod parity: Keep development, staging, and production as similar as possible Logs: Treat logs as event streams Admin processes: Run admin/management tasks as one-off processes External Resources:
Cloud-Native Applications
Summary:
Cloud native computing is an software development approach that utilizes cloud computing to build and run scalable applications in modern, dynamic environments such as public, private, and hybrid clouds [3]
Cloud-Native Principles [1]:
If a project is cloud native, it uses immutable infrastructure, declarative apis, and microservices. If infrastructure is immutable, it is easily reproduced, consistent, disposable, will have a repeatable deployment process, and will not have configuration or artifacts that are modifiable in place. If a project has an efficient and repeatable deployment process, its process is versioned, automated, and has low overhead/coarse grained packaging. If a project’s deployment is automated, configuration, environment, and artifacts are completely managed by a pipeline. If a projects deployment is managed completely by a pipeline, the project’s environment is protected. If a project’s environment is protected, it provides observability of the project’s internal components. If a project’s uses declarative APIs, its configuration is declarative. If a project’s configuration is declarative, it designates what to do, not how to do it. If a project exists as a microservice, it is not monolithic, it is resilient, it follows 12-factor principles, and is discoverable. If a microservice is resilient, it is self-healing and distributed. External Resources:
Feature flags
Summary:
Feature flags (also known as or feature switches) are a software development technique that turns certain functionality on and off during runtime, without deploying new code. This allows for better control and more experimentation over the full lifecycle of features. [2] External Resources:
Deployment and Operation
Deployment strategies: Rolling update, red/black, canary.
Summary:
External resources:
External Configuration Store
Summary:
Move configuration information out of the application deployment package to a centralized location. This can provide opportunities for easier management and control of configuration data, and for sharing configuration data across applications and application instances.
External resources:
Let it crash
Summary:
Prefer a full component restart to internal failure handling.
External resources:
Sidecar pattern
Co-locate a cohesive set of tasks with the primary application, but place them inside their own process or container, providing a homogeneous interface for platform services across languages.
External resources:
Observability
USE & RED method:
Summary:
USE method: For every resource, check utilization, saturation, and errors. [1]
Utilization: the average time the resource was busy servicing work Saturation: the degree to which the resource has extra work which it can’t service, often queued Errors: the count of error events RED method: With the RED method, three key metrics are instrumented that monitor every service in your architecture [2]:
(Request) Rate — the number of requests, per second, your services are serving. (Request) Errors — the number of failed requests per second. (Request) Duration — The amount of time each request takes expressed as a time interval. External Resources:
Health Endpoint Monitoring
Summary:
Implement health monitoring by sending requests to an endpoint on the application. The application should perform the necessary checks, and return an indication of its status.
External Resources:
Logging, Metrics Monitoring, Error Tracking, and Distributed Tracing
Summary: [1]
, aka distributed tracing, provides insight into the full lifecycles, aka traces, of requests to the system, allowing you to pinpoint failures and performance issues. provide quantitative information about processes running inside the system, including counters, gauges, and histograms. provides insight into application-specific messages emitted by processes. External Resources:
Further Reading