AI en el desarrollo de software: ¿para quién es el código que ya no escribimos?
El impacto de la inteligencia artificial en el desarrollo de software y cómo afecta las buenas prácticas y los patrones de diseño creados inicialmente por y para humanos.
Durante años, muchas de las buenas prácticas del desarrollo de software se justificaron desde una idea bastante humana: el código tenía que ser entendible para nosotros.
Separábamos responsabilidades porque no podíamos sostener todo el sistema en la cabeza al mismo tiempo. Creábamos abstracciones para no repetirnos. Encapsulábamos detalles de infraestructura para poder enfocarnos en la lógica de negocio. Diseñábamos límites entre capas para que una persona pudiera leer, modificar y mantener una parte del sistema sin tener que comprenderlo todo.
Pero en debates recientes con amigos y colegas del industria, surgió la idea de que la llegada de la inteligencia artificial como herramienta de desarrollo empieza a incomodar esa explicación.
Si la AI puede leer cientos de archivos en segundos, detectar usos repetidos, modificar múltiples lugares a la vez, escribir tests, revisar código, explicar errores, proponer refactors y eventualmente quizás operar parte del ciclo completo de desarrollo, entonces aparece una pregunta incómoda:
¿Siguen teniendo sentido las abstracciones, los patrones y las buenas prácticas si el principal consumidor del código ya no es solamente un humano?
Personalmente, creo que la respuesta es sí. Pero no por las mismas razones de siempre.
La AI reduce el costo de escribir código, pero no elimina el costo de diseñar sistemas
Una idea es que ciertos principios clásicos, como DRY (Don’t Repeat Yourself), empiezan a perder valor. El argumento suele ser más o menos así:
“Antes no queríamos código duplicado porque después había que cambiarlo manualmente en muchos lugares. Ahora una AI puede buscar todas las ocurrencias, modificarlas y ajustar los tests. Entonces duplicar código ya no importa tanto.”
Somos conscientes de que la AI efectivamente reduce el costo mecánico de editar código. Cambiar cinco funciones similares, actualizar diez archivos, generar una migración o adaptar una firma repetida en varios servicios es mucho más barato que antes.
Pero esa visión confunde el costo de edición con el costo de diseño.
DRY nunca fue solamente “no escribir lo mismo dos veces”. En su versión más importante, DRY significa que una regla, una decisión o un concepto del negocio debería tener una representación autoritativa dentro del sistema.
No es lo mismo duplicar una condición simple como:
if (amount <= 0) {
throw new InvalidAmountError();
}
que duplicar una regla de negocio como:
const shouldCompleteTransaction =
blockchainStatus === 'COMPLETED' &&
kytStatus === 'PASSED' &&
approvalStatus === 'APPROVED';
La primera duplicación puede ser tolerable. La segunda representa conocimiento del dominio. Si esa regla aparece en un webhook, en un cron job, en una acción de backoffice y en una API pública, el problema no es solamente que haya que editar cuatro lugares cuando cambie. El problema es que el sistema ya no tiene un único dueño para la idea de “transacción completada”.
La AI puede ayudar a encontrar todas las copias. Pero no siempre puede garantizar que esas copias signifiquen exactamente lo mismo, que pertenezcan al mismo contexto, o que deban evolucionar juntas.
Por eso, en un mundo con AI, la pregunta no debería ser “¿hay código repetido?”. La pregunta debería ser: “¿Estamos duplicando mecánica o estamos duplicando significado?”. La duplicación mecánica importa menos que antes. La duplicación conceptual sigue siendo peligrosa.
Las abstracciones débiles sí se vuelven obsoletas
La AI deja en evidencia algo que ya era cierto antes de su llegada: muchas abstracciones existen sin una razón fuerte.
Capas que solamente reenvían llamadas. Interfaces con una sola implementación y ninguna intención de reemplazo. Repositories que envuelven un CRUD trivial sin proteger ningún límite real. Services, Managers, Handlers, Processors y UseCases que no agregan significado, sino solamente distancia.
Ese tipo de abstracción se justificaba muchas veces con frases como “así queda más ordenado” o “así seguimos Clean Architecture”. Pero si la abstracción no protege una regla, no define una frontera, no impone una dependencia, no encapsula una política y no reduce un riesgo real, entonces probablemente sea parte de la decoración.
Y la AI hace que la decoración sea todavía menos defendible.
Si una herramienta puede generar, navegar y modificar código repetitivo con facilidad, entonces las abstracciones cuyo único propósito era hacer más cómoda la navegación humana pierden fuerza. No desaparecen todas, pero sí se vuelven más sospechosas.
En ese sentido, la AI no mata las buenas prácticas. Mata las malas justificaciones. No alcanza con decir “esto está abstraído”. La pregunta importante es: “¿Qué decisión protege esta abstracción?”.
Si la respuesta es “ninguna”, quizás no debería existir. Personalmente, ya comulgaba con esta idea antes de la llegada de la AI. La inteligencia artificial solo reforzó mi opinión.
Las fronteras fuertes no son ayudas visuales: son restricciones del sistema
El argumento más interesante que escuché en contra las abstracciones dice algo así:
“El objetivo de separar base de datos, lógica de negocio, transporte e infraestructura era ayudar a los humanos a enfocarse en una cosa a la vez. Pero si la AI puede entender todo el sistema, esas fronteras dejan de ser necesarias.”
Esa crítica tiene sentido si uno piensa las fronteras solamente como una herramienta de comprensión. Pero las buenas fronteras no existen solo para que el código sea más fácil de leer. Existen para limitar lo que el sistema puede hacer.
Una frontera puede expresar reglas como:
- “Esta parte del sistema puede hablar con Postgres.”
- “Esta parte puede interpretar payloads externos.”
- “Esta parte es la única autorizada a mutar balances.”
- “Esta parte contiene la máquina de estados de una transacción.”
- “Esta parte emite eventos solo después de persistir cambios correctamente.”
Eso no es simplemente organización. Eso es diseño.
Hay una diferencia enorme entre un sistema donde una AI puede detectar una violación a una regla y un sistema donde la arquitectura hace que esa violación sea difícil o imposible.
Por ejemplo, podríamos tener lógica de balances distribuida por todo el código:
await db.accountBalances.update({
accountId,
instrumentId,
balance: currentBalance + amount,
});
Una AI suficientemente poderosa podría encontrar todos esos lugares, revisarlos y detectar inconsistencias. Pero el sistema seguiría permitiendo que cualquier parte modifique balances directamente.
En cambio, si existe una frontera clara:
interface LedgerService {
applyMovement(command: ApplyMovementCommand): Promise<ApplyMovementResult>;
}
entonces la arquitectura expresa una restricción: “Los balances solo se modifican aplicando movimientos.”
Esa frontera vale aunque una AI escriba el código. Vale porque reduce el espacio de estados inválidos. Vale porque transforma una convención en una estructura.
Lo mismo ocurre con una máquina de estados:
const nextState = transactionStateMachine.apply(currentState, event);
La importancia no está en que sea más fácil de leer. La importancia está en que todas las transiciones pasan por un punto canónico. El sistema ya no depende de que cada handler recuerde implementar la regla correctamente.
La AI puede escribir el código, pero el sistema sigue necesitando invariantes
La idea de que “la AI puede manejar todo” suele asumir que el problema principal del software es modificar texto. Pero el software no es solamente texto. Es un conjunto de decisiones sobre reglas, dependencias, efectos colaterales, fallos posibles, ownership y evolución.
Una AI puede generar un adapter. Pero alguien, o algo, tiene que decidir dónde termina la semántica del proveedor externo y dónde empieza el dominio interno.
Una AI puede escribir un repository. Pero el sistema tiene que decidir si la lógica de negocio puede conocer SQL, locks, índices, transacciones y detalles de persistencia.
Una AI puede escribir tests. Pero alguien tiene que decidir qué propiedades del sistema deben permanecer verdaderas y qué debe ser mockeado.
Una AI puede actualizar todos los usos de una función pero eso no reemplaza la necesidad de definir cuál es el único lugar donde vive una regla de negocio.
Esto se vuelve especialmente importante en sistemas donde los errores no son baratos: finanzas, ledger, transacciones cripto, estados distribuidos, idempotencia, concurrencia, seguridad, integraciones externas y procesos asincrónicos.
En esos contextos, las buenas abstracciones no son decoración. Son barreras de contención.
No existen para que el código se vea más limpio. Existen para que el sistema tenga menos formas de romperse.
El código ya no es solo para humanos, pero tampoco debería ser solo para AI
Durante mucho tiempo dijimos que “el código se lee más de lo que se escribe”. Esa frase probablemente sigue siendo cierta, pero quizás necesita una actualización: el código ahora también es leído, interpretado y modificado por modelos.
Eso cambia algunas prioridades. Tal vez dejemos de valorar tanto las abstracciones que solo ayudaban a navegar archivos. Tal vez aceptemos más duplicación local cuando sea más clara que una abstracción prematura. Tal vez escribamos menos boilerplate a mano. Tal vez los patrones de diseño importen menos como recetas y más como lenguaje de intención.
Pero que la AI sea un nuevo consumidor del código no significa que el código deba convertirse en una masa amorfa que solo una AI puede operar.
Incluso si en el futuro la AI revisa, debuggea, despliega y responde incidentes, el sistema sigue beneficiándose de restricciones explícitas. Una AI puede razonar sobre un sistema acoplado, pero eso no vuelve bueno al acoplamiento. Una AI puede seguir rastros en código duplicado, pero eso no crea una fuente única de verdad. Una AI puede detectar una dependencia peligrosa, pero eso no reemplaza una arquitectura que la prohíbe.
La inteligencia, humana o artificial, no elimina la necesidad de una estructura explícita y clara.
De hecho, cuanto más rápido se puede generar código, más importante se vuelve que existan límites claros sobre dónde puede vivir cada decisión.
El nuevo criterio: menos decoración, más intención
La llegada de la AI no debería llevarnos a abandonar patrones de diseño, principios y abstracciones. Debería obligarnos a justificarlos mejor.
Antes podíamos aceptar una abstracción porque “ayuda a ordenar”. Ahora esa explicación es débil.
Una abstracción debería poder defenderse con algo más concreto:
- “Esta frontera impide que la lógica de dominio dependa del motor de base de datos.”
- “Esta interfaz permite cambiar de proveedor sin contaminar el flujo principal.”
- “Esta máquina de estados centraliza las transiciones válidas.”
- “Este servicio es el único lugar donde se mutan balances.”
- “Este mapper evita que payloads externos entren crudos al dominio.”
- “Este outbox asegura que los eventos se publiquen después del commit.”
Ese tipo de límite sigue siendo valioso en un mundo con AI. Quizás más valioso, no menos.
En cambio, si las justificaciones son algunas de las siguientes:
- “Porque así queda más enterprise.”
- “Porque siempre usamos repositories.”
- “Porque Clean Architecture dice que va una interfaz acá.”
- “Porque tal vez algún día haya otra implementación.”
- “Porque no quiero repetir tres líneas.”
entonces probablemente la AI nos empuje a eliminarlo.
Y eso es bueno.
En pocas palabras
La AI cambia profundamente la forma en que desarrollamos software. Reduce el costo de escribir código, de modificarlo, de explorarlo y de generar alternativas. También vuelve menos valiosas algunas habilidades mecánicas que antes ocupaban una gran parte del trabajo diario.
Pero no vuelve obsoleto el diseño.
Lo que sí vuelve obsoleto es el diseño performativo: patrones usados como decoración, abstracciones sin fuerza, capas que no protegen nada, DRY aplicado a similitudes superficiales y arquitecturas copiadas sin entender qué problema resuelven.
El código que ya no escribimos manualmente igual necesita expresar intención.
Necesita decir qué reglas son importantes. Qué dependencias están permitidas. Qué estados son válidos. Qué partes del sistema pueden producir efectos. Qué conceptos pertenecen al dominio y cuáles son detalles externos. Si esto no es explícito, la AI puede generar código que no cumpla con las reglas del sistema, el AI-slop en el código existe, es real, potencialmente afecta la seguridad y la escalabilidad del sistema y genera un efecto bola de nieve porque retroalimenta a los modelos que continuan trabajando sobre el slop generando aún más slop.
Tal vez en el futuro la AI escriba la mayor parte del código. Tal vez también revise, debuggee, despliegue y opere sistemas completos.
Pero incluso en ese escenario, la pregunta central no desaparece. No es “¿puede la AI entender este código?”
La pregunta es: “¿Este sistema hace explícitas las reglas que no podemos permitirnos romper?”
Ahí es donde las buenas abstracciones, patrones de diseño y principios siguen teniendo sentido. No porque los humanos sean incapaces de entender todo. Sino porque los sistemas correctos no deberían depender de que alguien, humano o AI, recuerde y/o revise todo cada vez.