• Aucun résultat trouvé

Etat des lieux et contraintes techniques

Le futur plan de production ne pourrait être réalisé sans une analyse technique inhérente aux besoins du client. Cette étape aura un impact sur le choix et le dimensionnement de la future solution technique détaillée au chapitre 2.3.

Dans cette section nous allons nous intéresser à la qualité de XeMeLios. Il est en général assez difficile de définir « la qualité ». C’est une notion abstraite et subjective. C’est pourquoi nous jugerons de la non-qualité du produit, notion sur laquelle nous pouvons avoir un regard objectif en s’appuyant sur des données factuelles. Nous distinguerons la qualité fonctionnelle en s’appuyant sur une étude dynamique, et la qualité structurelle en effectuant une étude statique.

Ces conclusions seront ensuite mises en parallèle avec les variations environnementales observées au cours de la période d’activité de XeMeLios. Nous pourrons ainsi juger la capacité de l’outil à s’adapter aux variations extérieures. Nous

en déduirons des prévisions afin que la future solution proposée soit la plus pérenne possible.

Enfin, un point d’attention particulier portera sur les contraintes techniques de la plateforme cible. Comme évoqué dans le chapitre 2.1.5, la DGFiP souhaite proposer les fonctionnalités de XeMeLios au travers des applications Web, nous devrons donc nous conformer à une infrastructure matérielle et logicielle cible. Du fait de la sensibilité des données manipulées nous devrons assurer la sécurité et l’intégrité des informations.

2.2.1 Identification des faiblesses de XeMeLios

2.2.1.1 Analyse dynamique

XeMeLios souffre de nombreux défauts ressentis lors de son utilisation. La DGFiP remonte régulièrement des problèmes de performance, de stabilité, de compatibilité, de fuite mémoire… Il n’est pas possible d’étudier l’ensemble des problèmes remontés par les utilisateurs, le temps consacré serait bien trop important compte tenu de la demande initiale. Nous allons uniquement nous intéresser aux problèmes de performances et de consommation mémoire qui constituent de loin le principal malaise vis-à-vis de l’outil.

Pour mettre en évidence ce constat, une étude a été réalisée. Elle consiste en l’application répétée du scénario décrit par la Figure 19.

Figure 19 - Scénario d'analyse dynamique

L’environnement est garanti identique entre chaque répétition par la remise à l’état initial du système (suppression des fichiers, purge de la base de données…).

Suppression des fichiers temporaires Purge de la base de données Lancement de XeMeLios Import du document Collecte des indicateurs

XeMeLios est écrit en Java et s’exécute sur une JVM 1.6. La collecte des indicateurs a été réalisée avec des outils comme MAT ou bien des scripts dédiés à cette tâche.

La machine utilisée est composée d’un processeur Intel I5-4570, de 8Go de RAM et d’un disque dur de 500Go à 7200 T/min. Le système d’exploitation installé est un Windows7 64 bits. Afin d’exclure des facteurs réseaux, toutes les opérations sont réalisées en local.

Indicateur 1 : le temps de traitement

Le temps de traitement nous permet de vérifier le ressenti utilisateur vis-à-vis des problèmes de performances. Cet indicateur nous permet de nous faire une première idée sur la performance globale de l’outil. Une affirmation simple et réaliste, est de supposer qu’il existe une relation de proportionnalité entre volume de données en entrée et temps de traitement. En effet, les opérations effectuées sur le document sont identiques quelle que soit sa taille.

Les résultats obtenus présentés sur la Figure 20 nous révèlent une tendance exponentielle du temps de traitement en fonction du volume de données en entrée. Plusieurs éléments peuvent être à l’origine de ces résultats, comme par exemple un choix inadapté de structure de données (arbre, graphe, liste…), ou encore une sollicitation trop importante de périphériques lents comme le disque dur.

Figure 20 - Analyse dynamique, temps de traitement

4,26 9,48 21,33 48,76 85,33 136,53 213,33 0 50 100 150 200 250 300 5 10 20 40 60 80 100 Temps de traitement (M)

Indicateur 2 : l’utilisation du processeur

