# Érosion de l'architecture logicielle

En informatique, l'érosion d'un logiciel est l'écart entre l'architecture prévue initialement pour ce logiciel 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.
Il existe divers moyens pour trouver où se situent ces points d'érosion et comment les contrer.

## Causes de l'érosion

Les causes liées à l'érosion de l'architecture logicielle peuvent être catégorisées comme suit :

### 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.
** Exemple : temps, personnel, ...
* Les refactorisations du projet trop peu effectuées dues à la sous-estimation du caractère inévitable de l'érosion architecturale..
** Il est nécessaire à un certain moment d'allouer du temps et des ressources afin d'inverser la dégénération de l'architecture. Cependant, les développeurs peinent souvent à trouver des arguments en faveur de la réalisation de ce processus étant donné que celle-ci n'apportera rien à l'utilisateur final puisqu'il ne verra rien de tout cela. Il existe donc une mesure définie aidant à mieux quantifier le besoin nécessaire d'arrêter la dégénération logicielle.
* L'organisation d'un projet est aussi parfois l'une des causes de son érosion logicielle. En effet, un environnement organisationnel malsain entraîne un mauvais travail.
** Le turnover du personnel induit une mauvaise compréhensibilité de l'architecture et son implémentation.
** De même, la distance géographique empêche une bonne intégration du système.

## Conséquences

Il est aussi important de comprendre les enjeux derrière ce contrôle de l'érosion logicielle pour en comprendre la nécessité.

### Systèmes plus difficiles à maintenir

Les systèmes érodés sont difficiles à maintenir. Localiser un bug ou tester des parties de code, à l'aide de tests unitaires par exemple, est beaucoup plus difficile et prend plus de temps à réaliser sur un logiciel avec une forte érosion.

### Systèmes plus chers à maintenir

Qui dit « temps » dit « argent », et si les développeurs passent plus de temps à modifier l'application ou corriger ses bugs, il va de soi que cela revient plus cher à sa maintenance.

### Logiciel non économique

Un logiciel non économique est un logiciel qui coûte plus cher à maintenir qu'à recoder de zéro. C'est le pire scénario d'érosion qui puisse arriver.

## Solutions

Les solutions apportées pour contrôler l'érosion de l'architecture logicielle sont diverses et peuvent se compléter entre elles. Aucune approche utilisée seule ne fournit une solution entièrement efficace pour contrôler l'érosion.

### Minimiser : limiter l'impact de l'érosion

Il est possible de limiter l'impact de l'érosion à l'aide de quelques méthodes. Ces solutions peuvent se diviser en trois catégories.

#### Processus pour la conformité avec l'architecture

Cette catégorie comprend un ensemble de processus qui permettent d'assurer la conformité avec une architecture pendant les phases de développement et de maintenance.

##### Techniques de documentation

La documentation sur le design de l'architecture, sur les raisonnements et les décisions qui ont mené à cette architecture se doit d'être assez détaillée pour comprendre complètement les besoins mais doit en plus avoir un certain niveau d'abstraction et ne doit pas trop rentrer dans les détails pour des soucis de compréhension par les développeurs. L'une de ces techniques est le "4+1 view model (en)". Les techniques informelles qui manquent de définition précise et qui amènent à une mauvaise compréhension, donc à l'érosion sont fortement répandues. Celles-ci peuvent être palliée par l'utilisation d'un ADL (Architecture description language (en)) qui permet de fournir une certaine formalité.
Exemples d'ADL : Acme (en), Darwin (en), ArchJava, Fractal, xADL, Rapide.
Il existe un standard IEEE 1471 (en) qui définit un ensemble de lignes directrices sur la manière dont une architecture logicielle devrait être documentée.
Les techniques de documentation sur les décisions architecturales ne sont pas très répandues. C'est pour cela qu'il existe également des systèmes qui permettent de retracer les raisonnements qui ont abouti à des décisions sur une architecture grâce à l'analyse de patterns particuliers trouvés dans cette architecture.

##### Méthodes d'analyse de l'architecture

Il existe plusieurs méthodes dont le but est de localiser les points faibles ou sensibles d'une architecture, d'où l'érosion peut démarrer. La SAAM (en) a vu le jour au milieu des années 1990 et a été la première méthode d'analyse de l'architecture à être documentée. Elle a servi de précurseur à la ATAM (en). Enfin, il existe également une technique qui utilise les réseaux de Petri colorés afin de valider les attributs de qualités clés d'une architecture.

##### Surveillance sur la conformité avec l'architecture

