top of page

Group

Public·73 members

Microservices Architecture: A Comprehensive Guide with Martin Fowler


What are microservices and why are they important?




Microservices are a popular architectural style for building modern applications that are scalable, resilient, and adaptable to changing business needs. Microservices are small, autonomous, and loosely coupled services that collaborate to provide a complex functionality. Microservices enable developers to use different technologies, languages, frameworks, and data stores for each service, and to deploy them independently and frequently.




micro services martin fowler pdf 17


Download Zip: https://www.google.com/url?q=https%3A%2F%2Furlcod.com%2F2ucmGw&sa=D&sntz=1&usg=AOvVaw12iylY_6f211py78YL366E



Microservices are not a new concept, but they have gained more attention in recent years due to the rise of cloud computing, DevOps, containers, and distributed systems. Microservices are also aligned with the agile and lean principles of software development, which emphasize delivering value to customers quickly and continuously.


However, microservices are not a silver bullet for every problem. Microservices introduce complexity and challenges in areas such as communication, coordination, testing, monitoring, security, and data consistency. Microservices also require a cultural shift in how teams are organized and how they collaborate.


In this article, we will explore what microservices are, what are their characteristics, benefits, and challenges, and how to design a microservice domain model using domain-driven design principles.


The definition and characteristics of microservices




There is no universally agreed-upon definition of microservices, but one of the most cited ones is from Martin Fowler and James Lewis, who wrote an article in 2014 titled Microservices. They defined microservices as:



In short, the microservice architectural style is an approach to developing a single application as a suite of small services, each running in its own process and communicating with lightweight mechanisms, often an HTTP resource API. These services are built around business capabilities and independently deployable by fully automated deployment machinery. There is a bare minimum of centralized management of these services, which may be written in different programming languages and use different data storage technologies.


Based on this definition, we can identify some common characteristics of microservice architectures:


Componentization via services




Microservices are components that can be composed to form a larger system. A component is a unit of software that can be independently replaced or upgraded. Components communicate with each other via well-defined interfaces or contracts. In a microservice architecture, components are implemented as services that run in their own processes and communicate via network protocols such as HTTP or messaging systems such as RabbitMQ or Kafka.


Organized around business capabilities




Microservices are designed to align with the business domains and processes that they support. Each microservice encapsulates a specific business capability or function that can be understood by both developers and business stakeholders. For example, an online store application may have microservices for product catalog, shopping cart, order processing, payment, inventory management, etc.


Products not projects




Microservices are treated as products rather than projects. A product is something that has a long-term vision and value for the customers and the organization. A project is something that has a fixed scope, budget, and timeline. In a microservice architecture, each microservice is owned by a cross-functional team that is responsible for the entire lifecycle of the service, from design to development to deployment to operation to evolution. The team is empowered to make decisions and deliver value to the customers continuously.


Smart endpoints and dumb pipes




Microservices communicate with each other using simple and lightweight mechanisms, such as RESTful APIs or message brokers. The communication logic is encapsulated in the services themselves, rather than in complex middleware or enterprise service buses. This way, the services are decoupled from each other and can evolve independently. The communication channels are dumb pipes that only transfer data without any business logic or transformation.


Decentralized governance




Microservices promote a decentralized approach to governance, where each team can choose the best technology, language, framework, and data store for their service, based on their needs and preferences. There is no need for a central authority or standardization across the services. However, this does not mean that there is no governance at all. There are still some common principles and guidelines that the teams need to follow, such as ensuring interoperability, security, quality, and consistency of the services.


Decentralized data management




Microservices follow a decentralized data management strategy, where each service owns its own data and exposes it through its API. There is no shared database or data model across the services. This way, the services can have different data schemas and storage technologies that suit their needs. However, this also introduces challenges in ensuring data consistency, integrity, and availability across the services.


Infrastructure automation




Microservices rely on infrastructure automation to enable fast and reliable delivery of the services. Infrastructure automation involves using tools and practices such as continuous integration, continuous delivery, configuration management, containerization, orchestration, monitoring, logging, etc. These help to automate the processes of building, testing, deploying, scaling, and managing the services.


Design for failure




Microservices acknowledge that failures are inevitable in a distributed system and design for them accordingly. Microservices use techniques such as timeouts, retries, circuit breakers, bulkheads, fallbacks, etc. to handle failures gracefully and prevent cascading failures across the system. Microservices also use health checks and alerts to detect failures quickly and recover from them.


Evolutionary design




