window.pipedriveLeadboosterConfig = { base: 'leadbooster-chat.pipedrive.com', companyId: 11580370, playbookUuid: '22236db1-6d50-40c4-b48f-8b11262155be', versión: 2, } ;(function () { var w = window if (w.LeadBooster) { console.warn('LeadBooster ya existe') } else { w.LeadBooster = { q: [], on: function (n, h) { this.q.push({ t: 'o', n: n, h: h }) }, trigger: function (n) { this.q.push({ t: 't', n: n }) }, } } })() thecodest, Author at The Codest - Page 8 of 18

Por lo tanto, para algunos es incomprensible que refactorización es en realidad un área de la programación, y también una parte muy importante del trabajo del programador. El código está en constante evolución, se modificará siempre que exista la posibilidad de añadir nuevas funcionalidades. Sin embargo, puede adoptar una forma que ya no permita añadir eficazmente nuevas funcionalidades y sería más fácil reescribir todo el programa.

¿Qué es la refactorización?

Normalmente, la respuesta que se oye es que se trata de cambiar la estructura del código aplicando una serie de transformaciones de refactorización sin afectar al comportamiento observable del código. Esto es cierto. Recientemente, también me encontré con una definición de Martin Fowler en su libro "Mejorar el diseño del código existente" donde describe refactorización como "hacer grandes cambios en pequeños pasos". Describe refactorización como un cambio de código que no afecte a su funcionamiento, pero insiste en que debe hacerse en pequeños pasos.

El libro también defiende que refactorización no afecta al funcionamiento del código y señala que no tiene ningún efecto sobre la superación de las pruebas en ningún momento. Describe paso a paso cómo realizar de forma segura refactorización. Me gustó su libro porque describe trucos sencillos que se pueden utilizar en el trabajo diario.

¿Por qué es necesaria la refactorización?

 La mayoría de las veces, puede necesitarlo cuando quiere introducir una nueva funcionalidad y el código en su versión actual no lo permite o sería más difícil sin cambios en el código. También es útil en casos en los que añadir más funcionalidades no es rentable en términos de tiempo, es decir, sería más rápido reescribir el código desde cero. Creo que a veces se olvida que refactorización puede hacer que el código sea más limpio y legible. Martin escribe en su libro cómo realiza la refactorización cuando siente olores desagradables en el código y, cómo lo dice, "siempre deja espacio para lo mejor". Y aquí me sorprendió al ver la refactorización como un elemento del trabajo cotidiano con el código. Para mí, los códigos son a menudo incomprensible, la lectura es un poco de experiencia como el código es a menudo poco intuitivo.

El rasgo distintivo de un programa bien diseñado es su modularidadgracias a la cual basta con conocer sólo una pequeña parte del código para introducir la mayoría de las modificaciones. La modularidad también facilita la incorporación de nuevas personas y permite empezar a trabajar de forma más eficiente. Para lograr esta modularidad, los elementos relacionados del programa deben agruparse, y las conexiones deben ser comprensibles y fáciles de encontrar. No existe una única regla general sobre cómo hacerlo. A medida que se conoce y comprende mejor cómo debe funcionar el código, se pueden agrupar los elementos, pero a veces también hay que probar y comprobar.

Una de las reglas de refactorización en YAGNIes un acrónimo de "You Aren't Gonna Need It" (No lo vas a necesitar) y procede de Programación eXtrema (XP) utilizado principalmente en Ágil desarrollo de software equipos. Resumiendo, YAGNI dice que sólo se deben hacer cosas actualizadas. Esto significa básicamente que aunque algo pueda ser necesario en el futuro, no debe hacerse ahora. Pero tampoco podemos aplastar las ampliaciones posteriores y aquí es donde la modularidad cobra importancia.

Al hablar de refactorizaciónEn este sentido, hay que mencionar uno de los elementos más esenciales: las pruebas. En refactorizaciónnecesitamos saber que el código sigue funcionando, porque refactorización no cambia su funcionamiento, sino su estructura, por lo que todas las pruebas deben ser superadas. Es mejor ejecutar pruebas para la parte del código en la que estamos trabajando después de cada pequeña transformación. Nos da una confirmación de que todo funciona como debe y acorta el tiempo de toda la operación. Esto es lo que Martin habla en su libro - ejecutar pruebas tan a menudo como sea posible para no dar un paso atrás y perder el tiempo buscando una transformación que rompió algo.

Refactorización del código sin pruebas es un coñazo y hay muchas posibilidades de que algo salga mal. Si es posible, lo mejor sería añadir al menos algunas pruebas básicas que nos den un poco de seguridad de que el código funciona.

Las transformaciones enumeradas a continuación son sólo ejemplos, pero resultan realmente útiles en la programación diaria:

Ejemplo

Este es un artículo sobre refactorización y se necesita un ejemplo. A continuación quiero mostrar un ejemplo sencillo de refactorización con el uso de Anulación de la declaración anidada y Sustitución del polimorfismo de instrucción condicional. Supongamos que tenemos una función de programa que devuelve un hash con información sobre cómo regar las plantas en la vida real. Dicha información probablemente estaría en el modelo, pero para este ejemplo, la tenemos en la función.