Deux techniques fournissent les moyens de savoir et de contrôler la conformité d'une implémentation avec son architecture originelle tout au long des phases de développement de maintenance :
* Technique des modèles réflexifs : cette techniques consiste à choisir un modèle d'un système, d'en déduire une hypothétique implémentation et de le comparer avec le modèle réellement implémenté. Cela permet de localiser les points de dérivation ou d'omissions par rapport à l'architecture de base.
* Technique des modèles réflexifs inversés : le modèle est considéré comme acquis et non hypothétique. Le modèle réellement implémenté est comparé à ce modèle acquis de manière répétitive. Cette technique est donc plus utilisée pour vérifier la conformité avec l'architecture voulue, et non pour retrouver l'architecture voulue, comme c'est le cas pour la technique non inversée.

##### Analyse des dépendances

La source la plus commune d'érosion d'une architecture provient de dépendances incorrectes entre les entités de cette architecture. Plusieurs outils commerciaux permettent de localiser ces points d'érosion potentiels grâce à une visualisation des dépendances. En voici des exemples : SonarJ (en), Structure101, Klocwork Architect, Coverity (en) et JDepend.

#### Gestion de l'évolution de l'architecture

L'évolution d'une architecture peut être contrôlée grâce à des outils de gestion de configuration, dits SCM (Sofware management configuration). Ceux-ci regroupent également les logiciels de gestion de versions qui sont généralement plus connus. Concrètement, les outils SCM se chargent de minimiser l'érosion d'une architecture logicielle en gérant la coévolution continuelle de l'architecture et de son implémentation.
Il existe deux sous-catégories d'outils dans ce domaine :

##### SCM centré sur l'architecture

Le logiciel de gestion de configuration joue le rôle central en définissant l'architecture logicielle en son sein.
Exemples :
* ArchEvol permet de surveiller l'évolution parallèle des spécifications de l'architecture et de son implémentation, et ainsi de faciliter la collaboration entre les architectes et les développeurs.
* ArchAngel surveille la conformité du code source avec l'architecture au moyen de modèles de dépendances définis par un architecte. Il se charge de "parser" le code source et d'identifier les relations entre les différents packages. Il compare ensuite ces relations avec celles prévues par l'architecte pour identifier les violations de dépendances.

##### Architecture centrée sur SCM

Le logiciel de gestion de configuration devient une partie intégrante de l'architecture. Des exemples d'outils sont Mae et Molhado.

#### Mise en application de conceptions d'architectures

Cette mise en vigueur regroupe un ensemble d'outils et de méthodes qui permettent la transformation de modèles d'architecture en implémentations organisées. Cela permet de minimiser fortement l'érosion logicielle si cette mise en vigueur est appliquée correctement. L'ensemble de ces méthodes sont repris dans les trois catégories suivantes :

##### Génération de code

Les outils de génération de code permettent de générer du code source à partir de la définition d'une architecture. Ces outils ne fournissent généralement pas un code source utile sans l'intervention ultérieure d'un programmeur. Il est cependant possible, en théorie, de générer des implémentations complètes à partir de modèles UML. Il existe quelques (ADL (en)), tel que l'environnement ArchStudio, qui permettent la génération de code à partir des spécifications architecturales définies.

##### Patterns d'architecture

Les patterns d'architecture sont similaires aux patterns de conception dans le sens où ils fournissent des solutions bien établies, testées et documentées à des problèmes récurrents dans la conception d'une architecture logicielle. Il est commun également de garder une trace des décisions sur l'architecture ainsi que le raisonnement qui a mené à cette décision. Les points positifs de cette méthode sont multiples :
* S'ils sont correctement appliqués, ces patterns d'architecture réduisent fortement la possibilité de violer des principes de conception.
* L'existence des traces des décisions sur l'architecture permettent de minimiser l'érosion car les programmeurs peuvent ainsi complètement comprendre ces décisions et laisser peu de place à l'interprétation.
Le point négatif principal est le fait que ces règles peuvent facilement être transgressées par les programmeurs qui ne sont pas sensibilisés sur l'importance de celles-ci. Le pattern d'architecture le plus connu est probablement le MVC. Il en existe d'autres tels que le Pipe and Filter (en), ou le Blackboard model.

##### Frameworks d'architecture

Les fraweworks d'architecture fournissent un ensemble de services qui guident les développeurs dans l'implémentation d'une architecture définie. Certains frameworks peuvent détecter quand l'implémentation diverge de l'architecture prévue. Les exemples suivants font partie des frameworks les plus connus : Spring et Struts.

### Empêcher : éradiquer l'érosion

Cette partie aborde les moyens pour empêcher l'érosion d'un système dès sa création.

#### Architecture liée au code source

