Anda di halaman 1dari 24

DAYANI ESPAÑA

¿Qué es Refactorización?

Es un cambio hecho a la estructura interna de un software para hacerlo fácil


de entender y mantener sin modificar el comportamiento observable.

Refactoring es un derivado del término “Factoring” y se le conoce


informalmente como limpiar el código. Su objetivo es mejorar la lectura del código
y eliminar código muerto (death code) para hacer más fácil el mantenimiento del
mismo. En este proceso normalmente nos encontramos con defectos que debemos
corregir: anidamiento excesivo, clases y funciones grandes, código
duplicado y comentado, acoplamiento excesivo, uso de nombres incorrectos
(clases, funciones, variables), etc.

¿Por qué debemos Refactorizar?

 Mejora el diseño
 Mejora la lectura del código
 Revela defectos
 Ayuda a programar más rápido

¿Cuándo debemos Refactorizar?

 Cuando desarrollamos usando TDD: Red – Gree – Refactor


 Cuando desarrollamos usando PDD (Pain driven development): Si el código te
causa dolor, entonces refactorizalo.
 Cuando se necesita agregar una nueva funcionalidad
 Cuando corregimos bugs
 Cuando hacemos la revisión de código
¿Cuándo no debemos Refactorizar?

 Cuando la deuda técnica es muy alta y la única opción es reescribir toda la


aplicación
 Cuando no se usa un código, en este caso recomiendo borrarlo.
 Cuando el fin del plazo de entrega está cerca, esto puede agregar nuevos bugs que
no se llegan a probar por falta de tiempo.

Principios de Refactorización

 KISS (Keep it simple stupid)


 DRY (Dont repeat yourself)
 Escribir código expresivo
 Reducir el código
 Separar responsabilidades
 Usar un nivel de abstracción apropiado

Tips de Refactorización

 Revisar constantemente el código


 Hacer un checklist de defectos a refactorizar
 Hacer refactorizaciones pequeñas, una a la vez
 Agregar casos de prueba o pruebas unitarias
 Revisar los resultados

Herramientas de Refactorización

 Visual studio (Microsoft)


 JustCode (Telerik)
 ReSharper (JetBrains)
 CodeRush (DevExpress)
 Visual Assist X (Whole Tomato)
ANDRES MAITA

Técnicas de Refactorización

 Rename Method
Una de las técnicas más sencillas pero efectivas, se puede usar sobre: clases,
funciones, propiedades, variables, etc. Usar nombres claros reduce el uso de
comentarios y aumente la lectura del código.

Antes

1 /// <summary>
2 /// Responsable de manejar los impuestos
3 /// </summary>
4 public class Class1
5 {
6 /// <summary>
7 /// Nombre del proceso a ejecutar
8 /// </summary>
9 public string Nombre { get; set; }
10
11 /// <summary>
12 /// Calcula el impuesto a pagar
13 /// </summary>
14 /// <param name="t">Numero de Cedula</param>
15 public double Calcula(string t) { }
16 }
Después

1 public class ServicioImpuesto


2 {
3 public string NombreProcesoEjecutar{ get; set; }
4 public double CalculaImpuestoAPagar(string numeroCedula) { }
5 }

 Introduce Explaining Variable


Esta técnica se relaciona con la anterior, pero se aplica cuando se tiene una
expresión complicada para darle un nombre fácil de entender.

Antes

1 if (solicitud.Tipo == 2 && solicitud.Cantidad > 10 && solicitud.Precio < 100)


2 {
3 solicitud.Descuento = 0.5M;
4 }
Después

1 var aplicaDescuento =
2 solicitud.Tipo == 2 && solicitud.Cantidad > 10 && solicitud.Precio < 100;
3 if (aplicaDescuento)
4 {
5 solicitud.Descuento = 0.5M;
6 }

 Inline Temp

Las variables temporales son un tipo de code smell que hacen que los métodos se
vuelvan más largos, siempre y cuando se usen una sola vez.
Antes

1 public void EjecutarProcesoAdmision(Solicitud solicitud)


2 {
3 var estudiante = solicitud.Estudiante;
4 var programa = solicitud.Programa;
5 var vacante = solicitud.Vacante;
6 var ciclo = solicitud.Ciclo;
7
8 var resultado = ValidarAdmision(estudiante, programa, vacante, ciclo);
9 }
Después

