DDDD 5 [Messages have Fluent Builders]

In DDDD 4 I was lucky enough to get some commentary from an astute reader Jimmy Bogard, he wrote in his comment:

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.

The builder helps alleviate a lot of this pain while at the same time making our code more readable. I have talked about fluent builders in the past in A Use for Extension Methods but I will briefly go through how they work again. The basic parts of the pattern are to create a class that is immutable and has internally the same members that will be required to call the constructor of the target object. Properties and methods are exposed with fluent names to help build the target object. The target object’s constructor is eventually called through an implicit cast operation. As is always the case code speaks 1000 words.

Let’s take a simple message.

 

InsertOrderCommand ioc = new InsertOrderCommand(null, MarketSide.Buy, “B12345678″, 0.12m, “NT”,
    TestDate, 1000, false, 100, 1000, false, TestDate, OrderDuration.Day, ExchangeGateways.CNQToronto, false, false);

 

YUCK!

 

Let’s try rewriting that with a builder.

InsertOrderCommand ioc = New.InsertDayOrder

                                             .On(ExchangeGateways.CNQToronto)

                                             .FromBroker(10)

                                             .ToBuy(1000)

                                             .OfSecurity(“NT”)

                                             .At(0.12m)

                                             .WithUniqueOrderNumberOf(“B12345678″);

 

note that the builder does not always match up 1-1 with the object … in this example ToBuy(Volume) sets that the order type is of type buy, it sets another field, and it sets the volume.

Phew that’s a whole lot easier to read! Let’s look at how to have this happen. First let’s look at a message.

 

    [Serializable]
public class EquityQuoteMessage : ILevelOneCommand, IHasSecurityInformation
{
public readonly DateTime Time;
public readonly string Symbol;
public readonly decimal BidPrice;
public readonly decimal AskPrice;
public readonly ExchangeGateways Gateway;

public EquityQuoteMessage(ExchangeGateways _Gateway, string _Symbol, DateTime _Time, decimal _BidPrice, decimal _AskPrice)
{
Gateway = _Gateway;
Symbol = _Symbol;
Time = _Time;
BidPrice = _BidPrice;
AskPrice = _AskPrice;
}

public string GetSummary()
{
return "InsertEquityQuote: " + Gateway.ToString() + " " + Symbol + " " + BidPrice + "-" + AskPrice;
}

ExchangeId IHasSecurityInformation.ExchangeId
{
get { return ExchangeGatewayIdTranslator.TranslateGatewayToExchangeId(this.Gateway); }
}

string IHasSecurityInformation.Symbol
{
get { return this.Symbol; }
}
}

Now … we need a builder for this message.

	public class EquityQuoteMessageBuilder {
internal readonly ExchangeGateways m_Gateway;
internal readonly string m_Security;
internal readonly DateTime m_Time;
internal readonly decimal m_BidPrice;
internal readonly decimal m_AskPrice;


[DebuggerStepThroughAttribute]
public EquityQuoteMessageBuilder OnGateway(ExchangeGateways _Gateway) {
return new InsertEquityQuoteCommandBuilder(_Gateway,m_Security,m_Time,m_BidPrice,m_AskPrice);
}

[DebuggerStepThroughAttribute]
public EquityQuoteMessageBuilder ForSecurity(string _Symbol) {
return new InsertEquityQuoteCommandBuilder(m_Gateway,_Symbol,m_Time,m_BidPrice,m_AskPrice);
}

[DebuggerStepThroughAttribute]
public EquityQuoteMessageBuilder At(DateTime _Time) {
return new InsertEquityQuoteCommandBuilder(m_Gateway,m_Security,_Time,m_BidPrice,m_AskPrice);
}

[DebuggerStepThroughAttribute]
public EquityQuoteMessageBuilder WithSpreadOf(decimal _BidPrice, decimal _AskPrice) {
return new InsertEquityQuoteCommandBuilder(m_Gateway,m_Security,m_Time,_BidPrice,_AskPrice);
}

private EquityQuoteMessageBuilder(ExchangeGateways _Gateway,string _Symbol,DateTime _Time,decimal _BidPrice,decimal _AskPrice) {
m_Gateway = _Gateway;
m_Security = _Symbol;
m_Time = _Time;
m_BidPrice = _BidPrice;
m_AskPrice = _AskPrice;
}

public EquityQuoteMessageBuilder {}

public static implicit operator EquityQuoteMessage(EquityQuoteMessageBuilder _Builder) {
return new InsertEquityQuoteCommand(_Builder.m_Gateway, _Builder.m_Security, _Builder.m_Time, _Builder.m_BidPrice, _Builder.m_AskPrice);
}
}

 

