[antipattern] Write Everything Twice (WET) (because "we enjoy typing")

HOT TIP: this content is flagged as highly recommended !
Keywords
Wikipedia quotes

In software engineering, don't repeat yourself (DRY) is a principle of software development aimed at reducing repetition of information of all kinds, especially useful in multi-tier architectures. The DRY principle is stated as "Every piece of knowledge must have a single, unambiguous, authoritative representation within a system." ..

..

DRY vs WET solution

Violations of DRY are typically referred to as WET solutions, which is commonly taken to stand for either "write everything twice", "we enjoy typing" or "waste everyone's time".

Source: Wikipedia: Don't repeat yourself, DRY vs WET solutions Version date: 2016-04-21

PLEASE READ TOP-TO-BOTTOM: This is an example of Writing Everything Twice (WET) code in typical Drupal-style, taken from the Current posts module example at Creating modules - a tutorial: Drupal 7.x:

/**
 * Custom page callback function, declared in current_posts_menu().
 */
function _current_posts_page() {
  $result = current_posts_contents('page');
  //Array to contain items for the block to render.
  $items = array();
  //Iterate over the resultset and format as links.
  foreach ($result as $node){
    $items[] = array(
    'data' => l($node->title, 'node/' . $node->nid),
    ); 
  }
 
  if (empty($items)) { //No content in the last week.
    $page_array['current_posts_arguments'] = array(
      //Title serves as page subtitle
      '#title' => t('All posts from the last week'),
      '#markup' => t('No posts available.'),
    );
    return $page_array;  
  } 
  else {
    $page_array['current_posts_arguments'] = array(
      '#title' => t('All posts from the last week'),
      '#items' => $items,
      //Theme function includes theme hook suggestion.
      '#theme' => 'item_list__current_posts', 
    );
    return $page_array;
  }
}

Let's start with the #title, which in both cases is:

'All posts from the last week'

It SHOULD be encapsulated, no excuses, so that if it is changed in one place it changes in all places, respecting the Don't Repeat Yourself (DRY Principle). We wouldn't want to use "search and replace" programming now would we ! This one is easy, simply use a common $title var:

 $title = 'All posts from the last week';
  if (empty($items)) { //No content in the last week.
    $page_array['current_posts_arguments'] = array(
      //Title serves as page subtitle
      '#title' => t($title),
      '#markup' => t('No posts available.'),
    );
    return $page_array;  
  } 
  else {
    $page_array['current_posts_arguments'] = array(
      '#title' => t($title),
      '#items' => $items,
      //Theme function includes theme hook suggestion.
      '#theme' => 'item_list__current_posts', 
    );
    return $page_array;
  }

But in fact, this code - like nearly of Drupal6, Drupal7 and to my great distress too often still Drupal8, is fairly riddled with WET code, because, despite progress towards object-orientation, Drupal still uses many structured arrays with mere key conventions, and the keys are repeated all over the place !

Let's tackle first 'current_posts_arguments', the key for $page_array. What happens if the module name is changed ? Would you perform "search and replace" through possibly more than one file ?

Or would you use a strategy that most programmers learn in kindergarten, namely encapsulating the parts that could vary yet are repeated in error prone fashion. Ahem.

There are lots of ways to do it, one way is to use a define() (later, in the tutorials for the OOE module we will see how we could also use PHP classes to encapsulate such things as organised constants):

define('MODULE','current_posts');

Now in the complete Current posts example module (which is available for download via this sandbox project) the string 'current_posts' occurs 32 times !. That's an awful lot of WET code:

  1. Many of those repeated occurrences of 'current_posts' are due to the drupal hook-by-convention system - which completely drives me up the wall jr-banghead.gif, and COULD (well, I really mean SHOULD sometime this century) easily be completely replaced by a simple interface registration pattern, so that one does not have to repeat the hook name and repeat the hook name and repeat the hook name and repeat the hook name which is all just one module name which is what classes with methods are for. Doh !
  2. Many of the repeated occurrences of 'current_posts' are either array keys or parts of array keys; these ones can be easily replaced with the MODULE constant definition, meaning the code can also (as a natural benefit of more DRY coding) easily be reused in modules of other names, simply by redefining the MODULE constant in one place (in accordance with the DRY principle)

Like this:

 
  $key = MODULE . '_arguments';//key is used twice below so encapsulate this as well !
  if (empty($items)) { //No content in the last week.
    $page_array[$key] = array(
      //Title serves as page subtitle
      '#title' => t($title),
      '#markup' => t('No posts available.'),
    );
    return $page_array;  
  } 
  else {
    $page_array[$key] = array(
      '#title' => t($title),
      '#items' => $items,
      //Theme function includes theme hook suggestion.
      '#theme' => 'item_list__' . MODULE, //Encapsulates a Drupal convention in a reusable way !
    );
    return $page_array;
  }
In fact, thanks to encapsulation of the module name, we could gain even more reuse from this code snippet by "injecting" the module name as a parameter into a highly reusable piece of function or method code (rather than a less flexible define() of MODULE) yielding code that could be used by many modules. That's the power of DRY !

There are still however even in this code snippet a few glaring bits of WET code, and some more subtle ones:

  1. '#title' is yet another magical Drupal array key convention, and clearly repeated within this code snippet. It COULD (ok, let's not hesitate, it SHOULD) be encapsulated somehow, somewhere, in an intelligent fashion, instead of just being stated in the docs, where no IDE can enforce it. (And the OOE = Object Oriented Examples = One Of Each module shows exactly how easy it is.)
  2. The array keys ''#items' and "#theme" may not be repeated in this small code snippet, but you can bet your life they are repeated lots in a typical WET Drupal project ! That's because the only way of enforcing the conventions for the structured array is, well, repeating the same strings over and over and over (and we certainly can't ask an IDE for much prompting help here yet).
  3. The 'item_list__' (note the tricky double underscore convention for default theming implementation override suggestions) part of the value of '#theme' is not only a convention, it is a convention that is bound to '#theme' by ... Drupal magic dust !

So what happens if the array key convention changed ? Oops, stuck. Doh !

What happens if the array key is mistyped ? Oops, compiler does not see or care (and no IDE can know or care either, let alone offer valid keys via intelligent editor prompting). Doh !

And where does 'item_list__' come from anyway ? Can't ask the IDE for help here, guess I'll have to .. stop coding and read the Drupal docs for this, which are where ? Doh ! It's yet another a tricky method-name Drupal convention thingy.

There are at least obvious ways to begin to address these major shortcomings of typical Drupal coding style:

  1. Encapsulate the keys as consts in say dedicated classes, merely to organise the keys, as a first step. This already admits a high degree of consistency, and supports prompting in IDEs, both huge advantages.
  2. Use objects (instances of classes with properties and methods) like most people who code in the 21st century would (and as soon as possible if PHP offered classes and robust OOP support, which it does, and has for many years already).

Of course, best would be to replace the $page_array "by convention" with classes completely, however as an interim solution, we can just have classes that are able to still talk to sleepy-old-Drupal core by building say a $page_array for us, while encapsulating all of the sleepy-old Drupal structured array conventions with "21st century" object-oriented intelligence and design patterns .. techniques which were of course already well known to nearly every C++ and Java programmer last century. And PHP can now handle this easily.

That is what this site, and the tutorial module OOE = Object Oriented Examples = One Of Each, are all about. Drupal is far too WET !
Visit also