5

Is it ok for a Feature module to reference the name (nothing else) of an item in the project layer?

As far as I can tell this would be classified as a weak dependency as it is only in the name of an item. However, this dependency is in the wrong direction as the Feature module effectively becomes dependent on content in the Project layer.

An example of this is the use of Dictionary items. You would call a (Foundation level) extension method to get a dictionary translation within a Feature layer component. But the dictionary item actually lives in the project layer (in the content of the site. Is there some rule about failing gracefully in the event of one of these dependent items not existing?

2 Answers 2

3

It depends.

Whilst the answer from Mark is technically correct and would be the general principle to use when following the Helix guidelines, there are always the "it depends" cases.

The specific example you are looking at from the Habitat example is the Dictionary Foundation module, so it's worth looking at the specifics of this and the actual "dependencies".

But there's a dependency...

In this instance the reference is on the Login dictionary item in Project layer from AccountsMenu.cshtml in Feature layer.

The dependency is on content. Content changes, and content can also be deleted. Your code should always be defensive to cater for these types of scenarios, which in this particular example does this. The built in Translate.Text("key") method for example will return the key if the Dictionary Item is not found, or Settings.GetSetting("SettingName", "default value") allows for a default value to be returned if none is set.

A package should only depend upon packages that are more stable than it is.

But there is no dependency in the traditional sense, there are no Feature layers referencing Project layers. If the Project layer instance was remove, the feature module would continue to function without any issues or compile/runtime errors.

Default Values

The DictionaryField helper accepts a default value, e.g.

@Html.Sitecore().DictionaryField("/Accounts/Accounts Menu/Login", "Login")

Again, Sitecore does this for it's own Dictionary implementation, through the use of Dictionary Domains and fallback (then finally returning the key itself), which allows you to override the default value of an item in a higher level, in this instance your Project layer. Your Project can decide to set a different value, or use the default value, in this case "Login". This is not a dependency IMO.

It's also worth noting the code in the DictionaryPhraseRepository GetItem implementation:

public Item GetItem([NotNull] string relativePath, string defaultValue = "")
{
  ...
  var item = this.GetOrAutoCreateItem(relativePath, defaultValue);
  if (item == null)
  {
    Log.Debug($"Could not find the dictionary item for the site '{this.Dictionary.Site.Name}' with the path '{relativePath}'", this);
  }
  return item;
}

If you look at the implemenation of GetOrAutoCreateItem() then setting dictionaryAutoCreate=true on the sites config means that if the Dictionary item does not exist in your Project content then it will be autocreated (later allowing your Content Editors to change the value with greater ease).

Is there some rule about failing gracefully in the event of one of these dependent items not existing?

Is there a rule? There are no rules, just guidelines. But bear in mind that this is just good software practice anyway, and Sitecore does this internally for a lot of it's own settings.

In this instance, due to the way the Foundation and Feature code is written there is no reverse dependency placed on the Project layer. You could argue there is a "soft dependency" but the code is defensive enough to cater for this and even allows that dependency to be auto-created if required.

7

No.

One of the core principles of Helix is, that it relies on the Stable Dependency Principle.

Stable Dependency Principle

The dependencies between packages should be in the direction of the stability of the packages. A package should only depend upon packages that are more stable than it is.

http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod

Which means your dependencies should always flow from unstable (project) towards stable (Feature -> Foundation).

Reference: Layers [Helix]

It doesn't really matter if all you reference is an item name, an item path or whatever else - your Foundation code should never rely on anything at all in layers above it.

Architecturally, it would be acceptable to have Foundation code and interfaces define what is required (in terms of an Interface or perhaps a base template), to make specific functionality work - and then the Project layer sending down an item or whatever conforming to this interface definition for the Foundation code to work with.

I'll exemplify

Naughty Foundation Code

public void KeywordExtractor()
{
    // just go home already, will ya?
    var itemToExtractFrom = Sitecore.Context.Item;
    ...
}

Doesn't really matter if it goes to Context Item or it references a specific Project Layer item directly - it's a clear no-go zone.

Better behaved Foundation Code

public void KeywordExtractor(Item keywordItem)
{
    Assert.That(keywordItem).InheritsFrom(myFoundationBaseTemplate);
    DoGreatFoundationThings(keywordItem);
}
3
  • :-( Well it looks like Habitat then violates one of the principles it sets out to demonstrate then ;-) e.g. AccountsMenu.cshtml references the dictionary item /Accounts/Accounts Menu/Login Sep 7, 2017 at 11:54
  • 2
    I think it's more important to remember; Helix is a loose set of architectural guidelines with plenty of wiggle room. And Habitat is an evolving non-production worthy demo site. Sep 7, 2017 at 11:56
  • 1
    Good points and thanks for the comprehensive answer. I might exercise my right to wiggle here then! Sep 7, 2017 at 11:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.