lunes, 23 de febrero de 2026

Una aparente paradoja: el retorno de la programación de bajo nivel

En los dos últimos post he hablado de dos fenómenos, en apariencia independientes y casi contradictorios y que, precisamente, van a colisionar en este artículo. 

Hablo, por un lado, de la evolución del desarrollo software que explicaba en 'La evolución del desarrollo software: productividad frente a deskilling' y que nos muestra una clara evolución a una programación cada vez más alejada de los detalles técnicos y más centrada en la productividad y cercanía a las necesidades funcionales. Una programación, en fin, de alto nivel.

Por otro, en el último post, 'El retorno del hardware: razones y perspectivas', destacaba cómo el hardware, al que hacía años que apenas dábamos importancia, ha vuelto a cobrar valor técnico, económico y estratégico, debido en buena medida a las demandas técnicas y de volumen que impone la inteligencia artificial generativa.

En este post examino un fenómeno en cierto modo sorprendente y contradictorio: el retorno, no ya del hardware, sino de la programación de bajo nivel.


Programación de bajo nivel


Como paso previo, y por si algún lector no esta suficientemente advertido, aclarar a qué nos referimos con lo de la programación de bajo nivel.

La programación de bajo nivel es la creación de un software que trabaja en temas de detalle y, sobre todo, muy cerca del procesador, ya sea un microprocesador de tipo CPU ('Central Processing Unit') tradicional, o los modernos GPU ('Graphical Processing Unit') o TPU ('Tensor Processing Unit'). La programación de bajo nivel suele implicar conocer bien el hardware, tanto los procesadores como la estructura de registros y de la memoria o cómo relacionarse directamente con dispositivos y periféricos.

Con la programación de bajo nivel normalmente no podemos resolver grandes problemas funcionales, pero, a cambio, podemos conseguir nuevas capacidades y, sobre todo, si se hace bien, unas altísimas prestaciones y una gran optimización computacional. Y eso es así porque al trabajar muy cerca del hardware y conociendo cómo funciona, explotamos al máximo sus capacidades y, además, hacemos ´únicamente lo que se necesita'.

El software de alto nivel, por su lado, en su búsqueda de generalidad y facilidad de uso, añade ingentes cantidades de lógica adicional no estrictamente necesaria en muchos casos y, además, al alejarse del hardware no optimiza su uso. Prima la productividad y facilidad de uso frente a la optimización computacional.


¿Por que realizar programación de alto nivel?


En realidad lo acabamos de mencionar y lo vimos también en un post anterior: favorecemos la programación de alto nivel porque es muchísimo más productiva en términos de cantidad de software producido, porque además es más sencilla de llevar a cabo (lo que redunda en productividad y, además, elimina barreras de entrada de profesionales) y, finalmente, porque permite concentrarse más en los problemas de negocio o en lo que realmente queremos proporcionar.

Por eso, una vez que el hardware alcanzó una potencia tal que ya no nos exigía su optimización para tener buenos resultados de prestaciones, se ha ido favoreciendo la programación de alto nivel


¿Y por qué realizar programación de bajo nivel?


Y, entonces ¿Por qué podríamos interesados, a estas alturas, en hacer programación de bajo nivel?

Bueno, en algunos casos no hay más remedio. Por ejemplo, para relacionarse con un nuevo dispositivo o periférico, hay que comenzar trabajando en el bajo nivel, aunque luego, de cara a otros programadores se preparen ya APIs o conectores simplificados.

Un poco en esa misma línea, si estás programando un sistema operativo no tienes más remedio que enfrentarte al bajo nivel porque una de las funciones principales de un sistema operativo es precisamente relacionarse con el hardware y ofrecer, hacia el exterior, un modo abstracto, una máquina virtual que independice a aplicaciones y programadores de ese hardware. Los programadores de esas aplicaciones pueden trabajar en el alto nivel, pero los del sistema operativo están obligados a relacionarse con el bajo nivel.

Pero hay algo que me importa mucho más ahora mismo, en relación con lo que quiero exponer en este artículo: utilizas la programación de bajo nivel porque cuando quieres optimizar el funcionamiento, cuando quieres maximizar las prestaciones, cuando quieres 'exprimir al máximo' la capacidad del hardware, tienes que acercarte al hardware, tienes que conocerlo, tienes que, en fin, realizar programación de bajo nivel.


