← Back to blog

Code Slop y la deuda técnica generada por IA

English Español Català

Terminé el artículo anterior de esta serie con una pregunta: la última vez que aprobasteis algo, ¿podríais haber explicado por qué estaba bien? Este trata sobre lo que pasa cuando la respuesta es no, y no como excepción, sino como la forma habitual en que funciona un pipeline.

El code slop no es código el cual se ve de forma muy obvia que es malo. El código obviamente malo se detecta. Es código que supera todos los puntos de control que habéis montado, todos los tests que habéis escrito, y que aun así no es algo que querríais tener que mantener dentro de seis meses.


Qué aspecto tiene realmente el code slop

Compila. Pasa los tests que se os ocurrió escribir. Hace lo que pedía el ticket, técnicamente. Y además es la cuarta forma ligeramente distinta de hacer lo mismo en esta base de código, porque el agente no tenía forma de saber que las otras tres ya existían: vio el archivo que le dijisteis que editara, no el patrón que ya estaba establecido dos carpetas más allá.

El slop no es un bug. Un bug falla con suficiente ruido como para que alguien acabe notándolo. El slop solo añade masa: un helper duplicado, una abstracción que tiene un único punto de uso, gestión de errores para un caso que no puede darse, un test que comprueba que el mock se comportó como el mock. Nada de eso está mal. Todo eso es ahora algo que una persona tiene que leer, entender y mantener, para siempre, o hasta que alguien reúna el valor de borrarlo.


Por qué supera todos los puntos de control

Los puntos de control del artículo anterior se diseñaron para detectar errores: una salida incorrecta, una lógica rota, una especificación incumplida. El slop no es un error. Es código correcto que no debería existir, o código correcto repetido tres veces, o código correcto que resuelve un problema que nadie tiene en realidad. Ninguna de vuestras comprobaciones actuales busca eso, porque «¿es esto correcto?» y «¿necesita esta base de código esto?» son preguntas distintas, y la mayoría de las revisiones, humanas o automáticas, solo hacen la primera.

Un agente que optimiza para «que los tests pasen» no tiene ninguna señal que le diga que el helper que acaba de escribir ya existe como formatDate dos archivos más allá. No tiene ninguna señal que le diga que la interfaz que acaba de introducir únicamente va a ser implementada una vez, que es la que el propio agente ha creado. No está siendo perezoso ni descuidado. Está teniendo éxito, exactamente como se le indicó, en un objetivo más estrecho que el que realmente os importa.


Los tests que no lo detectan

Esta es la parte que más me costó aceptar: una batería de tests en verde es prueba de que el código hace lo que comprueban los tests. No es prueba de que el código sea la cantidad de código adecuada. Podéis escribir un test perfectamente válido para una clase que no debería existir, una interfaz con una única implementación, una opción de configuración que nadie usará nunca con un valor distinto del predeterminado.

Las cifras de cobertura empeoran esto, no lo mejoran. Un porcentaje de cobertura alto sobre código innecesario solo significa que habéis probado a fondo ese código innecesario. Es una cifra real que mide lo que no toca, y eso es más peligroso que una cifra obviamente falsa: una cifra falsa se cuestiona, una cifra real que mide el eje equivocado se da por buena.


Qué busco ahora en realidad

La pregunta que me hago ya no es «¿funciona?»; eso ya lo han respondido los tests. Es «¿lo habría escrito yo así?» y, más en concreto, «¿hay menos código que haga el mismo trabajo?». Algunas cosas que sacan a la luz el slop de forma bastante fiable cuando las busco:

  • Buscad antes de fiaros de una función nueva. Si un agente acaba de escribir un helper, buscad primero algo parecido. Las utilidades reinventadas son lo que más me encuentro, y son invisibles a menos que las busquéis a propósito.
  • Contad los puntos de uso. Una interfaz, un flag de configuración o una factory con exactamente una implementación o un único punto de uso es una decisión tomada para un futuro que no ha llegado. Eliminad la ceremonia y quedaos con lo concreto.
  • Leed el diff pensando en contra de qué protege. La gestión de errores y la validación para estados que no pueden darse no son seguridad: son relleno que parece seguridad, y es justo el tipo de cosa que los revisores dejan pasar porque parece responsable.
  • Preguntaos qué pasa si lo borráis. Si quitar un fragmento de código no cambia ningún comportamiento observable, es que no se ganaba el sitio.

Nada de esto es exótico. Es la misma disciplina de revisión que ya aplican los buenos ingenieros al código escrito por personas. La diferencia es que un agente genera diez veces ese volumen en la misma tarde, así que las partes de la revisión que antes eran opcionales, las que podíais saltaros porque una persona no solía escribir tanto código innecesario de una sentada, dejan de serlo.


Cómo pagarla antes de que se acumule

La versión cara de este problema no es el slop en sí: es el slop que revisa otro agente más adelante, que trata la duplicación existente como precedente y añade una quinta versión del mismo helper junto a las otras cuatro. La deuda que genera una persona despacio se detecta despacio, al mismo ritmo al que se acumula. La deuda que genera un agente deprisa puede adelantar a las personas que se supone que la vigilan antes de que nadie lea el diff con suficiente atención para ver el patrón.

La solución no es más puntos de control; el artículo anterior ya explicó por qué eso sale mal. Es hacer que «¿esta base de código ya hace esto?» forme parte de lo que se le indica al agente que compruebe antes de escribir código nuevo, en lugar de algo que una persona reconstruye después a partir de un diff enorme. Sale más barato señalarle a un agente el patrón que ya existe que limpiar después su intento de adivinarlo.


Conclusión

Un pipeline que solo comprueba la corrección enviará encantado a producción código correcto que no debería existir. El slop no es el fallo de un proceso roto: es el resultado previsible de un proceso que nunca se hizo la segunda pregunta.

En el próximo artículo de esta serie veré cómo medir de verdad si una configuración de agentes mejora con el tiempo, en lugar de limitarse a parecer que mejora: Evals: cómo sé de verdad si mi agente ha mejorado — construir el bucle de retroalimentación que detecta las regresiones que ni los puntos de control ni los tests en verde detectan.

Hasta entonces, la pregunta que merece la pena hacerse sobre vuestro propio resultado no es:

¿Esto funciona?

Es:

¿Es esto lo mínimo de código que podía hacerlo funcionar?

Si habéis encontrado una forma de detectar duplicación o abstracción innecesaria antes de que llegue a producción, me gustaría saber cómo. No dudéis en escribirme.