DRY (Don’t Repeat Yourself) Programming Principle

The DRY principle (Don’t Repeat Yourself) is a programming principle that suggests that code should not be duplicated unnecessarily, and that repetition should be eliminated through abstraction and modularisation. This principle is important because it can help reduce the complexity of code, make it easier to maintain and modify, and avoid errors that can arise from duplicated code.

Here’s an example of DRY in practice. Let’s say you have a program that needs to perform some calculations on an array of numbers. You might be tempted to write separate functions for each calculation, even though many of these functions might have a lot of duplicated code.

Here’s an example of what that code might look like:

public class ArrayCalculator {
  public static double sum(double[] arr) {
    double sum = 0;
    for (double x : arr) {
      sum += x;
    }
    return sum;
  }
  
  public static double average(double[] arr) {
    double sum = 0;
    for (double x : arr) {
      sum += x;
    }
    return sum / arr.length;
  }
  
  public static double max(double[] arr) {
    double max = arr[0];
    for (double x : arr) {
      if (x > max) {
        max = x;
      }
    }
    return max;
  }
  
  public static double min(double[] arr) {
    double min = arr[0];
    for (double x : arr) {
      if (x < min) {
        min = x;
      }
    }
    return min;
  }
}
Java

This code calculates the sum, average, maximum, and minimum of an array of numbers, but it repeats the same loop code for each function. This violates the DRY principle, as it introduces unnecessary complexity and makes it harder to maintain the code.

Here’s an example of how you can apply DRY to this code:

public class ArrayCalculator {
  public static double sum(double[] arr) {
    return reduce(arr, 0, (acc, x) -> acc + x);
  }
  
  public static double average(double[] arr) {
    return sum(arr) / arr.length;
  }
  
  public static double max(double[] arr) {
    return reduce(arr, Double.NEGATIVE_INFINITY, (acc, x) -> Math.max(acc, x));
  }
  
  public static double min(double[] arr) {
    return reduce(arr, Double.POSITIVE_INFINITY, (acc, x) -> Math.min(acc, x));
  }
  
  private static double reduce(double[] arr, double initial, DoubleBinaryOperator op) {
    double acc = initial;
    for (double x : arr) {
      acc = op.applyAsDouble(acc, x);
    }
    return acc;
  }
}
Java

In this code, the loop code is abstracted into a single reduce function that takes an initial value and a binary operator as arguments. Each calculation function then uses this reduce function with the appropriate initial value and operator to perform the calculation. This eliminates the duplicated loop code and makes the code simpler, more maintainable, and less error-prone.