1 public void EjecutarProcesoAdmision(Solicitud solicitud)


2 { var resultado = ValidarAdmision(solicitud.Astudiante,
3 solicitud.Programa, solicitud.Vacante, solicitud.Ciclo);
4 }
No siempre es malo usar variables temporales, en algunos casos pueden servir para
volver el código más fácil de entender, por ejemplo al llamar un método o una
propiedad que su nombre no sea lo suficientemente claro.

Antes

1 ValidarAdmision(solicitud.Ent,
2 solicitud.Programa, solicitud.Vacante, solicitud.Ciclo);
Después

1 var estudiante = solicitud.Ent;


2
3 ValidarAdmision(estudiante,
4 solicitud.Programa, solicitud.Vacante, solicitud.Ciclo);

 Split Temp Variable

Esta técnica se aplica cuando una variable tiene muchas responsabilidades o


almacena distintos resultados.
Antes

1 //Almacena el total
2 var temp = solicitud.Monto * solicitud.Cantidad;
3 //Calcula el impuesto
4 temp = (temp * 0.15);
Después

1 var total= solicitud.Monto * solicitud.Cantidad;


2 var imuesto = (total * 0.15);

 Replace Temp With Query

Esta técnica es parecida a la técnica Inline temp pero con la diferencia que invoca
a un método que contiene la evaluación de la expresión compleja.
Antes

1 var total= solicitud.Monto * solicitud.Cantidad;


2 var impuesto = (total * 0.15);
Después

1 var total= CalcularTotal(solicitud);


2 var impuesto = (total * 0.15);
3
4 public double CalcularTotal(Solicitud solicitud)
5 {
6 return solicitud.Monto * solicitud.Cantidad;
7 }
LUIS RODRIGUEZ

 Extract Method

Esta es una de las técnicas más usadas e importantes de la refactorización.


Consiste en dividir métodos largos moviendo pedazos de códigos en nuevos
métodos con nombres descriptivos.

Antes

1 public void CaducarPoliza(Poliza poliza)


2 {
3 var servicioPoliza = new ServicioWebPolizaExterno();
4 RequestOpera105874 requestCaducarPoliza;
5 //Código...
6 servicioPoliza.Opera105874(requestCaducarPoliza);
7
8 var servicioNotificacion = new ServicioNotificacion();
9 Mensaje mensajeResponsable;
10 //Código...
11 servicioNotificacion.EnviarNotificacion(mensajeResponsable);
12
13 var servicioTraza = new ServicioTraza();
14 Traza trazaPolizaCaducada;
15 //Código...
16 servicioTraza.Registrar(trazaPolizaCaducada);
17 }
Después

1 public void CaducarPoliza(Poliza poliza)


2 {
3 CaducarPolizaServicioExterno(poliza);
4 EnviarNotificacionResponsable(poliza);
5 RegistrarLogPoliza(poliza);
6 }
7
8 private void CaducarPolizaServicioExterno(Poliza poliza)
9 {
10 var servicioPoliza = new ServicioWebPolizaExterno();
11 RequestOpera105874 requestCaducarPoliza;
12 //Código...
13 servicioPoliza.Opera105874(requestCaducarPoliza);
14 }
15
16 private void EnviarNotificacionResponsable(Poliza poliza)
17 {
18 var servicioNotificacion = new ServicioNotificacion();
19 Mensaje mensajeResponsable;
20 //Código...
21 servicioNotificacion.EnviarNotificacion(mensajeResponsable);
22 }
23
24 private void RegistrarLogPoliza(Poliza poliza)
25 {
26 var servicioTraza = new ServicioTraza();
27 Traza trazaPolizaCaducada;
28 //Código...
29 servicioTraza.Registrar(trazaPolizaCaducada);
30 }
 Inline Method

Esta técnica es opuesta a la técnica Extract method ya que une todos los métodos
en un solo, se debe aplicar siempre y cuando una función solo se use en un solo
lugar y tener el código en métodos separados no agregue ningún beneficio.
Antes

1 public double Calcula(Solicitud solicitud)


