it-swarm-es.com

¿Cuándo es un GRAN reescribir la respuesta?

Acabo de leer el pregunta sobre las grandes reescrituras y recordé una pregunta que quería responder.

Tengo un proyecto horrible que se me transmitió, escrito en Java antiguo, usando Struts 1.0, tablas con relaciones inconsistentes, o ninguna relación en absoluto, e incluso tablas sin claves primarias o campos destinados a ser claves primarias, pero no son únicos en absoluto. De alguna manera, la mayor parte de la aplicación "simplemente funciona". La mayoría de las páginas se reutilizan (copia el código pegado) y están codificadas. Todos los que han trabajado en el proyecto lo han maldecido de una forma u otra.

Ahora había considerado durante mucho tiempo proponer a la alta gerencia una reescritura total de esta horrenda aplicación. Poco a poco intento hacerlo en tiempo personal, pero realmente siento que esto merece algunos recursos dedicados para que esto suceda. Después de leer los artículos sobre grandes reescrituras, tengo dudas. Y eso no es bueno cuando quiero convencer a mis superiores de apoyar mi reescritura. (Trabajo en una empresa bastante pequeña, por lo que la propuesta tiene la posibilidad de ser aprobada)

TL; DR ¿Cuándo es una gran reescritura de la respuesta y qué argumentos puede usar para apoyarla?

288
Jonn

Lo sentimos, esto va a ser largo, pero se basa en la experiencia personal como arquitecto y desarrollador en múltiples proyectos de reescritura.

Las siguientes condiciones deberían hacer que considere algún tipo de reescritura. Hablaré sobre cómo decidir cuál hacer después de eso.

  • El tiempo de aceleración del desarrollador es muy alto. Si se necesita más tiempo que por debajo (por nivel de experiencia) para aumentar un nuevo desarrollador, entonces el sistema debe ser rediseñado. Por tiempo de aceleración, me refiero a la cantidad de tiempo antes de que el nuevo desarrollador esté listo para realizar su primer compromiso (en una función pequeña)
    • Recién salido de la universidad - 1.5 meses
    • Todavía verde, pero he trabajado en otros proyectos antes - 1 mes
    • Nivel medio - 2 semanas
    • Experimentado - 1 semana
    • Nivel sénior - 1 día
  • La implementación no se puede automatizar debido a la complejidad de la arquitectura existente.
  • Incluso las correcciones de errores simples toman demasiado tiempo debido a la complejidad del código existente
  • Las nuevas funciones tardan demasiado y cuestan demasiado debido a la interdependencia de la base de código (las nuevas funciones no pueden aislarse y, por lo tanto, afectan las funciones existentes)
  • El ciclo de prueba formal lleva demasiado tiempo debido a la interdependencia de la base de código existente.
  • Se ejecutan demasiados casos de uso en muy pocas pantallas. Esto causa problemas de capacitación para los usuarios y desarrolladores.
  • La tecnología que tiene el sistema actual lo exige
    • Los desarrolladores de calidad con experiencia en la tecnología son demasiado difíciles de encontrar.
    • Está en desuso (no se puede actualizar para admitir plataformas/características más nuevas)
    • Simplemente hay una tecnología de nivel superior mucho más expresiva disponible
    • El costo de mantener la infraestructura de la tecnología anterior es demasiado alto.

Estas cosas son bastante evidentes. Cuándo decidir sobre una reescritura completa versus una reconstrucción incremental es más subjetivo y, por lo tanto, tiene más carga política. Lo que puedo decir con convicción es que decir categóricamente que es nunca una buena idea está mal.

Si un sistema puede rediseñarse de forma incremental y tiene el pleno apoyo del patrocinio del proyecto para tal cosa, entonces debe hacerlo. Aquí está el problema, sin embargo. Muchos sistemas no pueden ser rediseñados de forma incremental. Estas son algunas de las razones que he encontrado para evitar esto (tanto técnico como político).

  • Técnico
    • El acoplamiento de componentes es tan alto que los cambios en un solo componente no pueden aislarse de otros componentes. Un rediseño de un solo componente da como resultado una cascada de cambios no solo en los componentes adyacentes, sino indirectamente en todos los componentes.
    • La pila de tecnología es tan complicada que el diseño de estado futuro requiere múltiples cambios de infraestructura. Esto también sería necesario en una reescritura completa, pero si se requiere en un rediseño incremental, entonces pierde esa ventaja.
    • Rediseñar un componente resulta en una reescritura completa de ese componente de todos modos, porque el diseño existente es tan fubar que no hay nada que valga la pena guardar. Nuevamente, pierde la ventaja si este es el caso.
  • Político
    • No se puede hacer que los patrocinadores comprendan que un rediseño incremental requiere un compromiso a largo plazo con el proyecto. Inevitablemente, la mayoría de las organizaciones pierden el apetito por el drenaje continuo del presupuesto que crea un rediseño incremental. Esta pérdida de apetito también es inevitable para una reescritura, pero los patrocinadores estarán más inclinados a continuar, porque no quieren dividirse entre un sistema nuevo parcialmente completo y un sistema antiguo parcialmente obsoleto.
    • Los usuarios del sistema están demasiado apegados a sus "pantallas actuales". Si este es el caso, no tendrá la licencia para mejorar una parte vital del sistema (el front-end). Un rediseño le permite evitar este problema, ya que están comenzando con algo nuevo. Todavía insistirán en obtener "las mismas pantallas", pero tienes un poco más de munición para hacer retroceder.

