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).
Según Robert
C. Martin el Principio
de Responsabilidad única establece:
«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