[Développement logiciel] Le droit à l'erreur

Un nouvel article (certes pas un article en 3 ans) et oui il est toujours temps de revenir ;)
L'idée de ce retour est de coucher sur le papier des principes et valeurs qui me semblent primordiaux dans le domaine du développement logiciel pour réussir des projets et avoir un travail plaisant et non une souffrance.
Aujourd'hui je vais vous parler de droit à l'erreur. What !?

Remise dans le contexte du développement logiciel

Le développement logiciel n'est pas une activité sans risque (sans risque physique quand même hormis peut être les écrans mais ça c'est une autre histoire).
Le développement logiciel consiste en la création et l'ajout de fonctionnalités soit sur un logiciel existant soit sur un nouveau projet tout frais. Cette seconde situation ne dure pas longtemps on arrive vite à la première mise en production et on repasse dans la première situation.
On se doute bien que comme dans tous projets de toutes sortes lorsque l'on modifie un existant opérationnel pour ajouter une nouvelle fonctionnalité aussi WAOUH soit-elle il peut y avoir des perturbations. Et bien oui le seul moyen de savoir qu'il n'y en aura pas serait d'avoir déjà ajouté CETTE fonctionnalité (que l'on vient de créer) sur CE logiciel (que nous sommes en train de créer).
Ah oui là c'est pas simple surtout dans le domaine du développement logiciel sur-mesure où par définition on créé quelque chose de nouveau en permanence sinon ce n'est plus du développement sur-mesure. Pour l'état d'esprit "pas de soucis je l'ai déjà fait avant une bonne dizaine de fois je maîtrise" on repassera.
Comment faire en sorte de limiter les risques ? Oh doucement Jolly Jumper ! Non on ne va pas commencer par ça on va déjà voir Pourquoi limiter les risques ? Aussi évident que cela puisse paraître nous allons enfoncer des portes ouvertes.

Pourquoi limiter les risques dans le développement logiciel ?

Bon je vais faire une liste des éléments qui me semblent primordiaux même si cela est tellement évident, je risque donc d'en oublier et vous êtes invités lecteur attentif à me le faire remarquer ;)
Tout d'abord la raison qui me paraît évidente vient du sens même du développement logiciel. Le développement logiciel est une activité de création en opposition à une activité de reproduction. Et contrairement à une activité de reproduction qui est prédictible sur le résultat (car on a déjà fait les actions par le passé) sur une activité de création impossible de prédire le résultat, il faut donc essayer -> échouer -> adapter -> réessayer et ainsi de suite jusqu'à trouver la solution. Et plus on échoue plus on approche de la solution, il faut donc donner les moyens aux développeurs d'échouer vite et sans risque sinon le projet sera ralenti.
Ensuite parce que comme tout professionnel on aime bien que les choses soient bien gérées par exemple pour la mise en production de nouvelles fonctionnalités, et bien oui voyez-vous cela me semble inconcevable en 2018, de se dire que l'on puisse mettre en production sans un minimum de sécurité en se disant mets en production, on vérifiera en production euh pardon ? Moi je ne fais pas ça. Donc si on veut délivrer de nouvelles fonctionnalités aux utilisateurs finaux ce qui vous en conviendrez est important dans notre métier, il faut limiter les risques.
La seconde raison tout aussi importante est pour éviter le syndrome du touche pas à ça petit con car là ça marche donc on refuse les évolutions par défaut sauf si on est autorisé à tout refaire et là on passe d'une demande d'évolution relativement simple à on refait tout le projet, c'est pas sérieux encore une fois (sauf dans certains cas désespérés que nombres d'entre nous ont déjà rencontré qui sont souvent des cas où l'erreur n'est pas permise par le contexte ;)).
La troisième raison et pas des moindres, l'attrait du projet pour les développeurs, on le sait bien un développeur motivé par un projet sera bien plus productif que si le projet n'est pas attractif. Or un projet sur lequel on n'a pas le droit à l'erreur, car les risques ne sont pas contrôlés, générera du stress quand on travaillera dessus et donc on aura moins envie de travailler dessus et encore une fois les évolutions seront en permanence remises en question pour essayer de ne pas les faire. Rendons donc les projets attractifs sur ces points que l'on peut contrôler.
Parce que parfois un petit coup de gueule ne fait pas de mal, je donnerais une dernière raison, les super ninja trop fort qui mettent en prod sans se poser de questions et qui ne plantent jamais de prod bah c'est comme le "v" de winner ça n'existe pas. Tous ceux que j'ai croisé étaient juste en train de respecter la méthode "à l'arrache" et n'avaient que peu de scrupules à planter la production. Donc non, ne faisons pas croire aux intervenants d'un projet que cette façon de faire est normale et encore moins la bonne. Mettons en place les sécurités nécessaires pour assurer au mieux nos déploiements sans compter sur la chance. Sinon c'est comme les tartines de confiture qui tombent c'est toujours sur le côté confiture aïe.
Bon bah beaucoup de bon sens et de portes ouvertes enfoncées (ça fait du bien ;)). Passons au comment.

