Sponsored By Aspose - File Format APIs for .NET

Aspose are the market leader of .NET APIs for file business formats – natively work with DOCX, XLSX, PPT, PDF, MSG, MPP, images formats and many more!

DDDD 4 [Messages are Value Objects]

This week I may take a break from these posts for a few days due to the Summit and Alt.Net but I should still push a few posts…

 

Messages as we will see are an interesting breed of objects as the same object will sometimes have differing connotations in different sections of code. In the domain messages are to be treated as value objects even though they may be treated differently later by certain types of infrastructure. There a a few aspects of being a value object that are imperative to a successful implementation of a messaging system within the domain. By looking at the general rules for value objects we can derive many of the rules for messages within our domain.

 

  • Messages ARE immutable
  • Messages should vary in equality based upon the data they hold
  • Messages should have fluent builders

 

Messages ARE immutable…

I don’t think that I can stress this point enough. Mutable messages are an anti-pattern. They are the path to a system that is held together with duct tape and bubble gum. There are many reasons why this is the case but the simplest reason is that you suddenly end up with different semantics when you cross a serialization boundary.

Let’s imagine for a moment the ridiculous case of a simple service that receives a message, alters a field in it then sends an ack that it completed its work (the caller keeping a copy of the message checks for the changed field when it receives the ack). Even worse it does something to the message that causes the message to say raise an event back to the caller. These sound like ridiculous cases that no one would ever do but I have seen both done. Either will work just fine so long as you are in the same process but will break once you introduce a serialization boundary.

 

Let’s make an additional rule to get help this issue (please,never need this rule): You should never hold a reference to a message after you send it. As far as you are concerned, once you dispatch it, its gone. We will learn later that if at all possible we also want to limit our exposure to any shared state between the message sender and receiver as it is this shared state that limits scalability.

 

Another reason that mutable messages are evil is that you never actually know that the message is in a valid state. The use of immutable messages introduces a stronger contract for your messaging as you know that if a message exists that it is also in a valid state. You will never have a SendEmailMessage that is missing a To and From unless you specify that that is a valid way of sending an email in your system. Because you know that your messages are in a valid state you can in the case of using a shared library for messaging fail early on your requests i.e. instead of whatever processes the SendEmailMessage saying “Hey guy you need to actually send me someone who this email is to!”, the thing sending the message fails to create a valid message. This is hugely beneficial because what if the thing processing the SendEmailMessage is actually on another system? Not only have we transported an invalid request across the wire but we now also have to route an error back to the sender!

 

What we have done by making our messages in an assumed valid state is allowed other code to operate upon them while making assumptions that the message is meeting its minimum contract. In other words, the thing processing the SendEmailMessage does not need to actually check that the fields in the SendEmailMessage are what it needs them to be unless it is requiring something that is above the specified contract of the message (let’s say that it requires something the message defines as optional). The SendEmailMessage has been given the responsibility of insuring that it is always in a valid state.

A side benefit of this is that when dealing with messaging to infrastructure services the invariants you maintain to them are part of your messages which are part of your ubiquitous language as opposed to being implemented in the code handling the messages (infrastructure).

 

I like to think about using validated messages in this way in relation to design by contract. My code that sends the email doesn’t just work on a message that defines data layouts, the message also defines invariants about my data! These can be quite simple (To is not null) or they can be extremely complex like To must be a valid email address that is not at gmail.com. This becomes extremely valuable later when we go to deal with the consumption of messages; one of the biggest problems with interfaces and testing with .NET is that you cannot specify enough information to narrow your contract. You should therefore to be precise test the entire surface of the interface for every implementation (yuck, these tests add up). It is far easier to introduce the message that defines the invariants and then assume them to be true in your code.

Quite quickly we end up thinking about a contract first method of development for these types of things. In other words that we create our message objects before we create the code that sends or processes them. I personally like this method of development a lot for messaging based systems.

Serialization can cause issues with your messaging if you deal with un-trusted clients (versionization problems can cause this as well) as if you use default serialization it can (and will) deserialize messages that are not valid according to say the logic you apply in their constructor! If you are running with untrusted clients you should implement ISerializable on your messages to take control of the serialization process for them so you can insure they are only created in a valid state. For a large system you may want to consider moving this behavior to a “message” layer super type or consider mixing in an interface/implementor pair for ISerializable if you are using compile time AOP

We will look later why but never use runtime AOP on your messages or on the handling functions, its slow, redundant, and way too complicated.

 

Messages should vary in equality based upon the data they hold

Why someone would feel the need to compare messages for equality in a domain context is completely beyond but …. If you do, do consider them to be varying based upon the data that they hold not upon their reference. Beyond that if you can come up with a reason to do it I would love to hear it :-)


Messages should have fluent builders

This is something I believe may be controversial and this post is getting a bit long so I will finish this part as DDDD 5 [Messages have FluentBuilders] on the bus to the summit today.

This entry was posted in DDD, DDDD. Bookmark the permalink. Follow any comments here with the RSS feed for this post.

5 Responses to DDDD 4 [Messages are Value Objects]

  1. korkless says:

    I suggest that a good reason to implement value equality is to help testing, a value equality helps to check only itand not every single fields.

    when testing for example a class MessageCache i think that is better a code as

    Message inMessage = ….

    MessageCache.Add(inMessage );

    Message outMessage = MessageCache.Get(inMessage.Id)

    Assert.That(inMessage.Equals(outMessage));

    but yes, there’s the assumption that Message .Equals is implemented, it’s not bugged,
    ( and in my particular test doesn’t help to test the behaviour with a generic IMessage).

  2. Greg says:

    Jimmy it sounds to me like you are shipping around entire aggregate roots as course grained objects … this can be ok (and is often done at times) but there are other ways of getting around this issue that we will get into in particular when you are focusing more on the mesh side as opposed to the SOA side of things.

    We also need to be very careful on distinguishing messages and DTOs which are a type of message.

  3. Jimmy Bogard says:

    I think I’d have to respectfully disagree here. Valid state can be enforced in more ways than an immutable object. Immutability leads to everything supplied in the constructor. If I have coarse-grained services, messages can get fairly large.

    Suppose instead of Email, you had something like Order. Order contains LineItems (flattened out), maybe Addresses, ShippingOptions, etc etc. This is quite a lot to satisfy in an immutable fashion.

    For simple message, I like to make them immutable to satisfy invariants. But if I’m using things like XML Serialization, it’s much simpler to have a plain DTO and a Validate method. I leave it to my Factory to satisfy invariants.

    As for other Value Object semantics like equality, I never got much use out of those. I never compared DTOs, as they were strictly used at the service layer boundary. Nothing interesting was ever done with them, as they are immediately used with a Mapper to get back to real domain objects.

    When I tried this concept (DTOs are Value Objects) a couple of years back, it started out nicely but broke down in our real-world scenarios of coarse-grained services. I chalked it up to my misplaced desire to model everything in our system in DDD concepts (entity, value object, service). Perhaps you’ve had a different experience.

  4. Evan says:

    A Pat Helland reference on the immutability of messages:
    http://msdn2.microsoft.com/en-us/library/ms954587.aspx

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>