Codeando con IA: agentes, skills y buenas prácticas para no morir en el intento

Jorge SaavedraJorge Saavedra
·17 de febrero, 2026·17 min de lectura
iaproductividadbuenas-practicasherramientasclaude-codecursor
Si llegaste hasta acá, probablemente ya usaste alguna herramienta de IA para programar. Quizás fue Copilot, Cursor, Claude Code o ChatGPT con un "hazme un CRUD en Spring Boot". Y seguramente te pasó algo así: la primera vez funcionó de maravilla, pero la segunda vez generó un desastre que tardaste más en arreglar que en escribirlo tú mismo.
Tranquilo, no eres el único. La realidad es que codear con IA es una habilidad, no un botón mágico. Y como toda habilidad, tiene sus técnicas, sus patrones y sus trampas.
En este post te voy a contar lo que he aprendido usándolas en mi día a día. Voy a usar Claude Code como referencia porque es la herramienta que más uso, pero los conceptos aplican a cualquier herramienta: Cursor, Copilot, Windsurf, Aider, lo que sea.

Los tres modos: Ask, Agent y Plan

Lo primero que necesitas entender antes de tocar cualquier herramienta es que no hay un solo "modo" de interactuar con la IA. La mayoría de herramientas modernas te ofrecen al menos tres formas de trabajar, y cada una tiene un propósito muy distinto. Elegir el modo correcto es tan importante como escribir un buen prompt.

Ask: pregunta sin tocar nada

El modo Ask es el más seguro y conservador. La IA solo lee y responde. No edita archivos, no ejecuta comandos, no toca nada de tu proyecto. Es como tener un compañero senior sentado al lado que puedes consultarle cualquier cosa.
Úsalo cuando:
  • Necesitas entender cómo funciona una parte del código que no escribiste
  • Quieres que te explique un error o un stack trace
  • Estás evaluando opciones antes de decidir cómo implementar algo
  • Quieres una opinión sobre tu enfoque sin que modifique nada
bash
# Ejemplo en modo Ask:
> Explicame como funciona el flujo de autenticacion en este proyecto.
  Cual es la ruta que sigue un request desde que llega hasta que se valida el token?

# La IA va a leer tus archivos, seguir el flujo y darte una explicacion.
# Pero NO va a cambiar ni una linea de codigo.
En Claude Code, activas el modo Ask con -p o simplemente cambiando al modo en la interfaz. En Cursor, es el chat normal (sin Composer). En Copilot Chat, es el comportamiento por defecto cuando preguntas algo.

Ask es tu mejor amigo para onboarding

Si acabas de entrar a un proyecto nuevo, usa Ask para entender la arquitectura antes de cambiar cualquier cosa. Pregúntale cosas como "qué patrón de diseño usa este proyecto?", "dónde se manejan los errores?", "cómo se conecta a la base de datos?". Es como tener un tour guiado del codebase.

Agent: manos a la obra

El modo Agent es el que hace cosas. La IA no solo piensa, sino que lee, escribe, ejecuta y verifica. Es como darle las llaves del carro: va a conducir, pero tú le dices a dónde ir.
En este modo, la IA puede:
  • Leer y editar múltiples archivos de tu proyecto
  • Ejecutar comandos en la terminal (./gradlew build, git commit, ./gradlew test)
  • Crear archivos nuevos
  • Correr tests y corregir errores automáticamente
  • Instalar dependencias si las necesita
bash
# Ejemplo en modo Agent:
> Agrega un endpoint GET /api/users/{id} que retorne un usuario por ID.
  Sigue el patron de OrderController. Incluye validacion del ID
  y retorna 404 si no existe.

# La IA va a:
# 1. Leer OrderController.kt para entender el patron
# 2. Leer la entity User.kt
# 3. Crear o editar el UserController.kt
# 4. Registrar la ruta en el controller con @GetMapping
# 5. (Opcionalmente) correr tests para verificar
En Claude Code, el modo Agent es el comportamiento por defecto cuando le das una instrucción. En Cursor, es el "Composer" o "Agent mode". En Copilot, es el "Copilot Edits".

