prompt-engineering-production-code.html
< BACK El escritorio oscuro de un desarrollador de noche con monitor brillante, notas dispersas y una taza de café fría bajo iluminación editorial de tono oscuro

Ingeniería de prompts para código en producción: lecciones difíciles

Eran las 11:43pm de un jueves y estaba mirando 340 líneas de código React que GPT-4 había generado con total confianza. Limpio. Bien comentado. Completamente roto en producción. El custom hook estaba manejando estado de una manera que causaba bucles silenciosos de re-render, el tipo que no lanza errores — simplemente mata silenciosamente tu rendimiento hasta que un cliente te llama el viernes por la mañana preguntando por qué su página de checkout tarda nueve segundos en cargar.

Esa noche me enseñó más sobre ingeniería de prompts que cualquier tutorial de YouTube o hilo de Twitter jamás lo ha hecho. Y he tenido muchas de esas noches desde entonces.

He estado construyendo en la web durante nueve años. En Seahawk Media hemos desplegado bien más de 12,000 sitios — WordPress, builds headless, apps React personalizadas, tiendas WooCommerce manejando volumen de transacciones serio. Los asistentes de codificación con IA entraron en mi flujo de trabajo apropiadamente alrededor de principios de 2023, y he oscilado entre pensar que son milagrosos y querer lanzar mi laptop al Támesis.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.

Aquí está lo que realmente he aprendido. De la manera difícil.

---

El Modelo No Conoce Tu Codebase. Tienes Que Decirle.

Suena obvio. No lo es, no en la práctica.

El error más grande que veo cometer a los desarrolladores — incluyéndome a mí durante los primeros seis meses — es tratar un LLM como a un ingeniero senior que ya leyó todo tu código. Le preguntas "escribe una función para manejar autenticación de usuarios" y escribe algo técnicamente correcto en el vacío. Pero tu proyecto usa Supabase, no Firebase. Tus tokens viven en cookies httpOnly, no en localStorage. Tu formato de error es { status, message, data }, no lo que el modelo predeterminó.{ status, message, data }, not whatever the model defaulted to.

El modelo no está equivocado. Solo no te conoce.

Dale un Preámbulo del Proyecto, Cada Maldita Vez

Ahora comienzo cada sesión de código significativa con lo que llamo un "bloque de contexto." Toma alrededor de 90 segundos escribirlo. Se ve algo como:

  • Stack: Next.js 14 (App Router), TypeScript, Supabase, Tailwind CSS 3.4
  • State: Zustand, sin Redux en ningún lado
  • Auth: Supabase Auth con cookies httpOnly vía middleware
  • Error shape: { success: boolean, error?: string, data?: unknown }{ success: boolean, error?: string, data?: unknown }
  • Convención de estilos: utility-first, sin archivos CSS personalizados a menos que sea absolutamente necesario

Pega eso antes de cualquier solicitud no trivial. Lo hago en Cursor manteniendo un archivo _context.md en la raíz del proyecto. Dos pulsaciones de tecla para pegar. La calidad del resultado mejora notablemente — menos suposiciones, menos cosas que tengo que descartar.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 especificidad es todo el juego

Allá por 2022, antes de usar IA intensivamente, un cliente me pasó un brief que literalmente tenía dos oraciones: "Construye un sistema de reservas. Hazlo bien." Pasamos tres semanas discutiendo el alcance. Esa experiencia se me quedó grabada, y moldea directamente cómo escribo prompts ahora.

Prompt vago → código vago. Siempre.

"Escribe una función que obtenga órdenes" te dará algo. "Escribe una función asincrónica de TypeScript llamada fetchOrdersByUser que acepte un userId: string, consulte la tabla orders en Supabase donde user_id coincida y status no sea cancelled, ordene resultados por created_at descendente, y retorne Order[] o lance un error tipado" te dará algo que realmente puedes desplegar.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 diferencia no es la capacidad del modelo. Es la especificidad del prompt.

Qué incluir en un prompt de código

  1. Nombre de función y firma — no dejes que el modelo invente convenciones de nombres — don't let the model invent naming conventions
  2. Tipos de entrada y tipos de salida — genéricos de TypeScript si es relevante — TypeScript generics if relevant
  3. La fuente de datos — qué tabla, qué endpoint de API, qué capa de caché — which table, which API endpoint, which cache layer
  4. Casos extremos que ya conoces — "manejar el caso donde el array está vacío" — "handle the case where the array is empty"
  5. Qué NO hacer — "no uses useEffect para esto, usa una server action" — "don't use useEffect for this, use a server action"