Il existe des mécanismes qui associent ou encapsulent les modèles d'architecture dans le code source et qui supportent le monitoring de la conformité avec l'architecture à l'exécution.
Un exemple est ArchJava, qui permet de coder en Java dans la spécification de l'architecture même. Le fait que l'architecture soit décrite dans le même langage que son implémentation permet de régler le problème principal qui survient dans les autres langages ADL, à savoir l'incapacité à assurer complètement l'obéissance des contraintes architecturales et plus particulièrement les communications entre les composants décrits dans l'architecture. Ceci est dû au fait qu'il ne sont pas décrits dans le même langage, et donc ne peuvent exprimer correctement certaines subtilités d'un langage particulier. Ils s'en remettent alors à la bonne volonté des développeurs de suivre des lignes directrices afin de respecter les communications entre les composants de l'architecture.
Il existe également la plateforme Archium qui est une extension à Java et un framework qui est chargé de vérifier les propriétés de l'architecture à l'exécution.
Enfin, ArchWare est lui aussi une plateforme mais qui vise essentiellement les architectures dynamiques. Pour cela, il fusionne complètement le modèle de l'architecture et son implémentation, ce qui permet une coévolution complètement simultanée.

#### Auto-adaptation

Cette technique permet aux systèmes de se reconfigurer afin de s'aligner sur leur architecture après qu'un changement dans l'implémentation ait été effectué. L'hypothèse établissant que l'être humain et sa tendance à ne pas respecter les lignes de directrices définies dans une architecture lorsqu'il doit réaliser un changement, est à l'origine des systèmes auto-adaptatifs. Typiquement, ces systèmes fonctionnent à l'aide de trois acteurs : des capteurs qui surveillent et capturent les changements survenus, des comparateurs qui comparent ces changements avec les règles définies au départ, et des actionneurs qui se chargent d'effectuer les changements nécessaires au système.
Un exemple de système auto-adaptatif est Rainbow.

### Réparer : réconcilier l'implémentation avec l'architecture

Il est nécessaire de planifier correctement le processus de réparation pour éliminer au mieux l'érosion. Ce processus ne peut fonctionner que si le système n'est pas trop détérioré. Il est donc conseillé de combiner les techniques de réparation avec d'autres mécanismes de prévention de l'érosion décrits ci-dessus.
Le processus typique de réparation d'un logiciel érodé se fait en trois phases:
* Il faut d'abord récupérer l'architecture qui a été implémentée.
* Réparer l'architecture récupérée en se conformant à l'architecture voulue au départ,
* Réconcilier cette nouvelle architecture réparée avec l'implémentation.
Il est nécessaire que ces trois phases soient fortement liées entre elles pour réparer efficacement un logiciel érodé.

#### Récupération de l'architecture

Cette phase consiste à extraire l'architecture implémentée à partir du code source. Il existe un nombre important d'outils pour effectuer cette tâche. Une grande partie d'entre eux utilisent la technique des modèles réflexifs. Ces modèles sont souvent agrémentés d'une technique de regroupement qui consiste à rassembler les entités d'un logiciel entre elles pour former un niveau d'abstraction supplémentaire. En plus de cette technique de regroupement, les modèles peuvent également comporter une fonctionnalité de filtrage qui permet de supprimer les entités non nécessaires à ce niveau d'abstraction.
Exemples d'outils et méthodes : Bunch, Architecture Reconstruction Method (ADM), Architecture Query Language (AQL).

#### Découverte de l'architecture

Dans le cas où il n'existe pas d'architecture de départ, la phase de découverte d'une architecture consiste en des techniques qui permettent de déduire une architecture à partir des propriétés d'un système et de ses cas d'utilisation. Cette architecture prévue au départ est absolument nécessaire pour réparer correctement un système érodé.

#### Réconciliation de l'architecture

Cela désigne le processus durant lequel l'architecture implémentée est rendue conforme à l'architecture voulue au départ qui a été obtenue soit à la suite de la méthode de récupération soit à la suite de la méthode de découverte décrite précédemment. Le refactoring est la solution la plus utilisée pour effectuer cette réconciliation.
Les deux grandes étapes d'un processus de refactoring consistent premièrement à localiser dans le code source des décisions d'implémentation qui représentent des violations à l'architecture décrite au départ puis, après avoir localisé ces violations dans le code, les refactoriser pour rester en concordance avec cette architecture.

##### Refactorisation du code à l'aide des outils d'un IDE

Pour éviter d'avoir un écart trop grand entre le logiciel et son architecture initialement prévue à mesure que le développement d'un logiciel avance, il est important de faire régulièrement de la refactorisation. La plupart des IDE contiennent des outils d'aide à la refactorisation. Mais ce procédé est souvent réalisé de manière peu organisée, sans tenir compte de l'architecture.

##### Langages de contrainte d'architecture

