Acabo de leer la 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 aplicación horrenda. 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?
fuente
Respuestas:
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.
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 afirmar categóricamente que nunca es 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).
Tenga en cuenta que el costo total de rediseñar de forma incremental siempre es mayor que hacer una reescritura completa, pero el impacto para la organización suele ser menor. En mi opinión, si puede justificar una reescritura y tiene desarrolladores superestrellas, hágalo.
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. La aceptación de ejecutivos y usuarios finales 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:
fuente
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 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:
Pero recomiendo encarecidamente el enfoque lento mediante la refactorización. Es menos riesgoso y mantiene contentos a sus clientes.
fuente
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:
//Here be dragons.
comentario está en todo su código.fuente
Si necesita un cambio fundamental en la arquitectura del proyecto, posiblemente sea 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 razones claras , defendibles y bien entendidas para participar en este curso de acción.
fuente
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.
fuente
¡Detener! Reescribir casi nunca es la respuesta. La mayoría de las veces, refactorizar es una mejor apuesta.
Por supuesto, no son momentos en los que una reescritura se justifica:
Para entender por qué recomiendo refactorizar sobre reescribir, considere lo que implica una reescritura. Debes:
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 donde existe esta información (si está en algún lugar) 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.
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:
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.
fuente
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:
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.
fuente
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.
fuente
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 un front-end GUI 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.
fuente
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 te vas por un año o más y luego, cuando regresas, todo cambió de todos modos y algunos de los errores desagradables se suavizaron y perdiste tu 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.
fuente
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 para el 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.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, tal vez no con elegancia, pero no fue prudente gastar el dinero en hacer un buen código 'hacer la misma cosa.'
fuente
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 utilizó y que fue escrito hace 20 años.
No se puede estar 100% seguro (cuando aún Netscape comete errores (de Joels artículo)), me sentí como el artículo de Joel fue enviado a Dios, porque puedo ser pesimista y encanta tirar pensamiento código Siempre puede escribir mejor un segundo tiempo, pero ahora me he dado cuenta de que esto solo cuesta mucho .
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í las 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 escribirlo / jugarlo en mi tiempo libre .
Solo mis 2 centavos, ¿vale?
fuente
La solución existente no escala.
Te estoy mirando, MS Access.
fuente
Según Joel, las grandes reescrituras son el peor error estratégico que una empresa puede cometer:
Cosas que nunca debes hacer, Parte I
fuente
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 de PHP, el autor simplemente copió / pegó spahgetti en lugar de incluir / clase / función) o se hizo cargo de algo de otra persona que es 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.
fuente
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).
fuente
Hay una broma clásica sobre "si fuera a XI 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 hice 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 voy a repetir el problema a su debido tiempo.
fuente
Es la respuesta cuando la reescritura 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:
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 conllevará 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.
fuente
Cuando se pasa a una tecnología completamente nueva, se necesita para proporcionar la funcionalidad deseada.
"Completamente nuevo": si planea reescribir pero usar 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 SO (que se extiende desde Linux a Windows o viceversa me viene a la mente), pero probablemente no 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 permitir 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 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.
fuente
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 inicie. 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.
fuente
Con mi métrica, debe cumplir dos condiciones para justificar una reescritura:
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 consolidar en una 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 facilitar la adición de 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.
fuente
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".
fuente
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 para 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 pirateando cosas juntos en el último minuto comienza a producirse.
== Refactorización en el lugar para un bien mayor, y cosas ==
Refactorizando el código heredado con el viejo enfoque incremental regular,
Ramificación por abstracción
Principio abierto cerrado 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.
fuente
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 de codificación modernas 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 se escribe su código, etc.
fuente
No creo haber visto personas reescribir una aplicación heredada.
Lo que sucede es que las personas escriben aplicaciones totalmente nuevas con una arquitectura, tecnologías, etc. diferentes que tienen algunas características en común con la generación anterior. Y se llama aplicación 2.0, pero de hecho tiene muy pocas cosas en común con el original.
Pero esto no es realmente una "reescritura" del original en el sentido de que está tratando de lograr la paridad de características.
fuente