The DevOps Handbook
Chapitre 9 / 14 · 22 min de lecture

Intégration continue et releases à faible risque

Pratiquer l'intégration continue en tronc commun, découpler déploiement et release, et architecturer pour des mises en production sûres et routinières.

Une fois les tests automatisés en place pour donner aux développeurs un retour rapide sur la qualité de leur travail, reste à les faire converger : faire de l'intégration de chacun dans le tronc commun une partie du travail quotidien de tous, automatiser le déploiement jusqu'à le rendre banal, puis découpler ce déploiement de la décision métier de livrer aux clients. Ce chapitre couvre trois leviers qui se renforcent — intégration continue, releases à faible risque, et architecture évolutionnaire — illustrés par des dizaines d'organisations qui ont fait de la mise en production un non-événement.

Le « merge hell » des branches à longue durée de vie

La possibilité de brancher (branch) dans les systèmes de gestion de version a été inventée pour permettre aux développeurs de travailler en parallèle sur des parties différentes du système, sans risquer que les modifications des uns déstabilisent le tronc (parfois appelé trunk, master ou mainline). Mais plus les développeurs travaillent longtemps isolés sur leurs branches, plus il devient difficile d'intégrer et de fusionner les changements de tout le monde. L'effort requis pour réunir les branches croît exponentiellement avec leur nombre et le nombre de modifications dans chacune.

Jeff Atwood, fondateur de Stack Overflow, observe que toutes les stratégies de branches se placent sur un spectre entre deux extrêmes :

StratégieOptimise pourAvantageCoût
Branche privée par personneProductivité individuellePersonne ne perturbe le travail des autresLa fusion devient un cauchemar ; collaborer relève de l'exploit
Tout le monde dans le troncProductivité d'équipeCommits simples, rien à comprendreChaque commit peut casser tout le projet d'un coup

Les problèmes d'intégration se traduisent par une masse considérable de retouches (rework) pour revenir à un état déployable : conflits à résoudre manuellement, fusions qui cassent les tests, mobilisation de plusieurs développeurs. Et comme l'intégration a traditionnellement lieu à la fin du projet — où elle prend bien plus de temps que prévu —, on en est réduit à rogner les angles pour tenir la date de livraison. S'ensuit une spirale descendante : quand fusionner fait mal, on le fait moins souvent, ce qui empire les fusions suivantes.

Attention

Un dernier effet pervers des grosses fusions : quand l'intégration est douloureuse, on devient moins capable et moins motivé pour refactoriser, car chaque refonte risque de créer du rework pour tout le monde. On finit par éviter de toucher au code qui a des dépendances dans toute la base — c'est-à-dire, tragiquement, là où les gains seraient les plus élevés. C'est exactement ainsi que Ward Cunningham a défini la dette technique (technical debt) : faute de refactorisation agressive, le code devient toujours plus difficile à modifier et à maintenir.

Le développement en tronc commun

La contremesure, c'est l'intégration continue (continuous integration) et le développement en tronc commun (trunk-based development) : tous les développeurs intègrent leur code dans le tronc au moins une fois par jour. Intégrer aussi fréquemment ramène la taille des lots (batch size) au travail produit par toute l'équipe en une seule journée, nous rapprochant de l'idéal théorique du flux unitaire (single-piece flow). Plus on intègre souvent, plus on détecte tôt les conflits — donc plus on les corrige petits.

On peut même configurer le pipeline de déploiement pour rejeter tout commit qui nous sortirait d'un état déployable. C'est la technique des commits gatés (gated commits) : le pipeline vérifie d'abord que le changement soumis fusionnera proprement, buildera comme attendu et passera tous les tests automatisés avant d'être réellement intégré au tronc. Sinon, le développeur est notifié et peut corriger sans impacter quiconque dans la chaîne de valeur.

La discipline du commit quotidien force aussi à découper le travail en plus petits morceaux tout en gardant le tronc dans un état fonctionnel et livrable. La gestion de version devient alors un véritable mécanisme de communication : chacun partage une meilleure compréhension du système, connaît l'état du pipeline, et peut aider les autres quand il casse. On peut dès lors enrichir la définition de « terminé » (les ajouts en gras) :

