It been a while since my last blog post – my second child Annika was born March 16th and since then I’ve been forced to realize that two children takes up a lot of blog-writing time.
A year ago I wrote a post titled Type before function, which pointed out the very type-centric design of Sitecore. Since then, we have in Pentia tried to develop a design practice which focuses more on isolating logically grouped functionality in our design and thinking outside the type-centric nature of Sitecore. For this purpose, we have “invented” the term component in our design. The purpose of components is to separate the functionality from the type, allowing the developer to focus on one purpose and its interfaces.
The practise has been quite successful – our large-scale solutions have become increasingly easy to maintain and extend. As a side effect of the process, we now have a high degree of reuse – not just knowledge, but actual code – between even seemingly un-similar projects. Not very surprisingly, it turns out that developers are more inclined to reuse code, which is easily overviewed. The design practice is so successful, that we have passed it on to external projects, through our Professional Services.
Here are a few tips on getting you started:
Consistent placement and naming
Not all items belonging to a component can be placed together. Naming and placement makes it easier to identify component items – in a type-centric system.
Keep your files together – we never use the standard Sitecore folders, e.g. /xsl and /layouts. All files in a component are placed below a folder named /Components/[ComponentName]. This makes it easy to identify which files belong together without e.g. garbling the filename with unnecessary prefixes. And if you think about it, it’s not hard to identify a file as an XSLT – so why put it in the/xsl folder? Keeping component items together also goes for templates, renderings and layouts in Sitecore. For the purpose of Sitecore best practice, we still place templates under /sitecore/templates (although I suppose it’s not strictly necessary), and layout items under /sitecore/layouts. But we always use subfolders which are named consistently, e.g. /sitecore/templates/Components/[ComponentName].
Each component has a separate Visual Studio project, and therefore a separate assembly. Aside from grouping files even further, this also helps to identify dependencies between components. Use build events on the project to move files from component folders to website folders if needed.
Think of templates in Sitecore as interfaces – never basetypes – which provide your pagetypes or data items with certain functionality. Always refer to these interfaces in the code within the components.
Example: The component Navigation (menu, breadcrumb and sitemap) defines the template Navigable with the fields Menu Title and Show In Menu. This template is assigned to the pagetypes which can be shown in the menu. The renderings Menu.xslt and Breadcrumb.xslt only references the Navigable template by using the XslHelper.IsItemOfType() method (or your own more optimized version).
There are a number of components which is always in a project, and which brings the functionality of the other components together.
The Design component contains all the graphic design for the project. Do not be tempted to place stylesheets and graphics within each component – the design for a single component is always related to other components, and therefore you will be forced to create unnecessary dependencies.
The PageTypes component brings together the interface templates and renderings and sublayouts in the other components on the actual page type template. Only page type templates are instantiated in the content tree. If you define the page type template News in the News component and not in the PageTypes component, you will be forced to create dependencies to other components e.g. Navigation.
Dependencies and Inversion of control
Keep your dependencies amongst components as few and as obvious as possible. It should not be necessary for a developer to know more than the component he is working on – too many dependencies makes the components too complex and less flexible. The common components is one way to reduce dependencies, another is the use of the inversion of control pattern and possibly an IoC container. Suppose the News component uses the Indexing component for providing data quickly. This could naturally be done by calling the indexing component directly through the News code, thereby creating a dependency. Alternately the News component could provide an appropriate interface which defines its necessary functionality. This interface could be implemented by the Indexing component and instantiated though Reflection or an IoC container like Unity or Spring, thereby inverting the dependency and making the News component more lean.