Contrairement au temps de traitement précédemment abordé, l’utilisation moyenne du processeur au cours du processus d’import est censée être constante quel que soit le volume de données à traiter. L’algorithme s’appuie sur un automate à états finis pour analyser le document et sur un ensemble d’itérations pour en extraire les informations nécessaires. Afin de bien interpréter les résultats il est important de noter que XeMeLios n’a pas été développé pour exécuter des traitements parallèles.

Monitorer l’utilisation du processeur nous permet de déterminer si ce dernier est exploité à saturation, dans ce cas il pourrait être un facteur limitant, ou bien au contraire, s’il est sous-exploité, ce qui pourrait être expliqué par une mauvaise exploitation des ressources matérielles, de goulots d’étranglements logiciels (tampon sous/sur dimensionné par exemple)…

L’interprétation des résultats de la Figure 21 nous confirme une utilisation faible du processeur aux environs de 16%-17%, il n’est donc pas un facteur limitant de la performance de l’application. Cependant une utilisation plus importante serait préférable et confirmerait une exploitation correcte des ressources physiques de la machine.

Figure 21 - Analyse dynamique, utilisation CPU (moyenne)

16% 15% 18% 15% 17% 16% 16% 0% 5% 10% 15% 20% 25% 5 10 20 40 60 80 100 Utilisation processeur

Indicateur 3 : la consommation mémoire (RAM)

Monitorer la consommation mémoire du processus offre un aperçu sur la bonne ou la mauvaise gestion de cette ressource. En effet, à l’instar du temps de traitement, une consommation proportionnelle au volume de données en entrée est attendue. Des écarts importants à la hausse abonderaient dans le sens d’une mauvaise gestion. Un élément important à prendre en considération est la libération de la mémoire une fois les opérations d’import terminées. Son absence indique une (des) fuite(s) mémoire(s).

Les résultats de la Figure 22 nous indiquent une consommation à tendance exponentielle de la mémoire en fonction du volume de données en entrée. Comme pour les indicateurs précédents, les causes peuvent être multiples. Néanmoins les cas les plus couramment rencontrés sont l’allocation dans des itérations, la portée trop large des variables et les références circulaires.

Figure 22 - Analyse dynamique, consommation mémoire

La collecte de cet indicateur une fois le processus d’import terminé nous confirme une fuite mémoire. En effet la mémoire consommée n’est jamais libérée. La multiplication des imports au sein d’une même instance de XeMeLios produit une saturation et l’arrêt impromptu de l’application.

123 178 236 375 751 1081 1606 2440 0 500 1000 1500 2000 2500 3000 0 5 10 20 40 60 80 100

Consommation mémoire (Mo)

Indicateur 4 : les échanges disque

Le disque dur est un périphérique lent, son utilisation a un impact important sur la fluidité de l’application. Comme pour le monitoring de l’utilisation du processeur, l’analyse des échanges disques nous permet de vérifier que ce dernier n’est pas un facteur limitant dans les performances de XeMeLios.

La Figure 23 nous montre clairement une utilisation intensive du disque dur. Les valeurs avoisinent 100% sans jamais l’atteindre, le reste étant probablement utilisé par des services du système d’exploitation.

Figure 23 - Analyse dynamique, échanges disque

Une analyse plus fine met en évidence la création de nombreux fichiers temporaires alimentés par des données destinées à être réutilisées par le processus d’import. Il est à noter que ces fichiers ne seront pas supprimés une fois le processus terminé et l’application fermée, ce qui conduira à terme à des ralentissements1 plus

importants des accès disque jusqu’à une saturation.

1 La structure d’allocation d’un système de fichier augmente avec le nombre de répertoires et de fichiers stockés. Par conséquent, le parcours de la structure est plus important et les accès en lecture sont plus lents.

89% 96% 93% 98% 88% 94% 90% 0% 10% 20% 30% 40% 50% 60% 70% 80% 90% 100% 5 10 20 40 60 80 100

Utilisation du disque dur

2.2.1.2 Analyse statique