2 {
3 //Codigo
4 AsignarAlumno(solicitud, idEstudiante);
5 var nroPedido = ObtenerNumeroPedido(solicitud);
6 //Codigo
7 }
8
9 private void AsignarAlumno(int idAlumno)
10 {
11 solicitud.IdAlumno = idAlumno;
12 }
13
14 private string ObtenerNumeroPedido(Solicitud solicitud)
15 {
16 return solicitud.NumeroPedido;
17 }
Después

1 public double Calcula(Solicitud solicitud)


2 {
3 //Codigo
4 solicitud.IdAlumno = idAlumno;
5 var nroPedido = solicitud.NumeroPedido;
6 //Codigo
7 }

 Move Method

Esta técnica mueve un método a otra clase ya que usa más características de la
otra clase que de ella misma. Al aplicar estas estrategias reducimos el
acoplamiento.

Antes

1 class Poliza
2 {
3 public void CaducarPoliza(Poliza poliza)
4 {
5 //Codigo
6 EnviarNotificacionResponsable(poliza);
7 //Codigo
8 }
9
10 private void EnviarNotificacionResponsable(Poliza poliza)
11 {
12 Mensaje mensajeResponsable;
13 //Código...
14 }
15 }
Después

1 class Poliza
2 {
3
4 private readonly IServicioNotificacion servicioNotificacion;
5
6 public Poliza(IServicioNotificacion servicioNotificacion)
7 {
8 servicioNotificacion = servicioNotificacion;
9 }
10
11 public void CaducarPoliza(Poliza poliza)
12 {
13 //Codigo
14 EnviarNotificacionResponsable(poliza);
15 //Codigo
16 }
17
18 private void EnviarNotificacionResponsable(Poliza poliza)
19 {
20 Mensaje mensajeResponsable;
21 //Código...
22 servicioNotificacion.EnviarNotificacion(mensajeResponsable);
23 }
24 }
25
26 class ServicioNotificacion : IServicioNotificacion
27 {
28 public void EnviarNotificacion(Mensaje mensajeResponsable){}
29 }

 Extract Class

Esta técnica se aplica cuando se tiene una clase que hace el trabajo (tiene muchas
responsabilidades) de dos o más.
Antes

1 public class ServicioNotificacion


2 {
3 public void EnviarNotificacionSuperisor(string mensaje) { }
4 public void EnviarNotificacionAdministrador(string mensaje) { }
5 public string Encriptar(string valor) { }
6 public string Desencriptar(string valor)
7 }
Después

1 public class ServicioNotificacion


2 {
3 public void EnviarNotificacionSuperisor(string mensaje) { }
4 public void EnviarNotificacionAdministrador(string mensaje) { }
5 }
6
7
8 public class ServicioCifrado
9 {
10 public string Encriptar(string valor) { }
11 public string Desencriptar(string valor)
12 }

 Inline Class

Esta técnica es opuesta a la técnica Extract class ya que une dos clases en una
sola, esto aplica siempre y cuando la otra clase no es usada en más lugares.
Antes

1 public class ServicioNotificacion


2 {
3 public void EnviarNotificacionSuperisor(string mensaje) { }
4 public void EnviarNotificacionAdministrador(string mensaje) { }
5 }
6
7
8 public class ServicioCifrado
9 {
10 public string Encriptar(string valor) { }
11 public string Desencriptar(string valor)
12 }
Después

1 public class ServicioNotificacion


2 {
3 public void EnviarNotificacionSuperisor(string mensaje) { }
4 public void EnviarNotificacionAdministrador(string mensaje) { }
5 private string Encriptar(string valor) { }
6 private string Desencriptar(string valor)
7 }

 Encapsulate Field

Se aplica cuando un campo es expuesto a otras clases, en lugar de exponerlo


públicamente se debe encapsular dentro de una propiedad.

Antes

1 class Persona
2 {
3 public string nombre;
4 }
Después

1 class Persona
2 {
3 public string Nombre { get; set; }
4 }

 Encapsulate Collection

Se aplica cuando una propiedad retorna una colección, en su lugar se debe crear
un método que permita agregar nuevos elementos a la colección.

Antes

1 public class Estudiante


