paint-brush
Por qué los aburridos proyectos de migración de software podrían ser su arma secretapor@ghadgetejas
Nueva Historia

Por qué los aburridos proyectos de migración de software podrían ser su arma secreta

por Tejas Ghadge11m2025/02/26
Read on Terminal Reader

Demasiado Largo; Para Leer

Los proyectos de migración son inherentemente difíciles porque se enfrentan a una barrera existente en cuanto a disponibilidad, escala, latencia y experiencia del cliente. La parte más aburrida es que se supone que los clientes existentes no deben saber que se reemplazó un sistema subyacente o una base de código.
featured image - Por qué los aburridos proyectos de migración de software podrían ser su arma secreta
Tejas Ghadge HackerNoon profile picture

Explore esta visión contraria sobre cómo acelerar su viaje para convertirse en un líder/desarrollador de software experimentado.

En mis 14 años de experiencia en ingeniería, vi a muchas personas tomar decisiones profesionales basadas en la oportunidad de trabajar en un servicio nuevo. No hay nada de malo en esa decisión. Sin embargo, hoy vamos a presentar un caso contradictorio de trabajar en proyectos de migración aburridos. Lo que no me di cuenta al principio de mi carrera fue que la mayor parte de mi aprendizaje fundamental en el desarrollo de software provino de proyectos que eran proyectos de migración, por ejemplo, migrar un almacén de datos subyacente a otra tecnología basada en la nube o descontinuar un servicio monolítico a favor de nuevos microservicios, etc.


Esto se debe a que las migraciones son inherentemente difíciles: estás obligado a cumplir, o incluso superar, una barrera existente en cuanto a disponibilidad, escala, latencia y experiencia del cliente que fue construida y perfeccionada a lo largo de los años por múltiples ingenieros. No enfrentarás esas restricciones en un sistema completamente nuevo porque eres libre de definirlas. No solo eso, sin importar cuán minucioso seas con las migraciones, habrá esqueletos ocultos en el armario con los que lidiar cuando cambies a nuevas partes del sistema (mira este interesante artículo sobre cómo la migración de Doordash de Int a BigInt para un campo de base de datos estuvo plagada de obstáculos).


Estos proyectos te obligan a pensar meticulosamente en las metodologías de prueba, la precisión de los resultados de los nuevos sistemas, los planes de implementación de software, los planes de reversión de software, etc., de modo que no siempre te estreses por trabajar en un sistema completamente nuevo porque no hay clientes existentes a los que prestar servicios. La parte más aburrida es que se supone que los clientes existentes no deben saber que en realidad reemplazaste un sistema subyacente o una base de código sin su conocimiento.

1. Pero ¿realmente necesitas una migración?

A menudo veo a nuevos ingenieros que quieren probar una nueva tecnología y reemplazar una funcionalidad existente, o alguien que quiere hacer una refactorización completa de la base de código. Si se trata de un cambio contenido (por ejemplo, usar una biblioteca de código abierto bien probada para realizar una pequeña operación en el servicio, etc.), no me molesta. Pero, si se trata de un cambio arquitectónico importante o de la reelaboración de una base de código completa, es importante recordar un famoso principio de ingeniería: “Respeta lo que vino antes”. (Me pareció gracioso este tuit que se refiere al código heredado como código legendario).


