Lancer tout son projet en local : une mauvaise habitude ?
Le rituel qu'on ne questionne plus
Tout les matins quand on arrive on lance notre terminal, et la première commande qu'on lance c'est podman up ou docker-compose up pour lancer notre BDD ou autres services externes pour ne pas le faire plutard. Et une fois tout up on est prêt à lancer notre back ou notre front quand on le souhaite pour vérifier que ce qu'on vient d'implementer fonctionne bien.
C'est devenue notre réflexe, on se pose plus la question si c'est nécessaire ou pas. On le fait car on en a pris l'habitude, c'est comme ça qu'on fait ici, sinon comment on fait pour tester ce qu'on vient d'implementer ?
Mais est-ce que ça nous aide ? Est-ce que lancer ce podman up ou ce docker-compose up nous dérangerai pas plus qu'il nous aide ? C'est quoi les problèmes que nous cache ce docker-compose up ?
Le problème : c'est un piège psychologique qui atrophie le filet de sécurité
Le piège individuel
Quand vous lancez toute votre stack en local et que vous faites un test manuel pour vérifier que tout fonctionne, vous voyez que ça marche. Vous avez vu le résultat, vous savez que c'est bon. Et c'est là que le piège se referme.
Parce que maintenant vous devez écrire des tests automatiques. Mais vous savez déjà que ça marche. Vous l'avez vu. Donc votre test, vous l'écrivez comme une formalité. Vous testez le cas passant, peut-être un ou deux cas d'erreur évidents, et vous passez à autre chose. Votre coverage est bon, votre PR peut passer.
C'est du biais de confirmation pur. Vous avez confirmé visuellement que ça fonctionne, donc vous n'allez jamais écrire le test qui challenge vraiment votre code. Le test qui pose la question "et si le client applique un code promo sur un produit déjà en solde ?", "et si l'utilisateur annule entre le paiement et la confirmation ?", "et si le panier contient un produit qui vient de passer en rupture de stock ?". Ces cas là, vous ne les testez pas parce que vous ne les avez pas rencontrés en local. Et comme vous ne les avez pas rencontrés, ils n'existent pas dans votre tête.
La norme d'équipe
Et le pire c'est que ça devient collectif. "Ici on lance en local avant de push." C'est implicite, personne ne le remet en question. C'est comme ça qu'on fait. Et si personne ne remet en question le processus, personne ne remet en question la qualité des tests non plus. L'équipe entière tourne avec des tests qui ne protègent de rien, mais tout le monde est rassuré parce que "j'ai testé en local, ça marche".
Le cercle vicieux
Ce que le local vous pousse à écrire, c'est des tests d'implémentation. Vous testez le "comment" : est-ce que telle fonction est appelée avec tel argument, est-ce que tel mock retourne bien telle valeur. Pas le "quoi" : est-ce que le comportement attendu par l'utilisateur est respecté.
Et ces tests d'implémentation sont fragiles. Vous refactorez une partie du code, vous changez un nom de méthode, vous réorganisez un module. Les tests cassent. Pas parce que le comportement a changé, mais parce que l'implémentation a bougé. Donc vous relancez en local pour vérifier que tout marche encore, vous réécrivez les tests pour qu'ils repassent, et le cycle recommence.
Tests fragiles → corvée → retour au local → tests encore plus fragiles. Le local reste roi parce que c'est le seul truc en qui vous avez confiance. Et c'est exactement le problème.
Le coût caché
Et tout ça a un coût qu'on ne mesure jamais. Le podman compose qui casse un matin parce qu'une image a changé de version. Le seed de votre BDD locale qui n'est plus à jour depuis trois semaines. Le nouveau qui arrive dans l'équipe et qui met deux jours à tout faire tourner sur sa machine. Les "moi ça marche chez moi" quand quelqu'un a un état différent du vôtre. C'est du temps invisible, dilué sur les semaines, jamais comptabilisé. Mais c'est du temps qui pourrait être investi ailleurs.
C'est un pattern récurrent dans notre métier. On rajoute des pansements plutôt que de s'attaquer au vrai problème, parce que c'est plus facile. Comme on avait pu le voir dans l'article sur les git hooks, c'était pareil : on vérifie avant de push pour pas casser la CI, au lieu de rendre la CI fiable. Le local c'est la même chose : on vérifie à la main pour être sûr que ça marche, au lieu de construire un filet qui nous donne cette confiance. Dans les deux cas, c'est un confort individuel qui masque un manque de fiabilisation.
Et c'est là qu'il faut poser la vraie question. La solution c'est pas "écrivez plus de tests". C'est "écrivez les bons tests". Des tests qui testent le quoi, pas le comment. Des tests qui vous protègent vraiment au lieu de vous donner l'illusion d'être protégé. C'est de ça qu'on parle dans la suite.
L'alternative : investir dans le filet de sécurité plutôt que dans le setup local
Chaque fois que vous lancez en local, c'est pour répondre à une question. "Est-ce que mon endpoint marche ?", "Est-ce que ma migration passe ?", "Est-ce que mes services communiquent bien ?". Le problème c'est pas la question. C'est que la réponse meurt avec votre session. Demain, personne ne saura que vous avez vérifié. Et dans deux semaines quand quelqu'un touche au même code, il devra revérifier à la main lui aussi.
L'alternative c'est de transformer chaque question en un test qui reste. Un test qui répond à la question aujourd'hui, demain, et à chaque CI qui passe.
Chaque réflexe local a son équivalent automatisable
Ça compile ?
Réflexe local — "Je lance pour voir si ça compile ou si ça crash."
↓ À automatiser avec : le type checking et le linter
Ils font cette vérification en continu. Si votre IDE est bien configuré, vous le savez avant même de sauvegarder.
Mon endpoint marche ?
Réflexe local — "Je lance mon app et je teste mon endpoint dans Postman."
↓ À automatiser avec : un test d'intégration API
Vous montez votre app, vous appelez l'endpoint, vous vérifiez la réponse. Ça prend le même temps que Postman, sauf que ça tourne à chaque push.
Ma migration passe ?
Réflexe local — "Je lance ma BDD locale et je joue ma migration."
↓ À automatiser avec : Testcontainers ou PGlite
Une BDD éphémère, from scratch, applique vos migrations dans l'ordre et vérifie l'état final.
Mes services communiquent ?
Réflexe local — "Je lance tous mes services pour voir s'ils se parlent."
↓ À automatiser avec : le contract testing
Avec Pact, par exemple, chaque service déclare ce qu'il attend et ce qu'il produit. Le contrat est vérifié des deux côtés sans jamais lancer les deux services ensemble.
Mon parcours utilisateur fonctionne ?
Réflexe local — "Je rejoue tout le parcours pour vérifier le comportement."
↓ À automatiser avec : le Behaviour Driven Development et l'example mapping
Vous formalisez le comportement attendu sous plusieurs perspectives, et il devient exécutable comme un test : "En tant que client, quand j'annule après le paiement, alors je suis remboursé sous 48h." C'est un test, pas un scénario dans votre tête.
Et avec d'autres valeurs ?
Réflexe local — "Je teste avec trois ou quatre valeurs choisies à la main."
↓ À automatiser avec : le property-based testing
Au lieu de cas fixes, vous définissez un invariant — "pour tout panier, le total ne peut pas être négatif" — et le framework génère des centaines d'inputs pour le vérifier. Il trouve les cas limites que vous n'avez pas en tête.
Et avec des entrées imprévues ?
Réflexe local — "Je teste trois cas dans Postman."
↓ À automatiser avec : le fuzz testing
Au lieu de choisir vos trois valeurs à la main, vous laissez un framework envoyer des centaines d'inputs aléatoires ou malformés. Il trouvera des crashes que vous n'auriez jamais imaginés.
Mes tests me protègent vraiment ?
Réflexe local — "Mes tests passent, c'est bon."
↓ À automatiser avec : le mutation testing
Il modifie votre code source automatiquement, une ligne à la fois, et vérifie que vos tests détectent le changement. Si votre test passe toujours après qu'on a supprimé un if, votre test ne testait rien.
L'exemple des migrations de BDD
C'est un cas où le réflexe local est le plus fort. "Je lance ma BDD, je joue ma migration, je regarde si ça passe." Sauf que votre BDD locale a un état unique, bancal, accumulé au fil des semaines. Elle ne ressemble ni à la prod, ni à celle de votre collègue.
L'alternative : une BDD éphémère qui part de zéro. Vous appliquez vos migrations dans l'ordre, vous vérifiez l'état final. Vous pouvez aussi tester la transformation de données : vous seedez le "avant", vous appliquez la migration, vous vérifiez le "après". Le test contrôle l'état de départ. Votre BDD locale, non.
La CI comme contrat commun
Le local c'est "ma vérité". La CI c'est "la vérité partagée". Quand vous vérifiez en local, vous vérifiez pour vous. Quand le test passe en CI, il vérifie pour toute l'équipe, sur un environnement propre, reproductible, identique pour tout le monde.
C'est pas une question d'outil. C'est une question de confiance. Aujourd'hui votre confiance repose sur votre machine, votre état, votre session. L'objectif c'est de déplacer cette confiance vers un filet qui appartient à toute l'équipe.
L'ère de l'agentic : le filet de sécurité n'est plus optionnel
Un agent IA peut techniquement lancer des choses en local. Avec les MCP et les outils qu'on lui branche, il peut exécuter des commandes, appeler des endpoints, vérifier un résultat. Mais c'est comme les tests E2E : trop lourd, trop coûteux, et ça ne scale pas. Plus votre projet grossit, plus le contexte nécessaire pour "lancer et vérifier" devient énorme. La boucle de feedback ralentit. L'agent passe plus de temps à attendre et à comprendre l'état du système qu'à coder.
Ce qui marche pour un agent, c'est un feedback rapide et ciblé. Un test unitaire qui tourne en millisecondes et qui dit "vert" ou "rouge". Pas un docker-compose up de 30 secondes suivi d'un curl pour vérifier un endpoint.
Et si vos tests ne testent rien de pertinent, l'agent tourne dans le vide. Il va modifier du code, les tests vont passer, et vous allez merger un truc cassé en prod. Pas parce que l'IA est mauvaise, mais parce que votre filet ne filtre rien.
L'IA force l'investissement
C'est là que ça devient intéressant. Si vous voulez utiliser l'IA efficacement pour coder, vous n'avez plus le choix : votre filet de sécurité doit être solide. C'est plus un nice-to-have, c'est un prérequis. L'IA force mécaniquement l'investissement dans les tests. Pas par conviction, par nécessité.
Le workflow test first
Le flow naturel avec un agent IA c'est : l'IA écrit les tests d'abord, vous vérifiez qu'ils décrivent bien le comportement attendu. Pas l'implémentation, le comportement. "Quand un client annule après paiement, il est remboursé sous 48h." Vous vous assurez que les tests sont liés au quoi, pas au comment. C'est là que votre expertise métier intervient.
Ensuite vous relancez l'IA dans un nouveau contexte pour faire passer les tests. Un contexte frais, sans connaissance de comment les tests ont été écrits. Pour pas qu'elle soit biaisée. Et vous lui demandez de faire passer les tests un par un. Pas la solution parfaite du premier coup, mais un test vert à la fois. L'IA itère, et vous review le résultat.
Dans ce workflow, le local n'existe pas. Le test est la vérification. L'IA est contrainte par la spécification, et la séparation des contextes garantit qu'elle ne triche pas avec ses propres tests.
L'IA comme accélérateur d'adoption
Et le plus beau c'est que l'IA vous aide aussi à écrire les tests eux-mêmes. Le property-based testing c'est dur. Formuler un invariant qui tient la route, trouver les bonnes properties, c'est un exercice mental exigeant. L'IA baisse cette barrière. Elle vous aide à formuler les properties, à trouver les edge cases métier, à structurer vos exemples en Behaviour Driven Development. Elle ne remplace pas ces pratiques, elle les rend accessibles.
Et quand toute l'équipe travaille en test first avec l'IA, les tests deviennent le langage commun. Plus fort que le local ne l'a jamais été.
Les limites honnêtes : le local comme validation finale, pas comme développement
Je ne vais pas vous dire que le local est mort. Ce serait malhonnête.
Storybook couvre vos composants isolés. La visual regression détecte les régressions CSS. Les tests E2E vérifient que votre flow fonctionne de bout en bout. Mais il reste un truc que aucun de ces outils ne peut faire : juger si c'est beau. Si c'est agréable. Si le responsive rend bien sur un écran bizarre. Si l'animation est fluide ou si elle donne mal à la tête.
Le jugement humain sur l'esthétique et l'UX, ça ne s'automatise pas.
Il y a aussi l'accessibilité. Des outils automatisés peuvent détecter un contraste insuffisant, un attribut manquant ou une mauvaise structure HTML. Mais ils ne peuvent pas garantir qu'un parcours est réellement utilisable au clavier, compréhensible avec un lecteur d'écran ou confortable avec un fort niveau de zoom. Là encore, il faut lancer, naviguer et ressentir le parcours comme le ferait un utilisateur.
Ce que le local couvre encore
Vous ne lancez pas en local pour vérifier que votre bouton appelle la bonne API. Ça c'est un test. Vous ne lancez pas pour vérifier que le bon texte s'affiche. Ça aussi c'est un test. Vous lancez uniquement pour le jugement visuel, le feeling et l'accessibilité réelle. Est-ce que ça coule bien ? Est-ce que le spacing est cohérent ? Est-ce que l'interaction est naturelle ? Est-ce que le parcours reste fluide au clavier ou avec un lecteur d'écran ?
C'est du local comme validation, pas comme développement. La nuance est importante. Vous ne développez plus avec le local comme béquille. Vous validez humainement un résultat final, une fois que le filet a déjà confirmé que tout fonctionne.
Le dernier bastion
Et c'est justement le cas où l'IA ne peut pas vous remplacer non plus. Elle ne juge pas l'esthétique. Elle ne sent pas si une animation est trop lente ou si un bouton est trop petit sur mobile. Les tests sont le contrat de supervision de l'IA pour tout ce qui est logique et comportement. Mais pour ce qui relève du jugement humain, c'est vous.
Le local reste le dernier bastion. Et il est réservé à ce que ni les tests ni l'IA ne peuvent couvrir.
Conclusion : le cercle vertueux
Le cercle vicieux on l'a vu : tests fragiles → corvée → retour au local → tests encore plus fragiles. Mais il suffit d'inverser un maillon pour que tout bascule.
Vous écrivez de bons tests, des tests de comportement. Vous n'avez plus besoin de lancer en local pour vérifier. Le temps que vous gagniez, vous le réinvestissez dans le filet. Les tests s'améliorent. La confiance de l'équipe augmente. Et le local disparaît petit à petit de votre quotidien, sans que personne ne le remarque.
Ce qu'on demande ici c'est pas un changement d'outil. C'est un changement de réflexe. Remplacer "je lance pour vérifier" par "j'écris un test pour vérifier". Le geste est différent, le résultat est permanent.
Et le cercle vertueux s'auto-alimente. Plus vous investissez dans le filet, moins vous avez besoin du local, plus vous avez de temps pour investir. C'est pas un effort constant, c'est un effort qui diminue avec le temps.
C'est pas une silver bullet. C'est une approche qui marche quand l'équipe est prête à investir dans son filet. Chaque contexte a ses contraintes.
Mais le filet de sécurité, c'est le seul investissement qui profite à toute l'équipe. Alors la vraie question : pourquoi on a encore besoin de lancer en local ?



Top comments (0)