Marrying Ditto with ModelsBuilder

Books I read
See all recommendations

I was happy to be allowed to speak at this years Umbraco UK Festival.
The topic was based on my previous post where I compare Ditto and ModelsBuilder. While preparing for that talk, I couldn't help but notice that the tools and techniques aren't mutually exclusive at all. On the contrary, they can compliment each other in a really nice way.
Slides and video from presentation linked further down.

I won't dive into too many details in this article, I recommend you read the previous article, and take a swim through the code at the github repository.

Cleaning up the processors

In the Dittoified TXT site Matt Brailsford made, we saw a bunch of processors querying the hierarchy. In my Modelsbuilderified version, we do nice and clean domain oriented queries.

Take for instance the top navigation on the site, where we look up all the visible children of the home page. The Ditto processor looks as such:

public class MainNavAttribute : DittoProcessorAttribute
{
    public override object ProcessValue()
    {
        var content = Value as IPublishedContent;
        if (content == null) return Enumerable.Empty<NavLink>();

        var homePage = content.AncestorsOrSelf(1).First();
        return new[] { homePage }.Union(homePage.Children.Where(x => x.IsVisible()));
    }
}

With ModelsBuilder, we point to the homepage from the base document type, and implemented the navigation items query on the homepage:

public partial class UmbHomePage
{
    IEnumerable<INavigationContent> INavigation.MenuItems
    {
        get
        {
            return new[] { this }
                .Union(
                    Children
                    .OfType<INavigationContent>()
                    .Where(c => c.IsVisible)
                );
        }
    }
}

What we keep forgetting though, is that the ModelsBuilder models are created before the content leaves the cache. If we install Ditto in the ModelsBuilderified version, or vice versa, we can actually use that MB query in the processor. Whether we'd like to keep the query and interface segregation on our ModelsBuilder classes, or we'd like to put most logic in the Ditto processors is still a matter of taste.

However, by just letting MB generate its models in the Dittoified project, not writing one single interface, we can refactor the MainNavAttribute as such:

public class MainNavAttribute : DittoProcessorAttribute
{
    public override object ProcessValue()
    {
        var content = Value as IPublishedContent;
        if (content == null) return Enumerable.Empty<NavLink>();

        var homePage = content.AncestorOrSelf<UmbHomePage>();
        return new[] { homePage }.Union(homePage.Children.Where(x => x.IsVisible()));
    }
}

The same can be done to the BaseNewsProcessorAttribute with even more "domain language":

public abstract class BaseNewsAttribute : DittoProcessorAttribute
{
    protected IEnumerable<UmbNewsItem> GetNews()
    {
        var content = Value as UmbMaster;
        if (content == null) return Enumerable.Empty<UmbNewsItem>();

        var newsArchive = content.Home.FirstChild<UmbNewsOverview>();
        if (newsArchive == null) return Enumerable.Empty<UmbNewsItem>();

        return newsArchive.Children<UmbNewsItem>()
            .OrderByDescending(x => x.DisplayDate);
    }
}

You'll notice I've added the DisplayDate implementation to UmbNewsItem so we don't need to think about the PublishDate and CreateDate properties every time we do ordering.

Where to start

I'd recommend that if you don't use either tool today, you should really just start using ModelsBuilder. It will improve your code immensly over using magic strings, level-based queries and all that comes with the basic IPublishedContent implementation. When you start to see that you want more separation of concerns and interfaces don't do that for you, look into adding Ditto on top.

Serialization

The main pain point of using ModelsBuilder today is that IPublishedContent implementations lend themselves badly to serialization. Serializing it without care will lead to cyclic references and/or super big graphs of parents and children.

By mapping the content to POCOs with Ditto, you don't have to care about this.

Strike a balance

In my opinion, one can go way too far with the processors in Ditto. Separation of concerns is good, but not at the cost of having to wade through 10-20 classes for one coherent piece of functionality.

The same can be said about ModelsBuilder. Creating too many compositions, adding to many interfaces, creating too many extensions can be just as overwhelming.

It basically boils down to the good old YAGNI principle.

Further exploration

The examples in this article is avaiable in a branch on GitHub.
I also did a presentation comparing the two tools, and marrying them at last at this years Umbraco UK Festival.
The presentation can be seen on YouTube.
The slides from the presentation are available here.

Author

comments powered by Disqus