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
Tdoit pouvoir être remplacée par une instance d'un sous-type deTsans 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.htmlGit : 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> # supprimerMerge, 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
>>>>>>> srcFichier 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.
Rebaser réécrit l'historique : les commits changent d'identité. Si d'autres les ont déjà récupérés, leurs dépôts divergent sans fusion propre possible.
Un commit supplémentaire documente la fusion et permet de l'annuler d'un seul
git revert — contrepartie : des commits en plus dès qu'on multiplie les pulls.
coursQU_03.pdf
R2.03 · Cours 3 — Qualité logicielle / Git : utilisation avancée · 60 diapositives
Chargement du document…
Dernière mise à jour le
Ch. 2 — Tests : politiques et outils
De la javadoc aux tests : niveaux CFTL, non-régression, white-box et black-box, mocks, DevOps et CI/CD — puis JUnit 5 : annotations, assertions et diagramme de cas d'utilisation.
Ch. 4 — Exceptions et manipulation du système
La hiérarchie Throwable de bout en bout : checked et unchecked, ordre des catch, propagation, exceptions personnalisées, try-with-resources, multi-catch — puis la classe File pour dialoguer avec le système.