2 {
3 public string Nombre{ get; set; }
4 public List<Clase> Clases;
5 }
6
7 public class ServicioMatricula
8 {
9 public void MatricularEstudiante(Estudiante estudiante, Clase clase)
10 {
11 var listaClases = estudiante.Clases;
12 //Codigo
13 listaClases.Add(clase);
14 }
15 }
Después
1 public class Estudiante
2 {
3 private List<Clase> _clases = new List<Clas3>();
4 public string Nombre{ get; set; }
5
6 public IReadOnlyCollection<Clas3> Clases
7 {
8 get { return _clases.AsReadOnly(); }
9 }
10
11 public void InscribirseEnClase(Clase clase)
12 {
13 _clases.Add(clase);
14 }
15 }
16
17 public class ServicioMatricula
18 {
19 public void MatricularEstudiante(Estudiante estudiante, Clase clase)
20 {
21 estudiante.IncribirseEnClase(clase);
22 }
23 }
IVAN ROCA

 Extract Interface

Aplica cuando dos clases tienen interfaces similares.

Antes

1 class Poliza
2 {
3 public void CaducarPoliza(Poliza poliza)
4 {
5 //Codigo
6 if(Configuracion.EsSmsActiva)
7 {
8 EnviarNotificacionResponsableSms(poliza);
9 }
10 else {
11 EnviarNotificacionResponsableSmtp(poliza);
12 }
13 //Codigo
14 }
15
16 private void EnviarNotificacionResponsableSmtp(Poliza poliza)
17 {
18 ServicioNotificacionSmtp servicioNotificacion;
19 servicioNotificacion.EnviarNotificacion(mensaje);
20 }
21
22 private void EnviarNotificacionResponsableSms(Poliza poliza)
23 {
24 ServicioNotificacionSms servicioNotificacion;
25 servicioNotificacion.EnviarNotificacion(mensaje);
26 }
27 }
28
29 class ServicioNotificacionSmtp
30 {
31 public void EnviarNotificacion(Mensaje mensajeResponsable){}
32 }
33
34 class ServicioNotificacionSms
35 {
36 public void EnviarNotificacion(Mensaje mensajeResponsable){}
37 }
Después

1 class Poliza
2 {
3
4 private readonly IServicioNotificacion servicioNotificacion;
5
6 public Poliza(IServicioNotificacion servicioNotificacion)
7 {
8 servicioNotificacion = servicioNotificacion;
9 }
10
11 public void CaducarPoliza(Poliza poliza)
12 {
13 EnviarNotificacionResponsable(poliza);
14 }
15
16 private void EnviarNotificacionResponsable(Poliza poliza)
17 {
18 servicioNotificacion.EnviarNotificacion(mensaje);
19 }
20 }
21
22 class ServicioNotificacionSmtp : IServicioNotificacion
23 {
24 public void EnviarNotificacion(Mensaje mensajeResponsable){}
25 }
26
27 class ServicioNotificacionSms : IServicioNotificacion
28 {
29 public void EnviarNotificacion(Mensaje mensajeResponsable){}
30 }

 Extract SubClase

Aplica cuando una clase tiene algunos métodos o propiedades solo se usan en
ciertos casos.

Antes

1 class Poliza
2 {
3 public void RegistrarPoliza(Poliza poliza)
4 {
5 //Codigo
6 }
7
8 public void CaducarPoliza(Poliza poliza)
9 {
10 if (Tipo == TipoPoliza.Caducable)
11 {
12 //Codigo
13 }
14 }
15 }
Después

1 class Poliza
2 {
3 public void RegistrarPoliza(Poliza poliza)
4 {
5 //Codigo
6 }
7 }
8
9 class PolizaCaducable : Poliza
10 {
11 public void CaducarPoliza(Poliza poliza)
12 {
13 //Codigo
14 }
15 }

 Extract SuperClase

Esta técnica aplica cuando dos clases tienen características similares.


Antes

1 public class ServicioNotificacionAdministrador