Pour localiser dans le code source des décisions d'implémentation qui représentent des violations de l'architecture décrite au départ, il existe des langages spécifiques ou des outils d'analyses qui permettent de localiser ces violations dans un code source, comme par exemple le langage DCL.
L'outil appelé SAVE (Software Architecture Visualization and Evaluation) permet également d'effectuer la connexion nécessaire entre le développeur et l'architecture d'un logiciel. En définissant une architecture visée et en spécifiant l'architecture actuelle, il fournit au développeur un outil visuel lui montrant les violations commises dans l'implémentation du logiciel par rapport à l'architecture visée.

##### Lignes de conduite pour le refactoring

Des lignes de conduites fournies automatiquement permettraient d'aider le développeur et de lui fournir la méthode adéquate à appeler en fonction du contexte dans lequel il se trouve.
Prenons par exemple le cas de refactorisation où il faut remplacer l'appel d'un constructeur d'une classe par l'appel à une méthode d'une factory appropriée. Le problème du développeur dans ce cas peut être le fait qu'il n'ait pas assez de connaissance du système pour savoir quelle méthode de quelle factory appeler à la place. Il lui serait donc automatiquement recommandé quelle méthode utiliser.
Ce système a pour but de fournir des recommandations pour supprimer les violations détectées par le langage DCL. Le processus est le suivant : on utilise le code source et les contraintes de dépendances fournies par l'architecte logiciel pour produire les violations détectées par le langage DCL, puis on utilise ce résultat pour fournir des recommandations adaptées.
Ce procédé contient une vingtaine de recommandations résultantes de violations de contraintes cannot du langage DCL. Ces recommandations sont également valables pour les contraintes de type only can et can only car il est possible de les exprimer sous forme de cannot au moyen de diverses opérations logiques. Les recommandations sont classées en fonction de leur importance. On retrouve en haut du classement la recommandation dictant l'utilisation d'une factory à la place du constructeur d'une classe si cette classe se situe dans un module différent de celui où on l'appelle. La recommandation permet même de générer une factory dans le cas où aucune autre factory ne correspond aux spécificités demandées. D'autres exemples de recommandations disent que le type d'une variable doit être la plus abstraite possible ou bien qu'il faut éviter de répandre trop loin la gestion d'une exception afin de diminuer le couplage.
Ce système est néanmoins récent, et nécessite d'être testé sur des projets plus importants avant d'être utilisé en environnement de production.

### Comparatif des différentes solutions

Avantages et inconvénients des solutions contre l'érosion :
| Solutions | Avantages | Inconvénients |
| Processus pour la conformité à l'architecture | Efficace pour réduire l'érosion dès le début du cycle de vie d'un logiciel S'intègre bien avec les pratiques de gestion de projet | Sujette à la négligence humaine Manque de rigueur pendant la phase de maintenance |
| Gestion de l'évolution de l'architecture | S'assure que l'architecture et l'implémentation sont en concordance l'un avec l'autre tout en leur permettant d'évoluer indépendamment | Nécessite des ADL standardisés et des outils SCM qui intègrent ces ADL |
| Mise en application de conceptions d'architectures | Simple et pratique pour la plupart des applications Les Patterns et frameworks utilisent les meilleurs pratiques de conception connues | Pas de mécanismes permettant d'empêcher les violations des propriétés de l'architecture dans des systèmes en évolution |
| Architecture liée au code source | Assure une association continue entre l'architecture et son implémentation | L'architecture et l'implémentation forment généralement une seule et unique entité |
| Auto-adaptation | Permet à l'implémentation de se reconfigurer toute seule pour se conformer à son architecture | Suppose que l'architecture reste relativement constante tout au long de l'évolution du système |
| Processus de réparation | Certaines techniques ont été bien adoptée dans l'industrie logicielle comme étant des solutions viables pour étendre la durée de vie d'un logiciel Peut être utilisé en plus des techniques de prévention de l'érosion | L'architecture prévue au départ n'est pas toujours récupérable Aucune des techniques présentées sont capables d'extraire les raisonnements derrière les décisions sur l'architecture |

## Conclusion

Il est clairement établi partout dans la littérature que l'érosion de l'architecture logicielle est un problème réel, récurrent, et surtout, inévitable. Les études menées autour de l'érosion logicielle partent toutes de ce postulat et cherchent donc à comprendre les raisons derrière ce caractère inévitable et établissent des solutions pour réduire tant bien que mal l'impact que peut avoir l'érosion sur les systèmes informatiques d'aujourd'hui. L'objectif est donc de repousser au maximum le moment critique où un logiciel est jugé plus coûteux à maintenir qu'à redévelopper de zéro.
Pour cela, diverses solutions ont été présentées mais aucune d'entre elles ne permet d'éliminer complètement l'érosion. Une potentielle solution a cependant été émise. Ce serait une “révolution” similaire à celle que fut la création de l'orienté-objet, successeur de la programmation procédurale et qui consisterait en de nouveaux modèles de programmation capables de spécifier et de se tenir à des propriétés architecturales.