Logotipo de ConstructiCat
CodeBust.
Explorar la sección ▾

Código repetitivo verboso.

Los asistentes de IA rellenan lógica sencilla con comentarios que repiten cada línea, narración paso a paso, escaleras defensivas de comprobaciones de null y expresiones largas donde bastaría un modismo del lenguaje o un helper existente, inflando el número de líneas sin añadir comportamiento.

##Signos y síntomas

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. Otras señales: constructores o envoltorios vacíos que solo delegan, la ceremonia try { ... } catch (e) { throw e }, x ? x : fallback donde bastaría ??, y un validador de email/URL hecho a mano junto al módulo de validación que el proyecto ya tiene. Cuando esa misma forma verbosa aparece además copiada como getDisplayName, getLabel y getInitials, cada una reimplementando lógica que ya cubre una utilidad formatName(), la verbosidad se ha convertido en Código Duplicado: consulta Duplicación en lugar de extracción.

##Causas del problema

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 el código circundante en el contexto, el modelo no puede saber que ya existe una utilidad formatName() o validateEmail(), así que vuelve a derivarla en línea. Encaja con dos patrones del informe de OX Security: la sobreespecificación (Over-Specification: "soluciones hiperespecíficas de un solo uso que no pueden adaptarse a otros fines", en el 80–90% del código de IA) y la evitación de refactorizaciones (Avoidance of Refactors, 80–90%).
  • Generación, no consolidación. Los agentes emiten código nuevo en cada prompt y rara vez vuelven para compactarlo. El análisis de GitClear de 2025 sobre 211 millones de líneas modificadas halló que las líneas asociadas a refactorización ("movidas") cayeron del 25% de las líneas cambiadas en 2021 a menos del 10% en 2024, mientras que las copiadas y pegadas subieron del 8,3% al 12,3% y en 2024 superaron por primera vez a las movidas; los bloques con cinco o más líneas duplicadas se multiplicaron aproximadamente por ocho durante 2024.
  • 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 acaban induciendo a error (el olor Comentarios de Fowler).
  • Corrección y seguridad: en cuanto un bloque verboso se copia, un fallo o una vulnerabilidad debe corregirse en N sitios: el patrón Bugs Déjà-Vu de OX (70–80%), que hace que "los mismos fallos aparezcan una y otra vez en el código y requieran la misma corrección varias veces".
  • 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.

##Tratamiento

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/ruff y una pasada de duplicación con jscpd, 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 función compartida y llámala" (Extraer método).
  • Consolida en la revisión: cuando veas la tercera casi-copia, aplica Extraer método, Subir Método o Consolidar fragmentos condicionales duplicados; donde un comentario solo explica qué hace una expresión, aplica Extraer Variable o Renombrar método para que sea el código el que lleve la explicación y el comentario pueda desaparecer.

Refactorización (antes → después)

// después: comentarios eliminados (el código se explica solo), ceremonia colapsada,
// y se reutiliza la utilidad formatName() existente en vez de rederivarla en línea
import { formatName } from "@/utils/format";

export const getFullName = (user?: User): string =>
  formatName(user?.firstName, user?.lastName);

Y elimina los duplicados de raíz: si getDisplayName/getLabel hacían lo mismo, dirige a quienes las llaman a una sola función y borra las copias (Método en Línea); lo que quede sin llamadas es Código muerto y también sobra. 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.

##Detectado por

  • ESLint (core) no-useless-catch — Cláusulas catch innecesarias (ceremonia de capturar y relanzar: catch (e) { throw e })
  • ESLint (core) no-unneeded-ternary — Operadores ternarios donde existe una alternativa más simple (con defaultAssignment: false detecta x ? x : fallback)
  • typescript-eslint @typescript-eslint/prefer-nullish-coalescing — Preferir ?? frente a || y a ternarios con comprobación explícita de null
  • 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)
  • jscpd --min-tokens / --threshold — Detección de copiar/pegar, para cuando los bloques verbosos se copian y pegan (umbral --min-tokens / --threshold)
  • SonarQube / SonarCloud typescript:S4144 — Las funciones y los métodos no deben tener implementaciones idénticas
  • ESLint (eslint-plugin-sonarjs) sonarjs/no-identical-functions — Las funciones no deben tener implementaciones idénticas