En informatique, la dégradation logicielle, nommée également érosion logicielle et érosion de l'architecture logicielle ou encore vieillissement logiciel , est le déséquilibre ou l'écart entre l'architecture logicielle et son implémentation. Elle désigne également le phénomène où l'architecture d'un système logiciel ne permet plus de changements à celui-ci, à cause des changements continus introduits dans le système et qui le rend donc non maintenable.
L'architecture logicielle permet de décrire comment doit être conçu le logiciel pour répondre aux spécifications de celui-ci. L'implémentation logicielle doit correspondre au modèle d'architecture produit lors de la phase de conception. Dans la pratique, il n'est pas toujours évident de respecter cette règle. Les origines des décalages sont multiples : l'évolution logicielle, les erreurs d'implémentations, les contradictions dans l'architecture envisagée qui ne pouvaient être prévues avant le développement, etc. Il est possible de faire face à cette problématique en appliquant des concepts du génie logiciel et en utilisant divers moyens pour trouver où se situent ces points d'érosion et comment les contrer.
Principe de base
Pour comprendre l'importance de l'architecture, il est nécessaire de connaître les différentes étapes à suivre lors de la réalisation d'un projet. Tout projet est issu d'un besoin. Pour satisfaire les futurs utilisateurs, il est nécessaire d'étudier leurs besoins avant de développer une solution. Grâce à cela, il sera possible de définir une architecture logicielle adaptée afin d'obtenir un résultat proche de celui escompté. Avec une architecture bien définie, l'implémentation de la solution sera facilitée et correspondra mieux aux attentes du client s'il n'y a pas de divergences entre les deux.
Importance de l'architecture logicielle L'architecture logicielle permet de réaliser entièrement le logiciel sous une forme théorique avant de le réaliser de manière pratique. Ceci permet de prévoir les contraintes techniques, d'envisager les évolutions de manière adaptée et de garantir la qualité du logiciel. Par conséquent, les coûts sont réduits et les logiciels sont sensiblement de meilleures qualités. L'architecture logicielle joue un rôle important dans les six aspects, ci-dessous, du développement logiciel : Elle simplifie notre capacité à comprendre les gros systèmes en les représentant par un niveau d'abstraction dans lequel une architecture de système haut niveau peut facilement être perçue. Elle favorise la réutilisation à multiples niveaux, des bibliothèques de composants aux framework. Elle permet la construction d'un plan pour le développement en indiquant les dépendances entre les différents composants. Elle facilite la mise en place des évolutions. Elle offre des nouvelles possibilités pour l'analyse telles que la vérification de la cohérence du système, la conformité des contraintes imposées par le style d'architecture, etc. Elle permet la bonne gestion de projets.
Liaisons entre architectures et implémentations Pour faire la liaison entre l'architecture et l'implémentation, il est nécessaire de définir un ensemble de règles. Celles-ci permettront de détecter lorsque l'implémentation sera en train de dévier de l'architecture.
Il est possible de distinguer deux types de règles: les règles structurelles et les règles d’interactions. Les règles structurelles concernent l'existence des mêmes entités et les relations qui les unissent tandis que les règles d’interactions concernent essentiellement la présence des appels de méthode dans le même ordre.
Avec cet ensemble de règles, lors de l'analyse il y a trois types de résultats possibles : Convergence : La relation implémentée correspond à celle définie dans l'architecture. Divergence : La relation implémentée diffère de celle définie dans l'architecture. Absence : La relation est présente dans l'architecture mais n'est pas implémentée.
Il suffit maintenant de traiter chaque divergence et absence une par une. La pratique la plus courante est de modifier le code pour qu'il corresponde à l'architecture. Néanmoins, il est possible de devoir modifier l'architecture du projet à cause de difficultés techniques lors du développement.
Causes de dégradations logicielles Les principales causes des dégradations logicielles sont les modifications apportées au code, à la documentation dans le non-respect des règles architecturales.
Changement des besoins utilisateurs L'une des principales causes des dégradations dans les architectures est l'évolution du besoin client. Le client n'est pas toujours conscient de ce qu'il attend jusqu'à ce qu'il ait une première version du produit. Il essaye alors d'apporter des modifications aux spécifications. Ce problème est également constaté lorsque les spécifications ne sont pas assez précises. Ces deux points définissent les deux principaux types de vieillissement logiciels : les défaillances causées par les modifications des propriétaires du produit à la suite des évolutions du besoin, et le résultat des modifications effectuées à la suite d'incompréhensions des deux parties (client/concepteur du logiciel) lors de la conception et du développement du produit.
Évolution du matériel Une autre cause de dégradations de logicielles est le matériel auquel se rattache le logiciel. Les architectures logicielles sont conçues dans le respect du matériel dont le logiciel dépend. Au fil du temps, le matériel est susceptible de changer et cela peut provoquer une instabilité et compromettre l'architecture prévue.
Allocation mémoire Les modifications apportées au logiciel durant sa durée de vie entraînent un problème d'allocation mémoire. En effet, plus il y a des changements dans le code, plus la taille du programme grandit, et plus la taille du programme grandit plus la mémoire demandée au système est conséquente. Il est difficile de prédéfinir la mémoire à allouer.
Problèmes de connaissances Ignorance La mauvaise connaissance d'une API et l'incompréhension d'un pattern de la part des développeurs peuvent entraîner sa mauvaise utilisation et affecter fortement la probabilité de non-respect de l'architecture prévue. Mauvaise appréciation de l'impact que peut avoir la non-utilisation d'un pattern. Le manque d'expérience personnelle technique de la part des développeurs diminue aussi la maintenabilité et augmente le taux d'apparition de défauts. Une documentation inexistante ou de mauvaise qualité entraînent un manque de compréhensibilité pour les personnes ne connaissant pas bien le projet. Utiliser des notations non expressives (ex : nom de variables, de fonctions ou de classes ne signifiant rien comme "a", "b", "object", etc) entraînent une perte de la traçabilité des décisions de conception pour l'application. Dans le cas où un développeur manque de connaissances du système développé, il peut ne pas utiliser correctement les moyens mis à sa disposition par l'architecture qui a été prévue. Par exemple, il se peut qu'il crée un objet directement alors qu'il devrait utiliser une factory prévue à cet effet.
Mauvaise utilisation L'abus du pattern Singleton crée un couplage extrêmement fort qui empêche d'être modifié facilement. Les développeurs sont parfois dans l'incapacité à adapter les patterns aux besoins du projet. Si l'on code avec une modularité faible ou inexistante, on risque d'empêcher les modifications possibles par la suite. Le code smell désigne plus ou moins les antipatterns et indique la présence de problèmes de conception. On peut retrouver comme exemple de code smell la god class qui désigne une classe à tout faire qui contient une grande partie du code d'un logiciel, ou encore spaghetti code qui représente du code fortement couplé et « emmêlé » comme son nom le suggère La programmation procédurale dans un environnement orienté-objet entraîne une non-utilisation du polymorphisme dans une hiérarchie d'objets ce qui va à l'encontre du paradigme orientée objet.
Problèmes de réalisation Problèmes d'exactitude Les changements fréquents des prérequis ou des technologies ou bien des prérequis imprécis entrainent une réduction de la maintenabilité du système. Les suppositions erronées des développeurs dues au manque d'informations explicites sur l'architecture sont aussi source d'érosion.
Problèmes de continuité Les décisions architecturales oubliées ou non utilisées par les développeurs. Les erreurs dans la compréhension de l'architecture posent des problèmes pour l'implémentation du logiciel conforme à l'architecture de départ. Si l'on ne donne pas de directives sur la manière d'effectuer les changements à venir dans le système on risque de le rendre non maintenable. De même que s'il manque de bons exemples de conception ou bien que les développeurs manquent d'entraînement dans la révision de la conception ou sa documentation. Si l'on ne connait pas l'histoire d'un logiciel, lorsque l'on rencontre une incertitude à propos de l'évolution du logiciel, cela entraîne une perte de logique au niveau de l'architecture du logiciel.
Problèmes de langage Les spécifications présentes dans l'architecture sont incompatibles avec la capacité réelle à exécuter ces spécifications dans l'environnement choisi. Par exemple, le langage choisi pour développer ne permet pas certaines choses prévues dans l'architecture.
Problèmes de gestion Problèmes de décisions Il est inévitable pour un logiciel de s'éroder au point d'envisager la solution qu'est de recommencer le développement logiciel à zéro. On parle généralement d'érosion dans la phase de maintenance d'un projet mais les recherches récentes prouvent que l'érosion peut apparaître dans la phase de développement due aux mauvaises décisions d'architecture prises. Il faut minimiser ces mauvaises décisions à la phase de développement pour obtenir un système final résistant aux changements et ainsi, retarder l'érosion du logiciel. Quelles que soient les décisions prises, le logiciel finira par s'éroder. La bonne qualité des décisions prises permettant seulement de retarder l'inévitable.
La conception d'une application consiste à choisir son architecture. Si l'architecture est au départ incorrecte ou bien que les décisions pour la conception sont non optimales, le système peut être difficile, voire impossible à maintenir. Si l'on prête peu d'attention à la conception de l'application lors de changements apportés à celle-ci. L'accumulation des décisions de conception différentes peuvent aussi la rendre difficile et chère à maintenir. La mauvaise compréhension de l'architecture de la part des développeurs est une cause principale de l'érosion d'un logiciel. En effet, à force de complexifier une application dans le but de la rendre plus flexible, celle-ci devient beaucoup plus difficile à comprendre, ce qui engendre d'autres mauvaises décisions dans la conception. L'adoption d'outils ou de méthodes de développement inadéquates sont un mauvais support pour le développement et la maintenance du système. Des problèmes de communication dans l'équipe peuvent engendrer du code redondant. La mauvaise planification ou estimation de l'impact d'un changement de l'architecture, peut engendrer des problèmes d'érosion.
Problème de gestion de projet Il y a deux stratégies dans la conception : optimale et minimaliste. Les logiciels industriels ne peuvent généralement pas se permettre d'utiliser la stratégie optimale par manque de temps ou d'argent et doivent se rabattre sur la minimaliste, ce qui engendre encore une fois l'érosion du logiciel.
Le développement à la hâte pour respecter les dates limites et la correction rapide des bugs peuvent entraîner des régressions dans le système. Les contraintes de temps obligent les développeurs à bâcler les classes "middle-level" qui aident grandement à la maintenance du projet. La mauvaise estimation des ressources nécessaires à la réalisation d'un projet.