The DRY Principle is more than avoiding duplicate code.

The craft of software engineering has changed a great deal in the last couple of decades, but Hunt & Thomas’s advice from 1999 is timeless:

Every piece of knowledge must have a single, unambiguous, authoritative representation within a system.

The DRY Principle (Don’t Repeat Yourself), as this is called, is like the Golden Rule: it has endless and varied applications and is — all by itself — enough to make you a Very Good Person.

You might think the DRY Principle comes down to not writing “duplicate code,” but there’s a lot more to it than that. In the next several posts, I will show how the DRY Principle is everywhere, in guises both large and small.

To whet your appetite, here’s a code snippet based on a pattern I have seen many times. Imagine that it’s part of a user object which contains an array of authorization groups.

this.isAdministrator = function() {
    if (this.groups.includes("administrator")) {
        return true;
    } else {
        return false;
    }
}

What could possibly be wrong with that? Doesn’t it beautifully encapsulate, in one DRY place, how to tell whether the user is an administrator? It’s much better than littering the code base with multiple if (user.groups.includes("administrator")) tests, isn’t it?

Yes it is, but thinking about the DRY Principle allows us to make this code more reliable in at least three ways.

Repetition of Intent

First, the idea that the function makes a Boolean determination according to the user’s group membership appears three times: in the if statement, and then in each return statement. Why ask a true-or-false question and then return true or false according to the answer? So here’s the first improvement:

this.isAdministrator = function() {
    return this.groups.includes("administrator");
}

Already we have reduced the body of the function from three code lines to one, while also reducing complexity. The code is more reliable because there’s less of it — fewer places to go wrong.

Repetition of a Special Value

Second, the string "administrator" surely occurs elsewhere in the program, such as when a user is made a member of that group. What if it’s misspelled in one of them? It should be part of an enumerated set of valid values that are stored in one DRY place, perhaps like this:

var groupNames = {
    admin: "administrator",
    guest: "guest"
};

So now we can do this:

this.isAdministrator = function() {
    return this.groups.includes(groupNames.admin);
}

(“But what if someone misspells a property name?” you ask. We’ll get to that.)

Repetition of the Choice of Data Structure

We’re still not done. The “piece of knowledge” that a collection of group names is best represented as an array of strings is doubtless scattered across the application.

What if the number of groups increases to the point where it is no longer efficient to iterate through an array in order to find one? (This may sound far-fetched, but in my day job we experienced exactly this problem.) Multiple places will have to be changed. By the way, this design mistake is called Primitive Obsession or Missing Abstraction.

There should really be a separate object that encapsulates the notion of “a collection of groups.” That way, if a different data structure becomes appropriate, there’s only one place to change it. Without getting into the details of the groupCollection object, we are now down to this:

this.isAdministrator = function() {
    return this.groupCollection.hasGroupOfName(groupNames.admin);
}

The function hasGroupOfName can even guard against a developer misspelling the property (e.g., groupNames.amdin) by verifying that the incoming value is not undefined.

Summary

Most developers think that they have adhered to the Don’t Repeat Yourself Principle if they avoid repeating blocks of code. In this short post, we have identified and fixed three DRY violations that go beyond that simplistic understanding:

  • There was repetition of intent where the original code tested a condition and then, on separate lines, returned the result. We fixed this by returning the result directly.
  • There was repetition of a special value, which we addressed by storing the value of the value in one authoritative place.
  • On a grander scale, there was repetition of the choice of data structure in the form of a Primitive Obsession. Our better choice was to encapsulate the choice in an abstraction.

In a large JavaScript application, these little steps toward DRYness can make the difference between a clean, maintainable app and a “big ball of mud.” Besides, what brings a developer greater joy than obsessing over each step toward perfection?

2 comments

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s