Il était 23h43 jeudi soir et je regardais 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 provoquait des boucles de re-rendu silencieuses, le genre qui ne lève pas d'erreurs -- qui tue simplement tranquillement votre performance jusqu'à ce qu'un client vous appelle vendredi matin en demandant pourquoi sa page de paiement prend 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 expédié bien plus de 12 000 sites -- WordPress, constructions headless, applications React sur mesure, boutiques WooCommerce gérant des volumes de transactions sérieux. Les assistants de codage IA ont vraiment intégré mon flux de travail autour de début 2023, et j'ai oscillé entre penser qu'ils sont miraculeux et avoir envie de jeter mon ordinateur portable 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 faire -- y compris moi-même pendant les six premiers mois -- c'est traiter un LLM comme un ingénieur senior qui a déjà lu tout votre code. Vous demandez « écris une fonction pour gérer l'authentification utilisateur » et il écrit quelque chose techniquement correct dans le 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 ce que le modèle a utilisé par défaut.Supabase, not Firebase. Your tokens live in httpOnly cookies, not localStorage. Your error format is { 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.4Next.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 cela avant toute demande non triviale. Je le fais dans Cursor en gardant un fichier _context.md à la racine du projet. Deux touches pour coller. La qualité de la sortie s'améliore notablement -- moins d'hypothèses, moins de choses que je dois arracher.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 de fonction et signature -- ne laissez pas le modèle inventer des 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ère 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 que les gens ne le réalisent. Dire au modèle ce qu'il faut éviter fait gagner énormément de temps. J'ai commencé à tenir une petite note « anti-patterns » par projet -- des choses comme « pas de composants client sauf si l'interaction utilisateur l'exige » -- et j'inclus les lignes pertinentes dans mes prompts pour 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 commis l'erreur au départ de demander à GPT-4 de « construire le composant du flux KYC complet ». Il a produit 600 lignes de code héroïque et inutilisable. Logique emmêlée, préoccupations mélangées, pas de véritable séparation 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."
La sortie de l'approche chaînée était utilisable. Pas parfaite -- 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 course dans une boucle async 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 le critiquer. Puis je lui demande de corriger la critique. C'est un peu absurde -- demander au modèle de vérifier son propre travail -- mais ça surfacise consistemment des choses que j'aurais repérées seulement après une session de débogage douloureuse.
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 tient profondément à l'efficacité des requêtes de base de données. Ta contrainte est que tu ne peux récupérer que ce qui est nécessaire pour ce rendu -- pas de sur-récupération. Écris une requête Supabase pour le tableau de bord admin 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 vraiment besoin. Et la contrainte agit comme un garde-fou -- quelque chose que le modèle vérifie explicitement contre lui-même en générant.
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.
L'enquête Stack Overflow Developer Survey 2024 a trouvé que 76% des développeurs utilisent ou envisagent d'utiliser des outils d'IA -- mais les mêmes données ont montré une confiance relativement faible dans la précision. Cet écart entre l'utilisation et la confiance, c'est exactement là où vit la bonne ingénierie des prompts.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 semble obsessionnel. Ça m'a probablement fait économiser six heures sur le dernier gros projet -- une build WooCommerce headless pour un détaillant qui migrait de Shopify. J'ai réutilisé une requête de produit (avec des modifications mineures) dans quatre composants différents au lieu de réingénier le contexte de zéro à chaque fois.
Versionnez-le avec Git. Sérieusement. La qualité des prompts est reproductible si vous les traitez comme des artefacts plutôt que comme des entrées jetables. Les modèles de prompts 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 ?
Largement transférable. Les principes fondamentaux -- spécificité, contextualisation, chaînage, boucles de critique -- s'appliquent à GPT-4, Claude 3.5 Sonnet, Gemini, et whatever comes next. La syntaxe varie un peu et certains modèles répondent mieux à certaines formulations, mais la logique sous-jacente tient bon. J'ai trouvé 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 revu. Point final. J'ai arrêté de signaler « c'était généré par l'IA » dans les PRs chez Seahawk parce que c'est devenu une fausse piste -- les relecteurs l'examinaient différemment, parfois injustement, parfois pas assez. Le code se tient ou tombe sur ses propres mérites. Ce que je signale : toute section où la logique n'est pas évidente et où je n'ai pas ajouté de commentaires inline expliquant le raisonnement.
Utilises-tu des system prompts ou seulement des chat prompts ?
Les deux. Dans Cursor, je me repose sur le fichier .cursorrules pour les instructions persistantes au niveau du projet -- les 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 réduit les répétitions de manière significative 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 ?
Ça remplace certaines tâches, pas les développeurs. Les appels de jugement -- quoi construire, comment l'architecturer, quel compromis convient à la situation réelle de ce client -- ceux-là ne sont nulle part près d'être automatisés. Si quelque chose, ce sont les développeurs qui sont pressurisés qui sont ceux qui étaient purement orientés exécution, pas conception ou architecture. Affûtez la couche de jugement. C'est la part 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.
