Messaging Commands & Events Explained!

In service oriented architecture (including microservices) that leverage messaging, you’re going to run into both types of messages: Commands & Events. What’s the difference between Commands & Events? When should you use a command and when should use an event?

YouTube

Check out my YouTube channel where I post all kinds of content that accompanies my posts including this video showing everything that is in this post.

What’s a Command?

Commands are messages with the intent to change the state of the system.

They are actions to be performed that have side effects.

They may be created by an end-user or another part of the system that could be automated.

They are away to execute behavior.

What’s an Event

Events are statements of fact.

They are named in the past tense because they represent something that has already occured.

Events are things that have happened within a system.

They are the result (not in the method/return sense) of an executed command.

They are notifications.

They are used to tell other parts of the system that something has occurred.

Consumers

One important distinction between Commands & Events are consumers.

A command will have exactly one consumer. There will only be one consumer that will handle an instance of a command. When your producer sends a command to a message broker, it will send that command to only one consumer.

Commands & Events Explained!

An event will have zero to many consumers. When a producer publishes an event to a message broker, it will deliver it to as many consumers that want it. Each consumer will receive a copy of the event. There may not be any consumers that want to receive an event. The publisher does not know who the consumers are, or how many of them exist for an event.

Commands & Events Explained!

When to use a Command?

When you want to tell the system to perform some type of behavior. For example, sending a PlaceOrder command. You’re telling the system to perform an action that could have a side effect.

Name your commands like actions or tasks. They should be contain a verb.

When to use an Event?

When something has occurred as the result of a command and you want to tell other parts of the system. For example, OrderPlaced event can let other parts of the system know that an order has been placed. This likely would have resulted from a PlaceOrder command.

Because events are things that have occurred, they will be named in the past tense.

Commands & Events: Orchestration

You can leverage both commands and events together to orchestrate a business process or workflow. An orchestrator will send commands and consume the resulting events to kick off the next command.

Check out my blog post and video on Event Choreography & Orchestration (Sagas) for more details.

Follow @CodeOpinion on Twitter

Enjoy this post? Subscribe!

Subscribe to our weekly Newsletter and stay tuned.

Start with a Monolith, NOT Microservices

Start with a Monolith! Why? Finding boundaries is a difficult thing to do and even harder to get right. Having to define those boundaries up-front for a microservices architecture is a recipe for additional and unneeded complexity. If you develop a loosely Coupled Monolith by applying the same principles when developing Microservices, you’ll be in a better place to refactor and change your boundaries as you gain insights.

YouTube

Check out my YouTube channel where I post all kinds of content that accompanies my posts including this video showing everything that is in this post.

Unknown Domain

When starting a greenfield project with likely a small team, the business will understand the domain, however, the developers will likely not.

Understanding the domain and the problem space takes time. It takes time to understand the domain, the capabilities of the system your building, and most importantly, defining boundaries for those capabilities.

My analogy for this process is walking into a pitch-black room with only a small flashlight. You have to shine the flashlight around the room to get some insights to the room. How big is the room, how high are the ceilings, are there any objects in the room, etc.

You don’t immediately know all this, it takes shining the light around to discover all these things.

If you do not know the domain your building a system for, it means you would know not know what the boundaries are. If you do not know what the boundaries are, you should not start with a microservices architecture.

Boundaries

Defining boundaries is one of the most important things to get right, yet the hardest thing to do. It takes iterations. As you gain more insights by shining the flashlight. As you discover more your models and boundaries will change.

Because of this iteration, it is much more feasible to make these refactoring and rewrites using a monolithic architecture.

That does not mean a big ball of mud. A monolith does not need to be a big ball of mud.

Loosely Coupled

Define boundaries within your monolith. Understand how they need to interact and make this interactions loosely coupled.

Essentially, use the same principles you would in a microservices or service oriented architecture and apply them to a monolith.

Microservices and Service Oriented Architecture is about creating units that own a set of behaviors and backing data. This should be driven by business capabilities, not technical concerns.

Each bounded context is a boundary. For more info on finding them, check out my Context is King: Finding Service Boundaries series.

The other benefit of (micro)services is separation of schema/data. Each boundary must own it’s own data. In a monolith this could be accomplished by simply separating the schema either into separate physical databases or even in the same database instance.

Each boundary should own it’s own data. No other boundary should be able to read or write to it’s schema. Never. This is a conceptual idea.

Start with a Monolith

As mentioned, you could use a single database instance but have clearly defined boundaries within it.

Start with a Monolith

Communication

If you want to be as loosely coupled as possible between boundaries, then communicating via asynchronous messaging will allow you to ultimately split a monolith into (micro)services.

Each boundary will send command and publish events to a message broker. Other boundaries within the monolith will be consumers of those messages.

