Best Practices For Sitecore, Helix and General Development
Here's a colleciton of guidance and best practices for sitecore development, that I've put together for Sitecore Foundation based projects. Some are specific to the framework, but most are general to Sitecore Development and Helix Architecture in general:
Sitecore Organizational Best Practices
- Follow Helix Folder Naming Conventions Most Everywhere
- Layouts (Layouts, Renderings, etc)
- Media Library (Especially when images are tied to features (e.g. Thumbnails)
- System > Dictionary, Rules, etc
- Marketing Control Panel > Goals, etc.
- Templates, Branch Templates, etc
- Global Resources (CSS/JS managed in Sitecore)
- Multisite Settings located in Site Configuration
- Leverage SF Branch Templates for Site and Content Organization Pattern
- Gives you Page, Site, Site Collection and Global Content
- If There is governance on the Site Collection, Organize All Content under Site Shared Content and Site Collection Shared Content
- If there is no governance, recommend content authors store most content under pages. (Also recommended for larger sites, where site shared content would be too unwieldy
- Manually Add Sub Folders to Content Folders to organize shared content folders.
- Highly Recommended especially if using Handlebar Templates. (SF)
- Avoid use of global Shared Content unless it truly is global.
Helix Best Practices
- General
- Keep Scope of Project Discrete. Don't be Afraid to Split to multiple ones.
- Manage Content Items for Project at that project level. (Use Unicorn Config pointing to relative serialization folder or add TDS project specific to that project).
- Organize Templates in Template Type Folders (Examples Below)
- Component Templates
- Configuration Templates
- Entity Templates
- Content Templates
- Rendering Parameter Templates
- Foundation
- Projects Reference Each Other as Needed
- Deal with a Suite of templates or Type of Integration
- No Renderings, Layoutsor Web API's.
- Feature
- All Components, Renderings, Web API's live in this layer
- Project
- Sites and Support Projects that assemble the site from multiple Feature and Foundation projects only
- Composition of the Site (Page Implementation, etc) should be in the project Layer Only.
- No Renderings or Components implemented in this layer.
- Layout templates and Sitewide Placeholder Settings are usually defined in these projects.
- Avoid creating a lot of layouts items. Create multiple page templates with different standard values to create different effective layouts for content authors to use.
- Create a Base Page Hierarchy and Set Up inheritance between them for your Site. Here's a typical strong approach
- Site Base Page
- Inherits all the SF Page Inheritance Templates (Meta Tags, Sitemap, search, etc)
- Standard Values set basic Header/Footer, etc.
- Home Page
- Inherits Base Page, Mods as needed.
- Standard Values Set Proper Insert Options for Other Page Types
- Canvas Page
- Inherits Base Page, Has Large Middle Area Placeholder with Settings for adding any component wanted
- Standard Values Set Proper Insert Options for Other Page Types
- Content Page
- Adds Fields for Title, Content, etc used on many pages or inherit from your own template defined in feature project.
- Uses Components (or Handlebar Components) to define basic layout and render pages from this template.
- Standard Values Set Proper Insert Options for Other Page Types
- Site Base Page
Sitecore Foundation Framework Tuning Recommended Best Practices
- Remove Projects that aren't desired or would not be wanted to used (don't include everything because it's there, you can add them back easily if you need them).
- Customize Site Configuration and Page Templates to inherit only from the feature templates you want to support.
Project Best Practices - Structure Your Projects Like This:
- References
- Use Nuget References to all Sitecore Assemblies
- Configure All Sitecore Assemblies to Copy Local to False
- General
- Organize All Classes/Items into Folders.
- Recommended Folder Structure
- App_Config
- Include
- [Feature|Foundation].Name
- Multiple Configs if Needed
- Zroutes
- Configs for Registering WebAPI routes if needed.
- [Feature|Foundation].Name
- Include
- Constants
- Classes Named with Types of constants or Enum to make Calling them seem fluent. (e.g Templates.TemplateAName)
- Use Static Properties for Value Based Types, Const for regular fields.
- Only use for things that should never change, or changing would require a rebuild anyway.
- Configuration
- Classes Named with Types of Configuration Values Encapsulated to make calling seem fluent.
- Use Static Properties for All Values
- For File Based Configuration use Sitecore Settings. Never Use App Settings.
- For Site Specific Configuration Consider using Sitecore Foundation Multisite Settings (SF Specific)
- To Manage Settings in Multiple Environments (dev, staging, prod, etc), Clone the Site Settings Root folder for each envrionment (clone not copy, so you can manage settings in the default/location master) and then override settings as needed. Use transforms in deployment to point SF.ConfigRoot to proper config folder for environment.
- For User Specific Properties, Consider using User Setting Facet (SF Specifci)
- Content (if not managing resources in Sitecore)
- [Feature.Foundation].Name
- Folders for Module/View/Area
- CSS or SASS/LESS files
- JavaScript related to Scripts.
- Folders for Module/View/Area
- [Feature.Foundation].Name
- Controllers
- All Controller Rendering Controllers should Extend GlassController
- use GetDataSourceItem and GetContextItem as needed to get bound data items
- All WebAPI Controllers should extend ServicesAPIController
- Use SF.Foundation.API's GetTracker Extension method to get Tracker if needed. (SF)
- Pass true to getTracker if you want API to count as an interaction in Path Analyzer.
- Use SF.Foundation.API's GetTracker Extension method to get Tracker if needed. (SF)
- Create a Register Routes Class to register API's.
- Extend SF.Foundation.API's RegisterRoutesBase class (SF)
- Use MapRouteWithSession if API needs to support Session or Tracker. (SF)
- All Controller Rendering Controllers should Extend GlassController
- Extensions
- Extension Method Classes
- Facades
- Classes that Encapsulate Business Logic to make available to other projects that depend on this.
- Methods should be Static Where Possible.
- Commonly used in Foundation Projects and Called by Feature Projects
- Facets
- Classes to Support xDB Facets
- Global (if syncing between Files and Sitecore)
- Scripts
- [Feature.Foundation].Name
- Folders for Module/View/Area
- Scripts
- Folders for Module/View/Area
- [Feature.Foundation].Name
- CSS/Less/SASS
- [Feature.Foundation].Name
- Folders for Module/View/Area
- CSS or SASS/LESS files
- Folders for Module/View/Area
- [Feature.Foundation].Name
- Scripts
- Mappers
- Classes that map from one type to another.
- Try to think through a fluent interface for calling
- Static Methods
- Pattern I've used, class name is MapToTargetType, methods are From(SourceType source)
- Try to think through a fluent interface for calling
- Classes that map from one type to another.
- Models
- POCO classes with light functions as needed only.
- These should mostly be ViewModels and Data Contracts
- Partials
- Any partial classes for auto generated models.
- Pipelines
- Processors that target Specific Sitecore Pipelines
- Repositories
- Classes that manage access to as Single Data Source
- Methods only concerned with a single type of data, single query or single service call.
- Implement Disposable if managing a resource (Connection) that may need to be disposed.
- Facades can call multiple repository methods,
- Views
- Feature.Name
- Cshtml Views - Should Inherit GlassView
- Web.config - set Build Action to None
- Feature.Name
- Add Additional Folders to Group Sets of Classes as Needed.
- If using TDS or generating Code from Templates, name generated should be name of Feature|Foundation project suffices with Model.cs (e.g. MyFeatureModel.cs)
- Web.config added by any services references/nuget package, but set Build Action to None.
- App_Config
General Development Best Practices
- Use Properties instead of Fields Where Possible.
- Avoid Use of Global Variables.
- Keep variable declaration close to usage. (No Pascal like initialization areas)
- Use Regions to group similar methods in larger classes
- Use Static Methods if all Methods have no need for shared State. (Should mean all class methods are static)
- Configuration Values should be managed in Configuration related Classes. Do not mix configuration with business logic.
- In general, error handling and try catch logic should be implemented in the last layer before the client. So instead of having try catches in business logic or data access classes, it should be in the Controllers, API Methods, etc. The one exception is if there is a specific exception that the business or DAL object knows how to handle, then it should do so. Do not catch an exception simply to catch an exception.
- When Catching an exception, Use Sitecore Diagnostics Log Error, and leverage the override that accepts the exception object as the second parameter. Do not customize the message with properties of the exception, but instead use the message for details about the call including any parameters being passed that could be helpful to debug (As long as params don't have PII).
Sitecore Development Best Practices
- Make Components Experience Editor Friendly (Make Editable).
- Do not render Editable Fields in HTML Tag attributes.
- Completely Configure Renderings
- Controller Renderings should use fully qualified types (with namespace and assembly name)
- All components that have data sources should be configured for Datasource Template and Data Source Location
- Use SF Data Source syntax to enable multi data source locations "e.g. /*/FolderType"
- If you need rendering parameters, create a new "Rendering Parameters Template" instead of expecting contact authors to remember what keys to use.
- Set Caching Defaults
- Add an Icon or thumbnail
- Add Custom Experience Buttons to drive configuration of fields that are not easily edited in Experience editor.
- Use Container Helper in Rendering cshtml to automatically flow Sitecore Foundation Rendering Parameters into the markup. (SF)
- Target Shared Layout when Adding Components to avoid issues with Versioning/Languages.
- Link Fields or Configuration Fields in Templates should be marked as "Shared" to avoid translations or the need for field level fallback rules.
- No more than 100 items per folder. If getting near there use Buckets.
- Search
- Do not use Sitecore Query unless searching less than 10 items
- Do not use Fast Query unless searching less than 100 items
- When in doubt, use the Content Search API.
Tooling / Recommended Packages and Guidance
- Glass Mapper
- Create Foundation Project to inject References and Boostrap it.
- Remove App_Start and Config from any project that manually adds references to it.
- TDS
- One TDS project per project
- Add one Project level project to add references to all others for creating unified projects
- Use TdsGlobal.config to set defaults for all TDS projects
- If using Gulp, Set maxcpucount: 1 to force the build to go in sequence.
- Add Project Dependencies Manually to ensure first deploy for new environments occur in correct order.
- Leverage Code Generation if working with Glass
- Use Partial Classes to enrich generated classes.
- Unicorn
- Use Foundation Project to Bootstrap and Set Basic Folder Structure that all other projects are dependent on.
- Coveo
- Add Feature/Foundation project to manage custom field configurations. Do not modify OOB configs (including custom configs). Better to use feature controlled patch files for needed areas only.
- Copy Provided Renderings and Extend Provided Component html as needed. Do not modify OOB rendering cshtml
- Use OOB Components or Customized Version of Coveo Components. Do not roll your own components leveraging the javaScript API's as they won't work properly with anlaytics, machine learning or any of the other cool features of Coveo easily.
- For Internal Search Needs avoid using Coveo API (Searching Buckets, stuff that doesn't need to drive analytics or special results), Use Lucene instead (is a little faster, and won't take from query limits if on a Cloud plan). Rule of thumb: Client Side Driven Searches use Coveo, Server Side use Lucene or SOLR
Source Control Workflow with Automated Releases
- GIT Highly Recommended with git flow. Typical Approach:
- Development Branch - Released to Dev Environment
- Each Developer Fork Developer Branch and Issue Pull Requests to and from Development Branch
- Only Tech Leads Can Approve Pull Requests from Developers into Development Branch
- Code Reviews done of Pull Requests Before Accepting
- Tech Leads Issue Pull Request from Dev Branch to Master Branch at Milestone intervals to release code for Testing
- Master Branch - Released to Staging/Test Environment
- Tech Leads Issue Pull Request from Master Branch to Release Branch at Milestone intervals to release code for Testing
- Have Test Team sign off on Pull Request
- Ops Team or Leadership should have to approve Pull Request
- Release Branch - Released to Production Environment
- Blue/Green or Odd/even rail Deployment recommended.