Microservices embrace change and evolution as part of their nature. Microservices are designed to be easy to change and deploy without affecting other services or the system as a whole. Microservices also use techniques such as feature toggles, canary releases, blue-green deployments, etc. to experiment with new features and functionalities without disrupting the users.


The benefits and challenges of microservices




Microservices provide several benefits for building modern applications, but they also come with some challenges that need to be addressed. Here are some of the main benefits and challenges of microservices:


Strong module boundaries




Microservices reinforce modular structure, which is particularly important for larger teams. Modularity helps to improve cohesion, reduce coupling, increase maintainability, and enable parallel development. Microservices also enforce clear boundaries between the services by using explicit contracts or interfaces that define what each service does and how it communicates with other services.


Independent deployment




Simple services are easier to deploy, and since they are autonomous, are less likely to cause system failures when they go wrong. Microservices also enable continuous delivery and deployment of the services without requiring coordination or synchronization with other teams or services. This helps to speed up the feedback loop and deliver value to the customers faster.


Technology diversity




With microservices you can mix multiple languages, development frameworks and data-storage technologies. This gives you the freedom to choose the best tools for each service and experiment with new technologies without affecting other parts of the system. This also helps to attract and retain talent who want to work with diverse and cutting-edge technologies.


Business alignment




Microservices align with the business domains and capabilities that they support. This helps to improve the communication and collaboration between developers and business stakeholders, and ensure that the software reflects the business needs and goals. This also helps to foster a culture of ownership and accountability among the teams who are responsible for delivering value to the customers.


Complexity




Complexity




Microservices introduce complexity in many areas such as design, development, deployment, and monitoring. With more moving parts, it becomes more challenging to manage and maintain the system. For example, microservices require more coordination and integration among the services, more network calls and latency issues, more configuration and deployment options, more testing and debugging scenarios, more logging and tracing data, etc.


Distributed systems issues




Microservices are inherently distributed systems, which means they have to deal with issues such as network failures, partial failures, inconsistent data, concurrency, scalability, security, etc. These issues are not trivial and require a good understanding of distributed systems concepts and best practices. For example, microservices need to implement patterns such as retries, circuit breakers, timeouts, load balancing, service discovery, etc. to handle network failures and latency.


Testing and monitoring




Testing and monitoring microservices are more difficult than testing and monitoring monolithic applications. Testing microservices requires different types and levels of testing, such as unit testing, integration testing, contract testing, end-to-end testing, etc. Testing microservices also requires mocking or stubbing dependent services or using service virtualization tools. Monitoring microservices requires collecting and aggregating metrics and logs from multiple sources and using tools such as distributed tracing to track the flow of requests across the services.


How to design a microservice domain model




One of the key challenges of designing microservices is how to decompose a complex system into smaller and cohesive services that can be developed and deployed independently. A common approach to tackle this challenge is to use domain-driven design (DDD) principles.


DDD is a software development methodology that focuses on modeling the business domain and its rules using a ubiquitous language that is shared by both developers and business stakeholders. DDD helps to create a rich domain model that captures the essence and complexity of the business problem.


DDD consists of several concepts and techniques that can help to design a microservice domain model. Some of the most important ones are:


Rich domain model versus anemic domain model




In his post AnemicDomainModel, Martin Fowler describes an anemic domain model this way:



The basic symptom of an Anemic Domain Model is that at first blush it looks like the real thing. There are objects, many named after the nouns in the domain space, and these objects are connected with the rich relationships and structure that true domain models have. The catch comes when you look at the behavior, and you realize that there is hardly any behavior on these objects, making them little more than bags of getters and setters.


An anemic domain model is a common anti-pattern in many applications that use a layered architecture with a separate data layer that handles data persistence. In this case, the domain objects are reduced to simple data structures that are passed between layers without any business logic or behavior.


A rich domain model, on the other hand, is a model that encapsulates both data and behavior in domain objects that reflect the business concepts and rules. A rich domain model expresses the meaning and intent of the domain using a ubiquitous language that is understood by both developers and business stakeholders.


A rich domain model is preferable for designing microservices because it helps to achieve high cohesion and low coupling among the services. Each service should have a rich domain model that implements its own business logic and rules without depending on other services.


Domain-driven design principles




