How to Enable Ubercart Product Image Zoom with Gallery Thumbnails

In my experience, ecommerce websites are their own beasts, with all sorts of specialized functionality that doesn’t get requested on other websites. One of the most frequent requests, and often times one of the most difficult to fulfill, is enabling product image zoom functionality along with gallery thumbnails that can seamlessly swap out the main image. Here is one way to accomplish that on a Drupal 6 website with Ubercart.

  1. Install the necessary modules. For this solution, you’re going to need CCK, ImageField, ImageCache, and Cloud Zoom (I used to prefer jQZoom, but found it to have less compatibility in WebKit browsers).
  2. Set up your image field. The code provided below is designed to work with the default image handling field creating by Ubercart, but it can work just as well with any CCK image field. Just be sure to swap out the $node->field_image_cache variable with the name of your own field if you’re using something different.
  3. Set up your ImageCache presets. You’re going to need three. Again, the solution below is tailored for use with product images in Ubercart, so I’ve named them accordingly. “product_full” is the main image displayed to the user, “product_zoom” is the larger image shown in the zoom window, and “product_thumbnail” is the gallery thumbnail that allows the user to swap out the main image. You can name these whatever you like; just be sure to change their names in the code as well.
  4. Stop the field from displaying. By default, Cloud Zoom can automatically display the image and zoom window without any need to mess with template files. This is very handy, but it doesn’t support gallery thumbnails, so we’ll need to disable the default behavior. Go into Administer > Content Management > Content Types > Manage fields > Display fields and change the Label, Teaser, and Full node drop-downs for your image field to . Be sure not to click the Exclude boxes, or else the template modifications below will not work properly.
  5. Add this code to your theme file. In the case of Ubercart, this goes in node-product.tpl.php where you’d like the images to appear. If you’re using a different content type, use that in place of product. And again, be sure to switch out the image field variable name or the ImageCache preset names if you’re using something different.

    &lt;?php<br /><br />
    drupal_add_js(drupal_get_path('module', 'cloud_zoom') . '/cloud-zoom/cloud-zoom.1.0.2.min.js');<br />
    drupal_add_css(drupal_get_path('module', 'cloud_zoom') . '/cloud-zoom/cloud-zoom.css');<br />
    if (is_array($node-&gt;field_image_cache) && count($node-&gt;field_image_cache) &gt; 0 && strlen($node-&gt;field_image_cache[0]) &gt; 0){<br /><br />
      // Display the primary image.<br />
      echo l(theme('imagecache', 'product_full', $node-&gt;field_image_cache[0]['filepath'], $node-&gt;field_image_cache[0]['data']['alt'], $node-&gt;field_image_cache[0]['data']['title']), imagecache_create_path('product_zoom', $node-&gt;field_image_cache[0]['filepath']), array('attributes' =&gt; array('class' =&gt; 'cloud-zoom', 'id' =&gt; 'zoom1'), 'html' =&gt; TRUE));<br /><br />
      // Display the gallery thumbnails.<br />
      $num_images = count($node-&gt;field_image_cache);<br />
      if ($num_images &gt; 1){<br />
        for ($i = 0; $i &lt; $num_images; $i++){<br />
          echo '&lt;a class="cloud-zoom-gallery" href="' . base_path() . imagecache_create_path('product_zoom', $node-&gt;field_image_cache[$i]['filepath']) . '" rel="useZoom:\'zoom1\', smallImage:\'' . base_path() . imagecache_create_path('product_full', base_path() . $node-&gt;field_image_cache[$i]['filepath']) . '\'"&gt;' . theme('imagecache', 'product_thumbnail', $node-&gt;field_image_cache[$i]['filepath']) . '&lt;/a&gt;';<br />
        }<br />
      }<br />
    }<br /><br />
  6. Stylize to taste. With a bit of added coding and some CSS, you can make the final product display however you like. For example, I like to put the gallery thumbnails into an unordered list and float them beneath the main image for ease of usability. Your needs may vary.

How to Add Variations to a Drupal Theme

Recently, I did work for a few clients who needed several very similar websites launched in a single project, each of which using an almost identical (yet subtly different) theme. As I started configuring them on Drupal multi-site installations, it got me thinking: Is there a way to take advantage of the same sort of code reuse within a theme?

