maintenance - sencillos - spaghetti con hongos
Cómo guardar mi cordura mientras mantengo el código de espagueti (15)
Solo quería escuchar algunos consejos (y comodidad) que me ayudarán a controlar un código de espagueti complicado, que fue desarrollado por varios programadores (por lo general, que nunca se conocen) durante mucho tiempo. Las características de la solución están parcheadas una encima de la otra.
Por lo general tiendo a ver 2 tipos de programadores:
"Programadores del miedo a la muerte": esos tipos no tocarán nada que no tengan que tocar. probablemente completarán la tarea de mantenimiento con una solución rápida y sucia que hará que el próximo programador comience a buscar la dirección de su casa ;-)
pros:
funcionacontras:
Esperas no volver a ver este código ..."Profesores": esos probablemente reescribirán todo el código mientras restauran completamente su lógica.
pros:
Bueno, alguien tiene que hacer el trabajo sucio ...contras:
lleva más tiempo y probablemente una de las características más importantes desaparecerá mágicamente del producto
Será agradable escuchar tu experiencia personal desde este lado más oscuro de la vida del programador.
Estoy especialmente curioso de escuchar cualquier consejo teórico / práctico que me ayude a sumergirme en la tarea de mantenimiento de espaguetis sin sentirme tan miserable.
- Lo primero y más importante es obtener la ayuda de la administración, ya que es necesario mejorar el código para proporcionar valor comercial (como agregar características en el futuro es más fácil). Personalmente, he perdido horas preciosas mejorando la aplicación al final de la vida.
- Comprenda el dominio a fondo, ciertos tipos de dominios fomentan ciertos tipos de (anti) patrones ... ayudaría a comprender por qué las cosas son como son.
- Escribir pruebas en torno al código heredado me ayuda a explorar los diversos matices en la lógica de negocios que hicieron el lío del código que es ahora. Personalmente, nunca apunto a la cobertura de código con pruebas alrededor de código heredado (aunque es un enfoque generalmente predicado), solo te volverá loco.
Aquí es cómo abordé este problema mientras mantenía un sistema de Perl heredado de 10 años. Para dar un poco de historia, este fue uno de los peores de los peores. Inicialmente estaba deprimido cuando comencé a trabajar en la empresa porque el código estaba muy mal pensado y diseñado (y fue mi primer trabajo de programación). Sin embargo, al final de ese concierto tenía un sistema bastante bueno.
En primer lugar, cada nueva característica se agregó como un nuevo módulo o métodos. Nada fue hackeado encima del código existente. Esto me permitió escribir pruebas unitarias para las cosas nuevas, brindando confianza en ellas, de modo que integrarme con las cosas antiguas era solo una cuestión de una o dos líneas.
En segundo lugar, cualquier corrección de errores se implementó de la misma manera. Pasé un poco de tiempo descubriendo lo que estaba sucediendo con las cosas antiguas (no buscando el error), lo escribí como un nuevo método (o módulo) y lo envolví en pruebas, y luego, por lo general, podría reemplazar .
Sin embargo, esto solo funciona si tienes tiempo, y el buy-in para hacerlo. Si no lo hace, haga un seguimiento del tiempo que dedica a un error determinado. Especialmente donde hay varios errores en el mismo archivo, proceso o lo que sea. En algún momento, es fácil señalar una determinada colección de código y decir que esto es tan malo, ha costado N cantidad de tiempo, es hora de volver a escribir.
Tuve el suficiente éxito con este enfoque que obtuve el título honorario "Programador forense", y también es una habilidad fantástica, porque la mayoría de las veces el nuevo trabajo ya tiene un código escrito: P
Aunque nunca he hecho esto por mí mismo, el enfoque tiene mucho sentido. Escriba cargas de barcos de pruebas alrededor de la interfaz expuesta existente para asegurarse de que la funcionalidad no cambie cuando entre y refactorice los dickens de la implementación. Esto asegurará que cualquier refactorización no cambie la forma en que funciona la aplicación.
Bueno, tal vez esto encaja en mi caso, pero aquí va:
Teniendo en cuenta todas las sugerencias anteriores, si fuera a trabajar en un código heredado durante mucho tiempo, estaría limpiando el código sucio, muy suave, así que no lo rompería, si no, no lo haría. molestia
Bueno, tengo que tener en cuenta un sitio web de pesadilla escrito en coldfusion, javascripts, html y hacer uso de parejas de complementos ... Soy el único desarrollador que queda para esta aplicación. La última persona que mantiene el sitio web y la base de datos fue transferida. Estoy atrapado con esta bestia fea. Re factoré algunos archivos y funciones, pero siguen apareciendo problemas y errores.
Mi problema debería concentrarme en corregir errores o refactorizar, me gustaría dedicar tiempo a refactorizar por completo, en vez de atender una solicitud de cambio o errores.
Algunos archivos tienen 8k de líneas porque la versión anterior (no la versión real) mantuvo y copió y pegó trozos de código en lugar de separar las funcionalidades. Este es un código muy acoplado, un pequeño cambio en un archivo requerirá cambios en 4 o 5 lugares más.
Propuse dividir los sitios web en pequeñas unidades de partes manejables y reconstruirlas desde cero. Hasta ahora, no escuchan realmente, pero siguen preguntando por qué el sitio web es lento.
Llego de uno en uno extrayendo y probando el código del sitio web principal (localmente).
Documento. Documento a fondo. Cada cambio que realice, cada advertencia que descubra, cada lógica extraña fluya, cada vez que piense que "esto podría hacerse mejor", documéntelo.
Es la única forma de reducir la velocidad y, finalmente, eliminar la entropía sistemática sin una reescritura sustancial.
Estoy en medio de correcciones de errores para una aplicación de código heredado. Trato de no basarme nunca en los desarrolladores anteriores (especialmente porque todavía estoy aprendiendo). Todo lo que cambio hago comentarios extensos para poder encontrarlo nuevamente y para que la siguiente persona entienda cómo ha evolucionado el código.
Siempre trate de recordar que no puede conocer todas las circunstancias en las que se escribió el código. Si bien eso no necesariamente justifica una mala programación o lógica, sin duda mantendrá su presión arterial baja.
También tomo cada rasguño de cabeza que encuentro como una nueva oportunidad para aprender algo y / o probar algo nuevo.
He encontrado muchas veces que puedes separar grupos de espaguetis en al menos archivos fuente separados, a veces clases separadas, sin tener que volver a escribir ninguna lógica real. Si puedes robar algo de tiempo para solucionarlo de una o dos correcciones de errores, estarás muy por delante de donde empezaste.
Más adelante, cuando aparezcan más errores, es posible que puedas modularizar las cosas un poco mejor. Lentamente, puedes enderezar los espaguetis de esta manera.
Intento envolver el código heredado realmente malo en las pruebas antes de comenzar. ¡En serio, lo sofoco en las pruebas, para ser honesto! Entonces tengo algo de confianza en bucear en una refactorización donde necesito.
Te puede gustar leer
Portada del libro http://ecx.images-amazon.com/images/I/51RCXGPXQ8L._SL500_AA240_.jpg
La única forma que conozco es:
- pruebas de escritura
- refactor
- ejecutar las pruebas
- arreglar lo que está roto
- escribir pruebas para la nueva característica
- introducir nueva característica
- ejecutar las pruebas
- arreglar lo que está roto
Puedes vivirlo de esta manera.
NOTA : hay ocasiones en las que es realmente difícil probar el código de espagueti: métodos de 3Klines que generan HTML, DAOs enredados con lógica de negocios, clases fuertemente acopladas ... en este caso un buen IDE con refactorización automática (capaz de extraer métodos, para comenzar con) y algunas herramientas de prueba como Selenium pueden ser realmente útiles.
Sé que en una conocida compañía de seguros para la que solía hacer administrador de sistemas, el sistema de precios principal utilizado es un mainframe de 25 años llamado GenZ. Desde mediados de los años noventa, creo que un nuevo sistema ha estado en desarrollo y actualmente se está implementando en versión beta.
El mainframe, probablemente, funcionó perfectamente bien en la década de 1980, pero a medida que la empresa creció, se agregaron más datos y el sistema necesitaba retener más. Se aplicaron parches, ocurrieron más problemas y así ha sido durante años.
Actualmente, el sistema interactúa con al menos otras 200 aplicaciones utilizadas por dicha compañía de seguros, por lo que reemplazarlo será un trabajo muy difícil, y es probablemente la razón por la que se ha postergado durante tanto tiempo.
Ahora que se está implementando el nuevo sistema (llamado Maxx), se deberán eliminar varios cientos de aplicaciones.
La codificación deficiente no se trata de que los desarrolladores tengan miedo de hacer cosas que no se requieren, sino que, en su mayoría, no piensan lo suficiente en el futuro, piensan en los peores escenarios o piensan en lo que podría ser para los consumidores y empleados. y los desarrolladores en el futuro.
Si bien el mejor consejo es, como han señalado todos los demás pósteres sobre este tema, para escribir pruebas, a menudo he estado en una situación en la que esto no es realista. Si el código es tan malo (métodos de 1000 líneas, números mágicos incrustados y no documentados, duplicación de códigos, etc., etc.) también es probable que tenga otro problema, que es que está profundamente acoplado y que los componentes son casi imposibles de aislar.
(Ejemplos: una base de código que se carga y almacena en caché cientos de objetos de base de datos diferentes en el inicio. Los componentes suponen que existen partes aleatorias de la memoria caché, y las partes de la memoria caché suponen otras partes de la memoria caché: en otras palabras, usted debe cargar todo para obtener cualquier cosa: código dependiente de variables de estado estáticas y promiscuamente públicas, donde es imposible determinar quién está configurando esas variables, o incluso qué significan)
Las mejores sugerencias que se me ocurren:
- Trate de arreglar las cosas fáciles / obvias primero. Rutas codificadas, referencias de números mágicos, duplicación de código evidente. Quizás un lanzamiento rápido que elimine el peor 20% de las violaciones sea de bajo riesgo y haga que los próximos pasos sean más fáciles de realizar.
- Obtenga apoyo de la organización para el reparto de la marca: a menudo no hay voluntad o deseo de hacer un trabajo que no agregue funcionalidad inmediata y corra el riesgo de romper el código existente. Hay, por supuesto, grandes argumentos para refactorizar, pero no todos los compran. Si la organización no lo apoya, es posible que tenga que renunciar a él.
- Traiga a otros desarrolladores al mismo punto de vista: si son buenos, probablemente estén tan descontentos con el código base como usted. Si el nuevo código se construye con mejores estándares y la gente está motivada, comenzarán a corregir el código anterior a medida que se necesiten ajustes.
- Si un subsistema en particular es realmente malo realmente y ha llegado al punto en que un nuevo desarrollo es casi imposible, probablemente pueda aprovechar esta oportunidad para reconstruirlo.
Toma lo mejor de ambos. Organice su proyecto en partes lógicas, preferiblemente utilizando un diagrama de clase UML de ingeniería inversa, y vea dónde están las interconexiones. Cualquier cosa que esté floja conectada es ideal para un refactor. En cualquier tiempo de inactividad, inspeccione también las conexiones fuertes y vea qué grupos se pueden dividir completamente en módulos separados con la menor cantidad de cambios. Averigüe qué está pasando realmente a un alto nivel antes de reescribirlo todo.
salselo :)
Si eso no es una opción, bueno ... primero, trata de hacer cara y cola. Para las cosas que he tratado, esta es a menudo la parte más difícil. Puede crear UML manualmente, puede usar algunas de las herramientas comerciales de "ingeniería inversa" del código fuente, o simplemente puede rastrear el código.
Cuando comprendas el código, es hora de refactorizar. Planea bien. Intenta escribir un montón de pruebas decentes. Luego pase por un enfoque iterativo de refactorización, redacción de pruebas adicionales y verificación (¡en funcionamiento!) De las modificaciones en el control de origen.
Dependiendo de cuán masoquista seas, esto puede ser muy divertido o tu propio infierno personal :)
- Sé lento y deliberado.
- Escribe pruebas cuando puedas, pero no te desanimes cuando no puedas. El código de espagueti es raramente un código comprobable.
- Recuerde que todos los que editaron el código antes de usted tenían una buena razón para hacer lo que hicieron. Asume lo mejor de ellos, y probablemente serás recompensado.
- Comprende el código antes de intentar cambiar el código.
- Tome notas a medida que aprende y manténgalas actualizadas mientras trabaja. Guárdalos y compártelos en un wiki si puedes.
- Use un sistema de control de revisión, haga cada cambio lo más pequeño y centrado posible, y regístrese con la mayor frecuencia posible.
- No muerdas más de lo que puedes masticar. A medida que realice un cambio, sin duda encontrará algo más que debe limpiarse. Agréguelo a su lista de tareas y manténgase enfocado en su misión original.
- Trate el proyecto como un lugar para acampar: déjelo en mejores condiciones de lo que lo encontró. Y recuerda que "mejor" es relativo; No puedes arreglar todo de una vez.