Agent requiere supervision

El modo Agent es poderoso, pero no es "fire and forget". Siempre revisa lo que genera antes de aceptar los cambios. Piénsalo como un junior muy rápido: hace bien el 80%, pero ese 20% restante necesita tu ojo crítico.

Plan: piensa antes de actuar

El modo Plan es el punto intermedio. La IA analiza tu solicitud, explora el codebase y te propone un plan de implementación detallado antes de ejecutar cualquier cambio. Tú lo revisas, lo ajustas si quieres, y recién entonces le das luz verde.
Es ideal para tareas grandes o complejas donde quieres asegurarte de que la IA entendió bien lo que necesitas antes de que empiece a tocar archivos.
bash
# Ejemplo en modo Plan:
> Necesito migrar el sistema de autenticacion de sesiones a JWT.
  Planifica como lo harias paso a paso.

# La IA te va a responder algo como:
#
# Plan de migracion: Sesiones -> JWT
#
# Paso 1: Crear el middleware de JWT
#   - Archivo: src/security/JwtAuthFilter.kt
#   - Dependencia: jjwt (ya esta en build.gradle.kts)
#
# Paso 2: Crear el servicio de tokens
#   - Archivo: src/service/TokenService.kt
#   - Funciones: generateToken(), verifyToken(), refreshToken()
#
# Paso 3: Modificar el login
#   - Archivo: src/controller/AuthController.kt
#   - Cambio: retornar JWT en vez de crear sesion
#
# Paso 4: Actualizar los endpoints protegidos
#   - Archivos: todos los controllers que usan @Secured
#   - Cambio: reemplazar filtro de sesion por JwtAuthFilter
#
# Paso 5: Tests
#   - Actualizar tests existentes
#   - Agregar tests para el flujo de JWT
#
# Quieres que proceda con este plan?
En Claude Code puedes activar el modo Plan escribiendo /plan o pidiéndole explícitamente que planifique antes de actuar. En Cursor, puedes pedirle "planifica esto antes de hacer cambios" en el Composer.

Cuándo usar cada modo

SituaciónModoPor qué
Entender código ajenoAskSolo necesitas respuestas, no cambios
Agregar un endpoint simpleAgentTarea concreta y acotada
Refactorizar un módulo completoPlanNecesitas alinear el enfoque antes de ejecutar
Debuggear un errorAskAgentPrimero entiende, luego corrige
Migrar de una tecnología a otraPlanAgentPlanifica la estrategia, ejecuta por fases
Revisar un PRAskQuieres una opinión, no que modifique el PR
Generar tests para código existenteAgentTarea mecánica y bien definida

Los modos se combinan

En la práctica, vas a ir saltando entre modos. Empiezas en Ask para entender, pasas a Plan para definir la estrategia, y ejecutas con Agent. No te cases con un solo modo. Usa el que tenga más sentido en cada momento.

La anatomía de una herramienta de IA para codear

Ahora que entiendes los modos, vamos un nivel más profundo. Entendamos cómo funcionan estas herramientas por dentro. Casi todas comparten tres conceptos fundamentales:

1. El Agente (Agent)

Un agente es la IA que toma decisiones por ti. No es solo "un modelo que responde preguntas". Un agente puede:
  • Leer archivos de tu proyecto
  • Ejecutar comandos en tu terminal
  • Editar código directamente
  • Buscar en internet
  • Decidir qué herramienta usar en cada paso
Imagina que le dices a Claude Code: "Agrega un endpoint POST /users que valide el email". El agente no solo genera el código. Primero lee tu proyecto para entender tu estructura, busca dónde están los otros controladores, revisa qué ORM usas, y entonces genera el código siguiendo tus patrones.

