De la ingeniería de software a la ingeniería AI-native
En corto: generar código se abarató. Decidir si está bien, no. Los equipos que sufren con la entrega asistida por IA suelen ser equipos que ya tenían una disciplina de revisión débil y que ahora industrializaron el lado de la salida de un proceso cuyo lado de entrada nunca escaló. Lo sé porque apunté un agente a mi propio portafolio —un sitio que ya había publicado y daba por terminado— y encontró dos defectos críticos que llevaba dos años sirviéndole a los visitantes.
La trampa de la velocidad
Lo primero que pasa cuando un equipo adopta asistencia de IA en serio es que la salida sube y el throughput no.
Llegan más diffs. Llegan más rápido. En promedio son sintácticamente correctos. Y luego se encolan, porque la cantidad de gente capaz de decir «sí, este es el cambio correcto» no se movió nada. El cuello de botella no desapareció. Se mudó, del teclado a la cola de revisión, y ahora está en un lugar con mucho menos margen.
Esto no es un argumento en contra de la asistencia de IA. La uso todos los días y no pienso volver atrás. Es un argumento sobre dónde quedó la dificultad, porque muchos equipos siguen optimizando la parte que dejó de ser difícil.
Qué se movió realmente
A grandes rasgos, el esfuerzo de ingeniería se repartía así: entender el problema, decidir el enfoque, escribir el código, verificarlo, mantenerlo. Escribir era una porción considerable.
Ahora es una porción pequeña. Lo que no se encogió:
- Decidir qué construir
- Decidir si lo construido está bien
- Saber cuál comportamiento existente es crítico
- Cargar ese contexto seis meses hacia adelante
Todos esos son problemas de criterio, y el criterio es justamente lo que no sale de un modelo. Peor: el flujo asistido por IA erosiona activamente uno de ellos. Un agente empieza cada sesión sin memoria de por qué la sesión anterior tomó las decisiones que tomó.
La especificación deja de ser ceremonia
Siempre había tratado la especificación pesada como algo que ocurre en proyectos con demasiados interesados. Trabajar con agentes me hizo cambiar de opinión, por una razón poco romántica: una especificación es el único artefacto que permite revisar intención en lugar de texto.
Cuando un humano escribe un diff de 400 líneas, normalmente se puede inferir la intención a partir del código, porque los errores de un humano están correlacionados. Entiende mal una cosa y eso aparece de forma consistente. Los errores de un agente no se correlacionan así. Puede producir un diff que es localmente razonable en todas partes y equivocado como conjunto, y leerlo línea por línea no revela eso.
Así que la revisión tiene que ocurrir antes, contra una declaración de qué se supone que hace el cambio. Eso es todo lo que es una especificación acá. No ceremonia: una declaración revisable de intención, escrita antes de que exista un diff que te seduzca.
El historial de git del sitio donde estás leyendo esto muestra la forma del problema. Tres commits seguidos: «language switcher improvements», «v2», «v3». Ninguno explica qué estaba mal. Ninguno explica si quedó arreglado. No quedó: la misma funcionalidad seguía rota dos años después, y solo me enteré porque algo la volvió a examinar desde cero.
El caso concreto
Apunté un agente a este sitio con una instrucción nada glamorosa: audítalo, contra el despliegue en producción, y decime qué está mal.
Esperaba una lista ordenada de actualizaciones de dependencias. Lo que volvió fue peor, y más útil.
Todas las páginas declaraban la portada como su URL canónica. Una sola línea en el
layout raíz —canonical: '/'— heredada por cada página anidada. Le estuve diciendo a los
buscadores que /about, /skills y todas las páginas en español eran duplicados de la
portada. Durante dos años. El sitio se veía perfecto; el defecto solo era visible en las
cabeceras de respuesta, que es exactamente el tipo de lugar donde uno deja de mirar
cuando la página se ve bien.
La portada en inglés estaba tirando a la basura su HTML del servidor en cada carga.
Dos componentes de cliente comparaban usePathname() contra el literal '/'. Bajo el
rewrite del idioma por defecto, el servidor evalúa ese pathname como /en y el navegador
como /. Valores distintos, árboles distintos, fallo de hidratación — y React responde
descartando el HTML del servidor y volviendo a renderizar la raíz entera en el cliente.
Todo el beneficio de la generación estática, perdido, en la página más visitada. Cinco
errores de React en la consola que nunca había abierto, porque quién abre la consola en
una página que se ve bien.
Y después los que simplemente dan vergüenza. Dos insignias de certificación de AWS intercambiadas, de modo que la entrada de Solutions Architect mostraba la insignia de Developer —en la única página cuyo público entero reconoce esas insignias de un vistazo. Enlaces de texto con contraste de 2.38:1 contra un requisito de 4.5:1, incumpliendo WCAG en todos los enlaces del sitio. Un registro laboral que hacía empezar mi carrera cuatro años antes de lo real.
Veintinueve hallazgos. Dos críticos.
Qué hizo mal el agente
Esta es la parte que importa, y es la que estos artículos suelen saltarse.
Midió mal y reportó con seguridad. El primer escáner de contraste que escribió
devolvió fallos que no eran reales. Subía por el DOM hasta el primer fondo no
transparente y usaba ese —sin componer el alfa— así que cualquier superficie translúcida
producía un número equivocado. Además leía textContent, que recoge el texto de los
descendientes y se lo atribuye al color del ancestro. Ambas cosas produjeron fallos
fantasma de 1:1. Si hubiera aceptado la salida, habría «arreglado» cosas que estaban
bien.
Invirtió la dirección de un hallazgo. Marcó una contradicción entre mi biografía y mis datos estructurados —la bio decía que dirijo un equipo SWAT, los datos decían Principal Technical Lead— y concluyó que la bio estaba desactualizada. La bio tenía razón. Los datos estructurados llevaban cuatro años desfasados. Eligió mal porque ambas cosas eran plausibles y no tenía manera de saber cuál reflejaba la realidad.
Su propia red de seguridad tenía un agujero. Escribió un verificador de paridad de
idiomas para garantizar que el español nunca se desviara del inglés, usando
indexOf('es: [') para encontrar el bloque en español —que hace match con
technologies: [. El verificador estaba leyendo el arreglo en español como vacío y habría
aprobado un archivo con cero entradas en español. La herramienta cuyo único trabajo era
prevenir una clase de error contenía ese mismo error.
Nada de esto es un argumento contra el enfoque. Son argumentos sobre dónde tiene que pararse el humano. Cada uno se detectó verificando: midiendo en lugar de afirmar, contrastando una afirmación contra la realidad, probando el verificador contra un fallo deliberado. Eso es una disciplina, y no es opcional.
Compensaciones
Esto es sobrecarga en trabajo pequeño. Para un arreglo de un archivo, escribir una especificación primero es pura ceremonia y no lo haría. El umbral, más o menos: si querrías discutir el enfoque antes de ver el diff, escribí la intención. Si no, no.
Verificar es más lento de lo que parece. «Que compile» no es verificar. Comprobar si la portada todavía hidrata implica abrir un navegador de verdad y leer la consola. Comprobar el contraste implica calcular ratios, y después comprobar la cosa que los calcula. Presupuestá ese tiempo, porque la alternativa es confiar en la salida, y confiar en la salida es como se llega a una respuesta equivocada y segura de sí misma.
Las especificaciones se pudren. Una especificación que ya no coincide con el sistema es peor que ninguna, porque la gente le cree. Si no las vas a actualizar cuando el cambio aterriza, no las escribás.
Qué haría yo
Si estás adoptando esto en un equipo:
- Adelantá la revisión. Revisá la intención antes de la implementación. Ahí es más barato, y es donde los errores no correlacionados de un agente se ven.
- Escribí las decisiones. No documentos de proceso: decisiones, con el razonamiento. Un agente empieza cada sesión sin memoria; en la práctica, las personas también, a los seis meses.
- Hacé la verificación concreta. «Compila» no es una compuerta. Nombrá qué vas a medir y cómo vas a saberlo.
- Verificá el verificador. Probá tus chequeos contra un fallo deliberado. Si un chequeo nunca falló, no sabés si puede fallar.
- Dejá al humano en el criterio. No en teclear. El modelo teclea mejor que vos, y sabe peor cuál de dos cosas plausibles es la verdadera.
Lo incómodo de todo esto es que nada es nuevo. Especificación, disciplina de revisión, verificación honesta, dejar las decisiones por escrito: es práctica de ingeniería pasada de moda que muchos equipos dejaron de hacer en silencio porque podían salirse con la suya.
La IA les quitó el salirse con la suya.
Todo lo de este artículo es verificable. La auditoría, las especificaciones, los hallazgos y los arreglos están en el repositorio desde el que se construye este sitio, incluidos los que me dejan mal parado.