El software ya no tiene cariño
14 min de lectura

El software ya no tiene cariño

Del disquete al bloat: una reflexión personal sobre cómo y por qué perdimos el cariño al programar.

Esto no es un manifiesto técnico, ni una guía experta. Es una crítica, una opinión, y una especie de lamento desde el lado más humano del desarrollo. No tengo todas las respuestas, pero sí muchas preguntas, y más de alguna molestia acumulada.

Cuando el software cabía en un disquete

Hubo un tiempo en que el software tenía que ser bueno. Porque no había opción. Los juegos venían en disquetes, y si no te cabía en uno o dos, estabas muerto. Los programadores exprimían hasta el último byte. Se usaban técnicas, trucos, a veces verdadera magia negra ensambladora. Y sí, a veces el código resultante no era precisamente para enmarcar en un cuadro (en mi opinión era algo horrible, pero era lo que había). Funcionaba. Rápido. Eficiente. Bien. Con 4 MB de RAM, se corría Doom. Con 16 MB hasta unos generosos 55 MB, se desarrollaban editores de texto, hojas de cálculo, y sistemas operativos completos como Windows 95. No había espacio para el bloat. Porque el hardware no perdonaba.

El software se hizo más complejo

No podemos negar que hoy todo es más complejo. Y no es necesariamente algo negativo:

  • Las apps hacen muchísimas más cosas.

  • Tienen que hablar con APIs, servicios en la nube, bases de datos distribuidas.

  • Deben ser (o intentar ser) accesibles, seguras, actualizables casi a diario.

  • La mayoría de usuarios esperan interfaces gráficas más sofisticadas

    Hay razones para que el software de hoy pese más. Y muchas son válidas. Pero en el camino, también se perdió algo. Y a veces, esa pérdida se siente desde el primer día en la trinchera del desarrollo.

Mis Experiencias

Permítanme una anécdota personal. Cuando entré a mi práctica profesional como informático, mi primera misión fue meterme de lleno en una aplicación hecha con .NET MAUI.

Para quienes no estén al tanto, digamos que MAUI no es precisamente famoso por su rendimiento estelar o su ligereza. Incluso cuando compila a paquetes de aplicaciones nativas, las aplicaciones pueden sentirse… pesadas, por decirlo suavemente. Es tan así que ni la propia Microsoft parece usarlo con entusiasmo en sus productos estrella. La aplicación que estábamos creando era para pasajeros de empresas de transporte. Tenía todo lo que una aplicación competente debería tener: autenticación, gestión de servicios, notificaciones, uso offline, ya se imaginan.

Las razones para usar MAUI eran claras; antiguamente, la empresa había desarrollado la misma aplicación, pero en Xamarin.Forms, también tenían una aplicación de conductores hecha en Xamarin.Android, por lo tanto, el equipo ya tenía experiencia con el mundo .NET y Xamarin.

MAUI prometía ser la evolución natural, un camino conocido hacia el futuro. Por lo tanto, la decisión fue tomada luego de unas breves pruebas de concepto, las cuales demostraron que MAUI se podía el trabajo.

Podíamos replicar el funcionamiento de la aplicación anterior (puesto que era una reescritura) y no debería haber problemas. Para dar un poco de contexto, la empresa trata con varios clientes de diferentes tamaños, requerimientos y necesidades, por ende la aplicación debía ser muy dinámica. Por ejemplo, había un formulario donde un pasajero podía solicitar un servicio de transporte con base en su convenio. Mediante la web, el administrador del convenio podía activar o desactivar ciertos campos del formulario o habilitar campos adicionales que son 100% dinámicos.

MAUI tuvo problemas al renderizar ese formulario, mientras más grande era, más lento se volvía. Especialmente con componentes dínamicos que renderizaban campos adicionales. Sin contar que de fondo debía haber un mapa, el cual usaba la dependencia de Map que MAUI provee en una dependencia.

Ahí fue la primera vez que aprendí a hacer profiling de una aplicación. Note que MAUI, al menos en Android, tenía graves problemas con su componente CollectionView, vi varias issues al respecto en su repositorio. La cantidad de investigación que tuve que hacer para poder hacer que la desgraciada aplicación fuera tan solo unos segundos más rápida fue monumental. Y aun así, no pude lograr que fuera lo suficientemente rápida como para que la experiencia fuera fluida. Sin contar que la DX de MAUI es horrible tanto en Visual Studio como Rider, y que la documentación es escasa y pobre especialmente cuando se trata de hacer cosas más avanzadas.

