Keep items out of your model
Item class is very flexible. But this flexability is a double edged sword. All too often, it’s tempting to simply pass items round your project API without creating a separate, explicit model. This can have performance implications when you need to scale and support 1000s of items.
Late last year I attended an event in Melbourne where I was chatting to someone who had previously used the WeBlog module on a customer’s site. Overall, their feedback was quite positive, which was great to hear. They did however, mention they faced one issue with scaling, which was a surprise to me. Off the back of that conversation, I registered a bug Performance issues with large number of posts. If you were unaware, I’m one of the maintainers of the WeBlog module.
The cause of the issue was the fact we were using items as our model. This really highlighted the need to keep items out of the model. The model I’m referring to here is the set of classes you use to represent your domain objects.
In the WeBlog module we’ve used the Custom Item Pattern to encapsulate field access of each template. This helps adhere to the DRY principal (Don’t Repeat Yourself). Now, this isn’t a bad thing, but using it as the model is. The major issue with this approach is creating instances of the model class.
Item class is not easily instantiated. It’s possible, as I wrote back in 2016 in Roll your own Sitecore Item, but it’s not particularly easy. And although you might use the technique I showed for your tests, you wouldn’t want to use that approach in production code.
So whenever you want an instance (in production), you always have to use the data API to retrieve the item from the content tree. That might not be such an issue for you, but as I mentioned at the start of this article, the issue I was looking into for the WeBlog module was related to scale.
Let’s say I have 10 posts to show on the post list view. That means I’ll need to retrieve those 10 items from the content tree. Loading an item from the content tree, even by ID, is not the fastest thing in the world with cold caches. At 10 or 100 posts this might not even be noticable, but what if you had 5000 posts. Yep, I reckon you’d feel that.
Your first reaction to this problem might be to point out that you don’t need to load all those items for the post list; if I’m only showing 10 items, only load those 10. Good catch. But the issue here is the model is used throughout the APIs. There are many other components within the WeBlog module which need all the posts to generate their output, such as the archive component, and even the tag cloud. So for those, all the posts need to be accessed, and with the model being the custom items, all those items need to be loaded.
So how do we solve this issue? Quite simply, keep items out of your model. Create separate model classes with an
ItemUri property which can be used to load the item for which the class instance corresponds. Let’s look at a simple example:
public class Entry
This is a normal POCO. The only thing that stands out is the
Uri property which allows us to load the item for this “Entry” when necessary as follows:
var item = Sitecore.Data.Database.GetItem(entryInstance.Uri);
With a POCO as the model, the API can easily return instances of
Entry without having to load them from the content tree.
There would be a number of readers currently smiling to themselves and nodding slightly. These are the readers who have used ORM tools and frameworks in their solutions. The whole purpose of an ORM in a Sitecore solution is to map between Sitecore items and POCO (or very simple) classes. So if you’ve used an ORM, you’ve probably already kept the items out of your model.