Helix Simplified

The aim of this blog post is to (at a very high level) work from Uncle Bob's "Principles of package and component design" (the main inspiration for the Helix principles) to a condensed description of Helix, and then to take a look at how the main features of Habitat fulfil the Helix aspirations.A Helixy picture Why do I think this is needed? In my opinion, the official documentation in its current state entangles Helix with Habitat in many places (although if you bear this in mind when reading it, it is still a great guide and worth reading) making it hard for newcomers to think about Helix without having to refer to Habitat example implementation.

Disclaimers

  • This is just my interpretation, and the decomposition of Helix is a very brief abbreviation
  • Helix also encompasses a lot of "best practice" stuff, a lot of which I’m disregarding below, as you should already know and follow most of these practises without knowing them as "Helix"
  • If you're interested you can view my previous blogs which introduce Helix/Habitat and then dig a bit deeper
  • This post assumes that you have at least some experience of Helix, i.e. you know about Foundation, Feature and Project modules, what they should contain and how they link up. If not, read my blogs and the official Helix documentation
  • HABITAT IS NOT A STARTER KIT!
  • Habitat is just one interpretation of Helix. Habitat is not Helix. Helix is the practises, Habitat is an example of how they *could* be applied
  • I'll be following this post with another about how you could implement Helix by not following Habitat - it's also likely that the official Helix documentation is going to eventually feature other non-Habitat Helix examples - check out this discussion on the GitHub for the official documentation for some context and useful opinions

 

A Helixy picture

 

Origins of Helix

In my view the defining aspects of Helix come from Uncle Bob's "Principles of package and component design" as introduced in his book Agile Software Development, Principles, Patterns, and Practices. Below I've listed the names of each of the six principles, and in brackets after each I've added my dumbed-down interpretation which helps me remember what each principle means:

Uncle Bob’s “Principles of package and component design” (PPCD)
  Package Cohesion Principles
PPCD1 Reuse-Release equivalence principle (package contains *all* the things that dependants needs for a particular business purpose)
PPCD2 Common-Reuse principle (package *only* contains things that dependants needs for a particular business purpose)
PPCD3 Common-closure principle (what changes together lives together)
  Package Coupling Principles
PPCD4 Acyclic dependencies principle (hopefully this is pretty obvious)
PPCD5 Stable-dependencies principle (unstable packages should depend on more stable packages)
PPCD6 Stable-abstractions principle (the more stable a package, the more abstract it should be)

 

Helix in a nutshell

Next I've grouped the Helix philosophy into three main aspects, and indicated each aspect's relation to the "Principles of package and component design" where applicable:

Main aspects which make up Helix
  Aspect Which PPCD aspects does this cover?
H1 Conceptual identification of foundation/feature/project module artifacts, and Helix dependency rules applied (“Low Coupling”). This aspect focuses on the relationships between modules. Mainly PPCD4/PPCD5/PPCD6
H2 Conceptual and/or “physical” grouping of Helix module artifacts, aka “what changes together belongs together"/High Cohesion. This aspect focuses on the module boundaries. Mainly PPCD1/PPCD2/PPCD3
H3 When a module needs to bind to another module, the connection should be as “loose”/simple as possible, aka dynamically bound components, rather than statically bound, avoiding soft references via JS/CSS/config etc
This aspect is only tangentially relevant to the PPCD, as Uncle Bob was probably was probably thinking more of code dependencies, which tend to be more "binary" (as in, either a module has a code reference to another, or it doesn’t)

 

Habitat in a nutshell

Finally I've listed what are - in my view - the main aspects of Habitat, and how each aspect enforces the "Main aspects which make up Helix" listed above. Again, Habitat is just one interpretation of Helix, which may or may not make sense for your project or organisation. Perhaps this summary of Habitat will help you think about which aspects of Habitat to keep or disregard for your implementation:

Main aspects which make up Habitat
Aspect Related Helix aspects How might this aspect be different in a traditional "non-Helix" solution? How this aspect helps fulfil the Helix principles
Project/Feature/Foundation modules as separate Visual Studio projects to strictly control code dependencies. Each VS project contains all the module's
  • Code
  • Serialized data
  • Config
  • JS
  • CSS
  • Views
H1+H2 Code split across application / domain / infrastructure Visual Studio projects, with no “strong” definition of Helix modules.

Config / views / CSS / JS might live in a “website” VS project

Serialized data might live in dedicated VS projects (e.g. Hedgehog TDS) or serialization configuration and data might also live in the "website" VS project (Unicorn)

Related artifacts are grouped to make it easier to identify relationships. For code especially, dependencies are explicit Visual Studio project to project dependencies. What changes together really does live together.

Module boundaries are explicitly reflected in the filesystem.

You also have the option of having different “views” on the overall implementation by creating extra Visual Studio solutions which contain a subset of the VS projects from the "master" solution. These could be split by business area or by team, for instance.

Project/Feature/Foundation data templates have Helix dependency rules enforced H1 No “strong” definition of Helix modules in your Sitecore data. Easy to see which IA artifacts are designed to be reused, and which are specific to certain websites. Feature and Foundation level IA (interface templates / renderings etc) can be reused across multiple Project modules
getRenderingDatasource pipeline customisation to allow rendering datasource and rendering templates to be specified, without needing rendering (Feature) to refer to Project module scope H1
Rendering datasource location and template are either blank, fixed to a particular project, or may introduce coupling between projects in the case that e.g. one datasource location is shared between projects. All features can be used across multiple projects without modification.
Features bring in their CSS/JS dependencies via asset references in their renderings, or via config registration. Project uses a Foundation module to pull in these references. H3 “Hard” references to the CSS/JS of Features, from code or views in Project scope. E.g. page layout references feature-specific JavaScript file Features can be dynamically bound to Projects via data, without (in theory) having to worry about CSS/JS dependencies. Also, depending on the approach, you have the option of only referencing artifacts when the relevant feature exists on a given page. Traditional "hard" references might not break the Helix dependency rules per se, as Project can depend on Feature - so the benefits are more related to ease of module reuse
All components are bound dynamically (except for maybe within a module, most likely a feature) H3 Static binding of components is allowed (e.g. header or nav statically bound to the main layout) Encourages flexible page composition. But as above, static binding wouldn’t break the dependency rules per se, as Project can depend on Feature. Again, the benefits are more related to ease of module reuse.
Developing outside the web root H2 Developing inside the web root. All non-code artifacts are therefore stored in the "website" Visual Studio project Developing outside the web root is required if non-code artifacts (CSS/JS/Views etc) are stored outside of a “root” VS project, so is somewhat a corollary of the first Habitat aspect.

Benefits include a better conceptual divide between Sitecore/custom code (e.g. don’t have to worry about including/excluding Sitecore files in the VS solution or in source control).

Security roles are defined for each feature H2/H3 Security roles are usually defined “top down” by identifying groups of business users, and mapping their access rights down to item level Project level security roles can be “composed” of pre-canned Feature level security roles. This is a level of indirection which means, at a global level, you only need to think about Features when configuring security, rather than any deeper (items).


In conclusion ...

Hopefully this post helps you deconstruct Helix and Habitat, and will help you start thinking about how you will approach Helix. For more to read on this subject, check out this post by Martin Davies which also explores the relationship between Uncle Bob's principles and Helix. He also has a great talk here with a practical example of implementing Helix without getting too bogged down with Habitat. I'll be exploring alternatives to Habitat shortly, in a future post.