L’analyse dynamique nous a permis de vérifier le sentiment des utilisateurs vis- à-vis de XeMeLios et d’émettre certaines hypothèses techniques sur l’origine des problèmes. Dans ce chapitre, nous allons découvrir les résultats de l’analyse statique du code. Cette dernière a été réalisée en utilisant des outils automatisés d’analyse de code tels que JDepend ou FindBugs, et d’une revue de code manuelle.

A l’instar de l’analyse dynamique, nous n’allons ici présenter qu’une partie des résultats en nous concentrant sur trois métriques « standards » considérées comme pertinentes :

· lignes de code (LOC),

· complexité cyclomatique de McCabe (CC), · couplage entre objets (CBO).

Pour l’ensemble de ces indicateurs, il est important de noter que les résultats obtenus avec des outils automatisés d’analyse de code sont soumis à une interprétation subjective. En effet, il n’y a pas de consensus établi sur l’interprétation des résultats mais uniquement des valeurs couramment admises comme seuils de référence dans l’univers du développement des logiciels de gestion. Il est alors possible de calculer l’écart entre la valeur obtenue est celle couramment admise.

Pour finir, à partir de la revue de code manuelle, nous aborderons quelques exemples représentatifs de non-qualité mais difficilement identifiables par des outils d’analyse automatisés. Nous aborderons trois problèmes couramment rencontrés dans le code de XeMeLios : les fuites de connexions, la mauvaise gestion des exceptions, et les failles de sécurité.

Indicateur 1 : Lignes de code

Bien que quantitatif, cet indicateur nous permet de porter un jugement qualitatif du code. Toutefois, ce jugement est à interpréter avec précaution du fait du nombre important de facteurs influençant la valeur finale de la mesure. Afin d’atténuer l’impact du « style » du développeur, cette analyse a été réalisée de manière logique, c’est-à- dire que la mesure est faite sur « une canonisation » du code qui ne tient pas compte des sauts de lignes physiques non-exécutées (déclaration des blocs, commentaires…).

Pour offrir une vision globale de cet indicateur, la valeur moyenne de l’ensemble des résultats a été calculée pour chaque fichier, classe et méthode du projet. Le Tableau IV présente une synthèse des résultats obtenus.

Tableau IV - Analyse statique, lignes de code

Entité analysée LOC moyen Seuil de référence Ratio1

Fichier 1320 800 165%

Classe 1080 600 180%

Méthode 282 100 282%

Le premier constat que nous pouvons faire de ces résultats est bien évidemment le dépassement du plafond pour les trois entités analysées.

Le second est le ratio qui est relativement proche pour l’analyse sur fichier et sur classe, mais qui est très élevé dans le cas des méthodes. Une interprétation possible serait que les classes de XeMeLios sont constituées de méthodes importantes mais peu nombreuses.

Cette interprétation a été confirmée par l’analyse du nombre d’objets par entité étudiée présenté sur le Tableau V. En moyenne, les classes de XeMeLios sont composées de 4,52 méthodes.

Tableau V - Analyse statique, lignes de code, nombre d'objets par entité

Moyenne

Fichiers / module 173.07

Classes / fichier 1.23

Méthodes / classe 4.52

Indicateur 2 : Complexité cyclomatique de McCabe

La complexité cyclomatique (de McCabe) se mesure en comptant le nombre d’instructions impactant le plan d’exécution d’une méthode (if, while, for, switch…). Le nombre obtenu représente le nombre de chemins d’exécution possibles d’une méthode (Figure 24). Plus cette valeur est élevée, plus la méthode est jugée complexe et difficile à comprendre.

Figure 24 - Analyse statique, complexité cyclomatique

Dans le cadre de cette étude, la valeur étudiée est la complexité cyclomatique moyenne calculée sur l’ensemble des méthodes présentes dans XeMeLios. Le résultat obtenu est une complexité moyenne de 9,2. Il est généralement admis que cette valeur devrait être inférieure à 10, représentant une méthode à forte complexité. Ce que nous pouvons déduire de ce résultat est que les méthodes de XeMeLios sont complexes, avec un nombre de chemins possibles élevé.

Ce résultat vient corroborer l’interprétation du premier indicateur, le nombre de lignes de code. En effet, un découpage plus fin de l’application aurait entraîné la baisse de ces deux indicateurs.