Ese último punto importa más de lo que la gente cree. Decirle al modelo qué evitar ahorra un tiempo enorme. He empezado a mantener una pequeña nota de "anti-patrones" por proyecto — cosas como "sin componentes de cliente a menos que la interacción del usuario lo requiera" — e incluyo las líneas relevantes en los prompts de ese proyecto.

---

Encadena Tus Prompts. No Pidas Todo de Una Vez.

Seahawk tuvo un cliente fintech a finales de 2023 — no voy a decir quién — donde estábamos construyendo un flujo KYC de múltiples pasos. Cosas complejas. Carga de documentos, integración de verificación de presencia, polling de estado. Cometí el error al principio de pedirle a GPT-4 que "construya el componente completo del flujo KYC." Produjo 600 líneas de basura de aspecto heroico. Lógica enredada, preocupaciones mezcladas, sin separación real entre estado de UI y lógica de negocio.

Así que lo descarté y comencé de nuevo con una cadena.

Primer prompt: "Diseña la máquina de estados para un flujo KYC de 4 pasos. Pasos: identidad, carga de documento, verificación de presencia, revisión. Dame solo el tipo de estado y las transiciones, sin 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."

Segundo prompt: "Dado este estado máquina [pegar], escribe el store de Zustand.""Given this state machine [paste], write the Zustand store."

Tercer prompt: "Dado este store [pegar], escribe el componente StepIdentity. Solo este paso.""Given this store [paste], write the StepIdentity component. Just this step."

El resultado del enfoque encadenado fue utilizable. No perfecto — igual tuve que reescribir alrededor del 30% — pero utilizable. El enfoque monolítico no me dio nada.

La propia orientación de Anthropic sobre prompting habla de dividir tareas complejas en subtareas, y honestamente, esto se alinea exactamente con lo que encontré por prueba y error. Divide el problema antes de dividir tu base de código. 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.

---

Haz que Discuta Consigo Mismo

Aquí hay uno en el que me topé completamente por accidente. Estaba revisando una función utilidad generada y en lugar de simplemente ejecutarla, añadí un prompt de seguimiento: "¿Cuáles son los posibles bugs o casos límite en el código que acabas de escribir?""What are the potential bugs or edge cases in the code you just wrote?"

El modelo encontró tres problemas que no había considerado. Uno de ellos era un problema genuino — una condición de carrera en un bucle asincrónico que habría sido una pesadilla depurar en producción.

Ahora lo hago rutinariamente. Escribe el código, luego pídele que critique el código. Luego pídele que corrija la crítica. Se siente ligeramente absurdo — pedirle al modelo que revise su propio trabajo — pero consistentemente saca a la luz cosas que solo habría atrapado después de una sesión de depuración dolorosa.

Puedes llevar esto más lejos. Después de obtener una función funcional, intenta: "Reescribe esto enfocándote en rendimiento" o "¿Cómo se comportaría esto bajo alta concurrencia?" Las respuestas no siempre son aplicables, pero aproximadamente el 40% de las veces sacan a la luz algo que vale la pena actuar."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.

---

El marco "Rol + Restricción"

Hay un patrón de prompts que uso constantemente ahora y que desearía haber descubierto en el primer año. Va así: "Eres un [tipo específico de ingeniero]. Tu restricción es [regla inamovible]. Ahora [tarea].""You are a [specific type of engineer]. Your constraint is [hard rule]. Now [task]."

Ejemplo: "Eres un ingeniero backend que se preocupa profundamente por la eficiencia de las consultas de base de datos. Tu restricción es que no puedes traer más de lo necesario para este renderizado — sin sobre-fetching. Escribe una consulta de Supabase para el dashboard administrativo que devuelva el conteo de órdenes, ingresos totales, y las cinco órdenes más recientes.""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."

Ese marco hace dos cosas. Alinea la "personalidad" del modelo con lo que realmente necesito. Y la restricción actúa como un guardrail — algo que el modelo verifica explícitamente contra sí mismo mientras genera.

Las mejores prácticas de prompting de OpenAI describen una idea similar sobre darle al modelo una personalidad con instrucciones explícitas. Vale la pena leer si no lo has hecho, aunque diría que el aspecto de restricción está subestimado en su documentación. 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.

Compara el output de ese prompt enmarcado con "escribe una consulta de Supabase para el dashboard administrativo." Noche y día. De verdad.

---

Cuándo dejar de hacer prompts y simplemente escribir el código

Esta es la parte que nadie quiere decir en voz alta.

