code design – Caso Practico – Refactorización Parte1

Refactoring spaghetti code
Refactoring spaghetti code

Artículos relacionados

Introducción

Ahora nos toca poner en práctica todo lo que se vio en el artículo anterior y principios de diseño, como SOLID, para mejorar el código de ejemplo que analizaremos en este caso. La idea es aplicar la mayoría de las técnicas de refactorización descritas anteriormente:

  • Rename Method
  • Introduce Explaining Variable
  • Inline Temp
  • Split Temp Variable
  • Replace Temp With Query
  • Extract Method
  • Inline Method
  • Move Method
  • Extract Class
  • Inline Class
  • Encapsulate Field
  • Encapsulate Collection
  • Extract Interface
  • Extract SubClase
  • Extract SuperClase
  • Hide Delegate
  • Replace Magic Numbers

Finalmente, para ver el resultado obtenido con la refactorización y las mejoras hechas sobre este código usaremos las métricas que nos brinda el Visual Studio con el Code Metrics.

Para descargar el código haz clic acá.

1. Escenario: Registro de solicitud

En este ejercicio tenemos la clase FormularioSolicitud con el método Registrar que se encarga de guardar una solicitud en un repositorio, dentro de este método se realizan las siguientes tareas: evaluar el responsable, validar los archivos a guardar, calcular el descuento y ejecutar algunas acciones según el tipo de solicitud. Como veremos el código no es largo, pero si es muy complicado de leer ya que dentro tiene muchas malas prácticas recopiladas que más de uno sentirá que ya las ha visto en otros proyectos.

Código
public class FormularioSolicitud
{

    public void Registrar(Solicitud solicitud)
    {
        try
        {

            if (solicitud.FechaEnvio.Year > DateTime.Now.Year)
            {
                if (solicitud.Cantidad > 1000)
                {
                    if (solicitud.Tipo == 1)
                    {
                        solicitud.RolResponsable = "Responsable1";
                    }
                    else
                    {
                        solicitud.RolResponsable = "Responsable2";
                    }
                }
                else
                {
                    solicitud.RolResponsable = "Supervisor";
                }
            }
            else
            {
                solicitud.RolResponsable = "Administrador";
            }


            #region Validacion de archivo

            var erroresArchivos = string.Empty;

            foreach (var archivo in solicitud.ArchivosAdjuntos)
            {
                try
                {
                    if (ExisteArchivo(archivo.Ruta))
                    {

                        if (!ValidarArchivo(archivo.Ruta))
                        {
                            throw new ApplicationException("Extension no valida");
                        }

                        #region Obtener tipo mime

                        var extension = Path.GetExtension(archivo.Ruta);

                        switch (extension)
                        {
                            case ".pdf":
                                archivo.Mime = "application/pdf";
                                break;
                            case ".txt":
                                archivo.Mime = "text/plain";
                                break;
                            case ".xls":
                                archivo.Mime = "application/excel";
                                break;
                            case ".doc":
                                archivo.Mime = "application/msword";
                                break;
                            default:
                                archivo.Mime = "application/mime";
                                break;
                        }

                        #endregion
                    }
                }
                catch (ApplicationException exApp)
                {
                    erroresArchivos += exApp.Message;
                }
                catch (FileNotFoundException exFile)
                {
                    erroresArchivos += exFile.Message;
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }

            if (!string.IsNullOrWhiteSpace(erroresArchivos))
            {
                throw new ApplicationException("Verifique los archivos");
            }

            #endregion

            if (solicitud.Tipo == 2 && solicitud.Cantidad > 10 && solicitud.Precio > 100)
            {
                solicitud.Descuento = 0.5M;
            }
            else
            {
                solicitud.Descuento = 0M;
            }

            switch (solicitud.Tipo)
            {
                case 1:
                    EnviarCorreo(solicitud.Tipo);
                    CalcularSolicitudes(solicitud.Tipo);
                    //Codigo
                    ActivarBanderas(solicitud.Tipo);
                    break;
                case 2:
                    EnviarCorreo(solicitud.Tipo);
                    //Codigo
                    DesactivarBanderas(solicitud.Tipo);
                    break;
                case 3:
                    EnviarCorreo(solicitud.Tipo);
                    //Codigo
                    ActivarBanderas(solicitud.Tipo);
                    break;
                default:
                    EnviarCorreo(solicitud.Tipo);
                    //Codigo
                    CalcularSolicitudes(solicitud.Tipo);
                    DesactivarBanderas(solicitud.Tipo);
                    break;
            }

            var repositorioSolicitud = new RepositorioSolicitud();
            repositorioSolicitud.Guardar(solicitud);
        }
        catch (Exception ex)
        {
            var mensaje = ex.Message + "\n";
            mensaje += ex.Source + "\n";
            mensaje += ex.StackTrace + "\n";
            File.WriteAllText("c:\\logs\\logError.txt", mensaje);
        }
    }

    private void EnviarCorreo(int tipo)
    {
        //Codigo
    }

    private void CalcularSolicitudes(int tipo)
    {
        //Codigo
    }

    private void DesactivarBanderas(int tipo)
    {
        //Codigo
    }

    private void ActivarBanderas(int tipo)
    {
        //Codigo
    }

    #region Validacion de archivo

    private bool ExisteArchivo(string ruta)
    {
        if (!File.Exists(ruta)) throw new FileNotFoundException("El archivo no existe");
        return true;
    }

    private bool ValidarArchivo(string a2)
    {
        var a1 = Path.GetExtension(a2);

        if (a1 == ".pdf" || a1 == ".txt" || a1 == ".xls" || a1 == ".doc")
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    #endregion

}

2. Análisis de código – VS Code Metrics

Para saber si nuestras técnicas de refactorización tienen efecto o no sobre el código de ejemplo, y para saber que tanto mejora o no el código, tomaremos como linea base el resultado del análisis del VS Code Metrics.

Code Metrics Taller refactoring
Code Metrics Taller refactoring

En la imagen superior vemos el resultado que arrojo el análisis de código del método Registrar:

  • Indice de mantenimiento: 36
  • Complejidad ciclomática: 23
  • Acoplamiento de clase: 13
  • Lineas de código: 61

El objetivo de este ejercicio es aumentar el índice de mantenimiento y disminuir la complejidad ciclomática, el acoplamiento y las líneas de código. En la siguiente artículo veremos el resultado final.

NOTA: Les dejo de tarea que cada uno aplique sus técnicas de refactorización sobre este código y pueda compartir sus resultados 🙂 en los comentarios.

Referencias:
Metal Tip:

Este artículo lo escribí escuchando la canción Brothers of Metal de la banda Manowar de EEUU, les comparto el enlace.

Happy coding and Stay Heavy lml

Anuncios

4 comentarios en “code design – Caso Practico – Refactorización Parte1

  1. Me parace excelente, pero podrias explicar brevemente lo que deberia de hacer el proyecto o cual es el objetivo ya que no entiendo a que se refiere el uso de la variable “Tipo” y para poder hacer la refactorizacion ya que asi no tengo idea del alcanse.

    Me gusta

    1. Hola Alex, podemos asumir en este ejemplo que necesitamos registrar una solicitud y el Tipo se refiere a los posibles tipos de solicitudes que se puedan registrar, tampoco me puse a pensar mucho en ese tipo :P.

      Le gusta a 1 persona

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s