A surprising amount of the configuration glue that holds our Drupal websites together is stored right along side all the end user-generated data that continually pours into a website's database. This is a great convenience for small sites, and really demonstrates the power of Drupal's administration. However, for projects with an ongoing development life-cycle, keeping track of what switches need to be flipped in Drupal's administrative interface during a feature launch becomes a developer's worst nightmare.
When you get several developers working together across multiple environments, it's difficult to keep track of where to find the "right" configuration. Comparing and replicating configuration changes between environments is one of the most important tasks to get right, and eyeballing these changes by hand is risky.
At Chicago's DrupalCon 2011, Dries announced that Configuration Management had been selected as one of the primary initiatives for Drupal 8. This initiative is rooted in the agile principle of Feature Driven Development, and aims to solve the problem of synchronizing custom data and configurations across environments through code. This will provide a standardized and straightforward way for site builders to group pre-defined content and configurations into functional website features.
The great news is we don't have to wait for Drupal 8 to adopt this agile strategy today. In Drupal versions 6 and 7 it is possible to put many configurations into the code so they can be tracked separately from end-user generated content stored in the production database. So, while the gurus develop a new data synchronization model for Drupal 8, just what can we do in the meantime?
Why feature-driven development?
If you already understand why, then you can skip this section and jump down to the nitty gritty explanation of what configurations can be exported to features.
One of the biggest hurdles in team-based Web development is figuring out how to synchronize configuration changes to a Drupal site between multiple environments. Each developer has a local copy of the site, then there is usually a staging site for client sign-off, and finally the changes are moved to the production site. When our clients request a change, it can involve changing different configurations on modules. In these complex project situations, it's not sustainable to change the module configurations and create content types in every environment.
On simple sites, it's easy enough to download the database, make the changes locally, test, and overwrite the database on the live site. However, on sites where content is continually being added, a snapshot of the database exported to a development machine becomes obsolete as soon as new content is generated on the production site. Some people might consider copying only specific tables that they can see have changed, and avoiding the node tables (where content is stored). TRUST ME, that will cause you a whole lotta grief. Don't do it! Wouldn't it be nice if all those configurations you spent hours tweaking could be safely exported and imported into the database without affecting live content?
So one of our primary goals on larger projects is to export as many site configurations into the code and out of the ever-changing production database as possible. With the settings in the code base, we can then employ a Version Control System like Git or Subversion to ensure that one developer's changes don't get lost or overwritten by another developer. We can then easily "push" sets of code changes between environments (eg, to a themer, or a staging server) and eventually deploy the new feature onto the production site, in many cases without even taking the site offline.
How to achieve feature-driven development in Drupal
We use Features, in concert with Strongarm and the CTools export functionality on a daily basis to facilitate code driven development. This enables us to sync changes made on developer environments to a staging server, and finally production, without the need to go into the Drupal administrative interface to reconfigure things by hand. Usually, the goal is to get every single configuration out of the database and synced into the code. So without further ado, I present the following:
Drupal site components that can and should be exported to code
Many modules use variables for storing their settings. The Strongarm module can be used to export those settings into features.
Menus items often straddle the "content" versus "configuration" divide, but in general, if they don't change daily during the normal execution of the live site, then they are usually static enough to enforce them being exported to code. The Features module has native support for exporting menu items.
Drupal 7 conveniently provides a user menu, and we almost always end up having to create the same thing in Drupal 6 sites as well. Exporting this to a feature, turns this menu into a reusable element packaged inside a small custom module. Menu definitions are exportable with the Features module.
Content type definitions & field configurations.
We always export content types as custom Features. These always have various configurations and custom fields attached, all of which are spread across a couple different places in the database. Some modules offer content-type specific configurations stored as Variables, and other modules such as Node Relationships and the BackReference module offer custom Features/CTools export integration. We usually export all these configurations together into a single feature for each content type. This requires a combination of the native Features module support, along with the Strongarm module to get the various content-type specific configurations out of Variables and into the code.
Roles & Permissions.
On sites with many modules, the Drupal permissions list becomes miles long. Multiply the length by the number of user Roles, and you end up with a really complex matrix. It's really useful to be able to make a change once, export it, and commit the change at the code level, so you don't have to try to replicate permissions matrix changes multiple times across different development environments. Having permissions in code is also very useful for security audits where changes to the permissions model on a production site can be gleaned with a single command via the command line.
Drupal 7's Image styles, and its predecessor, ImageCache for Drupal 6, are both exportable with Features.
Views require a LOT of configuration, and a LOT of clicking. Even though they do provide their own export/import functionality, on larger sites we need to ensure changes to our views get pushed to various environments, so we always export these to code.
Rules and Rules Sets.
The rules module is installed on nearly every project we work on, as they offer a quick way to handle custom business logic workflows without writing PHP code. Even though we aren't writing any code, doesn't mean its not uber-important to track rule configurations in code. I've contributed this patch required to maintain Rules export order in the code across our varying developer environments. Your patch review is welcome. ;)
This isn't necessarily related to Features, but worth mentioning here, since string overrides are usually considered "configuration", depending on your site. Many people use the aptly named String Overrides module, however, that puts string overrides into the database (not good!). Drupal has a great way to allow you to change its default interface text strings without any additional modules, so we promote getting your string overrides into a
settings.php file, or more typically in our case
sites/all/settings_shared.php (to be be discussed in a future post).
Panels: Pane Managers, Mini-panels, Panes, Stylizer styles, etc.
The Panels module was created by the CTools developer, Earl Miles (merlinofchaos on Drupal.org), and hence has CTools exportability built in.
Components that are more difficult to get into code
Drupal isn't perfect. And with multiple thousands of contributed modules, many of them are rather complex, and have no surefire way to sync configuration data to code. This is especially true where the line between content and configuration gets really muddy. The Drupal 8 Content Management initiative has sights set on solving the problem of tracking and staging content, which is great for the future of Drupal. Sadly, though, there simply isn't a good way to manage content staging at this point for Drupal 6 and 7. Here are some common modules you may use that currently don't have a Gold Standard for exporting to code:
It's still on the table whether taxonomy should be considered "content" or "configuration". In many cases its a combination of both and various modules have tried to make taxonomy terms and configurations exportable, but its wrought with the problem of uniqueness that is currently being worked on in the Drupal development world.
The NodeQueue module is another very useful module that currently has no great way to export lists of nodes to code because it is fundamentally dependent upon the fact that there is no stable solution for universally unique node identifiers.
Custom blocks, built through the Drupal's administrative UI don't have a true export mechanism. There are ways around this that do require some work, by turning your blocks into boxes, which are exportable.
If you need to export what Drupal traditionally consideres "content" to code, you should look into testing the UUID and UUID Features Integration modules.
If you're interested in following what's going on with the Drupal 8 initiative, I recommend you subscribe to the Build Systems & Change Management group on groups.drupal.org.