Message Naming Guidelines

Message Naming Guidelines

As with many things in software development, naming can be difficult. The name of a message can be incredibly important which is why naming of your messages should be taken with consideration. This post is to be used for message naming guidelines with dos and don’ts based on my prior experiences of the good, the bad, and the ugly.

YouTube

If you haven’t already, check out my YouTube channel where I’m covering this blog post in video form.



Commands vs Events

Commands and Events are the types of messages I generally deal with within a system. We need to differentiate between commands and events because they will be named differently depending on which one they are.

Commands

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 a way to execute behavior.

I try to avoid using Create, Update, Delete, Save prefix as the verb. Rather I try to focus on the business process and the intent of the user to initiate the state transition. This can be one of the verbs mentioned above, but try and dig deeper to reveal the actual intent.

My general guideline for naming is a verb and a noun. Basically the action against a thing.

Do

PlaceOrder
GenerateInvoice
ApplyDiscount

Don’t

Order
SaveInvoice
Discount

Events

Events are statements of fact. They are named in the past tense. They are named this way because they have already occurred. Events are things that have happened within a system. They are the result (not in method return sense) of an executed command.

I try to avoid Created, Updated, Deleted suffix as the verb. Trying to stay way from CRUD naming to get to the essence of what actually occurred from a business process view.

My general guideline for naming an event is a noun and a verb. As mentioned the verbs are past tense.

Do

OrderPlaced
OrderInvoiced
DiscountApplied

Don’t

Ordered
InvoiceCreated
Discounted

Suffix

I generally prefer using a suffix of Command or Event to your types/classes. Ultimately, my only guideline is to be consistent in doing so. If you choose to suffix, always do it, if not, don’t ever do it. Consistency is key.

Examples

PlaceOrder vs PlaceOrderCommand

OrderPlaced vs OrderPlacedEvent

Serialization

If you are persisting events to an event store, document store, or relational database, you’re likely serializing your event objects.

Consumers of those events will then pull those serialized event objects out of the store and try and deserialize them back to an event object you want it to be in the original type.

For example, in .NET you might be serializing using JSON.NET;

The issue now is how do you deserialize this string back to an OrderPlaced type?

Don’t

The first reaction may be to include the CLR Type name alongside the JSON. You can accomplish this by using the TypeNameHandling setting the serializing:

This would result in a $type property that points to the CLR type. When deserializing this string, you can now get it back as the original type.

I discourage using the explicit CLR type information alongside the event because you are very likely going to either rename, change the namespace, or assembly of an event. And at this point, you won’t be able to deserialize using this information.

Do

Include and persist a separate piece of static data alongside your serialized event to define what the name of the event is. This should be concrete and manually mapped from this string to a specific type you want to deserialize to. This allows you to move the specific event type to any assembly, namespace or even rename.

You can see an example of this in my SQLStreamStore demo/sample application.

Message Naming Guidelines

If you have any additional message naming guidelines that I have omitted, please let me know on Twitter or in the comments.

Related Links

Enjoy this post? Subscribe!

Subscribe to our weekly Newsletter and stay tuned.

Message Properties

Message Properties

Over the years I’ve learned various aspects of messaging either through using various products, reading other blogs, or unfortunately in a lot of cases, discovering them myself. One of those aspects is is message properties.

Specifically, (meta) data that you might want to include in your messages to solve some common problems.

My plan is to dive deeper with implementation examples for each topic listed in this post. Hopefully, this post can serve as a reference point to your adventures in messaging or possibly gain some insight that provides a solution for a pain point you may (already) be experiencing.

I was inspired to write this post after seeing this tweet:

Type/Name

The naming of messages is incredibly important for a variety of reasons. When talking about events, it’s important to name them in the past tense because it conveys that they are statements of fact.

Most often the name of an event is used to determine how to deserialize into a specific type. Where I’ve personally run into problems, in .NET specifically, is using the CLR type name as the event name to determine how to deserialize. The issue with this is you’re very likely to change the name of your CLR type.

Prefer to having a static name for an event and not using the CLR type name at runtime to create the event name.

More info on naming can be found in my post Message Naming Guidelines

Message Version

Most often when needing to version a message is to simply create a new type/name. With events, I think this approach works fairly well when you discover a better way to describe the event and along with it the data to expose.

When a new event isn’t required, but rather a slight change in data is to specify the version in the message. Consuming clients can use the message name along with the version to determine how to process the body of the message.

Message ID

A unique identifier of a message. This can be used for idempotency and concurrency. Message Handlerscan keep track of which messages IDs they have processed and determine if they should act upon receiving a message.

This is important because message handlers should be reentrant and messages can be delivered more than once.

Correlation ID

A unique identifier that allows you to reference the flow of events (event chain) or a transaction. Also, often called a Trace ID. Assigning a correlation ID as soon as possible and any message handler that receives a message with a correlation ID then uses that same ID for any messages it outputs.

This is very useful for logging and error handling in asynchronous and distributed environments.

