28 Mar
2009

Experimenting With Fluent Interfaces in the Domain

As you might have guessed from my previous two blog posts, I’ve been experimenting with fluent interfaces lately. I’ve been thinking about passing an expression builder to an aggregate root so that the root entity can use the builder to create a particular child entity. This begs for some code.

public class Category : DomainEntity
{
    private readonly ISet<Item> _items;
    public virtual String Name { get; private set; }

    protected Category()
    {
        _items = new HashedSet<CatalogItem>();
    }

    public void Categorize(String productNumber,
                     String itemName, String manufacturer)
    {
        var item = new Item(productNumber, itemName,
                            manufacturer);

        _items.Add(item);
    }
}

Suppose I have an aggregate root called Category. A Category can have a list of Items. So in order to add another Item to a Category, the code might look like this.

The Categorize method adds a new Item to the Category. What I don’t like about this method is the number of arguments, even for this simple example. In real life, there can be plenty of arguments that need to be passed to this method. Another thing that somewhat disturbs me is the fact that the Category class is also responsible for creating an Item class.

Lets see what I ended up with using an expression builder. First I created one for building an Item.

public interface IItemBuilder
{
    Item Build();
}

public class ItemBuilder
    : DomainObjectBuilder<Item>,
      IItemBuilder
{
    protected Manufacturer Manufacturer { get; set; }
    protected String Name { get; set; }
    protected Product Product { get; set; }

    public ItemBuilder Named(String name)
    {
        Name = name;
        return this;
    }

    public CatalogItemBuilder ManufacturedBy(
                   Action<ManufacturerBuilder> buildUsing)
    {
        var manufacturerBuilder = new ManufacturerBuilder();
        buildUsing(manufacturerBuilder);
        Manufacturer = manufacturerBuilder.Build();

        return this;
    }

    public CatalogItemBuilder ForProduct(
                        Action<ProductBuilder> buildUsing)
    {
        var productBuilder = new ProductBuilder();
        buildUsing(productBuilder);
        Product = productBuilder.Build();

        return this;
    }

    public override Item Build()
    {
        return new Item(Name, Manufacturer, Product);
    }
}

This is a quite straightforward expression builder where the creation of Manufacturer and Product value objects is handed of to other expression builders, which are not important for this example. Notice the IItemBuilder interface, which can now be used by the Categorize method.

public void Categorize(IItemBuilder itemBuilder)
{
    var item = itemBuilder.Build();
    _items.Add(item);
}

This way I both eliminate the number of arguments I need to pass to the method and the code creating an Item object, which is now moved to the expression builder. Notice that by passing in an instance of IItemBuilder, the domain object is unaware of the actual expression builders themselves which live on top of the domain entities and value objects anyway. Now, in order to remove the need of creating an instance of an ItemBuilder in the layers that use the domain, I added an extra extension method that does that for us.

public static class CatalogCategoryExtensions
{
    public static void Categorize(
        this CatalogCategory catalogCategory,
        Action<CatalogItemBuilder> buildUsing)
    {
        var catalogItemBuilder = new CatalogItemBuilder();
        buildUsing(catalogItemBuilder);
        catalogCategory.CategorizeItem(catalogItemBuilder);
    }
}

This results in the following syntax in the application service (except for the hard-coded values, of course).

category.Categorize(item =>
    item.Named("iPhone")
    .ManufacturedBy(manufacturer =>
        manufacturer.Named("Apple"))
    .ForProduct(product =>
        product.Numbered("AA1687")));

Although this all looks good, I’m not entirely sure of this approach yet but it certainly looks interesting to me. All feedback is more than welcome, off course. I could be totally jumping the shark on this one :-). So let me know what you think.

10 thoughts on “Experimenting With Fluent Interfaces in the Domain

  1. Way too complex for the place that should be kept simple and refactorable. Fluency is welcome in published interfaces, framework-like things. Taking it into domain, or even domain services – i’m not sure.

  2. @Valeriu: Isn’t that what a Domain Specific Language comes from. At the KaizenConf in Austin last year I overheard Dave Laribee talking about DSL’s layered on top a domain model. I agree on the complexity, but if it reduces coupling to the domain entities and therefore increases maintainability, why not?

  3. I would agree with Valeriu Caraulean here.

    This is about the maintainability of the code. Here you are expecting that everyone that is ever going to edit this code is comfortable with fluent interfaces. Not only that, they need to be comfortable with changing the DSL if the requirements change.

    Why not keep it simple ? It’s programmers that are going to read this code, not business people 😉

    Well, that’s my opinion anyway 🙂

  4. @BjartN: I have to disagree on the learning part. When I’m developing a WCF service then every other developer needs to have some notion about WCF in order to maintain it and make changes later on. Same goes for fluent interfaces or any other architecture/technology.

    Business people are never going to read code. But suppose they would, is a fluent interface making the code more readable then, regardless whether you’re a developer or a business person? Why not making that minor effort then, to make your code more readible?

  5. for me, i much prefer to have DSL within my infrastructure layer and service and not in domain itself. For me because you expose infrastructure layer/service to client then it’s the good place for Fluent Interface. I agree with Valeriu Caraulean we should keep our domain simple. Simplicity of domain model should can cover the complexity of business process

  6. @Jan: Firstly, I want to say I really enjoy reading your blog – your posts are rather inspiring and are very well written.

    In terms of the approach taken here, I don’t see any issue with having an application service use a DSL that sits above your domain, and would argue that maintainability of the code would be improved rather than decreased, due to the reduced coupling of domain objects and more readable code in your application services. In addition, since the fluent interface for this lives in extension methods sitting above the domain model, I would suggest that the domain model itself is simpler if anything.

    I am wondering however why an ItemBuilder is being passed into the Aggregate Root, rather than an Item itself? Assuming that an uncategorized item is valid in the domain, or that an item can belong to multiple categories, I would expect the domain to have CategorizeItem method taking an Item as a parameter, rather than a builder.

    Am I missing something here?

  7. @CraigCav: I completely agree. As for the ItemBuilder being passed to the aggregate root: I’ve reused some of the code from a sample application I’m building, but needed to remove some other code that wasn’t of any use for the point I was trying to make. That’s probably what’s missing here 🙂

Comments are closed.