I have had the pleasure of working in software engineering for over 20 years and content management systems (CMS) for more than half of that. When I first began working with CMS, I immediately discovered some significant differences from more traditional engineering practices. Perhaps the most significant of these are related to the building and deployment of CMS implementations. Version control, automated build processes, and automated deployment processes are widely adopted by software development companies. However, they have not gained much traction in the CMS space. I believe this is a missed opportunity. While there are some unique challenges to getting these best practices in place, they are surmountable.
Perhaps the largest challenge to overcome is the blurry line that most CMS implementations have between content and code. In a more traditional project this line is frequently clear. Generally, code is the files on disk and the database schema, while content is the actual rows within the database. The code should be version controlled and only changed by a qualified development team following a defined and tested process. The content is not version controlled and is instead representative of the work of content creators, end users, and live feeds from external systems. Content can vary by environment, but code should be consistent.
This line is much fuzzier in the CMS world. One good example of this is how content models relate to their visual representation. While each CMS has a different name for them, all CMS are built around the idea of structured content and templates/layouts that display that structured content to end users. The content structure defines the properties that each type of content or page has, but the template/layout defines how that information is displayed. The two pieces must go together. If your structure defines properties that your template does not display, then the information will not be visible to the end user. If your templates try to display properties that are not defined in the content structure then there will be nothing to display, creating blank areas or even errors.
This makes the solution obvious that, in principle, the structure and the templates must both be version controlled so they are always in sync with each other. The practical execution of this solution is the real challenge. I’d like to share how we’ve dealt with this challenge for Umbraco, though these concepts can be applied to any modern CMS.
In Umbraco, content structure is defined by use of Document Types and Data Types. Layout is defined by use of Views and Partial Views. The types are defined using the Umbraco back office interface and stored as rows in a variety of database tables. The views are defined primarily by .cshtml files on disk, but they also have a presence in the database and should be created first using the back office. Version control for database rows is extremely challenging. While excellent tools like RedGate SQL Compare do exist, there is a better answer for our problem. uSync is a time-tested tool designed to serialize Document Types, Data Types, and other Umbraco settings to files on disk. By storing this data on disk it can easily be kept in sync with the views and stored in the version control system of your choice.
Installing uSync can be done via NuGet and should be as simple as one-click for most developers. Though there are a few default settings that should be changed.
The “Files and Folders” section is particularly important here. By default, uSync will create a nested folder structure and use item names for file names. This can be a problem in the long run as it can be difficult to reconcile items that change names or move location. By using a flat folder structure, and a Guid system we can avoid these issues. In addition, setting the system to import at startup and export on save will ensure that every environment pulls the latest settings from disk when the application starts and changes will always appear immediately on disk to prevent them from being missed.
These settings are edited in the back office of Umbraco, but they are saved to disk in a config file as well. This allows us to version control these settings and minimize the effort to move across multiple environments.
While this is a great start, it is not a complete solution. uSync will keep our types and views in sync with each other. However, without some actual content a developer will struggle to work with the solution. Unfortunately, content should not be source controlled. It is normal and expected that content editors will be making constant changes and trying to source control that would defeat the purpose of a CMS.
Our solution to this is selective use of uSync.ContentEdition. This extension to uSync allows us to serialize content as well as types so that we can store it in source control. We do not make any attempt to store all the content, and our developers don’t work with live content. Instead, we create test content that contains example implementations of each type of page and content. This test site serves as both a test bed for our developers as well as guide for the limits and controls of the content system. By creating test content that stretches the limits of the content rules we are able to ensure that our edge cases are covered, our developers are working from a common foundation, and we have some baseline documentation for proper usage of the site as implemented.
Using this test content our developers work locally to create the implementation needed. We reserve the creation and integration of real site content for remote server or servers where multiple editors can work in parallel to the ongoing development activity. In this remote environment the test content lives along side the live content without interference as pictured below. Since uSync also serializes hostname bindings we don’t have to worry about the test content getting in the way of the live content. An added side benefit is that content editors can practice on the development site to get comfortable with the framework without any fear of their changes spilling out into the real world.
With these tools in place we can easily create a project file that any developer can clone from source and run quickly. We can also ensure that any changes made are tracked and we do not run into situations where human error can lead to types and views becoming desynchronized. We have also set ourselves up to create a seamless integration and deployment process that allows for rapid deployment of changes without sacrificing security and stability. Furthermore, we have a framework that allows a team of any size to work on a given CMS implementation with all the benefits of conflict resolution and version history.