Patrón anticuado u obsoleto.
Los asistentes de IA emiten con total seguridad APIs, bibliotecas y expresiones idiomáticas que eran actuales hace años pero que ahora están obsoletas, eliminadas o superadas, porque su conocimiento paramétrico está congelado en una fecha de corte del entrenamiento y el patrón antiguo sigue siendo el estadísticamente más común en su corpus.
##Signs and Symptoms
Un revisor reconoce este olor cuando el código generado se ejecuta pero se ajusta al estilo de un tutorial de hace dos o tres años: llama a APIs sobre las que el framework ya advierte, fija versiones mayores antiguas o recurre a expresiones heredadas en lugar de la biblioteca estándar/sintaxis moderna. Señales reveladoras:
- Advertencias de obsolescencia en la instalación/compilación/ejecución que el modelo ignoró (
DeprecationWarning,[DEP0005],componentWillMount is deprecated). - Expresiones idiomáticas anteriores a la base actual del lenguaje:
varen lugar deconst/let, cadenas de callbacks/.then()donde la base de código usaasync/await,require()en un proyecto ESM,moment.jsen lugar deIntl/Temporal/date-fns. - Llamadas a bibliotecas eliminadas en la versión que tienes instalada realmente: pandas
df.append(...)/.ix[], ciclos de vida heredados de React,datetime.utcnow(),new Buffer()de Node,url.parse(). - Valores de seguridad heredados por defecto que dominan los datos de entrenamiento antiguos: hashing MD5/SHA1,
crypto.createCipher, SQL concatenado en crudo con cadenas. - Reinventar lo que la plataforma ya incluye (
deepClone,groupBy, UUID hechos a mano) en lugar destructuredClone,Object.groupBy,crypto.randomUUID().
// Generado por IA: compila, pero cada línea es un patrón ya obsoleto
const crypto = require('crypto'); // el proyecto ESM usa import
const buf = new Buffer(userInput); // Buffer() obsoleto desde Node 6
const id = crypto.createHash('md5') // MD5 obsoleto para cualquier uso de seguridad
.update(token).digest('hex');
const cipher = crypto.createCipher('aes-256-cbc', key); // API de ruta eliminada, KDF débil
request(apiUrl, (err, res, body) => { /* ... */ }); // 'request' sin mantenimiento desde 2020
##Reasons for the Problem
Por qué los modelos lo producen
- Desactualización por la fecha de corte del entrenamiento. El conocimiento paramétrico de un LLM queda congelado en su fecha de corte, pero las bibliotecas siguen evolucionando. Los estudios que lo miden encuentran una tasa de uso de APIs obsoletas del 25–38 % en ocho bibliotecas de Python dentro de las terminaciones generadas por LLM (Wang et al., ICSE 2025), e incluso los modelos más avanzados solo alcanzan un 48–51 % en la generación condicionada por versión (GitChameleon 2.0). No existe conciencia en tiempo real de la API ni de la versión durante la inferencia.
- La frecuencia del siguiente token favorece la forma antigua. El corpus contiene años de código heredado, así que la terminación estadísticamente más probable suele ser la obsoleta. OX Security señala que los modelos recurren por defecto a la concatenación de cadenas y a MD5/SHA1 precisamente porque esos "aparecen con mayor frecuencia en los datos de entrenamiento", y Veracode descubrió que los modelos eligen la opción insegura/heredada el ~45 % de las veces cuando se les da a elegir (OX Security).
- Sin contexto del repositorio. Normalmente el modelo no sabe qué versión mayor tienes instalada realmente, qué fija tu lockfile, ni que
lib/hash.tsya existe, así que no puede apuntar a tu superficie de API. Como lo plantea Stack Overflow: un agente es "un gran reconocedor de patrones… buen código entra, buen código sale"; sin un ejemplo actual, recurre al promedio de sus datos de entrenamiento (Reyes Q&A). - Recompensa de "hazlo funcionar" + adulación. Los modelos optimizan para que el código compile de forma plausible y satisfaga la petición, no para que "use la vía actual y soportada". La llamada obsoleta todavía funciona hoy, así que parece correcta.
Por qué resulta perjudicial
- Mantenibilidad / rotura como bomba de tiempo. Obsoleto hoy significa eliminado en la próxima versión mayor: el código funciona hasta que una actualización lo rompe en silencio, y estos patrones se copian y pegan en lugar de refactorizarse. El análisis de 211 millones de líneas de GitClear muestra que las líneas copiadas/pegadas subieron del 8,3 % al 12,3 % mientras que las líneas refactorizadas ("movidas") cayeron del 24,1 % al 9,5 % entre 2020 y 2024, con bloques duplicados multiplicándose ~8 veces, de modo que una sola expresión obsoleta se propaga en vez de corregirse una sola vez (GitClear 2025).
- Corrección. Las APIs superadas suelen tener una semántica sutilmente distinta (
utcnow()devuelve un datetime naive; los ciclos de vida heredados se disparan en momentos distintos), produciendo errores que superan una prueba rápida de humo. - Seguridad. La criptografía obsoleta (MD5,
createCipher) y las versiones de paquetes anticuadas arrastran CVE conocidos que el modelo nunca contrasta con ninguna base de datos de avisos: un motor central del hallazgo de que la mayoría del código generado por IA se entrega con al menos una vulnerabilidad. - Carga de revisión y deuda técnica. Cada aparición es una corrección manual independiente y, como el patrón está duplicado en lugar de centralizado, el coste se acumula por toda la base de código.
##Treatment
Tácticas de revisión y de prompting
- Indica las versiones en el prompt o el contexto. "Usamos React 19, pandas 2.2, Node 22 (ESM): emplea solo APIs vigentes en esas versiones." Incorpora la documentación actual al contexto (un MCP de documentación / Context7) en lugar de fiarte de la memoria paramétrica.
- Obliga a una pasada de herramientas. Exige que el modelo ejecute el linter, el verificador de tipos y
npm outdated/pip list --outdated, y luego corrija cada advertencia de obsolescencia antes de darlo por terminado. Las advertencias de obsolescencia son el detector más barato posible: no dejes que se ignoren. - Exige reutilización en lugar de reinvención. "Usa el ayudante existente en
lib/hash.ts; no implementes el hashing a mano." Apunta al módulo canónico para que el modelo no regenere una versión heredada (Código duplicado). - Codemods en lugar de ediciones manuales. Para actualizaciones sistemáticas, ejecuta los codemods/modernizadores oficiales en lugar de pedir al modelo que reescriba a mano:
npx @next/codemod, los codemods de React, las reglaspyupgrade/UPde Ruff. Son deterministas y completos.
La refactorización: en esencia es Sustituir algoritmo / reemplazar-API-obsoleta, y consolidar las llamadas obsoletas duplicadas en un único ayudante aplica Extraer función contra Código duplicado:
// Antes — APIs obsoletas o de ruta eliminada
const buf = new Buffer(userInput);
const id = crypto.createHash('md5').update(token).digest('hex');
const cipher = crypto.createCipher('aes-256-cbc', key);
// Después — actuales, compatibles y sensatas en seguridad
import crypto from 'node:crypto';
const buf = Buffer.from(userInput); // constructor seguro
const id = crypto.createHash('sha256').update(token).digest('hex');
const iv = crypto.randomBytes(16); // IV explícito
const cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
// (para contraseñas, usa argon2/bcrypt, no un hash en crudo)
Para las dependencias, la corrección equivalente es subir la versión fijada y dejar que el codemod migre los puntos de llamada, y luego bloquear la deriva futura en CI (la regla de lint anterior + una política de Dependabot/Renovate) para que el modelo no pueda reintroducir el patrón antiguo en silencio.
##Detected by
- ESLint (eslint-plugin-n) n/no-deprecated-api — Prohíbe las APIs básicas obsoletas de Node.js (Buffer(), crypto.createCipher, url.parse, etc.)
- typescript-eslint @typescript-eslint/no-deprecated — Señala el uso de cualquier símbolo marcado como @deprecated en su declaración JSDoc/TS
- ESLint (eslint-plugin-react) react/no-deprecated — Señala APIs y métodos de ciclo de vida de React obsoletos (componentWillMount, etc.)
- SonarQube / SonarSource RSPEC-1874 ("@Deprecated" code should not be used) — Informa del uso de código anotado/marcado como obsoleto
- Ruff pyupgrade (UP) rules — Detecta y reescribe expresiones idiomáticas de Python anticuadas/superadas a sus equivalentes modernos
- Dependabot version-updates — Señala versiones de dependencias anticuadas (la faceta de paquetes desactualizados de este olor)