2 {
3 private void Enviar(Notificacion notificacion, int tipo)
4 {
5 var smtp = CrearClienteSmtp();
6 AsignarCredenciales(smtp);
7 var formatoCorreo = ObtenerFormatoCorreo(notificacion);
8 var mensajeFinal = PrepararMensaje(formatoCorreo);
9 var mail = new MailMessage();
10 //Codigo
11 mail.Body = //Codigo
12 smtp.Send(mail);
13 }
14 }
15 public class ServicioNotificacionSupervisor
16 {
17 private void Enviar(Notificacion notificacion, int tipo)
18 {
19 var smtp = CrearClienteSmtp();
20 AsignarCredenciales(smtp);
21 var formatoCorreo = ObtenerFormatoCorreo(notificacion);
22 var mensajeFinal = PrepararMensaje(formatoCorreo);
23 var mail = new MailMessage();
24 //Codigo
25 mail.Body = //Codigo
26 smtp.Send(mail);
27 }
28 }
Después
1 public abstract class ServicioNotificacion<T>
2 {
3 protected abstract string ObtenerFormatoCorreo(T parametro);
4
5 private void Enviar(T notificacion)
6 {
7 var smtp = CrearClienteSmtp();
8 AsignarCredenciales(smtp);
9 var formatoCorreo = ObtenerFormatoCorreo(notificacion);
10 var mensajeFinal = PrepararMensaje(formatoCorreo);
11 var mail = new MailMessage();
12 //Codigo
13 mail.Body = mensajeFinal;
14 smtp.Send(mail);
15 }
16 }
17
18 public class ServicioNotificacionAdministrador :
19 ServicioNotificacion<NotificacionAdministrador>
20 {
21 protected override string ObtenerFormatoCorreo(NotificacionAdministrador parametro)
22 {
23 //Codigo
24 }
25 }
26
27 public class ServicioNotificacionSupervisor :
28 ServicioNotificacion<NotificacionSupervisor>
29 {
30 protected override string ObtenerFormatoCorreo(NotificacionSupervisor parametro)
31 {
32 //Codigo
33 }
34 }

 Hide Delegate

Esa técnica se aplica cuando un cliente llama a la propiedad de otra propiedad


dentro de la clase.

Antes

1 public class Empleado


2 {
3 public string Nombre { get; set; }
4 public Departamento Departamento { get; set; }
5 }
6
7 public class Cliente
8 {
9 public void Procesar(Empleado empleado)
10 {
11 var administrador = empleado.Departamento.Administrador;
12 }
13 }
Después

1 public class Empleado


2 {
3 public string Nombre { get; set; }
4 public Departamento Departamento { get; set; }
5
6 public Empleado Administrador
7 {
8 get { return this.Departamento.Administrador; }
9 }
10 }
11
12 public class Cliente
13 {
14 public void Procesar(Empleado empleado)
15 {
16 var administrador = empleado.Administrador;
17 }
18 }

 Replace Magic Numbers

Esta técnica se aplica cuando se tiene un valor en duro y no se sabe que significa.

Antes

1 var aplicaDescuento =
2 solicitud.Tipo == 2 && solicitud.Cantidad > 10 && solicitud.Precio < 100;
3 if (aplicaDescuento)
4 {
5 solicitud.Descuento = 0.5M;
6 }
Después

1 const int CantidadMaximaContraEntrega = 10;


2 const double PrecioMaximoContraEntrega = 10;
3 const double DescuentoContraEntrega = .5M;
4
5 var aplicaDescuento =
6 solicitud.Tipo == Tipo.SolicitudContraEntrega &&
7 solicitud.Cantidad > CantidadMaximaContraEntrega &&
8 solicitud.Precio < PrecioMaximoContraEntrega;
9 if (aplicaDescuento)
10 {
11 solicitud.Descuento = DescuentoContraEntrega ;
12 }

Conclusiones: Conocido informalmente como limpiar el código su objetivo es


mejorar la lectura del mismo para hacer más fácil su mantenimiento. Debemos tener
en cuenta que la primera versión de nuestro código no siempre será la mejor, la
refatorización debe realizarse poco a poco hasta encontrar el resultado esperado.
Se debe refactorizar cuando: necesitamos agregar nuevas funcionalidades,
corregimos bugs o revisamos el código; pero también necesitamos saber que si
estamos próximos a entregar el producto la refactorización puede agregar bugs sino
se prueba adecuadamente. Para refactorizar se necesita: revisar el código
frecuentemente, hacer un cheklist con los defectos encontrados, hacer pequeñas
refactorizaciones, ejecutar las pruebas unitarias y verificar los resultados.