8 puntos por GN⁺ 2025-08-15 | 2 comentarios | Compartir por WhatsApp
  • Los ingenieros de software efectivos construyen y mantienen un modelo mental claro de los requisitos y del código, y ejecutan un ciclo de comparación y actualización de forma repetida
  • Los LLM pueden escribir y modificar código, crear pruebas y depurar, pero carecen de la capacidad de mantener un modelo mental preciso, por lo que se confunden en tareas complejas
  • Actualmente, los LLM tienen limitaciones para identificar con precisión las diferencias entre el código y los requisitos y corregirlas adecuadamente debido a problemas de omisión de contexto, sesgo de recencia y alucinaciones
  • Las personas pueden cambiar su forma de pensar con flexibilidad según la situación, por ejemplo almacenando temporalmente el contexto completo o escondiendo por un momento los detalles para ver el panorama general, pero los LLM no pueden implementar esto
  • Los LLM son útiles para tareas con requisitos simples, pero en el desarrollo de software complejo, al final el ingeniero de software debe responsabilizarse directamente de la claridad de los requisitos y del comportamiento del código, y el LLM cumple el papel de herramienta de apoyo

El ciclo de la ingeniería de software

  • Un ingeniero experimentado trabaja repitiendo los siguientes pasos
    1. Construir un modelo mental de los requisitos
    2. Escribir código de acuerdo con ese modelo
    3. Entender lo que realmente hace el código escrito
    4. Identificar las diferencias y corregir el código o los requisitos
  • La clave de este ciclo es la capacidad de contar con un modelo mental preciso y sostenible

Las limitaciones de los LLM

  • Los LLM pueden realizar funciones como escribir código, identificar problemas y corregirlos, crear y ejecutar pruebas, agregar logging y usar un depurador
  • Sin embargo, como no pueden mantener un modelo mental, surgen problemas como los siguientes
    • Suponen que el código que escribieron funciona bien
    • Cuando una prueba falla, dependen de conjeturas para decidir si deben corregir el código o la prueba
    • Cuando se confunden, borran todo el código y lo reescriben desde cero
  • A diferencia de una persona, cuando una prueba falla les falta la flexibilidad para revisar el modelo y decidir la dirección de la corrección, o para destrabar el problema a través de la conversación cuando sienten frustración
  • Un ingeniero de software ejecuta pruebas durante el trabajo y, cuando aparece un problema, puede juzgar con claridad qué parte debe corregirse
  • A veces, incluso reiniciar todo el trabajo lleva a un resultado en el que la comprensión del problema se vuelve más profunda

Posibilidades futuras

  • Es posible que esto cambie a medida que los modelos mejoren, pero la ingeniería de software exige más que una simple generación de código
  • Cuando resuelven problemas importantes, los humanos pueden traer temporalmente a la memoria el contexto completo, concentrarse en un tema o mirar el panorama general
  • Lo importante no es seguir aumentando indefinidamente la información de contexto, sino una forma de pensar que trate de manera selectiva la información necesaria
  • Los LLM carecen de la capacidad de almacenar y recuperar contexto temporalmente como una persona, o de alternar entre el panorama general y los detalles al pensar
  • Restricciones principales de los LLM actuales
    • Omisión de contexto (Context omission): no detectan bien las partes donde falta información necesaria
    • Sesgo de recencia (Recency bias): dan un peso excesivo a la información más reciente dentro de la ventana de contexto
    • Alucinación (Hallucination): inventan detalles que no existen
  • Si se añaden funciones de memoria, algunas cosas podrían mejorar, pero al superar cierto nivel de complejidad siguen fallando en la comprensión del contexto y el mantenimiento del modelo
  • Les falta la capacidad de mantener dos modelos mentales similares, analizar sus diferencias y decidir dónde deben modificarse los requisitos o el código

