Sitecore Helix- Modules that need to reference another module in the same layer Part 2

One module which is dependent on 2 or more modules

This is the second part in a 3-part series on dependency, if you have not read part 1 please read it first.

When a single module is dependent on 2 or more other modules in the feature layer there are few ways to solve this issue:

  1. Introduce an abstraction and implemented the abstraction in the project layer.
  2. Introduce an Abstractions in the foundation layer.
  3. Move the module to the project layer.

The Metadata Challenge

A typical example of a module, which can be dependent on 2 or more modules, is Metadata. In addition to providing keywords, taxonomy, etc. metadata is generally responsible for generating the title element in the head section and typical requirements could be as follows:

  1. If it is a news article, use the news title.
  2. If it is a blog post, use the blog post.
  3. If it is a product page, get the product title from the database.
  4. Otherwise return the item display name.

Metadata is a good example where implicit/soft dependency typically creep in, i.e. the metadata module needs the title for a given item and it uses the Sitecore field from the news module, blog module, product module, etc.

Solution 1 – Introduce an abstraction and implemente the abstraction in the project layer.

The only information that the metadata module needs that it can not determine itself is the title for a given item. Therefore, it is necessary to introduce an interface that satisfies that requirement, for an item give me the title. It is in fact very simple, see below.

namespace Feature.MetaData
{
	internal interface ITitleRepository
	{
		string Get(Item item);
	}
}

The context in the project layer is well suited to implement the ITitleRepository interface, as the project layer is responsible for aggregating/mediating the functionality provided by the feature and foundation layers.

Therefore, the next step is to implement ITitleRepository in the project layer, by getting the relevant information from the features (i.e. news, blogs, products) and provide the default behavior of returning the Display name if all else fails (see the example implementation below).

namespace Feature.MetaData
{
namespace Project.Context
{
	class TitleRepository : ITitleRepository
	{
		public string Get(Item item)
		{
			if (item == null)
				return string.Empty;

			// we assume that each repsository returns null, if the item is ot of the correct type...
			string value;
			//is the item a news?
			var news = _newsRepository.Get(item);
			if (!string.IsNullOrEmpty(news?.Title))
				return news.Title;

			//is it a blog post?
			var blog = _blogRepository.Get(item);
			if (!string.IsNullOrEmpty(blog?.Title))
				return blog.Title;

			//is a blog post?
			var product = _productRepository.Get(item);
			if (!string.IsNullOrEmpty(product?.Name))
				return product.Name;

			//default return display name...
			return item.DisplayName;
		}
		readonly ProductRepository _productRepository = new ProductRepository();
		readonly NewsRepository _newsRepository = new NewsRepository();
		readonly BlogRepository _blogRepository = new BlogRepository();
	}
}}

The last step is to use dependency inject to inject the implementation from the project layer, for the interface ITitleRepository.

Solution 2 – Introduce an Abstractions in the foundation layer

In some situations, it might be appropriate to introduce an abstraction in the foundation layer, but only if more than one feature depend on the abstraction. If only the Metadata is using the abstraction it is not sufficient to introduce an abstraction in the foundation layer.

In addition, you should consider why was the abstraction not identified and or present already, it could be a mistake but be sure.

See Part 1, where I have a step by step guide on how to implement this.

Solution 3 – Move the module to the project layer

Whilst this is an easy solution I do not recommend it.

The purpose of the project layer is to aggregate functionality provided by the feature layer and not provide functionality. For example:

  • Page Types module – determine which features are shown on given page type.
  • Context module is responsible for determining the context for each request
    • for example using dependency injection to decide which implementation should be used for any abstractions.

In addition the project is the least stable layer, and the majority of the Metadata functionality in my experience is very stable and similar across all projects, the only variation is how the title is generated and this is not enough to warrant it being moved to the project layer.

I hope this was helpful, and please continue to part 3.

5 thoughts on “Sitecore Helix- Modules that need to reference another module in the same layer Part 2

  1. Peter

    Hi Alan

    Is there a code example for Solution 2? In particular, it would be nice to see how Project layer module makes a decision on which Feature module’s implementation should be used in regards to Metadata functionality implementation.

    Reply
  2. Michael Edwards (@mikeedwards83)

    Hi Alan

    An alternative to the TitleRepository is to implement a Sitecore pipeline. Each feature can then just register a new processor. This avoids the need for anything in the project to be changed when a new repo is introduced.

    Mike

    Reply
      1. Alan Coates Post author

        But then each feature has to implement a pipeline processor and in theory they know about the metadata modules requirements so it could be seen as a soft dependency, what do u think?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s