There are already options for this, of course, such as sub-themes or the Color module. In my case, however, I decided to try something a little different: I used a custom theme setting to add a CSS class to the body tag, then created the theme variations with pure CSS. Here’s how I did it.

Step One: Set Up the Advanced Theme Setting

In case you’re a Drupal themer who doesn’t know this trick, it’s a life-saver. You can configure your theme with a form to collect custom settings, then use those settings in the theme itself. I like to use this for things like phone numbers that don’t deserve their own block region but need to be configurable by the client nonetheless.

There’s a great Drupal article on advanced theme settings, which I won’t bother repeating. As far as theme variants go, all you have to do is include the following code in the theme_settings.php file of your theme folder:


function themename_settings($saved_settings){
$defaults = array(
'variant' =&gt; 'default'
$settings = array_merge($defaults, $saved_settings);

$form['variant'] = array(
'#title' =&gt; t('Variant'),
'#type' =&gt; 'select',
'#default_value' =&gt; array($settings['variant']),
'#options' =&gt; array(
'default' =&gt; 'Default',
'variant_1' =&gt; 'Variant #1',
'variant_2' =&gt; 'Variant #2',
'variant_3' =&gt; 'Variant #3'

 return $form;

This will create a drop-down selection menu on your theme configuration page that allows you to select the desired variant. Be sure to change the keys and values in the #options array to include the CSS class and variant names you want.

Step Two: Hook the Variant Setting into the Template Files

Now that the variant can be defined, it’s time to dynamically include it in your template files. This is accomplished with the theme_get_setting() function. Include the following code at the top of your page.tpl.php file (and any other relevant template files):

$variant = theme_get_setting('variant');
if ($variant == 'default'){

Then, on the body tag in each template, include code to insert the variant as a CSS class:

&lt;body&lt;?php echo ($variant) ? ' class=" . $variant . "' : ''; ?&gt;&gt;

If you want, you can do other useful things with the $variant variable. For example, I took it a step farther and created image subfolders at theme_folder/images/$variant. That way, if I had images that needed to vary, all I had to do was name the images the same and include $variant in the image src attribute.

Step Three: Add CSS to Customize Each Variant

Once the body is being classed according to the theme variant setting, you can do whatever you like to customize each variant. Simply add CSS to your style.css file in order to tweak the theme’s appearance according to the new body class. For example, you might adjust the font face and color of each variant:

#content { color:#000; font-family:Arial; }
.variant_1 #content { color:#F00; font-family:Helvetica; }
.variant_2 #content { color:#00F; font-family:Verdana; }

Possible Uses

The main use of this technique is to provide a fast, easy way to create minor variations in a single Drupal theme. You might add some seasonal stylization for a holiday variant, for example. Or, as in my case, you might have a few small differences between sites using the same theme and want to keep a common code base for ease of maintenance.

Anything more than that and you’re probably better off using one of the aforementioned techniques, such as sub-theming or the Color module. It’s really just a matter of how different your variations are going to be.

Attach Files to Taxonomy Terms in Drupal

From what I can tell, there are plenty of ways to attach files to nodes in Drupal, and even a few ways to attach them to users, but none that I could find to attach them to taxonomy terms (images through the Taxonomy Image module, for sure, but not files in general). My guess is that there just aren’t enough people who need to do so.

In a recent project, however, I found myself needing just that. The client in question was using a vocabulary of fonts that had to be associated with their respective font files for JavaScript. After beating my head against the problem for awhile, I managed to figure out a solution. Instead of attaching a file directly to the taxonomy term, I assigned the same vocabulary to a new content type to hold the attachment. Here’s how it works:

  1. Go to Administer > Site building > Modules and make sure the core Taxonomy and Upload modules are enabled.
  2. Go to Administer > Content management > Content types and click the link at the bottom to Add a new content type.
  3. Give your new content type an intuitive name (e.g., Font File) and enable attachments under Workflow settings. Configure the other settings as you see fit and hit Save.
  4. Go to Administer > Content management > Taxonomy and edit the vocabulary for which the file attachments are intended (e.g., Fonts). Check the box next to your new content type and click Save.

Great! Now you have a way of associating a term with a file, albeit indirectly through a node. How you use that information will, of course, vary. In my case, the font files needed to be populated into a drop-down list of font choices for use by JavaScript. Here’s how you might go about accessing the attachment from the database:


// Fetch the file path of the most recently uploaded file attached to a node that shares the given term
$attachment_path = db_result(db_query("

SELECT filepath FROM {files} f JOIN {upload} u ON f.fid = u.fid JOIN {node} n ON u.vid = n.vid JOIN {term_node} tn ON n.vid = tn.vid WHERE n.type = '%s' AND tn.tid = %d ORDER BY f.timestamp DESC LIMIT 1



Of course, the best solution would be to create a custom module to handle all of this. In my case, there simply wasn’t enough time for that. I invite some enterprising developer to invalidate my technique by creating a module that allows file attachments on taxonomy terms. Until then, I hope someone finds my roundabout hack useful.

Selectable Items per Page Hack for Drupal 6 Views

I’m sure regular contributors to Drupal will cringe at what I’m about to show you, but I found it to be a handy trick. Let’s say you’re using the Views module in Drupal 6 and you want a way to dynamically control the number of items listed in a view. In my case, a client I was working for wanted to be able to select the number of products displayed per page.

Reasonable request, right? Unfortunately, Views doesn’t handle it out of the box. After a bit of fiddling, I managed to come up with the following hack. Mind you, I use the term “hack” here literally; you should never edit a module like this if you can avoid it, if only because it makes updates painful later on.

The operative code is in the pre_execute() function on line 1795 of modules/plugins/ It normally looks like this:


As the name suggests, anything you feed to this function will set the number of items displayed by the view. In my case, I wanted to use a URL variable coupled with a drop-down menu and some jQuery to toggle it, so I changed it like so:

$this-&gt;view-&gt;set_items_per_page((($_GET['items-per-page'] &gt; 0) ? $_GET['items-per-page'] : $this-&gt;get_option('items_per_page')));

Voila! One line of code and you’re off to the races. Type ‘?items-per-page=X’ into the URL (with X being a number, of course) and it should work like a charm. The pagination even follows suit.

For those who want the full solution, here’s the code for the drop-down menu. You’ll need to add it to a view-specific template file. Just follow the pattern to create your own items per page options.

&lt;?php $items_per_page_override = ($_GET['items-per-page'] &gt; 0) ? $_GET['items-per-page'] : 12; ?&gt;
&lt;div id="items-per-page-selector"&gt;&lt;strong&gt;Items per Page:&lt;/strong&gt; &lt;select&gt;
&lt;option value="12"&lt;?php echo ($items_per_page_override == 12) ? ' selected="selected"' : ''; ?&gt;&gt;12&lt;/option&gt;
&lt;option value="18"&lt;?php echo ($items_per_page_override == 18) ? ' selected="selected"' : ''; ?&gt;&gt;18&lt;/option&gt;
&lt;option value="24"&lt;?php echo ($items_per_page_override == 24) ? ' selected="selected"' : ''; ?&gt;&gt;24&lt;/option&gt;
&lt;option value="9999"&lt;?php echo ($items_per_page_override == 9999) ? ' selected="selected"' : ''; ?&gt;&gt;All&lt;/option&gt;

And here is the jQuery that controls the behavior of the drop-down menu.

$('#items-per-page-selector select').change(function(){
window.location = '?items-per-page=' + $(this).val();

How to Hotwire WordPress in 7 Steps

First, let me go ahead and set the right expectation for this article. This is a brief guide to gaining legitimate access to a WordPress site for which you do not know the username or password. This is NOT a guide on hacking a WordPress site.

It’s a fine line, but there are legitimate reasons for needing to hotwire WordPress. For example, the client who owns the site may not be available to provide the username and password, or a hacker may have locked you out. Personally, when I need to get into a client site, I find hotwiring is sometimes faster than digging up the password myself and waiting on someone else to find it for me. The point is, there are good, honest reasons to do it.

Now that you’ve listened to my lengthy disclaimer, we can get down business.

  1. Access the database. Most web hosts nowadays offer PHPMyAdmin, which I recommend using. If you don’t know the database credentials, you can get them from the wp-config.php file in the WordPress root directory.
  2. Find the users table. Don’t forget that it might have a prefix; if there’s any confusion, the prefix should also be in wp-config.php.
  3. Find the account you want to hotwire. In my experience, the first user is most often the administrator with all of the best privileges, so that’s the row you’ll want to change. If the user_login is “admin,” like it is in most default WordPress installations, you may want to make a note to discuss changing it as a security precaution, but that’s a different article.
  4. Copy the old user_pass. See that gobbledygook in the user_pass field? Copy it and save it for later. Otherwise, you won’t be able to restore the previous password. In the event that you’re changing the password permanently, it’s not necessary to copy the original value, but that would be more like hijacking that hotwiring. 😉
  5. Insert your temporary user_pass. You’ll want to place an md5-encrypted version of the temporary password you’ll be using in place of the old user_pass. There are plenty of websites out there that can hash it for you; just plug “md5 encrypter” into Google. Put the md5 hash value into the user_pass field and save your changes.
  6. Log into WordPress. You should now be able to log in normally using the username of the account you’re hotwiring and the temporary password that you encrypted.
  7. Restore the old user_pass. Most people don’t like having their passwords changed arbitrarily, so it’s good form to change it back for them. To do this, repeat steps one through three and replace the user_pass field with the original value that you overwrote.

WYSIWYR: What You See is What You Regret

Once upon a time much earlier in my career, a coworker observed me composing code in a basic text editor and described the approach as, “Spartan.” I argued that my argument was cleaner, leaner, and all together better. My coworker argued that WYSIWYG code was more convenient and efficient.

In the time since, I’ve progressed in my choice of web editors; nowadays, I usually stick to Adobe Dreamweaver to get the job done. Despite Dreamweaver’s code-generating capabilities, however, I generally stick to code view and never allow it to do more than fill in some end tags. With all the modern amenities at my disposal, I still practice Spartan coding.

Why? Because I recognize that the convenience of WYSIWYG comes at a high price. Don’t believe me? Consider a few of the following points and see if you feel the same about your beloved WYSIWYG editors afterward.

  • WYSIWYG editors makes you lazy. Web professionals may not be athletes, but that doesn’t mean we don’t need to practice to stay on top of our game. Coding by hand might seem more difficult, but, much like PHP’s white screen of death, it helps keep you sharp. With WYSIWYG, you’re actually wasting time and effort to increase your expertise with a program rather than the code that’s your livelihood.
  • WYSIWYG code is bloated. Try to export a Word document as a web page some time and see what the code looks like. It’s ripe with repetitive font tags and arbitrary classes that add unnecessary size to the document. Don’t think size is important in the age of high-speed internet? Tell that to visitor using a cell phone.
  • WYSIWYG code is hard to maintain. As far as the browser and the user are concerned, things like indentation and tag casing aren’t a big deal. However, it’s hardly a courteous way to code. Somebody will have to come along and maintain your code at some point in the future. Hand-crafted code will make the job easier; auto-generated code will make it harder.
  • WYSIWYG code isn’t up to design standards. Nowadays, using tables for layout is a cardinal sin, but that’s exactly what you’ll get when you use the Adobe Photoshop slice tool. The bottom line is, if you want to produce rich, standards-compliant code, WYSIWYG is not the way to do it.
  • WYSIWYG code isn’t necessarily more efficient. As Andy Clark points out in his book, Transcending CSS: The Fine Art of Web Design, taking the time to develop meaningful, well-structured code makes it highly reusable, which can drastically increase your long-term efficiency.

Shiver Me Timbers! jQuery Off the Starboard Bow!

Before you get confused, no, jQuery doesn’t have anything to do with pirates (at least, not that I’m aware of). In honor of International Talk Like a Pirate Day, I’ll be interspersing this post with random, distracting, inappropriate pirate jargon. Don’t blame me; blame the guys who started the meme. 😉

I’ve never been a big fan of JavaScript. Like many developers, I use it when absolutely necessary (AJAX, form validation, DOM scripting, etc.) and avoid it in favor of server-side scripting solutions the rest of the time. This saves me the hassle of writing JavaScript that is cross-browser compatible, a feat which is often more troublesome than getting CSS to behave in Internet Explorer.

That was before I got a hold of jQuery. In case you’ve never heard of it, jQuery is an open source JavaScript library that simplifies most DOM scripting tasks. I won’t go into detail on its virtues here; if you’re curious about the specifics, I encourage you to check out the jQuery website. Instead, I’ll show you just how I used it to spruce up the starboard side of the site by walking through the contents of my scripts.js file.

// Custom jQuery interaction layer for by Stephen Ward



Most languages have boilerplate code, and jQuery is no different. This is just the part that says, “Weigh anchor when the page is loaded and ready to manipulate.”
// Toggle search prompt
$search_box = $('#s');
  if ($search_box.val() == 'search this site...')
  if ($search_box.val() == '')
      $search_box.val('search this site...');

Here, we see a few lines of code that toggle the “search this site…” prompt in the search box. I hate having to delete default text like this, so I made it so nobody has to. This used to be accomplished with much less in-line JavaScript, so, at first, it might seem like a bad example of jQuery’s seaworthiness. However, when you consider that the interaction logic is now completely removed from the semantic HTML without complicated selector and event binding functions, it’s pretty obvious how useful jQuery can be. It’s the holy trinity, the separation of content (HTML), presentation (CSS), and interaction (JS) with minimal effort.
// Set default menu states
expanded = $('li.expanded &gt; h2');
expanded.css('cursor', 'pointer');
jQuery.each(expanded, function(){
  $(this).text('- ' + $(this).text());
collapsed = $('li.collapsed &gt; h2');
collapsed.css('cursor', 'pointer').next('ul').css('display', 'none');
jQuery.each(collapsed, function(){
  $(this).text('+ ' + $(this).text());

// Switch menu states when the menu headers are clicked
$('li.toggleable &gt; h2').click(function(){
  menu_header = $(this);'ul').slideToggle('normal');
  if (menu_header.text().substring(0, 2) == '+ ')
    menu_header.text('- ' + menu_header.text().substring(2));
  else if (menu_header.text().substring(0, 2) == '- ')
    menu_header.text('+ ' + menu_header.text().substring(2));

Did I need collapsible menus for Ward on the Web? No, but I thought it would be a fun exercise to make them anyway. Here, you see the code that does it. Again, notice how easily jQuery lets me select HTML elements for manipulation. All I had to do was assign the “toggleable” class to designate a collapsible menu, along with either the “expanded” or “collapsed” class to designate its default state; a few simple jQuery selectors did the rest. This is especially handy in case I decide to add more menus later.

The visual effect is, of course, stunning. Collapsible menus come in many varieties; I programmed a very simple, in-line script for Simon over at Bloggasm that toggles the display state without animation. However, jQuery’s “slideToggle” function blows it out of the water with smooth, organic transitions. Note that most of the above code toggles the plus and minus signs in front of the menu headers; I could have accomplished the collapsing menu effect with two lines of jQuery code.

Perhaps the most important part of all is what the menu looks like without the jQuery interaction layer. All of the CSS and content changes that have to do with collapsing the menus are isolated in the JavaScript. When it’s turned off, they revert to normal, non-collapsible menus. In other words, it degrades perfectly.

Overall, I’d say jQuery is a great tool that makes writing cross-brower-compliant JavaScript much simpler. Beyond that, its main benefit lies in simplifying the separation of interaction from content. No more in-line scripting; now your program logic can be just as extensible and maintainable as your CSS. Granted, I’ve still got a lot to learn about it; the above code could probably be accomplished in fewer lines by a more experienced scallywag. Still, it’s been a pleasure to discover jQuery for the first time. I only wish I had found it sooner.

Debugging Syntax Errors in PHP

PHP is unforgiving of syntax errors. Misplaced a semicolon? White screen of death. Mismatched your single and double quotes? White screen of death. Considering a career in Ruby on Rails? White screen of death.

Okay, maybe not the last one, but you get the point. Unless you beg and plead with it to output errors, PHP will give you the computing equivalent of a blank stare. Even if you do get it to report the problem, because of the nature of syntax errors, the line it specifies will rarely be correct.

In my experience, there are two surefire ways to weed out pesky syntax errors in PHP.

Sequential Commenting

Proper programming is supposed to involve a step-by-step process of adding and testing small portions of code in sequence. If you do this properly, any problems can easily be attributed to the most recently added block of code and subsequently fixed.

Of course, any good developer knows that “proper” programming is an anomaly. So what do you do when you’ve written 517 lines of new code and encounter the white screen of death? Simple. Comment it all out, then uncomment and test small portions of it sequentially like you should have from the start. You get pretty much the same effect, albeit at slightly less efficiency.

Execution Counter

PHP will generally cease execution at the first point where it encounters a syntax error. By placing the following line of code at regular intervals throughout a broken program, you can use that fact to your advantage and quickly narrow down the problem.

For example, assume that you placed five counters like this throughout your code, and the final output is, “123.” Because the fourth counter failed to execute, you can safely assume that the problem occurred between it and the third counter.

Of course, you could just use a utility such as Dreamweaver or Eclipse that makes syntax errors much more obvious. Then again, what would be the point of programming in PHP without the challenge of guessing what went wrong? 😉

Output a Snapshot of All Defined Variables in PHP

The following line of code is one of the most useful diagnostic tricks in my PHP coding arsenal:

’; print_r(get_defined_vars()); echo ‘’; ?>

Simply input the above snippet of code into any PHP file and you’ll get a browser-friendly snapshot of all variables defined in the current scope. This is especially handy in larger systems like WordPress or Smarty where a needed value may already be defined by the system but you have no way of knowing the variable’s name.

With a slight variation, you can even use this trick on live systems without alerting ordinary users to the output.

’; ?>

This will produce the same output but limit its visibility to those viewing the source code.

In either case, be sure not to leave code like this active for longer than necessary, since a hacker could potentially use it to exploit your website.

Do any of you PHP coders out there have some similarly useful debugging tricks to share with the rest of us?

7 Keys to Courteous Coding

Clean, readable code adds value

All too often in my professional career, I’ve been tasked with working on legacy code. For those of you unfamiliar with the term, “legacy” in the computing sense refers to old software that has been passed down. Often, legacy programs work just well enough to keep, but not well enough that they don’t require maintenance. Thus, the same code often gets handed down to a company’s next generation of programmers, who must then figure out what it does and how to perform updates without breaking it.

Unfortunately, many developers don’t program in a courteous manner. Courteous coding is the practice of leaving cues about your code to help the next person who works on it. He or she can then spend more time programming and less time deciphering your program logic.

It’s more than just professional courtesy, though. Coding standards are important from a business standpoint because, as the folks at Sun put it, “80% of the lifetime cost of a piece of software goes to maintenance,” and, “Hardly any software is maintained for its whole life by the original author.” By making your programs easier to read and understand, you increase their long-term value.

Whether you’re a developer or you employ them, then, it’s worthwhile to know these seven keys to courteous coding.

  1. Use meaningful names. File, variable, class, and function names are only as instructive as you make them. Ideally, they should accurately but succinctly describe the information being stored. Using names like “$temp” and “script.php” leaves the next programmer in the dark as to the intended purpose of your work.
  2. Leave meaningful comments. Every modern-day programming language gives developers the ability to comment out areas of code that are removed from the flow of execution. Naturally, comments are often used to debug and deactivate code. However, it’s worth noting that they’re called “comments” for a reason. Be sure to use them for their intended purpose. Leave notes for the next programmer explaining how your code works and they won’t have to do as much guesswork.
  3. Sign, date, and describe your program. In the same vein as leaving comments, it’s often useful to leave details of when the program was written, by whom, and for what purpose at the top of the file. Much like other comments, this helps the next programmer put your code into context. Also, if you’re still available to the company, he or she knows who to ask for help if needed.
  4. Use a standard casing convention. Exactly what casing convention you use is a matter of personal preference. For example, you might make all of your variables lower case, while “camel casing” all your functions and methods (i.e., capitalizing the first character of every word but the first). This enhances your code’s readability. Whatever convention you choose, however, any enhanced readability will be lost if you break from it, so be sure to case with consistency.
  5. Use proper spacing and indentation. Language interpreters and compilers strip out white space, so things like line breaks, spaces, and indentation are largely just tools for human understanding. Use them liberally and consistently. Add spacing around things like conditionals and variable declarations. Indent blocks of code once for each block. If you arrange your code neatly, the next developer will thank you for it.
  6. Maintain clean code. Even if you use proper spacing and indentation, your program may be difficult to read due to large amounts of clutter. Once development is complete, be sure to go back and delete unnecessary elements. Things to remove include repetitive declarations, output statements used for testing, and commented code that is no longer useful to keep around.  (Note: Jesse over at The Future of the Web recently clued me in to the term “code refactoring”, which describes the practice of cleaning up your code for future use.)
  7. Provide documentation when necessary. Particularly large programs can become labyrinthine in their complexity. Documentation is the road map that leads users and programmers through it safely. If your code is complicated enough to require it, take the extra time to write out its usage and function.