The Discipline of De-Duping Code

The Discipline of De-Duping Code

About the author

Alvin Lee is a full-stack developer and remote worker based in Phoenix, Arizona. He’s been a member of the PullRequest network of reviewer since June 2020. As a member of the PullRequest network, he’s helped over 25 development teams, from startup to Fortune 500, catch mission-critical issues before they’re deployed to production and write optimal, future-proof code. See him in action here.

He specializes in web development, API building, and service integrations for startups and small businesses. He’s available on Moonlight (part of PullRequest), where you can view his profile or request to hire him for services.


images/the-discipline-of-de-duping-code.jpeg

As a reviewer for PullRequest, I see duplicate code a lot. A lot. Duplicate code is, by far, the issue that I spot out most frequently. When I gently nudge developers to address it — to DRY up their code — I often emphasize that you can’t measure the gains of de-duping your code just by counting lines saved in that particular instance. In fact, sometimes de-duping your code results in more lines of code rather than fewer.

Removing code duplication is about the discipline of doing so, not about the lines saved. The goal is to make de-duping your code a reflexive habit — like the way you take a sip of coffee every time you save your file. As it becomes your habit — your discipline — you’ll find that your code becomes easier to debug, maintain, and modify.

An Example

Let’s look at an example, to see code de-duplication in action. The goal is for us to see the little places where we can clean up our code. Do that often enough, and we’ll start to see the big places where we can de-dupe too.

Here’s a module for a Node.js application, used for setting up some test data:

const { 
  addTimestamps,
  truncateLocations
} = require('./testHelpers')

const userData = require('./testData/userData.json')
const deviceTypes = require('./testData/deviceTypes.json')
const nutritionPlans = require('./testData/nutritionPlans.json')
const exerciseRoutine = require('./testData/exerciseRoutine.json')
const goals = require('./testData/goals.json')
const miniChallenges = require('./testData/miniChallenges.json')
const rewards = require('./testData/rewards.json')

export function prepare() => {
  truncateLocations(userData)
  truncateLocations(deviceTypes)
  truncateLocations(nutritionPlans)
  truncateLocations(exerciseRoutine)
  truncateLocations(goals)
  truncateLocations(miniChallenges)
  truncateLocations(rewards)

  addTimestamps(userData)
  addTimestamps(deviceTypes)
  addTimestamps(nutritionPlans)
  addTimestamps(exerciseRoutine)
  addTimestamps(goals)
  addTimestamps(miniChallenges)
  addTimestamps(rewards)

  return {
    userData,
    deviceTypes,
    nutritionPlans,
    exerciseRoutine,
    goals,
    miniChallenges,
    rewards
  }
}

You already see the duplication, don’t you? Of course you see it. I manufactured this example to make it easy for you to see it.

When a developer is working furiously to knock out this module (for test data, no less!), copy/pasting just seems faster than stopping, taking a step back, and considering how this can be done with less duplication. And you know what? It is faster … now.

But, not when you need to make changes later on.

And copy/paste is only faster because you haven’t developed the discipline to make your de-duping really fast too.

One Small De-Dupe At A Time

Let’s go through this one, one step at a time.

First, the import declarations at the top. It is noteworthy that prepare() returns an object with all of these variables in it. Let’s take advantage of that:

const result = {
  userData: require('./testData/userData.json'),
  deviceTypes: require('./testData/deviceTypes.json'),
  nutritionPlans: require('./testData/nutritionPlans.json'),
  exerciseRoutine: require('./testData/exerciseRoutine.json'),
  goals: require('./testData/goals.json'),
  miniChallenges: require('./testData/miniChallenges.json'),
  rewards: require('./testData/rewards.json')
}

That might not seem like a big change, but it opens up some new possibilities. We can store all of our keys in an array, and then add them to result with a loop:

const KEYS = [
  'userData',
  'deviceTypes',
  'nutritionPlans',
  'exerciseRoutine',
  'goals',
  'miniChallenges',
  'rewards'
]

const result = {}

for (const key of KEYS) {
  result[key] = require(`./testData/${key}.json`)
}

Now, the duplication is starting to go away. And, that for loop is the game-changer for the rest of the file:

const { 
  addTimestamps,
  truncateLocations
} = require('./testHelpers')

const KEYS = [
  'userData',
  'deviceTypes',
  'nutritionPlans',
  'exerciseRoutine',
  'goals',
  'miniChallenges',
  'rewards'
]

export function prepare() => {
  const result = {}
  for (const key of KEYS) {
    result[key] = require(`./testData/${key}.json`)
    truncateLocations(result[key])
    addTimestamps(result[key])
  }
  return result
}

Well, look at that. It turned out to be fewer lines after all.

Work Now. Save Later.

But line-count savings aside, let’s consider some of the future gains here:

  1. One day, you’ll need to add a new key to your result, with some more test data in a .json file for that key. Make that change by adding one line — adding that new key to the KEYS array.
  2. One day, you’ll need to call another function on all of the data sets, in addition to truncateLocations and addTimestamps. You don’t need to write that line seven times. You make that change by adding one line — adding that function call inside the for block.

But the biggest gain of all — from taking the time to de-dupe this little module which, sure, might never get updated or even looked at ever again — is the building of discipline.

As you exercise the discipline of removing code duplication in the little places, you’ll get faster. You’ll be able to spot out where you can do this in the big places. And you’ll be more confident about tackling those big places.

Go. Do the work. Save yourself some time.


Photo by Iker Urteaga on Unsplash.


About PullRequest

HackerOne PullRequest is a platform for code review, built for teams of all sizes. We have a network of expert engineers enhanced by AI, to help you ship secure code, faster.

Learn more about PullRequest

Alvin Lee headshot
by Alvin Lee

February 4, 2021