À la fin de chaque intervalle de développement, nous devons disposer d'un code intégré, testé, fonctionnel et potentiellement livrable, démontré dans un environnement proche de la production, créé à partir du tronc via un processus en un clic, et validé par des tests automatisés.

Adhérer à cette définition garantit la testabilité et la déployabilité continues du code, et permet d'éliminer la pratique courante d'une phase séparée de test et de stabilisation en fin de projet.

À retenir

Le tronc commun n'a de sens qu'avec une solide automatisation des tests. Comme l'observe Gary Gruver, directeur de l'ingénierie de la division firmware des imprimantes LaserJet de HP : « Sans tests automatisés, l'intégration continue est le moyen le plus rapide d'obtenir un gros tas de déchets qui ne compile et ne tourne jamais correctement. » Son équipe de 400 développeurs répartis entre les États-Unis, le Brésil et l'Inde ne livrait que deux versions de firmware par an, avec seulement 5 % du temps consacré aux nouvelles fonctionnalités. En migrant tous les modèles vers un tronc commun — les capacités de chaque imprimante étant définies à l'exécution via un fichier XML, et non plus à la compilation —, en bâtissant une ferme de 2 000 simulateurs d'imprimantes et une culture qui arrête tout dès que le pipeline casse, ils ont fait passer le temps consacré à l'innovation de 5 % à 40 %, réduit les coûts de développement d'environ 40 % et fait chuter le temps de régression de six semaines à une journée.

Étude de cas : l'intégration continue chez Bazaarvoice (2012)

Bazaarvoice fournit du contenu généré par les clients (avis, notes) à des milliers de distributeurs comme Best Buy, Nike et Walmart. En 2012, l'entreprise — 120 millions de dollars de chiffre d'affaires, en route vers une introduction en bourse — reposait sur l'application monolithique Conversations : près de cinq millions de lignes de Java datant de 2006, réparties sur 15 000 fichiers, tournant sur 1 200 serveurs. Ernest Mueller, qui avait piloté la transformation DevOps de National Instruments, prend en main les processus de release.

La première tentative de passer à un rythme bimensuel, en janvier 2012, fut un désastre : 44 incidents clients, et la réaction du management se résuma à « ne refaisons plus jamais ça ». Mueller identifie trois problèmes : l'absence de tests automatisés, une stratégie de branches autorisant les commits jusqu'au dernier moment, et des microservices déployés indépendamment qui entraient en collision avec le monolithe. Pendant six semaines, les développeurs cessent de produire des fonctionnalités pour écrire des suites de tests (unitaires en JUnit, régression en Selenium) et monter un pipeline dans TeamCity. Ils adoptent un modèle tronc/branche : toutes les deux semaines, une branche de release dédiée est créée, sans nouveau commit autorisé sauf urgence.

Le gain en prévisibilité fut saisissant :

Release de janvier 2012 ──► 44 incidents clients   (début de la CI)
Release du 6 mars 2012  ──►  5 jours de retard, 5 incidents
Release du 22 mars 2012 ──►  à l'heure, 1 incident
Release du 5 avril 2012 ──►  à l'heure, 0 incident

Le succès fut tel qu'ils passèrent à des releases hebdomadaires « sans presque aucun changement côté ingénierie : c'était aussi simple que de doubler le nombre de dates sur le calendrier ». Le plus gros du travail incomba aux équipes marketing et service client, qui durent adapter leurs propres processus. Le tronc commun reste la pratique la plus controversée de l'ouvrage — beaucoup d'ingénieurs n'y croient pas avant de l'essayer —, mais les données du State of DevOps Report 2015 sont nettes : il prédit un meilleur débit, une meilleure stabilité, une satisfaction au travail plus élevée et moins de burnout.

Automatiser et permettre des releases à faible risque

Chez Facebook, Chuck Rossi, directeur de l'ingénierie des releases, supervise le push quotidien du code. Juste avant la mise en production, tout développeur dont des changements partent doit être présent sur le canal de discussion (IRC) ; les absents voient leurs changements automatiquement retirés du paquet. « Si tout est au vert sur nos tableaux de bord et nos tests canary, on appuie sur le gros bouton rouge, et en vingt minutes des milliers et des milliers de machines tournent sur le nouveau code, sans impact visible pour les utilisateurs. » Plus tard, Rossi doublera la fréquence à deux pushes par jour. Comme le résume Kent Beck, créateur de l'Extreme Programming et coach chez Facebook : « Il semble exister un nombre fixe de changements que Facebook peut gérer par déploiement. Si on veut plus de changements, il faut plus de déploiements. »

