Get started with 33% off your first certification using code: 33OFFNEW

DRY: What is it and how to implement it. Don't Repeat Yourself

3 min read
Published on 3rd May 2023
DRY: What is it and how to implement it. Don't Repeat Yourself

The DRY (Don't Repeat Yourself) principle is a key concept in software development that focuses on reducing code duplication and improving maintainability. By following the DRY principle, developers can create cleaner, more efficient, and less error-prone codebases. In this article, we will discuss the importance of the DRY principle and illustrate its application in JavaScript with two practical examples.

If you're looking for an example of writing DRY code then check out our article about safelist classes in Tailwind, which rewrites the ruleset to make them DRY.

Section 1: Understanding the DRY Principle

The DRY principle states that each piece of logic in a codebase should have a single, unambiguous representation. In other words, you should avoid duplicating code and extract repetitive parts into reusable components or functions. This approach ensures that when you need to make changes or fix bugs, you only have to do it in one place, making your code more maintainable and less prone to errors.

Section 2: Benefits of the DRY Principle

  1. Improved maintainability: With less duplicated code, it is easier to understand, modify, and extend your codebase.
  2. Reduced likelihood of bugs: By centralizing logic, you reduce the chances of introducing inconsistencies and errors when updating your code.
  3. Enhanced readability: DRY code is generally more concise and easier to read, making it simpler for other developers to understand and work with your code.
  4. Easier debugging: When logic is centralized, it's simpler to track down and fix issues, as you only need to investigate one location instead of multiple instances of the same logic.

Section 3: DRY Principle in JavaScript – Example 1

Consider the following code that calculates the price of items after applying a discount:

Before applying DRY:

function getPriceAfterDiscountA(price) {
  const discountA = 0.1;
  return price * (1 - discountA);
}

function getPriceAfterDiscountB(price) {
  const discountB = 0.2;
  return price * (1 - discountB);
}

console.log(getPriceAfterDiscountA(100)); // 90
console.log(getPriceAfterDiscountB(100)); // 80

In this example, we have two functions with nearly identical logic, except for the discount values. This code is repetitive and not DRY.

After applying DRY:

function applyDiscount(price, discount) {
  return price * (1 - discount);
}

function getPriceAfterDiscountA(price) {
  const discountA = 0.1;
  return applyDiscount(price, discountA);
}

function getPriceAfterDiscountB(price) {
  const discountB = 0.2;
  return applyDiscount(price, discountB);
}

console.log(getPriceAfterDiscountA(100)); // 90
console.log(getPriceAfterDiscountB(100)); // 80

We've extracted the common logic into an applyDiscount() function, which is now used by both getPriceAfterDiscountA() and getPriceAfterDiscountB(). This change makes our code DRY and more maintainable.

As an of maintainability, imagine we have 10 discounts instead of the 2 above, and we have a change to this code where we want to apply some kind of pre or post-tax discount across all available discounts. Using the original method we would have to make that change in 10 places, but in the DRY code we just change the applyDiscount function. The extra layer of abstraction will result in less code, less bugs, easier to read code and more maintainable code.

Section 4: DRY Principle in JavaScript – Example 2

Let's look at another example where we want to calculate the area of different shapes:

Before applying DRY:

function calculateCircleArea(radius) {
  return Math.PI * radius * radius;
}

function calculateRectangleArea(length, width) {
  return length * width;
}

function calculateTriangleArea(base, height) {
  return (base * height) / 2;
}

After applying DRY:

function calculateArea(shape, ...dimensions) {
  switch (shape) {
    case "circle":
      const [radius] = dimensions;
      return Math.PI * radius * radius;
    case "rectangle":
      const [length, width] = dimensions;
      return length * width;
    case "triangle":
      const [base, height] = dimensions;
      return (base * height) / 2;
    default:
      throw new Error("Invalid shape");
  }
}

console.log(calculateArea("circle", 5)); // 78.53981633974483
console.log(calculateArea("rectangle", 4, 6)); // 24
console.log(calculateArea("triangle", 3, 7)); // 10.5

In this example, we've extracted the logic for calculating the area of different shapes into a single calculateArea() function. This function takes the shape and its dimensions as arguments and uses a switch statement to determine the appropriate calculation. By doing so, we've made our code DRY and easier to maintain.

Conclusion:

Embracing the DRY principle in JavaScript is an essential practice for writing clean, maintainable, and efficient code. By identifying repetitive code patterns and extracting them into reusable functions, you can reduce the likelihood of bugs and make your codebase more readable and easier to understand. Remember to always be on the lookout for opportunities to apply the DRY principle in your projects, as doing so will significantly improve the quality of your code.