11.03 — Refus explicites#

Synthèse des refus dispersés dans le Holy Book.

Tableau récapitulatif#

RefusRaisonRéférence
async/awaitSelenium synchrone, Requests synchrone ; lisibilité ; aucun intérêt d’introduire une event-loopHoly Book
Plugin pytestIndépendance, fidélité ISTQBREADME Ocarina
DSL textuel (Robot, Gherkin)Pas de couche de traductionHoly Book
Programmation réactiveStatic scenarios, cache in-memory suffitHoly 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é actifsFonctionnel et statique uniquement, jamais d’attaquesCLAUDE.md ai-example

1. Refus d’async/await#

Citation centrale :

Ocarina ne supporte pas async/await et ne le fera jamais.

ArgumentRé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 pytestStandalone runner
Vocabulaire pytest (function, fixture, parametrize)Vocabulaire ISTQB (test, suite, campaign, cycle)
Lifecycle dépend de pytestLifecycle propre, contrôlable
Compatibility avec autres plugins pytestPas de surface API à maintenir
Discoverable via pytest --collectpython -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 textuelDSL 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 / partielType 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 subscriptionsScénarios déclaratifs lisibles
Debugging difficile (event flow)Debugging trivial (sequential calls)
Concurrency hazards subtilsthreading.Lock simple
Dependencies sur RxPY ou similaireAucune 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, # noqa to silence a rule, time.sleep to mask a race, driver.implicitly_wait to 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: ElementClickInterceptedException had a clean polling fix; the JS click hid the problem.

HackPourquoi c’est non
driver.execute_script("...click()") pour bypass hit-testingCache un défaut UI réel ; un utilisateur humain n’aurait pas pu cliquer
# noqa sans justificationCache une vraie violation de style/sécurité
time.sleep(N) pour masquer une race conditionConneries de « timings mystérieux »
driver.implicitly_wait(N) patché hors frameworkDé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 cacheUn 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”.

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 :

RefusSimplification
Pas d’asyncCode synchrone lisible
Pas de plugin pytestPas de pytest API incompréhensible à apprendre
Pas de DSL textuelPas de parser à maintenir
Pas de réactivitéCache simple suffit
Pas de hacksCode expressif
Pas de contributions « stylées »Direction cohérente
Pas de tests sécurité actifsRespect 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 peine

Si 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é.