The DRY Principle: When Is ‘Simple Code’ a Better Option?

0

The Pitfall of the DRY Principle: Simplicity Enhances Maintainability

Every developer has heard of the ‘DRY (Don’t Repeat Yourself)’ principle. It’s mentioned so often that it becomes ingrained from the moment one starts learning to code. However, following this principle blindly doesn’t always yield the best results. In fact, applying DRY can sometimes lead to overly complex code that is harder to maintain. This article will explore the pros and cons of the DRY principle and why, at times, simple code may be the better choice.


DRY Principle: The Risk of Good Intentions

The DRY principle is designed to reduce code repetition, aiming for concise code and improved reusability. When developers first learn to program, they use variables and functions to reduce repetitive code and make it more concise. Consider this simple console output example:

console.log(1);
console.log(2);
console.log(3);
console.log(4);

This code performs a repetitive task, and applying the DRY principle would simplify it as follows:

for (let i = 1; i < 5; i++) {
  console.log(i);
}

In this example, the DRY principle helps reduce code length and improve readability. However, real-world scenarios can be more complex. Let’s consider implementing a navigation menu.

An Example of Misapplied DRY: Diminished Maintainability

When writing a navigation menu, it’s common to group repeated structures according to the DRY principle. However, if abstraction is done poorly, it can make the code difficult to read and prone to errors whenever modifications are needed.

Code Example: Bad Abstraction

Here’s an example of a DRY approach to creating a navigation menu.

const NavigationMenu = () => {
  const items = [
    { url: "/about", icon: "question-icon.png", label: "About" },
    { url: "/contact", icon: "person-icon.png", label: "Contact" },
    { url: "/buy", icon: "cash-icon.png", label: "Buy" },
  ];

  return (
    <ul>
      {items.map((item) => (
        <li key={item.url}>
          <a href={item.url}>
            <img src={item.icon} alt={item.label} />
            {item.label}
          </a>
        </li>
      ))}
    </ul>
  );
};

This code uses an array of objects to generate navigation items. At first glance, it seems concise, but over time, you’ll realize how challenging it is to maintain. Every time you need to change the behavior of a button or alter the style, modifying this code can become confusing.

Advantages of Simple Code

On the other hand, simple code is intuitive and easy to understand. In some cases, it’s better not to apply the DRY principle and define each button individually. For example, when you need to change the style of a specific button, simple code might be more efficient.

const NavigationMenu = () => {
  return (
    <ul>
      <li><a href="/about"><img src="question-icon.png" alt="About"/>About</a></li>
      <li><a href="/contact"><img src="person-icon.png" alt="Contact"/>Contact</a></li>
      <li><a href="/buy" style={{ border: '1px solid red' }}><img src="cash-icon.png" alt="Buy"/>Buy</a></li>
    </ul>
  );
};

In this code, each button’s style can be defined individually, avoiding complex abstraction. This can be a better choice in terms of maintainability.

Conclusion: When to Abandon DRY

The DRY principle remains a valuable tool, but it doesn’t need to be applied in every situation. Sometimes, keeping code simple can lead to better long-term outcomes. Abandoning DRY in favor of simple code is a good option in certain circumstances, especially when frequent changes or maintenance are required. Ultimately, what matters most is writing code that serves its purpose and is easy for others to understand.

Reference: swizec, “DRY – the common source of bad abstractions”

Leave a Reply