I have written a generator to make skeletons of these builder classes that I may post which simplifies this process greatly (especially if you use resharper ctrl+rr or f2 everything else is done) but I will only release it if people promise not to make fun of the code as it was written in an afternoon just to save time when writing a few and looks like it was written by a second year student :-)

 

 

Aaron over at elutian uses a structurally identical pattern (except for the additional use of extension methods in A Use for Extension Methods) in his post Fluent Fixtures the key difference between what I call a Fluent Builder and what he calls a Fluent Fixture is in the intent. Aaron uses his fixtures only for the initialization of setup data for tests which they are EXTREMELY valuable for (especially when dealing with messages as it produces a soluble method of expressing what is in the method) … My fluent builders are used not only for the initialization of test data but also for the creation of real objects (I might even go so far as to say that the construtors for messages should be made internal and you should only expose builders though in some extremely high performance conditions you might want to actually use constructors).

 

Jimmy Bogard hit the nail on the head in that complex messages can be a nightmare to build immutably because they get really big. What we do to get around that is we use an mutable builder that we then cast to an immutable message. This gives us the best of both worlds although the builders can be annoying to type, since essentially we have made explicit a transient mutable version of the message and a fixed immutable version of the message.

 

To be more clear, let’s try a bigger example like the one that Jimmy mentions and see how bad it is to create a bigger message. I will use a DTO example since they tend to be the offenders

 

