---
# System prepended metadata

title: Refactoring

---

# Refactoring

Link video: https://drive.google.com/drive/folders/1EqYrPi9zWVhrzoR-giyyTmSUF3WmlVMS?usp=sharing
Repositorio: https://github.com/andres-alvarez19/FilmAffinityFruna

## Formato creación de videos

Los videos los haremos entre 2 personas para cumplir con el apartado de la pauta donde solicita que todos participemos en el video.

| Code smell | Identificacion | Refactoring |
|:-------:|:--------:|:-----------------:|
| Dispensable (1) | Angel Rocha| Andres Alvarez|
| Change preventer (2) | Nahuel | José|
| Coupler (3) | Nahuel | Diego | 

### Creación de Pruebas Unitarias (PU) con IA

Se usó inteligencia artificial para generar pruebas unitarias para cada clase Service y Controller. Este enfoque facilitó identificar que Mockito era esencial para probar correctamente las funcionalidades en Spring Boot.

**Las ventajas del uso de IA fueron**:

- La IA ayudó a acelerar la comprensión del entorno de pruebas, especialmente en el uso de herramientas como Mockito.
- Nos permitió generar una base inicial de pruebas unitarias que cubrían los casos básicos, lo que fue útil para familiarizarnos con las funcionalidades que debíamos testear.

**Desafíos y complejidades enfrentadas**

Aunque la IA generó ejemplos y el esqueleto de las pruebas, nuestra falta de experiencia con Mockito presentó dificultades. Adaptar y comprender el código tomó más tiempo de lo previsto, a pesar de las ventajas iniciales.

El principal reto fue entender cómo Mockito maneja las simulaciones (mocks) y verificaciones (verify), así como la configuración de pruebas para excepciones. Esto fue un desafío inicial debido a que habíamos trabajado principalmente con JUnit 5 sin el uso intensivo de Mockito.

**Proceso de aprendizaje y mejoras aplicadas**

Tras estudiar más a fondo el framework y aplicar nuestra experiencia con JUnit 5, identificamos varias áreas de mejora en los tests generados por la IA, lo cual nos permitió aumentar su robustez.