Indicateur 3 : Couplage entre objets

Le couplage indique le niveau d’interaction entre deux ou plusieurs composants. Il s’établit à différents niveaux, de la méthode à l’application en passant par l’objet et le module. Nous nous intéresserons ici au couplage entre objet, c’est-à- dire à la conception objet de l’application, et non au couplage entre modules résultant du découpage vertical de l’application.

Un couplage fort, c’est-à-dire un ensemble de composants présentant un nombre important d’adhérences entre eux, est un signe de non-qualité. La conséquence directe est la production de code spaghetti1 qui entrainera une

maintenabilité, une réutilisabilité et une extensibilité difficiles et coûteuses.

Le calcul du couplage est relativement simple, il suffit de référencer au sein d’une classe les types rencontrés dans les attributs, les paramètres, les variables… l’héritage en faisant partie. Plus cette valeur est importante et plus le couplage est élevé. Cependant il est important de noter que les objets étudiés sont uniquement ceux concernés par le projet, les classes de la JVM sont par exemple exclues. Le Tableau VI représente les résultats obtenus et les compare à une valeur de référence :

Tableau VI - Analyse statique, couplage entre objets

CBO XeMeLios Seuil de référence Ratio

Minimum 0 0 0%

Maximum 77 20 385%

Moyen 58 10 580%

Les résultats ne laissent aucun doute sur la gestion des dépendances dans XeMeLios. Le couplage est très important, le risque de modifications en chaîne sur l’ensemble de l’application est présent (code spaghetti) et le risque de régression est élevé. Depuis plusieurs années, la DGFiP et les développeurs intervenant sur XeMeLios ont remarqué que le temps consacré à la maintenance suivait une tendance exponentielle. Ce constat est une des conséquences d’un couplage fort en l’absence de refactoring permanent.

1 Code résultant d’une conception favorisant les dépendances voir les interdépendances entre les objets

Exemple 1 : Fuite de connexion

Une fuite de connexion se produit lorsqu’une application obtient une connexion et ne la libère pas. La saturation de la base de données ou d’un pool de connexions éventuel constituent le risque principal, entrainant en général le dysfonctionnement de l’application. Le code de la Figure 25 met en évidence une possible fuite de connexion (les lignes superflues ont été supprimées).

Figure 25 - Analyse statique, fuite de connexion

En effet, la connexion récupérée depuis le pool est stockée dans un attribut, elle n’est jamais libérée. La durée de vie de la connexion est au minimum identique à la durée de vie de l’objet qui la référence. La saturation du pool entraînera dans un premier temps un ralentissement de l’application, et pourra se terminer par un inter blocage rendant l’application inutilisable. En règle générale, il est nécessaire dans un premier temps de s’assurer de la libération explicite des ressources, et dans un deuxième temps de limiter la portée des variables.

Sur cet exemple nous pouvons également faire une remarque sur le nommage des objets. Les noms donnés ne permettent pas d’identifier rapidement le type et l’utilisation des variables. Il est important de définir une convention de nommage connue et respectée par l’ensemble des intervenants du projet.

Exemple 2 : Mauvaise gestion des exceptions

La gestion des exceptions conduit à s’interroger sur le composant le plus apte à gérer l’exception levée. En effet, le premier appelant n’est pas forcément le meilleur candidat pour traiter cet évènement et laisser remonter l’exception est souvent la solution. Par conséquent, il ne suffit pas d’intercepter l’erreur et de l’ignorer. Ce comportement conduit à des effets de bord difficiles à identifier et à corriger.

Dans l’exemple présenté par la Figure 26, les exceptions éventuellement remontées sont ignorées, le bloc catch destiné à traiter l’erreur est vide.

Figure 26 - Analyse statique, "catch" vide

Ce problème se retrouve à de nombreux emplacements dans le code, notamment sur des fonctionnalités sensibles comme l’import des données. Dans ce cas, une conséquence peut être un problème d’intégrité de données, fait qui a déjà été de nombreuses fois relevé par la DGFiP.

