lunes, 28 de mayo de 2018

El principio de responsabilidad única (SRP) - Clean architecture

Aunque inicialmente pueda entenderse como que una clase o método debería hacer sólo una cosa este enfoque sería maś un principio de refactorización de funciones grandes y no la definición del Single Responsibility Principle (SRP).


«A module should have only one reason to change.»

Según se explica en el libro Clean Architechture, la única razón para que cambie una clase sería por requisito de un actor que la utilice. Con lo que el principio se reescribe:

«A module should be responsible to one, and only one, actor.»

Con módulo se refiere a un archivo fuente que en POO es una clase.

Entonces, las clases deberían responder ante un único actor y no ante varios de manera que el cambio que un requisito producido por uno de los actores no tenga impacto o pueda llegar a influir en el código del otro actor.

Robert C. Martin establece unos síntomas para entender que este principio no se está cumpliendo.

Sintoma 1: duplicación accidental

Teniendo una aplicación de nóminas con una clase Empleado la cual tiene tres métodos: «calculatePay()», «reportHours()» y «save()».

La clase infringe el principio porque los tres métodos son responsables de tres actores diferentes:
  • «calculatePay()» es específico para el departamento de cuentas.
  • «reportHours()» es específico para recursos humanos.
  • «save()» es específico para el administrador de la base de datos.

Incluir el código fuente de los tres actores en la misma clase produce que el código de los distintos actores se acople. Este acoplamiento puede causar que un cambio por parte de un actor afecte a otro de los actores de forma colateral.

Por ejemplo, si «calculatePay()» y «reportHours()» comparten una función para un cálculo concreto «regularHours()». En un determinado momento el departamentos de cuentas necesita hacer un cambio sobre este cálculo por lo que un programador modifica «regularHours()» para que cumpla las nueva especificación pero no repara en que esta función no debería cambiar para «reportHours()».

El programador hace los test y los responsables lo validan subiendo el nuevo código a producción y dejando el error hasta que alguien lo descubra accidentalmente.

Sintoma 2: merges

Siguiendo con el caso anterior, si el departamento de recursos humanos y el departamento de cuentas cambian la manera de calcular las horas regulares «regularHours()» puede que dos programadores hayan desarrollado el código para cada tarea y a la hora de mezclar el código se produzca un «merge».

Esto es un claro ejemplo de que el código responde a dos actores distintos.

Soluciones

Hay varias soluciones aunque todas implican separar las funciones en diferentes clases.

La primera solución es crear tres clases que contengan las tres funciones y que utilicen los datos de la clase Empleado. Cada clase mantiene su propio código y no está acoplado a las otras clases.


La desventaja de esta solución es que los desarrolladores tienen ahora tres clases que instanciar y seguir la pista. Una solución común es usar el patrón Facade.


En este caso, se crea la clase «EmployeeFacade» que contiene tres métodos que coinciden con los métodos iniciales. Cada uno de estos métodos es responsable de instanciar y delegar a las distintas clases con sus funciones.

Algunos desarrolladores prefieren mantener las reglas de negocio en un lugar más cercano a los datos por lo que se puede utilizar la clase «Employee» para implementar estos métodos y usar esa clase como si fuera un Facade para los métodos menos importantes.


Conclusión


El «Single Responsibility Principle» concierne a funciones y clases pero este también influye en el nivel de componentes donde se convierte en el «Common Closure Principle» y en el nivel de arquitectura donde se convierte en el eje de cambio responsable de la creación de los límites de la arquitectura.

No hay comentarios:

Publicar un comentario