Cuando finalmente se terminó el desarrollo de la aplicación, se empezó a hablar del siguiente proyecto: la aplicación de conductores. La razón por la que debíamos reescribirla era porque el soporte de Xamarin estaba terminado y no se podría subir más actualizaciones a la Play Store. Por ende teníamos poco tiempo para hacer la reescritura. Estábamos entre dos opciones, todos sabíamos que MAUI no era la mejor opción, luego estaba Flutter donde solo yo tenía experiencia. Hubo unas semanas de discusiones, pero al final se decidió que MAUI era la mejor opción simplemente por temas de tiempo. Si te pones a pensar era algo obvio desde el inicio, ya que, como se usó MAUI para la aplicación de pasajeros, se podía reutilizar gran parte del código y el equipo ya tenía experiencia con el framework y sus mañas.

En cierto modo, la decisión fue correcta. Pero también fue un error monumental, desde mi punto de vista.

Yo aún no soy el más experimentado del área, pero pensaba que las decisiones se tomaban en base que sería lo mejor para el usuario final, no con base en lo que era más conveniente para la empresa. Digamos que mi inocencia me llevó a pensar que las preocupaciones de los usuarios importaban más que cualquier otra cosa. Y la verdad no es así.

El cariño desapareció

Con historias como la anterior resonando, no sorprende que hoy muchas aplicaciones parezcan hechas en piloto automático. Se sienten como una torre de Jenga de dependencias, frameworks apilados sobre otros frameworks, capas de abstracción y decisiones que, aparentemente, nadie cuestionó con suficiente vehemencia. Se prioriza la velocidad de desarrollo, él time-to-market. La facilidad de mantenimiento (para el desarrollador, claro). Pero ¿y el usuario? ¿Y el rendimiento? ¿Y el respeto por la máquina que, con tanto esfuerzo, se compró ese usuario? Todo eso parece haber quedado atrás, como una reliquia de la era de los disquetes.

El usuario: ese ser paciente y condenado

Antes, usar un computador implicaba saber una cosa o dos. Tenías que entender el sistema operativo, saber instalar, configurar, y a veces, reparar con comandos arcanos. Hoy, el usuario común solo quiere que las cosas funcionen. Y, con demasiada frecuencia, no puede. Tiene un PC de gama media, perfectamente capaz. Quiere abrir una app para trabajar, estudiar, o conversar. Pero se topa con Electron devorando RAM como si fuera gratis, con renderizados innecesarios para mostrar una lista, con efectos de blur y JavaScript que se ejecuta como si la CPU tuviera núcleos infinitos y energía ilimitada. Su computador no es lento. El software es glotón. Y mientras todo se congela, quizás recuerda con nostalgia que su antiguo notebook, ese con un procesador de hace una década, podía correr Age of Empires II con gráficos al máximo sin pestañear. Y se pregunta, con genuina confusión: “¿Por qué ahora Teams se pega al abrir el maldito calendario?” La respuesta nunca llega. Porque hoy el estándar parece ser aguantar.

Y el que sabe… sufre sabiendo

El desarrollador que sí entiende el percal tampoco está a salvo. Tiene un notebook que le entrega su empleador, una bestia con 16 GB o incluso 32 GB de RAM. Corre Android Studio (que ya es decir), Chrome con 50 pestañas (porque investigar es así), Teams (porque la empresa lo exige), una terminal, y el monitor de sistema abierto en un intento desesperado por entender dónde se va la memoria. Y aun así, todo se siente lento, pastoso. No porque esté compilando el kernel de Linux o programando shaders en tiempo real. Si no porque todo el stack está hinchado, lento, y lleno de capas innecesarias. Y lo peor es que, muchas veces, ya lo aceptó. Ya ni reclama. Solo reinicia la aplicación, o el PC entero, o cierra ventanas rezando para que le den un byte más de potencia para seguir trabajando.

El problema es mental, no (solo) tecnológico

