Hola Mi nombre es Ivan Melnichuk, soy Jefe del Departamento de Desarrollo en una empresa de TI de Ucrania. En la publicación quiero compartir mis enfoques profesionales personales con respecto a la resolución del problema del código heredado en el contexto del rápido desarrollo del proyecto y contar sobre las técnicas a las que recurre nuestro equipo en los casos "cuando las características deben ser entregadas" para ayer ".
Nos ocupamos del proyecto
Para transmitir cuán preciso, minucioso y minucioso debe ser el trabajo con el legado, haré una analogía con un castillo de naipes.
Así es como se ve el código heredado. Si decidimos eliminar o reemplazar al menos una carta de este edificio, corremos el riesgo de abrumar a toda la casa y nivelar sus restos con el suelo.
Legacy se comporta aproximadamente de la misma manera. Por lo tanto, el trabajo de un programador que asumió la tarea de modernizar y "dar una segunda vida" al proyecto debería ser, en cierta medida, una joyería. La mayoría de los programadores intentan evitar y generalmente "saltan del tema" de la deuda técnica. Incluso compiló un exitoso desfile de las citas más comunes que tuvieron que escuchar los programadores atrapados en condiciones heredadas:
- Creamos un sitio "simple", y ahora quieres obtener un nuevo "bollo", y necesitamos reescribir todo esto, ya que tenemos un legado ...
- Nadie sabe cómo funciona esto ...
- Para agregar un módulo, debe verificar todo el sitio, solo de esta manera entenderemos qué y dónde puede salir ...
- No voy a ir allí en ningún caso, todo ya está mal allí ...
Pero la experiencia en programación muestra que existe vida después del legado. No hay problemas con la programación. Solo hay tareas que deben abordarse. Y antes de elaborar un plan de acción "para superar el código de herencia", debe comprender qué tan mal están las cosas en el proyecto en su conjunto. En el curso de la práctica, identificó 6 etapas del problema del proyecto:
- Sin documentación técnica. El umbral más bajo de problemas, porque puede probar y llegar a conjeturas preliminares sobre cómo debería funcionar esto.
- Sin documentación comercial. Si falta toda la documentación (tanto técnica como comercial), involuntariamente aparece la sensación de que "parece que estamos atrapados en la historia". De hecho, incluso una empresa no recuerda cómo debería funcionar, lo que significa que el equipo, al menos, no comprende el resultado esperado.
- No hay nadie que diseñó esto. Si, además de la falta de documentación, tampoco hay un desarrollador que pueda explicar cómo debería funcionar el proyecto, entonces ya huele a frito.
- No sabemos lo que el usuario debería obtener en última instancia. Una cosa es cuando surgen preguntas solo en el backend, pero si todavía no tenemos idea de lo que se debe mostrar en el frente, entonces esto ya está cerca del estado "el paciente tiene más probabilidades de estar muerto que vivo".
- Más de 200 usos de cada función y se llaman getA . Quinto nivel de dificultad: cuando entras en Legacy, ves el uso de la función A y 200, y nadie sabe por qué es ...
- No hay programadores que quisieran / pudieran desarrollar. No hay comentarios
Comprender los negocios
Los negocios cuentan con dinero. Las empresas no quieren gastar recursos financieros adicionales simplemente en rehacer lo que ya funciona. Una empresa nunca comprará la idea: "Lo haré de una manera nueva porque no me gusta". Por lo tanto, siempre ofrece más.
A menudo, los desarrolladores empujan a las empresas hacia ideas inútiles. En esta ocasión, hay un "fondo de citas de oro" por separado.
- Estamos contratando un nuevo equipo para el "corte" de alta calidad del código. Es decir, necesitamos un equipo de especialistas que harán el proyecto en paralelo con el equipo existente. No es el hecho de que el resultado sea diferente, pero el negocio ya debería contener dos proyectos.
- Dejamos de agregar funciones, ¡ahora solo refactorizamos! Oficialmente declaras a la empresa: tabú absoluto sobre las características, solo es posible "poner las cosas en orden" bajo el capó. Extraoficialmente, usted dijo que no habrá mejoras a gran escala y mejoras en el proyecto, solo que las "arreglará" localmente.
- Ya tengo todo lo que necesito en WP, solo necesito migrar la base de datos. Este es un "síntoma" de un principiante. La canción favorita de June: es un sitio tan simple, solo funciona durante una o dos horas ...
Para negociar con el negocio con respecto a la reencarnación de un código obsoleto, que se sirve bajo la salsa de nuevas características rentables, es necesario desde la posición de abrir nuevos horizontes de negocios. Sin embargo, antes de las negociaciones, se deben responder las siguientes preguntas:
- ¿El negocio está listo para crecer? Debe comprender: ¿la empresa tiene una solicitud para elevar el estándar financiero o simplemente necesita el servicio para trabajar de manera más competente?
- ¿Etapa prototipo? A menudo, una empresa solicita un prototipo simple, con el que quiere "probar" el mercado en el momento de la relevancia del producto. Y solo si comienza a ganar dinero, el negocio está listo para desarrollar la función en un proyecto más avanzado y completo.
- Desarrollo completado y ahora solo soporte? Es importante comprender la gama completa de tareas.
- ¿Hay suficiente fuego en nuestros ojos y no se apagará? El proyecto debe inspirar, no desmotivar. Es muy importante que su equipo quiera participar en la reencarnación de Legacy, de lo contrario, las personas se dispersarán gradualmente en proyectos más interesantes para ellos.
- ¿Hay un arquitecto? Esta es la pregunta más importante: ¿tiene una persona que pueda hacer la arquitectura correcta y comenzar a escribir un buen código ya? Ni siquiera tiene sentido intentar comenzar si no hay un arquitecto. De lo contrario, en una semana se convertirá en el que creó el legado del problema.
Cuando venda ideas a empresas, concéntrese en los mensajes de "nuevo, crear, agregar" ... La empresa responde muy bien a las ofertas de la serie: "Le haremos una nueva función y el proyecto X será más rápido ..." y "Para aumentar la conversión, agregue una nueva ... "
P - Planificación
Para trabajar de manera rápida y eficiente con deudas técnicas, necesita un plan.
1.
Definición de tareas en las que parasitaremos. ¿Por qué parasitar? A menudo sucede: vendimos una función, y con ella nos referimos en parte a la refactorización.
2.
Definición de requisitos de alto nivel. Es necesario registrar una solicitud comercial clara para un "alto estándar" a fin de elaborar la documentación correcta.
3.
Definición de los principales módulos del sistema, la imposición de módulos. Antes de comenzar la refactorización, debe comprender los módulos principales del sistema: dónde, cómo, qué y con qué puede interactuar y delimitar el código en secciones.
4.
Definición de integración. Al crear un módulo específico, debemos pensar de antemano en la capacidad de montarlo en un legado vecino.
5.
Definición del equipo. Uno en el campo de refactorización no es un guerrero. El equipo es un elemento muy importante de un resultado exitoso. Fervor, unidad de equipo y excelente interacción entre los participantes en el proceso imprescindible.
6.
¿Cómo vamos a probar? Si va a tomar un proyecto de alta calidad, debe pensar en el futuro y en las opciones de prueba del producto.
Junto con lo anterior, también es importante determinar cuál debería ser el resultado final deseado, elaborar un plan de escala y registrar los cuellos de botella del proyecto. Por ejemplo, en el caso del escalado de código, es importante comprender dónde pueden surgir problemas bajo condiciones de alta carga (puede ser una base de datos, consultas pesadas, una cuadrícula o algún otro enlace intermedio que puede "caer").
Es igualmente importante determinar los límites del proyecto, dónde estaba el antiguo código y dónde habrá un nuevo nivel de "obra maestra". También debe considerar enfoques para microservicios, o DDD, o, tal vez, necesita algo más de "nanomagy".
Técnicas de legado ninja
Después del "trabajo preparatorio" llegamos a las técnicas que facilitan el proceso de ahorro de la deuda técnica. No hay una receta universal y una panacea para todos los males en Legacy, pero en el curso del trabajo en proyectos de gran carga, hice una lista de ingredientes con los que puede preparar un código realmente "sabroso".
1.
No reinventar la rueda. Para mí, este es el truco principal para escribir código. Todo ha sido inventado antes que tú, no recurras a bailar con panderetas y otros experimentos para resolver problemas con código heredado.
2.
El código es estándar. Sin un solo estándar, cada desarrollador escribirá a su manera. El "estilo de autor" contribuirá al caos y aumentará aún más la basura del código.
3.
Revisión del código. No solo una presencia del código estándar. También es necesario que el equipo sea responsable de verificarlo. De lo contrario, todo volverá a la normalidad, es decir, al nivel del código anterior.
4.
Analizadores de código estático, detector de mensajes PHP, etc. (en lugar de mil libros) . Estas y otras técnicas automáticas serán necesarias para acelerar el proceso, en particular con el mismo código de revisión.
5.
Intentamos microservicios. Por separado, también puede haber módulos o bibliotecas. ¿Por qué microservicios? Su ventaja es aislar la lógica tanto como sea posible y limitarla a una API específica. La ventaja de este último es que la API es una entidad más monolítica en comparación con el "adaptador en el código que se puede arreglar". Sin embargo, la API tiene un inconveniente en forma de costos de red adicionales.
6.
Arquitectura de la base de datos, fuentes de datos. Es la base de datos que considero el primer cuello de botella de cualquier Legacy. Pero cada uno diseña como quiere, e incluso en SQL, puede encontrar fallas desenfocadas. Aquí hay algunos consejos para trabajar con la nueva base de datos:
- No jodas nada, sed de todo. Si desea cambiar la antigua estructura de datos incorrecta a un nuevo formato de datos, más rápido y más productivo, puede hacerlo de dos maneras. El primero es poner una nueva base, eliminar por completo la anterior, y pase lo que pase. El segundo: en el caso de un legado duro, introduzca un nuevo formato en paralelo. Hablando en sentido figurado, plantar uno nuevo cerca de un árbol viejo. ¿Por qué la segunda forma está justificada y es más prometedora? Debido a que todo lo nuevo funcionará de manera eficiente, y si surgen problemas durante la implementación o en la etapa de integración, simplemente puede revertir el código, y no hay necesidad de revertir todas las migraciones de bases de datos complejas.
- Se crea una nueva base de datos en la estructura correcta. Al crear un nuevo recurso, es importante controlar los lugares en los que escribimos la nueva estructura. Paralelamente, es necesario crear soporte para la estructura anterior, ya que no es práctico deshacerse de ella por completo. Es decir, seguimos escribiendo material nuevo y, al mismo tiempo, apoyamos la plantilla anterior, en la que traducimos todo lo nuevo y, por lo tanto, permitimos que la antigua también funcione, como si fuera la antigua, pero apoyando la nueva estructura.
- Controlamos toda la grabación. No perdemos los detalles del campo de atención para garantizar el soporte de la base de datos.
7. ¿
Pero SQL? Si desde un punto de vista arquitectónico puede operar con entidades, opere. El concepto de algo definido y finito lo ayudará a no crear relaciones innecesarias y duplicadas.
8.
Decoradores, adaptadores, púas ... Estos patrones son uno de los principales para integrar el nuevo código en el antiguo legado.
9.
Plan B, o plan de reversión para la integración. Muchos cometen el error de olvidarlo. Es vital en la situación "cuando algo sale mal" cuando se vierte material nuevo. Es decir, tan pronto como comencemos a construir arquitectura, ya en esta etapa deberíamos entender cómo la revertiremos en caso de un error.
10.
Un nuevo código sin pruebas (muelles) se convierte en un legado en una semana. No importa cuán hermoso sea su código, sin documentación en una semana estará en el estado "heredado", debido a su incomprensibilidad.
11.
Pruebas. Si las pruebas unitarias son demasiado caras, entonces usamos pruebas de humo, funcionales y de integración. ¿Qué tan realista es vender pruebas unitarias a un negocio con salsa "para hacer un trabajo hermoso?" En nuestras realidades, esto es más bien una rareza que un patrón. Si por alguna razón no funciona con "unidades", entonces recurrimos a las pruebas de humo, funcionales o de integración, y también no olvidamos que podemos delegar la tarea, por ejemplo, a un probador manual.
En lugar de un epílogo
Lo más importante en esta historia es hacer el trabajo y no dejar atrás el legado de 6 etapas problemáticas (enumeradas en orden de simple a más complejo):
- Sin documentación técnica
- Sin documentación comercial
- No hay nadie que haya desarrollado esto.
- No sabemos qué debe recibir el usuario.
- Más de 200 usos de cada función y se llaman getA ()
- No hay nadie a quien le gustaría / podría desarrollar esto.