11.03 — Refus explicites#
Synthèse des refus dispersés dans le Holy Book.
Tableau récapitulatif#
| Refus | Raison | Référence |
|---|---|---|
async/await | Selenium synchrone, Requests synchrone ; lisibilité ; aucun intérêt d’introduire une event-loop | Holy Book |
| Plugin pytest | Indépendance, fidélité ISTQB | README Ocarina |
| DSL textuel (Robot, Gherkin) | Pas de couche de traduction | Holy Book |
| Programmation réactive | Static scenarios, cache in-memory suffit | Holy Book |
| Tricks et hacks | « Teach the pattern, not the symptom » | CLAUDE.md ai-example |
| Contributions « stylées » | « C’est ma voiture » | Holy Book |
| Tests sécurité actifs | Fonctionnel et statique uniquement, jamais d’attaques | CLAUDE.md ai-example |
1. Refus d’async/await#
Citation centrale :
Ocarina ne supporte pas
async/awaitet ne le fera jamais.
| Argument | Réponse |
|---|---|
| « C’est plus rapide » | Pas pour Selenium (synchrone par nature) |
| « Tout le monde le fait » | Tout le monde le fait souvent mal |
| « Pour les API HTTP » | requests (synchrone) marche très bien |
| « Pour les locks » | threading.Lock + redis.lock suffisent |
| « Pour paralléliser » | ThreadPoolExecutor (cf. ../02-ocarina/05-orchestration/04-test-suite.md) |
2. Refus d’être un plugin pytest#
README d’Ocarina :
Ships its own test runner: Ocarina is NOT a pytest plugin.
| Avec plugin pytest | Standalone runner |
|---|---|
| Vocabulaire pytest (function, fixture, parametrize) | Vocabulaire ISTQB (test, suite, campaign, cycle) |
| Lifecycle dépend de pytest | Lifecycle propre, contrôlable |
| Compatibility avec autres plugins pytest | Pas de surface API à maintenir |
Discoverable via pytest --collect | python -u src/main.py direct |
→ Cf. ../01-philosophy/02-istqb-vs-pytest.md
3. Refus de DSL textuels#
Pas de fichier .robot, .feature, .spec.yml. Tout est Python.
Citation (Holy Book what-is-it) :
Robot Framework a essayé de la contourner avec un DSL (…) leur propre format et leur propre écosystème de plugins. Ainsi, RF impose de-facto ses propres standards : c’est le coût immédiat de sa promesse.
| DSL textuel | DSL Python embedded |
|---|---|
| Couche de traduction (parser, runtime alternatif) | Aucune : c’est juste Python |
Refactoring difficile (chercher dans des .robot) | Refactoring trivial (IDE Python) |
| Type checking impossible / partiel | Type checking complet (mypy strict) |
| Outillage propriétaire (PyCharm RF plugin, RIDE, etc.) | N’importe quel éditeur Python |
→ Cf. ../01-philosophy/01-flip-the-problem.md
4. Refus de la programmation réactive#
Holy Book (chapitre « Premiers jutsus », section « Programmation réactive : NON ») :
Les scénarios de test d’Ocarina sont volontairement statiques. Pourtant, une application web est dynamique et parfois, enregistrer une valeur à la volée pour la passer à une étape suivante est tout à fait légitime.
Ocarina n’y répond pas. Il n’en a pas besoin.
Réponse : cache in-memory + clés réservées (cf. ../07-ocarina-example/08-caches-locks.md)
| Avec réactivité | Sans (cache) |
|---|---|
| Scénarios pleins de streams et de subscriptions | Scénarios déclaratifs lisibles |
| Debugging difficile (event flow) | Debugging trivial (sequential calls) |
| Concurrency hazards subtils | threading.Lock simple |
| Dependencies sur RxPY ou similaire | Aucune dep réactive |
5. Refus des « trucs de geeks »#
CLAUDE.md ocarina-with-ai-example :
No tricks or hacks. JS-clicks to skip hit-testing,
# noqato silence a rule,time.sleepto mask a race,driver.implicitly_waitto patch a timing bug. If a hack is genuinely the only option, document why no clean fix exists and mark it so a reader doesn’t copy the pattern. The JS-click-for-logout incident is the canonical anti-example:ElementClickInterceptedExceptionhad a clean polling fix; the JS click hid the problem.
| Hack | Pourquoi c’est non |
|---|---|
driver.execute_script("...click()") pour bypass hit-testing | Cache un défaut UI réel ; un utilisateur humain n’aurait pas pu cliquer |
# noqa sans justification | Cache une vraie violation de style/sécurité |
time.sleep(N) pour masquer une race condition | Conneries de « timings mystérieux » |
driver.implicitly_wait(N) patché hors framework | Décorrèle de la config CLI --wait-timeout |
delete_all_cookies() pour « reset state » | Un utilisateur ne fait pas ça ; cache un vrai bug de session |
driver.refresh() pour bypass cache | Un utilisateur ne fait pas ça ; cache un vrai bug |
Query-string cache-busters (?_=<ts>) | Idem |
→ Si un hack est vraiment nécessaire : documenter pourquoi.
6. Refus des contributions « stylées »#
Holy Book (chapitre « Premiers retours », section « Incorruptibles ») :
« Transmettre Ocarina, c’est transmettre une voiture dont j’ai fait tout l’entretien moi‑même, pour moi‑même, donc très précautionneusement. En revanche, elle est et restera transmise telle quelle. C’est ma voiture. »
Et :
« Contribuer à un projet open source parce que c’est “stylé” est une vision totalement immature et la tolérance à ce phénomène crée des ravages. »
→ Critère d’acceptation des contributions : alignement avec la direction. Pas « est-ce que ça marche » mais « est-ce que ça respecte la philosophie du projet ? ».
L’auteur cite DHH :
Ma réponse sera complétée d’une citation de David Heinemeier Hansson (DHH) : “Fuck You”.
7. Refus des tests de sécurité actifs/offensifs#
CLAUDE.md ocarina-with-ai-example :
This is a functional test suite. (…) Inside that scope:
- Static analysis is welcome and encouraged.
- Functional tests that exercise security-relevant behaviour through the normal UI/HTTP path (…) are fine.
Forbidden, no exceptions:
- Crafted attack payloads of any kind: SQL injection strings, XSS / HTML / JS payloads, command injection, header/parameter pollution, path traversal, deserialisation payloads.
- Token tampering, signature stripping, cookie forgery, session-fixation attempts, forced-browsing fuzzers.
- Cross-origin POSTs constructed outside the suite, scripted directory enumeration, DOS, rate-floods — anything that escalates from “use the app like a user” to “attack the app like an adversary”.
→ Limite stricte : on utilise l’app comme un utilisateur, on ne l’attaque pas comme un acteur malveillant.
Si on veut tester activement : c’est un autre projet (Burp, ZAP, sqlmap, nouveau contrat et périmètre dédiés).
Pourquoi#
Chaque refus recentre le projet :
| Refus | Simplification |
|---|---|
Pas d’async | Code synchrone lisible |
| Pas de plugin pytest | Pas de pytest API incompréhensible à apprendre |
| Pas de DSL textuel | Pas de parser à maintenir |
| Pas de réactivité | Cache simple suffit |
| Pas de hacks | Code expressif |
| Pas de contributions « stylées » | Direction cohérente |
| Pas de tests sécurité actifs | Respect du périmètre fonctionnel |
→ Le non est aussi du design. Cf. Steve Jobs : « Innovation is saying no to 1,000 things. »
Refus de l’expansion sans bénéfice#
En réalité, aucun de ces refus n’est dogmatique.
Chacun est justifié par un compromis explicite :
Avantage hypothétique : X
Coût opératoire : Y
Verdict : pas la peineSi demain un nouveau cas d’usage justifie de reconsidérer un refus, l’auteur le fera.
Mais le fardeau de la preuve est sur celui qui propose, pas sur l’auteur.
C’est l’incarnation pratique de la souveraineté.
