24 Jul 2009

Building sustainable building blocks

garfield's picture
Senior Architect and Consultant
5

At Palantir, we try to be "sustainable" in everything we do. Our office is made from mostly recycled materials and we strive for being carbon-netural. Our approach to employees is to avoid the "long hours and weekends" trap, because we don't want people to get burned out before their time. Our approach to Drupal theming is built around site sustainability, and allowing the theme to grow with the site as it evolves.

It also means building code that is sustainable. That isn't really a new concept; generally it's called "reusable code". But with how straightforward it is to bend Drupal in various ways with form alters and theme overrides, it's easy to miss a rather important little revolution in Drupal development that Palantir has embraced wholeheartedly: Sub-module building blocks.

So what does that fancy term mean? Aren't modules already the building blocks of Drupal? Well, no. Modules are just bundles of code. They are not the pieces from which you build a site, they are the providers of those pieces. And those pieces are changing.

Back in the day, Drupal sites were built around nodes. And if you wanted a node of your own with your own fields, why you just wrote a new node module. Those dark ages passed with the coming of CCK, which lets you construct a node out of "fields".

Back in the day, if one wanted to make a list of nodes, users, or something else, why you just wrote a custom page callback and a little SQL of your very own. Those dark ages passed with the coming of Views, which lets you build complex queries into your data model with a few button clicks.

Of course, this should be nothing new to the skilled Drupalista. Well of course CCK and Views are the bees knees. Every good Drupaler knows that. But how many people take it the next logical step?

I know I didn't for a long time. Want to make a given field look different? Theme overrides are easy, do that. Want to do some custom, site-specific weirdness in a listing of nodes? Make a list view, use the theme wizard, and modify the resulting theme function to taste. Easy! And also totally unportable and unreusable.

But then along comes the one-two punch of CCK 2 and Views 2, or more specifically very important API changes in both of those systems. In Drupal 6, CCK got overhauled to the point that making new fields is much easier than it used to be. New formatters are really just wrappers around the theme layer, and new widgets are just particularly advanced and complex form fragments (that use parts of the Form API that make them very difficult to form_alter). Views, which in Drupal 5 was not the easiest system to extend either, now supports "plugins" at virtually every level, and because it's object-oriented it's very straightforward to make a plugin that is just a slight change from another plugin.

Why is that important? Because now instead of overriding the theme function for a field you write a new formatter that does just what you want. It's not all that much more difficult, once you're used to it, but you get far more flexibility out of it. You can control exactly what fields use that formatter, per node type, per output type (full page, teaser, RSS, etc.). Some other modules like Composite Layout let you vary the formatter per node. And when building a view, you can select any formatter that supports that field regardless of which formatter is normally used for that field on the node.

Your theme override trick has now become a well-encapsulated, portable, flexible building block that you can reuse anywhere on your site, or on your next site, or your next 12 sites. The same applies to CCK widgets, which are the edit-form side of a field. (Although admittedly the widget API could still use work.) If you haven't seen the nodereference_url widget yet, you haven't lived.

And speaking of views, one-off overrides are so old school. Instead of building everything off of list views and custom theming, build a new style plugin. Or a display plugin. Or an argument handler. True, it's another API to learn (as if Drupal doesn't have enough already), but the result is a reusable building block that does just what you need in a clean, extensible fashion that can be mixed and matched with other reusable building blocks, both yours and someone else's. The code will be more stable, and less bug prone, too, because it's going "with the grain" of the system. And for your investment of the extra time to make a building block the first time, you are just a few button clicks away from using it the second time (assuming you made it properly configurable in the first place, which you did, right?) That lets your code grow with your site just as your sustainable theme does.

There's also that great sensation of seeing the way you put a feature together and knowing that it just feels right, and is elegant. Don't under-estimate the emotional return of elegant code.

More often than not you'll find these building blocks are or can easily be made generic enough to contribute back to the community where your one-off theme trick is not. Often times not, especially if you make a one-off CCK field (which is more useful than you'd think), but very often it can be. Consider, the CCK Formatters module, which contains several simple "plug and play" CCK formatters. Want to format a list of text fields in some way other than a series of divs? The Text Formatter module has for easy-to-use options and welcomes more submissions. Need to place a context-sensitive view on a node? You could just call views_embed_view() yourself in hook_nodeapi, or you could use the wrapper that is the component module, but it would be even better to drop in views_attach and just push buttons.

Or if you want to create a date view for totally custom periods, say seasons or academic quarters, you could hack something together with a manual "season" field or, with a little work, you can build a generic date range argument for views that requires less manual intervention and gives you more flexibility to boot. Or there's my favorite, Views Cycle, which lets you piece together an Ajax-ified image gallery using jQuery based on any Views criteria without writing any significant amount of code. Of course, it had to be written in the first place but that's the point.

