language-agnostic - refactory - refactorizar sinonimo
¿Cómo se refactoriza una gran base de código desordenada? (14)
Tengo un gran lío de código. Es cierto que lo escribí yo mismo hace un año. No está bien comentado, pero tampoco es muy complicado, así que puedo entenderlo, pero no lo suficiente como para saber por dónde empezar en cuanto a la refacturación.
Violé todas las reglas que he leído durante el año pasado. Hay clases con múltiples responsabilidades, hay accesos indirectos (me olvido del término - algo así como foo.bar.doSomething()
), y como he dicho, no está bien comentado. Además de eso, es el comienzo de un juego, por lo que los gráficos se combinan con los datos, o los lugares donde intenté desacoplar gráficos y datos, publiqué los datos para que los gráficos puedan acceder a los datos. necesita...
¡Es un gran desastre! ¿Dónde empiezo? ¿Cómo comenzarías en algo como esto?
Mi enfoque actual es tomar variables y cambiarlas a privadas y luego refactorizar las piezas que se rompen, pero eso no parece ser suficiente. ¡Sugiera otras estrategias para atravesar este desastre y convertirlo en algo limpio para poder continuar donde lo dejé!
Actualización dos días después: he estado dibujando diagramas tipo UML de mis clases, y atrapé algunas de las "Frutas colgantes bajas" en el camino. Incluso encontré algunas partes de código que fueron el comienzo de nuevas funciones, pero como estoy tratando de reducir todo, he podido eliminar esos bits y hacer que el proyecto se sienta más limpio. Probablemente voy a refactorizar todo lo posible antes de manipular mis casos de prueba (¡pero solo las cosas que están 100% seguras de no afectar la funcionalidad, por supuesto!), Para que no tenga que refactorizar casos de prueba como yo cambiar la funcionalidad (¿Cree que lo estoy haciendo bien o, en su opinión, sería más fácil para mí aspirarlo y escribir las pruebas primero?)
¡Vote por la mejor respuesta para que pueda marcarla justamente! Siéntase libre de agregar su propia respuesta al grupo también, ¡todavía hay lugar para usted! Lo daré un día más o menos y luego probablemente marque la respuesta más votada como aceptada.
¡Gracias a todos los que han respondido hasta ahora!
25 de junio de 2010: descubrí una publicación de blog que responde directamente a esta pregunta de alguien que parece tener una buena comprensión de la programación: (o tal vez no, si lees su artículo :))
Con ese fin, hago cuatro cosas cuando necesito refactorizar el código:
- Determine cuál era el propósito del código
- Dibujar UML y diagramas de acción de las clases involucradas
- Compare los patrones de diseño correctos
- Determinar nombres más claros para las clases y métodos actuales
Compre un IDE que tenga un buen soporte de refactorización. Creo que IntelliJ es el mejor, pero Eclipse lo tiene ahora también.
La idea de la prueba unitaria también es clave. Querrá tener un conjunto de grandes transacciones globales que le den el comportamiento general del código.
Una vez que los tenga, comience a crear pruebas unitarias para clases y paquetes más pequeños. Escriba las pruebas para demostrar el comportamiento adecuado, realice los cambios y vuelva a ejecutar las pruebas para demostrar que no ha roto todo.
Haga un seguimiento de la cobertura del código sobre la marcha. Querrá trabajarlo hasta en un 70% o más. Para las clases que cambia, querrá que sean un 70% o mejores antes de realizar los cambios.
Acumula esa red de seguridad a lo largo del tiempo y podrás refactorizar con cierta confianza.
Creo que debería usar Eclipse como un IDE porque tiene muchos complementos y es gratuito. Ahora debe seguir el patrón MVC y sí debe escribir casos de prueba usando JUnit.Eclipse también tiene un complemento para JUnit y también proporciona la función de refactorización de código. así que eso reducirá su trabajo. Y recuerde siempre que escribir un código no es importante, lo principal es escribir código limpio. Por lo tanto, presente comentarios en todas partes para que no solo usted, sino cualquier otra persona, lea el código mientras lee el código. debe sentir que está leyendo un ensayo.
Elija una copia de Refactoring de Martin Fowler. Tiene algunos buenos consejos sobre cómo desglosar el problema de refactorización. Alrededor del 75% del libro son pequeños pasos de refactorización al estilo libro de cocina que puede hacer. También recomienda pruebas de unidad automatizadas que puede ejecutar después de cada paso para demostrar que su código aún funciona.
En cuanto a un lugar para comenzar, me sentaría y dibujaría una arquitectura de alto nivel de su programa. No tiene que ser elegante con modelos detallados de UML, pero algunos UML básicos no son una mala idea. Necesitas una idea general de cómo encajan las piezas principales para que puedas ver visualmente dónde se producirá el desacoplamiento. Solo una o dos páginas de algunos diagramas de bloques básicos te ayudarán con la sensación abrumadora que tienes ahora.
Sin algún tipo de especificación o diseño de alto nivel, solo corre el riesgo de perderse de nuevo y terminar con otro desastre inmanejable.
Si necesita comenzar desde cero, recuerde que nunca realmente comienza desde cero. Usted tiene algún código y el conocimiento que obtuvo de su primera vez. Pero a veces ayuda comenzar con un proyecto en blanco y extraer cosas sobre la marcha, en lugar de apagar incendios en una base de código desordenado. Solo recuerda no tirar por completo lo viejo, usarlo para sus partes buenas y tirar de ellas a medida que avanzas.
Es posible que desee consultar el libro Refactoring Martin Fowler. Este es el libro que popularizó el término y la técnica (mi pensamiento al tomar su curso: "He estado haciendo mucho de esto todo el tiempo, no sabía que tenía un nombre"). Una cita del enlace:
La refactorización es una técnica controlada para mejorar el diseño de una base de código existente. Su esencia es aplicar una serie de pequeñas transformaciones para preservar el comportamiento, cada una de las cuales es "demasiado pequeña para que valga la pena". Sin embargo, el efecto acumulativo de cada una de estas transformaciones es bastante significativo. Al hacerlo en pequeños pasos, reduce el riesgo de introducir errores. También evitará que se rompa el sistema mientras lleva a cabo la reestructuración, lo que le permite refactorizar gradualmente un sistema durante un período de tiempo prolongado.
Como han señalado otros, las pruebas unitarias te permitirán refactorizar con confianza. Y comience por reducir la duplicación de código. El libro te dará muchas otras ideas.
Aquí hay un catálogo de refactorizaciones .
Estás en una posición mucho mejor que muchas personas que enfrentan este problema, ya que entiendes lo que se supone que debe hacer el código.
Extraer variables de un alcance compartido, como lo está haciendo, es un gran comienzo, en el sentido de que está repartiendo responsabilidades. En última instancia, desea que cada clase exprese una sola responsabilidad. Algunas otras cosas que podrías mirar:
- Los objetivos fáciles para la refactorización son códigos duplicados en muchos lugares y métodos largos.
- Si está administrando el estado de la aplicación mediante singleton estáticamente inicializados o algo peor, un estado global con el que todo está hablando, considere moverlo a un sistema de inicialización administrado (es decir, un marco de inyección de dependencia como Spring o Guice) o al menos asegúrese de que la inicialización no está enredado con el resto del código.
- Centralice y estandarice cómo está accediendo a los recursos externos, especialmente si tiene cosas como ubicaciones de archivos o direcciones URL codificadas.
La definición correcta de código desordenado es un código difícil de mantener y cambiar.
Para usar más definición matemática, puede verificar su código mediante las herramientas de métricas de código .
De esta manera, mantendrá el código que ya es lo suficientemente bueno y encontrará muy rápido el código incorrecto.
Mi experiencia dice que esa es una forma muy poderosa de mejorar la calidad de tu código. (si su herramienta puede mostrar el resultado en cada compilación o en tiempo real)
Lo que fue más importante para mí en diferentes ocasiones fueron las pruebas unitarias: me tomó unos días escribir pruebas para el código anterior y luego fui libre de refactorizar con confianza. Cómo exactamente es una pregunta diferente, pero tener las pruebas me permitió hacer cambios reales y sustanciales en el código.
Para el código Java, mi primer paso favorito es ejecutar Findbugs y luego eliminar todas las tiendas muertas, campos no utilizados, bloques de captura inalcanzables, métodos privados no utilizados y probables errores.
A continuación, ejecuto CPD para buscar evidencia de código de cortar, copiar y pegar.
No es inusual ser capaz de reducir la base del código en un 5% haciendo esto. También le ahorra código de refactorización que nunca se usa.
Siempre puedes comenzar desde "cero". Eso no significa descartarlo y comenzar de la nada, pero trata de reconsiderar las cosas de alto nivel desde el principio, ya que parece que has aprendido mucho desde la última vez que trabajaste en él.
Comience desde un nivel superior y, a medida que crea el andamio de su estructura nueva y mejorada, tome todo el código que pueda volver a utilizar, que probablemente será más de lo que cree si está dispuesto a leerlo y realizar algunos pequeños cambios.
Cuando realices los cambios, asegúrate de ser estricto contigo mismo respecto de seguir todas las buenas prácticas que conoces, porque de verdad te lo agradecerás más adelante.
Puede ser sorprendentemente refrescante rehacer el programa adecuadamente para hacer exactamente lo que hizo antes, solo que más "limpiamente". ;)
Como otros han mencionado también, ¡ las pruebas de unidad son su mejor amigo! Te ayudan a garantizar que tu refactorización funcione, y si comienzas desde cero, es el momento perfecto para escribirlas.
Solo una refactorización adicional que es más importante de lo que piensas: ¡nombra las cosas correctamente!
Esto se aplica a cualquier nombre de variable y nombre de método. Si el nombre no refleja con precisión para qué se utiliza la cosa, cámbiele el nombre a algo más preciso. Esto podría requerir varias iteraciones. Si no puede encontrar un nombre breve y totalmente preciso, entonces ese elemento es demasiado y tiene un excelente candidato para un fragmento de código que debe dividirse. Los nombres también indican claramente dónde se realizarán los cortes.
Además, documenta tus cosas. ¿Siempre la respuesta a POR QUÉ? no se transmite claramente por la respuesta a ¿CÓMO? (siendo el código) necesitarás agregar cierta documentación. Capturar decisiones de diseño es probablemente la tarea más importante, ya que es muy difícil de hacer en el código.
Tíralo, contrólalo nuevo.
Voy a poner en segundo lugar las recomendaciones de todos para Refactorización de Fowler, pero en su caso específico es posible que desee ver el trabajo eficaz de Michael Feathers con Legacy Code , que es realmente perfecto para su situación.
Feathers habla sobre las pruebas de caracterización , que son pruebas unitarias para no afirmar el comportamiento conocido del sistema, sino para explorar y definir el comportamiento existente (incierto) en el caso en que haya escrito su propio código heredado y lo haya arreglado usted mismo, este puede que no sea tan importante, pero si su diseño es descuidado, entonces es muy posible que haya partes del código que funcionen por "magia" y su comportamiento no sea claro, incluso para usted; en ese caso, las pruebas de caracterización ayudarán.
Una gran parte del libro es la discusión sobre encontrar (o crear) uniones en su base de código: las costuras son "líneas de falla" naturales, si lo desea, donde puede penetrar en el sistema existente para comenzar a probarlo, y tirando hacia un mejor diseño. Difícil de explicar, pero vale la pena leerlo.
Hay un breve artículo donde Plumas da cuerpo a algunos de los conceptos del libro, pero realmente vale la pena buscarlo todo. Es uno de mis favoritos.
muy lentamente: D
No en serio ... da un paso a la vez. Por ejemplo, refacturar algo solo si le afecta o le ayuda a escribir el error / función actual en el que está trabajando ahora y no hace más que eso. Y antes de refactorizar asegúrese de tener algún tipo de prueba automatizada que se ejecute en cada compilación y que realmente pruebe lo que está escribiendo / refactorizando. Incluso si no tiene pruebas unitarias, nunca es demasiado tarde para comenzar a agregarlas a todos los códigos nuevos y modificados que se escriben. Con el tiempo, su base de código mejorará en pequeños incrementos diarios o semanales en lugar de empeorar, todo sin que usted haga montones monumentales de cambios.
En mi opinión personal y experiencia, no vale la pena simplemente refactorizar una base de código (heredada) en masa por el bien de refactorizar. En esos casos, lo mejor es comenzar de cero y hacerlo bien de nuevo (y muy raramente se le ofrece la oportunidad de hacer tal cosa). Por lo tanto, solo refactorizar incremental es el camino a seguir.
Refactorizar la fruta baja. Mordisquea los bits fáciles, y mientras haces eso, los trozos más duros comenzarán a ser un poco más fáciles. Cuando no quedan elementos para refactorizar, ya está listo.
Las refactorizaciones que probablemente le resulten más útiles son Renombrar método (e incluso Renombraciones más triviales como Campo, Variable y Parámetro), Extraer método y Extraer clase . Para cada refactorización que realice, escriba las pruebas unitarias necesarias para que la refactorización sea segura y ejecute todo el conjunto de pruebas unitarias después de cada refactorización. Es tentador, y seamos honestos, bastante seguros, confiar en las refactorizaciones automatizadas de su IDE, sin las pruebas, pero es una buena práctica y será bueno tener las pruebas en el futuro a medida que agrega funcionalidad a su proyecto.