Pedir código es fácil; pedir una prueba que lo contradiga es lo que te hace avanzar

Soy Martin Rojas y voy a ser directo: pedirle a una IA “resuelve esto” es la versión moderna de dejar el motor encendido y esperar que el coche te lleve a donde quieras. Parece cómodo, pero confías en una caja negra que optimiza por probabilidad, no por garantía. Si la pieza que te entregan pasa los ejemplos felices pero falla con un input vacío, el coste de ese error te lo cobran los usuarios, no el prompt.

Empecemos por desmontar ese prompt ingenuo con una situación concreta. Pides una función que concatene nombres y apellidos. Una serie de ejemplos “felices” muestra entradas con nombre y apellido y la función devuelve «Nombre Apellido». Todo bien. Pero la producción le envía un registro con apellido nulo o con cadenas vacías; el resultado es «null» o «undefined» o un espacio redundante. La IA ganó el test superficial; perdió la realidad.

Ese fallo no es un bug menor: es evidencia de un contrato incompleto. Cuando solo pedimos que produzca código, delegamos la responsabilidad de las fronteras al sentido común del modelo. En un contrato real —y en ingeniería rigurosa— se firma la especificación. La diferencia entre “resuelve esto” y “prueba que lo contradiga” es la diferencia entre un borrador y una especificación ejecutable.

Qué significa convertir a la IA en adversaria de verificación

La tesis central aquí es simple: el prompt que realmente enseña no pide la respuesta final; pide un caso de frontera o una prueba que podría contradecir la solución. En lugar de usar la IA como un escriba, úsala como un revisor que busca —deliberadamente— romper tu solución. Ese cambio de rol obliga a formalizar cuatro elementos en el diálogo: especificación, ejemplo mínimo, contraejemplo y criterio de aceptación.

Especificación: qué hacen las entradas, qué no está permitido (valores nulos, formatos alternativos), y qué invariantes deben mantenerse.
Ejemplo mínimo: un caso claro y simple que ilustra el comportamiento esperado.
Contraejemplo: un caso frontera que debería provocar una falla si la especificación no se respeta.
Criterio de aceptación: condiciones medibles que determinan si el código pasa o no (por ejemplo, manejo explícito de nulos, pruebas unitarias con cobertura de frontera, mensajes de error consistentes).

Convierte cada interacción en un contrato corto. Cuando la IA actúe como adversaria, te obliga a definir los límites. ¿Qué ocurre si el input es la cadena vacía? ¿Y si el apellido contiene caracteres unicode especiales? Estas preguntas dejan de ser suplentes para convertirse en cláusulas contractuales.

Tres tarjetas de contradicción: herramientas mentales para forzar límites

Tarjeta 1 — Entrada vacía
Plantea explícitamente una entrada vacía o null y exige la respuesta exacta: lanzamiento de excepción, valor por defecto o mensaje de error. Si la IA no asume una política clara, la regresión será inevitable.
Tarjeta 2 — Formato inesperado
Introduce variantes válidas pero atípicas: espacios de más, mayúsculas mezcladas, separación por comas, o caracteres unicode. Pide pruebas que demuestren cómo la función normaliza o rechaza estos casos.
Tarjeta 3 — Integridad semántica
Exige una prueba que verifique invariantes: longitud máxima, ausencia de números en un nombre, o consistencia entre campos. Una implementación que pasa ejemplos felices pero viola estas invariantes está rota.

Estas tarjetas no son trucos; son plantillas para preguntas que todo prompt debería incluir. Si no añades una tarjeta de contradicción, no puedes culpar a la IA por producir código que «parece correcto».

Rechazo y contraargumento: “no sé escribir tests”

Una objeción legítima sugiere que escribir pruebas es una habilidad que algunos no tienen. Respuesta corta: eso deja más razones para pedirlas explícitamente en el prompt. Pide a la IA que genere tests junto con el código, y pide también que explique cómo se ejecutan. No estás delegando la responsabilidad de testear la lógica a la herramienta; le estás pidiendo que construya el arnés de verificación que tú ejecutarás o integrarás en CI.

Si realmente nunca has escrito un test, tuplea el diálogo: pide un archivo de pruebas sencillo (por ejemplo, con pytest o jest) y una breve guía de tres pasos para ejecutarlo. La investigación sobre asistencia de depuración y comprensión indica que los sistemas de IA pueden ofrecer no solo código sino estrategias de depuración y planificación —útiles para quien aprende a testear—. Consulta trabajos recientes que exploran cómo la IA puede asistir en habilidades de programación y depuración para comprender mejor qué pedir en contextos de aprendizaje y soporte.

Contraargumento habitual: “un caso que pasa ya basta”

Este es el tipo de pensamiento que garantiza fallas en producción. Aceptar un caso feliz como suficiente es aceptar una deuda técnica que se materializará en incidencias. Pide al sistema un contraejemplo que rompa la función. Si no lo encuentra, pide que explique por qué cree que no existe tal caso. La investigación sobre límites de suites homogéneas muestra que las pruebas superficiales comparten sesgos y no capturan fallos sistemáticos; en entornos reales, las suites homogéneas generan falsa confianza por limitaciones estructurales.