Agente vs. Autocompletado

No confundas un agente con el autocompletado de Copilot. El autocompletado predice la siguiente línea. Un agente planifica, ejecuta y verifica múltiples pasos de forma autónoma. Son dos mundos distintos.
En Claude Code, cuando lanzas una tarea, el agente decide de forma autónoma qué archivos leer, qué comandos ejecutar y cómo modificar tu código. En Cursor, el "Composer" hace algo similar: analiza tu codebase y propone cambios en múltiples archivos.

El loop de un agente

Un agente funciona como un ciclo: observa, piensa, actúa, repite. Esto es lo que pasa internamente cuando le das una instrucción:
  1. Recibe tu instrucción ("agrega validación de email al endpoint de registro")
  2. Planifica: decide qué archivos necesita leer y qué herramientas usar
  3. Ejecuta: lee archivos, busca patrones, edita código
  4. Evalúa: verifica si el resultado tiene sentido (a veces corre tests)
  5. Itera: si algo falló, ajusta y vuelve al paso 2
Ese loop es lo que hace a un agente fundamentalmente diferente de un chatbot. Un chatbot te da una respuesta y ya. Un agente sigue trabajando hasta completar la tarea. Si un test falla, lee el error, corrige el código y vuelve a correr el test. Solo.

Cómo crear agentes personalizados

Aquí es donde la cosa se pone interesante. No solo puedes usar el agente "default" de tu herramienta, sino que puedes crear tus propios agentes especializados.
En Claude Code, por ejemplo, puedes definir sub-agentes con diferentes roles. Imagina que tienes un proyecto grande y quieres que un agente se enfoque en explorar el codebase mientras otro se encarga de escribir tests:
markdown
# Ejemplo: instrucciones para un agente de exploracion (en CLAUDE.md)

Cuando necesites explorar el codebase para entender la arquitectura:
- Primero lee los archivos de configuracion (build.gradle.kts, application.yml)
- Luego mapea la estructura de carpetas
- Identifica los patrones de diseno usados
- Resume tus hallazgos antes de hacer cambios
En Cursor, puedes crear agentes especializados usando "Custom Instructions" por proyecto. Le defines un rol, restricciones y un flujo de trabajo. Por ejemplo:
markdown
# .cursorrules - Agente de migracion de base de datos

Eres un especialista en migraciones de base de datos.

## Tu flujo de trabajo:
1. Lee la migracion anterior mas reciente en src/migrations/
2. Sigue la convencion de naming: YYYYMMDD_HHMMSS_descripcion.sql
3. Siempre incluye un bloque DOWN (rollback)
4. Nunca hagas DROP TABLE sin confirmacion
5. Valida que los tipos de datos son compatibles con PostgreSQL 15
La idea clave es esta: un agente sin instrucciones claras es como un desarrollador nuevo sin onboarding. Va a hacer algo, pero probablemente no lo que necesitas. Mientras más contexto le des de su rol y restricciones, mejor resultado vas a obtener.

Paralelización de agentes

Una de las capacidades más poderosas (y menos conocidas) es la posibilidad de correr múltiples agentes en paralelo. Esto es particularmente útil cuando tienes tareas independientes que no dependen entre si.
Piénsalo así: si necesitas agregar tests a 5 servicios distintos, no tiene sentido hacerlo uno por uno. Puedes lanzar 5 agentes en paralelo, cada uno trabajando en un servicio diferente.
bash
# En Claude Code, puedes pedirle que lance sub-agentes en paralelo:
> Necesito que hagas estas 3 tareas en paralelo:
  1. Agrega tests unitarios para UserService
  2. Agrega tests unitarios para OrderService
  3. Agrega tests unitarios para ProductService
  Cada servicio es independiente. Usa el mismo patron de tests
  que ya tenemos en src/test/kotlin/services/PaymentServiceTest.kt
