Este principio, desarrollado inicialmente por Robert C. Martin, reza lo siguiente:
Los clientes de un programa dado sólo deberían conocer de éste aquellos métodos que realmente utilizan, y no aquellos que no necesitan utilizar.
Robert C. Martin como consultor para Xerox
Cuando Robert trabajaba en Xerox observó que un sistema de impresora nuevo creado por la empresa que ejecutaba varias tareas como grapar o enviar faxes tenía un software creado desde cero con una clase base llamada Job que se utilizaba prácticamente en todas las tareas. El problema de este diseñó es que como todas las tareas estabas interconectadas entre sí al final la tarea de grapado tenía acceso a las tareas de impresión, por ejemplo. La solución consistió en crear interfaces separadas para las tareas de impresión y de grapado, implementándolas en la clase Job.
Vaya, nos encontramos con un pequeño problema. Desde el principio de esta serie de artículos se ha utilizado Ruby como lenguaje de programación en el que ver y aplicar los principios SOLID pero… Ruby no tiene interfaces. Sin embargo, podemos mostrar un ejemplo similar de violación del ISP con una calculadora de tarifas:
class FeeCalculator def calculate_fee(product, user, vat) # Calculation code... end end class ProductController def show_fee @fee = FeeCalculator.new.calculate_fee(product, user, vat) end end
Hasta ahora no parece haber ningún problema, tenemos nuestra clase calculadora de tarifas con su método para realizar el cálculo y un controlador que llama a este método.
Pero entonces otro desarrollador nos informa que va a añadir un nuevo controlador para guardar órdenes de compra y necesita realizar el cálculo de la tarifa guardando además el resultado en la base de datos. Y es entonces cuando muchos desarrolladores llegan a la siguiente conclusión:
class FeeCalculator def calculate_fee(product, user, var, store_result) # Calculation code... if store_result # Store result into DB end end end class ProductController def show_fee @fee = FeeCalculator.new.calculate_fee(product, user, vat, false) end end class OrderController def create_order @fee = FeeCalculator.new.calculate_fee(product, user, vat, true) end end
Añadimos un nuevo argumento a nuestro método existente, metemos el código adicional… Y listo, ¡todo funcionando!.
Si nos paramos detenidamente a ver esta solución, el desarrollador que ha confeccionado ProductController se ve obligado a modificar su llamada original para enviar un parámetro que no tiene ningún sentido para él ya que nunca le ha interesado guardar el cálculo de la tarifa. Entonces, ¿por qué le obligamos a depender de un código que no está utilizando?
Si leemos el enunciado del principio de segregación de interfaces y traducimos interfaz por parámetros del método veremos que estamos violando este principio.
No pases más de cuatro parámetros en un método. Las opciones de hash son parámetros.
Sandi Metz
Una vez visto el problema podríamos proceder a resolverlo de diferentes formas. Esta es una aproximación:
class FeeCalculator def calculate_fee(product, user, vat) # Calculation code... end def save(fee) # Store result into DB end end class ProductController def show_fee @fee = FeeCalculator.new.calculate_fee(product, user, vat, false) end end class OrderController def create_order fee_calculator = FeeCalculator.new fee = fee_calculator.calculate_fee(product, user, vat, true) fee_calculator.save(fee) end end
Simplemente hemos dividido nuestro método original en dos métodos y así cada cliente utiliza el código que realmente necesita utilizar.
buenas prácticas, desarrollo, SOLID
Comments RSS Feed