En Ramp, un monorepo de flujos de trabajo de aprendizaje automático había pasado de ser un espacio compartido conveniente a lo que el equipo llamaba «un poco de pantano»: un requirements.txt con dependencias transitivas sin fijar que variaban entre máquinas, formato inconsistente, ausencia de pruebas automatizadas y anotaciones de tipo que faltaban o eran sutilmente incorrectas. Los ingenieros se volvieron recelosos de tocar el código por miedo a romper algo, y la velocidad, el objetivo original, se había ralentizado hasta casi detenerse.
En lugar de reescribir el repositorio, el equipo adoptó cuatro herramientas sobre la marcha: poetry para dependencias bloqueadas y reproducibles; ruff para formato y linting; pytest para probar utilidades compartidas de alto impacto en lugar de perseguir una cobertura total; y mypy para verificación de tipos gradual. El truco que hizo posible la adopción en una base de código activa no fue corregirlo todo primero. Ejecutaron un autoformateador una vez sobre todo el repositorio en un único commit y luego añadieron el hash de ese commit a .git-blame-ignore-revs para que no contaminara el historial de blame.
Para el linting y la verificación de tipos, en lugar de corregir cientos de errores preexistentes antes de activar CI, generaron automáticamente comentarios «# noqa» y «# type: ignore» para cada violación existente, y luego activaron la aplicación estricta para todo lo nuevo. La regla «RUF100» de Ruff y «warn_unused_ignores» de mypy marcaban cualquier comentario de supresión que quedara obsoleto una vez que el código subyacente se corregía realmente, de modo que la lista de ignorados solo podía encogerse, nunca podrirse en silencio.
El resultado fue una base de código que nunca fue «limpia» por decreto, pero que quedó bajo aplicación estricta de cara al futuro desde el primer día, con la deuda reduciéndose a medida que los desarrolladores tocaban naturalmente los archivos antiguos.
Abuelizar las violaciones antiguas, aplicar las reglas solo al código nuevo
Una reescritura completa o una limpieza de golpe consumiría semanas antes de que pudiera empezar cualquier aplicación de reglas, así que el equipo aplicó las reglas de cara al futuro en lugar de retroactivamente.
La generación automática de los comentarios de supresión iniciales convirtió una limpieza manual ilimitada en un paso único y automatizable.
Marcar los comentarios de supresión sin usar significaba que la deuda solo podía disminuir, ya que corregir una violación antigua sacaba a la luz un comentario de ignorado ahora inútil que CI detectaría.
Comprimir el reformateo en un único commit y excluirlo de git blame preservó la capacidad de ver quién tocó una línea por última vez por una razón real.
No necesitas una base de código limpia antes de aplicarle estándares. Silencia cada violación existente una vez, aplica estrictamente solo al código nuevo, y el atraso se reduce a medida que la gente toca los archivos antiguos de todos modos.
El equipo informó que la base de código alcanzó un estado en el que la calidad se mantenía de cara al futuro: el archivo de bloqueo de poetry proporcionaba entornos consistentes entre las máquinas de los desarrolladores y CI, ruff detectaba errores reales como claves de diccionario duplicadas antes de la fusión, y mypy detectaba regresiones por cambios de firma en los puntos de llamada que las pruebas unitarias no cubrían. La publicación enmarca el objetivo como la confianza restaurada para hacer cambios amplios, no las herramientas en sí, y señala que el equipo seguía considerando trasladar más de esta carga de los contribuyentes a las herramientas.
CONSULTA LAS PRUEBAS
Las fuentes
- Increasing velocity by modernizing a Python codebase Ramp Engineering · builders.ramp.com ·