Las verdades de software de Joel Spolsky siguen siendo útiles cuando la IA escribe código rápido. Aprende a mantener pruebas, contratación y simplicidad enfocadas en la corrección.

La IA puede producir código que parece funcionar en minutos. Eso cambia el ritmo de un proyecto, pero no cambia lo que hace que el software tenga éxito. Las lecciones de las “verdades de software” de Joel Spolsky nunca fueron sobre la velocidad de tecleo. Eran sobre el juicio, los bucles de retroalimentación y evitar complejidad autoinfligida.
Lo que sí ha cambiado es el coste de crear código. Puedes pedir tres enfoques, cinco variaciones o una reescritura completa y obtener algo al instante. Lo que no ha cambiado es el coste de elegir el enfoque correcto, verificarlo y convivir con él durante meses. El tiempo ahorrado en escribir a menudo se traslada a decidir qué querías decir, validar casos límite y asegurarte de que la victoria rápida de hoy no se convierta en la tasa de mantenimiento de mañana.
La corrección, la seguridad y la mantenibilidad siguen llevando tiempo real porque dependen de pruebas, no de confianza. Un flujo de inicio de sesión no está hecho cuando compila. Está hecho cuando rechaza entradas malas de forma fiable, maneja estados extraños y no filtra datos. La IA puede sonar segura mientras omite un detalle crucial, como un chequeo de permisos en un endpoint o una condición de carrera en una actualización de pago.
La IA es más fuerte cuando la tratas como una máquina de borradores rápida. Brilla en boilerplate, patrones repetitivos, refactors rápidos y en explorar opciones que puedes comparar lado a lado. Usada bien, comprime la fase de “página en blanco”.
La IA perjudica más cuando le entregas objetivos vagos y aceptas la salida tal cual. Los mismos patrones de fallo aparecen una y otra vez: suposiciones ocultas (reglas de negocio no declaradas), caminos no probados (manejo de errores, reintentos, estados vacíos), errores confiados (código plausible pero sutilmente equivocado) y soluciones “ingeniosas” que son difíciles de explicar después.
Si el código es barato, el nuevo recurso escaso es la confianza. Estas verdades importan porque protegen esa confianza: con los usuarios, con los compañeros y con tu yo futuro.
Cuando la IA puede generar una feature en minutos, es tentador tratar las pruebas como la parte lenta que debes eliminar. El punto de Spolsky sigue vigente: la parte lenta es donde está la verdad. El código es fácil de producir. El comportamiento correcto no lo es.
Un cambio útil es tratar las pruebas como requisitos ejecutables. Si no puedes describir el comportamiento esperado de forma verificable, no has terminado de pensar. En trabajo asistido por IA, esto importa más, no menos, porque el modelo puede producir algo que suene correcto pero esté ligeramente equivocado.
Empieza probando lo que más dolería si se rompiera. Para la mayoría de productos, eso son los flujos centrales (registro, checkout, guardar, exportar), permisos (quién puede ver, editar, eliminar) e integridad de datos (sin duplicados, totales correctos, migraciones seguras). Luego cubre los bordes que suelen causar incidentes nocturnos: entradas vacías, textos largos, zonas horarias, reintentos y límites externos poco fiables como pagos, correos y subidas de archivos.
La IA es excelente proponiendo casos de prueba, pero no puede saber lo que realmente prometiste a los usuarios. Úsala como socio de lluvia de ideas: pídele casos límite faltantes, escenarios de abuso y combinaciones de permisos. Luego haz el trabajo humano: ajusta la cobertura a tus reglas reales y elimina pruebas que solo “prueban la implementación” en vez del comportamiento.
Haz que las fallas sean accionables. Una prueba que falla debe decirte qué se rompió, no enviarte a una búsqueda. Mantén las pruebas pequeñas, nómbralas como oraciones y haz mensajes de error específicos.
Imagina que construyes una sencilla app de “notas de equipo” con ayuda de la IA. Las pantallas CRUD aparecen rápido. El riesgo de corrección no es la UI. Es el control de acceso y las reglas de datos: un usuario no debe ver las notas de otro equipo, las ediciones no deben sobrescribir cambios más recientes y borrar una nota no debe dejar archivos adjuntos huérfanos. Las pruebas que aseguran estas reglas sentirán que son el cuello de botella, pero también son tu red de seguridad.
Cuando las pruebas son el cuello de botella, obligan a la claridad. Esa claridad es lo que evita que el código rápido se convierta en errores rápidos.
Una de las verdades más duraderas es que el código simple gana sobre el ingenioso. La IA hace tentador aceptar abstracciones elegantes porque llegan pulidas y rápido. El coste aparece después: más lugares donde esconder bugs, más archivos que revisar y más momentos de “¿qué hace esto?”.
Cuando el código es barato, la complejidad es lo que pagas. Un diseño pequeño y aburrido es más fácil de probar, cambiar y explicar. Eso importa aún más cuando el primer borrador vino de un modelo que puede sonar seguro mientras está sutilmente equivocado.
Una regla práctica es mantener funciones, componentes y módulos lo suficientemente pequeños para que un compañero los revise en minutos, no en horas. Si un componente de React necesita varios hooks personalizados, una máquina de estados local y una capa genérica de “renderizador inteligente”, párate y pregúntate si estás resolviendo un problema real o simplemente aceptando arquitectura porque la IA la ofreció.
Unos pocos “tests de simplicidad” ayudan a resistir:
Los prompts importan aquí. Si pides “la mejor arquitectura”, a menudo obtendrás una sobreconstruida. Pide restricciones que empujen hacia menos piezas móviles. Por ejemplo: usa el enfoque más simple con menos archivos; evita nuevas abstracciones a menos que eliminen duplicación en tres o más lugares; prefiere código explícito sobre helpers genéricos.
Un ejemplo concreto: pides a la IA añadir control de acceso por roles a una página de admin. La versión ingeniosa introduce un framework de permisos, decoradores y un DSL de configuración. La versión simple comprueba el rol del usuario en un solo lugar, blinda rutas en un único punto y registra accesos denegados. La versión simple es más fácil de revisar, probar y menos propensa a malinterpretaciones.
Si construyes en una herramienta basada en chat como Koder.ai, la simplicidad también hace que snapshots y rollback sean más valiosos. Cambios pequeños y obvios son más fáciles de comparar, conservar o revertir.
Cuando el código es fácil de producir, la habilidad escasa es decidir qué debe existir y asegurarse de que sea correcto. El viejo consejo de “contrata grandes programadores” sigue aplicando, pero el trabajo cambia. No contratas a alguien para que tipeé más rápido. Contratas a alguien para que juzgue, refine y defienda el producto.
Las personas más valiosas en desarrollo asistido por IA suelen compartir cuatro rasgos: juicio (qué importa), gusto (qué se ve bien), habilidad para depurar (encontrar la causa real) y comunicación (hacer claros los trade-offs). Pueden tomar una feature escrita por IA que “casi funciona” y convertirla en algo en lo que puedas confiar.
En lugar de pedir una solución perfecta desde cero, da a los candidatos un pull request generado por IA (o un diff pegado) con algunos problemas realistas: nombres poco claros, un caso límite oculto, pruebas faltantes y un pequeño error de seguridad.
Pídeles que expliquen qué intenta hacer el código en lenguaje llano, encuentren las partes de mayor riesgo, propongan correcciones y añadan (u esbocen) pruebas que atrapen regresiones. Si quieres una señal fuerte, pregúntales también cómo cambiarían las instrucciones para que la próxima vez la IA lo haga mejor.
Esto revela cómo piensan en condiciones reales: código imperfecto, tiempo limitado y la necesidad de elegir prioridades.
La IA a menudo suena confiada. Los buenos talentos se sienten cómodos rechazando propuestas. Pueden decir no a una feature que añade complejidad, no a un cambio que debilita la seguridad y no a enviar algo sin pruebas.
Una señal concreta es cómo responden a “¿Lo mergearías?”. Los candidatos fuertes no responden con una intuición: dan una decisión y una lista corta de cambios requeridos.
Ejemplo: pides una actualización rápida de control de acceso y la IA sugiere esparcir chequeos por handlers. Un candidato sólido rechaza ese enfoque y propone una capa clara de autorización, más pruebas para caminos admin y no-admin.
Por último, establece estándares compartidos para que el equipo edite la salida de la IA de la misma manera. Mantenlo simple: una definición de terminado, expectativas de revisión consistentes y una base de pruebas.
Cuando la IA puede generar mucho código en minutos, es tentador saltarse el pensamiento y simplemente iterar. Eso funciona para demos. Falla cuando necesitas corrección, comportamiento predecible y menos sorpresas.
Un buen prompt suele ser una especificación corta disfrazada. Antes de pedir código, transforma el objetivo vago en algunos criterios de aceptación y no-objetivos explícitos. Esto evita que la IA (y tu equipo) expanda el alcance en silencio.
Mantén la especificación pequeña pero específica. No estás escribiendo una novela. Estás poniendo límites sobre:
Define “terminado” antes de generar, no después. “Terminado” debe ser más que “compila” o “la UI se ve bien”. Incluye expectativas de prueba, compatibilidad y qué se monitorizará después del lanzamiento.
Ejemplo: quieres “añadir restablecimiento de contraseña”. Una especificación más clara podría decir: los usuarios solicitan restablecimiento por email; los enlaces expiran en 15 minutos; el mismo mensaje aparece aunque el email no exista; límite por IP; registrar intentos sin almacenar tokens en texto plano. No-objetivo: no rediseñar la página de login. Ahora tu prompt tiene guardrails y las revisiones son más sencillas.
Mantén un changelog ligero de decisiones. Un párrafo por decisión basta. Anota por qué elegiste un enfoque y por qué rechazaste alternativas. Cuando alguien pregunte “¿por qué está así?” dentro de dos semanas, tendrás la respuesta.
El mayor cambio con la IA es que producir código es fácil. La parte difícil es decidir qué debe hacer el código y probar que lo hace.
Empieza escribiendo el objetivo y las restricciones en lenguaje llano. Incluye qué nunca debe pasar, qué puede ser lento y qué está fuera de alcance. Una buena restricción es verificable: “Ningún usuario debe ver datos de otro usuario” o “Los totales deben coincidir con la exportación financiera al centavo”.
Antes de pedir código, pide un diseño simple y los trade-offs. Quieres que la IA muestre su razonamiento en una forma que puedas juzgar: qué guardará, qué validará y qué registrará. Si propone algo ingenioso, resiste y pide la versión más simple que cumpla las restricciones.
Un bucle repetible se ve así:
Aquí hay un escenario pequeño: añades “estado de reembolso” a una pantalla de orden. La IA puede generar la UI rápido, pero la corrección vive en los casos límite. ¿Y si un reembolso es parcial? ¿Y si el proveedor de pagos reintenta un webhook? Escribe esos casos primero, luego implementa un solo corte (columna en BD más validación) y verifícalo con pruebas antes de avanzar.
Si usas Koder.ai, funciones como modo de planificación, snapshots y rollback encajan naturalmente en este bucle: planifica primero, genera en trozos y captura un punto de restauración seguro para cada cambio significativo.
Cuando la generación de código es rápida, es tentador tratar el código como el producto final. No lo es. El producto final es el comportamiento: la app hace lo correcto, incluso cuando las cosas van mal.
La IA suele sonar segura, incluso cuando está adivinando. La falla es saltarse la parte aburrida: ejecutar pruebas, comprobar casos límite y validar entradas reales.
Un hábito simple ayuda: antes de aceptar un cambio, pregunta “¿Cómo sabemos que esto es correcto?”. Si la respuesta es “se ve bien”, estás apostando.
A la IA le encanta añadir extras: caching, reintentos, más settings, más endpoints, una UI más bonita. Algunas ideas son útiles, pero aumentan el riesgo. Muchos bugs vienen de funcionalidades “agradables de tener” que nadie pidió.
Mantén una frontera estricta: resuelve el problema que te planteaste y para. Si una sugerencia es valiosa, créala como tarea separada con sus propias pruebas.
Un commit grande generado por IA puede ocultar una docena de decisiones no relacionadas. La revisión se convierte en un estampado porque nadie puede retenerlo todo.
Trata la salida del chat como un borrador. Divídela en cambios pequeños que puedas leer, ejecutar y revertir. Los snapshots y rollback solo ayudan si los tomas en puntos sensatos.
Unos límites simples previenen la mayor parte del dolor: una feature por conjunto de cambios, una migración por conjunto, una área de alto riesgo a la vez (auth, pagos, borrado de datos), pruebas actualizadas en el mismo cambio y una nota clara de “cómo verificar”.
La IA puede reproducir patrones de datos de entrenamiento o sugerir dependencias que no entiendes. Aunque la licencia sea correcta, el riesgo mayor es la seguridad: secretos hardcodeados, manejo débil de tokens o operaciones inseguras con archivos y consultas.
Si no puedes explicar lo que hace un snippet, no lo publiques. Pide una versión más simple o reescríbela tú mismo.
Muchos bugs de “funciona en mi máquina” son realmente problemas de datos y escala. La IA puede crear cambios de esquema sin pensar en filas existentes, tablas grandes o tiempo de inactividad.
Un ejemplo realista: el modelo añade una columna NOT NULL nueva a una tabla PostgreSQL y la rellena con un loop lento. En producción, eso puede bloquear la tabla y romper la app. Siempre considera qué pasa con un millón de filas, una red lenta o un deploy que falla a mitad.
Imagina un pequeño gestor interno de solicitudes: la gente envía solicitudes, los managers aprueban o rechazan y finanzas marca items como pagados. Suena simple, y con ayuda de la IA puedes generar pantallas y endpoints rápido. Lo que te frena es la misma vieja verdad: las reglas, no el tipeo.
Empieza escribiendo lo mínimo que debe ser correcto. Si no puedes explicarlo en palabras sencillas, no puedes probarlo.
Una definición inicial ajustada suele verse así: campos (título, solicitante, departamento, monto, motivo, estado, timestamps); roles (solicitante, aprobador, finanzas, admin); estados (borrador, enviado, aprobado, rechazado, pagado). Luego indica las transiciones que importan: solo un aprobador puede mover enviado a aprobado o rechazado; solo finanzas puede mover aprobado a pagado.
Usa la IA en un orden controlado para atrapar errores temprano:
Las pruebas de mayor valor no son “la página carga”. Son las comprobaciones de permisos y transiciones de estado. Prueba, por ejemplo, que un solicitante no puede aprobar su propia solicitud, que un aprobador no puede marcar algo como pagado, que solicitudes rechazadas no pueden pagarse y que (si es tu regla) los montos no se editan tras el envío.
Lo que más tarda es aclarar casos límite. ¿Puede un aprobador cambiar de opinión después de rechazar? ¿Qué pasa si dos aprobadores hacen click en aprobar al mismo tiempo? ¿Y si finanzas necesita pagar parcialmente? La IA puede generar código para cualquier respuesta que elijas, pero no puede elegir por ti. La corrección viene de tomar esas decisiones y luego forzar que el código las cumpla.
La IA puede producir mucho código rápido, pero la última milla sigue siendo trabajo humano: demostrar que hace lo que querías y fallar de forma segura cuando no lo hace.
Antes de empezar a marcar casillas, elige la definición mínima de “terminado” que importe. Para una feature pequeña, puede ser un camino feliz, dos caminos de fallo y una pasada rápida de legibilidad. Para pagos o auth, sube el listón.
Supón que la IA añade “invitar usuarios en masa” a una pantalla admin. El camino feliz funciona, pero el riesgo real son los casos límite: emails duplicados, fallos parciales y límites de tasa. Una decisión sólida para lanzar podría ser una prueba automática para duplicados, una comprobación manual para mensajes en fallos parciales y un plan de rollback.
Cuando el código es barato, el riesgo se traslada a la calidad de las decisiones: qué pediste, qué aceptaste y qué enviaste. La forma más rápida de hacer que estas verdades rindan en trabajo asistido por IA es añadir guardrails que impidan que cambios “casi correctos” se cuelen.
Empieza con una especificación de una página para la siguiente feature. Mantenla en lenguaje llano: para quién es, qué debe hacer, qué no debe hacer y un puñado de tests de aceptación escritos en lenguaje cotidiano. Esos tests de aceptación se convierten en tu ancla cuando la IA sugiere atajos tentadores.
Un conjunto de guardrails que escala sin mucha carga de proceso:
Los prompts son parte de tu proceso ahora. Pon de acuerdo un estilo: qué librerías están permitidas, cómo se manejan errores, qué significa “terminado” y qué pruebas deben pasar. Si un prompt no puede ser reutilizado por otro compañero, probablemente es demasiado vago.
Si prefieres una forma de construir web, backend y apps móviles centrada en chat, Koder.ai (koder.ai) es un ejemplo de plataforma de “vibe-coding” donde el modo de planificación, snapshots y exportación de código pueden apoyar estos guardrails. La herramienta acelera borradores, pero la disciplina es la que mantiene a los humanos a cargo de la corrección.
Trata la salida de la IA como un borrador rápido, no como una característica terminada. Empieza escribiendo 3–5 comprobaciones de aceptación que sean pasar/fallar, luego genera un solo fragmento pequeño (un endpoint, una pantalla, una migración) y verifícalo con pruebas y escenarios de fallo antes de seguir.
Porque las pruebas son donde descubres lo que el código hace realmente. La IA puede producir lógica plausible que omite una regla clave (permisos, reintentos, estados límite). Las pruebas convierten tus expectativas en algo que puedes ejecutar, repetir y en lo que puedas confiar.
Empieza por lo que más daño causaría si fallara:
Añade más cobertura después de asegurar los comportamientos de alto impacto.
Pide el enfoque más simple con restricciones explícitas y elimina capas extra a menos que realmente lo justifiquen. Una buena regla: no introduzcas una nueva abstracción a menos que elimine duplicación en 3+ lugares o facilite probar la corrección.
Escribe una especificación corta: entradas, salidas, errores, restricciones y no-objetivos. Incluye ejemplos concretos (peticiones/respuestas de muestra, casos límite). Luego define “terminado” por adelantado: pruebas requeridas, expectativas de compatibilidad hacia atrás y una nota rápida de “cómo verificar”.
Divídelo. Mantén cada conjunto de cambios revisable en minutos:
Esto hace que la revisión sea real en lugar de un estampado en blanco.
No confíes en la confianza: confía en la prueba. Ejecuta pruebas, intenta entradas malformadas y verifica los límites de permisos. También busca trampas comunes de la IA: faltas de checks de autorización, construcción insegura de consultas, manejo débil de tokens y silenciamiento de errores.
Prefiere endpoints de transición explícita sobre un “actualiza cualquier cosa”. Por ejemplo: submit, approve, reject, pay en lugar de una ruta genérica de actualización. Luego escribe pruebas que impongan quién puede hacer cada transición y cuáles están prohibidas.
Proporciona a los candidatos un diff generado por IA con problemas reales: nombres poco claros, una prueba faltante, un caso límite y un pequeño fallo de seguridad. Pídeles que expliquen la intención, identifiquen las partes de mayor riesgo, propongan correcciones y describan las pruebas que añadirían.
Usa las funciones de la herramienta para apoyar un bucle disciplinado: planifica primero, genera en pequeños fragmentos, haz snapshot antes de cambios riesgosos y revierte si la validación falla. En una plataforma de chat como Koder.ai, esto encaja bien con modos de planificación, snapshots y rollback—especialmente cuando los cambios tocan auth, pagos o migraciones.