Aller au contenu principal
genie-logicielLes principes du génie logiciel

Les principes du génie logiciel

Ce que ce chapitre apporte

  • Définir le génie logiciel et dire ce qui le distingue de la programmation.
  • Nommer les critères de qualité d'un logiciel et savoir les opposer entre eux.
  • Situer les activités du cycle de vie et les grands modèles de processus.
  • Expliquer ce qu'est la dette technique et comment elle se contracte.
  • Employer les notions de couplage, de cohésion et de séparation des responsabilités.
  • Distinguer vérification et validation.
Où on va
Écrire un programme qui fonctionne est une chose. Écrire un programme que quelqu'un d'autre reprendra dans six mois, qu'on modifiera sans le casser, et qui vivra dix ans, en est une autre. Ce chapitre pose le vocabulaire de cette seconde activité : les critères de qualité et la façon dont ils s'opposent, les activités du cycle de vie, la dette technique, et les quelques principes de conception qui reviennent dans tout le reste du bloc.

Ce que recouvre le génie logiciel

Définition

Le génie logiciel est l'ensemble des méthodes, techniques et outils permettant de produire et de faire évoluer un logiciel dans des conditions maîtrisées de coût, de délai et de qualité.

La programmation s'arrête quand le programme donne le bon résultat. Le génie logiciel commence là. Il s'intéresse à ce que coûtera la modification suivante, à ce qui se passe quand trois personnes travaillent sur le même code, à ce qui reste compréhensible une fois l'auteur parti.

Cette différence n'est pas une question de taille de programme. Un script de cinquante lignes exécuté chaque nuit depuis quatre ans relève du génie logiciel, parce qu'il faut pouvoir le corriger. Un prototype de dix mille lignes jeté après la démonstration n'en relève pas.

Le critère qui décide
La question à se poser est : ce code sera-t-il lu et modifié ? Si oui, tout ce qui suit s'applique. Un logiciel juste mais impossible à faire évoluer devra être jeté, ce qui revient au même qu'un logiciel faux, en plus cher.

Les critères de qualité

La norme ISO 25010 en distingue huit. Six suffisent à couvrir l'essentiel de ce qui se discute en conception.

CritèreCe qu'il mesure
Fonctionnalitéle logiciel fait-il ce qui est demandé
Fiabilitése comporte-t-il correctement dans la durée, y compris en cas d'erreur
Performanceconsomme-t-il des ressources raisonnables
Utilisabilitéest-il compréhensible par celui qui s'en sert
Maintenabilitécombien coûte une modification
Portabilitéfonctionne-t-il ailleurs que sur la machine de développement
Ces critères entrent en concurrence
Optimiser la performance conduit souvent à un code moins lisible, donc moins maintenable. Rendre un logiciel portable ajoute des couches d'abstraction qui coûtent en performance. Renforcer la fiabilité multiplie les vérifications et donc le volume de code à écrire et à tester.
Aucun logiciel n'est excellent sur les six axes. Une décision de conception privilégie certains critères aux dépens d'autres, et la seule vraie faute consiste à ne pas savoir lesquels on a sacrifiés.
Un arbitrage courant
Un traitement doit garantir qu'une ressource n'est jamais utilisée par deux tâches à la fois. On peut poser un verrou global autour de tout le traitement : quelques lignes, facile à relire, mais qui sérialise plus que nécessaire. On peut aussi verrouiller ressource par ressource : meilleure exploitation du parallélisme, au prix d'une logique qu'il faudra reconstituer mentalement à chaque relecture.
Le premier choix privilégie la maintenabilité, le second la performance. Les deux se défendent. Ce qui ne se défend pas, c'est de choisir sans savoir ce qu'on échange.

Le cycle de vie

Les mêmes activités se retrouvent quel que soit le processus employé pour les enchaîner.

  1. Recueil et analyse des besoins : ce que le client demande, et ce dont il a besoin, qui ne coïncident pas toujours.
  2. Spécification : ce que le logiciel fera, formulé de façon vérifiable.
  3. Conception : comment il sera structuré. Les chapitres sur UML, les patrons et l'architecture traitent de cette phase.
  4. Implémentation : l'écriture du code.
  5. Tests : unitaires, d'intégration, de recette.
  6. Déploiement : la mise à disposition.
  7. Maintenance : corrective, évolutive, adaptative.
La maintenance domine le coût total
Les estimations varient selon les secteurs et les études, mais toutes placent la maintenance très au-dessus du développement initial, fréquemment au-delà des deux tiers du coût sur la durée de vie du logiciel.
Cela renverse une intuition répandue. Le temps consacré à rendre un code lisible n'est pas retiré au développement : il est investi dans la phase qui coûtera le plus cher.

Les modèles de processus

ModèlePrincipeContexte d'emploi
Cascadeles phases s'enchaînent, chacune achevée avant la suivantebesoins figés, contraintes réglementaires
Cycle en Vcascade, avec un niveau de test associé à chaque phase de conceptionsystèmes critiques, recette contractuelle
Incrémentallivraison par morceaux fonctionnels successifsle besoin se précise en avançant
Itératif, agilelivraisons fréquentes, ajustement à chaque itérationbesoin instable, retour client régulier

Le choix se joue sur la stabilité du besoin. Un système embarqué certifié se développe en V parce que la recette est contractuelle et que chaque exigence doit être tracée jusqu'à un test. Une application métier dont les utilisateurs découvrent leurs attentes en s'en servant se développe par itérations.

Anticiper n'est pas implémenter d'avance
Un développement incrémental met à l'épreuve la conception initiale : la version 1 doit accueillir des fonctions qui n'existent pas encore. La tentation est d'implémenter tout de suite ce qu'on croit deviner, ce qui produit du code inutile et souvent faux.
La bonne discipline est plus modeste. Il s'agit d'éviter d'écrire du code qui interdirait la suite : des variables globales partagées qui empêcheront le parallélisme, une écriture directe dans un fichier qui empêchera de changer de support, une classe qui suppose qu'un seul traitement tourne à la fois.

La dette technique

Définition

La dette technique désigne le coût futur des raccourcis pris aujourd'hui. Comme une dette financière, elle porte des intérêts : plus le remboursement tarde, plus chaque modification devient coûteuse.

Elle se contracte de plusieurs manières, et toutes ne sont pas fautives. Une équipe peut décider de livrer une solution imparfaite pour tenir une date, en sachant ce qu'elle devra reprendre. La dette est alors un instrument de gestion. Ce qui pose problème, c'est la dette contractée sans qu'on s'en aperçoive : du code recopié parce que c'était plus rapide, des noms qui ne veulent rien dire, des fonctions qui font six choses.

Quelques symptômes permettent de la reconnaître avant qu'elle ne bloque :

  • Une petite modification oblige à toucher beaucoup d'endroits.
  • Personne ne sait dire si une fonction est encore appelée.
  • Corriger un défaut en fait apparaître un autre ailleurs.
  • Les nouveaux arrivants mettent des semaines à devenir productifs.

Trois notions de conception

Elles reviennent dans tous les chapitres suivants, et la plupart des décisions d'architecture se justifient par l'une d'elles.

Séparation des responsabilités

Chaque module, chaque classe, chaque fonction assume une responsabilité. Une classe qui lit une configuration, calcule un résultat et écrit un journal en assume trois, et devra donc changer pour trois raisons indépendantes.

Couplage et cohésion

Le couplage mesure la dépendance entre modules. On le veut faible : modifier l'un ne doit pas obliger à modifier les autres.

La cohésion mesure à quel point les éléments d'un même module concourent au même but. On la veut forte.

Ces deux mesures varient souvent en sens inverse d'une mauvaise conception : un module qui fait trop de choses a une cohésion faible, et il finit couplé à beaucoup d'autres parce qu'il a besoin de tout.

Viennent ensuite des règles plus terre à terre : ne pas dupliquer, nommer explicitement, écrire court, laisser le code se lire plutôt que de le commenter partout. Et tester.

À quoi servent les tests
Trouver des défauts, oui, mais ce n'est pas leur apport principal. Une suite de tests qui passe autorise à modifier une partie du code sans craindre d'en casser une autre. Elle rend la refonte possible, donc le remboursement de la dette.
Un projet sans tests se fige : chacun évite le code existant et le contourne, ce qui augmente encore la dette.

Vérification et validation

Définition

L'assurance qualité logicielle regroupe les activités destinées à donner confiance dans le fait que le logiciel satisfera les exigences : revues, tests, mesures, respect des processus.

Elle recouvre deux contrôles distincts que l'on confond souvent.

La vérification demande si le produit a été construit correctement, c'est-à-dire conformément aux spécifications. La validation demande si c'est le bon produit qui a été construit, celui qui répond au besoin réel.

Un logiciel peut passer toutes ses vérifications et échouer à la validation : il fait exactement ce qui était écrit, et ce qui était écrit ne correspondait pas au besoin. Cette situation coûte cher parce qu'elle se découvre tard, souvent à la recette.

Exercices type

Un client demande que le traitement soit « rapide ». Que faire de cette exigence ?

La refuser en l'état et la reformuler.

« Rapide » ne se vérifie pas. On ne peut ni concevoir contre cette exigence, ni dire à la livraison si elle est tenue.

Une exigence devient vérifiable quand elle est chiffrée et située : traiter 10 Go de fichiers de 2 Mo en moyenne en moins de cinq minutes sur une liaison gigabit. On peut alors mesurer, et discuter.

Ce travail appartient à la spécification. Une exigence floue produit un désaccord au moment de la recette, quand il n'est plus temps.

Pourquoi la maintenance coûte-t-elle plus cher que le développement ?

D'abord parce que la vie d'un logiciel dépasse largement sa construction : quelques semaines d'écriture, plusieurs années d'exploitation pendant lesquelles il faut corriger, adapter et étendre.

Ensuite par un effet de composition. Chaque modification faite sans soin rend la suivante plus difficile, si bien que le coût unitaire d'une modification augmente avec l'âge du logiciel, sauf si l'on entretient sa structure.

La conséquence pratique porte sur la première version : le temps consacré à découper proprement conditionne le coût de toutes les suivantes.

Distinguer vérification et validation sur un exemple.

La spécification indique : « le journal enregistre l'horodatage, l'identifiant du traitement, la taille traitée et la durée ».

Vérification : le journal contient-il ces quatre champs, au bon format ? Un test automatisé répond.

Validation : ces quatre champs permettent-ils réellement à l'exploitant de diagnostiquer un échec ? Il manque peut-être le message d'erreur, ou le chemin du fichier fautif.

Le logiciel peut réussir la première et échouer la seconde. C'est la différence entre construire le produit correctement et construire le bon produit.

Est-il toujours mauvais de contracter de la dette technique ?

Non. Livrer une solution imparfaite pour tenir une échéance, en sachant ce qu'il faudra reprendre, est une décision de gestion défendable.

Deux conditions la rendent acceptable. Elle doit être consciente : on sait ce qu'on a simplifié. Elle doit être consignée, avec une estimation du coût de remboursement.

La dette problématique est celle qu'on contracte par ignorance, qui ne figure nulle part, et qu'on découvre le jour où elle empêche une évolution.

Quel critère de qualité sacrifie-t-on en dupliquant du code ?

La maintenabilité, tout de suite et durablement.

Recopier une fonction fait gagner quelques minutes. Le jour où le comportement change, il faut retrouver toutes les copies. Celles qu'on oublie créent des incohérences difficiles à diagnostiquer, puisque le logiciel se comporte différemment selon le chemin emprunté.

La fiabilité en souffre aussi : un correctif appliqué à une seule copie laisse le défaut vivant ailleurs.

La duplication n'améliore aucun autre critère, ce qui la distingue des vrais arbitrages. Ce n'est pas un compromis mais une perte différée.

Pourquoi exiger des tests avant d'autoriser une refonte ?

Une refonte modifie la structure sans changer le comportement. Sans moyen de vérifier que le comportement est resté identique, l'opération relève du pari.

Les tests jouent le rôle de filet : on déplace, on découpe, on renomme, et l'on sait en quelques secondes si quelque chose a cassé.

Cela explique la spirale des projets sans tests. Le code se dégrade, personne n'ose le reprendre faute de garantie, la dette s'accumule, et le coût de la moindre évolution finit par dépasser celui d'une réécriture.

La méthode

  1. Rends chaque exigence vérifiable avant de concevoir. Ce qui ne se mesure pas ne se livre pas.
  2. Nomme les critères de qualité prioritaires, et ceux que tu acceptes de sacrifier.
  3. Découpe par responsabilité : une classe, une raison de changer.
  4. Vise un couplage faible entre modules et une cohésion forte à l'intérieur de chacun.
  5. N'écris pas de code qui interdise la suite, sans pour autant implémenter d'avance ce qui n'est pas demandé.
  6. Consigne toute dette contractée sciemment, avec son coût estimé.
  7. Écris les tests avant la refonte, jamais après.

En résumé

  • Le génie logiciel s'occupe du coût de la prochaine modification, pas seulement de la justesse du code.
  • Les critères de qualité entrent en concurrence. Concevoir consiste à choisir, et à l'assumer.
  • Le cycle de vie va du besoin à la maintenance, phase la plus coûteuse.
  • Cascade et cycle en V pour un besoin figé, incrémental et itératif quand il évolue.
  • La dette technique est acceptable si elle est consciente et consignée.
  • Séparation des responsabilités, couplage faible, cohésion forte gouvernent la plupart des décisions de conception.
  • Les tests servent surtout à autoriser le changement.
  • Vérification : le produit est-il conforme. Validation : est-ce le bon produit.

Et ensuite ? Plusieurs personnes vont modifier le même code en parallèle. Il faut savoir qui a changé quoi, revenir en arrière, et fusionner des travaux concurrents. C'est l'objet du chapitre suivant, consacré à la gestion de versions.

Les principes du génie logiciel | Plateforme ETS