El papel y uso actuales

  • Los LLM destacan en la generación rápida de código y en la integración de requisitos y documentación, por lo que pueden aprovecharse suficientemente en tareas simples y claras
  • Pero en problemas no triviales, es difícil mantener suficiente contexto y mejorar de forma iterativa
  • Por lo tanto, la clarificación de requisitos y la validación del código siguen siendo responsabilidad del ingeniero de software
  • Se busca un entorno en el que las personas y los agentes (LLM) creen software juntos, pero en el momento actual el ingeniero debe liderar y el LLM debe usarse como herramienta

2 comentarios

 
kandk 2025-08-18

Por qué los LLM "actuales"...

 
GN⁺ 2025-08-15
Opiniones en Hacker News
  • No resolvemos los problemas simplemente metiendo más palabras en la ventana de contexto; si lo hiciéramos, perderíamos la cordura.
    Tampoco vemos los problemas solo como texto cuando aparecen.
    Si sale un error de autenticación en el depurador, no pensamos algo como: “¿Y si simplemente eliminamos la validación del token en el código?”.
    En realidad damos un paso atrás para ver la situación completa y entender la causa raíz del problema.
    Por ejemplo, si aparece un error de autenticación, volvemos a revisar todo el proceso de validación del token o los permisos del usuario que hace la llamada, y podemos llegar a darnos cuenta de que la prueba en sí estaba mal.
    En ese proceso, en lugar de solo quitar el error, también descubrimos que hace falta distinguir con más detalle si un 401 se debe simplemente a falta de autenticación o a falta de permisos, por ejemplo.
    Véase Grugbrain.dev

    • Creo que los programadores se dedican a traducir reglas de negocio a una forma estricta que la computadora pueda entender.
      Como hay que entender al mismo tiempo qué significan esas reglas y cómo funciona la computadora —o el framework y las capas de abstracción que se usan—, el proceso de traducción no siempre es sencillo.
      Sobre todo cuando un requisito nuevo rompe todos los supuestos anteriores o entra en contradicción con ellos, no queda más remedio que rehacerlo varias veces.
      Incluso la traducción entre lenguajes humanos es ambigua y compleja; como la computadora ejecuta exactamente lo que le dices, hasta un error pequeño puede convertirse en un gran problema.

    • Personalmente creo que un enfoque realista es aquel donde el humano participa siempre de forma iterativa.
      Como con ese método puedo trabajar más rápido y con mejor calidad, lo sigo usando.

    • Yo personalmente sí puedo cargar en mi cabeza grandes cantidades de contexto.
      El texto del código en sí se descarta enseguida, y mi cerebro lo parsea como una estructura parecida a un AST (árbol de sintaxis abstracta), o incluso como un grafo espacial.
      Modelo el programa en sí de forma lógica y lo percibo como una estructura totalmente separada del texto.
      Desde esa perspectiva, los LLM no entienden la estructura del software porque solo se enfocan en el texto y no logran construir un modelo lógico del programa.
      Diseñar la arquitectura de sistemas grandes, que requiere pensamiento abstracto, demanda muchísimo esfuerzo mental, pero los LLM carecen de esa capacidad de abstracción.

    • Mi método es el siguiente.
      Cuando se reporta una prueba fallida, primero identifico el componente en cuestión y analizo a fondo su propósito, su flujo de control interno, los cambios de estado y hasta los supuestos sobre el contexto alrededor, y lo organizo en un resumen Markdown (<nombre-del-componente>-mental-model.md).
      Después, siempre consulto ese modelo mental cuando trato problemas de pruebas.
      Si pegas ese análisis en un prompt de Claude, el LLM puede dar mejores resultados.
      Incluso puedes leer y corregir directamente el modelo mental que construyó el LLM.

    • La IA también puede aconsejarte usar 403 en lugar de 401 cuando el problema es falta de permisos.

  • Parece que el autor del artículo no entiende bien las capacidades actuales de los LLM y las herramientas de programación.
    La afirmación de que, cuando falla una prueba, el LLM solo adivina si el código está bien o si la prueba está mal, y que cuando se frustra termina borrando todo el código, no coincide con lo que yo he visto en la práctica.
    Los ingenieros de software siempre identifican de manera concreta la causa de una prueba fallida según el modelo mental que tienen en la cabeza.
    Yo desarrollo con TDD en Rails usando Cline y Anthropic Sonnet 3.7, y siempre hago que el LLM escriba primero las pruebas y luego el código.
    Divido el trabajo en unidades pequeñas para poder revisar cada parte, y cuando falla una prueba suele razonar bastante bien qué parte hay que corregir y la arregla correctamente.
    Los LLM no son perfectos, pero muchas veces dan resultados comparables o incluso mejores que los de un ingeniero junior humano.
    A veces no logran arreglar un bug, pero a los desarrolladores novatos humanos también les pasa.

    • Los LLM funcionan especialmente bien en trabajo CRUD dentro de frameworks consolidados como Rails.
      En cambio, cuando intenté hacer una app nativa de Windows con Direct2D y Rust, fue pésimo.
      Ojalá hubiera evaluaciones más abiertas para distintos casos.

    • Es un fenómeno muy conocido que los modelos usan atajos y trucos, como hardcodear, para hacer pasar pruebas que están fallando.

    • En mi experiencia, la variación según el lenguaje, la plataforma y el dominio es enorme.
      Últimamente ni yo mismo he trabajado con Ruby, así que no he probado con Rails, pero Rails tiene una cultura de programación tan consistente que parece un área donde un LLM podría rendir razonablemente bien.
      En cambio, con Python hay tantos estilos de código mezclados que muchas veces el LLM terminaba combinando varios patrones y las pruebas se volvían inestables.
      Había que cambiar el código repetidamente, y aunque el error real fuera “falta ordenar el resultado de la consulta”, el LLM salía con cosas raras como recomendar quitar SqlAlchemy y cambiar todo a Django.
      En R, conseguir código que simplemente funcione según la especificación ya es bastante difícil.

    • Si limitamos al LLM al nivel de un ingeniero junior, entonces realmente encuentra y aplica soluciones muy rápido, sobre todo para problemas que ya ha visto.
      En cambio, para problemas que no ha visto, el LLM necesita más explicación e instrucciones; en esos casos, mi papel termina siendo el de mentor.
      En nuestro equipo usamos mucho el enfoque “claude-code” para refactorizaciones simples que llevaban mucho tiempo en el backlog o para tareas repetitivas bien conocidas, como sistemas de análisis secundario.
      Personalmente, me gusta arrastrar un bloque de código y pedir cosas como “explícamelo como si tuviera 5 años” o “encuentra si hay riesgo de race condition”.
      Como el código generado suele diferir del código y el estilo ya existentes, muchas veces tengo que ajustarlo yo mismo para que encaje.
      Últimamente incluso se oye eso de “escribe código para que la IA lo lea fácil”, pero todavía siento que el beneficio no compensa tanto la carga adicional.

    • Sobre la afirmación de que “a veces el LLM está al nivel de un junior o incluso mejor”, más bien me hace pensar si esos casos no reflejan el nivel reciente de contratación de desarrolladores.
      Si yo hubiera contratado a un junior peor que Sonnet 3.7, de verdad me sentiría muy decepcionado.

  • Puede que la mayoría de las críticas a los LLM sean correctas, pero después de años invirtiendo aprendí que hay que prestar atención a tecnologías o empresas que “todavía no son gran cosa, pero siguen mejorando”.
    En los primeros y mediados años 90 había muchas quejas sobre internet, pero la gente lo siguió usando, y Twitter también se caía seguido pero igual terminó consolidándose como plataforma de noticias.
    Los autos eléctricos, los smartphones y otras tecnologías también eran incómodos al principio, pero como valían la pena, siguieron mejorando.
    Aunque los LLM todavía no sean perfectos en muchas tareas, hoy ya son 10 veces mejores que en 2022, y creo que en los próximos 5 años la mayoría de los problemas mencionados aquí también se resolverán.

    • Pero en todos los ejemplos mencionados antes también hubo casos donde las expectativas no coincidieron con la realidad.
      Aunque internet se volvió más rápido, el metaverso nunca se convirtió en tendencia dominante, y limitaciones físicas como el mareo en VR siguen sin resolverse.
      En ese entonces no es que hubiera tantas quejas porque los teléfonos fueran lentos; las expectativas de uso eran distintas.
      El hecho de que una tecnología haya evolucionado de cierta manera no garantiza que los LLM vayan a seguir necesariamente el mismo patrón.
      También hay que tener presente que una tecnología nueva podría traer una solución mejor.
      El año pasado sí se amplió el campo de aplicación, pero todavía no ha habido un gran avance que pueda llamarse una verdadera ruptura.

    • Aunque los celulares de antes fueran lentos y tuvieran mala cámara, con su uso principal de entonces —poder contactar a alguien en cualquier momento y desde cualquier lugar— ya eran algo indispensable.
      Los avances radicales fueron un “extra”; la gente no estaba esperando diciendo “¿cuándo mejorará este teléfono?”.

    • Creo que aquí también hay una distorsión de la memoria.
      A diferencia de las quejas populares sobre el internet de los 90, en realidad los usuarios eran pocos y no se volvió algo masivo hasta mucho después.
      No hay mucha evidencia de que hubiera una gran masa de gente quejándose públicamente porque internet fuera lento.

    • Solemos recordar solo los pocos productos que sí crecieron con éxito; la mayoría se olvidaron rápido o desaparecieron sin mejorar.
      En vez de asumir que la tecnología va a mejorar, prefiero juzgar con base en la situación actual.

    • Me cuesta aceptar la lógica simplista de que el avance explosivo de los LLM en los últimos años necesariamente va a continuar igual hacia adelante.
      Puede que se acerquen a un límite de crecimiento, y siento que su incapacidad para descubrir conocimiento nuevo o razonar sobre información desconocida es una limitación decisiva de los LLM.
      No digo que sean herramientas inútiles, pero no pienso sumarme a expectativas exageradas.

  • Ya de entrada es poco realista esperar que un LLM escuche apenas unas cuantas frases y de inmediato programe hasta un prototipo.
    Si a un equipo humano de desarrollo le dieras trabajo de esa forma, tampoco podría construirlo bien; por eso me pregunto por qué se le exige eso a un LLM.
    Para mejorar de verdad la calidad del resultado de desarrollo de software con LLM, hay que aprovechar activamente los procesos y herramientas que ya usa un equipo de desarrollo tradicional.
    artículo sobre autonomous-software

    • Yo empecé un proyecto llamado steadytext donde el código se hizo de manera totalmente autónoma, muy en modo vibe, y el LLM llegó a escribir incluso un proyecto complejo de 7 mil líneas —una librería de Python, un CLI y una extensión de Postgres— resolviendo por su cuenta issues y feature requests.
      Ni siquiera he visto personalmente el 90% del código, y aun así la cobertura total de pruebas, el CI en verde y el uso real en producción no han dado problemas.
      Eso sí, en CLAUDE.md hace falta un plan muy detallado, además de issues y requests claramente especificados, pero con esa preparación sí funciona bien.
      No es fácil lograr que un agente de programación administre y escriba de forma eficiente, pero mi experiencia ha sido positiva.
      GitHub de steadytext

    • Acepto las posturas críticas, pero al final, para resolver problemas ambiguos lo esencial es que todo el equipo comparta mucho contexto.
      Incluso las soluciones más creativas salen de restricciones explícitas e implícitas.
      Los LLM no son capaces de captar esas restricciones ni de diseñar una solución nueva dentro de restricciones que no están claramente definidas.
      Solo después de que los humanos definan el problema, delimiten el alcance y entiendan las restricciones, el LLM puede servir como herramienta de apoyo en la implementación.
      Por ahora, no es más que una opción adicional del tipo “¿qué herramienta usamos para completar el código?”.
      Me parece más irreal intentar llevar toda esta discusión a una única solución absoluta de todo o nada.

    • De hecho, también hay muchos ingenieros humanos que funcionan razonablemente bien en este tipo de situaciones.
      Si darle instrucciones a un LLM no es tan fácil, me pregunto cuál es entonces su razón de ser.

    • Kiro está aplicando este enfoque; todavía está en una etapa temprana y no es perfecto, pero si se usa como fue pensado, funciona bastante bien.

  • Cada vez me frustra más, usando claude code, el hecho de que “los LLM no pueden construir un modelo mental claro”.
    No estoy seguro de que un LLM basado en texto pueda resolver bien este problema.

    • Me recuerda al caso de Google Genie 3, que pierde su estado interno en alrededor de un minuto.
      Intuitivamente siento que este problema requerirá una arquitectura nueva a nivel transformer, una que permita contexto de corto y largo plazo y ajuste de pesos propios —algo así como una imitación del aprendizaje—.
      Referencia: discusión relacionada

    • Últimamente pienso que una estructura jerárquica de agentes podría ser una alternativa realista.
      Estaría bien que un agente de nivel superior mantuviera solo el modelo mental general, mientras los agentes subordinados se reparten el trabajo.
      Incluso ahora debería poder hacerse algo parecido con la función de agentes de la herramienta Code, así que me gustaría ver si alguien comparte estrategias sobre eso.

    • Probé claude-code-requirements-builder y mejoró un poco, pero todavía no me deja satisfecho.

    • Siendo realistas, incluso un desarrollador junior “promedio” en un entorno de trabajo tampoco difiere tanto de lo que se describe abajo.
      Cree que el código que hizo está bien sí o sí, se desconcierta cuando falla una prueba y, si pierde el rumbo, en el peor caso borra todo el código y vuelve a empezar.
      Sale el clásico copiar y pegar de StackOverflow, echarle la culpa al compilador, e incluso decir que “fue por radiación cósmica”.

    • Al usar LLM, uno termina sintiendo por sí mismo que tiene que seguir liderando la planeación y el diseño.
      Me gusta poder dejarle al LLM las tareas repetitivas de bajo nivel y las pruebas, y así ganar tiempo para pensar en el panorama general.
      Eso sí, me gustaría que mejorarán mucho más cosas como la revisión de resultados del LLM o las propuestas de cambios, de forma bastante más interactiva.

  • Creo que la dirección de las startups de IA es el núcleo del problema ahora mismo.
    Hace falta algo más que una simple interfaz de chat: se necesita un flujo de trabajo de IA integrado de forma natural dentro del IDE.
    Esa es la tendencia en Visual Studio, InteliJ y Android Studio.
    Quiero una herramienta que se parezca de verdad a un programador real: darle instrucciones por voz en mi idioma nativo, que la IA entienda todo el contexto del proyecto y abarque refactorización, análisis estático, feedback de IA, UI a partir de bocetos, programación desde escritura a mano, generación de mensajes de commit a partir de cambios en el código, etc.

  • Estoy de acuerdo en que los LLM son bastante útiles para tareas de nivel junior.
    Últimamente he vuelto a pensar en esa vieja idea de que “la velocidad de tipeo no importa tanto”.
    Antes, como el diseño general y la estructuración eran mucho más importantes que la velocidad de teclear código, el tiempo de escritura en sí no pesaba tanto.
    Pero usando Claude me di cuenta de que ahora es posible hacer fácilmente cambios de código que antes uno evitaba por tediosos, y hacerlo sin necesidad de concentrarse demasiado.
    Antes, cada vez que agregaba un valor a un enum tenía que corregir con cuidado todas las partes relacionadas, pero el LLM puede hacer esas correcciones automáticamente.
    También esas tareas tediosas de arreglar errores de compilación uno por uno se las puedes delegar a Claude de forma iterativa.
    Como varios agentes pueden retocar distintas partes del código al mismo tiempo, yo puedo usar ese tiempo para pensar en la estructura grande o incluso escribir en HN.
    O sea, como ya no hace falta arreglar personalmente los errores de compilación, se pueden aplicar más cambios con rapidez, y tareas que antes le tomaban todo el día a un junior ahora pueden resolverse de una sola vez.
    Por eso puedo concentrarme más en el diseño de la arquitectura general y hasta cerrar pendientes de codificación que llevaba arrastrando mucho tiempo, lo cual ayuda bastante a la motivación.

    • Estoy de acuerdo con eso de que “aunque escribas más rápido, no llegas antes al objetivo porque el cuello de botella es el diseño”.
      Los LLM son bastante malos para hacer buen diseño, e incluso funciones pequeñas casi siempre necesitan refactorización.
      Sí hay una mejora de productividad en la etapa de implementación, pero a nivel de concretar ideas que ya estaban en mi cabeza o en documentos.
      Como herramienta de brainstorming, sí sirven.
      Si les lanzas todo el código y las pruebas y preguntas “¿se me escapó algún edge case?”, una o dos veces de cada diez sale un comentario útil.
      El fix de corto plazo para que algo funcione y la excelencia estructural de largo plazo son problemas demasiado distintos, así que todavía no está claro si los LLM podrán alcanzar también lo segundo.

    • Sobre eso de que “hay muchísimas cosas que me gustaría hacer en el codebase”, en realidad yo siento que el cuello de botella no es cambiar el código, sino revisarlo.

    • Si eso de que “el LLM hace rápido lo que a un junior le tomaría todo el día” termina quitándoles oportunidades de aprendizaje a los recién llegados y reduciendo la contratación, me preocupa quién va a formar a esa gente para que crezca.

  • Sobre el fenómeno de “no poder decidir si hay que corregir el código o la prueba cuando una prueba falla”, ayuda usar el lenguaje de “Red-Green-Refactor”.
    Ahora le transmito claramente al LLM el flujo de etapa RED (que falle la prueba es normal), etapa GREEN (hacer que pase con el mínimo código posible) y etapa REFACTOR (mejorar el código sin romper las pruebas).
    Así el LLM puede reconocer no solo la idea de “arreglar código roto”, sino el modelo mental de TDD.

  • Creo que está claro que los LLM todavía no dan para un proyecto totalmente nuevo y completo al nivel de “créame mi propio Facebook”.
    En cambio, en tareas más específicas como “agrega este modal y mantén el estilo revisando el código existente”, muchas veces sí he conseguido el resultado que quería.
    Si divides el problema en unidades pequeñas y las vas pasando una por una, el resultado suele ser mucho mejor.

    • Copiar el código existente y modificarlo como quiero ya lo puedo hacer yo mismo.
      El portapapeles de mi sistema, a diferencia del LLM, siempre funciona de forma determinista y no me crea infinitamente problemas nuevos e inesperados.

    • Me da curiosidad cómo responderán herramientas nuevas como v0 a este tipo de solicitudes.

  • Siento que el proceso de cuatro etapas del inicio del artículo se parece muchísimo a lo que plantea Deutsch en "The Beginning of Infinity".
    Nuestras teorías nacen de “conjeturas”, y el conocimiento se genera en una estructura de “ciclo entre conjetura y crítica”.
    Escribir código es una especie de “conjetura”, y crear pruebas es una “crítica” de esa conjetura.
    Ambas cosas son intentos de acercarse a la explicación que tenemos en la cabeza —un ideal platónico—.