Nuevas arquitecturas de procesadores


Durante bastantes años, los procesadores, aunque evidentemente evolucionaban, y no poco, eran de tipo CPU.

Con el auge de aplicaciones de gran riqueza gráfica como los videojuegos, nacieron y cobraron importancia las GPU ('Graphical Processing Unit'). Pero la auténtica explosión ha venido de la mano del machine learning al 'descubrir' que las operaciones algebraicas que se utilizan en el mundo gráfico, son similares a las que se utilizan en machine learning, fundamentalmente en redes neuronales. En ambos mundos abundan las operaciones con vectores, matrices y tensores. Y las GPU lo que hacen es optimizar esas operaciones.

En un paso más allá en especialización, existen las TPU ('Tensor Processing Unit') o los 'tensor cores' de NVIDIA que, pese a que suenen a algo muy potente, en realidad se especializan en una única operación: la multiplicación de dos matrices y acumulación del resultado en una de ellas. En cierto modo, son elementos muy sencillos, pero altamente especializados y optimizados.


La nueva programación de bajo nivel


Aunque la programación de bajo nivel, pese a su escasa visibilidad, nunca se había ido, ahora cobra una gran importancia para explotar estos nuevos procesadores.

¿Por qué?

Pues porque estos procesadores son muy especializados pero, para que produzcan los resultados esperados, hay que programarlos conociendo cómo funcionan. Así, para explotar bien las GPU hay que convertir la resolución de nuestros problemas en operaciones de algebra lineal y, además ser capaces de definir la resolución de un problema en términos de unas funciones, los denominados 'kernel', en que la misma lógica pueda trabajar en paralelo sobre diferentes datos (por ejemplo, sobre diferentes partes de una misma matriz).

Más específico aún es el caso de los 'tensor cores' en que, para aprovecharlos, hay que ser capaces de identificar o forzar operaciones que consistan en una multiplicación de matrices seguidas por una acumulación.

Y esto no se puede hacer con sólo conocer un problema de negocio o la sintaxis de un lenguaje de programación. Para ello hay que comprender el hardware con que se trabaja y la mejor forma de obtener todo su rendimiento.

Es decir, hay que trabajar en el bajo nivel.


Deshaciendo la aparente contradicción


Y llega el momento de deshacer la aparente contradicción.

¿No habíamos dicho que la evolución del software nos conducía a una visión cada vez más alejada del hardware, una visión que en sus vertientes 'No Code' o 'Vibe coding' ni siquiera trabajaba con código fuente e incluso que en las soluciones de más alto nivel el desarrollador expresaba sus necesidades en lenguaje natural?

Si, lo habíamos dicho y así es.

Lo que ocurre que el trabajo en el bajo nivel lo realizan, comparativamente, muy pocas personas organizadas en equipos especializados. Esas pocas personas programan el software más exigente y, además, preparan componentes optimizados para su uso en el alto nivel por desarrolladores menos especializados.

Así, las típicas librerías python usadas en machine learning y deep learning, están fuertemente optimizadas a nivel interno, aunque el común de los programadores las utilicen directamente sin preocuparse de los detalles. Y no digamos ya nada cuando ni siquiera se trabaja con las librerías sino con componentes gráficos que las abstraen (caso del 'low-code / 'no-code') o cuando incluso es la inteligencia artificial la que general el código que invoca a las librerías, sin que el desarrollador sea necesariamente consciente de ello.

En el fondo, esa ha sido siempre la relación entre al bajo y el alto nivel: unos pocos equipos especializados trabajan en el bajo nivel, cerca del hardware, y preparan componentes optimizados reutilizables en el alto nivel.

Lo único que ocurre es que ahora, con la enorme demanda computacional existente y procedente de la inteligencia artificial, muy especialmente en su vertiente generativa., cobra nueva importancia el  contar con algunos de esos equipos especializados para sacar jugo a un hardware especializado y que, pese a las enormes inversiones, se nos está quedando corto en volumen. 


Conclusiones


La gran demanda computacional exigida por la inteligencia artificial generativa ha llevado al desarrollo de procesadores especializados a nivel hardware, pero el uso adecuado y óptimo de ese hardware implica el trabajo en el bajo nivel aunque luego los resultados puedan ser reutilizados vía librerías y APIs, en la programación de alto nivel.

No hay comentarios:

Publicar un comentario