Many of those modules came out of two of Palantir's recent larger sites, the Sam Fox School of Design and Visual Arts and the journal Foreign Affairs. In the case of Sam Fox, we had several site-specific crazy requirements we needed to complete. We could have just made them one off customizations, as we've done in the past, but after thinking about it we decided it would, in fact, be easier to create building blocks rather than code one-off solutions. The code itself would be easier to understand, and we could leverage CCK and Views more readily. We were right, too. Creating reusable modules was almost a side-effect, albeit a pleasant one. The net result was, for instance, portfolio pages, which stack together a Views Cycle style plugin inside a Views Attach display plugin, referencing nodes by nodereference, creating images using imagecache, and displaying individual fields using custom CCK formatters; all to create one slick-looking interface with a simple admin backend that we can now replicate on another site with almost zero additional code.

While Foreign Affairs didn't result in as many reusable bits, going the building block route allows us to offer the client a level of customization and configuration impossible with simple theme overrides. The best example is the newsletter pages. These nodes contain a large number of fields the client wanted to be able to customize per-node. Enter the Composite Layout module (not one of ours, but still highly cool), which allows a user to edit not only a node but its layout, and configure the formatter used by a given CCK field per-node. Throw in 11 new formatters (each of which is only about 4 lines of code; really, not difficult) and you have an unprecedented amount of flexibility right from the admin. No theme modifications required.

Of course, by making heavy use of building blocks you also run into the rough edges of those APIs, especially those that haven't been as heavily used. That is a good thing, because it means you can figure out where they need to be improved in the next version. In our case, we've run into two main road blocks. First, CCK widgets are still more complicated than they need to be. Second, formatters are in desperate need of configuration options. Working out a UI to support that needs to be a high priority for Drupal 7, as otherwise it requires ballooning the number of formatters with slightly different implementations. Anyone want to help out there?

Taking the time to build a sustainable building block pays off on your next site enhancement, or the next site you build, or more likely both, and it's much easier than you think. And the community gets a cool new module out of it to boot.

Comments

Amen, friend!

Drupal's evolution from "flexible community blog" to "Erector set for content-driven sites" has been fascinating to watch. I wrote about similar stuff about two years ago, and it's awesome to see how many tools are at our disposal now.

A client of ours needed some extremely tweaky dynamic pages, and after a bit of thinking we realized it could be done with just one custom Views plugin -- reusable, compartmentalized, and easy to maintain compared to the tangle of hacks and tweaks that could have been used.

Exactly!

The biggest boon of sub-module building blocks is that those little glue code bits can now be made into modules, rather than snippets in a handbook page. That makes them 10x as useful, because it makes them "reusable, compartmentalized, and easy to maintain", and easy to share and distribute. That makes the site better, and the next site easier/cheaper.

"Of course, this should be

"Of course, this should be nothing new to the skilled Drupalista. Well of course CCK and Views are the bees knees. Every good Drupaler knows that. But how many people take it the next logical step? ... Want to make a given field look different? Theme overrides are easy, do that."

That certainly pegs me!

I've been resistant to solving theme issues with reusable "sustainable" code because I simply don't know PHP at all(and I lean on my experience with Perl or other languages when I absolutely must hack some Drupal PHP code)... but this "emotional return of elegant code" you talk about does sound appealing :P I'll try to struggle through PHP and the Views/CCK APIs the next time a new feature calls for it. My whole purpose for using Drupal is a quest for learning anyway.

Nice article -- especially helps me to better understand the Drupal abstraction... "sub-module building blocks" are a new idea for me.

patrick

The new approach to Drupal

The new approach to Drupal development — The Drupal Way — which you write about, has truly revolutionized our work at NodeOne. For instance, it made it possible for us to build Sony-Ericsson Labs on Drupal with only 162 hours of development. Something we hope to talk more about at DrupalCon Paris.

However, it seems to me that far from all Drupal developer yet understand this new paradigm of Drupal development. Your blog post is therefore very important.

I took the liberty to submit it to Digg and DZone.

inspired

And I thought using .tpls to customize my views/cck node output was the Drupal way :) I know that it is at least better than some developers we've contracted who stare blankly at a design comp, scratch their head and then say "I guess we could rearrange everything with jQuery."

There's still a lot of evangelizing to do in the community and part of that has to happen via documentation. I know that the biggest barrier to writing my own formatters, widgets, and style and display plug-ins is that I would expect to bumble around looking for docs and blog posts and then have to run my own experiments.

But this post has inspired me. Awesome.