Tenga en cuenta que el costo total de rediseñar de forma incremental siempre es mayor que hacer una reescritura completa, pero el impacto en la organización suele ser menor. En mi opinión, si puedes justificar una reescritura y tienes desarrolladores superestrellas, entonces hazlo.

Solo hágalo si puede estar seguro de que existe la voluntad política de completarlo. Esto significa la aceptación tanto del ejecutivo como del usuario final. Sin ella, fracasarás. Supongo que es por eso que Joel dice que es una mala idea. Ejecutivo y la aceptación del usuario final parece un Unicornio de dos cabezas para muchos arquitectos. Tienes que venderlo agresivamente y hacer campaña para que continúe continuamente hasta que se complete. Eso es difícil, y estás hablando de apostar tu reputación en algo que algunos no querrán ver tener éxito.

Algunas estrategias para el éxito:

  • Si lo hace, sin embargo, no intente convertir el código existente. Diseñe el sistema desde cero. De lo contrario, estás perdiendo el tiempo. Nunca he visto ni oído hablar de un proyecto de "conversión" que no haya terminado miserablemente.
  • Migre usuarios al nuevo sistema un equipo a la vez. Identifique los equipos que tienen el MÁS DOLOR con el sistema existente y migre primero. Permítales difundir las buenas noticias de boca en boca. De esta manera, su nuevo sistema se venderá desde adentro.
  • Diseña tu marco como lo necesites. No comience con un marco de trabajo que he pasado 6 meses construyendo este marco que nunca ha visto código real.
  • Mantenga su pila de tecnología lo más pequeña posible. No sobre diseño. Puede agregar tecnologías según sea necesario, pero eliminarlas es difícil. Además, cuantas más capas tenga, más trabajo les costará a los desarrolladores hacer cosas. No lo dificultes desde el primer momento.
  • Involucre a los usuarios directamente en el proceso de diseño, pero no permita que dicten cómo cómo hacerlo. Gana su confianza mostrándoles que puedes darles lo que quieren mejor si sigues buenos principios de diseño.
328
Michael Meadows

He participado en dos grandes reescrituras. Primero fue un pequeño proyecto. El segundo fue el producto principal de una empresa de software.

Hay varias trampas:

  • las reescrituras siempre tardan más de lo esperado.
  • las reescrituras no tienen efectos/beneficios directos para el cliente.
  • la capacidad dedicada a la reescritura no se utiliza para apoyar al cliente.
  • perderá funcionalidad con una reescritura a menos que tenga documentación al 100%.

Las reescrituras rara vez son la respuesta real. Puede refactorizar gran parte del código sin perder nada y sin mucho riesgo.

Las reescrituras pueden ser la respuesta si:

  • estás cambiando a otro idioma o plataforma.
  • está cambiando marcos/componentes externos.
  • el código base existente ya no se puede mantener.

Pero recomiendo encarecidamente el enfoque lento mediante la refactorización. Es menos riesgoso y mantiene contentos a sus clientes.

112
Toon Krijthe

Es hora de reescribir cuando:

El costo de reescribir la aplicación + mantener la aplicación reescrita es menor que el costo de mantener el sistema actual a lo largo del tiempo

Algunos factores que hacen que mantener el actual sea más costoso:

  • El idioma es tan antiguo que tiene que pagarle a las personas que saben mucho dinero programar en él (COBOL).
  • (por experiencia, desafortunadamente) El sistema está en una arquitectura de hardware que es tan antigua que tienen que buscar en Ebay y COLECCIONAR partes para agregarlas a la máquina en la que se está ejecutando porque ya no están hechas. Esto se llama "soporte vital de hardware" y es costoso porque a medida que las piezas se vuelven más escasas, (pueden) subir de precio o (absolutamente) eventualmente se agotarán.
  • Se ha vuelto tan complejo que el //Here be dragons. el comentario está en todo el código.
  • No puede escribir ningún otro proyecto y agregar un nuevo valor a la compañía porque siempre está remendando a esta bestia fea.
74
Ryan Hayes

Si necesita un cambio fundamental en la arquitectura del proyecto, es posiblemente hora de comenzar de nuevo.

