Chez Ramp, un monorepo de workflows d'apprentissage automatique était passé d'un espace partagé pratique à ce que l'équipe appelait « un peu un marécage » : un requirements.txt avec des dépendances transitives non épinglées qui dérivaient d'une machine à l'autre, un formatage incohérent, aucun test automatisé et des annotations de type soit absentes, soit subtilement erronées. Les ingénieurs hésitaient de plus en plus à toucher au code par crainte de casser quelque chose, et la vélocité, l'objectif initial, était tombée à un rythme très lent.
Plutôt que de réécrire le dépôt, l'équipe a adopté quatre outils sur place : poetry pour des dépendances verrouillées et reproductibles ; ruff pour le formatage et le linting ; pytest pour tester les utilitaires partagés à fort impact plutôt que de viser une couverture complète ; et mypy pour une vérification progressive des types. L'astuce qui a rendu l'adoption possible sur une base de code en production n'était pas de tout corriger d'abord. Ils ont exécuté un formateur automatique une fois sur tout le dépôt dans un seul commit, puis ajouté le hash de ce commit à .git-blame-ignore-revs pour qu'il ne pollue pas l'historique de blame.
Pour le linting et le typage, au lieu de corriger des centaines d'erreurs préexistantes avant d'activer la CI, ils ont généré automatiquement des commentaires « # noqa » et « # type: ignore » pour chaque violation existante, puis activé une application stricte pour tout ce qui était nouveau. La règle « RUF100 » de Ruff et l'option « warn_unused_ignores » de mypy signalaient tout commentaire de suppression devenu obsolète une fois le code sous-jacent réellement corrigé, de sorte que la liste des ignorés ne pouvait que diminuer, jamais pourrir silencieusement.
Le résultat fut une base de code qui n'était jamais « propre » par décret, mais qui est devenue strictement encadrée pour l'avenir dès le premier jour, la dette diminuant à mesure que les développeurs touchaient naturellement les anciens fichiers.
Exempter les anciennes violations, n'appliquer les règles qu'au nouveau code
Une réécriture complète ou un nettoyage de type big-bang aurait consommé des semaines avant que toute application des règles puisse commencer, donc l'équipe a appliqué les règles pour l'avenir plutôt que rétroactivement.
La génération automatique des commentaires de suppression initiaux a transformé un nettoyage manuel sans limite en une étape unique et automatisable.
Le signalement des commentaires de suppression inutilisés signifiait que la dette ne pouvait que diminuer, puisque corriger une ancienne violation faisait apparaître un commentaire d'ignorance désormais inutile que la CI détecterait.
L'écrasement du reformatage en un seul commit et son exclusion de git blame préservait la possibilité de voir qui avait touché une ligne en dernier pour une vraie raison.
Vous n'avez pas besoin d'une base de code propre avant d'y appliquer des normes. Faites taire chaque violation existante une fois, appliquez strictement les règles au nouveau code uniquement, et le passif diminue à mesure que les gens touchent de toute façon aux anciens fichiers.
Suites
L'équipe a rapporté que la base de code avait atteint un état où la qualité était maintenue pour l'avenir : le fichier de verrouillage de poetry garantissait des environnements cohérents entre les machines des développeurs et la CI, ruff détectait de vrais bugs comme des clés de dictionnaire en double avant la fusion, et mypy détectait des régressions de changement de signature sur les sites d'appel que les tests unitaires ne couvraient pas. L'article présente l'objectif comme la confiance retrouvée pour effectuer des changements de grande ampleur, et non l'outillage lui-même, et note que l'équipe cherchait encore à transférer davantage de cette charge des contributeurs vers l'outillage.
VÉRIFIEZ LES SOURCES
Les sources
- Increasing velocity by modernizing a Python codebase Ramp Engineering · builders.ramp.com ·