@neikyun/ciel 6.11.2 → 6.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/.claude/agents/ciel-critic.md +71 -12
- package/assets/.claude/agents/ciel-explorer.md +59 -18
- package/assets/.claude/agents/ciel-improver.md +6 -3
- package/assets/.claude/agents/ciel-researcher.md +85 -25
- package/assets/.claude/hooks/block-destructive.sh +2 -2
- package/assets/.claude/hooks/check-test-first.sh +2 -2
- package/assets/.claude/hooks/memory-bootstrap.sh +0 -0
- package/assets/.claude/hooks/memory-engine.py +82 -15
- package/assets/.claude/hooks/post-tool-write.sh +32 -0
- package/assets/.claude/hooks/pre-agent-gate.sh +11 -6
- package/assets/.claude/hooks/pre-compact.sh +18 -0
- package/assets/.claude/hooks/pre-tool-write.sh +56 -31
- package/assets/.claude/hooks/session-start.sh +22 -1
- package/assets/.claude/hooks/session-version-check.sh +1 -1
- package/assets/.claude/hooks/stop.sh +104 -0
- package/assets/.claude/hooks/subagent-stop.sh +54 -0
- package/assets/.claude/hooks/track-file.sh +2 -2
- package/assets/.claude/hooks/user-prompt-submit.sh +11 -15
- package/assets/.claude/settings.json +18 -4
- package/assets/AGENTS.md +1 -1
- package/assets/CLAUDE.md +103 -175
- package/assets/commands/ciel-audit.md +58 -399
- package/assets/commands/ciel-create-skill.md +24 -38
- package/assets/commands/ciel-eval.md +25 -37
- package/assets/commands/ciel-init.md +36 -126
- package/assets/commands/ciel-status.md +22 -19
- package/assets/commands/ciel-update.md +20 -39
- package/assets/platforms/opencode/.opencode/agents/ciel-researcher.md +71 -895
- package/assets/platforms/opencode/.opencode/commands/ciel-audit.md +58 -296
- package/assets/platforms/opencode/.opencode/commands/ciel-create-skill.md +24 -46
- package/assets/platforms/opencode/.opencode/commands/ciel-eval.md +25 -45
- package/assets/platforms/opencode/.opencode/commands/ciel-init.md +36 -131
- package/assets/platforms/opencode/.opencode/commands/ciel-status.md +22 -24
- package/assets/platforms/opencode/.opencode/commands/ciel-update.md +20 -40
- package/assets/platforms/opencode/AGENTS.md +4 -4
- package/assets/rules/security.md +30 -0
- package/assets/rules/testing.md +23 -0
- package/assets/skills/agile/SKILL.md +42 -0
- package/assets/skills/alerting/SKILL.md +55 -0
- package/assets/skills/api-design/SKILL.md +46 -0
- package/assets/skills/appsec/SKILL.md +43 -0
- package/assets/skills/architecture/SKILL.md +74 -0
- package/assets/skills/backend/SKILL.md +41 -0
- package/assets/skills/backup-recovery/SKILL.md +42 -0
- package/assets/skills/caching/SKILL.md +44 -0
- package/assets/skills/cdn/SKILL.md +42 -0
- package/assets/skills/chaos/SKILL.md +41 -0
- package/assets/skills/cicd-pipeline/SKILL.md +56 -0
- package/assets/skills/cloud/SKILL.md +42 -0
- package/assets/skills/code-quality/SKILL.md +42 -0
- package/assets/skills/code-review/SKILL.md +41 -0
- package/assets/skills/communication/SKILL.md +42 -0
- package/assets/skills/containers/SKILL.md +42 -0
- package/assets/skills/cqrs/SKILL.md +41 -0
- package/assets/skills/crypto/SKILL.md +46 -0
- package/assets/skills/data-engineering/SKILL.md +42 -0
- package/assets/skills/database-design/SKILL.md +46 -0
- package/assets/skills/ddd/SKILL.md +45 -0
- package/assets/skills/deployment-strategies/SKILL.md +51 -0
- package/assets/skills/desktop/SKILL.md +42 -0
- package/assets/skills/devsecops/SKILL.md +43 -0
- package/assets/skills/event-driven/SKILL.md +46 -0
- package/assets/skills/frontend/SKILL.md +41 -0
- package/assets/skills/functional/SKILL.md +42 -0
- package/assets/skills/high-availability/SKILL.md +42 -0
- package/assets/skills/iac/SKILL.md +46 -0
- package/assets/skills/logging/SKILL.md +46 -0
- package/assets/skills/meta/ciel-improve/SKILL.md +127 -0
- package/assets/skills/meta/learnings-capture/SKILL.md +105 -0
- package/assets/skills/meta/patch-spec/patch-spec.md +50 -0
- package/assets/skills/meta/skill-creator/SKILL.md +115 -0
- package/assets/skills/meta/skill-freshness-auditor/SKILL.md +164 -0
- package/assets/skills/meta/skill-variant-evaluator/SKILL.md +100 -0
- package/assets/skills/meta/skills-first-design-auditor/SKILL.md +192 -0
- package/assets/skills/ml-engineering/SKILL.md +42 -0
- package/assets/skills/mobile/SKILL.md +42 -0
- package/assets/skills/monitoring/SKILL.md +54 -0
- package/assets/skills/networking/SKILL.md +42 -0
- package/assets/skills/nosql/SKILL.md +41 -0
- package/assets/skills/oop-solid/SKILL.md +42 -0
- package/assets/skills/performance/SKILL.md +41 -0
- package/assets/skills/reactive/SKILL.md +42 -0
- package/assets/skills/release-management/SKILL.md +51 -0
- package/assets/skills/research/fact-check-claims/SKILL.md +98 -0
- package/assets/skills/research/research-forums/SKILL.md +103 -0
- package/assets/skills/research/research-github-issues/SKILL.md +103 -0
- package/assets/skills/research/research-web-sources/SKILL.md +108 -0
- package/assets/skills/research/synthesize-findings/SKILL.md +112 -0
- package/assets/skills/research/validate-source-credibility/SKILL.md +103 -0
- package/assets/skills/resilience/SKILL.md +41 -0
- package/assets/skills/serverless/SKILL.md +42 -0
- package/assets/skills/servers/SKILL.md +41 -0
- package/assets/skills/sql/SKILL.md +45 -0
- package/assets/skills/supply-chain/SKILL.md +41 -0
- package/assets/skills/system-design/SKILL.md +91 -0
- package/assets/skills/tech-leadership/SKILL.md +46 -0
- package/assets/skills/testing/SKILL.md +41 -0
- package/assets/skills/tracing/SKILL.md +36 -0
- package/assets/skills/utility/branch-cleaner/SKILL.md +195 -0
- package/assets/skills/utility/branch-setup/SKILL.md +144 -0
- package/assets/skills/utility/changelog-updater/SKILL.md +125 -0
- package/assets/skills/utility/commit-writer/SKILL.md +154 -0
- package/assets/skills/utility/issue-closer/SKILL.md +106 -0
- package/assets/skills/utility/issue-creator/SKILL.md +200 -0
- package/assets/skills/utility/pr-merger/SKILL.md +189 -0
- package/assets/skills/utility/pr-opener/SKILL.md +180 -0
- package/assets/skills/utility/release-publisher/SKILL.md +224 -0
- package/assets/skills/workflow/ciel-dev-process/SKILL.md +94 -0
- package/assets/skills/workflow/faire-gatekeeper/SKILL.md +3 -1
- package/assets/skills/workflow/prouver-verifier/SKILL.md +11 -2
- package/dist/cli/check.d.ts.map +1 -1
- package/dist/cli/check.js +11 -2
- package/dist/cli/check.js.map +1 -1
- package/dist/cli/claude.d.ts.map +1 -1
- package/dist/cli/claude.js +0 -2
- package/dist/cli/claude.js.map +1 -1
- package/dist/cli/init.d.ts.map +1 -1
- package/dist/cli/init.js +11 -2
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/opencode.d.ts.map +1 -1
- package/dist/cli/opencode.js +2 -1
- package/dist/cli/opencode.js.map +1 -1
- package/package.json +1 -1
- package/assets/commands/ciel-migrate.md +0 -35
- package/assets/commands/ciel-refresh.md +0 -91
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: validate-source-credibility
|
|
3
|
+
description: Scores information sources on credibility and freshness — official docs > maintainer blog > GitHub issue > StackOverflow > community forum > random blog. Flags stale content (> 12 months for fast-moving libs). Invoked during research synthesis to rank findings before trusting.
|
|
4
|
+
allowed-tools: WebFetch
|
|
5
|
+
context: fork
|
|
6
|
+
agent: researcher
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# validate-source-credibility — Rank sources by trust
|
|
10
|
+
|
|
11
|
+
## What this covers
|
|
12
|
+
Meta-research skill #4 of 6. Not all sources are equal. Wrong information confidently presented causes downstream failures. This skill scores every finding before it influences code decisions.
|
|
13
|
+
|
|
14
|
+
## Core principle
|
|
15
|
+
**Credibility is tiered, not binary.** A Tier-1 source (official docs) needs no validation. A Tier-4 source (random blog) is a hypothesis until cross-referenced.
|
|
16
|
+
|
|
17
|
+
## Inputs
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
SOURCE_URL: [URL of information source]
|
|
21
|
+
CLAIM: [what the source says]
|
|
22
|
+
TECHNOLOGY: [lib name]
|
|
23
|
+
VERSION: [version the claim is about]
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Credibility tiers
|
|
27
|
+
|
|
28
|
+
| Tier | Source | Trust |
|
|
29
|
+
|------|--------|-------|
|
|
30
|
+
| **1** | Official docs, GitHub release notes, source code | High — always prefer |
|
|
31
|
+
| **2** | Maintainer blog, maintainer GitHub discussion, conference talk | High for scope; possible bias |
|
|
32
|
+
| **3** | SO accepted (50+ upvotes), GitHub issue with maintainer comment, Reddit consensus | Medium — cross-reference |
|
|
33
|
+
| **4** | Random blog, low-upvoted SO, Medium article without credentials | Low — verify against Tier 1/2 |
|
|
34
|
+
| **5** | AI-generated content, old tutorials without authorship | Zero — flag, do not follow |
|
|
35
|
+
|
|
36
|
+
## Freshness thresholds
|
|
37
|
+
|
|
38
|
+
| Library pace | Max age |
|
|
39
|
+
|-------------|---------|
|
|
40
|
+
| Fast (React, Next.js, Ktor, Tailwind) | 12 months |
|
|
41
|
+
| Medium (Rails, Django, Spring) | 18 months |
|
|
42
|
+
| Slow (C, SQL, git) | 36 months |
|
|
43
|
+
| Stable fundamentals | 5+ years |
|
|
44
|
+
|
|
45
|
+
## Process
|
|
46
|
+
|
|
47
|
+
### 1. Identify tier from URL + content
|
|
48
|
+
|
|
49
|
+
### 2. Extract publication date
|
|
50
|
+
|
|
51
|
+
### 3. Compute freshness (fresh / aging / stale)
|
|
52
|
+
|
|
53
|
+
### 4. Score: Tier + Freshness → FULL / VERIFY / REJECT
|
|
54
|
+
|
|
55
|
+
## Common patterns
|
|
56
|
+
|
|
57
|
+
### Good credibility assessment
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
## SOURCE CREDIBILITY — https://blog.example.com/react-19-patterns
|
|
61
|
+
|
|
62
|
+
Tier: 4 (personal blog, no maintainer credential)
|
|
63
|
+
Freshness: aging — published 2025-11-08, 5 months old
|
|
64
|
+
Library pace: fast (React)
|
|
65
|
+
|
|
66
|
+
Credibility signals:
|
|
67
|
+
- Author unknown in React contributor list
|
|
68
|
+
- No upvote/engagement data available
|
|
69
|
+
|
|
70
|
+
Trust assessment: VERIFY — cross-reference with official docs before using
|
|
71
|
+
|
|
72
|
+
Recommendation: Do not trust alone. Verify claim "use() replaces useEffect" against react.dev.
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Bad credibility assessment
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
Source looks reliable. Use it.
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Problems: no tier, no freshness check, no trust assessment.
|
|
82
|
+
|
|
83
|
+
## Anti-patterns
|
|
84
|
+
|
|
85
|
+
- **Tier 4/5 trusted alone** — always cross-reference against Tier 1/2
|
|
86
|
+
- **Tier 1 overrides common sense** — if docs contradict source code for installed version, flag conflict
|
|
87
|
+
- **Age penalized unfairly** — stable fundamentals don't age. A 2017 article on TCP sockets is still correct.
|
|
88
|
+
- **Freshness = correctness** — a brand-new blog post can be wrong; an old maintainer article on stable API can be right
|
|
89
|
+
- **AI-generated content not detected** — boilerplate patterns, generic structure, no author credentials → suspect
|
|
90
|
+
|
|
91
|
+
## How to verify
|
|
92
|
+
|
|
93
|
+
- [ ] Tier assigned (1-5)?
|
|
94
|
+
- [ ] Publication date extracted?
|
|
95
|
+
- [ ] Freshness assessed against library pace?
|
|
96
|
+
- [ ] Trust assessment given (FULL / VERIFY / REJECT)?
|
|
97
|
+
- [ ] Recommendation states how main session should treat this source?
|
|
98
|
+
|
|
99
|
+
## When triggered
|
|
100
|
+
|
|
101
|
+
- By `synthesize-findings` when merging multi-source research
|
|
102
|
+
- On any finding from Tier 3/4/5 before it influences code decisions
|
|
103
|
+
- User request: "how reliable is this source?"
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: resilience
|
|
3
|
+
description: "Resilience — circuit breakers, retry with backoff, timeouts, bulkheads, graceful degradation. À charger quand on rend un système tolérant aux pannes."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Resilience
|
|
7
|
+
|
|
8
|
+
**Principe premier :** La résilience n'est pas "gérer les erreurs" — c'est concevoir le système pour qu'il continue à fonctionner (même en mode dégradé) quand ses dépendances tombent. Chaque dépendance externe va tomber un jour. La question n'est pas "est-ce que Redis est fiable ?" mais "que fait mon application quand Redis est down ?". Le circuit breaker n'est pas un pattern — c'est un réflexe : ne pas continuer à appeler un service qui ne répond pas.
|
|
9
|
+
|
|
10
|
+
## Checklist
|
|
11
|
+
- [ ] Timeouts explicites sur tout appel externe : connect < 2s, read < 5s, request < 10s
|
|
12
|
+
- [ ] Circuit breaker sur chaque dépendance : échecs > N → circuit OPEN → fast fail
|
|
13
|
+
- [ ] Retry avec backoff exponentiel + jitter — pas de retry immédiat, max 3-5 tentatives
|
|
14
|
+
- [ ] Bulkhead : pools de connexions séparés par client/type de requête
|
|
15
|
+
- [ ] Fallback défini pour chaque point de défaillance : cache, defaults, degraded mode
|
|
16
|
+
- [ ] Chaos engineering : tester la résilience en production, pas en théorie
|
|
17
|
+
|
|
18
|
+
## Anti-patterns
|
|
19
|
+
### Retry sans backoff
|
|
20
|
+
**Ce qu'on voit :** `while (!ok) { try { call(); ok = true; } catch {} }` — retry immédiat en boucle.
|
|
21
|
+
**Pourquoi c'est dangereux :** thundering herd. Le service en difficulté reçoit 1000× plus de requêtes à cause des retries. L'incident s'aggrave. Un retry immédiat est une attaque DDoS contre soi-même.
|
|
22
|
+
**Faire plutôt :** backoff exponentiel avec jitter. 1s → 2s → 4s → 8s, max 5 tentatives. Le jitter (aléatoire ±25%) empêche la synchronisation des retries de tous les clients.
|
|
23
|
+
|
|
24
|
+
### Pas de fallback
|
|
25
|
+
**Ce qu'on voit :** si Redis est down → 500 Internal Server Error. Le cache est devenu un point de défaillance unique.
|
|
26
|
+
**Pourquoi c'est dangereux :** une dépendance non-critique (cache, analytics, recommandations) fait tomber tout le service. Le client voit une erreur pour une fonctionnalité qui aurait pu fonctionner sans cette dépendance.
|
|
27
|
+
**Faire plutôt :** si cache down → servir depuis la DB (plus lent mais fonctionnel). Si analytics down → logger localement et réessayer plus tard. Chaque dépendance a un fallback explicite.
|
|
28
|
+
|
|
29
|
+
### Timeout = 60 secondes
|
|
30
|
+
**Ce qu'on voit :** `http.get(url, { timeout: 60000 })`. L'utilisateur attend 60s.
|
|
31
|
+
**Pourquoi c'est dangereux :** les threads/workers sont bloqués. Le pool s'épuise. L'app devient non-réactive. Un timeout trop long transforme une défaillance partielle en outage total.
|
|
32
|
+
**Faire plutôt :** timeouts agressifs. Connect < 2s, read < 5s. L'utilisateur préfère un échec rapide qu'une attente infinie. Fast fail > slow timeout.
|
|
33
|
+
|
|
34
|
+
## Patterns
|
|
35
|
+
### Circuit Breaker
|
|
36
|
+
**Quand :** toute communication avec une dépendance externe.
|
|
37
|
+
**Comment :** CLOSED (normal) → OPEN après N échecs consécutifs → HALF_OPEN après timeout → CLOSED si succes. En OPEN, les appels sont rejetés immédiatement (pas de tentative inutile).
|
|
38
|
+
|
|
39
|
+
### Bulkhead
|
|
40
|
+
**Quand :** ressources partagées entre différents appels/clients.
|
|
41
|
+
**Comment :** pool de connexions séparé par client. Si un client sature son pool, les autres ne sont pas affectés. Comme les cloisons étanches d'un navire — une voie d'eau ne coule pas le bateau.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: serverless
|
|
3
|
+
description: "Serverless — fonctions comme unites de deploiement, cold starts, concurrency, API Gateway, Step Functions, cout a la requete. A charger quand on utilise des fonctions serverless."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Serverless
|
|
7
|
+
|
|
8
|
+
**Principe premier :** Le serverless n'est pas "pas de serveur" — c'est "le serveur n'est pas ton probleme". Tu echange le controle contre la simplicite operationnelle. Le piege : tu ne controles plus le runtime, la memoire, le reseau, le systeme de fichiers. Chaque hypothese que tu fais sur l'execution ("le /tmp existe", "l'IP est stable", "le process survit entre deux requetes") est une source de bug. Le serverless recompense l'architecture stateless et punit le stateful. Le cout est a la requete — une fonction inefficace coute de l'argent a chaque appel, pas juste du CPU.
|
|
9
|
+
|
|
10
|
+
## Checklist
|
|
11
|
+
- [ ] Les fonctions sont stateless — pas de donnees persistees dans le filesystem local (/tmp est ephemere)
|
|
12
|
+
- [ ] Les connexions DB/Redis sont hors du handler (global scope, reutilisees entre invocations)
|
|
13
|
+
- [ ] Le timeout est configure explicitement (3s pour API, 30s max pour async) — pas de timeout infini
|
|
14
|
+
- [ ] La memoire est dimensionnee correctement (plus de RAM = plus de CPU, mais plus de cout)
|
|
15
|
+
- [ ] Les cold starts sont mesures (P50/P95) et optimises (bundling, provisioned concurrency si necessaire)
|
|
16
|
+
- [ ] API Gateway / load balancer a un health check independant de la fonction
|
|
17
|
+
- [ ] Les fonctions ont un dead letter queue pour les evenements non traites
|
|
18
|
+
|
|
19
|
+
## Anti-patterns
|
|
20
|
+
### Fonction monolithe
|
|
21
|
+
**Ce qu'on voit :** une seule Lambda/Cloud Function qui gere toutes les routes. 500MB de code, 3s de cold start. "C'est un microservice."
|
|
22
|
+
**Pourquoi c'est dangereux :** le cold start est proportionnel a la taille du code. Le deploiement est tout-ou-rien. Le debugging est un cauchemar. C'est un monolithe avec les inconvenients du serverless (cold starts, timeouts) sans les benefices (isolation, deploiement independant).
|
|
23
|
+
**Faire plutot :** une fonction par endpoint/operation. Chaque fonction est independante : son propre code, son propre deploiement, son propre timeout. Si une fonction est lente, les autres ne sont pas affectees.
|
|
24
|
+
|
|
25
|
+
### State cache dans le handler
|
|
26
|
+
**Ce qu'on voit :** `let connection; export const handler = async (event) => { if (!connection) connection = await createDbConnection(); ... }` — le test unitaire passe, la prod echoue aleatoirement.
|
|
27
|
+
**Pourquoi c'est dangereux :** la connection est reutilisee entre invocations mais pas entre cold starts. Le comportement depend de l'etat du container (warm/cold), ce qui est non deterministe. Pire : si la connection est stales (timeout serveur), elle echoue silencieusement.
|
|
28
|
+
**Faire plutot :** initialiser dans le global scope, AVANT le handler. Verifier la sante de la connexion a chaque invocation. Accepter que les cold starts arrivent et les monitoriser.
|
|
29
|
+
|
|
30
|
+
### Serverless pour tout
|
|
31
|
+
**Ce qu'on voit :** toute l'architecture est en serverless. Y compris un job qui tourne 24/7, un websocket qui reste ouvert 2h, une DB de 10 To.
|
|
32
|
+
**Pourquoi c'est dangereux :** le serverless est optimal pour les charges sporadiques et les pics. Pour une charge constante, le cout par requete est superieur a un serveur. Les timeouts (15 min Lambda, 60 min Cloud Functions) rendent certains workloads impossibles. Les websockets sur serverless = cout eleve et latence variable.
|
|
33
|
+
**Faire plutot :** serverless pour les API, les traitements asynchrones, les cron jobs. Serveur/container pour les charges constantes, les connexions longues, les traitements lourds. Hybride : ce n'est pas l'un ou l'autre.
|
|
34
|
+
|
|
35
|
+
## Patterns
|
|
36
|
+
### Global scope initialization
|
|
37
|
+
**Quand :** toute fonction qui utilise une connexion externe (DB, Redis, API client).
|
|
38
|
+
**Comment :** initialiser les clients hors du handler. Le runtime reutilise le container pour plusieurs invocations — le code hors handler n'est execute qu'au cold start. SDK clients, connexions, configuration : tout dans le global scope. Le handler ne fait que le metier.
|
|
39
|
+
|
|
40
|
+
### Step Functions pour l'orchestration
|
|
41
|
+
**Quand :** workflow multi-etapes (paiement → stock → email → facture).
|
|
42
|
+
**Comment :** chaque etape est une fonction separee. Step Functions gere les transitions, les retries, les timeouts, la compensation (Saga pattern). Le workflow est visible dans la console, chaque etape est monitorisee independamment.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: servers
|
|
3
|
+
description: "Servers — reverse proxy comme défense périmétrique, TLS termination, process management, OS hardening. À charger quand on configure des serveurs."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Servers
|
|
7
|
+
|
|
8
|
+
**Principe premier :** Un serveur n'est pas la machine où tourne l'app — c'est la première ligne de défense. Ne jamais exposer une application directement. Toujours un reverse proxy devant qui gère TLS, rate limiting, buffering. L'application ne doit voir que du trafic propre et autorisé. Le serveur doit survivre à un reboot, un crash applicatif, et un pic de trafic sans intervention humaine.
|
|
9
|
+
|
|
10
|
+
## Checklist
|
|
11
|
+
- [ ] Reverse proxy devant l'application (Nginx/Caddy/Traefik) — jamais d'exposition directe
|
|
12
|
+
- [ ] TLS 1.3 avec certificats auto-renouvelés (LetsEncrypt/cert-manager)
|
|
13
|
+
- [ ] Process manager avec restart automatique (systemd) — pas de `node server.js &`
|
|
14
|
+
- [ ] Health check endpoint utilisé par le load balancer (liveness ≠ readiness)
|
|
15
|
+
- [ ] Firewall : seuls les ports 443 et 80 (redirect) sont ouverts, SSH restreint
|
|
16
|
+
- [ ] Log rotation configurée avec retention max — pas de disque plein par les logs
|
|
17
|
+
|
|
18
|
+
## Anti-patterns
|
|
19
|
+
### Application directement exposée
|
|
20
|
+
**Ce qu'on voit :** `app.listen(443)` — l'app écoute directement sur le port public. Pas de proxy.
|
|
21
|
+
**Pourquoi c'est dangereux :** pas de buffering → un client lent bloque un worker. Pas de rate limiting → pas de protection DDoS basique. Pas de cache statique → chaque requête touche l'app. Le reverse proxy est une couche de défense gratuite.
|
|
22
|
+
**Faire plutôt :** Nginx/Caddy en frontal. Il gère TLS, compression, cache statique, rate limiting. L'app écoute sur localhost:3000 et ne voit que du trafic filtré.
|
|
23
|
+
|
|
24
|
+
### Redémarrage manuel
|
|
25
|
+
**Ce qu'on voit :** `node server.js` lancé dans un screen/tmux. Crash → app down jusqu'à intervention humaine.
|
|
26
|
+
**Pourquoi c'est dangereux :** tout process crashe un jour. OOM, segfault, exception non catchée. Sans restart automatique, chaque crash = outage non borné. À 3h du matin, personne ne relance.
|
|
27
|
+
**Faire plutôt :** systemd avec `Restart=always` et `RestartSec=5`. Le process manager relance en secondes.
|
|
28
|
+
|
|
29
|
+
### Logs sans rotation
|
|
30
|
+
**Ce qu'on voit :** `app.log` qui grossit depuis 6 mois. 50 Go. Le disque se remplit.
|
|
31
|
+
**Pourquoi c'est dangereux :** disque plein = tout tombe. L'app ne peut plus écrire, la DB s'arrête. L'outage par manque d'espace disque est le plus évitable de tous.
|
|
32
|
+
**Faire plutôt :** logrotate avec retention 30 jours. Alerte si espace disque < 20%. Les logs sont streamés vers un système centralisé, pas stockés localement.
|
|
33
|
+
|
|
34
|
+
## Patterns
|
|
35
|
+
### Reverse proxy
|
|
36
|
+
**Quand :** toute application web en production.
|
|
37
|
+
**Comment :** Nginx/Caddy en frontal. TLS termination, compression, cache statique, rate limiting. L'applicatif derrière sur localhost uniquement.
|
|
38
|
+
|
|
39
|
+
### Health check
|
|
40
|
+
**Quand :** load balancer ou orchestrateur devant l'app.
|
|
41
|
+
**Comment :** `GET /health` → `{"status":"ok","uptime":3600,"db":"connected"}`. Vérifié toutes les 10s. 3 échecs → retirer l'instance du pool.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sql
|
|
3
|
+
description: "SQL — EXPLAIN ANALYZE comme discipline, CTE & window functions, requêtes N+1, transactions courtes, connection pooling. À charger quand on écrit ou optimise des requêtes SQL."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# SQL
|
|
7
|
+
|
|
8
|
+
**Principe premier :** Le SQL n'est pas un langage de requête — c'est un langage déclaratif qui décrit CE QUE tu veux, pas COMMENT l'obtenir. Le planificateur de la DB décide du comment. Ton job n'est pas d'écrire "la bonne requête" — c'est d'écrire une requête que le planificateur peut optimiser. La discipline fondamentale est donc : toujours vérifier ce que le planificateur a fait (EXPLAIN ANALYZE). Sans ça, tu codes à l'aveugle. Un index n'existe que si le planificateur l'utilise.
|
|
9
|
+
|
|
10
|
+
## Checklist
|
|
11
|
+
- [ ] EXPLAIN ANALYZE dans la PR pour toute requête non-triviale — pas après la mise en prod
|
|
12
|
+
- [ ] Pas de `SELECT *` sauf si tu as VRAIMENT besoin de toutes les colonnes
|
|
13
|
+
- [ ] Les JOINs sont vérifiés : chaque condition de JOIN a un index des deux côtés
|
|
14
|
+
- [ ] Pas de N+1 — les données liées sont fetchées en une requête (JOIN, IN, ou LATERAL)
|
|
15
|
+
- [ ] Les transactions sont aussi courtes que possible — tout le calcul est fait avant le BEGIN
|
|
16
|
+
- [ ] Connection pooling : PgBouncer (transaction mode) ou équivalent entre l'app et PostgreSQL
|
|
17
|
+
|
|
18
|
+
## Anti-patterns
|
|
19
|
+
### N+1 queries
|
|
20
|
+
**Ce qu'on voit :** `for (const user of users) { orders = await db.query('SELECT * FROM orders WHERE user_id = $1', [user.id]) }`. 100 users = 101 requêtes.
|
|
21
|
+
**Pourquoi c'est dangereux :** le N+1 est le tueur silencieux de performance. Chaque requête a une latence réseau (0.5ms en local, 5ms en cloud). 1000 users = 5 secondes juste en overhead réseau. Et le pire : la DB pourrait répondre en 50ms avec un JOIN.
|
|
22
|
+
**Faire plutôt :** `SELECT * FROM orders WHERE user_id = ANY($1)` avec un tableau d'IDs. Ou JOIN. Toujours regarder les boucles qui contiennent des requêtes DB — c'est le pattern N+1.
|
|
23
|
+
|
|
24
|
+
### EXPLAIN jamais fait
|
|
25
|
+
**Ce qu'on voit :** la requête est lente en production. On ajoute un index "au pif" sur une colonne qui semblait importante. La requête est toujours lente — l'index n'est pas utilisé.
|
|
26
|
+
**Pourquoi c'est dangereux :** sans EXPLAIN ANALYZE, tu ne sais pas ce que la DB fait vraiment. Seq Scan ? Index Scan ? Nested Loop ? Hash Join ? Chaque choix du planificateur a un impact 100-1000× sur la performance. Deviner l'index est du gaspillage.
|
|
27
|
+
**Faire plutôt :** `EXPLAIN (ANALYZE, BUFFERS) SELECT ...` → regarder le plan. Seq Scan sur grosse table → index. Nested Loop sur 100K×100K → Hash Join. L'index se met là où le plan montre un goulot, pas là où "ça semble logique".
|
|
28
|
+
|
|
29
|
+
### Transaction longue
|
|
30
|
+
**Ce qu'on voit :** `BEGIN; calculApplicatif(); query1(); appelAPIExterne(); query2(); COMMIT;` L'appel API prend 2 secondes.
|
|
31
|
+
**Pourquoi c'est dangereux :** la transaction garde des locks (RowExclusive, ShareLock) pendant toute sa durée. Toutes les modifications concurrentes sur les mêmes rows sont bloquées. 2 secondes de blocage → file d'attente → timeout → erreurs en cascade.
|
|
32
|
+
**Faire plutôt :** tout le calcul, les appels API, la validation métier sont faits AVANT le BEGIN. La transaction ne contient QUE les requêtes DB. Durée < 100ms. Si un appel externe est nécessaire au milieu → reconsidérer le design.
|
|
33
|
+
|
|
34
|
+
## Patterns
|
|
35
|
+
### CTE (Common Table Expression)
|
|
36
|
+
**Quand :** requête complexe avec des étapes intermédiaires.
|
|
37
|
+
**Comment :** `WITH active_users AS (SELECT id FROM users WHERE last_login > now() - interval '30 days'), user_orders AS (SELECT ...) SELECT ... FROM active_users JOIN user_orders ...`. Le CTE nomme chaque étape — bien plus lisible qu'une soupe de sous-requêtes. `MATERIALIZED` ou non selon que le CTE est réutilisé.
|
|
38
|
+
|
|
39
|
+
### Window functions
|
|
40
|
+
**Quand :** classement, cumuls, ou comparaison entre rows sans perdre la granularité.
|
|
41
|
+
**Comment :** `ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY created_at)` pour le premier/dernier par groupe. `LAG(price) OVER (PARTITION BY product ORDER BY date)` pour la variation. Pas de self-JOIN coûteux.
|
|
42
|
+
|
|
43
|
+
### Connection pooling
|
|
44
|
+
**Quand :** toute application en production avec PostgreSQL.
|
|
45
|
+
**Comment :** PgBouncer en transaction mode. L'app se connecte à PgBouncer (local), PgBouncer multiplexe sur PostgreSQL (peu de connexions). 1000 clients → 20 connexions DB. Évite le fork() par connexion de PostgreSQL.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: supply-chain
|
|
3
|
+
description: "Supply Chain Security — dépendances comme surface d'attaque, lockfile integrity, SBOM, SLSA provenance, signed commits. À charger quand on sécurise la chaîne d'approvisionnement."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Supply Chain Security
|
|
7
|
+
|
|
8
|
+
**Principe premier :** Chaque dépendance est une backdoor potentielle. La sécurité de la supply chain ne consiste pas à auditer chaque package — c'est impossible. Elle consiste à réduire la surface d'attaque (moins de dépendances), garantir la reproductibilité (lockfiles, pinning), et créer de la traçabilité (SBOM, provenance). Le jour où une CVE sort (et elle sortira), tu dois pouvoir répondre en < 1h à la question : "quels services utilisent ce package ?"
|
|
9
|
+
|
|
10
|
+
## Checklist
|
|
11
|
+
- [ ] Les dépendances sont épinglées (version exacte ou lockfile commité) — build reproductible
|
|
12
|
+
- [ ] Le nombre de dépendances est surveillé comme une métrique de risque — chaque ajout est justifié
|
|
13
|
+
- [ ] SBOM généré à chaque build (SPDX ou CycloneDX) et requêtable en cas d'incident
|
|
14
|
+
- [ ] SLSA niveau 2 minimum : build isolé, provenance attestée, artefacts signés
|
|
15
|
+
- [ ] Les dépendances non maintenues sont identifiées et remplacées proactivement
|
|
16
|
+
- [ ] Les signatures de commits et tags sont vérifiées — pas de "verified" sur un seul commit sur 100
|
|
17
|
+
|
|
18
|
+
## Anti-patterns
|
|
19
|
+
### Dépendance non épinglée
|
|
20
|
+
**Ce qu'on voit :** `"express": "^4.18.0"` dans package.json, pas de lockfile dans le repo. Chaque `npm install` peut installer une version différente.
|
|
21
|
+
**Pourquoi c'est dangereux :** un build non reproductible est un build non auditable. Si un attaquant compromet une version mineure de express, ton build l'installe silencieusement. Le hash de ton artefact change sans que tu saches pourquoi.
|
|
22
|
+
**Faire plutôt :** lockfile commité dans le repo. `npm ci` (pas `npm install`) dans la CI. Version exacte pinnée pour les dépendances critiques. Le lockfile est ta déclaration de ce qui tourne en production — traite-le comme tel.
|
|
23
|
+
|
|
24
|
+
### Dépendance comme choix gratuit
|
|
25
|
+
**Ce qu'on voit :** `npm install left-pad` pour une fonction de 11 lignes. `npm install is-odd` pour `n % 2 === 1`. 1500 dépendances au total.
|
|
26
|
+
**Pourquoi c'est dangereux :** chaque dépendance est un vecteur d'attaque et une dette de maintenance. `event-stream` (2018) a été compromis pour voler des bitcoins. `ua-parser-js` (2021) a été infecté par un malware. Plus tu as de dépendances, plus ta surface d'attaque est grande.
|
|
27
|
+
**Faire plutôt :** évaluer chaque dépendance avant de l'ajouter : est-ce que ça fait plus de 50 lignes de logique non-triviale ? Est-ce maintenu (dernier commit < 6 mois) ? Combien de maintainers ? Préférer la stdlib ou copier 10 lignes (attribuées) plutôt qu'une dépendance pour une fonction triviale.
|
|
28
|
+
|
|
29
|
+
### SBOM inutilisable en incident
|
|
30
|
+
**Ce qu'on voit :** un SBOM est généré, stocké dans un artefact de build que personne ne sait requêter. Le jour J, retrouver les services affectés prend 4h.
|
|
31
|
+
**Pourquoi c'est dangereux :** un SBOM qui n'est pas utilisable en incident est du théâtre de sécurité. Log4Shell a montré que les équipes qui avaient un SBOM requêtable ont patché en heures. Les autres en semaines.
|
|
32
|
+
**Faire plutôt :** SBOM versionné, stocké dans un registre central requêtable. Test d'audit trimestriel : "Simule une CVE sur le package X. Chronomètre le temps pour lister tous les services affectés." Si > 10 min, le processus est cassé.
|
|
33
|
+
|
|
34
|
+
## Patterns
|
|
35
|
+
### SBOM comme produit
|
|
36
|
+
**Quand :** toute application en production.
|
|
37
|
+
**Comment :** génération automatisée via Syft/Trivy dans la CI. Format SPDX ou CycloneDX. Stockage dans un registre (Dependency-Track, OWASP). API pour requêter "quels services utilisent log4j ?" en une requête. Le SBOM est un livrable, pas un sous-produit.
|
|
38
|
+
|
|
39
|
+
### SLSA provenance
|
|
40
|
+
**Quand :** consommateurs qui ont besoin de vérifier l'origine de l'artefact.
|
|
41
|
+
**Comment :** SLSA niveau 2 : build isolé (pas d'accès au réseau arbitraire), provenance signée (attestation du build system). Le consommateur vérifie la signature avant d'utiliser l'artefact. Le but : empêcher qu'un build compromis produise un artefact qui a l'air légitime.
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: system-design
|
|
3
|
+
description: "System Design — estimation back-of-envelope, CAP theorem, trade-offs, scalability patterns, load balancing, caching layers. A charger quand on concoit un nouveau service."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# System Design
|
|
7
|
+
|
|
8
|
+
**Principe premier :** Le system design n'est pas "choisir les bonnes technologies" — c'est identifier les contraintes et les accepter. Chaque decision d'architecture est un trade-off : consistency vs availability, latence vs throughput, simplicite vs flexibilite. Si tu ne peux pas nommer ce que tu sacrifies, tu n'as pas vraiment designe. La competence cle n'est pas de connaitre les patterns — c'est de savoir estimer (back-of-envelope) pour ne pas resoudre un probleme qui n'existe pas.
|
|
9
|
+
|
|
10
|
+
## Checklist
|
|
11
|
+
- [ ] Estimation back-of-envelope faite avant tout choix d'architecture (req/s, stockage, bande passante)
|
|
12
|
+
- [ ] Le CAP theorem est arbitre : ce systeme doit-il etre CP ou AP ? Pourquoi ?
|
|
13
|
+
- [ ] Chaque couche a une strategie de scale (vertical, horizontal, ou sharding)
|
|
14
|
+
- [ ] Les single points of failure sont identifies et elimines (ou assumes avec un plan de recovery)
|
|
15
|
+
- [ ] Le caching est place la ou il reduit la latence, pas la ou il est facile a implementer
|
|
16
|
+
- [ ] Les operations lourdes sont async (file d'attente, workers) — l'utilisateur ne bloque pas
|
|
17
|
+
- [ ] Le plan de capacity planning existe : a quel seuil on passe au niveau superieur ?
|
|
18
|
+
|
|
19
|
+
## Trade-offs : les 3 choix structurants
|
|
20
|
+
|
|
21
|
+
### SQL vs NoSQL
|
|
22
|
+
|
|
23
|
+
| | SQL (PostgreSQL, MySQL) | NoSQL (DynamoDB, MongoDB) |
|
|
24
|
+
|--|-------------------------|---------------------------|
|
|
25
|
+
| **Modele** | Schema fixe, relations, JOINs | Schema flexible, pas de JOINs |
|
|
26
|
+
| **Scale** | Vertical puis read replicas | Horizontal natif (sharding) |
|
|
27
|
+
| **Quand choisir** | Relations complexes, transactions ACID, reporting | Acces par cle connu, schema variable, scale horizontal obligatoire |
|
|
28
|
+
| **Piege** | Les migrations deviennent le bottleneck | Tu decouvres que t'as besoin de JOINs → impossible |
|
|
29
|
+
| **Ne JAMAIS faire** | `SELECT * FROM orders JOIN ... JOIN ... JOIN ...` sur 10M rows | Utiliser NoSQL "au cas ou" sans avoir mesure le besoin de scale |
|
|
30
|
+
|
|
31
|
+
### Sync vs Async
|
|
32
|
+
|
|
33
|
+
| | Sync (HTTP/gRPC) | Async (queues/events) |
|
|
34
|
+
|--|------------------|----------------------|
|
|
35
|
+
| **Consistance** | Immediate (le client sait tout de suite) | Eventuelle (le client sait plus tard) |
|
|
36
|
+
| **Couplage** | Le caller attend le callee | Decouple temporellement |
|
|
37
|
+
| **Quand choisir** | L'utilisateur attend la reponse | Operation lourde, notification, propagation |
|
|
38
|
+
| **Piege** | Le timeout tue tout (si B est lent, A est lent) | Debugging : ou est l'event ? Qui l'a traite ? |
|
|
39
|
+
|
|
40
|
+
### Monolithe vs Microservices
|
|
41
|
+
|
|
42
|
+
| | Monolithe | Microservices |
|
|
43
|
+
|--|----------|--------------|
|
|
44
|
+
| **Deploy** | 1 artefact | N artefacts independants |
|
|
45
|
+
| **Scale** | Tout ou rien | Par service (le checkout scale, pas l'auth) |
|
|
46
|
+
| **Complexite** | Dans le code (couplage) | Dans le reseau (latence, serialisation, erreurs) |
|
|
47
|
+
| **Quand choisir** | Equipe < 20, domaine stable, pas de besoin de scale independant | Equipes autonomes (> 5 equipes), modules qui scalent differemment |
|
|
48
|
+
| **Piege** | Le monolithe devient un "big ball of mud" (pas de frontieres internes) | 12 services pour 3 devs : le cout de coordination > benefices |
|
|
49
|
+
| **Regle** | Commencer monolithe modulaire. Extraire en service UNIQUEMENT quand la douleur est prouvee. |
|
|
50
|
+
|
|
51
|
+
## Anti-patterns
|
|
52
|
+
### Designer pour Google
|
|
53
|
+
**Ce qu'on voit :** sharding, event sourcing, CQRS, 12 microservices — pour 100 utilisateurs.
|
|
54
|
+
**Pourquoi c'est dangereux :** la complexite que tu construis aujourd'hui est la dette que tu paieras demain. Chaque couche ajoute des points de defaillance.
|
|
55
|
+
**Faire plutot :** estimation back-of-envelope. "100 req/s x 50ms = 5 workers suffisent. Une DB avec read replicas tient 10 000 req/s. Pas besoin de sharding avant 100k req/s." Le design evolue avec la charge.
|
|
56
|
+
|
|
57
|
+
### Single point of failure ignore
|
|
58
|
+
**Ce qu'on voit :** un load balancer, une DB, une region. "On verra quand ca tombera."
|
|
59
|
+
**Pourquoi c'est dangereux :** tout tombe. Un SPOF qui tombe = 100% du service down.
|
|
60
|
+
**Faire plutot :** redondance sur chaque couche. Multi-AZ, replicas, failover automatique. Si un composant ne peut pas etre redondant, documenter explicitement pourquoi.
|
|
61
|
+
|
|
62
|
+
### Pas d'estimation avant de coder
|
|
63
|
+
**Ce qu'on voit :** un endpoint cree sans savoir combien de req/s il va prendre. En production, ca s'effondre.
|
|
64
|
+
**Pourquoi c'est dangereux :** sans estimation, le choix d'architecture est arbitraire. SQL vs NoSQL, sync vs async — ces decisions dependent des ordres de grandeur.
|
|
65
|
+
**Faire plutot :** estimation en 5 min : req/s x pics, taille payload x volume, latence acceptable. Des ordres de grandeur. Si les ordres changent d'un facteur 10, le design change.
|
|
66
|
+
|
|
67
|
+
## Patterns
|
|
68
|
+
### Back-of-envelope estimation
|
|
69
|
+
**Quand :** avant tout choix d'architecture.
|
|
70
|
+
**Comment :** 3 calculs. (1) Throughput : req/s / temps de traitement = workers necessaires. (2) Storage : req/s x taille par req x retention = volume disque. (3) Network : req/s x taille de reponse = bande passante. Toujours x10 pour la marge. Si les chiffres sont petits, rester simple.
|
|
71
|
+
|
|
72
|
+
**Mise en place :** (1) Lister les endpoints/operations. (2) Estimer les req/s en pic. (3) Multiplier par la taille de payload. (4) Verifier que chaque couche (LB, app, DB, cache) tient ces chiffres. (5) Documenter les seuils de passage a l'echelle superieure (ex: a 1000 req/s → add read replica).
|
|
73
|
+
|
|
74
|
+
### Consistent hashing
|
|
75
|
+
**Quand :** sharding avec redistribution minimale quand on ajoute/supprime un nœud.
|
|
76
|
+
**Comment :** ring de hash. Chaque cle → premier nœud dans le sens horaire. Ajout d'un nœud ne redistribue que les cles voisines (pas tout le keyspace).
|
|
77
|
+
|
|
78
|
+
**Mise en place :** (1) Choisir une fonction de hash (SHA-256, MD5 tronque). (2) Placer les nœuds sur le ring. (3) Pour chaque cle, hash → premier nœud dans le sens horaire. (4) Pour la redondance, chaque cle va sur N nœuds consecutifs (replication). (5) Ajouter/supprimer un nœud ne deplace que ~K/N cles. Utilise par CDN, caches distribues, partitions DB.
|
|
79
|
+
|
|
80
|
+
### Backpressure
|
|
81
|
+
**Quand :** un producteur est plus rapide que le consommateur.
|
|
82
|
+
**Comment :** refuser explicitement (429/503) plutot qu'accepter et timeout. Rate limiting a l'entree. Queue avec capacite max.
|
|
83
|
+
|
|
84
|
+
**Mise en place :** (1) Definir la capacite max (ex: 1000 requetes concurrentes). (2) Rate limiter a l'entree (token bucket, sliding window). (3) Queue bornee (taille max, pas infinie). (4) Si file pleine → 429. (5) Le client retry avec exponential backoff + jitter. La backpressure se propage — si le worker est plein, l'API refuse, le client ralentit.
|
|
85
|
+
|
|
86
|
+
### Cache layers (ou placer le cache)
|
|
87
|
+
**Quand :** latence a reduire sur un chemin critique.
|
|
88
|
+
**Comment :** cache navigateur (Cache-Control headers) → CDN (edge cache) → cache applicatif (Redis) → DB. Chaque couche reduit la latence et la charge sur la couche suivante.
|
|
89
|
+
- **Avantages :** reduction drastique de la latence (DB: 10ms, Redis: 1ms, CDN: 0ms pour le client)
|
|
90
|
+
- **Desavantages :** stale data, invalidation complexe, memoire = cout
|
|
91
|
+
- **Mise en place :** (1) Identifier la hot path. (2) Mesurer la latence actuelle par couche. (3) Ajouter le cache le plus proche du client d'abord (CDN > Redis > local). (4) Definir TTL = fraicheur acceptable. (5) Monitorer hit rate > 80%.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: tech-leadership
|
|
3
|
+
description: "Tech Leadership — ADR, RFC, architecture reviews, dette technique, mentoring, estimation, roadmap technique. A charger quand on fait du leadership technique."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Tech Leadership
|
|
7
|
+
|
|
8
|
+
**Principe premier :** Le leadership technique n'est pas "le dev le plus senior decide" — c'est creer un environnement ou les bonnes decisions emergent de l'equipe. Le tech lead n'est pas un architecte omniscient qui dicte les solutions — c'est un jardinier qui cree les conditions pour que les bonnes pratiques poussent. Les deux livrables principaux sont les ADR (Architecture Decision Records) qui capturent le contexte et le pourquoi des decisions, et la strategie de dette technique (toute equipe a de la dette — la question est de savoir laquelle et a quel prix). Le technicien resout les problemes ; le tech lead rend l'equipe capable de resoudre les problemes sans lui.
|
|
9
|
+
|
|
10
|
+
## Checklist
|
|
11
|
+
- [ ] Les decisions techniques sont documentees en ADR (contexte, alternatives considerees, decision, consequences)
|
|
12
|
+
- [ ] La dette technique est suivie, budgetee (ex: 20% du sprint), et communiquee aux stakeholders
|
|
13
|
+
- [ ] Les RFC sont le processus standard pour les changements majeurs (> 2 semaines d'effort)
|
|
14
|
+
- [ ] L'estimation est basee sur l'historique (cycle time, throughput) — pas sur des jours/homme devines
|
|
15
|
+
- [ ] Les revues d'architecture sont regulieres (mensuelles) avec des criteres objectifs
|
|
16
|
+
- [ ] Le mentoring est structure : chaque dev junior a un plan de progression avec objectifs mesurables
|
|
17
|
+
- [ ] La roadmap technique est alignee avec la roadmap produit — pas deux planifications paralleles
|
|
18
|
+
|
|
19
|
+
## Anti-patterns
|
|
20
|
+
### Tech lead = seul decideur
|
|
21
|
+
**Ce qu'on voit :** le tech lead prend toutes les decisions seul. "Je connais le systeme, faites ce que je dis." L'equipe execute sans comprendre.
|
|
22
|
+
**Pourquoi c'est dangereux :** goulot d'etranglement decisionnel. L'equipe devient passive — "je fais ce que le lead dit". Le lead devient le bus factor = 1. Quand il part, la connaissance part avec lui. Les decisions ne sont pas contraintes parce que personne ne les conteste.
|
|
23
|
+
**Faire plutot :** decisions via RFC. L'auteur propose, l'equipe review, le lead approuve ou demande des changements. Le lead est un editeur, pas un auteur. Les decisions sont documentees (ADR) pour que le contexte survive au lead.
|
|
24
|
+
|
|
25
|
+
### Dette technique = tabou
|
|
26
|
+
**Ce qu'on voit :** l'equipe sait qu'il y a de la dette. Personne n'en parle aux stakeholders. Un jour, tout explose et le sprint "refactoring urgent" dure 3 mois.
|
|
27
|
+
**Pourquoi c'est dangereux :** la dette technique non communiquee est une bombe a retardement. Les stakeholders ne comprennent pas pourquoi "une feature simple prend 3 semaines". La confiance s'erode. L'equipe est en mode pompier permanent.
|
|
28
|
+
**Faire plutot :** la dette technique est un choix economique, pas une honte. La quantifier ("ce module coute 2x plus cher a modifier que la moyenne"). La presenter aux stakeholders comme un risque avec un cout. Budgeter 20% du sprint pour la reduction de dette. Montrer le ROI : "apres ce refactoring, les features sur ce module seront 2x plus rapides".
|
|
29
|
+
|
|
30
|
+
### Estimation = souhait
|
|
31
|
+
**Ce qu'on voit :** "c'est 3 jours" — base sur rien. Les estimations sont systematiquement x2-x3. Les deadlines sont basees sur les estimations et deviennent des engagements.
|
|
32
|
+
**Pourquoi c'est dangereux :** l'estimation n'est pas un engagement, mais les stakeholders l'entendent comme tel. Le cycle se repete : estimation optimiste → sous-performance percue → pression → estimation encore plus optimiste pour compenser → burn-out.
|
|
33
|
+
**Faire plutot :** estimer en probabilites : "50% de chances en 3 jours, 90% en 7 jours." Utiliser l'historique (cycle time reel, pas estime). Separer estimation (combien de temps) et engagement (quand c'est livre). L'engagement vient apres l'exploration, pas avant.
|
|
34
|
+
|
|
35
|
+
## Patterns
|
|
36
|
+
### ADR (Architecture Decision Record)
|
|
37
|
+
**Quand :** toute decision architecturale non triviale.
|
|
38
|
+
**Comment :** format standard : Titre, Contexte (pourquoi maintenant), Decision (ce qu'on a decide), Alternatives considerees, Consequences (positives et negatives). Fichier `docs/adrs/NNNN-title.md`. Les ADR documentent le POURQUOI, pas juste le QUOI. Un nouveau membre peut lire les ADR et comprendre l'histoire de l'architecture.
|
|
39
|
+
|
|
40
|
+
### RFC (Request for Comments)
|
|
41
|
+
**Quand :** changement qui affecte > 1 equipe ou > 2 semaines d'effort.
|
|
42
|
+
**Comment :** document de 2-4 pages. Sections : Motivation, Design propose, Alternatives, Impact (migration, cout, risques). Review period : 3-5 jours. L'auteur n'est pas le decideur — l'equipe (ou les equipes) commentent, le lead tranche. La decision est capturee en ADR.
|
|
43
|
+
|
|
44
|
+
### Probabilistic estimation
|
|
45
|
+
**Quand :** estimation d'une tache de > 1 jour.
|
|
46
|
+
**Comment :** "J'ai 50% de confiance que ca prendra X jours, 90% que ca prendra Y jours." Le ratio Y/X mesure l'incertitude. Si Y > 3X → l'incertitude est trop grande, faire un spike pour reduire. L'estimation est basee sur des taches similaires passees (historique), pas sur l'intuition.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: testing
|
|
3
|
+
description: "Testing — RED-GREEN-REFACTOR, test pyramid, testing behavior not implementation, FIRST principles, flaky test quarantine. À charger quand on écrit ou planifie des tests."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Testing
|
|
7
|
+
|
|
8
|
+
**Principe premier :** Les tests ne sont pas là pour prouver que le code marche — ils sont là pour te permettre de changer le code sans peur. Un test qui ne survit pas à un refactoring n'est pas un test, c'est un otage. Le but ultime n'est pas 100% de couverture — c'est la confiance : si les tests passent, je peux déployer. Si tu ne peux pas déployer après un test vert, les tests ont échoué, pas le code.
|
|
9
|
+
|
|
10
|
+
## Checklist
|
|
11
|
+
- [ ] RED (test échoue) → GREEN (passe) → REFACTOR — dans cet ordre, toujours
|
|
12
|
+
- [ ] Les tests testent le comportement observable, pas l'implémentation interne
|
|
13
|
+
- [ ] Test pyramid : 70% unitaires, 20% intégration, 10% E2E — pas de pyramide inversée
|
|
14
|
+
- [ ] Chaque test est isolé — pas d'ordre d'exécution, pas de state partagé, pas de dépendance
|
|
15
|
+
- [ ] Les tests sont FIRST : Fast, Isolated, Repeatable, Self-validating, Timely
|
|
16
|
+
- [ ] Flaky test detection : > 2% de flaky → quarantaine automatique → fix ou delete dans le sprint
|
|
17
|
+
|
|
18
|
+
## Anti-patterns
|
|
19
|
+
### Tester l'implémentation
|
|
20
|
+
**Ce qu'on voit :** test qui mock `repository.findById()` et vérifie qu'il est appelé avec les bons arguments. Le test sait QUELLES méthodes le code appelle, pas ce que le code produit.
|
|
21
|
+
**Pourquoi c'est dangereux :** le test est couplé à l'implémentation. Tu refactores en inline le `findById()` → le test casse alors que le comportement est identique. Ces tests ne donnent PAS la confiance pour refactorer — ils empêchent le refactoring.
|
|
22
|
+
**Faire plutôt :** tester le comportement observable. Input → output. "Given un utilisateur avec id 123, when GET /users/123, then retourne {name, email}". Peu importe si le handler appelle un service ou un repository.
|
|
23
|
+
|
|
24
|
+
### Mock absolument tout
|
|
25
|
+
**Ce qu'on voit :** DB mockée, Redis mocké, filesystem mocké, horloge mockée. Le test unitaire passe, le test d'intégration n'existe pas. Premier déploiement → explosion.
|
|
26
|
+
**Pourquoi c'est dangereux :** les mocks mentent. Un mock Redis ne vérifie pas le format de la clé. Un mock DB ne vérifie pas la contrainte UNIQUE. Le test passe mais le code est cassé en condition réelle. C'est la fausse confiance — pire que pas de confiance.
|
|
27
|
+
**Faire plutôt :** mocker les frontières lentes/non-déterministes (appels HTTP externes, emails). Tester avec une vraie DB en intégration (testcontainers, pg_tmp). La DB est le composant le plus important à tester réellement.
|
|
28
|
+
|
|
29
|
+
### Test flaky toléré
|
|
30
|
+
**Ce qu'on voit :** "ce test faille parfois, relance le job". Le pipeline passe au 3ème rerun. Le flaky rate est de 5% mais personne ne le mesure.
|
|
31
|
+
**Pourquoi c'est dangereux :** chaque test flaky érode la confiance dans le pipeline. Quand le rouge ne veut plus dire "bug", les vrais bugs passent. L'équipe développe un réflexe "rerun" au lieu de "investigate". C'est la mort lente de la CI.
|
|
32
|
+
**Faire plutôt :** quarantaine automatique. Flaky > 2% → test déplacé dans une suite séparée. Le pipeline principal reste strict (vert = ok, rouge = bug). La quarantaine est prioritaire — chaque test est fixé, réécrit, ou supprimé.
|
|
33
|
+
|
|
34
|
+
## Patterns
|
|
35
|
+
### Test pyramid
|
|
36
|
+
**Quand :** toute suite de tests.
|
|
37
|
+
**Comment :** base large de tests unitaires (rapides, isolés, nombreux). Milieu de tests d'intégration (DB réelle, API réelle). Sommet étroit de tests E2E (parcours critiques). Si la pyramide s'inverse (beaucoup d'E2E, peu d'unitaires), le feedback est lent et le debugging est coûteux.
|
|
38
|
+
|
|
39
|
+
### FIRST principles
|
|
40
|
+
**Quand :** écrire chaque test.
|
|
41
|
+
**Comment :** Fast (< 5ms unitaire, < 100ms intégration), Isolated (pas d'ordre), Repeatable (même résultat à chaque run), Self-validating (assertion, pas de log à vérifier manuellement), Timely (écrit AVANT le code — RED first).
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: tracing
|
|
3
|
+
description: "Tracing — OpenTelemetry, distributed traces, spans, sampling, context propagation. À charger quand on met en place du tracing distribué."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Tracing
|
|
7
|
+
|
|
8
|
+
**Principe premier :** Le tracing n'est pas "du monitoring avec plus de détails" — c'est le seul outil qui te permet de voir une requête traverser 5 services et identifier lequel a pris 90% du temps. Sans tracing, chaque service est une boîte noire. Avec tracing, tu as un diagramme de séquence généré automatiquement. OpenTelemetry est le standard — ne pas utiliser de solution propriétaire.
|
|
9
|
+
|
|
10
|
+
## Checklist
|
|
11
|
+
- [ ] OpenTelemetry SDK configuré dans chaque service — pas de vendor lock-in
|
|
12
|
+
- [ ] Chaque requête entrante génère un span racine avec trace ID unique
|
|
13
|
+
- [ ] Les appels sortants (HTTP, DB, Redis, queue) créent des spans enfants
|
|
14
|
+
- [ ] Le contexte de trace est propagé automatiquement (W3C Trace Context headers)
|
|
15
|
+
- [ ] Sampling configuré : 100% en dev/staging, sampling adaptatif en prod
|
|
16
|
+
- [ ] Les spans contiennent les attributs clés : service, endpoint, userId, status code
|
|
17
|
+
|
|
18
|
+
## Anti-patterns
|
|
19
|
+
### Tracing = logs améliorés
|
|
20
|
+
**Ce qu'on voit :** des spans manuelles `span.setAttribute("message", "processing order")` — comme des logs déguisés.
|
|
21
|
+
**Pourquoi c'est dangereux :** le tracing n'est pas du logging. Son pouvoir vient de l'automatisme : les spans sont créées automatiquement par l'instrumentation, pas manuellement par le dev. Des spans manuelles = du bruit.
|
|
22
|
+
**Faire plutôt :** laisser l'auto-instrumentation créer les spans (HTTP, DB, gRPC). Ajouter manuellement UNIQUEMENT les spans qui représentent des étapes métier importantes (OrderProcessing, PaymentValidation).
|
|
23
|
+
|
|
24
|
+
### Pas de sampling
|
|
25
|
+
**Ce qu'on voit :** 100% des traces en production. 10 millions de spans/heure. Coût du stockage x10.
|
|
26
|
+
**Pourquoi c'est dangereux :** coût et volume. La plupart des traces normales n'apportent rien. Seules les traces lentes et les traces avec erreurs sont utiles en prod.
|
|
27
|
+
**Faire plutôt :** sampling adaptatif : 100% des traces avec erreur ou > P95. 10% des traces normales. Assez pour voir les patterns, pas assez pour exploser le budget.
|
|
28
|
+
|
|
29
|
+
## Patterns
|
|
30
|
+
### OpenTelemetry auto-instrumentation
|
|
31
|
+
**Quand :** tout service en production.
|
|
32
|
+
**Comment :** importer le SDK OTel. Auto-instrumentation pour HTTP, DB, gRPC, queues. Zéro code pour les spans de base. Export vers Jaeger/Tempo/Honeycomb. Standard ouvert — change de backend sans changer le code.
|
|
33
|
+
|
|
34
|
+
### Span attributes
|
|
35
|
+
**Quand :** chaque span.
|
|
36
|
+
**Comment :** `service.name`, `http.method`, `http.status_code`, `db.system`, `user.id` (pas de PII). Assez pour filtrer et grouper, pas assez pour identifier une personne.
|