Contract Owner

Who owns the message contract can be important. Depending on how messages are distributed, there may be many messages from various owners. Knowing who owns a message contract is helpful for troubleshooting as well as how to handle that message.

An OrderPlaced event seems like it could be unique across all services, however, in a distribution domain, is that a Sales OrderPlaced from the Sales service or a Purch OrderPlaced from the purchasing service?

Having the owner of the message provides the ability to distinguish how to handle the message when the name alone doesn’t provide enough distinction.

UTC Timestamp

This seems obvious but it gives more context to when the message was created. A useful is keeping track of latency between a message being created to how long it’s taking a given service to process it.

Sender

Who originated the message. Not the service, but rather the user. This could be an access token that is then used to determine if the sender has the correct permissions or is authorized to perform the given request.

Resource/Entity Version

The version of the resource/entity that you are performing an action on. Similar to the message ID this can be used for concurrency. A wonderful example of this is Azure Cosmos DB which uses an ETag as the resource version which is then used with an If-None-Match header for optimistic concurrency. If you’re using Cosmos DB check out my post on Optimistic Concurrency in Azure Cosmos DB

Message Properties

I’ll be going in-depth in each of the above topics with code examples for the actual implementation of how you would use these message properties. Stay tuned.

If you’d like to add to the list, let me know in the comments or on Twitter.

Related

Enjoy this post? Subscribe!

Subscribe to our weekly Newsletter and stay tuned.

Avoiding the Repository Pattern with an ORM

For many years now I’ve advocated not using the repository pattern on top of an ORM such as Entity Framework. There are many reasons why that I’ll try and cover throughout this post based on ways that I’ve seen it implemented. Meaning, this post is talking about poorly implemented approaches or pitfalls that I’ve seen.

To clarify, since this topic seems to really fire people up, I’m not saying that you shouldn’t use the repository pattern. I’m going to clarify why I don’t think under certain situations it’s very useful and other situations that I do find it useful.

This post was spurred on by a blog post and tweet:

IQueryable

The first thing I’ve seen with a repository is exposing IQueryable<T> (or DbSet<T>) from the underlying DbContext in your repository. This serves no purpose. It’s not abstracting anything at all.

What’s even worst is the consumers/callers don’t necessarily know at what point will they actually be retrieving data (doing I/O), unless you’re aware that the underlying IQueryable is coming from Entity Framework., Now when you call a method that materializes your query and actually hits the database (such as ToListAsync()).

Lazy Loading

Second, to this point is now if you have any type of navigation properties and are accessing IQueryable<T> from repository consumers, you must either eager load (via Include()) or have your consumers do the Include() or not realize all navigation properties are lazy loading.

Again, consumers are now aware of the underlying implementation that is Entity Framework.

IEnumerable

To overcome these issues, usually what comes next is avoiding the IQueryable<T> by returning an IEnumerable<T>.

The issue now is since you’re taking away control from the consumer, you must decide what data to Include() and Select() behind query methods.

What this often turns into is a pile of methods with various filtering parameters that could have been much easier expressed via a LINQ expression against the DbSet directly.

Query Objects

So if I don’t generally use the repository pattern, what do I use? Query Objects.

For querying, I’d rather have specialized objects that can return very specific data for the given use case. When implementing in vertical feature slices, as opposed to layers, each query is responsible for how it retrieves data.

The simplest solution is to use the DbContext and query directly.

The primary benefit is query objects only have dependencies that they actually require. Because each query object defines its own dependencies, you can change those dependencies without affecting other query objects.

A simple example of this is if you wanted to migrate from Entity Framework 6 to Entity Framework Core. You could migrate one query object at a time to EF Core instead of having to change over an entire repository that is highly coupled.

Testing

I can see the argument for using a repository because testing was difficult with EF6. However, with EF Core using the SQLite or the InMemory Provider, testing is incredibly easy.

I’ve written a post on how to use the SQLite provider with an in-memory database.

Testing a Query Object becomes incredibly easy without the need to mock.

Caching

Another argument for using the repository pattern is being able to swap out the implementation for a “cached repository”. I do use this pattern but in very select cases. Most times this is across bounded context were cached or stale data is acceptable.

If you decide to swap out the implementation of your repository, which was previously always hitting the database (point of truth) and now is using a cache implementation, how does that affect the callers? How quickly is the data invalidated?

Data can be stale the moment you retrieve it from the database, however adding caching to your repository without your callers knowing it can have a big impact on behavior.

Aggregate Root

One place I do often use a repository is when accessing an aggregate (in DDD Terms). My repositories often only contain two methods, Get(id) and Save(aggregateRoot).

The reason I do use a repository in this situation is that my repository usually returns an object that encapsulates my EF data model. I want it to fetch the entire object model and construct the aggregate root. The aggregate root does not expose data but only behavior (methods) to change state.

Repository Pattern Related

Enjoy this post? Subscribe!

Subscribe to our weekly Newsletter and stay tuned.