Incluso con eso, potencialmente habrá grandes extensiones de código que aún vale la pena reutilizar en su nuevo proyecto.

Sin embargo, tenga en cuenta la advertencia justa. Un proyecto actual tendrá sus reglas comerciales probadas y refinadas con innumerables horas de uso real, algo que no será cierto para un proyecto que se inició desde cero.

Dudo que un período de tiempo o una intuición sea una medida apropiada de una medida tan drástica. Debe tener claro, defendible y bien entendido razones para participar en este curso de acción.

17
Dan McGrath

Aunque estoy de acuerdo con la respuesta de Kramii y la opinión de Joel, hay momentos en que es apropiado hacer una reescritura. En aplicaciones de larga duración (estoy hablando de 10 a 20 años o más), el mantenimiento se vuelve cada vez más costoso con el tiempo. Esto se debe a que el código se está volviendo cada vez más espagueti ya que la arquitectura original se sacrifica por parches de mantenimiento rápidos. Además, los desarrolladores de tecnologías más antiguas se vuelven más raros y más caros. Finalmente, el hardware comienza a envejecer y cada vez es más difícil encontrar nuevo hardware, sistemas operativos, marcos, etc. para ejecutar la aplicación anterior. Además, las empresas evolucionan, y lo más probable es que un sistema anterior no satisfaga las necesidades comerciales de la organización como lo haría un sistema nuevo.

Por lo tanto, debe sopesar todos los costos de mantenimiento continuo, así como los beneficios potenciales de un nuevo sistema para el negocio, contra el costo de reescribirlo desde cero. Sea muy pesimista en sus estimaciones sobre el costo de una reescritura. Casi siempre cuesta más y lleva más tiempo de lo que piensas.

12
RationalGeek

¡Detener! La reescritura es casi nunca la respuesta. Más a menudo que no, refactorizar es una mejor apuesta.


Por supuesto, hay hay veces cuando se justifica una reescritura:

  • Estás cambiando a una nueva plataforma donde las herramientas de migración no existen (o no se pueden escribir a un precio suficientemente bajo).
  • La aplicación a reescribir es trivial.
  • El código fuente de la aplicación original se pierde y la recuperación es más costosa que la reescritura.
  • La gran mayoría de las reglas comerciales encapsuladas por la aplicación existente ya no se aplican.
  • Hay pocos usuarios activos del código existente.
  • Tienes el recurso (tiempo, talento y herramientas) para emprender la reescritura.
  • La aplicación existente no se puede ejecutar en un entorno de producción, por razones legales o prácticas.

Para comprender por qué recomiendo refactorizar sobre reescribir, considere lo que implica una reescritura. Debes:

  1. Comprenda los matices de lo que hace la aplicación existente. Esto no suele ser trivial cuando se tienen en cuenta todas las reglas comerciales sutiles que encapsula, el entorno (tanto humano como técnico) en el que opera y las ventajas y desventajas de la solución actual. La mayoría de las veces, el único lugar en el que existe esta información (si existe) es en el código fuente de la aplicación existente. Es lamentable que una de las principales razones para realizar una reescritura es que el código existente es difícil de entender y mantener.

  2. Reproduzca esta funcionalidad (o una versión actualizada de la misma) en una nueva aplicación probada y confiable. Es posible que los desarrolladores no entiendan el código existente, pero sus usuarios lo entienden bien. Es posible que no satisfaga sus necesidades comerciales actuales, pero al menos pueden decirle qué hace la aplicación en diversas circunstancias.

Las grandes ventajas de la refactorización son que:

  • Puedes tomar las cosas una pieza pequeña a la vez.
  • Cualquier cambio puede probarse en el contexto de la aplicación de trabajo existente.
  • Las hipótesis sobre la forma en que funciona el código existente se pueden probar haciendo pequeños cambios y observando lo que sucede.
  • Los cambios a menudo se pueden entregar a los usuarios en fases en lugar de todos a la vez.
  • Aprender de las primeras etapas de la refactorización puede informar las etapas posteriores de la refactorización.
  • Si abandona el proceso a mitad de camino, aún habrá beneficios en términos de una base de código más limpia (en lugar de una reescritura que debe completarse para ofrecer cualquier beneficio al usuario o desarrolladores).

Recuerde también que si hace una reescritura, tiene la garantía de introducir muchos errores nuevos y meterse en la nueva base de código.

11
Kramii

Este gráfico podría ayudar, es una función de la calidad de la base del código y el valor comercial de la aplicación:

enter image description here

El cuadro pretende ser una guía sobre cuándo se justifica una reingeniería del software heredado y cuándo no. Por ejemplo, si el software tiene un alto valor comercial y la calidad del código es deficiente, se justifica una reingeniería.

10
Tulains Córdova

Creo que estoy en la única situación en mi carrera donde la gran reescritura es la respuesta:

Fusión de empresas, gran superposición en la funcionalidad de los sistemas. Muchos, muchos sistemas se han fusionado y retirado, y otros aún están en proceso.

Heredé un sistema de la otra compañía que aún vive. Tiene una base de código enorme, que solía soportar múltiples departamentos muy similares a los nuestros, pero con un diseño y marcos completamente diferentes. Solo queda un sector empresarial que lo usa, lo que genera suficiente dinero para mantener esta cosa viva en un estado zombie. Toda la experiencia anterior se ha ido, no hay documentación. La carga de soporte es alta, con fallas cada semana. No se ha fusionado con los sistemas de nuestras empresas, porque nuestra empresa nunca apoyó este sector particular del negocio, por lo que no tenemos la funcionalidad o la experiencia.

Parece que este es el único caso donde se necesita la reescritura. Parece que voy a tener que descubrir este gigante, extraer los bits de funcionalidad dedicados a este negocio y reescribir las piezas que deben agregarse a nuestros sistemas existentes. Una vez hecho esto, nuestros sistemas existentes pueden soportar este nuevo sector, y esta bestia puede salir de su miseria. De lo contrario, voy a perder la cordura.

8
Jay

Trabajé para una pequeña empresa de software que tenía un par de aplicaciones de DOS que se actualizaron para manejar Y2K, reescritas como una aplicación de Windows de 16 bits y luego totalmente reescritas como una aplicación de 32 bits con una función 'pequeña' adicional (en última instancia, solo utilizada por un cliente) que impactó toda la estructura.

Mover el código de 16 bits a 32 podría haber sido hecho en un mes por una persona, pero NOOOOOOOOO, tuvimos que volver a escribirlo para que sea Muuuuuuuuuuuuuuuuuuuuucho mejor. Esto podría adaptarse para otras industrias, tendría especificaciones completas y código psuedo incluso antes de comenzar. Se crearon las especificaciones, pero tomó tanto tiempo que ni siquiera hubo tiempo para escribir el código real. Fue lanzado tarde, con más errores que los 16 bits 'iniciados' (estaba en v.3.0 y finalmente hasta el punto en que casi lo hicimos una semana sin que alguien informara un nuevo error).

Pensarías que reescribir la misma aplicación 3-4 veces traería algunas mejoras, pero no creo que una interfaz gráfica de usuario pueda justificarse tanto.

Este fue mi primer trabajo de TI como jefe de soporte técnico. Debería escribir un libro sobre cómo no desarrollar software para distribución. Obviamente cometimos muchos errores, pero el hecho de que continuamos reescribiendo aplicaciones agravó la incompetencia.

7
JeffO

Tuve un caso muy similar al tuyo, solo que el código ni siquiera estaba usando Struts. Lo que hice en cambio fue apuntar a áreas que eran particularmente malas y que causaban muchos problemas. Este enfoque dirigido nos hizo progresivamente mejores.

Durante un período de 2 años, trabajamos en la refactorización de piezas y piezas junto con el trabajo de mejora. Siempre trabajamos una tarea de "Endurecimiento" en un plan de proyecto. Al centrarnos en las áreas específicas que no funcionaron bien, obtuvimos el máximo rendimiento. Lo que funcionó lo dejamos solo. También es crítico que este trabajo se haya realizado en el curso del desarrollo normal y se haya publicado. El problema con una gran reescritura es que se dispara durante un año o más y luego, cuando regresa, todo cambió de todos modos y algunos de los errores desagradables se suavizaron y perdió su ROI.

Nunca reescribimos todo el asunto. Sin embargo, dejamos de usar esa plataforma para nuevos trabajos y lanzamos una nueva plataforma nueva para un gran proyecto nuevo. Eso fue aprobado y entregamos un excelente producto en un tiempo razonable.

5
Bill Leeper

Entonces, aquí estoy sentado en mi escritorio, comencé a reescribir el código para este desastre absoluto de un gran archivo aspx, la base de datos detrás de él, y reemplazar la interfaz de MS Access en MsSQL.

Este programa asp está plagado de cosas como

  • include(close.aspx) que en su interior tiene una línea de código que cierra la última conexión de base de datos abierta.
  • El código heredado acaba de comentar al azar
  • Sin consideración por la seguridad
  • Código de espagueti, miles de líneas. Todo en un solo archivo.
  • Funciones y variables sin un significado claro detrás de sus nombres.

Si alguna vez necesitamos hacer un ligero cambio, es como jugar cinco juegos simultáneos de kal-toh en modo pesadilla.

Fui contratado para replicar la funcionalidad y hacer un producto que pudiera ser personalizable y vendible para otros en la industria. El problema es que esto se ha escrito en los últimos 10 años para satisfacer todas las necesidades comerciales (bueno, de todos modos diría que cinco o seis sigma de ellas).

