Développement piloté par les spécifications
DDD pour nommer les choses, BDD pour les spécifier, le plus petit changement pour les satisfaire, des preuves pour le démontrer. Indépendant de la pile.
1. Réfléchir avant de coder
- Énoncer les hypothèses. Si la demande est floue ou peut être interprétée de plusieurs façons, les nommer et demander. Ne jamais choisir en silence.
- Si une approche plus simple existe, le dire et la proposer.
- Lire le code que la tâche touche. Lister tout ce que le changement doit atteindre (appelants, tests, fixtures, configuration, exports) et ce qu’il pourrait casser (données détruites ou exposées, appelants qui cessent de fonctionner). C’est le périmètre ; les fonctionnalités supplémentaires n’en font pas partie. Nommer les extras ignorés en une ligne.
- Avant la première écriture, créer une branche à partir de main avec un nom adapté au travail (ex.
feat/<fonctionnalité>,fix/<bug>). Un travail en lecture seule ne nécessite pas de branche.
2. Modéliser le domaine (DDD)
Avant le code, écrire en quelques lignes :
- Contexte délimité et son langage ubiquitaire : les termes utilisés par les experts du domaine. Réutiliser les termes existants du code ; n’en ajouter que si nécessaire.
- Agrégat et ses invariants : ce qui doit toujours être vrai.
- Les noms dans le code, les tests et les messages utilisent ces termes. Rejeter les noms génériques (
handle,process,manager,utils). - La logique métier est pure et porte sur des données simples. Les E/S (base de données, réseau, horloge, aléa) sont derrière un port en périphérie, injecté.
Enregistrer dans docs/specs/<fonctionnalité>.md.
Ignorer pour les changements triviaux qui n’ajoutent aucun concept de domaine.
3. Spécifier le comportement (BDD)
Écrire des scénarios Given/When/Then dans le langage du domaine, un par comportement, incluant les cas limites et les cas d’échec. Chacun décrit un comportement observable, pas l’implémentation. Obtenir l’accord de l’utilisateur sur les scénarios non évidents ; ils constituent le contrat. Les enregistrer dans docs/features/<fonctionnalité>.feature.
4. Planifier
Pour un travail en plusieurs étapes, écrire un court plan dans docs/plans/<fonctionnalité>.md : chaque étape avec sa vérification. Lors de la poursuite à partir d’une spécification existante, écrire toujours le plan d’abord. Puis s’arrêter et demander à l’utilisateur de le relire ; ne jamais exécuter tant qu’il n’a pas approuvé. Prendre la première option qui fonctionne complètement :
- Est-ce nécessaire ? Sinon, passer.
- Déjà présent dans ce code ? L’utiliser comme le code environnant le fait.
- Bibliothèque standard ou fonctionnalité de la plateforme ? L’utiliser.
- Dépendance installée ? L’utiliser. Ne jamais en ajouter une pour quelques lignes.
- Une ligne compréhensible au premier coup d’œil ? L’utiliser.
- Sinon, le code minimum qui fonctionne.
5. Exécuter
Orchestration
Avant d’exécuter des tâches, avec ou sans spécification ou plan, vérifier si elles sont adaptées : plusieurs éléments séparables (ex. 3+ corrections), étapes indépendantes, ou étapes de difficultés clairement différentes. Si c’est le cas, lire orchestration.md (à côté de ce fichier) et demander ses deux options (via AskUserQuestion) avant la première modification : dans le même tour que la relecture du plan si vous écrivez un plan, sinon immédiatement. Toujours demander ; aucune autre approbation (plan, spécification, « ok ») ne compte comme un choix. Si les tâches ne sont pas adaptées, les faire en ligne.
Rouge, vert, refactoriser, par scénario
- Transformer un scénario en test échouant. L’exécuter ; constater qu’il échoue pour la bonne raison.
- Écrire le code minimal qui passe. L’exécuter.
- Refactoriser uniquement ce que ce changement a rendu désordonné.
- Correction de bug : reproduire avec un scénario échouant d’abord, analyser chaque appelant de la fonction, corriger la cause racine une fois dans le code partagé.
6. Maintenir le diff chirurgical
- Ne toucher que ce qui est nécessaire. Respecter le style existant ; ne pas améliorer le code adjacent. Chaque ligne modifiée doit être liée à la demande.
- Supprimer uniquement les orphelins créés par votre changement ; mentionner les autres code mort, ne pas le supprimer.
- Pas d’abstraction, de wrapper, d’option, de configuration ou de code « pour plus tard » que personne n’a demandé. La suppression prime sur l’ajout.
- Le code déplacé conserve sa gestion d’erreurs et sa validation.
- Commenter uniquement le pourquoi, en une ligne. Une limitation connue donne
shortcut: <la limite>, <quand mettre à niveau>. - Ne jamais supprimer : la validation aux frontières de confiance, la gestion d’erreurs qui empêche la perte de données, la sécurité, l’accessibilité, tout ce que l’utilisateur a demandé.
7. Vérifier avant de déclarer terminé
Exécuter les tests et toute vérification de build ou de typage. Lire la sortie. Rapporter les résultats réels ; si quelque chose a échoué ou n’a pas été exécuté, le dire. Pas de « ça devrait marcher ».
8. Répondre
Terminer par une ou deux lignes : ce qui a été ignoré ou non vérifié, et tout risque que l’utilisateur doit connaître.