Guide de contribution¶
Ce guide decrit le workflow de developpement, les conventions de code et la checklist de revue pour Revise Mieux.
Workflow TDD¶
Chaque critere d'acceptation (AC) en Given/When/Then se traduit directement en un test Go. Le cycle est strict :
- Rouge -- Ecrire le test. Il echoue car le code n'existe pas encore.
- Vert -- Ecrire le minimum de code pour que le test passe.
- Bleu -- Refactorer si necessaire, en verifiant que le test passe toujours.
Processus pour une AC¶
- Lire l'AC correspondante dans
docs/ac/Z*.md - Ecrire le test en Given/When/Then (TDD red)
- Implementer le minimum pour passer le test (TDD green)
- Refactorer si necessaire (TDD refactor)
- Mettre a jour
docs/lot0-tracker.md(statut[x])
Conventions de nommage Go¶
Packages¶
- Nom en un mot minuscule :
mastery,chapter,session(pasmastery_service) - Fichiers en
snake_case.go
Types¶
- Structs exportees en
PascalCase - Interfaces nommees d'apres le comportement :
Repository,Clock,Publisher(pasIRepository) - Enums metier comme Value Objects immuables :
MasteryState,ItemType,SessionStatus
Fonctions et methodes¶
- Constructeurs
New*qui valident les invariants :NewMastery(state)refuse un state vide - Premier parametre toujours
ctx context.Context - Errors wrapping avec contexte :
fmt.Errorf("mastery.RecordAttempt: %w", err)
Erreurs metier¶
Erreurs sentinelles definies dans le domaine :
var (
ErrTransitionBlocked = errors.New("transition blocked: spacing requirement not met")
ErrItemArchived = errors.New("item is archived")
ErrSessionNotResumable = errors.New("session cannot be resumed from current status")
)
Les handlers HTTP mappent ces erreurs vers les status codes HTTP correspondants.
Patterns de test¶
Nommage des tests¶
Nommer les tests d'apres l'AC couverte :
func TestZ1AC01_UnknownToFragile(t *testing.T) { ... }
func TestZ1AC04_SpacingBlocksOKToSolid(t *testing.T) { ... }
func TestZ2AC05_LLMFailureFallback(t *testing.T) { ... }
Un test par AC minimum, plus de tests pour les cas limites.
Table-driven tests¶
Utiliser des table-driven tests pour les transitions Mastery et le scoring :
func TestMasteryTransition(t *testing.T) {
tests := []struct {
name string
initial MasteryState
score float64
want MasteryState
wantCS int
}{
{"unknown_success", Unknown, 1.0, Fragile, 1},
{"unknown_failure", Unknown, 0.0, Unknown, 0},
{"solid_failure", Solid, 0.0, OK, 0},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
m := NewMastery(tt.initial)
m.RecordAttempt(tt.score, time.Now())
assert(t, m.State, tt.want)
assert(t, m.ConsecutiveSuccesses, tt.wantCS)
})
}
}
Strategie de test par couche¶
| Couche | Type de test | Quoi tester | Quoi mocker |
|---|---|---|---|
domain/ |
Unitaire pur | Transitions, regles metier, validations | Rien -- pas de dependance |
app/ |
Unitaire + mocks | Orchestration, enchainement d'appels | Repositories (interfaces), clients externes |
infra/postgres/ |
Integration | Requetes SQL, mappings | Rien -- vraie DB |
http/handler/ |
HTTP | Status codes, DTOs, validation input | Services (interfaces) |
Regles¶
go test ./...doit passer en moins de 30 secondes (tests unitaires)go test -tags=integration ./...pour les tests avec DB- Pas de
time.Sleepdans les tests -- injecter uneClockinterface pour l'espacement 24h - Ecrire un mock uniquement quand on ne peut pas tester avec la vraie implementation
Regles d'architecture¶
Ce qu'il ne faut PAS faire¶
- Importer Gin ou pgx dans
domain/ - Retourner une entite domaine dans une reponse HTTP (utiliser un DTO dans
http/dto/) - Tester la logique metier via des tests HTTP end-to-end
- Ajouter une feature non listee dans le Lot 0 tracker
- Utiliser
interface{}/anyquand un type concret existe - Mettre de la logique metier dans les handlers HTTP
- Modifier un
Itemdirectement -- passer par l'agregatChapter - Modifier un
Attemptdirectement -- passer par l'agregatSession
Sens des dependances¶
Les imports vont toujours vers l'interieur :
- http/ importe app/ et domain/
- app/ importe domain/
- infra/ importe domain/ (implemente les interfaces)
- domain/ n'importe rien du projet
Checklist PR¶
Avant de soumettre une pull request, verifier :
- Le test existe et couvre l'AC
- Le domaine ne depend d'aucun package infra
- Les erreurs sont wrappees avec contexte
- Les transitions Mastery passent par l'entite, pas par SQL direct
- Les DTOs sont separes des entites domaine
- Les migrations sont idempotentes ou versionnees
- Le tracker Lot 0 est mis a jour
Commandes utiles¶
| Commande | Description |
|---|---|
make test |
Tous les tests (unitaires + integration) |
make test-unit |
Tests unitaires uniquement |
make test-integration |
Tests d'integration (necessite DB) |
make lint |
Lint complet (golangci-lint + go vet) |
make fmt |
Formatage du code Go |
make check |
Lint + tests (CI gate) |
make bench |
Benchmark LLM (IDP) |
make bench-ocr |
Benchmark OCR |
make bench-all |
Benchmark tous les modeles |
make bench-report |
Genere le rapport HTML des benchmarks |
make backend-test-mastery |
Tests du domaine Mastery uniquement |
make backend-swagger |
Regenere la doc Swagger |
make backend-tools |
Installe golangci-lint et swag |