De plus, il est courant de trouver des interceptions sur Throwable. Ceci est une mauvaise pratique du fait du risque de capturer les erreurs de la JVM (une saturation mémoire par exemple) et d’empêcher l’arrêt de l’application qui continuera de s’exécuter dans un état instable.

Exemple 3 : Faille de sécurité

La sécurité informatique est un des piliers majeurs dans le développement logiciel. La nature du projet et la sensibilité des données manipulées sont des critères à prendre en compte pour établir la criticité du logiciel. En effet, un petit jeu pour

smartphone ne répond pas aux mêmes besoins en termes de sécurité que l’application de saisie des impôts.

Les données manipulées par les utilisateurs de XeMeLios sont qualifiées de très sensibles du point de vue de leur intégrité, et moyennement sensibles sur le plan consultatif (les comptes de gestion des collectivités sont publics). Cependant, les utilisateurs sont rattachés à un périmètre de consultation (géographique, par entité…) et il n’est pas concevable de pouvoir accéder à un périmètre sur lequel les autorisations nécessaires ne sont pas satisfaites.

L’exemple présenté ci-dessous met en évidence une faille de sécurité de type SQL Injection. Les données d’entrée ne sont pas vérifiées et sont insérées en l’état dans la requête, ce qui permet à un individu mal intentionné de modifier le champ d’application de la requête. Cette requête récupère un ensemble de dépôts pour une collectivité:

Figure 27 - Analyse statique, SQLInjection

Dans ce cas il est aisé de transformer la requête et de récupérer l’ensemble des dépôts, il suffit de donner la valeur toto' OR '1' = '1 à la variable idColl. La requête finalement exécutée sera :

SELECT * FROM IX_CG_REPOSITORY WHERE IDCOLL = 'toto' OR '1' = '1' L’introduction de la tautologie aura pour effet de ramener l’ensemble des dépôts sans aucune restriction. Cet exemple a été volontairement retenu car la fonctionnalité impactée n’est pas critique pour l’application. D’autres cas ont été détectés mais ils ne seront bien évidemment pas détaillés.

2.2.1.3 Le support de plusieurs SGBD

Dans sa version actuelle, XeMeLios supporte les bases de données Oracle et MySQL. L’abstraction du support de persistance est loin d’être suffisant. En effet, la définition s’appuie sur l’écriture de code SQL, ce qui entraine une dépendance entre la définition et le dialecte cible du SGBD. Par conséquent, l’adaptation d’une nouvelle

base de données est réalisée par la réécriture complète du paramétrage de la persistance embarquée dans les configurations de document. L’annexe A met en évidence ce comportement où nous voyons apparaitre une duplication de code entre les deux définitions de support de SGBD.

Du point de vue du code Java, le constat est semblable. Nous sommes face à un code trop peu mutualisé avec une duplication systématique. Les technologies Java et SQL ne sont pas suffisamment séparées ce qui entraîne une forte adhérence entre elles. De plus, la conception n’offre pas un découpage suffisamment fin. La conséquence est un code regroupé dans des classes atteignant un volume trop important pour une bonne compréhension.

En l’état, porter l’outil vers un nouveau système de gestion de base de données est un travail laborieux et redondant, et, techniquement une erreur de conception. La quasi-duplication des requêtes de génération des structures de table de données et d’indexation entraine une maintenance difficile et le support d’un nouveau SGBD implique une livraison des configurations de document.

2.2.2 Un environnement qui évolue

Les premières lignes de code de XeMeLios ont été produites en 2005. A l’origine, le produit a été développé comme un prototype, un client lourd exploitant une base de données MySQL. Il a ensuite été adapté pour répondre aux exigences d’un environnement de production et distribué à large échelle (26 000 collectivités).

Pendant ses premières années, XeMeLios a su répondre aux attentes de l’utilisateur et s’adapter aux demandes d’évolution. Malgré un probable manque de remise en cause de la conception qui a conduit aux résultats décrits dans le chapitre précédent, la satisfaction des utilisateurs était au rendez-vous. Il faut cependant garder à l’esprit que l’outil disposait et dispose encore du monopole de l’exploitation des documents relatifs aux comptes de gestion.

Par la suite le tableau a commencé à se noircir. La volonté du ministère