Cómo revisar código generado por IA: un ejemplo y una checklist
Dambert Muñoz
Staff iOS Architect & AI Architect
Una respuesta de IA puede ser fácil de leer y tener el comportamiento equivocado. La revisión empieza por preguntar qué prometía resolver, qué entradas acepta y qué pasa cuando esas entradas no son las del ejemplo feliz. En este artículo usamos una función pequeña de descuentos para practicar. Es un ejemplo didáctico, no código listo para procesar pagos.
Pedirle al mismo modelo que confirme si su respuesta está bien puede descubrir problemas, pero no sustituye una comprobación independiente. El código debe poder contrastarse con un contrato y con resultados esperados. Si el contrato está implícito, tanto la persona como el modelo pueden completar los huecos con supuestos distintos y seguir creyendo que han terminado.
1. Escribe el contrato antes de aceptar el código
Supongamos que un catálogo trabaja en céntimos y permite un descuento porcentual entero. El importe debe ser un entero seguro no negativo, el porcentaje debe estar entre cero y cien, y el resultado también tiene que expresarse en céntimos. La regla de redondeo se acuerda explícitamente. En este ejemplo se redondea al entero más cercano con mitades hacia arriba para valores no negativos.
- Los nombres deben señalar la unidad:
amountMinorexpresa unidades mínimas. - El descuento aceptado es un porcentaje entero entre 0 y 100.
- El descuento de 0% conserva el importe y el de 100% produce cero.
- Una entrada inválida se rechaza; no se corrige silenciosamente.
- La regla de redondeo es una decisión de negocio del ejemplo.
2. Busca el fallo que el ejemplo feliz no muestra
function discountedTotal(amount: number, discount: number) {
return amount - amount * discount / 100;
}Para cien y diez, la propuesta devuelve noventa. El ejemplo funciona, pero no cuenta toda la historia. El nombre no indica si se usan soles o céntimos. Un descuento superior a cien devuelve un importe negativo. Una cantidad fraccionaria mantiene una precisión que tal vez no pueda cobrarse. NaN e infinito pasan sin un error útil. El problema no es el formato: faltan reglas.
Antes de tocar la función, lista lo que todavía necesitas saber. ¿Se aceptan porcentajes con decimales? ¿Se redondea por línea o sobre el total? ¿Hay un máximo comercial por compra? Esas preguntas no se resuelven añadiendo un Math.round al final. Una revisión útil devuelve decisiones abiertas, no únicamente una versión más larga del mismo código.
3. Implementa el alcance acordado sin ocultar entradas inválidas
export function discountedTotalMinor(
amountMinor: number,
percent: number,
): number {
if (!Number.isSafeInteger(amountMinor) || amountMinor < 0) {
throw new Error("INVALID_AMOUNT");
}
if (!Number.isInteger(percent) || percent < 0 || percent > 100) {
throw new Error("INVALID_PERCENT");
}
// BigInt keeps the intermediate multiplication exact.
const numerator = BigInt(amountMinor) * BigInt(100 - percent);
return Number((numerator + 50n) / 100n);
}La multiplicación intermedia utiliza BigInt: aunque el importe de entrada sea un entero seguro, multiplicarlo por cien con number puede superar su precisión exacta. El resultado vuelve a number después de dividir y permanece dentro del rango del importe original. Esto responde al contrato del ejemplo; no valida una moneda, un impuesto, un estado de pago ni un JSON externo.
Tampoco convierte el subtotal recibido del navegador en un importe confiable. En un checkout real, el servidor debe volver a obtener productos, precios y descuentos autorizados. Una función aritmética correcta puede seguir formando parte de un flujo incorrecto si permite que el cliente elija el total que se cobrará.
4. Construye las pruebas a partir del contrato
import assert from "node:assert/strict";
import { discountedTotalMinor } from "./discount";
assert.equal(discountedTotalMinor(1000, 0), 1000);
assert.equal(discountedTotalMinor(1000, 100), 0);
assert.equal(discountedTotalMinor(999, 10), 899);
assert.equal(discountedTotalMinor(1, 50), 1);
assert.equal(discountedTotalMinor(Number.MAX_SAFE_INTEGER, 0), Number.MAX_SAFE_INTEGER);
assert.throws(() => discountedTotalMinor(-1, 10));
assert.throws(() => discountedTotalMinor(1000, 101));
assert.throws(() => discountedTotalMinor(1000, 2.5));
assert.throws(() => discountedTotalMinor(NaN, 10));Las expectativas se escriben desde las reglas, no copiando lo que devuelve la implementación. La prueba de una mitad documenta el redondeo y la del entero máximo comprueba el límite de precisión. Si la herramienta genera pruebas que solo repiten sus propias fórmulas, las dos piezas pueden compartir el mismo error.
Después del ejemplo unitario, vuelve al sistema. Verifica dónde se llama la función, qué valida la entrada y cómo se muestra el resultado. Una prueba de integración debería comprobar que el precio procede del catálogo y que una compra de otra cuenta no puede leerse. La revisión termina cuando el recorrido autorizado cumple el resultado esperado, no cuando el editor deja de mostrar errores.
5. Una checklist corta para cada propuesta de IA
- Intención: ¿qué resultado debía producir y qué queda fuera del alcance?
- Contrato: ¿qué tipos, unidades, estados y permisos espera?
- Entradas: ¿qué sucede con vacío, límite, formato inválido y dato inesperado?
- Dependencias: ¿la API o versión utilizada existe en la documentación oficial?
- Integración: ¿la solución sigue las convenciones y consumidores del proyecto?
- Evidencia: ¿qué prueba independiente demuestra la propiedad importante?
- Operación: ¿hay errores útiles, trazabilidad y una manera de recuperar el flujo?
Ajusta la profundidad al riesgo. Un texto o una clase de estilo no requiere el mismo esfuerzo que una autorización o un cálculo de cobro. La IA puede ayudar a buscar consumidores, proponer casos límite y resumir un diff. La decisión de aceptar el cambio necesita explicar por qué la evidencia obtenida es suficiente para su alcance.
6. Dale a la IA una tarea que puedas comprobar
Una petición más útil que «haz que funcione» incluye el contexto, las reglas y el criterio de aceptación. Por ejemplo: «Revisa esta función de descuentos en céntimos. Acepta porcentajes enteros de 0 a 100, rechaza entradas inválidas y conserva precisión hasta el entero seguro máximo. Devuelve los supuestos y casos límite antes del cambio». La respuesta se convierte en una propuesta contrastable.
Conserva el diff, los casos de prueba y los límites de la revisión. Si el código consulta un servicio externo, añade qué respuesta real observaste y cuál simulaste. Compilar un proyecto demuestra una propiedad diferente de ver una pantalla o confirmar una transacción; mezclar esas pruebas produce una confianza mayor que la evidencia disponible.
Si estás empezando, puedes practicar estas bases en el curso de programación desde cero y AI coding. Para revisar un caso propio, consulta la mentoría para programadores. Y si tu equipo quiere diseñar un flujo con herramientas y evaluaciones, revisa la consultoría de agentes IA.
Escrito por
Dambert Muñoz
Staff iOS Architect & AI Architect
Arquitectura de software, productos móviles y formación práctica.