Hay quien dice: “Si reescribiéramos Slack en Qt o WPF, sería más rápido”. Y sí, probablemente lo sería. Pero esa es solo una parte de la ecuación. Podríamos escribirlo en Rust, en C++, en Assembly si nos volvemos locos… Y si lo hacemos con la misma mentalidad actual de “agregar sin pensar”, el resultado sería igual de pesado, o casi. Quizás arrancaría un segundo más rápido, pero seguiría consumiendo recursos como si no hubiera un mañana. Porque el bloat no está fundamentalmente en el lenguaje o el framework. Está en la cabeza. Cuando priorizamos la conveniencia inmediata del desarrollador sobre la eficiencia a largo plazo para el usuario, cuando metemos dependencias “por si acaso” o por costumbre, cuando dejamos de cuestionar lo que agregamos a la base de código, cuando ya no nos importa cuánto pesa o cuánta RAM consume “esa pequeña feature nueva”, el resultado inevitablemente será el mismo. Solo que, si es en un lenguaje de bajo nivel, será más difícil de depurar. Y esta mentalidad de “agregar por agregar” o “seguir la moda sin cuestionar” se ve también en cómo aplicamos ciertos principios de diseño…

El dogma del “Clean Code” y las arquitecturas overkill

Y ya que estamos sincerándonos… hablemos de ese culto a ciertas arquitecturas. Patrones, principios SOLID, Clean Architecture… son herramientas valiosísimas. En el contexto adecuado. Pero cuando ves un proyecto para hacer un CRUD simple con tres tablas convertido en una estructura de siete capas, con interfaces para todo, inyección de dependencias hasta para instanciar un string, y un patrón Repository que esconde una sola llamada a un ORM… empiezas a preguntarte si no se nos ha ido un poco de las manos. Todo eso para guardar un texto. Porque “es lo correcto”, porque “así se hace en las grandes ligas”. Hay patrones que sirven. Claro. Pero no todo necesita ser una startup de Silicon Valley a punto de escalar a millones de usuarios. Aplicar arquitecturas complejas sin una razón de peso, solo por moda o por currículum, es otra forma de hinchar el software. Solo que esta vez, el bloat no es (solo) en el binario o en el consumo de RAM. Es en la complejidad innecesaria del código, en la cantidad de archivos que hay que tocar para un cambio simple, en la curva de aprendizaje para el nuevo del equipo.

La trampa de las dependencias: ¿Cómo llegamos acá?

En Linkedin he visto a gente que se jacta de usar Next.js para un sitio web que fácilmente podría haber sido estático. O a quienes usan un framework de frontend cuando la página solo muestra un par de datos y no necesita nada más que HTML y CSS. ¿Por qué? Porque “es lo que se usa ahora”, “es lo que está de moda”, “es lo que me enseñaron en el curso de la semana pasada” de Midudev.

De por sí a mí me carga Next.js o React en sí, pero eso es otro tema. Lo que quiero es que por ejemplo, ese framework de frontend, que trae consigo un montón de dependencias, una arquitectura compleja y está hecho para aplicaciones que necesitan ser dinámicas, se use para algo que no lo necesita. Porque prácticamente no hiciste una evaluación de si realmente lo necesitabas.

Ojo que esto no cuenta si estás haciendo un proyecto personal de estudio o aprendizaje, ahí haz lo que quieras. Pero si es un proyecto que va a ser usado por alguien más, deberías pensar en el usuario

Y cada dependencia trae más, y más, y más hasta que terminamos siendo como Cookie Run que con cada actualización te deja el celular con menos espacio hasta el punto que debes borrar las fotos de tu familia porque ahora el juego pesa 1 TB y no puedes jugarlo sin espacio suficiente.