Las herramientas de IA para código son brillantes en: boilerplate, operaciones CRUD, funciones utilitarias, escribir tests para código que ya escribiste, traducir entre formatos (esquema JSON a tipo TypeScript, SQL a consulta Supabase, etc.), y primeros borradores de cosas que modificarás mucho.

Son genuinamente malas en: entender la arquitectura real de tu app, saber qué trade-off importa para tu escala específica, escribir cualquier cosa que toque una interacción stateful complicada sin mucha guía, y cualquier cosa donde la especificación es fundamentalmente ambigua.

Tengo una regla personal ahora: si envié más de cuatro prompts de seguimiento intentando que un pedazo de código funcione, cierro el chat y lo escribo yo mismo. El costo de tiempo del prompt debugging puede exceder el costo de tiempo de solo escribirlo, especialmente para cualquier cosa menor a unos 50 líneas.

La Stack Overflow Developer Survey 2024 encontró que el 76% de los desarrolladores están usando o planeando usar herramientas de IA — pero los mismos datos mostraron confianza relativamente baja en la precisión. Esa brecha entre uso y confianza es exactamente dónde vive la buena ingeniería de 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.

---

Versioná Tus Prompts Como Versionás Tu Código

El año pasado comencé a mantener una carpeta prompts/ en proyectos donde la asistencia de IA es significativa. Archivos Markdown. Uno por cada área de feature importante. Cuando un prompt produce output particularmente bueno, lo guardo. Cuando encuentro una versión mejor, actualizo el archivo.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.

Suena obsesivo. Probablemente me ahorró seis horas en el último proyecto grande — un build de WooCommerce headless para un retailer que se mudaba de Shopify. Reuticé un prompt de consulta de producto (con edits menores) en cuatro componentes diferentes en lugar de re-ingenierizar el contexto desde cero cada vez.

Git-trackealo. En serio. La calidad de los prompts es reproducible si tratas los prompts como artefactos en lugar de inputs desechables. Las prompt templates de LangChain formalizan esta idea en un contexto de framework, pero no necesitas ningún framework — una carpeta de archivos Markdown es suficiente para la mayoría de workflows de agencias.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

¿La ingeniería de prompts es realmente una habilidad transferible o solo depende del modelo?

Mayormente transferible. Los principios clave — especificidad, establecimiento de contexto, encadenamiento, ciclos de crítica — aplican en GPT-4, Claude 3.5 Sonnet, Gemini, lo que venga después. La sintaxis varía un poco y algunos modelos responden mejor a ciertos enfoques, pero la lógica subyacente se mantiene. He encontrado que Claude responde bien a restricciones explícitas; GPT-4 responde bien a ejemplos. Diferencias menores, fundamentos iguales.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.

¿Cómo manejas el código generado por IA en la revisión de código?

Igual que cualquier otro código. Si va a producción, se revisa. Punto. He dejado de marcar "esto fue generado por IA" en los PRs de Seahawk porque se convirtió en una distracción — los revisores lo escrutinizaban diferente, a veces injustamente, a veces no lo suficiente. El código se sostiene o cae por sus propios méritos. Lo que sí marco: cualquier sección donde la lógica no es obvia y no he añadido comentarios inline explicando el razonamiento.

¿Usas prompts del sistema o solo prompts de chat?

Ambos. En Cursor me apoyo en el archivo .cursorrules para instrucciones persistentes a nivel de proyecto — cosas que de otro modo pegaría cada vez. Para tareas puntuales en la web UI de ChatGPT o Claude, todo va en el chat. El enfoque de .cursorrules ha reducido significativamente la repetición y el modelo se mantiene más consistente a lo largo de una sesión larga..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.

¿Cuál es tu opinión honesta sobre la IA reemplazando desarrolladores?

Está reemplazando ciertas tareas, no desarrolladores. Los juicios críticos — qué construir, cómo arquitecturarlo, qué trade-off se ajusta a la situación actual de este cliente — esos están lejos de estar automatizados. Si acaso, los desarrolladores que están siendo presionados son los que eran puramente orientados a la ejecución, no a diseño o arquitectura. Fortalece la capa de juicio. Esa es la parte defensible.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.

---

Nueve años construyendo cosas en la web, y la lección fundamental se repite constantemente: la calidad de tu output está determinada por la calidad de tus inputs. Era verdad cuando eran briefings de clientes. Ahora es verdad con los 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.

El modelo es un desarrollador junior rápido, ocasionalmente brillante, frecuentemente demasiado confiado. Manéjalo en consecuencia.

< BACK