Wednesday, 9 January 2013

Features in Drupal


We do large Drupal websites. Usually you want to make it modular. So you can turn on and off certain coherent parts of it. A messaging system. A content type. A functionality. Or maybe reuse those components on other platforms. You also want it to be in code, so you have all the benefits of version tracking, quality assurance, testing and whatnot. Sounds like a dream :) I'm not trying to be a whiny kid showing my suffer - I'm rather interested what am I doing wrong here. So please don't hold your critique back.


It was a rainy day when I met Features (as part of Open Atrium). As it became a standard in our development workflow we realized more and more the practical pain side of it. Here you are my concerns.

Not everything is feature ready.

To make a feature complete leaving out certain items is just silly. The whole point of the code driven development is that you can easily apply your updates by updating (reverting) the feature on an environment.

Solution: implement the Features API or add your changes to the feature's update / install / disable / uninstall hooks. This latter one usually works fine, however only serves as a workaround. Strongarm can help to featurize your variables for example.

Features use IDs.

You save configurations and objects with their ID as a reference. The ideal implementation for this is a unique artificial name (machine name). So lookup is obvious. When it's based on auto-generated values (like vocabulary IDs) you have the risk of ID incompatibility through systems. And that can happen easily.

Solution: care about your data. Don't let anybody create those objects (such as taxonomy vocabularies) randomly. Helper modules: Features extra (helps on taxonomy and node queue), Boxes (for blocks) or Bean (even fancier blocks).

PHP array order is not determined.

Features is using a smart (but not too smart) difference analysis method to find changes in the system. Unfortunately - due to PHP - array items sometimes mixed up and Features fire a false alarm. That's not too dangerous, only a bit annoying. OCD guys like to the [default] state :)

Solution: no real solution - whenever it happens you can correct it, but it's temporary.

Semantically it's really hard to make coherent, independent features.

Some single feature-able units can relate to many features. A views can be part of a page, or a certain content type, or another semantic feature. Same with reused field instances. Sometimes the case is that you think you've found a feature - and then you have to relocate some items, and that's a real hassle or execute. Also some item's just don't make a full feature, so you start making bundled features - which is in practice really to as a why-not-put-here feature for everything.

Solution: create a company standard for feature grouping. Discover project requirements early. Don't create bundled objects, such as views with multiple (multipurpose) displays. Don't reuse fields Be very careful when reusing fields among multiple content types.

Uber-warning: a feature has a conflict.

I've never seen such a horrible merge conflict as with a feature. Since it's a code generated code you don't have an obvious resolve path. When you change a config array to a similar one it looks like 2 different colors of ink mixed together.

Solution: Always make sure you rebuild your feature when your repository is up-to-date and everything is clean. If shit hits the fan - maybe better to just re-click the config and rebuild again.

The WTF diff problem.

Sometimes Features reports [overridden] state but you really cannot get the update with a rebuild.

Solution: install the Diff module, check the report and do the changes by hand.

Favorite Features quirks:

One of my favorite nastiness was when we created one field that we had to reuse in many content types. Then we saved the field in a master feature, that was later in the alphabet to another feature which stored a content type using that field. This layout prevented the latter feature from recreation and always showed the [overridden] state.

Other funny coincidence was when some lazy feature implementation triggered revert whenever admin visited the Features admin list page. (On a site having over a million page views per day sometimes.)

If you create your features prematurely (without selecting hardly any exportables) it doesn't include the *.features.inc file. Which will miss Ctools api hook and that leads to many other problems. Always make sure that file is included from the *.module file.

Enabling a feature with a feature caused that funny incident when the referenced feature was just turned on but the orphan check noticed it's not needed so it turned off in the same PHP run.

So why we use Features - you may ask. Because it still helps more than it harms. Code driven development, ability to test components, clear (better be) upgrade path, quality assurance.

What's next? CMI baby :) Drupal 8 have an awesome new configuration management layer, but let's talk about that another time.

---

What's your experience with Features?

Peter

2 comments:

  1. "Don't reuse fields."

    It is ok now in D7, the features stores per instance settings.

    ReplyDelete
  2. That's true, you're right. However I still have no other solution for the problem than putting the inherited instance later in the alphabet. Do you have any idea?
    Thank you!

    ReplyDelete