filefunc × Hono — El código que un agente lee de una vez: de 60 a 18 líneas

Si tu agente de código en un codebase grande sigue modificando lo que no debe, si al pedirle que lea un archivo te arrastra 19 funciones irrelevantes contaminando el contexto, si dudas de que convenciones como “1 archivo 1 concepto” sirvan realmente — aquí están los resultados de medirlo en un framework real de producción con 23k estrellas.

“¿No se multiplican demasiado los archivos?”

Es la pregunta que más recibo sobre filefunc. Si divides 186 archivos en 626, ¿no se vuelve inmanejable?

La respuesta está en Hono. Un framework web ultraligero que corre en Cloudflare Workers, Deno, Bun y Node.js. Más de 23k estrellas, más de un millón de descargas semanales en npm. Código de producción probado en el mundo real. Refactoricé este código con filefunc. 4419 tests, todos pasaron. (Puedes verificarlo directamente en el fork park-jun-woo/hono)

Los números

MétricaOriginalTras refactorización
Archivos fuente186626
Líneas totales24.65330.244
Violaciones filefunc3970
vitest pasados44194419
vitest fallidos44 (defectos preexistentes)
vitest omitidos3333

Los archivos se multiplicaron por 3,4. Las líneas crecieron un 23%. Las violaciones pasaron de 397 a 0. Ningún test se rompió — más exactamente, exactamente igual que en el original, 4 fallaron (defectos que ya existían antes). El incremento del 23% en líneas proviene de las anotaciones (//ff:func, //ff:what) y los re-export hub. La lógica no cambió ni una línea. Refactorización puramente estructural.

La clave no es el número de archivos sino la ’longitud de lectura'

“0 violaciones, 626 archivos” es en realidad un proxy. El propósito real de filefunc no es fragmentar archivos — es lograr que cuando un agente lee un concepto, solo lea ese concepto, sin leer más de lo necesario. Por eso el número que hay que demostrar no es el recuento de violaciones sino la longitud de lectura por archivo. Lo medí.

Líneas por archivoOriginalTras refactorización
Mediana60,017,5 (−71%)
p90305119 (−61%)
Máximo2.7781.051 (−62%)
Proporción de archivos ≤20 líneas26%54%

Cuando un agente abre un concepto, antes consumía una media de 60 líneas; ahora consume 18. Incluso en el peor caso (p90), cayó de 305 a 120 líneas. La longitud de las funciones en sí permanece igual (mediana 11→12 líneas) — lógico: no se reescribieron las funciones, se reubicaron. Lo que se redujo es “el código circundante que hay que leer inevitablemente para acceder a un concepto”.

¿Por qué importa? El contexto largo no es gratuito. Los LLM pierden sistemáticamente información enterrada en el medio de entradas largas (Liu et al., Lost in the Middle, TACL 2023, arXiv:2307.03172). En tareas de código, el rendimiento cae en picado al crecer el contexto — en un benchmark, la precisión de Claude 3.5 Sonnet se desplomó del 29% al 3% (Rando et al., LongCodeBench, 2025, arXiv:2505.07897). Y entregar exactamente la parte necesaria por unidad conceptual en lugar de archivos enteros mejora más la calidad del completado de código (Yusuf et al., 2025, arXiv:2510.06606). Reducir la longitud de lectura no es cuestión de estética — es defensa de la precisión.

El problema de types.ts

Veámoslo en concreto, no en abstracto. El src/types.ts original de Hono contenía más de 20 interfaces y tipos.

¿Qué pasa cuando un agente de IA hace read de este archivo para encontrar el tipo HonoRequest? Le llegan arrastrados 19 tipos innecesarios. Contaminación del contexto.

Tras la refactorización, cada tipo vive en un archivo independiente. Si solo se necesita HonoRequest, basta con leer hono_request.ts. El types.ts original se conserva como re-export hub para preservar las rutas de importación existentes.

# Original
import { HonoRequest } from './types'  // arrastran 20+ tipos

# Tras refactorización
import { HonoRequest } from './types'  // misma ruta, mismo comportamiento
// internamente types.ts → re-export de hono_request.ts

Visto desde fuera, nada ha cambiado. Visto por un agente de IA, todo ha cambiado.

De profundidad 6 a 2

El algoritmo de enrutamiento de Hono es complejo. El Node.search del trie-router tenía una profundidad de anidamiento de 6.

for → if → if → for → if → if   // profundidad 6

¿Es mala práctica una profundidad 6? No. La búsqueda en trie es inherentemente profunda. Pero para que un agente de IA entienda esta función tiene que meter en la cabeza 6 niveles de anidamiento a la vez. Igual que una persona. filefunc extrajo la lógica interna en métodos privados y funciones flecha a nivel de módulo. Profundidad 6 → 2. Cada pieza tiene un único flujo de control. El algoritmo completo es idéntico.

# Original: search monolítico
Node.search()   // profundidad 6, 100+ líneas

# Refactorizado: descompuesto en piezas
Node.search()           // profundidad 2, solo composición
  → matchParam()        // profundidad 1, coincidencia de parámetros
  → matchWildcard()     // profundidad 1, manejo de wildcards
  → mergeHandlers()     // profundidad 1, fusión de handlers

La F1 de TypeScript, y la cola honesta

La regla central F1 de filefunc es “un archivo, una función”. En Go es intuitivo. Pero en TypeScript fragmentar archivos rompe el sistema de módulos. Extraer métodos de clase a archivos externos hace desaparecer el binding de this. Por eso el parser TypeScript de filefunc (ts_ast.js) solo cuenta las declaraciones function y no cuenta las const arrow functions. El principio es “un archivo, un concepto”, no “exactamente una function a nivel sintáctico”.

Aquí hay que ser honesto. Este enfoque separó limpiamente los casos fáciles (tipos, helpers individuales), pero no logró separar todo. Si medimos de nuevo el resultado tras refactorizar:

  • De los 626 archivos, el 90% (566) tienen ≤1 función — cumplen “1 archivo, 1 concepto”. (El original era el 70%.)
  • Pero 60 archivos (9,6%) siguen alojando 2 o más funciones juntas. Y justo esos son los largos — la mediana de líneas de esos 60 es 151. Por ejemplo, src/utils/url.ts tiene 14 funciones en 319 líneas.

Es decir, la técnica de las const arrow pasa el contador pero logra el objetivo solo parcialmente. Si en un archivo quedan varias funciones flecha, el agente que abre ese archivo seguirá leyendo varios conceptos. En el momento en que la métrica se convierte en el objetivo, la métrica se corrompe (Goodhart). filefunc no es una excepción — la mayor parte del riesgo de read-length restante se concentra en ese 10% de cola. No elevar el número “0 violaciones” a respuesta definitiva, sino medir también lo que aún falta — eso es verificación.

“¿Y en qué mejora concretamente?”

Con 626 archivos, una persona puede sentirse incómoda. Abre el directorio y se derrama una avalancha de archivos. Pero un agente de IA no abre directorios. Hace grep.

rg '//ff:func' --glob '*.ts' -l | head -20    # extraer archivos candidatos
rg '//ff:what.*router' --glob '*.ts'            # solo funciones relacionadas con el router

Si 186 archivos contienen una media de 3-4 funciones cada uno, grep encuentra el archivo pero al leerlo arrastran funciones innecesarias. Si 626 archivos contienen 1 concepto cada uno, el archivo que grep encuentra = el concepto que se necesita. Desaparece el paso intermedio. “Localizar la posición relevante” es el cuello de botella en la resolución de problemas posteriores en la exploración de código por agentes (Chen et al., LocAgent, 2025, arXiv:2503.09089), y filefunc hace esa búsqueda determinista al alinear concepto con frontera de archivo.

¿La unidad función es siempre la respuesta?

Miremos la evidencia contraria también con honestidad. Un experimento controlado reporta que “el chunking por función en autocompletado de código RAG es 3,6–5,6 pp inferior a otras estrategias y no es Pareto-óptimo” (Wu et al., 2026, arXiv:2605.04763). La unidad función no lo es todo.

Sin embargo, es un argumento en otra capa. Ese experimento trata de la autocompletación donde el recuperador trocea el código para meterlo en el prompt. filefunc no trata de cómo el recuperador crea chunks, sino de la unidad operativa que un agente elige y lee directamente. Estrategia de chunking (retrieval chunk) y unidad operativa (archivo que un agente abre) son capas distintas. Aun así es importante explicitar esta distinción — “fragmentar más siempre es mejor” no es la afirmación de filefunc. La afirmación es “cuando la unidad que un agente lee coincide con el concepto, la longitud de lectura se acorta”, y los números anteriores lo demuestran.

La restricción es libertad

Refactorizar Hono con filefunc confirmó una sola cosa.

La restricción estructural no limita el código. Libera la exploración.

Multiplicar los archivos tiene un coste. Pero cuando cada archivo contiene un solo concepto, el agente lee exactamente lo que necesita sin contaminarse de contexto innecesario — la medición que muestra una reducción de 60 a 18 líneas es la prueba. Lo mismo vale para las personas. Cuando el nombre de la función es el nombre del archivo, el directorio se convierte en un índice.

Que 397 violaciones se conviertan en 0, que 4419 tests pasen de forma idéntica al original. Y que cualquiera pueda repetir el experimento desde el informe de refactorización del README. Esta es la prueba de que “1 archivo, 1 concepto” no es teoría sino práctica. Incluyendo el 9,6% de cola que queda.

Artículos relacionados

Lecturas recomendadas (externas)

  • Effective context engineering for AI agents — Anthropic. Identifica “context rot” y el presupuesto de atención finito como problema central — el mismo fundamento por el que filefunc reduce el contexto innecesario.
  • Strategies and Tactics for working with Coding Agents — Brian Kihoon Lee. Argumenta diseñar manualmente la arquitectura de información y la exploración basada en grep — directamente relacionado con convenciones de estructura de archivos que hacen que el agente “lea solo el objetivo”.
  • The Vibes Don’t Scale — Paul Stack. El mecanismo por el que el vibe coding colapsa en deriva arquitectónica a escala — la conciencia del problema que filefunc busca resolver: “los codebases grandes rompen a los agentes”.
  • Agentic Engineering Patterns — Simon Willison. Patrones de gestión de contexto como Context Quarantine/Pruning — extiende la afirmación agent-operable de filefunc al lenguaje de patrones prácticos.
  • Agent Harness Engineering — Addy Osmani. El rendimiento del agente se decide más en la infraestructura circundante que en el modelo — recontextualiza las convenciones de estructura de código como un eje del harness.

Bibliografía

  • Liu et al. “Lost in the Middle: How Language Models Use Long Contexts” (TACL 2023, arXiv:2307.03172)
  • Rando et al. “LongCodeBench: Evaluating Coding LLMs at 1M Context Windows” (2025, arXiv:2505.07897)
  • Yusuf et al. “Beyond More Context: How Granularity and Order Drive Code Completion Quality” (2025, arXiv:2510.06606)
  • Chen et al. “LocAgent: Graph-Guided LLM Agents for Code Localization” (2025, arXiv:2503.09089)
  • Wu et al. “How Does Chunking Affect Retrieval-Augmented Code Completion? A Controlled Empirical Study” (2026, arXiv:2605.04763)
  • Verificación del resultado de refactorización: park-jun-woo/hono (filefunc Refactoring Report en el README) · Convención: filefunc
  • Imagen principal: generada por IA (Google Gemini)