Messages generally have both the message content (body) that is the data the message exists to carry and metadata (header) that contains information about the message itself. In general these should be of interest to different code: business logic should care about the content and infrastructure should care about the metadata. As such it makes sense to ensure a clean separation of these two types of data.
If you're using a third-party platform this separation is generally handled for you. Your job then is to make sure that you don't violate the separation which is generally pretty easy to do. If you're building the message system yourself though it's all to easy to mix these data types.
I've made this mistake on a system I worked on that used messages heavily. I created a base Message type that all other messages derived from. This type had a number of attributes that defined things like message and aggregate Ids, timestamps and the message originator. As these were attributes of the type directly developers consuming and creating messages would tend to use them rather than creating business specific properties. This was particularly a concern with the message timestamp for reasons I've already discussed.
There were two possible solutions to this problem that I could have adopted:
- Place all the metadata attributes into a type of their own and include this as a Metadata attribute on the base Message type.
- Flip the encapsulation such that the message becomes an attribute of a transport type that also contains the metadata.
Both of these solutions make the distinction clear, ensuring that any developer who uses the metadata in business logic is at least making a conscious decision to do so.