Si no quisiéramos vender el producto, probablemente no habrían necesitado una reescritura, ya que hace la mayor parte de lo que quieren, quizás no con elegancia, pero no fue prudente gastar el dinero al hacer que el código de Niza 'haga lo mismo'

5
Incognito

La solución existente no se escala

Te estoy mirando, MS Access.

4
user21007

Joel Spolsky tiene un excelente artículo sobre esto: Cosas que nunca debes hacer, Parte I

Por el título que puedes decir, es un poco unilateral (habla sobre por qué nunca deberías tirar código) IMO, hay mucha verdad, recientemente vi un video de channel9 en el 25 Aniversario de Excel donde algunos desarrolladores dijeron, cómo incluso hoy, si miraba la fuente, verificaría la revisión y terminaría volviendo al código que Excel usó y que fue escrito hace 20 años.

No puede estar 100% seguro (cuando incluso Netscape comete errores (del artículo de Joels)), [~ # ~] i [~ # ~] Sentí que el artículo de Joel fue enviado por Dios, porque puedo ser pesimista y amar desechar el código pensando que siempre puedo escribirlo mejor una segunda vez, pero ahora me doy cuenta de que esto solo cuesta un lote .

Para dar una respuesta concreta, solo diría que necesita hacer un análisis exhaustivo de Costo vs Valor .

Mi mundo real: una aplicación de Silverlight que estoy desarrollando v0.6 hasta ahora tiene un desorden de llamadas asíncronas que hacen que el código sea tan complicado. Desde que descubrí Extensiones reactivas esta semana realmente quiero volver a escribir la mayor parte del código, pero ahora ¿qué le digo a mi cliente? El programa funciona perfectamente bien (con algunas pérdidas de memoria) pero ¿no les importa? No puedo decirles Oh, estoy tomando 2-3 semanas más porque quiero volver a hacer algo. Sin embargo, voy a bifurcar el código y volver a escribir /jugar con él en mi gratis tiempo.

Solo mis 2 centavos, ¿vale?

4
gideon

Hay una broma clásica sobre "si fuera a X no comenzaría desde aquí".

Una vez tomé un trabajo, donde la principal motivación del empleador era traer talento a bordo para lanzar una reescritura de una aplicación crítica para el negocio. La pregunta que no pude hacer fue, ¿por qué has terminado en esta situación en primer lugar? Debería haber sido una bandera roja, si la causa fue

  • demasiada presión para agregar funcionalidad para mantener y refactorizar gradualmente a la bestia,

  • muy poca habilidad en el departamento,

  • muy poca aceptación por parte de los clientes o la gerencia para un trabajo incremental,

o lo que sea, y esto causa una supuración hasta que el problema alcanza un nivel intolerable.

Así que voy a estar de acuerdo con Joel en que una reescritura masiva es probablemente una muy mala idea a menos que tenga pruebas firmes de que todas las razones subyacentes detrás de por qué una reescritura importante parece tan necesaria se han abordado , es muy probable que repita el problema a su debido tiempo.

2
Julia Hayward

Es la respuesta cuando la reescritura le permite a la organización seguir una estrategia que ofrece una ventaja competitiva o le permite servir mejor a sus clientes de una manera que la arquitectura actual no puede acomodar.

En cambio, las reescrituras suelen aliviar las preocupaciones de la administración:

  • todo debería estar en .NET,
  • nuestros desarrolladores dicen que nuestro código apesta,
  • nos estamos quedando atrás técnicamente
  • no podremos encontrar recursos para apoyar nuestro sistema o, muy a menudo,
  • han pasado diez años, así que es hora.

La mayoría de estas preocupaciones no se materializarán y, si lo hicieran, podrían manejarse. Ese último, sin embargo, es el peor. Es esencialmente: no tenemos una razón.

Sí, como el automóvil, un sistema comenzará a mostrar signos de desgaste. Esto puede aliviarse mediante el mantenimiento de rutina. Ya sabes lo que dicen sobre cómo un poco de mantenimiento preventivo es muy útil. Como inversión, el servicio de rutina (es decir, refactorización y estandarización) casi siempre tendrá un costo menor que una reescritura.

Sin embargo, tenemos que anticipar que eventualmente será necesaria una reescritura. Establezca fechas y planifique tentativamente para ello, pero a medida que la fecha se acerque más tarde a favor de alcanzar otros objetivos estratégicos hasta que tenga una razón convincente como ...

En los últimos años hemos perdido la oportunidad de ganar grandes cuentas porque no pudimos satisfacer sus necesidades de manera oportuna o costosa. Nuestro sistema se reescribirá utilizando una arquitectura extensible que permite que las personalizaciones se conecten (y no se codifiquen como lo hacemos actualmente). Esto disminuirá drásticamente el tiempo y el costo de acomodar a los clientes con necesidades especiales. Ganaremos más cuentas y satisfaceremos mejor las necesidades de nuestros clientes actuales.

2
Mario T. Lanza

Creo que la razón principal que justifica las reescrituras son los cambios de plataforma. Por ejemplo, si tiene una aplicación GUI de escritorio de Windows y el propietario de la compañía decide que quiere que la próxima versión sea una aplicación basada en la web. Aunque no siempre, en mi experiencia, la mayoría de las veces esto requerirá una reescritura, a menos que los desarrolladores originales escribieran código muy modular y reutilizable (casi no sucede).

2
Craig

Según Joel, las grandes reescrituras son el único peor error estratégico que una empresa puede cometer:

Cosas que nunca debes hacer, Parte I

... Es importante recordar que cuando comienzas desde cero no hay absolutamente ninguna razón para creer que vas a hacer un mejor trabajo del que hiciste la primera vez. En primer lugar, es probable que ni siquiera tenga el mismo equipo de programación que trabajó en la versión uno, por lo que en realidad no tiene "más experiencia". Simplemente volverá a cometer la mayoría de los viejos errores e introducirá algunos problemas nuevos que no estaban en la versión original.

El viejo mantra ¡construye uno para tirar es peligroso cuando se aplica a aplicaciones comerciales a gran escala. Si está escribiendo código experimentalmente, es posible que desee extraer la función que escribió la semana pasada cuando piensa en un algoritmo mejor. Esta bien. Es posible que desee refactorizar una clase para que sea más fácil de usar. Eso también está bien. Pero descartar todo el programa es una locura peligrosa, y si Netscape realmente tuviera supervisión de un adulto con experiencia en la industria del software, es posible que no se hayan disparado tanto en el pie.

2
user3287

Nunca, siempre refactorice, la verdad es que si el código fue escrito por usted, no podrá hacerlo mejor.

A menos que desee cambiar la tecnología, el código carece de cualquier estructura (lo vi hace mucho tiempo en algún sitio web PHP, el autor simplemente copió/pegó spahgetti en lugar de incluir/clase/función) o tomaste algo de otra persona que está muy mal escrito.

Todo debe estar diseñado como una caja negra. Modular, API simple, lo que hay dentro ... eso es menos importante :) Si tienes espagueti, tal vez puedas cerrarlo dentro de una caja negra, para que no contamine un buen código.