Piénsalo de este modo, mientras más cosas haya, más cosas debe hacer el software. Terminamos con:

  • Un binario de 400 MB que hace funcionalmente lo mismo que uno de 20 MB podría hacer.

  • Un arranque que toma 20 eternos segundos en un SSD NVM M.2 (te observo a ti, Microsoft Teams).

  • Bugs que no sabes si vienen de tu código, de la dependencia A, o de la dependencia X que A usa transitivamente.

  • Una superficie de ataque de seguridad del tamaño de un campo de fútbol.

    Entonces, ¿cómo llegamos a este punto? Creo que es una mezcla de factores:

  • El hardware mejoró tanto y tan rápido que dejamos de sentir la necesidad imperiosa de optimizar. “Total, la máquina lo aguanta”, nos dijimos. Y vaya si lo aguanta… hasta que deja de hacerlo.

  • Los frameworks y las librerías lo hacen “fácil”, pero a menudo esconden lo que pasa debajo. Es cómodo, sí, pero también nos hace perder la noción del coste real. Importamos una librería para validar un email y, sin darnos cuenta, añadimos 15 MB al bundle.

  • Las dependencias se instalan sin pensar demasiado. Un npm install o un pip install es tan rápido que a veces no ponderamos si realmente necesitamos toda esa librería para esa única función que vamos a usar.

  • Se prioriza la velocidad de desarrollo (o la percepción de ella) por encima de la calidad y eficiencia del producto final. “Sácalo rápido, ya lo optimizaremos luego” (spoiler: “luego” nunca llega).

  • Los usuarios, en su mayoría, no se quejan o no saben cómo hacerlo de forma efectiva, porque no tienen otra opción o han normalizado que el software sea lento.

  • Nadie quiere ser el “amargado” del equipo que siempre está preguntando: “¿Realmente necesitamos esto? ¿No deberíamos hacerlo más simple? ¿Han visto cuánto consume esto?”.

Yo siento que la mejor forma de evitar caer en esta trampa es desarrollar en un PC con recursos escasos, para que sientas lo que sentirá un usuario con un equipo de gama media o baja. Si tu aplicación corre bien en un equipo así, entonces felicidades, has hecho un buen trabajo. Si no, entonces deberías replantearte como escribes cada línea de código.

Lo peor es que últimamente, debido al auge de las LLM y la IA en general, se ha vuelto aún más fácil para que cualquier loquillo de centro intente escribir código sin entender exactamente qué demonios está haciendo. Y eso, en mi opinión, es un problema aún mayor. Porque si ya teníamos problemas ahora tenemos a gente que escribe código sin entenderlo, y eso es un desastre esperando a suceder.

¿Y el futuro?

Podría empeorar, siendo sinceros. Porque:

  • El software se seguirá inflando si no cambiamos el chip.
  • La RAM seguirá subiendo en las especificaciones de las máquinas, pero el uso que le damos también lo hará, dejándonos en el mismo sitio.
  • Las apps nativas, con su posible potencial de eficiencia, podrían seguir siendo reemplazadas por navegadores empaquetados, porque es “más rápido desarrollar así para todas las plataformas”.
  • El conocimiento profundo de cómo funcionan las cosas podría ser reemplazado por la habilidad de ” copiar y pegar código de la LLM de moda”, sin entender realmente las implicaciones. A menos que hagamos algo.

Volver al cariño: una propuesta (casi) artesanal

No estoy pidiendo que todo el software pese 3 MB y corra en MS-DOS o en una Commodore 64. Eso sería absurdo e impráctico para las necesidades actuales. Pero sí que recordemos algo básico: el software es una artesanía, no solo una industria. Sí, debe ser útil. Pero también puede y debe aspirar a ser elegante en su eficiencia. Sí, debe ser mantenible. Pero no a costa de una experiencia de usuario insufrible. Sí, podemos y debemos usar herramientas modernas. Pero con conciencia, cuestionando su impacto. Quizás el primer paso es individual:

  • Cuestiona cada nueva dependencia: ¿Realmente la necesitas? ¿Toda entera? ¿No hay una forma más ligera?

  • Dedica tiempo a perfilar: Entiende dónde se van los recursos en tu propia aplicación. Te sorprenderías.

  • Piensa en el usuario final: Especialmente en aquel que no tiene el último Mac M-Infinity con 256 GB de RAM y 8 Petabytes de almacenamiento. ¿Cómo se sentirá al usar tu software?

  • No temas simplificar: A veces, la solución más “aburrida” y simple es la mejor.

    Porque cuando dejas de cuidar lo que haces, cuando solo produces por producir, cuando escribes código sin alma… lo que estás haciendo ya no es software. Es basura digital. Y no hay framework, ni arquitectura limpia, ni IA que lo arregle si el cariño no está presente desde el principio.

Publicado el