Volviendo al tema de los proyectos de migración, siempre es recomendable evaluar si se puede solucionar el mismo problema con un esfuerzo comparativamente menor en comparación con hacer una revisión importante del código base o la arquitectura. Pero el atractivo de utilizar una nueva tecnología o patrón de diseño siempre es tentador, así que ¿cómo evaluamos esta decisión? A continuación, se incluyen algunas preguntas y consideraciones para ayudarlo a comenzar antes de embarcarse en un proceso de migración:


  1. ¿El negocio (o la experiencia del cliente) se ve afectado negativamente o se verá afectado en el futuro si no resolvemos este problema y el equipo ha agotado todas las opciones para resolverlo sin una gran iniciativa de un proyecto de migración importante? Opte por una revisión de otro ingeniero sénior que no esté en su equipo y que pueda actuar como abogado del diablo para poner a prueba su razonamiento. Algunos ejemplos de justificaciones podrían ser mejorar la agilidad en 4 meses de desarrollo para cada lanzamiento de función, usar diferentes pilas de tecnología para diferentes servicios para mejorar la latencia p99 en 400 ms, eliminar los cuellos de botella de escalamiento más allá de X TPS, etc. Siempre busque desacuerdos para romper su sesgo de confirmación en tales situaciones.


  2. Compara los esfuerzos que supone realizar la migración con los beneficios que ésta producirá, de modo que puedas estimar cuánto tiempo te llevará empezar a cosechar los beneficios del proyecto. Un ejemplo personal que puedo compartir es el siguiente:

    • Mi equipo poseía dos sistemas separados que atendían a dos conjuntos diferentes de bases de clientes, y cada lanzamiento de una nueva característica requería que el equipo hiciera cambios similares, pero no exactos, en estos sistemas separados. En general, la duplicación generó un esfuerzo adicional de 1 desarrollador por mes por característica. Lanzamos alrededor de 4 de esas características cada año, lo que generó 4 meses de desarrollo de esfuerzo duplicado o desperdiciado. Esto era frustrante para los ingenieros. Uno de los ingenieros presentó una propuesta para combinar estos dos sistemas y calculó que el esfuerzo sería de 24 meses de desarrollo. Se necesitarían 24 lanzamientos de características y 6 años (suponiendo que se lanzaran 4 características por año) para que el equipo comenzara a cosechar los beneficios de la migración. No hicimos la migración y pasamos a un enfoque alternativo de usar bibliotecas compartidas para reducir el esfuerzo de duplicación en un 50% y, más tarde, descontinuamos el sistema después de 3 años a favor de otro servicio.


  3. En algunos casos, la migración es una guía de arriba hacia abajo para alcanzar un objetivo más amplio (por ejemplo, Amazon deja de usar Oracle ) donde aún puede hacer el análisis pero no es necesario obtener la aprobación para continuar con el proyecto.


Una vez que haya identificado las justificaciones correctas para realizar la migración y haya probado el razonamiento con algunos ingenieros o líderes externos, es hora de pasar a los siguientes pasos.

2. Disposición de los requisitos funcionales y no funcionales de un sistema

Esto es similar a lo que harías mientras te preparas para una entrevista de diseño de sistemas . Una vez que se establecen los requisitos funcionales y no funcionales, es prudente olvidarse del sistema existente por el momento y plantear cómo construirías un nuevo sistema si no hubiera restricciones.


La razón para hacer este ejercicio es que muchos miembros del equipo actual tendrán una tendencia inconsciente a crear un nuevo sistema que no sea muy diferente del sistema existente, lo que frustraría el propósito mismo de la migración en muchos casos. Consideremos otro ejemplo de mi pasado:

  • Habíamos decidido dejar de usar una base de datos SQL local debido a cuellos de botella de escalabilidad y problemas de mantenimiento. Esto se debía a que nuestro servicio usaba una base de datos SQL como motor de programación para realizar un seguimiento de las actualizaciones relacionadas con el inventario. Ejecutábamos múltiples consultas complejas en la base de datos SQL cada segundo, lo que era un desperdicio. Nuestros ingenieros presentaron un diseño para reemplazar nuestra base de datos SQL con una base de datos SQL en la nube . La justificación era que la base de datos SQL en la nube era más escalable, pero lo que estábamos haciendo en realidad era trasladar nuestro problema que surgía de patrones incorrectos a la tecnología en la nube. Deberíamos haber corregido el patrón incorrecto en lugar de trasladar el problema a una tecnología en la nube. Un ingeniero principal dirigió nuestro enfoque para construir un sistema impulsado por eventos utilizando una notificación de Pub/Sub y una cola de transmisión (por ejemplo, Kafka o AWS Kinesis , etc.) que escalaba varias magnitudes mejor que nuestra propuesta original.


La participación de alguien con más experiencia que no haya trabajado en sistemas existentes llevó la conversación a construir un sistema completamente diferente que fuera más escalable, en tiempo real y más fácil de mantener. Aunque esto no siempre sea posible, no está de más intentar realizar este ejercicio.


Si está realizando una migración similar a la que propusimos antes (es decir, trasladar una base de datos SQL local a una base de datos SQL en la nube), es posible que le resulte más fácil cumplir con los requisitos no funcionales. Sin embargo, si su sistema final es drásticamente diferente del sistema actual, al menos debería intentar corregir el antipatrón integrado en el sistema. Por ejemplo, en lugar de sondear para obtener un cambio de actualización en una clave de la base de datos, puede publicar una notificación de cambio mediante un servicio de publicación/suscripción para los suscriptores.


Sin embargo, como en todos los proyectos de sistemas distribuidos, las migraciones tendrán desventajas en lo que respecta a los requisitos no funcionales, y será necesario planificar para ello. Por ejemplo, si hay un servicio monolítico con una disponibilidad del 99,9 % que maneja dos cálculos independientes relacionados con el negocio (estimación de la fecha de entrega y estimación de los gastos de envío), y decidimos dividir esta responsabilidad en dos microservicios A (servicio de estimación de la fecha de entrega) y B (estimación de los gastos de envío), cada uno con una disponibilidad del 99,9 %, entonces la disponibilidad general del sistema se convierte en:


P(A) * P(B) = 0,999 * 0,999 = 99,8% de disponibilidad


La creación de microservicios a partir de un monolito condujo a una reducción de la disponibilidad del 99,9% al 99,8%.


Recuerde siempre que, si necesita resultados de 'n' llamadas de servicio (llamadas de servicio secuenciales o paralelas) para devolver una respuesta a su cliente, debe multiplicar la disponibilidad individual de cada uno de los 'n' servicios para llegar a la disponibilidad final del sistema.


Para cumplir o superar la disponibilidad original del sistema (es decir, 99,9 %), tendremos que pensar en otras técnicas como el almacenamiento en caché, los reintentos, etc. Pero cada una de estas opciones tiene sus propias desventajas. Por ejemplo, el almacenamiento en caché, en algunos casos, puede significar que el sistema debería poder tolerar datos obsoletos; los reintentos pueden agregar demoras y hacer que el sistema sea susceptible a tormentas de reintentos, etc.


Sin embargo, realizar este ejercicio debería permitirle ver si al menos está cumpliendo con un requisito existente sobre requisitos no funcionales o si necesita la aprobación del liderazgo sobre nuevos requisitos no funcionales que desea proporcionar a sus clientes.

3. ¿Los clientes necesitan realizar alguna acción?

Con un nuevo sistema, sus clientes adoptarán la nueva versión del cliente. Con los proyectos de migración, es posible que tenga que lidiar con el problema de qué sucede si no todos los clientes pueden migrar a la nueva versión del cliente (es decir, pensar en la compatibilidad con versiones anteriores). Si todos sus clientes son internos de la empresa o tiene una adopción limitada fuera de la empresa, puede trabajar con todos sus clientes para migrarlos a una nueva versión del cliente.


En otros casos, esto simplemente no es posible. Por ejemplo, si posee un gran servicio en la nube que se ha adoptado ampliamente en la industria, no hay forma de obligar a todos los clientes a migrar a una nueva versión del cliente. Esto puede agregar obstáculos significativos, así como una sobrecarga de mantenimiento para el equipo y, en algunos casos, la solución es mantener dos versiones de sistemas, con el sistema más antiguo en modo de mantenimiento (es decir, no se agregan nuevos clientes a este sistema) y se brinda un incentivo a los clientes más antiguos para que se muden a una versión más nueva del sistema, ya que ofrece mejores beneficios para los clientes.


Sin embargo, si tienes una situación como el enlace que compartí arriba con Doordash donde el uso de Int como el tipo de datos de la clave principal iba a desbordarse, no tienes otra opción que obligar a todos a realizar la migración.

4. ¿Ya se han realizado migraciones similares?

Al crear nuevos sistemas, la mayoría de los ingenieros hacen un trabajo fabuloso al cubrir casi todos los casos de uso. Sin embargo, ocurre lo contrario con las migraciones, porque se está manejando un sistema que fue desarrollado, parcheado y mantenido por decenas, si no cientos, de ingenieros antes que usted. Incluso si desea aprender sobre cada caso de uso, ruta de código o cuello de botella del sistema, es difícil comprender el servicio completo.


En estos casos, lo más sencillo es buscar información de equipos, ingenieros sénior, etc. que hayan realizado migraciones similares sobre qué procesos se pueden seguir para cubrir los puntos ciegos. Muchas empresas siguen un proceso de revisión más amplio del diseño y la migración a nivel de la organización. Busque los desacuerdos como una parte sagrada del proceso para consolidar su enfoque y comprensión. Las migraciones están plagadas de minas terrestres que se activan de manera inesperada.


La mayoría de las migraciones suelen pertenecer a una de las dos categorías siguientes o a una combinación de ambas:

  1. Migraciones de servicios: descontinuar un servicio existente en favor de una nueva arquitectura que puede consistir en utilizar partes del servicio actual y un nuevo servicio o lanzar nuevos microservicios para reemplazar un sistema existente.


  2. Migraciones de almacenes de datos: descontinuar un almacén de datos existente y reemplazarlo con uno nuevo o hacer uso de un sistema impulsado por eventos.


