• Aucun résultat trouvé

Chapitre 5 EVOLUTION DU PROJET EM2

5.3. l Implantation du noyau

7.1.6 Synthèse

Après avoir examiné ces différents types de métriques, il est temps d'effectuer une petite synthèse sur les caractéristiques d'une métrique, et plus particulièrement d'une métrique intra-modulaire.

Une métrique consiste à projeter le code source d'un programme selon un certain plan et à évaluer le résultat de la projection. La projection peut aussi être considérée comme un filtre. Deux critères sont à la base de la qualité du résultat de la projection. Il faut trouver un bon plan de projection, qui conserve uniquement les caractéristiques fondamentales de la complexité, et ensuite il faut définir une mesure calibrée.

Concernant le plan de projection, on s'aperçoit qu'il est düficile à trouver. Beaucoup d'approches différentes (par exemple, suivant le graphe de contrôle ou le flot de données) donnent des résultats similaires:

il n'y a donc pas de direction explicite vers laquelle convergent ces approches.

La projection permet de sélectionner un certain nombre d'éléments et d'ignorer les autres. Il faut trouver un compromis entre une projection qui ne garde que très peu d'informations (par exemple, le nombre de lignes de code) ou, au contraire, une qui conserve beaucoup trop d'informations (par exemple, les expressions régulières).

La mesure doit être calibrée, c'est-à-dire que la mesure doit avoir une plage de valeurs possibles raisonnable. Un programme de complexité moyenne (un programme simple, structuré, et d'environ une centaine de lignes) doit donner une valeur ni trop petite, ni trop grande. Par exemple, si la mesure de la complexité donne une valeur de 1 ou 2, ou de 10000000, la signification des résultats, pour des programmes plus ou moins complexes, risque de ne pas être très évidente, ce qui est le cas dans la métrique de Henry et Kafura [Hen 81).

Un point important, trop souvent ignoré, est qu'une métrique doit être facile à comprendre et, si·possible, à calculer.

Facteurs d'influence

Les facteurs d'influence de la complexité intra-modulaire permettent de définir les caractéristiques fondamentales à conserver lors de la projection. Les principaux facteurs sont les suivants:

- la taille du programme (nombre de lignes), - le nombre de différentes structures de contrôle,

- la complexité d'une séquence linéaire augmente en fonction du nombre d'instructions constituant la séquence,

- une structure de boucle engendre une complexité plus grande qu'une instruction conditionnelle,

- le niveau d'emboîtement des différentes structures de contrôle, - la complexité des conditions dans les instructions conditionnelles, - le nombre de données,

- la structure des données,

- le nombre et le type de références aux données.

Programmation structurée

Les métriques portant sur la structure de contrôle d'un programme servent principalement à mesurer la complexité des algorithmes. La programmation structurée consiste, entre autres, à modulariser un programme ou un module en de plus petites unités, les procédures et les fonctions. Qu'un progranune soit en un seul bloc ou décomposé en sous-programmes n'a aucune répercussion sur les résultats de ces métriques.

Seules, les métriques basées sur les données sont fonction de cette décomposition, puisqu'elles contieruient généralement une mesure du flot de données entre ces composants.

Métrique et atelier de génie logiciel

Dans un environnement, une métrique pennet de mesurer la qualité des logiciels produits par l'environnement. Les résultats de cette mesure font partie intégrante de la documentation associée à un projet, il faut donc essayer de donner une bonne approximation. Pour atteindre ce but, il ne suffit pas de montrer les résultats obtenus par l'application d'une métrique propre à l'atelier. Une méthode plus adaptée consiste à appliquer aussi d'autres métriques plus standard. Car, pour pouvoir comparer la qualité des programmes produits par des ateliers différents, et ainsi, pour faciliter la validation d'un atelier, il faudrait que les métriques soient standard d'un atelier à l'autre.

7.2 LA MÉTRIQUE EM2/COMPLEX 7.2.1 EM2/Complex

La métrique EM2/Complex est la métrique associée à l'environnement EM2, qui pennet d'évaluer la complexité d'un programme modulaire. Nous nous intéressons ici à. la partie complexité intra-modulaire. Cette métrique, effectuant une analyse statique du code, est destinée à évaluer la qualité d'un module propre aux langages modulaires. Elle est construite sur un ensemble de métriques, ce qui lui permet d'être relativement fiable et complète. Un certain nombre des métriques sont des métriques classiques, ce qui permet d'établir et de respecter une mesure standard, et, aussi, de valider nos propres métriques. Notre proposition s'appuie donc sur des méthodes existantes avec, cependant, un certain nombre de variations, mais l'essentiel consiste en la combinaison des différents éléments de métriques.

Notre métrique repose sur les métriques suivantes:

- nombre d'objets du module,

- nombre d'objets du type variable globale, - nombre de variables globales au module, - nombre de lignes de commentaires, - nombre d'effets de bord,

- nombre de lignes de code, - science du logiciel (Halstead), - complexité cyclomatique (McCabe), - polynôme caractéristique ajusté, - polynôme des données.

Nombre d'objets du module

Le nombre d'objets du module représence le nombre d'objets exportés par ce module. Il ne faut pas que ce nombre soit trop grand (> 10), car alors le module devient lourd à utiliser et à maintenir, et il ne doit pas être trop petit ($; 3), car cela aboutit à une sunnodularisation du logiciel, ce qui est néfaste à la complexité inter-modulaire.

Nous considérons que l'interface d'un module doit contenir environ 7±2 objets exportables. La valeur moyenne 7 provient du fait qu'un homme normal peut enregistrer une liste simple d'environ 7 éléments [Mil 56]. Au-delà de cette valeur, il faut que la liste soit structurée en une hiérarchie de niveaux, où à chaque niveau, on ne dépasse pas cette valeur limite.

Nombre d'objets du type variable globale

Le nombre d'objets (exportés) du type variable globale entre entre les modules joue un rôle important dans l'évaluation de la complexité, car ceux-ci augmentent l'entropie du logiciel. De plus, nous verrons dans le chapitre suivant (chapitre 8) qu'il est relativement facile de les remplacer par un type abstrait qui, lui, diminue l'entropie.

Nombre de variables globales au module

Les variables globales à un module limitent la ré-entrance, donc la possibilité de réutiliser ce module dans divers contextes d'un programme.

Nombre de lignes de commentaires

La métrique basée sur le nombre de lignes de commentaires est relativement simple. On calcule le rapport existant entre le nombre de lignes de commentaires et le nombre de lignes de code source. Il est

difficile de donner une valeur pour laquelle on peut affirmer que l'objet considéré est bien documenté, mais, généralement, la valeur la plus largement adoptée se situe autour de 1/3.

Ces quatre métriques sont les seules qui soient appliquées directement au niveau du module. Les autres métriques sont appliquées aux différents objets composant ce module. Ensuite, on répercute les résultats au niveau du module, en calculant la moyenne et l'écart type de chacun d'eux. Le rapport de complexité associé -à chaque module comprend les évaluations propres aux objets et leurs statistiques qui permettent d'évaluer la complexité du module.

Nombre d'effets de bord

Le nombre d'effets de bord correspond au nombre de variables globales qui sont utilisées d'une manière ou d'une autre dans un sous-programme sans avoir été déclarées dans la partie interface. Cette mesure est effectuée pour chaque objet de type sous-programme en tenant compte des divers sous-programmes utilisés par ces objets. Les différents résultats sont sommés pour donner la valeur globale absolue du module.

Une autre approche, assez répandue, consiste à mesurer la visibilité des opérandes, c'est-à-dire à compter le nombre de sous-programmes qui pourraient utiliser ces opérandes. Nous considérons que cette métrique n'est pas adaptée. Car lorsqu'un sous-programme est imbriqué dans un autre, les variables du sous-programme global sont visibles à celui qui est interne. Cette technique pennet de modulariser un sous-programme, et de réduire_ sa complexité, mais elle a pour effet d'augmenter la mesure de visibilité de ces variables.

Les métriques suivantes: nombre de lignes de code, science du logiciel et complexité cyclomatique sont les métriques classiques qui constituent la partie standard de notre métrique. Nous les utilisons dans le sens défini par leurs auteurs. Les deux prochaines métriques sont là pour satisfafre notre point de vue sur la complexité.

Polynôme caractéristique ajusté

Nous considérons que l'approche du polynôme caractéristique est satisfaisante pour exprimer la complexité d'un algorithme, mais elle ne tient pas compte de la modularité, et ainsi elle n'exprime pas pleinement la complexité d'un programme construit sur d'autres sous-programmes. Nous avons donc été amenés à ajuster ce polynôme pour satisfaire ces nouvelles spécifications.

Un des points critiques dans la construction du polynôme est Je poids attribué aux structures de type séquence. En effet, comme cela a été souligné par Tamine, deux boucles en série génèrent la même complexité que deux boucles emboîtées. La solution suggérée par Tamine consiste à différencier les structures emboîtées en leur attribuant différents symboles.

Si on se réfère au nombre de chemins possibles engendrés par ces exemples, dans le cas des boucles en série, on a un facteur d'addition, alors que dans le cas des boucles emboîtées, on a un facteur de multiplication.

Nous considérons donc que le facteur multiplicatif associé aux séquences n'est pas pleinement justifié. Dans le polynôme caractéristique, deux structures quelconques mises en série engendrent une complexité égale au produit de leur complexité. Il est évident que des structures mises

en

série engendrent une complexité plus grande que s'il n'y a qu'une seule structu.re, mais qu'elle doit être sa valeur? Une solution similaire à celle de Tamioe est d'attribuer des symboles différents pour les structures séquentielles et de garder le même symbole pour les structures emboîtées.

Cette approche est plus satisfaisante, car alors le degré d'un monôme indique le niveau d'emboîtement et les symboles différents indiquent des structures en série. Les exemples suivants montrent la fonne générale de ce polynôme et l'application sur un programme constitué de deux boucles, soit disposées en série, soit emboîtées.

Exemple 1

Le polynôme ab2 c correspond à un programme contenant une structure simple suivie de deux boucles emboîtées et suivies d'une structure.

Exemple 2 sous-progranunes, nous effectuons deux évaluations sur les objets de type sous-programme. La première consiste à calculer le polynôme caractéristique en prenant en compte les appels à des sous-programmes appartenant aux modules. Pour cela, chaque appel à un sous-programme du module est remplacé par la variable X. Les appels à des so·us-programmes externes au module ne sont pas pris en compte dans cette mesure de complexité, car ils

traduisent des liens inter-modulaires et ils sont évalués justement dans les mesures inter-modulaires.

Le polynôme aura la forme suivante:

n

~

ci . (ai +

f

b j . xj)

~

j=l

i=l

Supposons que le monôme suivant fasse partie du polynôme caractéristique associé à un sous-programme:

c3. (a3 + b1 . xl + b4 . x4)

alors on peut dire que parmi l'ensemble des chemins possibles qui empnmtent 3 structures cycliques, il y a

a3 chemins qui ne comportent aucun appel à des sous·progrommes, b1 chemins qui comportent un seul appel à un sous-programme, et b4 chemins qui comportent 4 appels à des sous-programmes.

La nécessité de présenter le polynôme sous forme compacte nous fait perdre de l'information se trouvant dans la structure. En effet, si x4 signifie qu'il y a 4 appels de sous-programmes, on ne sait pas si c'est le même programme qui est appelé plusieurs fois ou s'il sagit de progr.ammes différents. Une possibilité aurait été de différencier les programmes appelés. Dans notre exemple, supposons qu'un sous-programme soit appelé une fois et un autre trois fois, cela aurait donné l'expression suivante: Xa + Xb3· De même, dans le cas d'une alternative, si chaque branche contient le même nombre d'appels, on factorise sans vérifier que la séquence d'appel soit la même.

Cette variante du polynôme caractéristique est relativement complexe, mais reste abordable pour des sous-programmes standards de complexité moyeime. Une autre approche aussi possible consiste à calculer le polynôme caractéristique en remplaçant les appels aux procédures par une valeur entière simple et en indiquant à côté du polynôme le nombre total d'appels effectués à l'intérieur du sous-programme.

Savoir quelle mesure est la plus adéquate nécessite un certain nombre d'expérimentations. Pour le moment, nous n'essayons pas de distinguer les appels à différents sous-programmes, chaque appel est remplacé par la variable X.

Cette première évaluation du polynôme caractéristique traduit la complexité du code d'une procédure en indiquant Je nombre d'appels à d'autres procédures. Une deuxième évaluation, traduisant la complexité

d'une procédure où l'on tient compte de la complexiré de toutes les procédures internes utilisées, consiste à évaluer la structure d'un sous-programme dans lequel chaque appel à un autre sous-sous-programme est remplacé par le code correspondant. C'est ce que nous appelons le polynôme caractéristique ajusté. En d'autres termes, on remplace chaque appel à une procédure, interne au module, par le code correspondant et on calcule le polynôme sur tout le code obtenu.

Pour réaliser cette mesure, il faut commencer par calculer la complexité de chaque sous-programme en remplaçant par la valeur 1 tous les appels à des sous-progranunes. Ensuite, on effectue le premier type d'évaluation pour chaque procédure impliquée, et on remplace chaque variable X par le polynôme correspondant au sous-programme appelé.

Toute récursion directe ou indirecte est ignorée.

Exemple

Polynôme des données

Cette métrique permet de mesurer la complexité des structures de données des différentes variables d'un module. Une première distinction doit être effectuée entre les données qui sont globales à l'intérieur du module et les données qui sont propres à chaque objet de type sous-programme.

La complexité due aux données est exprimée par un polynôme en C et en I de la forme suivante:

L

n aj . chi . 1Cï*

i=O

où aj représente le nombre de variables du Lypt: ù6Lt:nui.né, bi représente le nombre de composants,

Cj représente le nombre d'imbrications,

*

indique une indirection (due à un pointeur).

Cette mesure donne une bonne approximation de la complexité des structu.res de données.

7.2.2 Implantation

Cette partie de EM2/Complex est implantée comme un système à part, mais elle est destinée à s'intégrer dans l'environnement EM2. Elle est d'ailleurs construit sur des outils de l'environnement, et son intégration ne posera pas de difficultés.

L'implantation d'une partie de ces métriques est le fruit du travail de licence de P. Racloz [Rac 86]. Elle a été facilitée par l'utilisation de GOS, un générateur d'outils syntaxiques [Guy 82). L'interface utilisateur est fidèle à celle de l'environnement EM2 (figures 7 .8 et 7 .9).

L'implantation de la métrique portant sur le polynôme des données n'a pas encore été effectuée. Longueur du programme observee Longueur du programme ca 1 eu 1 ee Effort da comprehens ion Temps pour cette comprehension

Vue globale Objets

Figure 7.8: Fenêtre concernant la métrique de Halstead

Exit

Figure 7.8 : Fenêtres concernant le polynôme caractéristique