Pour atteindre cela, le déploiement doit être automatisé, répétable et prévisible. Tant qu'il reste manuel, chronophage, pénible et source d'erreurs — avec un transfert peu fiable entre Dev et Ops —, on le fait de moins en moins, et l'on accumule des différences toujours plus grandes entre le code à livrer et la production, ce qui augmente la taille des lots et le risque. On documente donc le processus (par exemple via une cartographie de la chaîne de valeur), puis on simplifie et automatise un maximum d'étapes : packaging du code, création d'images de VM ou de conteneurs, copie des paquets, redémarrage des services, génération des fichiers de configuration depuis des modèles, migrations de schéma de base de données, et tests de fumée (smoke tests) automatisés.

Les exigences du pipeline sont claires : déployer de la même façon dans tous les environnements (dev, test, production), exécuter un test de fumée à chaque déploiement pour vérifier les connexions aux systèmes dépendants, et maintenir des environnements cohérents et synchronisés. Et bien sûr, en cas de problème pendant un déploiement, on tire le cordon Andon et l'on essaime sur le problème jusqu'à résolution.

Astuce

Peu importe qui déploie. Le State of DevOps Report 2013 n'a trouvé aucune différence statistiquement significative dans le taux de réussite des changements entre les organisations où c'est Dev qui déploie et celles où c'est Ops. Dès lors qu'il existe des objectifs partagés, de la transparence et une responsabilité commune sur les résultats, on peut viser des déploiements en libre-service (self-service) : n'importe qui — développeur, testeur, chef de projet — peut builder, tester et déployer dans les environnements auxquels il a accès, sans étape manuelle ni transfert. Comme le dit Tim Tischler, de Nike : « Il n'y a jamais eu de moment plus satisfaisant dans ma carrière que lorsque j'ai écrit le code, appuyé sur le bouton pour le déployer, vu les métriques confirmer qu'il marchait en production — et que j'ai pu le corriger moi-même quand ça n'allait pas. »

Étude de cas : déploiements quotidiens chez CSG (2013)

CSG International exploite l'une des plus grandes opérations d'impression de factures des États-Unis. Scott Prugh, architecte en chef, double la fréquence des releases de deux à quatre par an. Mais les déploiements en production étaient réalisés par l'équipe Ops, alors que Dev déployait quotidiennement en test : « C'était comme si nous avions une équipe d'entraînement qui s'exerçait chaque jour dans des environnements de test à faible risque, et une équipe du match qui n'avait que deux occasions de jouer par an — dans des environnements de production à haut risque, très différents des autres. »

La solution : une Shared Operations Team (SOT) responsable de tous les environnements, déployant quotidiennement en dev et test, et en production toutes les quatorze semaines. Comme les déploiements avaient lieu chaque jour, tout problème non corrigé réapparaissait le lendemain, créant une motivation énorme pour automatiser et fiabiliser. Les déploiements étant exécutés près de cent fois avant la production, l'essentiel des problèmes était trouvé et corrigé bien en amont. Les résultats : incidents de production en baisse de 91 %, MTTR en baisse de 80 %, et délai de déploiement en mode « mains libres » passant de quatorze jours à un seul. Prugh rapporte que les équipes Ops jouaient aux jeux vidéo dès la fin du premier jour.

Étude de cas : le déploiement en libre-service chez Etsy (2014)