Comment peut-on limiter les risques et donc donner le droit à l'erreur aux développeurs ?

Vous connaissez la différence entre la théorie et la pratique ? En théorie il n'y en a pas. Cette douce blague nous rappelle qu'il faut faire au mieux en fonction du contexte (contexte client, état actuel du projet, budget du client, implication du client, ...). Je vais donc parler ici de théorie en indiquant par expérience la complexité à obtenir les différents points, tout cela est à relativiser en fonction du contexte.

Le contexte projet

Le contexte projet est d'ailleurs à traiter en priorité et il faut en prendre conscience, c'est un travail à part entière. Ce point doit se traiter avec le client et non dans son dos. C'est un point central pour réduire les risques sur un projet il faut avoir un but commun pour tous les acteurs du projet, tout le monde doit notamment souhaiter la réussite du projet sans que ce soit au détriment des autres parties prenantes. Il faut, souvent, partir d'une situation de défiance vers une situation de confiance. Cette confiance sera centrale pour éviter les risques qui sont bien souvent pris par contraintes et non par plaisir, stress imposé par des deadlines incohérentes, des pressions inutiles, ... Tous ces points sont à expliquer afin de les éviter au maximum et construire une vraie relation gagnant-gagnant et un partenariat. Ce point est loin d'être simple et se travaille jour après jour, il faut du temps et de la patience mais cela est juste primordial pour la réussite du projet.

Le versionning

Le changement c'est bien, le changement quand c'est maîtrisé c'est mieux, et c'est là que les outils de versionning, comme Git bien évidemment, entre en jeux afin de tracer les changements. Le but de ces outils est de tracer les ajouts et retraits de ligne de code dans la base commune de code. Cela permet notamment de retrouver les changements ayant entraîné une régression mais aussi de faire un retour arrière en cas de soucis. La mise en place de ces outils de versionning a un coût quasi nul et ne dépende que de la volonté et connaissance des développeurs sur le projet à mettre en place ce système, donc foncez ! Ce qui nous amène au point suivant la capacité de faire un retour arrière.

Le retour arrière

Un point important sur la diminution des risques est la capacité de pouvoir revenir en arrière rapidement afin de remettre une production dans un état précédent opérationnel si le déploiement en cours se passe mal. Plusieurs solutions sur ce point l'utilisation des outils de versionning comme expliqué précédemment ou alors l'utilisation d'outils de déploiement comme capistrano qui permettent de stocker chaque versions livrées et de revenir à la version précédente en une ligne de commande, d'autres outils plus ou moins graphiques permettent de gérer les déploiements et notamment cette capacité à faire un retour arrière. Ce point est un point technique au premier abord on se dit que cela ne concerne pas le client mais en fait ces éléments ne peuvent se mettre en place que dans le contexte technique du client. Et en fonction des cas, nous n'avons pas la main complète sur l'architecture et le réseau du client, il faut donc travailler de concert ce point mais en expliquant le besoin et l'intérêt de ce point, cela peut ne pas poser de difficultés.

Les environnements

L'environnement technique en production