El agente principal actúa como un coordinador: divide el trabajo, lanza sub-agentes para cada tarea, y luego consolida los resultados. Esto puede reducir drásticamente el tiempo de tareas repetitivas.
En Cursor, la paralelización ocurre de forma más implícita. Cuando le das una tarea que involucra múltiples archivos, el Composer puede procesar varios archivos simultáneamente. Pero puedes guiarlo para que sea más explícito:
bash
# En Cursor Composer:
> Necesito actualizar todos los controladores para usar el nuevo middleware de auth.
  Los controladores son independientes entre si:
  - src/controller/UserController.kt
  - src/controller/OrderController.kt
  - src/controller/ProductController.kt
  Aplica el mismo cambio en todos: agregar JwtAuthFilter a la cadena de seguridad para cada ruta.

Cuidado con las dependencias

Solo paraleliza tareas que sean realmente independientes. Si el Servicio B depende del Servicio A, no los proceses en paralelo. El agente puede terminar con conflictos o imports rotos. Regla simple: si un archivo necesita leer el resultado de otro agente, va secuencial.
Un patrón avanzado es usar la paralelización para explorar y ejecutar al mismo tiempo. Por ejemplo:
bash
# Patron "explorador + ejecutor":
> Haz dos cosas en paralelo:
  1. Explora el codebase y hazme un resumen de como funciona
     el sistema de autenticacion actual (archivos involucrados,
     flujo del token, donde se valida)
  2. Mientras tanto, agrega tests para el endpoint GET /api/users
     que ya existe en UserController.kt

# El agente explorador te da contexto mientras el ejecutor avanza
# con trabajo que no depende de esa exploracion.
La paralelización no es exclusiva de herramientas específicas. El concepto es el mismo en todas: identifica tareas independientes, lanzalas al mismo tiempo y combina resultados. Si tu herramienta no soporta sub-agentes nativos, puedes simular el efecto abriendo dos ventanas del chat y trabajando en tareas diferentes en cada una.

2. Las Herramientas (Tools)

Las herramientas son las acciones concretas que el agente puede ejecutar. Piensa en ellas como los brazos y piernas del agente. Sin herramientas, la IA solo puede hablar. Con herramientas, puede hacer cosas.
Ejemplos típicos de herramientas:
HerramientaQué haceEjemplo
ReadLee un archivoLeer src/controller/UserController.kt
EditModifica un archivo existenteAgregar una validación en una función
BashEjecuta un comando en terminal./gradlew test
GrepBusca texto en el codebaseEncontrar todas las rutas que usan /api/v1
WriteCrea un archivo nuevoCrear un nuevo componente React
Esto es universal. En Cursor se llaman "tools" también. En Copilot Workspace son "actions". El nombre cambia, el concepto es el mismo: darle manos a la IA.

3. Las Skills (Habilidades)

Las skills son flujos predefinidos que encadenan herramientas para resolver tareas comunes. En vez de que el agente improvise cada vez, una skill le dice: "para esta tarea, sigue estos pasos".
Piénsalo así: si las herramientas son los verbos (leer, escribir, ejecutar), las skills son las oraciones completas ("lee el diff, analiza los cambios, genera un mensaje de commit y ejecuta el commit").

Skills integradas: las que vienen de fábrica

Cada herramienta trae skills listas para usar. En Claude Code, se invocan con / (slash commands):
SkillQué haceCuándo usarla
/commitAnaliza tu diff, genera mensaje de commit y ejecuta el commitCuando terminaste un cambio y quieres commitear rápido
/review-prRevisa un PR completo: código, tests, posibles bugsAntes de hacer merge, como un code review automatizado
/simplifyRevisa el código cambiado y busca oportunidades de simplificaciónDespués de un refactor, para asegurarte de no sobrecomplicar
Veamos /commit en detalle. Cuando lo ejecutas, internamente pasa esto:
  1. Ejecuta git status y git diff para ver tus cambios
  2. Lee los commits recientes para seguir el estilo de mensajes del repo
  3. Analiza si es un fix, feat, refactor, docs, etc.
  4. Genera un mensaje descriptivo enfocado en el "por que", no el "que"
  5. Ejecuta git add de los archivos relevantes y git commit
  6. Verifica que el commit fue exitoso con otro git status