2
Slawek

Cuando se pasa a una tecnología completamente nueva, se necesita para proporcionar la funcionalidad deseada.

"Completamente nuevo": si planea reescribir pero usa la misma plataforma, entonces la refactorización y la reestructuración juiciosa es casi seguro la mejor solución. "Plataforma", como se usa aquí, es algo vago: considérelo que incluye lenguaje, y tal vez el sistema operativo (se extiende desde Linux a Windows o viceversa), pero probablemente no sea el marco (por ejemplo, reemplazar Struts con Spring).

"Necesario para proporcionar la funcionalidad deseada": alrededor del año 2000, inicié un proyecto para reescribir un componente principal del servidor en Java desde C++ para habilitar el enhebrado inmediato, un caché de objetos, y transacciones controladas por el cliente. En ese momento, había varias bibliotecas de subprocesos para C++ que habríamos tenido que admitir, y la habilitación de subprocesos de gran parte de nuestro código de base de datos habría requerido una reescritura casi total. En cuanto a las transacciones controladas por el cliente. ... no va a suceder con la arquitectura antigua.

Incluso entonces, no estoy seguro de haber hecho la reescritura, excepto que tenía un conocimiento detallado del comportamiento del sistema actual, y era un código relativamente limpio que no había desarrollado muchas verrugas en sus 11 años de vida.

1
Anon

Bueno, puedo imaginar escenarios hipotéticos en los que podría tirar la base de código existente (situaciones hipotéticas en las que las bolas de bucky tienen cero peso y volumen, donde a nadie le importa si perdemos semanas o meses de productividad mientras luchamos por agregar características y errores pasados ​​por alto) correcciones en el sistema, y ​​donde el sistema es tan trivial y odiado por una organización que puedo reemplazar todo el ejército de servidores con notepad ++ y una netbook en diez minutos y aumentar la productividad y la moral de todos en todos los ámbitos).

Para casi cualquier escenario del mundo real, aunque solo recomendaría refactorizar en su lugar. ^ _ ^. Tiende a haber demasiados costos ocultos e imprevistos para reescribir cuando los requisitos legales y comerciales indocumentados comienzan a aparecer y el último minuto hackeando las cosas en el último minuto comienza a producirse.

== Refactorización en el lugar para un bien mayor, y cosas ==