Ce point est un peu plus croustillant, en effet il va toucher à des éléments qui peuvent cliver les personnes. Mais je veux quand même l'évoquer car par expérience les situations techniques en production des projets influent largement sur la partie développement du projet. Car oui je parle de mises en production faites par les développeurs et non par les administrateurs. On comprend alors que le développement d'une fonctionnalité ne s'arrête qu'une fois en production. Et que par conséquent la complexité des environnements techniques entraîne plusieurs risques lorsque ceux-ci ne sont mis en place que dans le but d'être "à la mode" sans une réelle maîtrise. Je ne dis pas ici de ne pas changer ces outils habituels pour les derniers outils à la mode mais juste que dans ce cas il faut s'assurer que ceux-ci n'amènent pas de risques supplémentaires dans les processus de déploiement car par expérience trop de passage sur de nouveaux outils à la mode se font sans prendre le temps de mettre en place les éléments nécessaires à la diminution des risques.
Un point qui ne sera jamais parfait mais sur lequel il faut toujours essayer d'améliorer est la capacité à reproduire l'environnement de production. Et oui voyez vous "être iso de la prod" comme on dit est très difficile mais une chose est sûre il vaut mieux être presque iso de la prod que à l'opposé car les fonctionnalités s'exécutent dans un environnement. Si cet environnement comporte de nombreuses différences avec la production alors le risque est plus grand qu'au passage en production nous rencontrions des difficultés. On comprend ici que sans une certaine maîtrise de l'environnement de production ce dernier sera difficile voir coûteux à reproduire (je pense ici à amazon, azure, and co). La conséquence directe sera de se dire on fait sans et là le risque augmente de manière importante si le client ne comprend pas l'intérêt d'être en capacité de reproduire l'environnement de production et donc de diminuer les risques alors il ne voudra pas dépenser du temps et de l'argent sur cet aspect du projet pourtant indispensable. Ce point est à la fois simple à faire comprendre mais la compréhension de ce point n'entraîne pas forcément la résolution de ce point. C'est un arbitrage entre risque et investissement où bien souvent le risque est sous-évalué, ne commettez pas cette erreur.

Les différents environnements

Pour développer dans des conditions acceptables d'un point de vue risque, il nous faut différents environnements, voici une liste non exhaustive.

  • L'environnement de développement : Environnement dédié aux développeurs idéalement en local sur leur ordinateur pour plus de réactivité et faciliter le développement de nouvelles évolutions. Encore plus idéalement conteneurisé (par exemple avec docker) ou virtualisé (par exemple avec vagrant), l'idée est que tous les développeurs aient un environnement le plus identique possible et rapidement reconstructible. Cet environnement est aussi utilisé lors des démonstrations avec le product owner des nouvelles fonctionnalités pour recueillir ces retours.

  • L'environnement de tests automatiques : Environnement dédié à l'exécution des tests automatiques situé à minima sur le poste local du développeur car utilisé au cours du développement de nouvelles fonctionnalités.

Ces 2 environnements ont un gros avantage d'un point de vue risque, ils sont complètement sans impact en cas d'erreur et ça c'est le top pour pouvoir se tromper. Dans l'idéal ces environnements sont constructibles rapidement justement en cas d'erreur et oui il faut pouvoir détruire ces environnements et les reconstruire rapidement pour faire un nombre d'essais / erreurs importants afin de concevoir de nouvelles fonctionnalités. La conséquence de cette construction rapide est que ces environnements sont proches de l'environnement de production mais forcément moins proche que l'environnement de préproduction qui lui se doit d'être le plus proche de la production possible.

  • L'environnement de préproduction : Environnement dédié au product owner pour vérifier que l'application et notamment les nouvelles fonctionnalités correspondent à ces besoins et n'entraînent pas de régressions ou d'effets de bord. Cet environnement contrairement aux environnements de développement et de tests n'a pas nécessairement besoin d'être entièrement reconstruit rapidement car il est moins susceptible de rencontrer des erreurs, il intervient après la première phase de développement afin de qualifier ce dernier.

  • L'environnement de production : Environnement référents'exécutent les développements pour les utilisateurs finaux. C'est cet environnement qu'il faut prendre comme exemple au maximum dans les différents environnements précédents en fonction du contexte et du but de chaque environnement.

  • L'environnement de qualification : Environnement similaire à l'environnement de préproduction qui permet notamment de tester des évolutions lourdes sans compromettre la préproduction afin de continuer les déploiements sereins en production.

  • Autres environnements de tests : Ici je fais mention des environnements de tests automatiques que l'on peut mettre ailleurs que sur le poste du développeur, par exemple sur la préproduction afin de qualifier les nouveaux développements plus rapidement. En production, afin de monitorer cette dernière.