Messages will be going outbound from one boundary to a message broker, and back into the monolith to other boundaries.

Start with a Monolith

If you choose for scaling reasons (either performance or developer teams) to carve off boundaries into independent services, that’s possible as you were never coupling beyond messages within the monolith.

Now you can see your monolith was loosely coupled. It was a single codebase to deploy a single unit but possible to separate into multiple codebases to multiple deployable units.

Start with a Monolith

You’re going to get boundaries wrong. And since you will gain more insights into the domain, you will need to refactor and rewrite. Having a single codebase as a single deployable unit of a Monolith at the beginning will be much simpler than having to deal with all the extra complexities of trying to refactor multiple services and their interactions.

Loosely Coupled Monolith

I have a whole series of blog posts and videos around creating a Loosely Coupled Monolith if you’re interested in more details on how to start with a monolith for a greenfield project.

Follow @CodeOpinion on Twitter

Enjoy this post? Subscribe!

Subscribe to our weekly Newsletter and stay tuned.

Splitting up a Monolith into Microservices

Splitting up a Monolith into Microservices is not an easy task. It can be broken apart into multiple steps. Defining boundaries and capabilities are key. Depending on how much coupling you have within your Monolith, and how you couple is a big factor in how challenging this process will be.

YouTube

Check out my YouTube channel where I post all kinds of content that accompanies my posts including this video showing everything that is in this post.

Monolith <> Big Ball of Mud

First, I believe most people have associated the term “Monolith” with a big ball of mud that is unmanageable because of tight coupling. The terms spaghettis code also comes to mind. The reason for this common perspective is likely because almost all codebases with size and age add more and more coupling, which makes things harder to change.

However, this couldn’t be farther from the truth.

A monolith does not need to be hard to change.

A monolith does not need to be tightly coupled.

Coupling

Large amounts of coupling within a system are because of a lack of boundaries. Coupling is the enemy. However, finding the right balance of cohesion & coupling.

Defining boundaries in any system is key. Microservices are single units that contain a certain set of capabilities within the system.

The same boundaries can and should be applied within a monolith.

Boundaries

The first thing that needs to be done is to define the capabilities of the system. Then defining the boundaries (Bounded Context) which are a collection of those capabilities. If you want to find more info on finding service boundaries, check out my series on Context is King: Finding Service Boundaries

Next to understand the coupling between boundaries.

Which Bounded Context reference/couple to other bounded contexts? Which capabilities in one bounded context need to call a function in another bounded context. Either to perform an action or get data.

RPC

If you want to carve off Bounded Context into its own service, you’re going to be stuck with dealing with two forms of coupling.

  • Functions/APIs
  • Database Schema

Function/api calls that were previously done in-process. Since you’re carving off to a new service, you can no longer make these calls in the same fashion. You now need to make Remote Procedure Calls over the network. This could be done via HTTP, gRPC, etc.

I strongly recommend this be an intermediate step, if at all. I do not believe that synchronous RPC are a good solution for a distributed system.

Ultimately we want each boundary to be autonomous and doing its communication via asynchronous messaging.

However, this can be an intermediate step towards moving portions of a system, in steps, to be independent and autonomous.

Database Schema

All interactions between Bounded Context must be done APIs, which are now done via RPC. Each boundary must own it’s own data. There cannot be a shared database. You need to remove this coupling.

Meaning, you cannot have one Bounded Context query the schema of another Bounded Context.

Monolith into Microservices

Asynchronous Messaging

At this point we’ve created a distributed monolith. You’ve moved all communication that was in-process to an RPC call over the network. This comes with a lot of issues and complexity at the gain of independent codebase and deployment.

You do not want to stay in this position. You want services to be autonomous. To do so, you need to remove the tight coupling of RPC and move towards asynchronous messaging.

Monolith into Microservices

Commands and Events will be sent and published to a Message Broker to remove RPC. This is a giant step in gaining autonomy of a service.

If you’re new to messaging, I’ve done a lot of videos about messaging that you can check out on my YouTube channel.

Monolith into Microservices

Once you’ve carved off a Bounded Context, it’s a matter of applying the same concepts to other boundaries and capabilities in your system. Splitting up a monolith into microservices is not easy but can be done.

Monolith into Microservices
  • Define Boundaries
  • Identify coupling
  • (Intermediate) Move to RPC
  • Define Data Ownership
  • Implement Asynchronous Messaging

Loosely Coupled Monolith

I do think creating a Monolith that has well-defined boundaries, communicates via asynchronous messaging is a great place to be as it allows you to carve off boundaries. I have a whole series of blog posts and videos around creating a Loosely Coupled Monolith.

Follow @CodeOpinion on Twitter

Enjoy this post? Subscribe!

Subscribe to our weekly Newsletter and stay tuned.