Refactorizando código heredado con el viejo enfoque incremental regular

  1. Si tiene la oportunidad, conviértase a UML y documente la pequeña arquitectura knarly que existe.
  2. Si está en control de versiones, busque generar algunos informes de cambio de código y averiguar qué archivos y secciones de archivos se han cambiado con más frecuencia. Tome nota de estos, ya que probablemente serán las áreas con las que querrá tratar primero.
  3. Antes de cambiar cualquier código, siempre intente agregar algo de cobertura de prueba (incluso las pruebas funcionales de pila completa fea lo harán). Si se trata de una lógica de extracción de código de procedimiento desordenada grande, tiene la intención de cambiar a algún método o función razonablemente nombrado y, si es posible, agregue algunos casos de prueba que verifiquen su nuevo método. haga cualquier truco horrible que tenga que hacer y, si es posible, paramatice el cambio si es algo comúnmente modificado como el ancho del margen o el título, por lo que será un poco más sencillo actualizar la próxima vez.
  4. Use el patrón del adaptador y evite ocultar los fragmentos de código heredado bajo una alfombra de clases y métodos con nombres lógicos para que, para las tareas más comunes que usted y los otros desarrolladores realicen, no tenga que preocuparse por los fragmentos de miedo que están sucediendo detrás de espaldas a esos pequeños métodos y clases limpios que has escondido detrás de ese código heredado, como esas familias agradables que mantienen deformados a los antiguos miembros de la familia de zombis asesinos en los graneros para que no estropeen el día a día de las granja . . normalmente.
  5. A medida que continúe reduciendo y limpiando las secciones del código, continúe aumentando su cobertura de prueba. Ahora puede profundizar aún más y "reescribir" aún más código cuando sea necesario/deseado con una confianza cada vez mayor.
  6. Repita o aplique enfoques de refactorización adicionales para continuar mejorando su base de código.

Ramificación por abstracción

  1. Defina el punto problemático en el código que desea eliminar (la capa de persistencia, el generador de pdf, el mecanismo de conteo de facturas, el generador de widgets, etc.).
  2. ejecute (escriba si es necesario) algunos casos de prueba funcionales (automatizados o manuales, pero usted sabe automatizados) contra la base del código que apunta a esta funcionalidad junto con el comportamiento general.
  3. Extraiga la lógica relacionada con ese componente de la base de origen existente en una clase con alguna interfaz razonable.
  4. Verifique que todo el código ahora esté usando la nueva interfaz para realizar la actividad X, que anteriormente estaba dispersa al azar en todo el código (agregue la base del código, agregue un rastro a la nueva clase y verifique que las páginas que deberían llamarlo son, etc.), y que puede controlar qué implementación se usará modificando un solo archivo. (registro de objetos, clase de fábrica, lo que sea IActivityXClass = Settings.AcitivtyXImplementer ();)
  5. vuelva a ejecutar casos de prueba funcionales que verifiquen que todo sigue funcionando con toda la actividad X lanzada en su nueva clase.
  6. Escriba pruebas unitarias siempre que sea posible alrededor de la nueva clase de actividad X wrapper.
  7. implementar una nueva clase con una lógica de espagueti menos loca que la implementación heredada que se adhiere a la misma interfaz que la clase heredada.
  8. verifique que la nueva clase pase las pruebas unitarias que escribió para la clase heredada.
  9. actualice su código cambiando el registro/método de fábrica/lo que sea para usar la nueva clase en lugar de la clase anterior.
  10. verifique que sus pruebas funcionales aún pasen.

Principio cerrado abierto y una lógica comercial común/capa de persistencia

Hasta cierto punto, es posible que pueda salirse con la separación de su presentación, negocio y capa de persistencia y escribir una nueva aplicación que sea totalmente compatible con la solución heredada, o como mínimo, aún puede manejar los datos ingresados ​​por la solución heredada. Probablemente no recomendaría este enfoque, pero a veces es un compromiso razonable de tiempo/horario/recursos/nueva funcionalidad requerida.

  • Como mínimo, separe la capa de presentación de las capas comerciales y de persistencia.
  • implemente una nueva interfaz de usuario y una mejor capa de presentación que utilice la misma capa común de negocios y persistencia.
  • Verifique que los datos creados con la nueva interfaz de usuario no rompan la interfaz de usuario anterior. (estará en agua caliente si los usuarios de la nueva herramienta interrumpen a los usuarios de la herramienta anterior). Si se esfuerza por lograr una compatibilidad total con versiones anteriores, debe guardar todo en las mismas capas de persistencia. Si solo desea compatibilidad con la nueva herramienta, utilice una nueva base de datos y nuevas tablas o tablas de extensión para rastrear datos que no están en el sistema heredado.
  • Para la nueva funcionalidad y la capa de persistencia necesita agregar nuevas tablas y métodos, no cambie la lógica heredada existente, ni agregue columnas, restricciones a las tablas existentes. p.ej. si necesita comenzar a rastrear el contacto de emergencia de los empleadores y algunos otros campos no modifican la tabla de empleados existente (no tenemos idea de qué suposiciones hacen los datos heredados sobre esa tabla) agregue una tabla de extensión employee_ext id, employee_id, emergency_contact_id, etc_id.
  • Migre lentamente a los usuarios al nuevo sistema. si es posible, coloque el sistema heredado en modo de solo lectura, o simplemente agregue algunas advertencias para informar a los usuarios que ya no estará disponible después de la fecha X.
  • implementar cualquier funcionalidad de alta prioridad perdida o requisitos comerciales en la nueva interfaz de usuario
  • pasar sobre la base de usuarios.
  • continúe limpiando la lógica de negocios y los usuarios de la capa de persistencia otras metodologías de refactorización.
