Begin with Microservices
Traditionally, software development has often relied on
monolithic architectures, where all functionalities are built as part of a
single, large service. This approach can lead to significant issues, as making
a change in one aspect of the system can impact the entire product.
Microservices architecture addresses this problem by creating boundaries around
different aspects of the product, known as contexts. Each context is
implemented as an independent service, referred to as a bounded context.
Bounded Context
A bounded context is a specific area of the application with
a clear boundary and interface. Each microservice has a specific role centered
around this context. Bounded contexts can have sub-contexts, which may be
related to data/models or functions. There are two primary approaches to
defining bounded contexts:
Ubiquitous Language:
This approach is suitable for smaller projects and teams.
The bounded context is defined based on the language or context used within the
team. During the definition process, if overlapping sub-contexts are
identified, they are either renamed to match the bounded context or extracted
to form a new bounded context. If cross-references between bounded contexts
remain, these points become integration points.
Event Storming:
Event storming is a planning, estimation, and design session
where the team goes over the details of all the events that form the product.
This includes the sequence of events, associated commands (which trigger
events), and any issues related to the events. By aggregating all the notes
around these events, the team can define the bounded context and the
corresponding services.
Aggregation of Microservices
In some cases, the contexts of two services are so closely
related that creating a single service is more efficient. In such scenarios, an
aggregate service is created to encompass both contexts.
Understanding Architecture
In a microservices architecture, asynchronous communication
is essential to ensure scalability, responsiveness, and efficient resource
utilization. Here’s a detailed look at why asynchronous connections are needed
and how to implement them effectively.
Why We Need Asynchronous Connections
With microservices architecture, numerous components are
connected over the network. To complete a particular action, multiple
microservices may need to interact. Keeping synchronous calls between services
can lead to a poor user experience and cause more network resources to be
blocked while waiting for responses. Asynchronous connections decouple clients
and services, eliminating direct dependencies and improving overall system
performance.
Asynchronous Architecture
Work Queue Pattern
In the Work Queue pattern, multiple workers are available to
finish a given task. Once a task is provided, any available worker executes it.
Each piece of work is independent and can be processed by separate workers.
This pattern allows scaling up workers to handle the load without impacting the
outcome. The caller/publisher gives the message to an individual broker, where
multiple workers are waiting to act upon it.
Publish and Subscribe Pattern
The Publish and Subscribe pattern differs from the Work
Queue pattern. Here, the publisher publishes an event, and subscribers
subscribe to it based on their responsibilities. This pattern is more
event-driven rather than command-driven. Multiple tasks by multiple workers are
performed when one event is raised.
Asynchronous API Calls
Messaging is not the only way to achieve asynchronous
communication. Asynchronous communication can also be implemented using HTTP
APIs. In this pattern, the front end talks to the BFF and receives an immediate
response. The BFF then communicates with downstream services and provides a
callback. Once the downstream service completes its work, it uses the callback
to notify the BFF, which in turn notifies the UI that the response is
available.
No comments:
Post a Comment