Todo eso pasa con un solo comando. Sin que tengas que pensar en el formato del mensaje, ni en si te olvidaste de agregar algún archivo al staging.

Skills personalizadas: crea las tuyas

Aquí es donde las skills se vuelven realmente poderosas. Puedes crear tus propias skills adaptadas a tu flujo de trabajo. En Claude Code, una skill custom es básicamente un archivo Markdown con instrucciones que se ejecutan cuando invocas un slash command.
Imagina que en tu equipo siempre siguen el mismo flujo al crear un nuevo endpoint: crear el DTO, el controller, el servicio, el repositorio y los tests. En vez de explicar eso cada vez, creas una skill:
markdown
# Skill: /new-endpoint (ejemplo conceptual)

## Instrucciones
Cuando el usuario pida crear un nuevo endpoint, sigue estos pasos:

### 1. Recopilar informacion
- Pregunta: metodo HTTP, ruta, descripcion de lo que hace

### 2. Crear el DTO de request/response
- Ubicacion: src/dto/{recurso}/
- Naming: {Recurso}Request.kt y {Recurso}Response.kt
- Siempre incluir validaciones con Jakarta Validation (@field:NotBlank, etc.)

### 3. Crear el controller
- Ubicacion: src/controller/{Recurso}Controller.kt
- Seguir el patron de OrderController como referencia
- Incluir decoradores de Swagger/OpenAPI

### 4. Crear el servicio
- Ubicacion: src/service/{Recurso}Service.kt
- Inyeccion por constructor, nunca usar @Autowired

### 5. Crear tests
- Ubicacion: src/test/kotlin/controller/{Recurso}ControllerTest.kt
- Minimo 3 casos: happy path, validacion fallida, recurso no encontrado

### 6. Verificar
- Ejecutar los tests con ./gradlew test
- Verificar que compila sin errores con ./gradlew compileKotlin
Esto convierte un flujo de 30 minutos de ida y vuelta con la IA en algo que se ejecuta de forma consistente con un solo comando. Y lo mejor: cualquier miembro del equipo puede usarla sin necesitar saber todos los detalles.
En Cursor, el equivalente son las "Custom Rules" o "Notepads". No son slash commands como tal, pero logran lo mismo: definir un flujo reutilizable que la IA sigue cada vez.
markdown
# Cursor Notepad: "Nuevo Componente React"

Cuando crees un nuevo componente React en este proyecto:

1. Usa TypeScript con interfaces (no types) para las props
2. Ubicalo en src/components/{NombreComponente}/
3. Crea estos archivos:
   - index.tsx (el componente)
   - {NombreComponente}.test.tsx (tests con Testing Library)
   - {NombreComponente}.stories.tsx (Storybook)
4. Usa Tailwind para estilos, nunca CSS modules
5. Exporta el componente como named export, no default
6. Si tiene estado complejo, usa useReducer, no multiples useState

Skills como documentación viva

Hay algo que no se menciona lo suficiente: las skills son una forma increíble de documentar los procesos de tu equipo. Piénsalo: en vez de tener un Confluence o un Notion con "Cómo crear un nuevo microservicio" que nadie lee, tienes una skill que ejecuta ese proceso automáticamente.
La skill se convierte en la fuente de verdad. Si el proceso cambia, actualizas la skill y listo. No hay documento desactualizado en algún wiki olvidado.

Piensa en las skills como recetas