0
Keith Brings

Diría que hay una tercera categoría en el espacio Refactor vs Rewrite ... Y eso es actualizar sus versiones de lenguaje, compiladores y bibliotecas ... A veces, simplemente adoptar técnicas modernas de codificación tiene un gran beneficio.

Tomemos C #, por ejemplo, el código v7 escribe mucho más limpio, más seguro y más conciso que v2. Cosas como Elvis y el operador de fusión nula ayudan mucho.

Cambiar los compiladores también podría dar nueva vida a un código más antiguo. Entonces, podrían crearse nuevas bibliotecas que faciliten el trabajo y la implementación ... La creación de redes es un gran ejemplo de un espectro de dificultades de implementación.

También: sistemas Linux integrados ... Piense en instalar nuevas herramientas: cambie a git desde svn. o agregue Vi a su sistema, etc., etc.

No siempre tiene que ser un refactor vs reescribir ... Su arquitectura probablemente necesite mejoras, pero funciona ... tal vez solo necesite pensar en cómo está escrito su código, etc.

0
visc

Para decidir el punto en el que debe comenzar de nuevo, debe determinar dónde el valor de continuar en su proyecto actual es inferior al valor de comenzar de nuevo.

La razón por la que esto es tan difícil es que hace una estimación precisa de la velocidad de desarrollo del equipo en el nuevo proyecto hasta que realmente lo inicia. Dicho esto, si, utilizando una estimación MUY conservadora de su velocidad de desarrollo en el nuevo proyecto, se estima que el proyecto ofrece un retorno de la inversión que vale la pena, entonces tiene un argumento comercial para comenzar de nuevo.

0
Nobody

Con mi métrica, debe cumplir dos condiciones para justificar una reescritura:

  1. Después de la reescritura, las nuevas características serán más fáciles/rápidas/menos complicadas de escribir
  2. La reescritura tomará menos o igual tiempo que agregar la nueva característica actual.

Incluso entonces desea limitar el alcance de su reescritura. Por ejemplo, teníamos un software heredado en una compañía que estaba escrito en C++ con la mentalidad de un programador de C que no sabía sobre modularidad. El resultado final fue un código de speghetti en forma de una máquina de estados finitos que abarcaba múltiples clases y DLL. Teníamos un nuevo requisito que era muy diferente de los supuestos incorporados en el código, y que iba a ser parte del valor agregado patentado de la compañía para sus clientes.

Después de pasar tiempo con el código implementando otras características, tuve una muy buena idea de cuánto tiempo tomaría averiguar cuál de las varias declaraciones de cambio necesitaría cambiar, etc. Mi propuesta fue reescribir la sección de código que estaba la enorme máquina de estados finitos: debería llevarme menos tiempo que extender el código existente. Pude consolidarme en uno DLL lo que solía ser tres, y proporcionar una estructura mucho más orientada a objetos que haría mucho más fácil hacer la nueva funcionalidad crítica además de hacer que sea más fácil Añadir nueva funcionalidad.

Había otras tres aplicaciones que usaban las bibliotecas que necesitaban reescribir, así que no quería tener que reescribir completamente esos programas. El alcance se limitaba a la biblioteca y lo que era necesario para vincular la biblioteca al software existente. Mis estimaciones no estaban lejos, y el trabajo se amortizó. Poco después del rediseño, me encargaron agregar una nueva característica. Lo que me hubiera llevado una semana con la estructura anterior solo me llevó un día con la estructura nueva.

0
Berin Loritsch

El OP no indica el alcance del proyecto, pero la pista principal que tomé fue "escrito en [idioma/dialecto] antiguo usando viejos [libs]", que para mí son los principales impulsores de una reescritura. De hecho, la mayoría de los proyectos en los que he estado involucrado en cualquier longevidad significativa del mercado finalmente se dan cuenta de que las actualizaciones de compilación/interpretación/sistemas operativos son una tarea importante para mantener la base del código.

En resumen, planearía la reescritura en fases, priorizando primero la actualización en libs. Puede ser que, en el camino, pueda colarse en otras optimizaciones, pero el hecho de que planea diferir algunos cambios a una fase posterior puede ser una excelente manera de cumplir con el cronograma y evitar "atascarse".

0
MarkHu