Les outils de déploiement et le déploiement continu

Un point crucial dans le développement de nouvelles fonctionnalités est le déploiement en préproduction et production de ces dernières de manières régulières voir à chaque fonctionnalités ainsi que les outils utilisés pour cela. Pourquoi est-ce un point crucial qui comporte des risques ? La première réponse est tirée du paragraphe précédent. Les environnements de tests et de développement on l'a vu se doivent d'être facilement constructibles or ce n'est pas le cas de la préproduction et de la production qui sont de ce fait "plus fragiles" (surtout pour la production ;)). Par conséquent réaliser des modifications sur ces environnements représentent des risques plus importants. C'est pourquoi il faut être attentif aux outils utilisés pour ces déploiements et notamment encore une fois à leur maîtrise par l'équipe de développement plutôt qu'à la mode. Une seconde réponse est assez logique, elle vient du temps de déploiement. Comment ça !? Et bien, prenons un cas extrêmement négatif (mais bien rencontré oui) sur un projet le temps de déploiement que ce soit en préproduction ou en production il faut une clé USB et une demi journée. Dans ce cas vous avez un souci et oui si les outils de déploiement entraîne un délai incompressible aussi long qu'une demi journée vous ne pouvez pas avoir une réactivité assez importante en cas de soucis. Par exemple si vous devez appliquer une correction à chaud (hot fix) ce dernier ne sera en place qu'une demi journée plus tard et cela ce n'est pas très sécurisant comme situation ;) Donc des outils de déploiement nous vient le temps de déploiement (au passage qui comprend aussi le process humain et oui si ce ne sont pas les développeurs qui déploient il faut prendre rendez-vous avec un administrateur ou un devops et là on peut arriver sur des délais en semaine oui oui) qui est primordial pour amener de la sécurité. Un second argument dans ce sens sur l'importance du temps de déploiement est la récurrence des déploiement. Et oui un temps de déploiement trop long entraîne forcément une récurrence des déploiements faible et ça ce n'est pas bon car une fréquence de déploiements faible entraîne une méconnaissance du process de déploiement et donc un risque supplémentaire. A contrario un temps de déploiement rapide entraîne une fréquence de déploiement accrue entraîne une maîtrise du processus de déploiement et donc une sécurité.
Les processus de déploiement c'est comme les transports en commun plus on les prend et moins on a de chances de se tromper.

Ce n'est qu'avec des outils maîtrisés et rapides que l'équipe de développeurs n'a qu'une seule envie mettre en préproduction et en production et dans ce cas c'est bon pour le projet si le risque est trop grand plus personne ne veux mettre en production et là on va vers un affaiblissement du nombre de fonctionnalités livrées et surtout vers un risque énorme à chaque mise en production.

Les tests

Déjà pourquoi tester ?

Le développement logiciel se réalise en plusieurs étapes (itérations), chacune d'entre elles correspondant à l'ajout d'une nouvelle fonctionnalité, ces étapes peuvent se réaliser en parallèle ou de manière séquentielle. Dans tous les cas l'ajout d'un élément dans un système pré-existant a un impact dans le meilleur des cas positif, le changement amené par cet ajout est souhaité et répond aux besoins des utilisateurs, c'est ce que l'on souhaite tous. Ou dans le pire des cas ce changement est négatif, le changement amené déstabilise l'ensemble du système voir le rend inopérant, c'est ce que nous ne souhaitons pas voir arriver. Ce cas peut se produire pour différentes raisons, la première la nouvelle fonctionnalité est inopérante et entraîne avec elle la fonctionnalité sur laquelle elle était basée nous avons donc amenée une régression assez classique. En voulant améliorer quelque chose nous avons cassé le fonctionnement de la fonctionnalité de base, par exemple nous avions un formulaire de contact simple qui fonctionnait et nous avons ajouté un objet à ce formulaire or la validation du formulaire ne passe plus à cause de ce nouveau champs. La fonctionnalité de base du formulaire vient d'être cassée mais nous nous en apercevons très vite car nous travaillons sur ce sujet. La seconde raison qui peut amener une régression est un peu plus sournoise on l'appelle "un effet de bord" : Qu'est-ce que c'est !? C'est en fait l'ajout d'une fonctionnalité tout à fait fonctionnelle prise unitairement mais incompatible avec le reste de l'application. Par exemple, prenons un module existant un formulaire d'inscription à une newsletter se basant sur une table utilisateur et une application de e-commerce dans laquelle il y a un formulaire pour se créer un compte se basant aussi sur une table utilisateur, ici nous voyons bien que si l'on ne teste que l'un ou l'autre des modules pas de soucis mais si l'on teste ces modules ensemble nous voyons bien que nous mélangeons 2 éléments qui n'ont rien à voir et nous risquons de mélanger les uns avec les autres voire pire si à l'installation le module d'inscription de newsletter vide la table utilisateur, nous pourrions même perdre de la donnée en production.

