« Tout code que vous écrivez aujourd’hui, vous le relirez demain. Écrivez pour votre futur vous. »

Cette page est une annexe de cours, pas un article. Elle synthétise huit ouvrages de référence en extrayant ce qui s’applique directement à un projet web d’étudiant — un site, une appli, un projet d’intégration.

Elle se consulte plutôt qu’elle ne se lit d’un bout à l’autre. Les articles du blog font le travail inverse : ils prennent un désaccord entre ces auteurs et le déplient. Les deux formats se complètent, et ni l’un ni l’autre ne remplace les livres.


1. Les fondamentaux du métier

The Pragmatic Programmer — Hunt & Thomas

Le livre-boussole. Ses principes s’appliquent dès vos premiers projets.

DRY — Don’t Repeat Yourself. Chaque morceau de connaissance doit avoir une représentation unique et non ambiguë. En pratique : si vous copiez-collez du CSS ou du JS entre plusieurs pages, c’est un signal. Factorisez.

flowchart TD
    A["3 pages
3 copies des styles"] -->|extraire| B["styles.css
source unique"] B -->|un lien chacune| C["3 pages
1 seule définition"] class A alerte class B ok

La théorie de la vitre brisée. Un console.log oublié, un nom cryptique : la négligence appelle la négligence. Maintenez la qualité dès le départ, même sur un TD.

flowchart TD
    A["1 console.log oublié"] --> B["Personne ne le retire"]
    B --> C["Trois autres s'ajoutent"]
    C --> D["Variables nommées x, y, z"]
    D --> E["Code mort non supprimé"]
    E --> F["Projet illisible"]
    class A attention
    class F alerte

Le prototypage comme outil de réflexion. Avant de coder une fonctionnalité complexe, faites un prototype jetable. L’objectif n’est pas du code propre, c’est d’apprendre vite. Puis jetez-le.

flowchart TD
    A["Idée"] --> B["Prototype
rapide et sale"] B --> C{"On a appris ?"} C -->|pas encore| B C -->|oui| D["Jeter
le prototype"] D --> E["Implémenter
proprement"] class B attention class D alerte class E ok

L’estimation. « Combien de temps pour cette maquette ? » ne se répond jamais au jugé. Décomposez, identifiez les inconnues, donnez une fourchette. C’est une compétence professionnelle autant que technique.

Avec une IA. Un modèle vous aide à prototyper vite — un squelette HTML/CSS en deux minutes pour tester une idée. Mais le code généré viole souvent DRY : duplications, styles inline. Explorez avec l’IA, nettoyez avec ces principes. Et pour l’estimation, elle n’a aucune idée du temps que vous mettrez.


A Philosophy of Software Design — Ousterhout

Une idée centrale : la complexité est l’ennemi principal. Tout en découle.

Modules profonds contre modules superficiels. Un bon module offre une interface simple et cache une implémentation riche. validerFormulaire(données) qui renvoie un booléen est profond. Dix petites fonctions verifierEmail(), verifierNom(), verifierAge() exposées séparément sont superficielles : elles déplacent la complexité vers l’appelant.

flowchart TD
    P1["Module profond
validerFormulaire()"] --> P2["Cache email, nom, âge,
format, cohérence"] P2 -.->|à l'opposé| S1["Module superficiel
six fonctions exposées"] S1 --> S2["Deux ou trois lignes
chacune"] class P1,P2 ok class S1,S2 alerte

La complexité vient de l’accumulation. Aucune ligne isolée ne rend un projet ingérable. C’est l’empilement de petites décisions floues. À chaque ajout : est-ce que je rends le projet plus simple ou plus compliqué à comprendre ?

%%{init: {"xyChart": {"width": 300, "height": 230}}}%%
xychart-beta
    title "La complexité s'accumule"
    x-axis ["S1", "S2", "S3", "S4", "S5", "S6", "S7", "S8"]
    y-axis "Complexité perçue" 0 --> 100
    line [5, 10, 18, 28, 42, 60, 78, 95]

Les commentaires stratégiques. N’écrivez pas ce que fait le code — il le dit déjà. Écrivez pourquoi vous avez fait ce choix.

// Délai de 300 ms : évite de relancer la recherche à chaque frappe
setTimeout(lancerRecherche, 300);

Concevoir deux fois. Avant d’implémenter, esquissez deux approches. Comparez. Même si vous gardez la première, avoir envisagé l’alternative améliore votre compréhension du problème.

Avec une IA. Elle produit souvent des modules superficiels — beaucoup de petites fonctions sans cohérence d’ensemble. Du code qui fonctionne sans avoir été pensé : exactement le piège décrit ici. Demandez-lui deux approches différentes, puis choisissez vous-même.


2. Écrire du code lisible

Clean Code — Robert C. Martin

Des noms qui ont du sens. d ne veut rien dire, delaiEnJours dit tout. Entre div1, container et grille-produits, le troisième transforme la lisibilité de votre HTML et de votre CSS.

Des fonctions courtes, à responsabilité unique. Si vous pouvez extraire un bloc en lui donnant un nom explicite, faites-le.

// Trop de responsabilités
function gererPanier(action, produit, quantite) {
  // quarante lignes qui font tout
}

// Chaque fonction a un rôle
function ajouterAuPanier(produit, quantite) { /* … */ }
function calculerTotal(panier) { /* … */ }
function afficherPanier(panier) { /* … */ }

La règle du boy-scout. Laissez le code plus propre que vous ne l’avez trouvé. Trente secondes pour corriger un nom flou pendant que vous travaillez à côté.

Avec une IA. Les modèles nomment de façon générique : data, result, item, temp. La première chose à faire sur du code généré est de renommer — et c’est un excellent exercice, puisqu’il faut comprendre le code pour lui donner de meilleurs noms.


The Art of Readable Code — Boswell & Foucher

Le test du temps de compréhension. Le meilleur code est celui qu’un camarade — ou votre futur vous dans trois mois — comprend le plus vite. Chaque décision doit réduire ce temps.

Simplifiez les conditions. Les if imbriqués sur quatre niveaux sont un cauchemar. Préférez les retours anticipés.

// Difficile à suivre
function traiterCommande(commande) {
  if (commande) {
    if (commande.estValide) {
      if (commande.articles.length > 0) {
        // enfin le vrai code
      }
    }
  }
}

// Lisible d'un coup d'œil
function traiterCommande(commande) {
  if (!commande) return;
  if (!commande.estValide) return;
  if (commande.articles.length === 0) return;
  // le vrai code, au bon niveau d'indentation
}

Réduire la portée des variables. Déclarez au plus près de l’utilisation. const par défaut, let quand nécessaire, jamais var.

Avec une IA. « Aplatis ces if imbriqués » fonctionne très bien : c’est un refactoring mécanique. En revanche elle ne peut pas juger si votre code est compréhensible par un humain — ce test-là reste le vôtre.


Refactoring — Fowler

Restructurer du code existant sans changer son comportement.

Quand refactorer : les signaux.

SignalCe que ça veut direAction
Code dupliquéLa même logique à deux endroitsExtraire une fonction commune
Fonction trop longuePlus de vingt ou trente lignesDécouper
Paramètres en cascadef(a, b, c, d, e, f)Regrouper dans un objet
Commentaire compensatoireIl explique un code confusRendre le code assez clair
Fichier fourre-toutUn utils.js de 500 lignesSéparer par responsabilité

Petit pas, test, petit pas. Ne refactorez jamais en gros. Un changement minimal, on vérifie, le suivant. En web : rouvrez la page après chaque modification.

flowchart TD
    A["Repérer un signal"] --> B["Petit changement"]
    B --> C["Tester dans
le navigateur"] C --> D{"Ça marche ?"} D -->|non| E["Annuler"] E --> B D -->|oui| F{"D'autres
signaux ?"} F -->|oui| A F -->|non| G["Fini"] class E alerte class G ok

Extraire une fonction est le refactoring le plus utile. Si un bloc mérite un commentaire explicatif, il mérite probablement d’être une fonction dont le nom remplace le commentaire.

Avec une IA. Domaine où elle brille et où elle est dangereuse : elle peut proposer un refactoring qui change le comportement sans le signaler. Le cycle petit pas → tester est votre filet. Jamais un gros refactoring d’un coup.


3. Coder avec une IA

Tous les principes ci-dessus deviennent plus importants avec un assistant, pas moins.

La règle d’or

Ne validez jamais du code que vous ne comprenez pas. Si un modèle génère trente lignes et que vous ne pouvez pas les expliquer à un camarade, vous ne pouvez pas les utiliser. Pas pour une raison morale : parce que vous ne saurez ni les déboguer, ni les faire évoluer.

flowchart TD
    GEN["Le modèle génère
du code"] --> Q{"Pouvez-vous expliquer
chaque ligne ?"} Q -->|non| L["Arrêter —
apprendre d'abord"] Q -->|oui| USE["Relire,
puis utiliser"] L --> R["Explication ligne à ligne,
doc, un camarade"] R --> Q class L alerte class USE ok

Où elle aide vraiment

Générer un squelette de départ, refactorer mécaniquement, expliquer une erreur, traduire entre deux syntaxes, explorer deux approches.

Où elle guide mal

Décider l’architecture, juger la lisibilité pour un humain, estimer le temps, garantir que le code est correct, remplacer votre compréhension.

Le prompt clair, c’est la pensée claire

Bien demander à un modèle relève exactement des mêmes principes que bien nommer une variable.

PrincipeApplication au prompt
Noms explicites« Un formulaire d’inscription avec email et mot de passe » plutôt que « fais-moi un formulaire »
Une responsabilitéUn prompt, une tâche
Commentaire stratégiqueDonnez le contexte et le pourquoi
Concevoir deux fois« Propose deux approches différentes »
DRYDonnez vos conventions pour qu’il ne réinvente pas

4. La culture professionnelle

Design Patterns — Gamma, Helm, Johnson & Vlissides

Vous n’avez pas besoin de tous les connaître. Quatre comptent en web.

Observer. Vous le pratiquez déjà : element.addEventListener('click', fn) en est une implémentation. Un sujet notifie ses observateurs. C’est le cœur du modèle événement → état → rendu.

%%{init: {"sequence": {"actorMargin": 4, "width": 68, "boxMargin": 4, "noteMargin": 4, "messageFontSize": 11, "actorFontSize": 12}}}%%
sequenceDiagram
    participant U as Utilisateur
    participant B as Bouton
    participant E as État
    participant R as Rendu
    U->>B: clic
    B->>E: notifie
    E->>E: change
    E->>R: rend
    R->>U: écran à jour

Module. Encapsuler dans un espace clos avec une interface publique. Les modules ES (import/export) font exactement ça. Le pourquoi : limiter ce qui est accessible de l’extérieur réduit les effets de bord.

Iterator. for...of, .map(), .filter(), .reduce() : parcourir une collection sans exposer sa structure.

Strategy. Changer un comportement à l’exécution. Au lieu d’un gros switch, passez une fonction.

const strategies = {
  parPrix: (a, b) => a.prix - b.prix,
  parNom:  (a, b) => a.nom.localeCompare(b.nom),
};
produits.sort(strategies[critereChoisi]);

Avec une IA. Elle connaît les patterns et tend à en mettre partout, y compris là où un if suffirait. Demandez-lui plutôt : « mon code utilise-t-il déjà un pattern sans le savoir ? »


Working Effectively with Legacy Code — Feathers

Du code legacy, vous en rencontrerez dès vos stages : tout code existant que vous n’avez pas écrit et devez modifier.

Comprendre avant de modifier. Résistez à l’envie de tout réécrire. Lisez, tracez les flux, identifiez les dépendances — les outils de débogage du navigateur sont faits pour ça.

Le filet de sécurité. Avant de toucher au code existant, un commit Git. Si tout casse, une commande vous ramène en arrière.

gitGraph TB:
    commit id: "Existant"
    commit id: "Filet"
    branch essai-1
    commit id: "Approche A"
    commit id: "Ça casse"
    checkout main
    branch essai-2
    commit id: "Approche B"
    commit id: "Ça marche"
    checkout main
    merge essai-2

Avec une IA. Excellent guide touristique du code legacy : « explique-moi ce que fait ce code, étape par étape » est souvent plus rapide que de déchiffrer seul. Mais elle peut se tromper sur l’intention d’origine, surtout avec des effets de bord subtils. Vérifiez en traçant vous-même.


Software Engineering at Google — Winters, Manshreck & Wright

La revue de code comme apprentissage. En entreprise, chaque modification est relue avant intégration. En projet, montrez votre code et relisez celui d’un camarade : vous apprendrez plus en une heure de relecture mutuelle qu’en trois heures seul.

La documentation vivante. Une documentation non mise à jour est pire que pas de documentation : elle induit en erreur. Documentez les décisions, pas les évidences.

Automatiser les corvées. Si vous faites la même chose à la main plus de trois fois, automatisez. Un linter, un formateur, un script de déploiement — le temps investi est récupéré la première semaine.

Penser à l’échelle du temps. Le code écrit aujourd’hui sera relu dans six mois, deux ans, cinq ans, peut-être par quelqu’un d’autre.

flowchart TD
    A["Semaine 1
vous écrivez, tout est frais"] --> B["Mois 3
un camarade doit le modifier"] B --> C["Mois 6
vous relisez, sans souvenir"] C --> D["An 2
un stagiaire hérite du projet"] D --> E["An 5
ça tourne, il faut migrer"] class A ok class E attention

Avec une IA. La revue par un modèle est un bon complément, un mauvais remplacement. Elle repère les bugs mécaniques et les incohérences de style, mais ne peut pas juger si votre code communique son intention. Les deux : l’IA en première passe, un camarade pour la vraie relecture.


Les dix réflexes

#RéflexeSource
1Ne vous répétez pasPragmatic Programmer
2Nommez clairementClean Code, Art of Readable Code
3Fonctions courtes et focaliséesClean Code, Refactoring
4Combattez la complexitéPhilosophy of Software Design
5Refactorez par petits pasRefactoring, Legacy Code
6Commit avant chaque modification risquéeLegacy Code
7Commentez le pourquoiPhilosophy of Software Design
8Relisez et faites relireSoftware Engineering at Google
9Automatisez les corvéesSoftware Engineering at Google
10Pensez événement → état → renduDesign Patterns

Dans quel ordre les lire

flowchart TD
    A["Maintenant
Art of Readable Code
Philosophy of Software Design"] --> B["Après quelques projets
Refactoring · Clean Code
Pragmatic Programmer"] B --> C["Stages et emplois
Software Eng. at Google
Legacy Code · Design Patterns"] class A ok class B attention class C neutre

Commencez par The Art of Readable Code, court et applicable immédiatement, puis A Philosophy of Software Design, dont les principes changent la façon de penser.

Quand vous serez à l’aise, Refactoring — les exemples de la deuxième édition sont en JavaScript —, puis The Pragmatic Programmer un chapitre à la fois, et Clean Code, dont certains exemples sont datés mais dont les principes tiennent.

Plus tard, Software Engineering at Google, Working Effectively with Legacy Code dont vous aurez besoin, c’est garanti, et Design Patterns à consulter comme une référence plutôt qu’à lire de bout en bout.


Sur ce blog

Les articles ne reprennent pas cette liste : ils prennent un désaccord entre ces auteurs et vont au bout. Les règles sont un point de départ explique pourquoi un catalogue de principes ne suffit pas, et pourquoi deux principes justes peuvent se contredire sur le même bout de code — suivi de quatre articles qui déplient chacun un de ces désaccords. Ils paraissent à l’automne, et se trouvent dans la liste des articles.

Références

  • Hunt, A. & Thomas, D. (1999). The Pragmatic Programmer. Addison-Wesley.
  • Ousterhout, J. K. (2021). A Philosophy of Software Design (2ᵉ éd.). Yaknyam Press.
  • Martin, R. C. (2008). Clean Code. Prentice Hall.
  • Boswell, D. & Foucher, T. (2011). The Art of Readable Code. O’Reilly.
  • Fowler, M. (2018). Refactoring: Improving the Design of Existing Code (2ᵉ éd.). Addison-Wesley.
  • Gamma, E., Helm, R., Johnson, R. & Vlissides, J. (1994). Design Patterns. Addison-Wesley.
  • Feathers, M. (2004). Working Effectively with Legacy Code. Prentice Hall.
  • Winters, T., Manshreck, T. & Wright, H. (2020). Software Engineering at Google. O’Reilly.