Table of Content
Toutes les équipes sont aux prises avec la dette technique, et toute équipe de développement logiciel crée une dette technique qu’elle s’efforce de minimiser. Certaines équipes sont meilleures que d’autres pour rembourser cette dette et parviennent à reconnaître ses répercussions négatives, à quantifier ses impacts potentiels, à hiérarchiser les corrections à apporter et à suivre un plan de résolution.
La dette technique est un frein au développement logiciel. Elle rend le code plus difficile à écrire, exécuter et déployer et peut même entraîner des interruptions majeures de la production. S’attaquer aux problèmes techniques, c’est la partie facile : cela implique habituellement le remaniement (refactoring) ou la modification d’une partie du code. La difficulté consiste à hiérarchiser et à quantifier la dette technique. Si les équipes de développement logiciel ne parviennent pas à résoudre la dette, c’est parce qu’elles ne s’y prennent pas assez tôt, et non parce qu’elles ne peuvent pas corriger les problèmes techniques.
Le remboursement de la dette technique et le développement de nouvelles fonctionnalités se disputent constamment la priorité parmi les tâches en souffrance. Lorsque l’on passe du développement d’application en cascade à Agile, la dette technique est souvent héritée des anciens systèmes et du code existant. Il n’existe pas de solution universelle permettant d’éliminer la dette technique, mais il est clair que les équipes agiles y sont invariablement confrontées sous de nombreuses formes différentes. Par ailleurs, travailler sur les mauvais problèmes pour rembourser un type de dette particulier fait perdre du temps et de précieuses ressources, ce qui est contraire aux principes d’Agile.
Trois niveaux : la dette locale, globale ou systémique
Certaines dettes finissent par amener les équipes à prononcer la faillite de leur logiciel, tandis que d’autres entraînent simplement le versement d’intérêts. Les dettes insignifiantes peuvent être ignorées puisqu’elles pourront être remboursées à tout moment. Les équipes font l’erreur de croire que toutes les dettes techniques devraient être éliminées, alors qu’en réalité, il ne faut se débarrasser que des dettes les moins viables. La dette technique se divise en trois grandes catégories : elle peut être locale, globale ou systémique. Il est important de catégoriser correctement chaque type de dette afin de séparer les dettes viables des dettes non viables.
La dette locale
se limite à une méthode, classe ou fonction unique. Imaginez des violations de SOLID appliquées à une méthode, une classe, une fonction ou un fichier unique. Leurs répercussions ne se ressentent que lors de la modification du code concerné.
La dette globale
se limite à une application ou un service unique. Contrairement à la dette locale, la dette globale implique des violations de SOLID à travers les sous-systèmes d’un système plus large qui s’étendent à des zones sans lien apparent. Par exemple, il peut s’agir d’une incompatibilité entre les couches d’abstraction (présentation vs données), de problèmes à d’autres points d’intégration ou de couplage fort. Ces problèmes n’affectent pas les utilisateurs de l’application ou du service mais se ressentent lors de la modification du service.
La dette systémique
s’étend à plusieurs applications, plusieurs infrastructures voire de multiples équipes. Par exemple, il peut s’agir de plusieurs services partageant une base de données, d’un couplage élevé à travers différents contextes délimités, ou encore d’une forte incompatibilité entre les mises en œuvre techniques et la logique métier. Les dettes systémiques ne sont pas viables sur le long terme.
Les catégories de dette ont chacune des répercussions différentes, si bien qu’elles doivent être hiérarchisées et traitées différemment.
Dette technique locale : les tâches les plus simples avec Agile
Les techniques connues de refactoring comme « l’extraction de méthode » ou « l’extraction de super-classe » permettent généralement de rembourser la dette technique locale. Elles peuvent même imiter les katas de code connus, ce qui fait d’elles les corrections les moins importantes et les rend même insignifiantes. Prenons un exemple :
Un ingénieur a écrit du code il y a un an. Son code est trop compliqué mais a passé les tests. C’est loin d’être le meilleur code, mais il fonctionne. Les exigences métier n’ont pas changé, si bien que le code reste tel quel.
Des ingénieurs veulent peut-être refactoriser ce code, mais cela n’en vaut pas la peine puisque ce code n’a pas été modifié depuis un an. D’un autre côté, la dette technique locale dans du code fréquemment modifié freine le développement, car ce code a généralement un rôle fondamental pour l’activité et d’autres développeurs doivent le comprendre et le modifier. Ici, éliminer la dette revient assurer la maintenance de la voie de gauche d’une autoroute en rebouchant les nids-de-poule. Si la dette technique n’est pas correctement remboursée, les ingénieurs écriront du code de plus en plus instable pour y pallier, et pourraient finir par créer une dette technique globale.
Les outils d’analyse du code statique permettent de limiter la dette technique locale, et presque de l’éliminer lorsqu’ils sont utilisés avant de valider le code et dans le cadre du processus de déploiement. Cependant, vous devrez adopter une approche différente pour lutter contre les problèmes existants. Pour commencer, il est préférable de confier les corrections locales aux nouveaux membres de l’équipe en guise d’exercice d’apprentissage. Les équipes peuvent également appliquer la « règle des boy scouts » selon laquelle tout programmeur devrait laisser le code en meilleur état qu’il ne l’a trouvé, une pratique qui fonctionne bien puisque les améliorations du code sont proportionnelles à la fréquence à laquelle le code est modifié.
La dette technique globale : les premiers signes de difficultés
La dette technique globale est nuisible. Voici un exemple basé sur une application web MVC typique :
L’équipe isole des préoccupations de couches de vue complexes dans une couche de présentation et reçoit une spécification selon laquelle l’IU doit afficher des données personnalisées. Les couches intermédiaires existantes ne le permettent pas, si bien que la couche de présentation appelle directement la base de données. Il s’agit d’abord d’une erreur d’encapsulation, qui peut déclencher la théorie de la vitre cassée et affecter d’autres zones.
Cela se produit plus souvent que les ingénieurs ne veulent bien l’admettre. Malheureusement, ces problèmes n’ont pas de solution rapide, car il faut s’intéresser à l’ensemble du code lié pour arriver à une solution. Les ingénieurs expérimentés sont les mieux équipés pour rembourser la dette en séparant soigneusement les préoccupations, en créant des limites et en faisant appliquer des préoccupations d’architecture de plus grande portée.
Une gouvernance judicieuse et des améliorations de workflow permettent d’atténuer les problèmes avant qu’ils ne surviennent, et l’ajout d’une étape d’examen minutieux du code à des versions spécifiques est un bon point de départ. Toutes les versions ne se valent pas. Les versions qui modifient le code à travers les limites ou qui remanient des concepts métier fondamentaux doivent être examinées de près afin de limiter la dette technique. Pour les versions qui modifient une seule classe peu utilisée, ce n’est pas nécessaire. Ces préoccupations devraient faire l’objet d’un shift left dans le workflow ; autrement dit, les ingénieurs devraient aborder la dette technique potentielle le plus tôt possible dans le processus afin de limiter les problèmes par la suite.
Il faut s’occuper de la dette technique globale lorsqu’elle freine le développement du code fréquemment modifié. Si la solution ne vous apparaît pas clairement dès le départ, adoptez une solution 80/20 potentielle et prenez des mesures rapidement avant de vous retrouver avec un problème systémique. Le nettoyage prendra du temps qui aurait dû être consacré aux sprints ; il faut donc vous organiser en conséquence.
La dette technique systémique
La dette technique systémique est la forme la plus dangereuse. Elle se manifeste durant toutes les phases du cycle de développement du système. Elle peut sérieusement ralentir le développement, démotiver les ingénieurs, vous forcer à réécrire le code de fond en comble et même causer la perte d’une société. Si la dette systémique est si puissante, c’est parce qu’elle capture les problèmes au niveau de l’architecture. Voici quelques exemples de problèmes susceptibles de survenir : utiliser une base de données NoSQL lorsqu’un système de gestion de base de données serait un meilleur choix, créer un couplage étroit entre des services indépendants, communiquer à travers des contextes délimités via une base de données partagée, diviser les préoccupations métier en un trop grand nombre de microservices, ou encore choisir la mauvaise architecture de déploiement.
Les problèmes systémiques ont tendance à prendre les équipes de développement de court. Ils sont toujours là, tapis dans l’ombre jusqu’au moment où une modification ou demande inoffensive fait naître en vous un sentiment de consternation. Vous vous frappez le front et tous vos collègues soupirent en réalisant qu’il y a un problème.
Il n’existe pas de solution prescriptive pour résoudre les problèmes systémiques. Pour rembourser cette dette, il faut des équipes d’ingénieurs, une planification et une exécution minutieuses, et du temps, la ressource la plus rare. Par conséquent, l’organisation a tout intérêt à s’attaquer à ces problèmes au plus tôt.
Construire une architecture évolutive permet d’automatiser la lutte contre les problèmes systémiques. Building Evolutionary Architectures propose de tester les caractéristiques d’architecture clés, comme le couplage des éléments ou la durabilité, à l’aide de fonctions d’adéquation. Le processus de déploiement exécute les fonctions d’adéquation dans le cadre de la vérification des critères, ce qui lui permet de rejeter le code qui présente de graves problèmes. Si vous ne pouvez pas adopter cette approche, vous devrez mettre en place des examens du code stricts de haut niveau avec des ingénieurs expérimentés afin d’identifier les problèmes à la main.
À ce stade, il est possible de définir des priorités et d’élaborer une stratégie afin d’atténuer la dette technique de votre organisation.
Hiérarchiser les tâches en souffrance
La dette technique devient un problème lorsque l’on ne s’en occupe pas. De nombreuses organisations ignorent ce problème, en espérant qu’il se résoudra par lui-même, ou concentrent leurs efforts dans la mauvaise direction. Les équipes font également une erreur lorsqu’elles prennent en compte la dette technique à travers plusieurs projets et les répercussions directes et indirectes qu’elle peut avoir. Par exemple, dans les projets dépendants, la dette technique peut freiner la livraison logicielle dans d’autres projets. Les équipes agiles doivent comprendre que la valeur de chaque dette a pour facteurs sa portée (locale, globale ou systémique), ses répercussions sur le code fréquemment modifié ainsi que le temps nécessaire pour la corriger. Les équipes doivent donner la priorité aux corrections et coordonner les versions à travers les tâches en souffrance de l’ensemble des projets.
Pour rembourser la dette technique, le mieux est d’adopter une approche 80/20 consistant à améliorer le développement sur les chemins de code les plus fréquemment modifiés. L’objectif n’est pas d’éliminer la dette technique mais de faire en sorte qu’elle reste facile à gérer et de l’intégrer à votre livraison logicielle agile. Par ailleurs, si elle ne freine pas les activités de développement courantes, laissez-la tranquille. Ainsi, l’équipe continuera à travailler dans la bonne direction.
Le remboursement d’une dette locale sans conséquences peut donc être relégué au bas de la pile, tandis que le remboursement de la dette technique globale vous apportera certainement les meilleurs résultats 80/20 en vous protégeant contre la dette systémique et en améliorant le développement du code fréquemment modifié. Donnez la priorité aux solutions 80/20 et partez de là. Reste donc le problème des dettes techniques systémiques. Leur résolution peut nécessiter de nombreux sprints et doit s’inscrire dans une stratégie à long terme. À nouveau, donnez la priorité aux solutions 80/20 pour les problèmes systémiques. Le résultat devrait vous aider à estimer les corrections à apporter et à les hiérarchiser par rapport à d’autres tâches en souffrance.
Ne vous donnez pas pour objectif d’éliminer la dette technique dans une seule release massive. Les corrections de la dette technique devraient être publiées par petits lots en continu. En pratique, ces versions peuvent regrouper plusieurs corrections de la dette technique locale. Les corrections des dettes globale et systémique nécessitent plusieurs petites releases ciblées. Le remboursement des dettes globale et systémique est compliqué ; allez-y doucement et posément et évitez d’inclure d’autres modifications dans les versions consacrées à ces catégories de dette. Votre stratégie de gestion des release devrait également promouvoir la visibilité sur les corrections et sur leurs relations avec d’autres projets et versions.
Donnez la priorité au futur avec l’investissement technique
Les investissements techniques dans l’automatisation des tests logiciels, les analyses statiques et les fonctions d’adéquation apportent de la qualité au processus. Au fil du temps, ils permettent de sortir la dette technique des tickets en souffrance et de l’intégrer à la culture actuelle. C’est ce genre de changement culturel agile qui permet de limiter les problèmes, jusqu’à ce que la dette systémique ne se manifeste plus que rarement.
Ce futur vous semble certainement lointain, c’est pourquoi vous devrez commencer par hiérarchiser les tâches en souffrance en tenant compte des différentes catégories de dette technique ainsi que du code et des flux métier affectés. Vous devrez également hiérarchiser les efforts à travers l’ensemble des projets, car tous les projets ne se valent pas. La visibilité sur l’ensemble des projets et des versions, qui peut être obtenue grâce à des logiciels comme Panaya, est essentielle pour décider des prochaines tâches à effectuer.
Évitez de corriger des problèmes locaux et intégrez en priorité l’analyse du code statique à votre ensemble de test existant afin de limiter la création d’une plus grande dette technique locale. Ensuite, donnez la priorité aux solutions 80/20 pour les problèmes de dette technique globale les plus graves. N’ayez pas les yeux plus gros que le ventre en vous attaquant dès le départ à la dette systémique. Élaborez une stratégie technique permettant d’atténuer les répercussions de cette dernière et concentrez vos efforts sur les solutions 80/20 après avoir traité les points de douleur urgents.
Pour cela, vous pouvez utiliser une solution de livraison agile en entreprise. La transition vers Agile n’a pas à être fastidieuse. Regardez ce webinaire pour découvrir comment.