-  Clase **ActorRestControllerExceptionTest**
![imagen](https://hackmd.io/_uploads/Sy8E92j-kl.png)

Inicialmente, las pruebas generadas por la IA verificaban el mensaje exacto de las excepciones, pero descubrimos que esta práctica era frágil. Incluso una mínima diferencia, como un error tipográfico o un cambio en la capitalización (por ejemplo, "Error" vs. "Eror"), podía generar falsos negativos.

![imagen](https://hackmd.io/_uploads/S1Co0hjZ1g.png)

- Clase **DirectorServiceExceptionTest**
![imagen](https://hackmd.io/_uploads/rJQPp3iWkx.png)

Un problema similar se presentaba en las pruebas para los Service, donde se verificaba el contenido del mensaje en lugar de la excepción misma.

Decidimos ajustar las pruebas para centrarnos en la excepción esperada y en asegurar que se manejara correctamente la lógica de negocio, sin depender del mensaje exacto

![imagen](https://hackmd.io/_uploads/rJnxR3sbJx.png)

#### Uso de verify para mejorar el aislamiento de las pruebas

Otra mejora implementada fue el uso de verify de Mockito para asegurarnos de que las dependencias en nuestras clases no realizaran acciones inesperadas. Esto garantiza que las pruebas unitarias se mantengan aisladas y enfocadas únicamente en la funcionalidad de la clase que se está probando.

**Buena práctica**: Utilizar verify para validar que ciertos métodos no sean invocados, lo que mejora la precisión y fiabilidad de los tests.

![imagen](https://hackmd.io/_uploads/ryeky6i-yl.png)

#### Conclusion

El uso de IA para crear pruebas unitarias aceleró el desarrollo inicial y destacó la importancia de comprender bien las herramientas utilizadas. Aunque la IA facilitó un punto de partida, fue necesario refinar y adaptar las pruebas para ajustarlas a nuestras necesidades y hacerlas más robustas.

**Lo bueno**: Aceleró la creación de pruebas y la identificación de casos de prueba.
**Lo malo**: Requirió un esfuerzo adicional para comprender y ajustar el uso de Mockito, especialmente en la validación de excepciones.


# Documentacion del refactoring

En esta parte haremos la documentacion para el taller 3

## Code smell 1: Dispensable

### Identificacion (Duplicate code)
En este caso, el code smell identificado en todas las clases RestController es del tipo *Duplicate Code*.

- Pagina 53 *Dive Into Refactoring*
![imagen](https://hackmd.io/_uploads/SksloGF-Jg.png)

Este problema surge porque en diferentes métodos se repite un bloque de código casi idéntico, específicamente un try-catch, lo que genera redundancia en el manejo de excepciones.

- Clase **ActorRestController**
![imagen](https://hackmd.io/_uploads/Hkrf7zt-ye.png)
- Clase **DirectorRestController**
![imagen](https://hackmd.io/_uploads/Hy3zvfY-Jl.png)

Esta duplicación no solo afecta la claridad del código, sino que también dificulta su mantenimiento, ya que cualquier modificación en el manejo de excepciones tendría que aplicarse en múltiples lugares.

### Tecnica de refactoring utilizadas

1. **Extract Method**

Para eliminar el bloque try-catch repetitivo en los métodos de cada controlador, se emplea la técnica de Extract Method para mover esta lógica de manejo de excepciones a un método separado. Esto permite reducir la duplicación dentro de cada clase de controlador y mejora la cohesión.

![imagen](https://hackmd.io/_uploads/H1lW3zKZkl.png)

2. **Extract Class**

Debido a que el mismo bloque de código de manejo de excepciones se encuentra en todas las clases RestController (ActorRestController, DirectorRestController, GenreRestController, MovieRestController, etc), deberiamos repetir el metodo extraido en todas las clases RestController lo que produciria un code smell del tipo duplicate code nuevamente, por lo que podemos usar el refactoring del tipo extract class llevar esta extracción a un nivel más global. 

![imagen](https://hackmd.io/_uploads/r1ePRGY-Jx.png)
(No hacemos herencia ya que esto no seria lo mas apropiado para nuestras clases)

Para ello, creamos una clase de manejo de excepciones utilizando @ControllerAdvice propia de SpringBoot, lo que nos permite gestionar las excepciones en una clase separada sin la necesidad de hacer llamadas del metodo o clase en cada uno de nuestros controladores.

Esto centraliza el manejo de excepciones para todos los controladores, permitiendo una mejor organización del código.

#### Implementación del refactoring 

La nueva clase captura cualquier excepción no controlada que se produzca en las clases Controller y devuelve una respuesta con un estado de error y un mensaje explicativo.

![image](https://hackmd.io/_uploads/Bkb1jHpWye.png)

Ademas para hacer funcionar correctamente el lanzador de excepciones cuando se entregen entidades con atributos vacios, se especifica mediante las propias clases Entity los campos que no pueden ser nulos.

![image](https://hackmd.io/_uploads/HyxKsr6-yl.png)

De esta forma aseguramos que las excepciones se arrojen al ingresar mal entidades en los controladores y ademas dejamos un mensaje de cual campo falta.

Tambien es necesario especificarlo en los parametros del contralador.

#### Explicacion metodo 

Este método maneja todas las excepciones (excepciones genéricas) lanzadas por los controladores y devuelve un JSON con el estado HTTP correspondiente y un mensaje de error. Al centralizar el manejo de excepciones, reducimos el código duplicado y mejoramos la mantenibilidad del sistema.

### Resultado del refactoring
A partir del refactoring realizado este seria el resultado en codigo:
![imagen](https://hackmd.io/_uploads/HyxcKGFbke.png)

![image](https://hackmd.io/_uploads/S1Fu7ljbyx.png)

De esta forma logramos:
- **Código más limpio y organizado**: Se eliminan los bloques try-catch redundantes en los métodos individuales de los controladores.
- **Manejo de excepciones centralizado**: Al gestionar todas las excepciones desde una clase, el mantenimiento y las actualizaciones del manejo de errores se simplifican significativamente.
- **Mejora en la cohesión**: Cada controlador se centra únicamente en la lógica principal, sin tener que preocuparse por el manejo de errores.

Esta estrategia de refactorización facilita la escalabilidad del proyecto y mantiene el código de los controladores conciso y enfocado en su propósito principal.

sobre las pruebas unitarias generadas con inteligencia artifical se generaron algunos problemas de codigo como 

## Code smell 2: Shotgun Surgery

### Identificacion 

El code smell identificado en las clases es del tipo *Shotgun Surgery*. 

- Página 43 *"Dive into Refactoring"*
![image](https://hackmd.io/_uploads/Bkkudgi-Jx.png)
![image](https://hackmd.io/_uploads/rk1YFlsW1x.png)


El problema ocurre debido a que el principio de responsabilidad única ha sido repartido en varias clases o métodos luego de aplicar excesivamente el Cambio Divergente *(Divergent Change)*.

* Clase **ActorService**
![image](https://hackmd.io/_uploads/ryJF9giW1x.png)
![image](https://hackmd.io/_uploads/H1C99li-1x.png)

* Clase **DirectorService**
![image](https://hackmd.io/_uploads/B1_ZoljZJg.png)
![image](https://hackmd.io/_uploads/rkUmiloZ1l.png)

* Clase **GenreService**
![image](https://hackmd.io/_uploads/B1gUsesWyg.png)
![image](https://hackmd.io/_uploads/SJ1DixjWye.png)

* Clase **MovieService**
![image](https://hackmd.io/_uploads/B14ciejW1l.png)
![image](https://hackmd.io/_uploads/Sy7isesWyx.png)

* Clase **UserService**
![image](https://hackmd.io/_uploads/Skvpsgi-Jl.png)
![image](https://hackmd.io/_uploads/BkAAjxs-Jx.png)

Este problema hace que sea más difícil el mantenimiento del código, genera desorden, y hace que exista código duplicado.

### Tecnica de refactoring
#### Extract Superclass
Se creó la clase BaseService que contiene las operaciones CRUD generales y comunes a los servicios específicos.
Los métodos como findById, existsById, existsByName, y saveEntity fueron centralizados en BaseService.
![imagen](https://hackmd.io/_uploads/r1ePRGY-Jx.png)
#### Move Method y Move Field
Se movieron métodos y campos específicos (como repository y métodos CRUD básicos) de los servicios individuales hacia BaseService.
Con estos métodos en BaseService, cada servicio específico (ActorService, DirectorService, etc.) quedó con solo las operaciones particulares de cada entidad.
![este](https://hackmd.io/_uploads/HkM2gO6b1x.png)



### Resultado del refactoring
#### Clase BaseService
En esta clase base, implementaremos métodos genéricos de CRUD que pueden ser utilizados por los servicios de entidad. Para permitir la reutilización, BaseService se parametrizará con el tipo de entidad y su repositorio.

![b1](https://hackmd.io/_uploads/HyEauDTZke.png)
![b2](https://hackmd.io/_uploads/rJp6OPT-Jg.png)

Métodos Específicos
1. Verificación de Existencia (existsByUniqueProperty): 
2. Registro (register): 
3. Métodos de Búsqueda y Eliminación Específicos (searchByName, deleteByName, searchByUsername, deleteByUsername): 



### Clase ActorService Refactorizada 
![a1](https://hackmd.io/_uploads/rkSKmua-ke.png)
![a2](https://hackmd.io/_uploads/B1sFmuabkl.png)



### Ventajas Especificas de esta refactorización

1. Mayor Facilidad para Añadir Nuevas Entidades:
* Si en el futuro se añaden nuevas entidades (como ProducerEntity o ReviewEntity), no se necesita escribir nuevamente los métodos de CRUD, simplemente se pueden extender de la clase BaseService y luego solo habría que enfocarse en la lógica específica de esa nueva entidad.
* Ventaja: Esto hace que el código sea más escalable y fácil de ampliar sin duplicación de esfuerzo.
2. Mayor Coherencia entre los Servicios:
* Todos los servicios (como UserService, MovieService, etc.) ahora heredan de la misma clase base, lo que asegura que se sigan las mismas convenciones y se use la misma lógica de negocios para las operaciones de CRUD.
* Ventaja: Esto mejora la coherencia entre los servicios, lo que facilita el trabajo de los desarrolladores y facilita la comprensión del sistema.
3. Simplicidad en la Lógica de las Clases Hijas:
* Las clases de servicio específicas ahora son mucho más simples. Solo contienen la lógica que es exclusiva de esa entidad (por ejemplo, campos específicos como nombre, fecha de nacimiento, o género), sin tener que lidiar con las operaciones comunes de CRUD.
* Ventaja: Esto hace que las clases de servicio sean más fáciles de entender y más fáciles de extender si se necesitan características específicas para esa entidad.
4. Facilita el Control de Errores:
* Si en el futuro se desea cambiar la forma en que se manejan los errores, como las excepciones que se lanzan cuando no se encuentra un registro, solo habría que modificarlo en la clase base.
* Ventaja: Esto centraliza el manejo de errores, facilitando la implementación de cambios y mejorando la consistencia en el tratamiento de errores en todo el proyecto.
5. Mejoras en la Reutilización de Código:
* La clase BaseService actúa como una clase base genérica para todas las entidades que implementen operaciones CRUD. Esto elimina la necesidad de escribir el mismo código de validación, guardado y eliminación en cada clase.
* Ventaja: Mejora la reutilización de código, reduciendo el esfuerzo necesario para implementar nuevas funcionalidades.





## Code smell 3
### Identificacion (Magic Strings)

El code smell identificado en todas las clases RestController es del tipo [Magic String](https://refactoring.guru/replace-magic-number-with-symbolic-constant#:~:text=How%20to%20Refactor%20Declare%20a%20constant%20and%20assign,If%20yes%2C%20replace%20the%20number%20with%20your%20constant.).

Ejemplos de clases afectadas:

- Clase **ActorRestController**
![image](https://hackmd.io/_uploads/HkOTA7ob1l.png)

- Clase **DirectorRestController**
![image](https://hackmd.io/_uploads/Bki-1Ejbyx.png)

### Descripcion del problema 

En los controladores, se utilizan mensajes hardcoded para responder a solicitudes HTTP, como "Actor no encontrado" o "Registro exitoso". Según el libro *Dive into Refactoring*, esto crea un problema de **Magic Strings** porque estos mensajes están dispersos en múltiples métodos y clases.

Estos Magic Strings representan valores literales incrustados en el código que no son claros a simple vista y pueden cambiar en el futuro, lo que hace que su mantenimiento sea más complicado.

- Pagina 182 de *Dive into refactoring (java)*
![image](https://hackmd.io/_uploads/HkU0yVi-Jg.png)
![image](https://hackmd.io/_uploads/HkuqZ4o-1e.png)

Aunque la descripción original de este code smell en el libro suele referirse a números (Magic Numbers), el problema es esencialmente el mismo: ambos representan valores literales incrustados en el código que pueden cambiar en el futuro, lo que resulta en un código frágil y difícil de mantener.

### Tecnica de refactoring

Para resolver este problema, se ha utilizado la técnica Replace Magic Literal with Constant, que consiste en mover todos los mensajes hardcoded a constantes.

![image](https://hackmd.io/_uploads/B1W1GNiWkx.png)

Si simplemente aplicáramos esta técnica en cada clase RestController, terminaríamos repitiendo las mismas constantes en múltiples lugares, generando un nuevo code smell del tipo Duplicated Code.

Por lo tanto, en lugar de duplicar las constantes, se utilizó la técnica de Extract Class para crear una clase centralizada llamada MessageConstant, que contiene todas las constantes de mensajes.

![image](https://hackmd.io/_uploads/B1CqfNsZyl.png)

### Resultado del refactoring
Ahora, el código es más limpio y organizado, ya que se eliminaron los Magic Strings dispersos por el código y centralizamos todos los mensajes en una única clase (MessageConstant).

**Ventajas obtenidas:**

**Mantenibilidad mejorada:** Los mensajes ahora se pueden actualizar en un solo lugar (MessageConstant), lo que facilita futuras modificaciones y reduce la probabilidad de errores.
**Escalabilidad:** Si en el futuro necesitas traducir los mensajes o personalizarlos, solo es necesario modificar la clase centralizada.

Ejemplos del resultado:

![image](https://hackmd.io/_uploads/HkCjNEsWJe.png)

![image](https://hackmd.io/_uploads/HysaNEsWyl.png)

### Justificacion refactoring

Aunque la nueva solución utiliza mensajes más genéricos, sacrificando algunos detalles específicos sobre la entidad (como Actor o Director), esta simplificación es suficiente para las necesidades actuales del proyecto. Ademas en como se hace este refactoring, se especifica que es importante revisar si el texto tiene sentido con el contexto de donde sera reemplazado.

![image](https://hackmd.io/_uploads/Sym6FEiZkg.png)



Si es necesario respuestas más detalladas y específicas, se puede extender la solución utilizando clases especializadas como ActorMessages o DirectorMessages. Sin embargo, por ahora, la respuesta genérica centralizada es una solución adecuada para el alcance del proyecto.

## Pauta

![image](https://hackmd.io/_uploads/ryEp6P-bkl.png)
