Livrez plus vite que votre ombre

Agile comme Lean partagent un objectif : réduire les temps de cycle. Or, livrer une version en production est souvent une opération chère. L’objectif de la livraison continue est de réduire au maximum ce coût. Jez Humble, de ThoughtWorks, a donné une formation jeudi 30 juin sur le sujet de la livraison continue. En voici les points clés.

Qu’est ce que c’est ?

Flickr was last deployed 16 hours ago, including 5 changes by 2 people. In the last week there were 85 deploys of 611 changes by 20 people.

source : page technique de flickr

Livrer en continue, cela signifie être capable de déployer à tout moment une nouvelle version sur un environnement de production.

Pourquoi voudrais-je faire ça ?

Our highest priority is to satisfy the customer through early and continuous delivery of valuable software.

source : 1e principe Agile

Pour de nombreuses raisons. Tout d’abord, en agissant ainsi, vous limitez vos risques. En effet, plutôt que de livrer de gros changements, qui ont de nombreuses raisons d’échouer, vous ne livrez que quelques petites fonctionnalités.

Dès qu’une fonctionnalité est développée, elle peut désormais être soumise à l’utilisateur. Vous baissez ainsi drastiquement votre time-to-market.

Vous baissez ainsi la courbe d’apprentissage de votre logiciel : les utilisateurs apprennent les nouvelles fonctionnalités petit à petit. S'il s'agit d'une application interne, cela limite les coûts de formation : l'application ne change que petit à petit, et les utilisateurs peuvent s'approprier les changements au fur et à mesure.

Plus vous livrerez fréquemment, plus votre processus de livraison devra être automatisé, et donc fiable. Livrer en continue renforce rapidement votre apprentissage.

Vous responsabilisez également vos développeurs. A tout instant le code doit être dans un état livrable. Fini les gros refactoring dans un couloir noir.

C’est bien beau, mais c’est extrêmement risqué ! Comment vais-je recetter une application qui change tout le temps ?

Test automation is the use of software to control the execution of tests. […] Commonly, test automation involves automating a manual process already in place that uses a formalized testing process.

source : Wikipedia

Les tests automatisés seront vos meilleurs atouts. Vous assurerez la non-régression fonctionnelle avec ces tests. Bien sûr, ce harnais de test ne sera pas suffisant.  Votre processus ressemblera à cela :

Commit -> test JUnit -> tests fonctionnels automatisés -> tests d’interface -> tests manuels -> « smoke test » en production -> mise à disposition.

Laissons aux ordinateurs ce qu’ils font le mieux, et concentrons-nous sur la haute valeur ajoutée.  L’ordinateur va tester automatiquement votre application : ce sont les tests unitaires.

Les tests fonctionnels seront passés automatiquement, avec des outils comme Greenpepper, et comme Selenium, pour valider que vos utilisateurs ne perdent pas de fonctionnalités.

Une intervention humaine est alors nécessaire. Au final, l’interface graphique est elle jolie et intuitive ?

Une fois que l’humain a validé, l’ordinateur peut mettre une version en ligne sur un environnement parallèle à la production, faire quelques tests d’accessibilité dessus, et enfin basculer la version en production sans aucun downtime.

Toute cette chaîne est immédiatement stoppée si un des tests ne passe pas, et ce sera la priorité des développeurs que de le remettre d’aplomb.

OK. Mais de mon côté, je développe plusieurs fonctionnalités en même temps. Comment organiser mes développeurs ?

Le pricipal focus sera sur l’intégration de ces fonctionnalités. Intégrez au plus tôt ! Ne fonctionnez pas sur des « feature branches », mais sur un trunk commun.

Plusieurs fois par jours, vos développeurs feront un « checkout » de ce tronc commun. Et plusieurs fois par jour, ils « commiteront » sur ce même tronc. Ainsi, on limite au maximum les problèmatiques d’intégration, de « merge ».

Du coup, vous aurez des fonctionnalités incomplètes dans votre tronc commun. Et c’est pourtant lui qui part en production.  Pour résoudre ce problème, fonctionnez avec des paramètres**.** Si le paramètre XXX est activé, la fonction correspondante est disponible pour l’utilisateur. N’oubliez pas d’enlever les anciens paramétrages…

Pourquoi pas. Mais comment gérer la mise en production elle-même ? Je ne peux pas couper le service pour mes utilisateurs plusieurs fois par jour !

