DRY Principle

DRY Principle

No te lo repitas... (Don't repeat yourself)

·

3 min read

Dentro de las recomendaciones que entrega el libro Clean Code, podemos encontrar un principio algo más moderno que complementa la sección de Métodos y funciones. Hablamos en esta oportunidad del principio DRY (Don't repeat yourself).

Este principio está basado en técnicas y consejos para evitar la duplicidad de código o la repetición de patrones de programación, en favor de la abstracción y escapando de la redundancia. El libro, The Pragmatic Programmer, define este principio donde "cada pieza de conocimiento debe tener una representación única, clara y autoritaria en un sistema", si creamos un algoritmo o método para resolver un problema, ese algoritmo debe aparecer sólo una vez en dicho sistema.

Por ejemplo, si tenemos una clase que se llama PaymentMethod que es parte del comportamiento de nuestra lógica de negocio, y utilizamos los medios de pagos en varias partes de nuestra aplicación, podríamos fácilmente repetir esa lógica en cada sitio que usemos nuestra clase. Pero, pero, pero... Si en seis meses cambia algo de esa lógica en nuestro negocio, debemos buscar en cada una de las implementaciones, corriendo un riesgo bastante alto de estropear las cosas 🤬 y hacer enojar a alguien.

Evitamos esto utilizando abstracción, generando la lógica en un sólo lugar y luego reutilizándola en cada parte que sea necesario. Si más adelante debemos realizar un cambio, será sólo en un sitio y no en 34 🤯.

Tenemos que poner una advertencia antes:

  • La duplicidad de conocimiento (o la manera de resolver un problema), es una violación al principio DRY.
  • Tener código duplicado, no es necesariamente una violación.

Ejemplos, en código (de la vida real 😳)

Tenemos cierta aplicación con una botonera de opciones de pago, distintas empresas con las que puedes cancelar un monto. En la integración con los servicios de cada empresa tenemos ciertos mensajes de retorno que son comunes, aquí un ejemplo:

public class PaymentMethodResponseError {

  public void controlMessageErrorsFromServices(PaymentMethod paymentMethod){
    if( paymentMethod.error == COMMUNICATION_ERROR ){
      throw new Exception("Error de comunicación. Intente nuevamente"); 
    }
    if( paymentMethod.error == SERVICE_DOWN ){
      throw new Exception("Servicio no disponible. Intente más tarde");
    }
    if( paymentMethod.error == TIMEOUT_ERROR ){
      throw new Exception("El servidor tardó mucho en responder. Intente nuevamente");
    }
  }

}

Alguno podría indicar que esto es una violación al principio DRY, porque tenemos un montón de if en el método. Y esta es la diferencia que quisiera resaltar. Esto no es violación del principio DRY, porque la lógica de los mensajes de respuesta ante un error no están en varias partes del programa, sino que están enmarcados en esta función. Sin embargo, puede que esto sea duplicidad innecesaria de código. Así podría quedar mejor:

public class PaymentMethodResponseError {

  private static final Map<String,String> SERVICE_ERRORS = Map.of(
        COMMUNICATION_ERROR, "Error de comunicación. Intente nuevamente",
        SERVICE_DOWN, "Servicio no disponible. Intente más tarde",
        TIMEOUT_ERROR, "El servidor tardó mucho en responder. Intente nuevamente"
  );

  public void controlMessageErrorsFromServices(PaymentMethod paymentMethod){
    SERVICE_ERRORS.forEach((k, v) -> {
      if( paymentMethod.error.equals(k) ){
        throw new Exception(v);
      }
    });
  }

}

Sin embargo, la lógica de negocio no ha cambiado de lugar, tampoco se ha movido o duplicado. Lo único que ha cambiado es la cantidad de if presentes en nuestro método.

Concluimos con esta observación: No todo el código duplicado es una violación al principio DRY, pero toda lógica de negocio duplicada, sí lo es.