Un chef (el agente) tiene ingredientes (las herramientas) y recetas (las skills). Puede improvisar, pero con una receta probada el resultado es más consistente. Las mejores skills nacen de tareas que haces una y otra vez. Si lo hiciste 3 veces manualmente, es hora de crear una skill.

La diferencia entre una skill y un prompt largo

Podrías pensar: "puedo simplemente copiar y pegar un prompt largo cada vez". Técnicamente sí, pero hay diferencias importantes:
AspectoPrompt copiadoSkill
ReutilizableTienes que buscarlo y pegarloUn comando y listo
VersionableSe pierde en el historial del chatVive en el repo, se commitea
CompartibleDepende de que alguien lo compartaTodo el equipo la tiene al clonar el repo
ConsistenteCada quien lo modifica a su gustoSiempre el mismo flujo para todos
MantenibleSi el proceso cambia, hay N copias desactualizadasActualizas un archivo y todos tienen la versión nueva

Contexto: el ingrediente secreto

Aquí está la clave de todo: la calidad de lo que la IA genera depende directamente del contexto que le das. Esto es cierto para cualquier herramienta, sin excepción.
Hay dos tipos de contexto:

Contexto automático

Es lo que la herramienta descubre sola. Cuando abres un proyecto en Cursor o Claude Code, la IA puede ver:
  • La estructura de archivos y carpetas
  • Los archivos que tienes abiertos
  • El historial de git
  • Las dependencias del proyecto (build.gradle.kts, pom.xml, etc.)

Contexto que tú le das

Aquí es donde la magia realmente sucede. Puedes darle contexto explícito a la IA de varias formas:
Archivos de instrucciones del proyecto: La mayoría de herramientas soportan un archivo tipo "instrucciones" que se carga automáticamente.
markdown
# CLAUDE.md (Claude Code) / .cursorrules (Cursor) / .github/copilot-instructions.md (Copilot)

## Stack del proyecto
- Backend: Spring Boot 3.2 con Kotlin
- Base de datos: PostgreSQL 15
- ORM: Exposed (no JPA)
- Testing: Kotest + Testcontainers

## Convenciones
- Nombres de endpoints en kebab-case
- Siempre validar DTOs en el controller con @Valid
- Los servicios nunca deben retornar entidades, solo DTOs
- Logs estructurados con logback en formato JSON

## Arquitectura
- Patron: Hexagonal simplificada
- Capas: controller -> service -> repository
- Sin usar @Autowired, solo inyeccion por constructor

Sin contexto, la IA adivina

Si no le dices que usas Exposed como ORM, la IA va a generar código con JPA/Hibernate porque es lo más común. Si no le dices que tus endpoints son kebab-case, va a usar camelCase. No esperes que adivine tu setup.

Buenas prácticas: lo que realmente funciona

Después de meses usando estas herramientas en proyectos reales, estas son las prácticas que marcan la diferencia:

1. Sé específico con lo que pides

La diferencia entre un buen resultado y un desastre muchas veces está en cómo escribes tu prompt. Mira la diferencia:

Prompt vago:

"Agrega autenticacion al proyecto"

Prompt específico:

"Agrega un filtro de autenticacion JWT en src/security/JwtAuthFilter.kt. Debe validar el token del header Authorization, extraer el userId del payload y setearlo en el SecurityContext. Si el token es inválido, retorna 401. Usa la misma libreria jjwt que ya tenemos en build.gradle.kts."

El segundo prompt le da a la IA todo lo que necesita: dónde poner el archivo,qué debe hacer, cómo manejar errores y qué dependencia usar.

2. Trabaja de forma incremental

No le pidas que construya toda la feature de una vez. Divide el trabajo en pasos y verifica cada uno antes de seguir.
bash
# Paso 1: Crea la entity
"Crea la entity User en src/entity/User.kt con campos: id, email, name, createdAt"

# Verificas que la entity se ve bien...

# Paso 2: Crea el repositorio
"Crea el repositorio UserRepository en src/repository/ usando la entity User que acabamos de crear"

