Organized around business capabilities - Running Containerized Microservices on AWS

Organized around business capabilities

Defining exactly what constitutes a microservice is very important for development teams to agree on. What are its boundaries? Is an application a microservice? Is a shared library a microservice?

Before microservices, system architecture would be organized around technological capabilities such as user interface, database, and server-side logic. In a microservices-based approach, as a best practice, each development team owns the lifecycle of its service all the way to the customer. For example, a recommendations team might own development, deployment, production support, and collection of customer feedback.

In a microservices-driven organization, small teams act autonomously to build, deploy, and manage code in production. This allows teams to work at their own pace to deliver features. Responsibility and accountability foster a culture of ownership, allowing teams to better align to the goals of their organization and be more productive.

Microservices are as much an organizational attitude as a technological approach. This principle is known as Conway's Law:

"Organizations which design systems ... are constrained to produce designs which are copies of the communication structures of these organizations." — M. Conway

When architecture and capabilities are organized around atomic business functions, dependencies between components are loosely coupled. As long as there is a communication contract between services and teams, each team can run at its own speed. With this approach, the stack can be polyglot, meaning that developers are free to use the programming languages and frameworks that are optimal for their component. For example, the user interface can be written in JavaScript or HTML5, the backend in Java, and data processing can be done in Python.

This means that business functions can drive development decisions. Organizing around capabilities means that each API team owns the function, data, and performance completely.

The following are key factors from the twelve-factor app pattern methodology that play a role in organizing around capabilities:

  • Codebase (one codebase tracked in revision control, many deploys) –Each microservice owns its own codebase in a separate repository and throughout the lifecycle of the code change.

  • Build, release, run (strictly separate build and run stages) – Each microservice has its own deployment pipeline and deployment frequency. This allows the development teams to run microservices at varying speeds so they can be responsive to customer needs.

  • Processes (execute the app as one or more stateless processes) – Each microservice does one thing and does that one thing really well. The microservice is designed to solve the problem at hand in the best possible manner.

  • Admin processes (run admin/management tasks as one-off processes) – Each microservice has its own administrative or management tasks so that it functions as designed.

To achieve a microservices architecture that is organized around business capabilities, use popular microservices design patterns. A design pattern is a general, reusable solution to a commonly occurring problem within a giving context.

Popular microservice design patterns include:

  • Aggregator Pattern – A basic service which invokes other services to gather the required information or achieve the required functionality. This is beneficial when you need an output by combining data from multiple microservices.

  • Branch Design Pattern – This design pattern, an extended version of the Aggregator Pattern, enables you to configure service calls dynamically, and guides the service communication with more than one service at a time.

  • API Gateway Design Pattern – API Gateway also acts as the entry point for all the microservices and creates fine-grained APIs for different types of clients. It can fan out the same request to multiple microservices and similarly aggregate the results from multiple microservices.

  • Chained or Chain of Responsibility Pattern – Chained or Chain of Responsibility Design Patterns produces a single output which is a combination of multiple chained outputs.

  • Asynchronous Messaging Design Pattern – In this type of microservices design pattern, all the services can communicate with each other, but they do not have to communicate with each other sequentially and they usually communicate asynchronously.

  • Database or Shared Data Pattern – This design pattern will enable you to use a database per service and a shared database per service to solve various problems. These problems can include duplication of data and inconsistency, different services have different kinds of storage requirements, few business transactions can query the data, and with multiple services and de-normalization of data.

  • Event Sourcing Design Pattern – This design pattern helps you to create events according to change of your application state.

  • Command Query Responsibility Segregator (CQRS) Design Pattern – This design pattern enables you to divide the command and query. Using the common CQRS pattern, where the command part will handle all the requests related to CREATE, UPDATE, DELETE while the query part will take care of the materialized views.

  • Circuit Breaker Pattern – This design pattern enables you to stop the process of the request and response when the service is not working. For example, when you need to redirect the request to a different service after certain number of failed request intents.

  • Decomposition Design Pattern – This design pattern enables you to decompose an application based on business capability or on based on the sub-domains.