Pour éviter la déstabilisation de l'application, il nous faut réaliser une série de tests permettant de vérifier dans différents environnements que le système n'est pas déstabilisé. Pour le "comment tester ?" il y a 2 grands types de tests, les tests manuels et les tests automatiques.

Tests manuels

Lorsque l'on développe une application nous venons de voir qu'il est nécessaire de pouvoir tester la stabilité de l'application, le moyen historique et simple à mettre en place est le test manuel. C'est assez simple, il suffit de prendre l'application dans un environnement de développement, de préproduction, de qualification ou un autre environnement (tant que ce n'est pas la production hein ;)) et utiliser l'application au plus proche de son utilisation en production, ainsi nous voyons son comportement et pouvons indiquer aux développeurs si celui-ci convient. Je dis bien utiliser l'application et non la nouvelle fonctionnalité car pour être sûr de ne pas avoir un effet de bord comme expliqué précédemment il faut vérifier l'application dans sa globalité à chaque nouvelle livraison de fonctionnalités et là on se rend compte que même avec un bon cahier de tests (documentation permettant de lister tous les cas de tests à passer avec quelles données) afin de savoir si l'application n'a pas été déstabilisée, cela reste très très long lorsque le nombre de fonctionnalités augmente. C'est pourquoi il est indispensable de passer sur des tests automatiques qui s'exécuteront bien plus vite et permettront de vérifier la stabilité de l'application plus rapidement et donc d'avoir une réactivité améliorée.

Les tests automatiques

Afin d'automatiser les tests il faut les coder et oui ça prend du temps il faut donc donner aux développeurs le temps de coder ces tests. Un test permet de vérifier une fonctionnalité avec un jeu de données précis, la globalité des tests d'une application permettent eux de vérifier la non-régression d'une application et quand ils sont automatisés on peut les lancer bien plus souvent donc on est plus serein. Je ne vais pas ici décrire en profondeur les tests automatiques mais sachez qu'il en existe de nombreux types plus ou moins adaptés en fonction des situations et en fonction de l'objectif. Mais sachez qu'en règle générale les tests automatiques sont plutôt utilisés sur les postes des développeurs et les tests manuels pour qualifier les développements en préproduction avant la mise en production. J'essaierai d'écrire prochainement un article dédié aux tests automatiques et leur utilisation qui pourrait aller plus loin ;).

Cette partie des tests et notamment automatisés est assez complexe à expliquer parfois mais encore une fois avec pas mal de bon sens et quelques erreurs arrivées en production, cela fait très vite sens que c'est un risque que nous ne pouvons pas prendre à la légère.

Conclusion

Comme nous l'avons vu tout au long de l'article le droit à l'erreur doit être permis tout au long du processus de développement de fonctionnalités et ce jusqu'à la mise en production. Ceci n'a qu'un seul but faire réussir les projets par les possibilités qui résulteront de ces risques maîtrisés car encore une fois permettre le droit à l'erreur et maîtrisés les risques permet de prendre des risques plus grand (car maîtrisés) et de faire des évolutions plus importantes sur les applications. Il faut donc ne pas sous-estimer le gain d'une mise en place de sécurité sur un projet de développement logiciel, alors travaillons ce point avec le client (product owner) sans relâche.