OrderDTO order = New.OrderDTO

        .WithId(SomeGuid)

        .ShippingTo(New.Address …..)

        .AddLineItem(New.LineItem.For(12).Of(“Product 1″).At(15.99)

        .AddLineItem(New.LineItem.For(1).Of(“Product 2″).At(22.97)

        .AddLineItem(New.LineItem.For(15).Or(“Product 3″).At(15.22)

naturally you could use a loop etc when building the message (and sometimes in terms of test fixtures you may find your self actually referencing the Builder then later adding more items to it similar to how an object mother would work but this is another post)

 

Of course we can go a different route than this. You will notice that a natural break is occurring in the setup of our message between the root and the pieces under the root. What if instead of trying to create one really big message we created a few smaller ones just like how our actual setup is working. In other words what if instead of having an OrderDTO as one big message we introduced a container to hold smaller messages and relate them as being one something like:

SnapShot

    CreateOrderMessage

    AddLineItemMessage

    AddLineItemMessage

    AddLineItemMessage

EndSnapShot

 

This would help prevent us from having to deal with the larger items but each method has their own benefits. The main benefit of the first method is that its schema exists within the message. Especially when dealing with external clients or other types of integration points this can be extremely beneficial (there is no need of logic to figure out how to build the data). When combined with something like XML this can be extremely powerful.

 

The second method can also be extremely powerful in a closed environment for a few reasons. In many circumstances it is actually simpler to send over these smaller pieces, the big problem with this methodology is that you need to have domain logic existing on the client in order to know how to process these smaller messages to get the client to a state matching what the originator of the message intended. As we will see later on though, in some circumstances (especially when we want disconnected access) some of this logic will be distributed for other reasons anyways so it may become a viable option.

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

16 Responses to DDDD 5 [Messages have Fluent Builders]

  1. Pingback: .NET Object Initializers Considered Harmful | nomade numérique

  2. Greg says:

    Daniel it certainly doesn’t apply to all fluent interfaces but perhaps fluent builders as you could get pretty close with immutability + initializers.

    even with initializers supporting immutable objects … there is still a use for fluent builders as they shorten code and expand meaning … The example above would be ToBuy(100) or DayOrder which set multiple fields …

  3. Hence, you seem to agree: if .NET implemented ctor/initializers in such a way it didn’t break inmutability, you wouldn’t need any of the fluent stuff everyone seems to be so fond of lately :).

    More to the point that it’s a hack in general, except when applied to very specific cases where it actually makes for a much easier to understand and discover API (i.e. MoQ ;))

  4. Greg says:

    I agree its a hack around a limitation but there are benefits beyond what the compiler could provide in most cases Buy(100) is a great example … is it extra code? yeah … but can it be generated … yeah.

    Given those parameters I am ok with it.

    Ideally for simple cases I would prefer the compiler to just route to a constructor (perhaps even via a generated builder?). This is what initializers SHOULD have done in the first place. I am initializing an object; it should not push me down a mutable path in order to do so. To implement it in any other way (such has calling a “Validate” method after) is a inexcusable hack on the part of the compiler team. Immutability is not a temporal concept in terms of an object life cycle and to try to model it as such is full of dangerous edge conditions.

     

    I end up with more … scarier code … by trying to implement an object that is mutable some of the time and immutable at other times in its life cycle. I would rather have 2 objects (1 immutable always valid and 1 mutable and possibly invalid that can create the first). 

  5. > you can assign multiple properties at once which I can’t do with an initializer

    You can always call a method on the object to do that, just like Buy(int) or Sell(int). They don’t have to be belong to a fluent interface, I’d say.

    Agreed on the immutability. I’ve suggested (and we should all push for it) to have private setter properties to be only set-ables during an initializer, and never again later. If that behavior is added to C#, together with the ctor (which should run after the initializer properties have been set, IMO), you could validate their values in a single step, and avoid making your objects mutable.

    I’d prefer that approach much better than a verbose fluent interface.

    But even without that, you could always provide inmutability through a SetReadonly() or Initialize() method on the object that would do the validation and throw exceptions for setter after that point.

    I can’t help but think fluent interfaces for this is more of a hack around the lack of inmutable (but at the same time easy to initialize) objects in .NET….

  6. Greg says:

    Daniel the problem with the initializer syntax is that it forces you to make your object mutable. The reason for the large numbers of arguments is that these objects are immutable (there are many reasons why we want these to be immutable).

    I actually had a talk with some members of the C# team last week as to this exact problem.

    I am not willing to trade my immutability in order to have an initializer … The ability to know that a constructed object is ALWAYS a valid instance of that object is *really* important in messaging based systems as it removes a lot of validation code.

    If I were doing this on a class that was not a DTO I would agree with your constructor # of parameters argument. But on a DTO?!

    Also the names that you gave the properties are not the same as what the properties of the actual message are. Example: “At” as you put it correlates to “Price” and there are some of these that correlate to multiple properties (one of the reasons the builders are nice, you can assign multiple properties at once which I can’t do with an initializer). A good example of this is Buy(int) and Sell(int) which set not only the type of operation that it is but the volume of the operation or DayOrder which sets about 3 seperate properties within the message.

  7. InsertOrderCommand ioc = new InsertOrderCommand(null, MarketSide.Buy, “B12345678″, 0.12m, “NT”,
    TestDate, 1000, false, 100, 1000, false, TestDate, OrderDuration.Day, ExchangeGateways.CNQToronto, false, false);

    This is not a good example neither a sufficient motivator to have fluent builders. I’ve RARELY seen such a promiscuous amount of arguments in a ctor. If you’ve more than 4 args in any ctor/method, I’d say you have a problem already (think why there are only that many Ts in Action and Func….)

    The typical solution here would involve an object with properties and a nice object initializer, which I’ll make up based on your builder:

    InsertOrderCommand ioc = new InsertOrderCommand {
    OrderDate = ExchangeGateways.CNQToronto,
    BrokerId = 10,
    BuyAmount = 1000,
    SecurityCode = “NT”,
    At = 0.12m,
    OrderNumber = B12345678 };

    To me, that’s equally good to read, and I didn’t have to change programming idioms or make up a ton of interfaces to provide the fluent API. Property validation/integrity/consistency has to be done eventually (unlike ctor args, which are determined at a single point in time), just like in your case.

    Looks to me like you’re stretching the fluent interface a bit… newing up objects is the core of any OO language, with very well understood semantics and syntax. Why make it more convoluted and try to force it to look like english just to gain a tiny bit (I don’t think you’re gaining even that in the above case) of readability?

  8. Christian Crowhurst says:

    Hi Greg,
    I would definitely be interested in the code gen for the skeleton of the builders. It was something that I was thinking of doing myself so any kick start would be very cool indeed.
    Christian

  9. Greg says:

    Yes the snapshot implies that the object is complete (and should be valid) … You are correct that the “validate” is implicit in the concept of the “snapshot” but I don’t think that’s too big of a deal as it makes sense when you understand what its doing …

    per “Can I have an order with no line items” this is completely up to aggregate in question and should be inherent in the message. The larger DTO (which can be very useful) would make the fact that it needs to have an order line item explicit.

    There are times when using a single large DTO can be better than using a series of fine grained message (it is absolutely a design decision).

    My my point I was trying to hit in this post was more so on the construction of a message object though as opposed to the mechanism they take when put together; putting both the big DTO and series of messages as choices here may have been a bit off topic on my part and requires further discussion.

  10. Joseph Gutierrez says:

    The OrderCompletedMessage I believe is implied instead of being explicit in your SnapShot.

    The link between what you’re describing and UDI’s is that the intentions are the same just you are using a different framework. You can even have the same granularity.

    Here is your DSL example of UDI’s implementation:

    CreateOrderMessage: 12345
    AddLineItem: 1
    AddLineItem: 2
    AddLineItem: 3
    EndMessage

    UpdateOrderMessage: 12345
    DeleteLineItem: 2
    DeleteLineItem: 3
    AddLineItem : 2
    AddLineItem : 3
    EndMessage

    CompleteOrderMessage: 12345
    ValidateLineItem: 1
    ValidateLineItem: 2
    ValidateLineItem: 3
    EndMessage

    DisplayOrderMessage: 12345
    DecorateLineItem: 1
    DecorateLineItem: 2
    DecorateLineItem: 3
    EndMessage

    DeleteOrderMessage: 12345
    DeleteLineItem: 1
    DeleteLineItem: 2
    DeleteLineItem: 3
    EndMessage

  11. Joseph Gutierrez says:

    @Greg

    The main gist of Udi’s post IMHO is that the domain language that he built for orders, needed to change the granularity of his order messages. I think it would be possible to to do the same thing with your fluent interfaces.

    When looking at your SnapShot there was an implied CompleteOrderMessage it wasn’t explicit.

    I know that using code examples in blogs is tough, but I think that showing an implementation of a CRUD should also include the rest of the operations. It should also discuss the influence of granularity of the Fluent Interface.

    Can you Create an order without AddLineItemMessages? Just looking at your code examples I would have to say NO. As a programmer, before I started using your framework (OrderBuilder) I would have to look at the source code to see the implementation allowed partial orders or If it had to be a complete order to instantiate the order.

    When designing a Domain Language or API you want to have low surface area, but high volume.

  12. Greg says:

    Joseph, yes it has been done before … I myself have posted about this before :-)

    per OrderCompletedMessage … I don’t see what you are referring to in that post … I know most of Udi’s stuff pretty well … These builders aren’t something that I have seen him post before, did you paste the wrong link?

    Greg

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=""> <strike> <strong>