# Verificas...

# Paso 3: Crea el servicio
"Crea el servicio UserService con metodos create, findById y findByEmail.
Usa UserRepository por inyeccion de constructor"

# Y asi sucesivamente...

Regla de oro

Si el cambio toca más de 3 archivos, divídelo en pasos. Tu yo del futuro te lo va a agradecer.

3. Revisa TODO lo que genera

Esto parece obvio, pero hay que decirlo: no hagas merge de código que no entiendas. La IA puede generar código que compila, pasa los tests y hasta se ve bonito, pero que tiene problemas sutiles:
  • SQL injection escondido en un query builder
  • Race conditions en código asíncrono
  • Dependencias innecesarias que inflan el bundle
  • Patrones que no siguen la arquitectura del equipo
Si la IA generó algo y no entiendes una parte, pregúntale. Literalmente dile: "Explícame por qué usaste esa estructura ahí". Es la forma más rápida de aprender y de detectar errores.

4. Usa el archivo de instrucciones del proyecto

Esto es lo más impactante que puedes hacer y lo que menos gente hace. Cada herramienta tiene su versión:
HerramientaArchivo de instrucciones
Claude CodeCLAUDE.md
Cursor.cursorrules
GitHub Copilot.github/copilot-instructions.md
Windsurf.windsurfrules
Aider.aider.conf.yml
La idea es la misma en todas: un archivo en la raíz del proyecto que le da contexto permanente a la IA. Commitalo al repo. Todo tu equipo se beneficia.

5. Aprende a decir "no"

A veces la IA propone algo que técnicamente funciona pero que no es lo que necesitas. No tengas miedo de rechazar su sugerencia y redirigirla. Unos ejemplos:
bash
# La IA propone crear un archivo nuevo...
"No, no crees un archivo nuevo. Agrega esa logica al servicio existente en src/service/OrderService.kt"

# La IA usa una libreria que no quieres...
"No uses java.util.Date, usamos kotlinx-datetime en este proyecto. Revisa el build.gradle.kts"

# La IA sobredisena la solucion...
"Eso es demasiado complejo. Solo necesito un when expression, no un patron Strategy"

6. Pide tests (en serio)

Una de las mejores formas de usar IA es para generar tests. En serio. Los tests son repetitivos, toman tiempo, y la IA los genera bastante bien.
bash
# Despues de crear tu servicio:
"Genera tests unitarios para UserService.
Usa Kotest con el estilo BehaviorSpec.
Mockea el repositorio con MockK.
Cubre los casos: crear usuario exitosamente, email duplicado, usuario no encontrado."

# Y para tests de integracion:
"Genera tests de integracion para el endpoint POST /api/users usando
@SpringBootTest con WebTestClient y Testcontainers.
Testea: creacion exitosa (201), email invalido (400), email duplicado (409)"
Lo bueno es que si ya escribiste el código (o la IA lo generó), tiene todo el contexto para crear tests que realmente validen el comportamiento.

Ejemplo práctico: workflow real con Claude Code

Veamos un ejemplo completo de cómo se ve un flujo real. Quiero agregar un endpoint de búsqueda de productos a un proyecto Spring Boot existente.
Paso 1: Le doy contexto de lo que quiero.
bash
> Necesito un endpoint GET /api/products/search que reciba un query param "q"
  y busque productos por nombre. Usa el patron que ya tenemos en los otros
  controllers (mira src/controller/OrderController.kt como referencia).
  La busqueda debe ser case-insensitive y retornar maximo 20 resultados.
El agente va a hacer algo como esto (automaticamente):
  1. Lee src/controller/OrderController.kt para entender el patrón
  2. Lee src/entity/Product.kt para ver los campos disponibles
  3. Lee src/config/WebConfig.kt para ver cómo se configuran las rutas
  4. Crea o edita src/controller/ProductController.kt
  5. Crea el src/service/ProductService.kt y src/repository/ProductRepository.kt