Contrairement à Facebook, chez Etsy n'importe qui peut déployer — Dev, Ops, Infosec. Le processus est devenu si sûr que les nouveaux ingénieurs déploient en production dès leur premier jour, tout comme des membres du conseil d'administration… et même des chiens. Les ingénieurs s'inscrivent dans une file d'attente sur un salon de discussion, voient l'activité en cours, diffusent la leur et s'entraident. Avant même de pousser leur code, ils lancent sur leur poste les 4 500 tests unitaires (moins d'une minute, tous les appels externes étant simulés) ; à l'intégration dans le tronc, plus de 7 000 tests automatisés s'exécutent en parallèle sur dix machines Jenkins, en onze minutes. Suivent les tests de fumée et les tests fonctionnels sur « Princess », un serveur de production retiré de la rotation, donc rigoureusement identique à la production. Via leur outil maison Deployinator, on pousse vers la QA, puis vers la production en un clic — et tout le monde sait, sur IRC et par e-mail, qui a poussé quoi. En 2009, déployer était source de stress et de peur ; en 2011, c'était une routine se produisant 25 à 50 fois par jour.

Découpler déploiement et release

Dans le lancement traditionnel d'un projet, la mise en production est dictée par la date de lancement marketing : la veille au soir, on déploie le logiciel (aussi complet que possible), et le lendemain on l'annonce au monde. Trop souvent, les choses tournent mal — charges jamais testées, retour arrière douloureux, correctifs risqués en production. Pour briser ce cycle, il faut découpler la mise en production de la livraison aux clients. Dans la pratique, les deux termes sont employés indifféremment ; ce sont pourtant deux actes distincts qui servent deux objectifs différents.

AspectDéploiement (deployment)Release
Nature de l'acteTechniqueMétier
DéfinitionInstaller une version donnée du logiciel dans un environnementRendre une fonctionnalité disponible aux clients (ou à un segment)
Qui en est responsableDev et OpsLe product owner
Lien au clientPeut n'avoir aucun lien avec une mise à dispositionDétermine ce que voient les utilisateurs
Risque concernéRisque de déploiement (erreurs techniques)Risque de release (le bon résultat métier est-il atteint ?)

Conflater les deux brouille la responsabilité. Les découpler permet de confier à Dev et Ops la réussite de déploiements rapides et fréquents, tout en laissant aux product owners la responsabilité des résultats métier. Surtout, dès lors qu'on sait déployer à la demande, le moment où l'on expose une fonctionnalité aux clients devient une décision métier et marketing, plus une décision technique. Deux grandes familles de patterns rendent cela possible : ceux fondés sur l'environnement (infrastructure) et ceux fondés sur l'application (code).

PatternFamilleMécanismeAtout principal
Bleu-vert (blue-green)EnvironnementDeux environnements de prod ; un seul reçoit le trafic ; on basculeSimple, peu de changement applicatif, retour arrière immédiat
CanaryEnvironnementPromotion automatique vers des environnements de plus en plus critiquesSécurité accrue, lead time réduit
Cluster immunitaireEnvironnementLe monitoring déclenche un retour arrière automatique hors plage attendueDétecte les défauts invisibles aux tests, réaction rapide
Feature togglesApplicationConditionnelle dans le code activant/désactivant une fonctionnalitéRelease par fonctionnalité, dégradation gracieuse, résilience
Dark launchApplicationDéployer du code masqué et le tester avec du trafic réelValider la charge réelle des semaines avant le lancement

Patterns fondés sur l'environnement

Ces patterns ne nécessitent aucun changement applicatif : on dispose de plusieurs environnements, mais un seul reçoit le trafic réel. Du coup, on ne déploie plus la nuit ou le week-end — Ops retrouve enfin des horaires de bureau normaux.

Le plus simple est le déploiement bleu-vert (blue-green) : deux environnements de production, bleu et vert, dont un seul sert le trafic à la fois. On déploie la nouvelle version dans l'environnement inactif, on la teste sans perturber les utilisateurs, puis on bascule le trafic — le retour arrière se fait simplement en redirigeant le trafic vers l'ancien. Le pattern est trivial à monter (un changement de routeur, un lien symbolique). La difficulté apparaît quand les deux versions partagent une base de données : il faut soit deux bases (avec un risque de perte de transactions au rollback), soit découpler les changements de base des changements applicatifs en ne faisant que des modifications additives, sans jamais muter ni supprimer d'objet existant — c'est le pattern expand/contract, utilisé par IMVU pour atteindre cinquante déploiements par jour.

Note

Étude de cas — Dixons Retail (2008). Dan North et Dave Farley, co-auteurs de Continuous Delivery, ont appliqué le bleu-vert à des milliers de terminaux de point de vente (POS) répartis dans des centaines de magasins. La bande passante était trop faible pour tout mettre à jour d'un coup, rendant impossible la migration « big bang ». Ils ont donc fait tourner deux versions du serveur central, poussé le nouveau logiciel client en état inactif des semaines à l'avance, puis laissé chaque directeur de magasin décider du moment de la release selon ses besoins. Résultat : une mise à jour bien plus fluide, des directeurs satisfaits, et la démonstration que les patterns DevOps s'appliquent aussi à des applications lourdes installées sur poste, et pas seulement aux services web.

Le canary automatise la promotion vers des environnements successivement plus larges et critiques, en surveillant le comportement à chaque étape : si quelque chose dérape, on revient en arrière ; sinon, on passe au suivant. Le nom vient des canaris que les mineurs descendaient dans les galeries pour détecter le monoxyde de carbone. Facebook organisait ainsi ses serveurs en groupes : A1 (employés internes seulement), A2 (un petit pourcentage de clients, une fois certains critères atteints) puis A3 (le reste). Le cluster immunitaire (cluster immune system) va plus loin en reliant le monitoring de production au processus de release : il déclenche un retour arrière automatique quand une métrique orientée utilisateur (par exemple le taux de conversion) sort de la plage attendue. Documenté par Eric Ries chez IMVU, il protège contre les défauts difficiles à attraper par les tests — comme un changement CSS rendant invisible un élément critique de la page.

Patterns fondés sur l'application

Implémentés dans le code, ces patterns offrent une flexibilité encore plus fine, souvent par fonctionnalité — mais exigent l'implication des développeurs. Le mécanisme central est le feature toggle (ou feature flag) : on enveloppe une portion de logique ou d'interface dans une condition activée ou désactivée par une configuration (fichier JSON ou XML, annuaire, ou service dédié). Au-delà de la simple bascule, les feature toggles permettent de :

  • revenir en arrière facilement — désactiver une fonctionnalité problématique est bien plus simple que de défaire toute une release ;
  • dégrader le service gracieusement — sous très forte charge, on réduit le niveau de fonctionnalité (par exemple en coupant les recommandations gourmandes en CPU) pour continuer à servir plus d'utilisateurs ;
  • gagner en résilience dans une architecture orientée services — on déploie une fonctionnalité qui dépend d'un service encore indisponible, masquée derrière un toggle, et on l'active quand le service arrive ; et inversement, on coupe une fonctionnalité quand le service dont elle dépend tombe.

Les feature toggles ouvrent la voie au dark launching (lancement à l'ombre) : on déploie toute la fonctionnalité en production puis on la teste pendant qu'elle reste invisible pour les clients. On peut, par exemple, faire émettre par 1 % des sessions des appels invisibles vers la nouvelle fonctionnalité, jeter les résultats, et augmenter progressivement la charge simulée pour valider le comportement sous des conditions réalistes — parfois des semaines avant le lancement réel. John Allspaw, alors VP des opérations chez Flickr, résumait l'effet : ce processus « augmente la confiance de chacun presque jusqu'à l'apathie » quant à la peur des problèmes de charge.

À retenir

Étude de cas — le dark launch de Facebook Chat (2008). Avec 70 millions d'utilisateurs actifs quotidiens, le défi n'était pas d'envoyer des messages mais de tenir chaque utilisateur informé de l'état en ligne / inactif / hors ligne de ses amis — un problème de complexité computationnelle catastrophique. Pendant près d'un an, l'équipe Chat a intégré son code chaque jour, masqué aux utilisateurs externes par Gatekeeper, le service de feature toggling de Facebook. Surtout, chaque session utilisateur chargeait un harnais de test invisible : le navigateur envoyait de faux messages de chat au service back-end déjà en production, faisant de chaque utilisateur un participant à un gigantesque test de charge. Le jour du lancement, il suffit de deux étapes — rendre la fonctionnalité visible via Gatekeeper et charger le nouveau JavaScript — pour passer « de zéro à soixante-dix millions d'utilisateurs du jour au lendemain ». Comme l'écrit l'ingénieur Eugene Letuchy : « Le secret pour aller de zéro à soixante-dix millions d'utilisateurs en une nuit, c'est d'éviter de tout faire d'un seul coup. »

Architecturer pour des releases à faible risque

Presque tous les exemplaires connus du DevOps — LinkedIn, Google, eBay, Amazon, Etsy — ont frôlé la mort à cause de problèmes architecturaux. C'est le principe de l'architecture évolutionnaire (evolutionary architecture) : comme l'observe Jez Humble, l'architecture « de tout produit ou organisation à succès évoluera nécessairement au cours de son cycle de vie ». Randy Shoup, qui fut architecte distingué chez eBay puis ingénieur chez Google, rappelle que « eBay et Google en sont chacun à la cinquième réécriture intégrale de leur architecture ». L'enjeu n'est pas de trouver l'architecture parfaite — il n'y en a aucune pour tous les produits et toutes les échelles — mais de savoir migrer continûment de l'architecture qu'on a vers celle dont on a besoin. Chez eBay, on commençait par un petit projet pilote pour prouver qu'on comprenait assez le problème, en visant les pages du site classées par revenu généré, et l'on s'arrêtait dès que le retour métier ne justifiait plus l'effort.

Une architecture trop fortement couplée se repère facilement : chaque tentative d'intégrer du code dans le tronc ou de déployer en production risque de provoquer des pannes globales. Le moindre changement exige alors une coordination énorme sur des jours ou des semaines, des approbations de tous les groupes potentiellement affectés, et des déploiements aux lots de plus en plus gros. D'où ce symptôme : « Mes développeurs ne passent que 15 % de leur temps à coder — le reste se passe en réunions. » À l'inverse, une architecture faiblement couplée (loosely-coupled), avec des interfaces bien définies qui dictent comment les modules se connectent, favorise productivité et sécurité : elle permet à de petites équipes « deux pizzas » de faire de petits changements déployables de façon indépendante et sûre, et l'API bien définie de chaque service facilite tests, contrats et SLA entre équipes. Shoup le résume à propos de Google : le service Cloud Datastore, l'un des plus gros NoSQL au monde, est maintenu par une équipe de huit personnes seulement, parce qu'il s'appuie sur des couches de services fiables empilées les unes sur les autres.

Note

Étude de cas — l'architecture évolutionnaire d'Amazon (2002). Amazon a démarré en 1996 comme une application monolithique baptisée Obidos, qui finit par contenir toute la logique métier et d'affichage (similarités, recommandations, Listmania, avis). Avec le temps, raconte le CTO Werner Vogels, Obidos devint « trop emmêlé », ses relations de partage complexes empêchant de mettre à l'échelle les morceaux indépendamment : « il ne pouvait plus évoluer ». Amazon migra vers une architecture orientée services (service-oriented architecture, SOA), dont Vogels tire trois leçons : l'orientation services stricte procure une isolation et un niveau de propriété inédits ; interdire l'accès direct à la base par les clients permet d'améliorer scalabilité et fiabilité sans les impliquer ; et le modèle de services crée des équipes pleinement responsables de leur service, de la conception à l'exploitation. L'effet sur la productivité fut spectaculaire : environ 15 000 déploiements par jour en 2011, près de 136 000 par jour en 2015.

Le pattern strangler fig

Le terme strangler fig (figuier étrangleur) a été forgé par Martin Fowler en 2004, inspiré par des lianes vues en Australie : « Elles s'enracinent dans les branches hautes d'un figuier et descendent peu à peu jusqu'au sol, finissant par étrangler et tuer l'arbre hôte. » Plutôt que d'« arracher et remplacer » un service vieillissant, on place la fonctionnalité existante derrière une API sans plus la modifier, et toute fonctionnalité nouvelle est implémentée dans les nouveaux services avec l'architecture désirée, appelant l'ancien système au besoin.

                  ┌─────────────────────────────────┐
   Trafic   ──►   │   Façade / API versionnée        │
                  └───────┬───────────────────┬──────┘
                          │                   │
            (nouvelles)   ▼                   ▼  (héritées, intactes)
                ┌──────────────────┐   ┌──────────────────┐
                │ Nouveaux services│   │  Monolithe legacy │
                │  faiblement      │──►│  (derrière l'API, │
                │  couplés         │   │   appelé au besoin)│
                └──────────────────┘   └──────────────────┘

   À chaque itération, on déplace une part de fonctionnalité
   vers les nouveaux services ──► le monolithe RÉTRÉCIT,
   parfois jusqu'à disparaître entièrement.

On cherche à accéder à tous les services via des API versionnées (versioned APIs, ou services immuables) : modifier un service sans impacter ses appelants, en créant une nouvelle version et en y migrant progressivement les équipes dépendantes. Gare à ne pas reproduire le piège du couplage fort en laissant la nouvelle application se connecter directement à la base d'un autre service. Fowler met en garde contre la tentation de la réécriture intégrale : « Vous croiriez ça facile — faire que le nouveau fasse ce que faisait l'ancien. Pourtant c'est toujours bien plus complexe qu'il n'y paraît, et débordant de risque. » L'approche par étranglement progressif évite ce piège et permet de livrer de la valeur incrémentale tôt.

Piège courant

Étude de cas — Blackboard Learn (2011). L'éditeur de technologies éducatives traînait une base de code J2EE remontant à 1997 (« nous avons encore des fragments de Perl disséminés partout », note l'architecte en chef David Ashman). Les graphes de leur dépôt étaient éloquents : le nombre de lignes de code continuait de grimper tandis que le nombre de commits diminuait — preuve objective de la difficulté croissante à changer le code, le simple retour de leur processus d'intégration prenant 24 à 36 heures. En appliquant le strangler avec ce qu'ils appelèrent les Building Blocks — des modules découplés du monolithe et accessibles via des API fixes —, ils inversèrent la tendance : « Chaque développeur, quand on lui laissait le choix, voulait travailler dans la base Building Blocks », où il jouait avec plus d'autonomie, de liberté et de sécurité, les erreurs ne causant plus que des pannes locales au lieu de catastrophes globales.

L'architecture est, de fait, l'un des principaux prédicteurs de la productivité des ingénieurs et de la rapidité avec laquelle les changements peuvent être faits en sécurité — un résultat confirmé par le State of DevOps Report 2015. Combinés, l'intégration continue en tronc commun, le découplage déploiement/release et l'architecture évolutionnaire transforment la mise en production : non plus un drame mobilisant des dizaines d'ingénieurs autour de l'horloge, mais une routine quotidienne qui ramène les délais de déploiement de plusieurs mois à quelques minutes — et qui, enfin, rend le travail d'exploitation humain.

À retenir

  • L'intégration continue combat le merge hell : intégrer dans le tronc commun au moins une fois par jour maintient des branches courtes, réduit la taille des lots et détecte les conflits quand ils sont petits ; les commits gatés empêchent même tout changement de sortir le tronc d'un état déployable.
  • Le tronc commun (trunk-based development) est la pratique la plus controversée du livre mais l'une des plus rentables — HP LaserJet a fait passer le temps d'innovation de 5 % à 40 %, Bazaarvoice de 44 incidents à zéro en quatre releases.
  • Déploiement et release sont deux actes distincts : le déploiement est l'installation technique d'une version dans un environnement ; la release est la décision métier de rendre une fonctionnalité disponible aux clients. Les découpler clarifie les responsabilités et fait de l'exposition aux clients une décision marketing, pas technique.
  • Les patterns fondés sur l'environnement (bleu-vert, canary, cluster immunitaire) réduisent le risque sans toucher au code applicatif ; ils permettent de déployer en horaires de bureau et de revenir en arrière en redirigeant simplement le trafic.
  • Les patterns fondés sur l'application (feature toggles, dark launching) offrent une release par fonctionnalité, la dégradation gracieuse et le test sous charge réelle avant le lancement — comme Facebook Chat passant « de zéro à soixante-dix millions d'utilisateurs » grâce à un harnais de test invisible.
  • Une architecture faiblement couplée à interfaces bien définies permet à de petites équipes de déployer indépendamment et en sécurité ; Amazon est passé d'un monolithe à une SOA pour atteindre 136 000 déploiements par jour.
  • Le pattern strangler fig fait migrer une architecture en plaçant le legacy derrière une API versionnée et en construisant le neuf à côté, jusqu'à faire rétrécir le monolithe — bien plus sûr qu'une réécriture « big bang », toujours « débordante de risque ».