Il était 23h43 un jeudi et je fixais 340 lignes de code React que GPT-4 avait généré avec une confiance totale. Propre. Bien commenté. Complètement cassé en production. Le hook personnalisé gérait l'état d'une manière qui causait des boucles de re-render silencieuses, le genre qui ne lance pas d'erreurs — elles tuent juste tranquillement votre performance jusqu'à ce qu'un client vous appelle vendredi matin en demandant pourquoi leur page de paiement met neuf secondes à charger.
Cette nuit m'a enseigné plus sur l'ingénierie de prompt que n'importe quel tutoriel YouTube ou thread Twitter ne l'aurait jamais fait. Et j'ai eu pas mal de ces nuits depuis.
Je construis sur le web depuis neuf ans. Chez Seahawk Media, nous avons déployé bien plus de 12 000 sites — WordPress, builds headless, apps React sur mesure, magasins WooCommerce traitant des volumes de transactions importants. Les assistants de codage IA ont intégré mon workflow correctement vers début 2023, et j'ai oscillé entre penser qu'ils sont miraculeux et avoir envie de jeter mon laptop dans la Tamise.Seahawk Media we've shipped well over 12,000 sites — WordPress, headless builds, bespoke React apps, WooCommerce stores handling serious transaction volume. AI coding assistants entered my workflow properly around early 2023, and I've swung between thinking they're miraculous and wanting to throw my laptop into the Thames.
Voici ce que j'ai réellement appris. À la dure.
---
Le modèle ne connaît pas votre base de code. Vous devez la lui expliquer.
Cela semble évident. Ce ne l'est pas, pas dans la pratique.
La plus grande erreur que je vois les développeurs commettre — moi-même inclus pendant les six premiers mois — c'est de traiter un LLM comme un ingénieur senior qui aurait déjà lu tout votre code. Vous demandez « écrire une fonction pour gérer l'authentification utilisateur » et il écrit quelque chose de techniquement correct en vide. Mais votre projet utilise Supabase, pas Firebase. Vos tokens vivent dans des cookies httpOnly, pas localStorage. Votre format d'erreur est { status, message, data }, pas celui par défaut du modèle.{ status, message, data }, not whatever the model defaulted to.
Le modèle n'a pas tort. Il ne vous connaît simplement pas.
Donnez-lui un préambule de projet, chaque fois
Je commence maintenant chaque session de codage significative avec ce que j'appelle un « bloc de contexte ». Cela prend environ 90 secondes à écrire. Cela ressemble à quelque chose comme :
- Stack: Next.js 14 (App Router), TypeScript, Supabase, Tailwind CSS 3.4
- State: Zustand, pas de Redux nulle part
- Auth: Supabase Auth avec cookies httpOnly via middleware
- Error shape: { success: boolean, error?: string, data?: unknown }
{ success: boolean, error?: string, data?: unknown } - Convention de style : utilitaire d'abord, pas de fichiers CSS personnalisés sauf si absolument nécessaire
Collez ça avant toute demande non triviale. Je le fais dans Cursor en gardant un fichier _context.md à la racine du projet. Deux coups de clavier pour coller. La qualité de la sortie augmente sensiblement — moins de suppositions, moins de choses à jeter.Cursor by keeping a _context.md file in the project root. Two keystrokes to paste. The output quality jumps noticeably — fewer assumptions, fewer things I have to rip out.
---
La Spécificité, C'est Tout le Jeu
En 2022, avant d'utiliser massivement l'IA, un client m'a remis un brief qui était littéralement deux phrases : « Construis-nous un système de réservation. Fais-le bien. » On a passé trois semaines à discuter de la portée. Cette expérience m'a marqué et elle façonne directement la façon dont j'écris les prompts maintenant.
Prompt vague → code vague. À chaque fois.
« Écris une fonction qui récupère les commandes » te donnera quelque chose. « Écris une fonction TypeScript async appelée fetchOrdersByUser qui accepte un userId: string, interroge la table orders dans Supabase où user_id correspond et status n'est pas cancelled, ordonne les résultats par created_at décroissant, et retourne Order[] ou lève une erreur typée » te donnera quelque chose que tu peux vraiment déployer.fetchOrdersByUser that accepts a userId: string, queries the orders table in Supabase where user_id matches and status is not cancelled, orders results by created_at descending, and returns Order[] or throws a typed error" will get you something you can actually ship.
La différence n'est pas la capacité du modèle. C'est la spécificité du prompt.
Quoi Inclure dans un Code Prompt
- Nom et signature de la fonction — ne laisse pas le modèle inventer les conventions de nommage — don't let the model invent naming conventions
- Types d'entrée et types de sortie — génériques TypeScript si pertinent — TypeScript generics if relevant
- La source de données — quelle table, quel endpoint API, quelle couche de cache — which table, which API endpoint, which cache layer
- Les cas limites que vous connaissez déjà — « gérer le cas où le tableau est vide » — "handle the case where the array is empty"
- Ce qu'il NE FAUT PAS faire — « n'utilisez pas useEffect pour cela, utilisez une server action » — "don't use useEffect for this, use a server action"
Ce dernier point est plus important qu'on ne le croit. Dire au modèle ce qu'il faut éviter vous fait gagner énormément de temps. J'ai commencé à tenir une petite note « anti-patterns » par projet — des choses comme « pas de client components sauf si l'interaction utilisateur l'exige » — et j'inclus les lignes pertinentes dans les prompts de ce projet.
---
Chaînez vos prompts. Ne demandez pas tout à la fois.
Seahawk avait un client fintech fin 2023 — je ne dirai pas qui — où nous construisions un flux KYC multi-étapes. Du truc complexe. Upload de documents, intégration de vérification de vivacité, polling de statut. J'ai fait l'erreur au début de demander à GPT-4 de « construire le composant complet du flux KYC ». Ça a produit 600 lignes de code qui avait l'air héroïque mais était en réalité un fouillis. Logique enchevêtrée, absence de séparation des responsabilités, aucune réelle distinction entre l'état UI et la logique métier.
Donc j'ai tout supprimé et j'ai recommencé avec une chaîne.
Premier prompt : « Concevez la machine d'état pour un flux KYC à 4 étapes. Étapes : identité, upload de document, vivacité, examen. Donnez-moi juste le type d'état et les transitions, pas d'UI. »"Design the state machine for a 4-step KYC flow. Steps: identity, document upload, liveness, review. Give me the state type and transitions only, no UI."
Deuxième prompt : « Étant donné cette machine d'état [coller], écris le store Zustand. »"Given this state machine [paste], write the Zustand store."
Troisième prompt : « Étant donné ce store [coller], écris le composant StepIdentity. Juste cette étape. »"Given this store [paste], write the StepIdentity component. Just this step."
Le résultat de l'approche chaînée était utilisable. Pas parfait — j'ai quand même réécrit environ 30 % — mais utilisable. L'approche monolithique ne m'a rien donné.
Les propres directives d'Anthropic sur les prompts parlent de diviser les tâches complexes en sous-tâches, et honnêtement, cela s'aligne exactement avec ce que j'ai découvert par essais et erreurs. Divise le problème avant de diviser ta base de code. talks about breaking complex tasks into subtasks, and honestly, this aligns exactly with what I found through trial and error. Break the problem down before you break your codebase.
---
Fais-le S'argumenter Contre Lui-même
Celle-ci, je l'ai découverte complètement par hasard. Je relisais une fonction utilitaire générée et au lieu de simplement l'exécuter, j'ai ajouté un prompt de suivi : « Quels sont les bugs potentiels ou les cas limites dans le code que tu viens d'écrire ? »"What are the potential bugs or edge cases in the code you just wrote?"
Le modèle a trouvé trois problèmes qu'il n'avait pas pris en compte. L'un d'eux était un vrai problème — une condition de concurrence dans une boucle asynchrone qui aurait été un cauchemar à déboguer en production.
Maintenant je fais ça régulièrement. J'écris le code, puis je lui demande de critiquer le code. Ensuite je lui demande de corriger la critique. Ça semble légèrement absurde — demander au modèle de relire son propre travail — mais cela met constamment au jour des choses que j'aurais repérées seulement après une session de débogage pénible.
Tu peux aller plus loin. Après avoir obtenu une fonction fonctionnelle, essaie : « Réécris ceci en mettant l'accent sur la performance » ou « Comment cela se comporterait-il sous une forte concurrence ? » Les réponses ne sont pas toujours applicables, mais environ 40 % du temps elles mettent au jour quelque chose qui vaut la peine d'être traité."Rewrite this with a focus on performance" or "How would this behave under high concurrency?" The answers aren't always applicable, but about 40% of the time they surface something worth acting on.
---
Le cadre « Rôle + Contrainte »
Il y a un schéma de prompt que j'utilise constamment maintenant et que j'aurais aimé découvrir en première année. Il va comme suit : « Tu es un [type d'ingénieur spécifique]. Ta contrainte est [règle stricte]. Maintenant [tâche]. »"You are a [specific type of engineer]. Your constraint is [hard rule]. Now [task]."
Exemple : « Tu es un ingénieur backend qui se soucie profondément de l'efficacité des requêtes de base de données. Ta contrainte est que tu ne peux pas récupérer plus que nécessaire pour ce rendu — pas de sur-récupération. Écris une requête Supabase pour le tableau de bord d'administration qui retourne le nombre de commandes, le revenu total et les cinq commandes les plus récentes. »"You are a backend engineer who cares deeply about database query efficiency. Your constraint is that you cannot fetch more than what's needed for this render — no over-fetching. Write a Supabase query for the admin dashboard that returns order count, total revenue, and the five most recent orders."
Ce cadrage fait deux choses. Il aligne la « persona » du modèle avec ce dont j'ai réellement besoin. Et la contrainte agit comme garde-fou — quelque chose que le modèle vérifie explicitement contre lui-même pendant sa génération.
Les meilleures pratiques de prompting d'OpenAI décrivent une idée similaire autour de donner au modèle une persona avec des instructions explicites. Ça vaut le coup de lire si tu ne l'as pas fait, mais je dirais que la partie contrainte est sous-estimée dans leur documentation. describe a similar idea around giving the model a persona with explicit instructions. Worth reading if you haven't, though I'd say the constraint piece is underemphasised in their docs.
Compare le résultat de ce prompt encadré à « écris une requête Supabase pour le tableau de bord d'administration ». C'est le jour et la nuit. Franchement.
---
Quand arrêter de faire des prompts et juste écrire le code
C'est la partie que personne ne veut dire à haute voix.
Les outils de codage IA excèlent à : le boilerplate, les opérations CRUD, les fonctions utilitaires, écrire des tests pour du code déjà écrit, traduire entre formats (schéma JSON vers type TypeScript, SQL vers requête Supabase, etc.), et les premières versions de choses que vous allez fortement modifier.
Ils sont vraiment mauvais à : comprendre l'architecture réelle de votre app, savoir quel compromis compte pour votre échelle spécifique, écrire n'importe quoi qui touche une interaction stateful délicate sans guidance lourde, et n'importe quoi où le spec est fondamentalement ambigu.
J'ai une règle personnelle maintenant : si j'ai envoyé plus de quatre prompts de suivi en essayant d'obtenir un morceau de code correct, je ferme la conversation et l'écris moi-même. Le coût en temps du prompt debugging peut dépasser le coût en temps de simplement l'écrire, surtout pour n'importe quoi en dessous d'environ 50 lignes.
Le Stack Overflow Developer Survey 2024 a trouvé que 76 % des développeurs utilisent ou planifient d'utiliser des outils IA — mais les mêmes données montraient une confiance relativement faible dans la précision. Cet écart entre l'usage et la confiance est exactement où vit le bon prompt engineering.Stack Overflow Developer Survey 2024 found that 76% of developers are using or planning to use AI tools — but the same data showed relatively low trust in accuracy. That gap between usage and trust is exactly where good prompt engineering lives.
---
Versionnez Vos Prompts Comme Vous Versionnez Votre Code
L'année dernière j'ai commencé à garder un dossier prompts/ dans les projets où l'assistance IA est significative. Fichiers Markdown. Un par zone de feature majeure. Quand un prompt produit une sortie particulièrement bonne, je la sauvegarde. Quand je trouve une meilleure version, je mets à jour le fichier.prompts/ folder in projects where AI assistance is significant. Markdown files. One per major feature area. When a prompt produces particularly good output, I save it. When I find a better version, I update the file.
Ça paraît obsessif. Ça m'a probablement sauvé six heures sur le dernier gros projet — un build WooCommerce headless pour un retailer qui migrait de Shopify. J'ai réutilisé un prompt de requête de produit (avec des edits mineurs) à travers quatre composants différents au lieu de ré-ingéniérer le contexte de zéro à chaque fois.
Git-track ça. Sérieusement. La qualité de prompt est reproductible si vous traitez les prompts comme des artefacts plutôt que comme des inputs jetables. Les prompt templates de LangChain formalisent cette idée dans un contexte de framework, mais vous n'avez besoin d'aucun framework — un dossier de fichiers Markdown suffit pour la plupart des workflows d'agence.LangChain's prompt templates formalise this idea in a framework context, but you don't need any framework — a folder of Markdown files is enough for most agency workflows.
---
FAQ
L'ingénierie des prompts est-elle vraiment une compétence transférable ou juste spécifique à chaque modèle ?
Surtout transférable. Les principes fondamentaux — la spécificité, la contextualisation, le chaînage, les boucles de critique — s'appliquent à GPT-4, Claude 3.5 Sonnet, Gemini, ou ce qui viendra après. La syntaxe varie un peu et certains modèles réagissent mieux à certaines formulations, mais la logique sous-jacente tient bon. J'ai observé que Claude répond bien aux contraintes explicites ; GPT-4 répond bien aux exemples. Des différences mineures, les mêmes fondamentaux.syntax varies a bit and some models respond better to certain framing, but the underlying logic holds. I've found Claude tends to respond well to explicit constraints; GPT-4 responds well to examples. Minor differences, same fundamentals.
Comment gères-tu le code généré par l'IA lors de la révision de code ?
Comme n'importe quel autre code. S'il va en production, il est révisé. Point final. J'ai arrêté de signaler « ce code a été généré par l'IA » dans les PRs chez Seahawk parce que ça devenait une fausse piste — les relecteurs l'examinaient différemment, parfois trop sévèrement, parfois pas assez. Le code se juge sur ses propres mérites. Ce que je signale : tout bloc où la logique n'est pas évidente et où je n'ai pas ajouté de commentaires en ligne expliquant le raisonnement.
Utilises-tu des system prompts ou seulement des chat prompts ?
Les deux. Dans Cursor je m'appuie sur le fichier .cursorrules pour les instructions persistantes au niveau du projet — des choses que je devrais sinon coller à chaque fois. Pour les tâches ponctuelles dans l'interface web de ChatGPT ou Claude, c'est tout dans le chat. L'approche .cursorrules a significativement réduit la répétition et le modèle reste plus cohérent sur une longue session..cursorrules file for persistent project-level instructions — things I'd otherwise paste every time. For one-off tasks in the ChatGPT or Claude web UI, it's all in the chat. The .cursorrules approach has meaningfully reduced repetition and the model stays more consistent across a long session.
Honnêtement, qu'en penses-tu : l'IA remplacera-t-elle les développeurs ?
Elle remplace certaines tâches, pas les développeurs. Les appels de jugement — quoi construire, comment l'architecturer, quel compromis convient à la situation réelle du client — tout ça est loin d'être automatisé. Si quelque chose, ce sont les développeurs purement orientés exécution qui sont serrés de près, pas ceux orientés conception ou architecture. Affûte la couche de jugement. C'est la partie défendable.tasks, not developers. The judgment calls — what to build, how to architect it, which trade-off fits this client's actual situation — those are nowhere near automated. If anything, the developers getting squeezed are the ones who were purely execution-oriented, not design or architecture-oriented. Sharpen the judgment layer. That's the defensible bit.
---
Neuf ans à construire des choses sur le web, et la leçon fondamentale ne cesse de se répéter : la qualité de votre output est déterminée par la qualité de vos inputs. C'était vrai quand il s'agissait de briefs clients. C'est vrai maintenant avec les prompts.the quality of your output is determined by the quality of your inputs. That was true when it was client briefs. It's true now with prompts.
Le modèle est un développeur junior rapide, occasionnellement brillant, mais souvent surconfiant. Gérez-le en conséquence.