def riego_info(planta)
     resultado = {}
     if planta.¿es? Suculenta || plant.is_a? Cactus
         result = { cantidad_de_agua: "Un poco" , how_to: "Desde abajo", watering_duration: "2 semanas" }
     elsif plant.is_a? Alocasia | plant.is_a? Maranta
         result = { cantidad_de_agua: "Gran cantidad", how_to: "Como prefieras", watering_duration: "5 días" }
     elsif planta.is_a? Peperomia
         result = { cantidad_de_agua: "Cantidad dicente",
             how_to: "¡Desde abajo! no les gusta el agua en las hojas",
             watering_duration: "1 semana" }
     si no
         resultado = { cantidad_de_agua "Cantidad dicente",
             how_to: "Como prefieras",
             duración_del_riego: "1 semana"
             }
     end
     devolver resultado
 fin

La idea es cambiar si volver:

si planta.isa? Suculenta || ¿planta.isa? Cactus

     resultado = { wateramount: "Un poco" , howto: "Desde el fondo",

A

return { cantidad_de_agua: "Un poco " , como_hacer: "Desde abajo",duración_riego: "2 semanas" } if plant.is_a? Suculenta || plant.is_a? Cactus

devolver { aguacantidad: "Un poco " , cómoa: "Desde abajo", riegoduración: "2 semanas" } if plant.isa? Suculenta || plant.is_a? Cactus

Y así con todo, hasta llegar a una función parecida a ésta:

def riego_info(planta)

return resultado = { cantidad de agua: "Un poco " , howto: "Desde abajo", wateringduration: "2 semanas" } if planta.isa? Suculenta || plant.is_a? Cactus

return resultado = { cantidad de agua: "Cantidad grande", howto: "Como prefieras", wateringduration: "5 días" } if planta.isa? Alocasia || plant.is_a? Maranta

return resultado = { cantidad_de_agua: "Cantidad dicente",

          howto: "¡Desde abajo! no les gusta el agua en las hojas",
          wateringduration: "1 semana" } if plant.is_a? Peperomia

return resultado = { cantidad_de_agua: "Cantidad dicente",

          how_to: "Como prefieras",

          duración_del_riego: "1 semana"

          }

end

 Al final, ya teníamos un resultado de vuelta. Y un buen hábito es hacer esto paso a paso y probar cada cambio. Podrías sustituir este bloque if por un switch case y quedaría mejor inmediatamente, y no tendrías que comprobar todos los ifs cada vez. Se vería así:

def riego_info(planta)

swich planta.clase.a_cadena

case Suculenta, Cactus

     { cantidad de agua: "Un poco" , howto: "Desde abajo", watering_duration: "2 semanas" }

caso Alocasia, Maranta

     { wateramount: "Gran cantidad", howto: "Como prefieras", duración_riego: "5 días" }

caso Peperomia

     { cantidad_agua: "Cantidad dicente",

          cómo: "¡Desde abajo! No les gusta el agua en las hojas",

          watering_duration: "1 semana" }

si no

     { cantidad_de_agua: "Cantidad dicente",

            how_to: "Como prefieras",

       duración_del_riego: "1 semana" }

end

fin

Y luego puede aplicar el Sustitución del polimorfismo de instrucción condicional. Se trata de crear una clase con una función que devuelva el valor correcto y los conmute en sus lugares adecuados.

clase Suculenta

...

def riego_info()

     return { cantidad de agua: "Un poco " , howto: "Desde abajo", watering_duration: "2 semanas" }

end

end

clase Cactus

...

def riego_info()

     return { cantidad de agua: "Un poco " , howto: "Desde abajo", watering_duration: "2 semanas" }

end

end

clase Alocasia

...

def información_de_riego

     return { cantidad de agua: "Cantidad grande", como: "Como prefieras", watering_duration: "5 días" }

end

fin

clase Maranta

...

def riego_info

     return { cantidad de agua: "Cantidad grande", como: "Como prefieras", watering_duration: "5 días" }

end

fin

clase Peperomia

...

def riego_info

     return { cantidad_agua: "Cantidad dicente",

      how_to: "¡Desde abajo! no les gusta el agua en las hojas",

      watering_duration: "1 semana" }

end

fin

clase Planta

...

def información_de_riego

     return { cantidad_agua: "Cantidad dicente",

              how_to: "Como prefieras",

              duración_del_riego: "1 semana" }

end

fin

Y en la watering_infofunction principal, el código tendrá este aspecto:

def riego_info(planta)

    plant.map(&:watering_info)

fin

Por supuesto, esta función puede eliminarse y sustituirse por su contenido. Con este ejemplo, quería presentar el general patrón de refactorización.

Resumen

Refactorización es un gran tema. Espero que este artículo haya sido un incentivo para leer más. Estos habilidades de refactorización te ayudarán a detectar tus errores y a mejorar tu taller de código limpio. Recomiendo leer el libro de Martin (Improving the Design of Existing Code), que es un conjunto bastante básico y útil de reglas de refactorización. El autor muestra varias transformaciones paso a paso con una explicación completa y motivación y consejos sobre cómo evitar errores en refactorización. Debido a su versatilidad, es un libro delicioso para frontend y desarrolladores backend.

Conviértete en Desarrollador Ruby Junior

Seguir leyendo

GraphQL Ruby. ¿Y el rendimiento?

Ferrocarriles y otros medios de transporte

Desarrollo Rails con TMUX, Vim, Fzf + Ripgrep

es_ESSpanish