Abrís un pull request de casi cuatro mil líneas. Lo generó un agente, con muy buena letra, tests incluidos y un mensaje de commit que da gusto leer. Adentro hay un selector de fechas hecho a mano, un validador de emails escrito desde cero, un pequeño sistema de colas para mandar correos y una función para formatear moneda que, a simple vista, funciona. Todo eso tiene alternativas maduras, muchas a un npm install de distancia. Y ahí estás vos, con el mate frío, tratando de comprobar si el selector de fechas sabe que febrero a veces trae 29 días.
El camino hacia un código más controlable y legible vuelve a pasar por algo conocido: módulos que puedan ser reutilizados, configurados y combinados. Sí, ya sé lo que estás pensando: ¿te volviste loco, Fabi? Si hoy el código es lo más barato que hay, ¿por qué no hacer todo desde cero?
Justamente por eso. Porque cuando algo se vuelve barato, el costo no desaparece: se muda. Herbert Simon lo planteó hace más de cincuenta años, cuando advirtió que la abundancia de información genera pobreza de atención. Cambiá "información" por "código" y tenés una buena descripción de lo que nos está pasando. Podemos generar en minutos una cantidad de código que nos lleva días entender y validar, y alguien tiene que hacerse responsable de que eso haga lo que tiene que hacer, respete los límites del sistema y se pueda mantener cuando cambien las condiciones.
Si usamos componentes probados para las tareas comunes, reducimos buena parte de esa carga y llevamos la atención a donde realmente importa: a elegir bien las piezas, a comprobar cómo encajan y a verificar el comportamiento que necesita nuestro negocio. Porque una parte enorme de cualquier sistema está hecha de problemas conocidos: formularios, validaciones, correos, archivos, autenticación, comunicaciones internas. La experiencia que construís con esas piezas puede ser diferencial, pero escribir desde cero el mecanismo que valida un email rara vez es lo que hace que un cliente te elija.
El valor suele estar en la regla de negocio que solo tu empresa entiende, en cómo conectás esas capacidades, en el flujo que tus clientes aman sin saber bien por qué. Y sin embargo, ahí estamos, gastando la atención más cara del equipo en revisar otra implementación de algo que ya estaba resuelto.
La idea tiene historia. En 1968, en la conferencia de la OTAN que ayudó a popularizar la expresión "ingeniería de software", Doug McIlroy propuso componentes de software producidos en masa, catalogados y combinables, algo parecido a lo que hacemos con los tornillos de una ferretería. Décadas después tenemos frameworks, librerías, gestores de paquetes y ecosistemas enteros de componentes reutilizables, con sus problemas, por supuesto, pero también con una cantidad enorme de trabajo acumulado. Y ahora que los agentes pueden producir código a una velocidad impresionante, resulta tentador volver a fabricar cada tornillo.
Muchas veces eso ni siquiera nace de una decisión de arquitectura. El prompt dice "hacé esto" o "hacé aquello", y el agente, si no tiene instrucciones ni contexto suficientes, tiende a recrear lo que ya existe. Entrega algo que parece razonable, los tests pasan y seguimos. La reinvención se parece mucho a la productividad cuando mirás solamente lo que salió: más código, más funcionalidades cerradas, más PRs mergeados. Ronald Coase explicaba que la frontera de una empresa se dibuja donde hacer adentro sale más barato que comprar afuera, y los agentes corrieron esa frontera de golpe: hacer adentro parece gratis. La cuenta cambia cuando incluís lo que después hay que comprender, verificar, operar y mantener. Cada comportamiento nuevo agrega una responsabilidad, y cada selector de fechas artesanal puede convertirse en algo que vas a tener que debuggear un 29 de febrero a las tres de la mañana.
Y hay algo más. Un módulo que lleva años en producción puede tener cicatrices valiosas: el bug que apareció con un calendario distinto, el parche para el navegador que todavía usa tu cliente más importante, la discusión de cuarenta comentarios sobre cómo manejar zonas horarias. Recrear su funcionalidad visible no te entrega esa experiencia acumulada. Podés generar en segundos algo que se parece mucho al resultado sin haber recuperado las razones por las que terminó siendo así. Polanyi decía que sabemos más de lo que podemos decir, y buena parte de ese saber vive justamente en esas decisiones que nadie terminó de documentar.
Ahora, tampoco te estoy proponiendo que instales lo primero que aparezca en una búsqueda. Las dependencias tienen su propia cuenta: mantenimiento, compatibilidad, licencias, vulnerabilidades, actualizaciones y, a veces, una complejidad desproporcionada para lo que necesitás. Hay funciones de veinte líneas que conviene escribir y mantener uno mismo, y hay bibliotecas que te ahorran años de problemas. El criterio está en comparar el costo completo de construir, integrar, verificar y sostener cada alternativa, porque reutilizar también exige hacerse cargo de la elección.
Entonces, ¿qué hacemos? Podemos empezar por algo bastante concreto: un catálogo pequeño de componentes aprobados, con ejemplos de uso, configuraciones, límites conocidos y tests. Piezas que el equipo entienda y que los agentes puedan encontrar y usar. El prompt puede dejar de decir solamente "hacé un formulario de alta de clientes" y empezar a decir "armalo con nuestros componentes de formulario y validación; si falta una capacidad, señalá el faltante y justificá cómo proponés resolverlo". Eso cambia la conversación: el código nuevo pasa a ser una decisión que podemos evaluar, y los reviews dedican más atención a la composición, a qué piezas elegimos, qué supuestos comparten, dónde están los límites y qué pasa cuando alguna falla.
Los tests tienen que acompañar ese cambio. Los de integración importan porque dos piezas probadas pueden fallar al juntarse, pero también necesitamos criterios de aceptación que vengan del problema que queremos resolver. Si el agente interpreta mal una regla y escribe tanto la implementación como los tests desde esa misma interpretación, podemos terminar con todo en verde y el negocio mal resuelto. Alguien tiene que definir qué significa que funcione: quién puede hacer qué, qué datos pueden salir del sistema, qué ocurre si un servicio no responde, qué errores son tolerables y cuáles no. Esa sigue siendo una parte central del trabajo, y no se delega.
Esto también cambia tu rol si liderás. Asegurar que el equipo escriba buen código sigue importando, pero ahora, además, tenés que decidir cuánto código nuevo conviene incorporar y qué capacidad tiene la organización para hacerse responsable de él. Podés generar diez veces más y seguir teniendo las mismas personas para entender las decisiones, evaluar los riesgos y responder cuando algo se rompe. La producción creció; la capacidad de hacerse cargo, quizás no. Ahí aparece una medida de productividad que me interesa bastante más: cuánto valor podemos entregar con una complejidad que todavía podamos manejar.
La arquitectura va a seguir tomando forma prompt a prompt, PR a PR. Los componentes disponibles, las instrucciones que reciben los agentes y las decisiones que aprobamos van a definir si terminamos con un sistema comprensible o con mil ruedas distintas, cada una girando a su manera.
Por eso, la próxima vez que te llegue el PR enorme con todos los tests en verde, la pregunta no es solo si funciona, sino cuánto de eso necesitaba existir. Y acordate: no hay código más barato que el que no necesitás hacer ni mantener.
Autor: Fabi Mesaglio


No hay comentarios:
Publicar un comentario