Un único caso positivo no aporta probabilidad baja de fallo; aporta suficiente evidencia de incompletitud. Cambia el objetivo: de “hacer que pase el caso” a “acotar y refutar la hipótesis de correctitud”.

Reconstruyendo el diálogo: ejemplos concretos

Un buen prompt no pide «resuelve esto». Pide:

  • Especificación formal breve de entradas y salidas.
  • Implementación en el lenguaje X con manejo explícito de nulos y normalización.
  • Una suite de pruebas que cubra casos felices, frontera y contraejemplos.
  • Un resumen de por qué cada prueba es relevante y qué invariantes verifica.

Además, añade un paso de planificación: solicita un plan breve de depuración y priorización de fallos (por ejemplo, “si la prueba X falla, sigue estos tres pasos”). Investigaciones sobre planificación y depuración señalan que pedir planes incrementa la calidad de las soluciones, porque orienta la generación hacia pasos verificables y rastreables y ayuda a localizar la causa raíz.

Un ejemplo de prompt eficaz (resumido): “Implementa la función concat_name que toma {first_name, last_name}. Especifica comportamiento para null/» y normalización unicode; incluye 6 pruebas: 3 felices, 2 fronteras, 1 contraejemplo; proporciona un criterio de aceptación y un plan de depuración de 3 pasos.” Esa estructura fuerza a la IA a razonar sobre heridas potenciales, no solo a improvisar una solución.

Cuando no conoces el resultado exacto, todavía puedes conocer una propiedad

Hay problemas donde escribir “la salida correcta” para cada entrada resulta incómodo, pero eso no significa que debas abandonar la verificación. Cambia la pregunta: ¿qué relación debe conservar el programa aunque cambien los datos? Si una función ordena una lista, el resultado debe tener la misma cantidad de elementos y ningún elemento nuevo; si normaliza un nombre, aplicarla dos veces debería producir el mismo resultado que aplicarla una sola vez; si convierte una fecha, una ida y vuelta razonable no debería perder información que el contrato promete conservar.

Estas propiedades se convierten en una conversación mucho más fértil con la IA. En lugar de “escribe tests para mi función”, prueba con: “propón tres invariantes de esta transformación; para cada una, genera una entrada que la ponga en tensión y explica qué fallo revelaría”. Después, altera deliberadamente un dato: cambia mayúsculas por minúsculas, quita una clave, duplica un elemento, introduce un espacio invisible o aumenta el tamaño de la colección. No necesitas conocer cada salida para saber que una función que borra registros, cambia su orden sin motivo o deja escapar un valor nulo está rompiendo un acuerdo.

Esta técnica también evita una trampa frecuente al trabajar con modelos: aceptar una respuesta que funciona para el ejemplo que el propio modelo eligió. Si la IA propone tanto la implementación como el único caso de prueba, puede compartir el mismo supuesto defectuoso en ambos lados. Pedir mutaciones de entrada y propiedades independientes obliga a separar generador y verificador. Es una versión pequeña, accesible y útil del razonamiento que los estudios de evaluación de código reclaman cuando advierten que suites homogéneas dejan pasar defectos sutiles.

La próxima vez que recibas una solución, no empieces preguntando “¿funciona?”. Pregunta “¿qué debería seguir siendo cierto si intento deformar la entrada sin violar el contrato?”. Esa pregunta no exige dominar un framework de testing; exige definir qué promete el código. Y esa definición es precisamente la parte que no conviene delegar.

Métodos prácticos para integrar la estrategia hoy

No necesitas reinventar tu pipeline. Integra estas prácticas en tu flujo actual:

  • Pide testcases como parte del entregable y agrega la ejecución de esos tests a tu CI.
  • Usa las tarjetas de contradicción como checklist en cada PR.
  • Convertir a la IA en adversaria: solicita activamente contraejemplos y explica por qué cada uno rompería la implementación si se cumpliera.

Si quieres apoyo para transformar prompts en contratos reutilizables, puedes revisar guías prácticas que he escrito sobre prompts para programar y errores comunes que evitarlos en este artículo. También recomiendo leer recursos sobre errores frecuentes en JavaScript y conceptos básicos de Python si tu stack lo requiere: errores comunes en JS, conceptos básicos en Python, y una reflexión sobre la dependencia de IA en la programación en esta publicación.

Una advertencia final: las suites de prueba homogéneas y los ejemplos repetidos crean ilusión de seguridad. El trabajo de validación es adversarial por naturaleza. El objetivo no es sólo lograr que el test pase, sino encontrar escenarios donde la hipótesis se rompe y cerrar esos huecos.

Transformar a la IA en un adversario verificante es incómodo al principio —te obliga a pensar en fallos—, pero es el camino más directo hacia software más robusto. El impulso que te hace avanzar no es pedir la solución perfecta; es pedir la prueba que demuestra que tu solución no lo es. Haz de esa prueba un requerimiento. Haz que la IA te la entregue. Y cuando te diga “no veo cómo romper esto”, pídela que explique por qué: a veces ese razonamiento revela supuestos ocultos que tú no habías considerado.

Martin Rojas — crítica y contrapunto sobre prácticas de ingeniería asistida por IA.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Scroll al inicio