DDD provides some principles that can guide the design of a microservice domain model. Some of these principles are:



  • Focus on the core domain. The core domain is the part of the system that provides the most value to the business and differentiates it from competitors. The core domain should be prioritized over other parts of the system that are less critical or can be delegated to third-party services.



  • Model based on bounded contexts. A bounded context is a natural division within a business domain that provides an explicit boundary within which a domain model exists. A bounded context defines the scope and meaning of the domain model, and isolates it from other models. A bounded context can be mapped to a microservice that implements the domain model within that context.



  • Use context mapping to identify relationships between bounded contexts. Context mapping is a technique to visualize and document the relationships and interactions between bounded contexts. Context mapping helps to identify the dependencies, constraints, and contracts between the services that correspond to the bounded contexts. Context mapping also helps to define the communication patterns and protocols between the services.



  • Use subdomains to decompose a large bounded context. A subdomain is a smaller part of a bounded context that can be further decomposed into smaller services. A subdomain can be classified into three types: core, supporting, and generic. A core subdomain is essential to the business and should be developed in-house. A supporting subdomain is important but not critical to the business and can be outsourced or bought off-the-shelf. A generic subdomain is common and does not provide any competitive advantage and can be reused or replaced by standard solutions.



Bounded contexts and context mapping




A bounded context is a natural division within a business domain that provides an explicit boundary within which a domain model exists. A bounded context defines the scope and meaning of the domain model, and isolates it from other models. A bounded context can be mapped to a microservice that implements the domain model within that context.


For example, consider an online store application that has several business domains such as product catalog, shopping cart, order processing, payment, inventory management, etc. Each of these domains can be modeled as a bounded context with its own domain model, language, and data store. Each of these bounded contexts can also be implemented as a microservice that exposes its functionality through an API.


Context mapping is a technique to visualize and document the relationships and interactions between bounded contexts. Context mapping helps to identify the dependencies, constraints, and contracts between the services that correspond to the bounded contexts. Context mapping also helps to define the communication patterns and protocols between the services.


For example, consider the following context map for the online store application:



The context map shows the different bounded contexts (microservices) and their relationships. The arrows indicate the direction of communication or dependency between the services. The labels on the arrows indicate the type of relationship, such as:



  • Customer/Supplier: One service (supplier) provides functionality or data that another service (customer) needs.



  • Conformist: One service (conformist) must conform to the model or contract of another service (downstream) without any negotiation or influence.



  • Anticorruption Layer: One service (upstream) provides an adapter or translation layer to protect another service (downstream) from its model or contract.



  • Shared Kernel: Two services share a common subset of their models or contracts.



  • Open Host Service: One service provides a well-defined and stable API that can be consumed by multiple services.



  • Published Language: Two services communicate using a standard or common language or protocol.



Aggregates and entities




An aggregate is a cluster of domain objects that can be treated as a single unit. An aggregate has one root entity, which is the only point of direct access to other entities within the aggregate. An aggregate defines consistency and transactional boundaries for its entities.


An entity is an object that has a unique identity and a lifecycle. An entity can have properties, behaviors, and relationships with other entities. An entity can also have invariants, which are rules or constraints that must always be true for the entity.


For example, consider an order processing domain that has an Order aggregate with OrderItem entities. The Order aggregate has an OrderId as its identity and defines rules such as:



  • An order must have at least one order item.



  • An order item must have a positive quantity and price.



  • An order cannot be modified once it is shipped.



The Order aggregate ensures that these rules are enforced whenever an order or an order item is created, updated, or deleted.


Value objects and domain events




A value object is an object that has no identity and is immutable. A value object is defined by its attributes or properties, rather than by its identity. A value object can also have behaviors or methods that operate on its attributes. Two value objects are equal if they have the same attributes.


Value objects and domain events




A value object is an object that has no identity and is immutable. A value object is defined by its attributes or properties, rather than by its identity. A value object can also have behaviors or methods that operate on its attributes. Two value objects are equal if they have the same attributes.


A domain event is an object that represents something that happened in the domain that is of interest to the business or the users. A domain event captures the relevant data or context of the event and usually has a timestamp. A domain event can trigger actions or reactions in other parts of the system.


For example, consider a payment domain that has a Money value object and a PaymentCompleted domain event. The Money value object has attributes such as amount and currency, and methods such as add, subtract, multiply, etc. The Money value object does not have an identity and is immutable. Two Money objects are equal if they have the same amount and currency.


The PaymentCompleted domain event is raised when a payment is successfully processed. The PaymentCompleted domain event has data such as paymentId, orderId, amount, currency, timestamp, etc. The PaymentCompleted domain event can trigger actions such as sending a confirmation email to the customer, updating the order status, etc.


Conclusion




In this article, we have learned what microservices are, what are their characteristics, benefits, and challen


About

Welcome to the group! You can connect with other members, ge...

Members

bottom of page