Modernización de aplicaciones
Actualizaciones y rescate de Laravel
Aplicaciones varias versiones por detrás, o heredadas de un equipo que ya no está - actualizadas de versión en versión, en producción, con una batería de pruebas construida antes de mover nada.
Hay dos situaciones que traen aquí a casi todos los equipos. O una aplicación se ha quedado lo bastante atrás como para que actualizarla parezca un proyecto y no una tarea, o la construyó alguien que ya no está y el equipo actual tiene miedo de desplegarla.
Las dos tienen solución. Ninguna suele requerir una reescritura.
Actualizaciones, de versión en versión
No hay atajo que cruce cuatro versiones mayores. El camino son las versiones en orden, porque la guía de actualización de cada release da por supuesto que usted viene de la anterior, y saltarse una significa razonar sobre interacciones que nadie ha documentado.
Lo que lo hace seguro es el orden del trabajo:
- Cobertura antes que movimiento. Pruebas de caracterización sobre las rutas y los trabajos que importan, afirmando lo que la aplicación hace hoy, bien o mal. Sin esto, una actualización es una serie de cambios sin manera de saber si rompieron algo.
- PHP al lado de Laravel. Las dos restricciones se mueven juntas, y el grafo de dependencias suele decidir el orden. Un paquete sin release para su versión de PHP objetivo se descubre ahora y no tres versiones más adelante.
- Una versión por rama, integrada. Cada paso desplegado por su cuenta, para que una regresión sea atribuible a un cambio y no a cuarenta.
- Dependencias auditadas, no subidas a ciegas. Un paquete abandonado es una decisión - sustituirlo, adoptarlo en el repositorio o aceptarlo - y esa decisión sale más barata tomada a propósito que tomada por una compilación rota a medianoche.
La parte que más tarda no suele ser el framework. Son los paquetes que lo rodean, y en concreto los que fueron abandonados en algún punto entre su versión y la actual.
Código heredado
Las dos primeras semanas no contienen ningún commit. Producen un mapa de dependencias, un inventario de cada ruta y cada trabajo con lo que toca cada uno, una lista de código demostrablemente muerto, y un registro de riesgos ordenado por lo que va a doler primero.
Ese documento se lo queda usted vaya como vaya la decisión. Más de un cliente se lo ha llevado a su propio equipo y lo ha ido resolviendo sin nosotros, lo cual es un resultado perfectamente bueno y que preferimos a un encargo a regañadientes.
Es el registro de riesgos lo que cambia la conversación. Nadie puede planificar contra "el código es un desastre": eso es un estado de ánimo. Contra lo que sí se puede planificar es: los pagos no tienen prueba, dos trabajos cobran dos veces si se reintentan, los fallos de cola no avisan a nadie, y tres paquetes tienen avisos de seguridad publicados sin ruta de actualización. Eso es un backlog, y un backlog lo va resolviendo en orden quien tenga la semana libre.
Lo que encontramos, casi siempre
Reglas de negocio en los controladores. La misma regla implementada tres veces de forma ligeramente distinta, de modo que nadie puede decir qué garantiza realmente la aplicación.
Un .env que es la única documentación de la infraestructura. Servicios
que nadie sabe nombrar, credenciales que nadie ha rotado, y al menos un valor
del que todo depende y que no está documentado.
Trabajos que no es seguro reintentar. Lo cual ha ido bien porque la cola lleva tiempo fallando en silencio en lugar de reintentar.
Un entorno de pruebas que no se parece a producción en la única dimensión que importa: normalmente el volumen de datos, de vez en cuando la versión de PHP.
Lo que sostiene el trabajo
Nada se mueve sin una prueba que se daría cuenta. Ese es todo el método. Primero la cobertura, después la actualización, y donde la cobertura sea realmente impracticable, el cambio es más pequeño y la vuelta atrás está ensayada.
Cada paso es desplegable. Sin ramas de larga vida. Si las prioridades cambian y el trabajo se para un trimestre, lo integrado es coherente y lo que queda es una lista y no un conflicto.
El estado final está escrito. Una actualización sin línea de meta anotada se convierte, en cuanto cambia una persona del equipo, en un código donde nadie sabe qué convención es la vigente.
Cuándo una auditoría es mejor primer paso
Si lo que tiene es una sospecha y no una decisión - la aplicación parece frágil, o cara de cambiar, y nadie sabe decir exactamente por qué - una auditoría responde a eso en dos semanas y le dice si una actualización es siquiera la respuesta correcta. A veces no lo es: la versión está bien y el problema son cuatro endpoints y una cola que nadie vigila, que es un trabajo bastante más pequeño.
Cómo se acota
Primero leemos la aplicación: la versión, los paquetes sin equivalente mantenido, qué cubre realmente la cobertura de pruebas, y cuánto se ha movido el framework por debajo.
De ahí sale un alcance escrito con los pasos de versión, su orden y un precio. La estimación es por paso y no una cifra única para todo el trayecto, así que puede parar después de cualquiera con una aplicación que funciona y decidir si el siguiente compensa. El contrato se refiere a ese documento.
El trabajo empieza una vez firmado. Una release cada vez, con cada paso en su propio pull request.
Qué recibe
La aplicación en una versión actual, movida una release cada vez, con cada paso en su propio pull request para que el cambio que rompió algo sea el que se puede señalar. Al lado, la cobertura de pruebas construida para que el movimiento fuese seguro, que se queda después y suele ser la mitad más valiosa.
También recibe la lista de lo que dejamos a propósito: paquetes sin equivalente mantenido, código que funciona y que todavía no conviene tocar, y lo que costará cada uno cuando por fin toque.