Incluso si no encuentra un ejemplo exacto de migración, siempre puede extraer enseñanzas más amplias para estos segmentos. En mi experiencia personal, las migraciones de almacenes de datos fueron las más difíciles, ya que existen inquietudes en torno a la precisión de los datos, que se ve afectada debido a problemas de coherencia entre los almacenes de datos antiguos y los nuevos. Por ejemplo, un usuario podría ver una versión anterior de los datos de un nuevo almacén de datos debido a demoras en la propagación.

5. Ejecución de sistemas antiguos y nuevos en paralelo

Al ejecutar sistemas nuevos y existentes en paralelo y solo proporcionar datos del sistema existente, podrá comparar los resultados de ambos sistemas con las solicitudes reales de los clientes. Este es el paso más útil y eficaz para comparar y validar que su nuevo sistema funciona correctamente.


Hace muchos años, trabajé en la migración de un servicio a una nueva pila técnica. Siempre que nuestro antiguo servicio recibía solicitudes de clientes, hacíamos una llamada asincrónica paralela a nuestro nuevo servicio en el backend. Registramos los resultados de los servicios existentes y nuevos en una ubicación S3. Luego, ejecutamos una consulta de AWS Athena al final del día para detectar cualquier discrepancia e identificar cualquier problema con el nuevo servicio. Eso todavía era algo bastante predecible de hacer en comparación con otra migración complicada que manejamos con un almacén de datos.


Estábamos trasladando un antiguo almacén de datos SQL a un nuevo almacén de datos NoSQL que se llenaba a partir de una fuente de datos nueva y más confiable. Sin embargo, el momento en que se actualizaban claves específicas entre los almacenes de datos antiguos y nuevos era impredecible, ya que provenían de dos sistemas completamente diferentes.


Después de intentar sin éxito varios enfoques para comparar datos entre almacenes de datos antiguos y nuevos, trabajamos con nuestros equipos de upstream para lanzar versiones de claves de datos, de modo que pudiéramos realizar una comparación de precisión de datos para una clave determinada utilizando versiones entre ambos sistemas. Este fue un trabajo descartable, ya que no necesitábamos versiones después del proyecto, pero no había otra forma de manejar esto.

6. Espera que las cosas salgan mal: ¿Puedes regresar al mundo anterior?

Incluso después de ejecutar el Paso 5, en el que pudo comparar con precisión los resultados del sistema antiguo y el nuevo, es muy posible que nunca haya encontrado un tipo específico de solicitud de algunos clientes que rara vez usan su sistema. No he podido dormir mientras trabajaba en algunos de estos proyectos de migración pensando: "¿Qué pasa si todo sale mal con el nuevo sistema?".


La forma más sencilla de abordar este problema era tener un interruptor de apagado del nuevo sistema en caso de que nuestras alarmas detectaran algo inesperado o lo activáramos manualmente para mover el tráfico de vuelta al sistema anterior. Tenga en cuenta que esto no es tan fácil como parece. En algunos casos, puede que no haya una manera de cambiar a un sistema anterior, pero tener esta palanca aliviará mucha presión sobre el equipo.


En los casos en los que esto no sea posible, el único punto en el que puede confiar es en ser minucioso con el paso 5 (ejecutar los sistemas antiguos y nuevos en paralelo). A esto le sigue una implementación gradual y lenta del nuevo sistema. Puede definir una implementación gradual y lenta utilizando técnicas como trasladar un pequeño porcentaje (1 % seguido de 5 %, 10 %, 25 %, 50 %, 100 %) del tráfico para que sea atendido por un nuevo servicio, o seleccionar cuidadosamente algunos clientes para que sean atendidos por el nuevo servicio con los que está trabajando en estrecha colaboración durante la migración, etc.


También es importante revisar en profundidad un manual de respuesta a incidentes que los operadores deben seguir si las cosas salen mal. Si todo falla, la intervención manual puede ayudar con los casos extremos que se pasaron por alto, pero esto puede volverse rápidamente inmanejable si el número de clientes afectados aumenta a miles. Esta es la razón por la que se debe dedicar suficiente tiempo a las fases descritas en los puntos 5 y 6.

Conclusión

Si bien trabajar en migraciones no es la única forma de perfeccionar algunas de estas habilidades, definitivamente puede acelerar el aprendizaje que puede aplicar a sus proyectos futuros, incluso si eso significa que son iniciativas completamente nuevas. Los proyectos de migración son menos glamorosos, pero fueron los que me pusieron a prueba, especialmente cuando brindo comentarios sobre documentos de diseño u otros documentos técnicos.


Entonces, si tienes la oportunidad de trabajar en uno, pruébalo: no te decepcionarás y tendrás un aprendizaje para toda tu carrera que, con suerte, podrás transmitir a otros para construir sistemas resilientes .