Paso 2: Reviso lo que generó. Veo que usó LIKE directamente en el query.
bash
> Cambia la busqueda para usar un indice full-text en vez de LIKE.
  Ya tenemos configurado tsvector en la tabla products.
Paso 3: Le pido tests.
bash
> Genera tests de integracion para el endpoint de busqueda.
  Usa el setup que ya tenemos con @Testcontainers y PostgreSQL.
  Cubre: busqueda con resultados, busqueda sin resultados, query vacio retorna 400,
  limite de 20 resultados.
Paso 4: Corro los tests y verifico.
bash
> Corre ./gradlew test --tests "*ProductSearch*"
Todo este flujo dura minutos, no horas. Pero lo clave es que en cada paso yo estoy verificando y dirigiendo. La IA no está volando sola.

Errores comunes (que todos cometemos)

1. El "si, si, acepta todo": Aceptar cada cambio sin leerlo. Es como hacer merge sin code review. Tarde o temprano algo explota.
2. Contexto cero: Abrir un proyecto nuevo y decir "hazme un login". Sin saber el stack, las convenciones ni la arquitectura, la IA va a generar código genérico que probablemente no encaje.
3. El prompt infinito: Escribir un prompt de 500 palabras describiendo absolutamente todo. Mejor divide en pasos. La IA trabaja mejor con instrucciones claras y acotadas.
4. No iterar: Si el primer resultado no es perfecto, no lo deseches. Dile que ajuste. Es una conversación, no un one-shot.
5. Olvidar que el código es tuyo: Si la IA generó un bug que llegó a producción, la responsabilidad es tuya. Tu nombre está en el commit. Trata el código generado con el mismo rigor que el que escribes a mano.

Comparación rápida de herramientas

Cada herramienta tiene su punto fuerte. Aquí va un resumen:
HerramientaTipoMejor para
Claude CodeCLI agénticoTareas complejas, refactors grandes, flujo en terminal
CursorIDE con IA integradaEdición multi-archivo, quien prefiere UI visual
GitHub CopilotExtensión de IDEAutocompletado rápido, sugerencias inline
WindsurfIDE con IAExperiencia tipo Cursor con modelo propio
AiderCLI open-sourceFlujo git-first, transparencia total

No hay herramienta perfecta

Lo más importante no es cuál usas, sino cómo la usas. Un desarrollador con buenas prácticas en cualquier herramienta va a obtener mejores resultados que alguien que use "la mejor" herramienta sin criterio.

Mi checklist personal

Antes de empezar a codear con IA en cualquier proyecto, me aseguro de:
  • Tener un archivo de instrucciones (CLAUDE.md / .cursorrules) con el stack y las convenciones
  • Hacer commits frecuentes (si algo sale mal, puedo hacer git checkout sin drama)
  • Trabajar en una rama separada para features grandes
  • Revisar cada diff antes de aceptarlo
  • Pedir tests para cada feature nueva
  • Si algo no entiendo, preguntarle a la IA que me explique antes de aceptar

Conclusión

Codear con IA no es vibe coding. No es "acepta todo y reza". Es una colaboración donde tú eres el senior y la IA es un junior muy rápido que necesita dirección, contexto y revisión.
Las herramientas van a seguir mejorando. Los agentes van a ser más autónomos. Pero el criterio técnico, la capacidad de revisar código y la habilidad de dar instrucciones claras van a ser cada vez más valiosas, no menos.
Así que la próxima vez que abras tu herramienta favorita, recuerda: no le pidas que haga magia. Dale contexto, sé específico, revisa lo que genera y trabaja de forma incremental. Eso es lo que separa a quien codea con IA de quien simplemente copia y pega IA.
La IA no reemplaza tu criterio. Lo amplifica.

Posts que podrian interesarte