The job of the canary (in the coal mine) is to die first when there’s a new problem. It’s used as a shared resource to verify correctness of recent changes and the current state of the overall project.

source : marketwatch.com se met au canary releasing

Voici deux pattern possible.

Admettons que vous ayez deux instances de votre server d’application sur la même machine. Il est tout à fait possible d’en avoir un accessible de l’extérieur, mais pas l’autre. Celui qui n’est pas accessible ne consomme pas beaucoup puisqu’il n’est pas utilisé. Profitez-en pour déployer la nouvelle version. Puis faites quelques tests dessus, pour vérifier que votre nouvelle version est bien déployée. Enfin, basculez tous les nouveaux utilisateurs sur la nouvelle version. Cette technique se nomme le « blue-green deployement ».

Pour aller plus loin, vous pouvez faire du « canary releasing ». Décidez d’un petit groupe de personnes, qui pourront accéder à la nouvelle version – tandis que tous les autres resteront sur l’ancienne. Si tout ce passe bien pour ces utilisateurs, vous pourrez alors passer la masse des autres utilisateurs sur la nouvelle version.

Couplée avec le paramétrage des fonctionnalités, cela peut vous donner de puissants outils pour mesurer l’impact de nouvelles fonctionnalités sur le comportement de vos clients. Il faudra pour cela un très bon niveau de collaboration, du marketing jusqu'aux opérationnels, en passant par les développeurs.

OK. Mais je n'ai qu'une base de données. Je n'ai aussi qu'un seul service mainframe. Je dois bien couper l'application pour la mettre à jour !

"Database refactorings are small changes to database schemas that IMPROVE their design, not simply CHANGE the design."

source : Essai online sur le database refactoring

Une base de données est un gros système qu'il est difficile de répliquer. D'autres systèmes peuvent avoir des propriétés similaires. Vous aurez du mal à dupliquer un service mainframe. Si vous pouvez dupliquer vos environnements pour cette mise en production continue, bravo ! Vous pourrez alors appliquer les techniques de « blue-green deployement », et sauter à la conclusion. Sinon, lisez la suite.

Le cycle traditionnel est le suivant :

  • Stopper l'application
  • Mettre à jour le service concerné
  • Mettre à jour l'application
  • Redémarrer l'application.

Le problème avec cette approche ? Vous ne pouvez pas arrêter votre application plusieurs fois par jour !

Pour palier à ce problème, Jez propose de faire trois versions de l'application. La première supporte l**'ancien modèle** de base de données. La deuxième sera capable de fonctionner sur les deux schémas. Enfin, vous pourrez simplifier l'application en retirant le support de l'ancien schéma. Votre cycle deviendra alors :

  • Changer la version de l'application avec une des techniques décrites plus haut
  • Mettre à jour votre base de données. L'application n'a pas besoin d'être stoppée : elle supporte aussi bien l'ancien que le nouveau schéma.
  • Changer à nouveau votre version de l'application pour ne supporter que le nouveau schéma.

Vous n'avez plus de coupure de l'application.

Par contre, il devient alors capital que la montée de version du schéma se fasse sans surprise. Pour cela, il est nécessaire de refactorer souvent, et par petites parties votre base de données.

Un article de blog complet pourrait être dédié à la gestion de la base de données. Pour plus de détails sur sa gestion, vous pouvez consulter le site de Scott Ambler, l'auteur du livre "Refactoring Databases". Souvenez vous : plus souvent vous mettez à jour, plus vous limitez les risques. Les changements seront moins grands, et votre processus plus maîtrisé.

La livraison de fonctionnalités en continu apporte donc bien des bénéfices. Elle s’appuie cependant sur un bon nombre de pratiques agiles avancées. Vous devez avoir des tests automatisés à tous les niveaux pour assurer la non-régression. Votre base de données doit pouvoir monter de version indépendamment de votre logiciel. Votre processus de livraison doit être maîtrisé pour être automatisable. Vous devez connaître votre architecture physique sur le bout des doigts pour permettre la bascule.

La livraison en continu n’est donc pas quelque chose que vous pouvez mettre en place en un claquement de doigts. Vous pouvez cependant implémenter ou améliorer chacune des pratiques au fur et à mesure, et ainsi augmenter progressivement la qualité de ce que vous livrez.