0

Clean Code #09 (2nd Edition): 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 no 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 tengo 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 un 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 variable 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, ¿Que 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 un 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 porque 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. ¿Cual? tenemos un if dentro de un if. Se los dejo para pensar. Siempre que veamos código duplicado siempre debemos en pensar en el Principio DRY(Dont’t Repeat Yourself).

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

Fernando Sonego

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *