Cours BUT Info

Ch. 3 — Qualité logicielle, Git avancé

Métriques de qualité (Déméter, complexité cyclomatique, Halstead), dette technique, SOLID, TDD, SCRUM et XP, PMD — puis Git avancé : tags, branches, merge, rebase et conflits.

Mesurer la qualité

Comment un client évalue-t-il la conformité de l'application livrée ? Comment, non-spécialiste, évalue-t-il la qualité du logiciel ? Trois réponses : des spécifications précises, des outils et métriques, des principes et méthodologies.

Quatre aspects : l'extensibilité (couplage, cohésion), la maintenabilité (substitution, abstraction), la clarté (lisibilité, imbrication), la testabilité (couverture). Aux indicateurs simples — lignes de code, nombre de méthodes, ratios divers — s'ajoutent trois métriques sérieuses :

  • Loi de Déméter (connaissance minimale) : chaque unité ne doit voir que les unités étroitement liées à la sienne — gage de maintenabilité et d'adaptabilité ;
  • Complexité cyclomatique : le nombre de chemins linéairement indépendants ; elle évalue couverture, nombre de tests nécessaires, cohésion ;
  • Complexité d'Halstead : fondée sur opérateurs et opérandes — uniques et totaux — pour estimer difficulté, effort et nombre de bugs.

La dette technique

Améliorer a posteriori est difficile et chronophage : cela revient à solder la dette technique — les défauts qu'on choisit de réparer plus tard, et qui coûtent plus cher qu'évités au départ : ils induisent des intérêts. Deux leviers pour la contenir : des principes (SOLID, KISS/DRY, MoSCoW, YAGNI) et des méthodologies (linéaire, itérative, agile, cycle en V, CMMI, XP, SCRUM, TDD).

SOLID

Cinq principes de conception pour produire des applications plus compréhensibles, flexibles et maintenables :

  • Single responsibility : une classe ou une méthode doit avoir une et une seule responsabilité ;
  • Open/closed : une entité applicative est fermée à la modification directe, ouverte à l'extension ;
  • Liskov substitution : une instance de type T doit pouvoir être remplacée par une instance d'un sous-type de T sans que la cohérence du programme ne soit modifiée ;
  • Interface segregation : préférer plusieurs interfaces spécifiques pour chaque client plutôt qu'une seule interface générale ;
  • Dependency inversion : dépendre des abstractions, pas des implémentations.

TDD

Le Test Driven Development conçoit le logiciel par petits pas, de façon itérative et incrémentale, en écrivant chaque test avant le code source et en remaniant le code continuellement. Trois lois : écrire un test qui échoue avant tout code de production ; une seule assertion à la fois ; le minimum de code pour la satisfaire. Cycle : test → échec constaté → changement minimal → test passe → tous les tests passent → remanier, corriger les régressions → itérer. Bénéfices : pas de modifications sans lien avec le but, pas d'« accidents de parcours », coût des évolutions maîtrisé, livraisons en confiance.

SCRUM et XP

SCRUM implémente la méthode agile : rôles précis (SCRUM master, product owner, l'équipe), processus itératif et incrémental, sprints de 1 à 4 semaines finissant sur une version opérationnelle et stable, client impliqué du début à la fin, pair programming. Bénéfices visés : réduire le délai de réalisation et détecter les écarts au plus tôt.

XP (Extreme Programming), orientée réalisation pour équipes réduites aux besoins changeants : client sur site, intégration continue, petites livraisons fréquentes, tests fonctionnels et unitaires, conception aussi simple que possible, refactoring régulier, appropriation collective du code, pair programming.

PMD, analyseur statique

Un analyseur statique traque les défauts courants sans exécuter le code : variables inutilisées, blocs catch vides, création inutile d'objets. Outre PMD : SonarQube, Checkstyle, SpotBugs. PMD définit quelques centaines de règles — OnlyOneReturn, CallSuperInConstructor — dont certaines se personnalisent : ExcessiveMethodLength, FieldNamingConventions (expressions régulières sur les noms d'attributs). Les règles se déclarent dans un fichier XML :

<rule ref="category/java/codestyle.xml/OnlyOneReturn"/>
<rule ref="category/java/design.xml/TooManyFields">
  <properties>
    <property name="maxfields" value="10" />
  </properties>
</rule>
pmd check -d <répertoire-source> -R pmd-rules.xml -f html > rapport.html

Git : tags et branches

Motivations : un CV en version principale avec des variantes par employeur visé ; un logiciel avec une version stable (corrections de bugs) et des versions expérimentales réintégrées une fois au point. Les tags marquent des états : git tag liste, git tag -a <tag> crée (éventuellement sur un ancien commit), git checkout <tag> y replonge.

Anatomie : chaque commit porte une liste de parents — 0 pour l'initial, 1 pour un commit ordinaire, 2 ou plus pour une fusion. Une branche est une lignée généalogique de révisions, dont le commit le plus récent — le sommet (tip) — avance à chaque commit. Un commit est accessible s'il appartient à au moins une branche ; les autres sont automatiquement supprimés. En mode detached HEAD, la copie de travail est liée à un commit, pas à une branche : les commits faits dans cet état n'appartiennent à aucune branche.

git branch <nom> [révision]       # créer, sans changer la branche courante
git checkout -b <nom> [révision]  # créer ET en faire la branche courante
git branch -d <nom>               # supprimer

Merge, rebase, conflits

La fusion (git merge <branche>) intègre les modifications d'une branche dans une autre. Si la destination est contenue dans la source, la fusion avance simplement son sommet : un fast-forward. Si les branches ont divergé, Git crée un commit de fusion qui devient le sommet de la destination — et à chaque git pull, une fusion est exécutée. Avec --no-ff, on obtient un commit de plus (voir ci-dessous). Le rebase dit « je veux baser mes changements sur ce que les autres ont fait » — et ne doit jamais porter sur des commits déjà pushés vers un dépôt public.

Git fusionne automatiquement dès que les modifications portent sur des fichiers différents ou des parties distinctes d'un même fichier texte. Le conflit survient quand deux branches modifient le même fichier binaire ou la même partie d'un fichier texte — à résoudre à la main.

Dans le fichier conflictuel, Git inclut les modifications non conflictuelles et fait apparaître les deux versions concurrentes entre marqueurs :

<<<<<<< HEAD
La 1e ligne modifiée
=======
La 1e ligne changée
>>>>>>> src

Fichier corrigé : git commit -a crée le commit de fusion — ses parents sont les sommets des branches fusionnées. git merge --abort abandonne.

A retenir

  • qualité : extensibilité, maintenabilité, clarté, testabilité — mesurées par Déméter, cyclomatique, Halstead ;
  • la dette technique produit des intérêts : SOLID, TDD, SCRUM/XP et PMD la contiennent ;
  • branche = lignée de commits ; pull = fetch + merge ; jamais de rebase sur des commits publics ;
  • conflit = même fichier binaire, ou même partie d'un même fichier texte.


coursQU_03.pdf

R2.03 · Cours 3 — Qualité logicielle / Git : utilisation avancée · 60 diapositives

Consultation seule — téléchargement désactivé

Chargement du document…

Dernière mise à jour le

Sur cette page