Clean Code #9: Código Duplicado

El código duplicado es otro tipo de code smell que debemos evitar. Si el código está duplicado, debemos modificarlo, tendríamos que hacerlo en todos lados. Esto podría generar que algunos métodos que lo consumen funcionen de forma incorrecta por olvidarnos modificar uno. Por otra parte, genera un código ruidoso y difícil de entender. Para esto nos basaremos en el principio DRY (Don’t Repeat Yourselft).

Veamos un ejemplo, tendremos 2 métodos que duplican la lógica en sus implementaciones. Hacen lo mismo 2 veces.

public class HotelReservation
    {
        public void AdmitGuest(string name, string admissionDateTime)
        {
            // logic 
            // ...

            int time;
            int hours = 0;
            int minutes = 0;
            if (!string.IsNullOrWhiteSpace(admissionDateTime))
            {
                if (int.TryParse(admissionDateTime.Replace(":", ""), out time))
                {
                    hours = time / 100;
                    minutes = time % 100;
                }
                else
                {
                    throw new ArgumentException("Bad Admission DateTime");
                }

            }
            else
                throw new ArgumentNullException("Bad Admission DateTime");

            // more logic 
            // ...
            if (hours < 10)
            {

            }
        }

        public void UpdateAdmission(int admissionId, string name, string admissionDateTime)
        {
            // Some logic 
            // ...

            int time;
            int hours = 0;
            int minutes = 0;
            if (!string.IsNullOrWhiteSpace(admissionDateTime))
            {
                if (int.TryParse(admissionDateTime.Replace(":", ""), out time))
                {
                    hours = time / 100;
                    minutes = time % 100;
                }
                else
                {
                    throw new ArgumentException("Bad Admission DateTime");
                }
            }
            else
                throw new ArgumentNullException("Bad Admission DateTime");

            // Some more logic 
            // ...
            if (hours < 10)
            {

            }
        }
    }

Extraemos este bloque de código en un nuevo método que se llama GetTime. Como necesitamos hours y minutes haremos que el método tenga 2 parámetros de salida.

public void UpdateAdmission(int admissionId, string name, string admissionDateTime)
        {
            // Some logic 
            // ...
            int time;
            int hours = 0;
            int minutes = 0;

            GetTime(out hours, admissionDateTime, out minutes);
            
            // Some more logic 
            // ...
            if (hours < 10)
            {

            }
        }

        public void GetTime(out int hours, string admissionDateTime, out int minutes){

            if (!string.IsNullOrWhiteSpace(admissionDateTime))
            {
                if (int.TryParse(admissionDateTime.Replace(":", ""), out time))
                {
                    hours = time / 100;
                    minutes = time % 100;
                }
                else
                {
                    throw new ArgumentException("Bad Admission DateTime");
                }
            }
            else
                throw new ArgumentNullException("Bad Admission DateTime");

        }

Lo próximo es deshacernos de los parámetros de salida del método GetTime. Estos podemos transformarlo en una tupla personalizada. Crearemos una nueva clase Time.

 public class Time{
            public int Hours { get; set; }
            public int Minutes { get; set; }

            public Time(int hours, int minutes)
            {
                Hours = hours;
                Minutes = minutes;
            }
        }

Ahora nuestro método GetTime devolverá Time

public Time GetTime(string admissionDateTime){

            int hours = 0;
            int minutes = 0;

            if (!string.IsNullOrWhiteSpace(admissionDateTime))
            {
                if (int.TryParse(admissionDateTime.Replace(":", ""), out time))
                {
                    hours = time / 100;
                    minutes = time % 100;
                }
                else
                {
                    throw new ArgumentException("Bad Admission DateTime");
                }
            }
            else
                throw new ArgumentNullException("Bad Admission DateTime");

            return new Time(hours, minutes);

        }

Luego cambiaremos en el método el nombre de la variable para que se más significativo.

public void UpdateAdmission(int admissionId, string name, string admissionDateTime)
        {
            // Some logic 
            // ...
            var time =  GetTime(admissionDateTime);
            var hours = time.Hours;
            var minutes = time.Minutes;

....

Ahora podemos remover las variables innecesarias:

 public void UpdateAdmission(int admissionId, string name, string admissionDateTime)
        {
            // Some logic 
            // ...
            var time =  GetTime(admissionDateTime);
             
            // Some more logic 
            // ...
            if (hours < 10)
            {

            }
        }

Nos hemos deshecho de nuestro código duplicado, pero ahora, ¿Qué más debemos hacer? Si vemos el método GetTime, es un método de tiempo. ¿Debería estar en este lugar? Si, si este método no sabe nada de lo que hace en esta clase. La lógica pertenece a otro contexto y esto quiere decir que pertenece a una clase distinta. Por esto, lo moveremos a una nueva clase que llamaremos Time. Luego, refactorizaremos nuestros métodos para que llamen a esta clase y a ese método que movimos.

public void UpdateAdmission(int admissionId, string name, string admissionDateTime)
{
    // Some logic 
    // ...
    var time =  Time.GetTime(admissionDateTime);
        
    // Some more logic 
    // ...
    if (hours < 10)
    {

    }
}

Algo más que debemos modificar es el nombre del Método. Se llama GetTime, pero un mejor nombre seria Parse porque le estamos pasando una cadena y debe ser convertido al objeto Time. Cada vez que tenemos que pasar un parámetro para convertirlo en un tipo distinto deberíamos llamarlo Parse. También, el nombre del parámetro no tiene por qué saber que es, por eso lo cambiaremos a str.

public Time Parse(string str){

            int hours = 0;
            int minutes = 0;

Conclusión

Si lo notaron, hay otro code smell en nuestro método. ¿Cuál? tenemos un if dentro de un if. Se los dejo para pensar. Siempre que veamos código duplicado siempre debemos pensar en el Principio DRY(Dont’t Repeat Yourself).

En el próximo post veremos Comentarios. Algo muy interesante y casi innecesario en la actualidad.

0 0 votos
Valora la Publicación
Suscribirse
Notificación de
guest
0 Comentarios
Más votados
Nuevos Viejos
Feedback en línea
Ver todos los Comentarios

Comentarios Recientes

0
Nos encantaría conocer tu opinión: ¡comenta!x
Ir a la barra de herramientas