Código repetitivo verboso.
Los asistentes de IA rellenan una lógica sencilla con comentarios redundantes, ceremonia defensiva y bloques casi duplicados copiados y pegados en lugar de reutilizar o extraer código existente, inflando el número de líneas sin aportar valor.
##Signs and Symptoms
Quien revisa detecta Código repetitivo verboso cuando un diff es mucho más largo de lo que el problema justifica: cada línea está narrada por un comentario que solo la repite, las expresiones simples se envuelven en escaleras defensivas de null/undefined y la misma forma de código reaparece dos o tres veces en vez de factorizarse en una función auxiliar. El delator es una alta proporción comentario-a-lógica y línea-a-comportamiento, además de bloques que podrían haber sido tres líneas de código idiomático.
// Función para obtener el nombre completo del usuario
function getFullName(user: User): string {
// Comprobar si el usuario está definido
if (user === null || user === undefined) {
// Devolver una cadena vacía cuando no se proporciona usuario
return "";
}
// Obtener el nombre, con cadena vacía por defecto
const firstName = user.firstName ? user.firstName : "";
// Obtener el apellido, con cadena vacía por defecto
const lastName = user.lastName ? user.lastName : "";
// Concatenar el nombre y el apellido con un espacio
const fullName = firstName + " " + lastName;
// Recortar los espacios en blanco y devolver el resultado
return fullName.trim();
}
Tres líneas de comportamiento enterradas en ~12 líneas de ceremonia. En un PR real sueles ver este mismo patrón copiado y pegado como getDisplayName, getLabel y getInitials, cada uno reimplementando a mano una lógica que una utilidad formatName() ya cubre: el clásico olor de Código duplicado. Otros delatores: constructores/envoltorios vacíos de paso directo, ceremonia try { ... } catch (e) { throw e } y un validador de email/URL hecho a medida junto al módulo de validación que el proyecto ya tiene.
##Reasons for the Problem
Por qué los modelos lo producen
- Sesgo de verbosidad del siguiente token. Los LLM se entrenan con volúmenes enormes de código de tutoriales, Stack Overflow y código principiante donde los comentarios paso a paso y la ceremonia explícita son la norma. La continuación más probable es la más explicada, no la más concisa.
- El RLHF recompensa "parecer minucioso". El ajuste por utilidad/verbosidad empuja a los modelos hacia una salida que aparenta ser completa y autoexplicativa —comentarios en cada línea, comprobaciones defensivas por todas partes— que los evaluadores y los usuarios recompensan aunque no aporte valor.
- Sin contexto del repositorio no hay reutilización. Sin la base de código circundante en el contexto, el modelo no puede saber que ya existe una utilidad
formatName()ovalidateEmail(), así que la rederiva en línea. Esto es exactamente la Sobreespecificación de OX Security ("soluciones hiperespecíficas de un solo uso en lugar de componentes generalizables y reutilizables", hallada en el 80-90% del código de IA) y la Evitación de refactorizaciones (80-90%). - Generación, no consolidación. Los agentes emiten código nuevo por cada prompt y nunca vuelven para deduplicar. El análisis de GitClear de 2025 sobre 211M de líneas modificadas halló que el código copiado/pegado subió de 8,3% (2020) a 12,3% (2024) y superó por primera vez a las líneas "movidas" (refactorizadas), mientras que las líneas refactorizadas cayeron de ~24% a 9,5% y los bloques duplicados de más de 5 líneas se multiplicaron ~8×.
- Comentar todo por defecto. OX Security encontró "Comentarios por todas partes" en el 90-100% del código generado por IA.
Por qué hace daño
- Mantenibilidad: más superficie que leer y cambiar; los comentarios redundantes se desincronizan del código y se vuelven activamente engañosos (el olor de los Comentarios de Fowler).
- Corrección y seguridad: los bloques duplicados implican que un fallo o una vulnerabilidad debe arreglarse en N sitios: el Déjà-vu de fallos de OX (70-80%). El código clonado se correlaciona con un 15-50% más de defectos.
- Carga de revisión: los diffs grandes y de baja señal ocultan los cambios reales e inducen fatiga en quien revisa, así que los problemas genuinos se cuelan.
- Deuda técnica acumulativa: cada casi-duplicado hace más difícil la siguiente extracción, atrincherando el problema que el modelo no puede ver entre archivos.
##Treatment
Tácticas de revisión y de prompts
- Fuerza la reutilización antes de generar: "Busca en la base de código funciones auxiliares existentes (
formatName,validate*) y reutilízalas; no las reimplementes." Proporciona las utilidades relevantes en el contexto. - Pon un presupuesto a la salida: "Mantén esto por debajo de ~15 líneas; sin comentarios que repitan el código, solo comentarios que expliquen el porqué."
- Haz que el modelo ejecute las herramientas: exige
eslint/ruffy una pasada de duplicación conjscpd, y que informe y arregle las violaciones antes de devolver. - Pide el diff más pequeño y un paso explícito de deduplicación: "Si algún bloque se repite, extrae una sola función compartida (Extraer función) y llámala."
- Consolida en la revisión: cuando veas la tercera casi-copia, aplica Extraer función, Subir método o Consolidar fragmentos condicionales duplicados, y Reemplazar comentario por código (renombra para que el código se autodocumente).
Refactorización (antes → después)
// después: comentarios eliminados (el código se explica solo), ceremonia colapsada,
// utilidad compartida reutilizada en vez de rederivada
function getFullName(user?: User): string {
return [user?.firstName, user?.lastName].filter(Boolean).join(" ");
}
Y elimina los duplicados de raíz: si getDisplayName/getLabel hacían lo mismo, bórralos y apunta a quienes los llaman hacia una sola función (Eliminar código muerto / Insertar función en línea). Sustituye el validador hecho a mano por la importación del módulo existente en lugar de mantener una copia paralela.
Regla práctica para el catálogo: trata cualquier bloque de IA donde los comentarios superen en número a las líneas de lógica, o donde puedas nombrar una función auxiliar existente que ignoró, como candidato a la eliminación-por-reutilización: el arreglo más rápido del código repetitivo suele ser menos código, no más.
##Detected by
- jscpd duplication threshold (--min-tokens / --threshold) — Detección de copiar/pegar (umbral de tokens mínimos)
- SonarQube / SonarCloud typescript:S4144 — Las funciones y los métodos no deben tener implementaciones idénticas
- SonarQube / SonarCloud typescript:S1192 — Los literales de cadena no deben duplicarse
- SonarQube / SonarCloud javascript:S1871 — Dos ramas de una estructura condicional no deben tener exactamente la misma implementación
- ESLint (eslint-plugin-sonarjs) sonarjs/no-identical-functions — Las funciones no deben tener implementaciones idénticas
- ESLint (eslint-plugin-sonarjs) sonarjs/no-duplicate-string — Los literales de cadena no deben duplicarse
- ESLint (core) no-useless-constructor — Constructor vacío redundante / código repetitivo de paso directo
- ESLint (core) max-lines-per-function — Longitud de función inflada/verbosa (indicador parcial)