Como programador, uno vive en el mundo abstracto del código. Pero ¿alguna vez te has preguntado qué ocurre realmente en el metal cuando ejecutas tu programa?

Entender la máquina que hay detrás de tus líneas de código no es solo una curiosidad académica, es una ventaja competitiva que te permitirá escribir software más rápido y eficiente.

En esta guía sobre los fundamentos de la programación viajaremos al corazón de tu ordenador para desmitificarlo, desde el electrón hasta el lenguaje de alto nivel. ¡Empecemos!

Diagrama ilustrando los fundamentos de la programación, conectando el software con el hardware.
Entender cómo tu código interactúa con el metal es el primer paso para dominar la programación de verdad.

¿Qué son los fundamentos de programación?

Los fundamentos de programación son el conjunto de conocimientos básicos sobre cómo el hardware y el software trabajan juntos. Implica entender los componentes de un ordenador, como la CPU y la memoria, y cómo las instrucciones de un lenguaje de alto nivel se traducen para que la máquina las ejecute.

Dominar esta base es crucial para desarrollar software optimizado y eficiente.

Entendiendo la Relación entre Hardware y Software

Para quienes se inician en el mundo de la introducción a la programación, es fundamental comprender la relación entre hardware y software.

Algunos conceptos son intuitivos. Entre ellos se incluyen fenómenos naturales y también invenciones humanas como la rueda o la pizza.

Por otro lado, existen conceptos que no son intuitivos y deben aceptarse como un acto de fe. Por ejemplo, ¿cómo convierte un televisor una señal invisible que viaja por el aire en audio y video?

La computación es uno de esos campos que no se comprenden de manera inmediata. ¿Cuál es el mecanismo que permite a una máquina ejecutar las acciones deseadas al presionar teclas en un teclado? Saber cómo funciona un ordenador a este nivel es parte de los fundamentos básicos de programación.

Algunos textos explican la memoria de un ordenador mediante la analogía de una biblioteca. Si esta analogía fuera literal, al tomar un libro de un estante, este desaparecería temporalmente. Esto implicaría que al leer desde la memoria, la sección leída se borraría. Sin embargo, el proceso real es más similar a tomar una copia del libro, no el libro en sí.

Este artículo tiene como objetivo explicar de manera concisa los conceptos de fundamentos de hardware y software para quienes comienzan. Se intentará que los diversos temas se vuelvan eventualmente “evidentes”, aunque es posible que encuentres algunos puntos complejos al principio.

Fundamentos de Hardware: Los Cimientos de tu PC

El computador del hombre primitivo

En la era prehistórica, al regresar de la caza, Ogg y Sogg añadirían nuevas piezas de carne a su pila de mamut. Sin embargo, más allá de poder presumir si una pila era notablemente más grande que la otra, no había mucho más que pudieran hacer con ella.

Un descendiente de Ogg, varias generaciones después, podría saber contar, escribir números y usar un ábaco (Sogg, en un intento de agrandar su pila de carne, fue aplastado por un mamut y no dejó descendencia). No obstante, para trascender el uso de estas herramientas y concebir el concepto de un ordenador, se requiere un salto en la imaginación y la tecnología. La primera tecnología indispensable es la electricidad.

Electricidad

Benjamin Franklin teorizó que la electricidad era un fluido invisible que fluía desde donde había una abundancia (positivo) hacia donde había una escasez (negativo).

Su concepción fue fundamentalmente correcta, pero la dirección del flujo era la opuesta. Los electrones fluyen desde lo que él denominó negativo hacia el positivo. Sin embargo, el electrón fue descubierto mucho después, y la terminología estaba tan arraigada que no pudo ser invertida. Como resultado, debemos recordar que los electrones fluyen en dirección opuesta a la corriente convencional.

Aunque fenómenos como la electricidad estática y los rayos eran conocidos desde la antigüedad, la clave para construir circuitos fue entender cómo controlar el flujo de electrones en materiales conductores como el cobre o el silicio, lo que permitió diseñar dispositivos electrónicos útiles.

Anteriormente, yo creía que la corriente eléctrica se generaba por electrones que se mareaban al girar en sus órbitas, pero la realidad es bastante diferente. Los electrones saltan de un átomo a otro. Es un proceso análogo a una serie de rodamientos de bolas en un tubo (o las perlas de tapioca en una pajita de té de burbujas). Al empujar una bola por un extremo, se produce una reacción en cadena que desplaza a las bolas adyacentes, expulsando una bola por el otro extremo.

Un electrón promedio se mueve lentamente (la velocidad de deriva en un cable es de aproximadamente 7.5 cm por hora), pero esta colisión casi simultánea permite que la onda electromagnética se propague a una velocidad extremadamente alta, que varía entre el 50% y el 99% de la velocidad de la luz, dependiendo del conductor.

Invención

Para construir un ordenador, todavía se necesitan los siguientes componentes:

  1. Un medio para almacenar información.
  2. Un medio para realizar operaciones con esa información almacenada.

Un concepto para la memoria es un interruptor. Se requiere un dispositivo que pueda estar en estado de encendido o apagado y mantener ese estado hasta que algo lo altere.

Un interruptor eléctrico controla el flujo de corriente abriendo o cerrando un circuito. Usamos interruptores para encender y apagar dispositivos como las luces. Lo que se necesitaba era un medio para que la propia corriente eléctrica controlara un interruptor.

Los primeros ordenadores (y televisores) utilizaban tubos de vacío para este propósito, pero eran grandes y eventualmente se quemaban. El invento más crucial para la creación del ordenador moderno fue, sin ninguna duda, el transistor, reconocido con el Premio Nobel de Física en 1956. Es más pequeño, más eficiente energéticamente y más fiable que un tubo de vacío.

El último paso fundamental fue la miniaturización masiva de los transistores y su interconexión en circuitos integrados. A lo largo de los años, los ordenadores se han vuelto progresivamente más pequeños, rápidos y significativamente más económicos. Las señales se transmiten más rápido cuanto menor es la distancia entre los componentes.

Sin embargo, existe un límite físico y económico a la densidad con la que se pueden empaquetar transistores en un chip. Aunque la miniaturización continúa, los procesos de litografía se acercan a límites atómicos y aumentan los costes y la disipación de calor.

Por eso la industria ha adoptado enfoques como multinúcleos y chiplets, que combinan múltiples módulos más pequeños en un mismo paquete para continuar ganando rendimiento sin depender exclusivamente de hacer transistores más pequeños, una evolución de la famosa Ley de Moore.

Ignorando estos detalles, son estos inventos los que nos permitieron construir una máquina, el ordenador, capaz de almacenar información y realizar operaciones con ella.

Gráfico mostrando los componentes de un ordenador y cómo se interconectan.
Cada componente tiene una función específica, y su velocidad de comunicación define el rendimiento del sistema.

Componentes de un Ordenador: Un Vistazo al Interior

Un ordenador real contiene innumerables elementos complejos, pero a continuación se describen solo sus componentes de un ordenador esenciales.

Una placa de circuito (circuit board) contiene una CPU, memoria, las conexiones eléctricas que las unen y puertos para conectar dispositivos externos.

CPU

La CPU (Unidad Central de Procesamiento), también conocida como chip, es la que realiza los “cálculos” reales.

  • Operaciones matemáticas como la suma.
  • Comparación de valores.

Memoria y Caché

La RAM (Memoria de Acceso Aleatorio) es donde se realiza el “almacenamiento” de datos en uso. La RAM es rápida pero volátil, lo que significa que sus datos se pierden si se interrumpe la alimentación eléctrica.

Con el tiempo, las CPU se volvieron más rápidas que la memoria. Por ello, los diseñadores de ordenadores añadieron una memoria más pequeña y rápida llamada caché entre la CPU y la memoria principal.

Cuando la CPU necesita leer un byte de información de la memoria, primero busca en la caché más cercana (llamada caché L1), luego en la siguiente (caché L2) y, finalmente, accede a la memoria principal.

Almacenamiento

Dado que la memoria principal pierde sus datos, también se necesita un almacenamiento no volátil. Algunos dispositivos de almacenamiento pueden contener una cantidad de datos considerablemente mayor que la memoria y a un costo menor, pero sus velocidades de transferencia son mucho más lentas.

Un dispositivo de almacenamiento tradicional es el disco duro magnético (HDD), que usa platos giratorios y un cabezal móvil para leer y escribir datos, lo que lo hace mucho más lento y con mayor latencia que tecnologías como SSD.

Posteriormente, surgió la tecnología de almacenamiento en estado sólido: las SSD (Unidades de Estado Sólido). Las SSD utilizan memoria flash no volátil, que no tiene partes móviles y ofrece acceso mucho más rápido que los discos magnéticos tradicionales. No son lo mismo que la RAM, sino dispositivos de almacenamiento rápidos y persistentes.

Entrada (Input)

Los medios principales de interacción humana son el teclado, el ratón y la pantalla táctil.

Salida (Output)

Generalmente, visualizamos la salida de un ordenador a través de una pantalla o una impresora.

Tiempos de acceso relativos

El tiempo necesario para transferir datos entre estos componentes varía enormemente. En la práctica, esta variabilidad tiene implicaciones significativas.

  • Por ejemplo, un software se ejecuta en la memoria y debe acceder a datos en ella, pero también necesita almacenar datos de forma segura en un dispositivo no volátil como un disco.
  • El problema es que el disco es miles de veces más lento que la memoria.

Los programadores buscan constantemente técnicas para equilibrar eficazmente la velocidad y el costo.

UbicaciónTiempoProporciónTiempo RelativoDistancia Relativa
CPU0.4 ns11 segundo1 cm
Caché L10.9 ns22 segundos2 cm
Caché L22.8 ns77 segundos7 cm
Caché L328 ns701 minuto70 cm
RAM100 ns2504 minutos2.5 m
SSD100 µs250,0003 días2.5 km
Disco Magnético10 ms25,000,0009 meses250 km
Internet: SFO → NYC65 ms162,500,0005 años16,250 km

Es notable que la ejecución de una instrucción de la CPU tarde menos de un nanosegundo. Dado que el disco y la red son extremadamente lentos en comparación con la CPU y la RAM, es aconsejable realizar la mayor cantidad de trabajo posible en memoria. Y como la CPU es considerablemente más rápida que la RAM, es preferible que los datos sean contiguos para que puedan ser suministrados desde las cachés de alta velocidad cercanas a la CPU.

Fundamentos de Software: Dando Vida al Metal

¿Cómo se controla el hardware de un ordenador? La base son las instrucciones y los datos. Estos son los fundamentos de software. Un ordenador de programa almacenado simplifica su diseño al tratar todo como datos.

Pero, ¿cómo se representan las instrucciones y los datos? ¿Qué es aquello que puede ser almacenado en un lugar y procesado en otro?

El bit como punto de partida

Volvamos al concepto del interruptor que puede recordar uno de dos valores. Puede estar encendido o apagado, en alta o baja tensión, ser positivo o negativo. Mantiene su estado y puede informar sobre su valor cuando se le consulta. Un circuito integrado permite empaquetar y conectar miles de millones de estos diminutos interruptores en un pequeño chip.

Si un interruptor solo puede tener dos valores, puede representar un bit, es decir, un dígito binario. Un bit puede tratarse como los enteros 0 y 1, sí y no, o verdadero y falso.

Sin embargo, un bit es demasiado pequeño para representar algo más allá de 0 y 1. ¿Cómo podemos usar bits para representar valores más grandes?

La respuesta está en nuestros dedos. En la vida cotidiana, usamos diez dígitos (0 a 9), pero podemos representar números mucho mayores que 9 mediante la notación posicional. Al sumar 1 al número 38, el 8 se convierte en 9, resultando en 39. Si sumamos 1 de nuevo, el 9 se convierte en 0 y se acarrea un 1 al dígito de la izquierda, convirtiendo el 3 en 4, para obtener 40.

La posición más a la derecha es el “lugar de las unidades”, y a su izquierda está el “lugar de las decenas”. Cada posición a la izquierda multiplica por 10 el valor de la posición a su derecha. Un número decimal de 3 dígitos puede representar 1,000 valores diferentes (de 000 a 999), es decir, 10 x 10 x 10.

Usando la notación posicional, una colección de bits puede representar valores mayores. Un byte consta de 8 bits y puede representar 2^8 (256) combinaciones diferentes. Con un byte, por ejemplo, se pueden representar enteros pequeños del 0 al 255 (en la notación posicional, se debe reservar espacio para el cero).

Un byte puede visualizarse como una secuencia de 8 bits. Cada bit tiene un valor de 0 (apagado, falso) o 1 (encendido, verdadero). El bit más a la derecha es el bit menos significativo (LSB), y el de la izquierda es el bit más significativo (MSB).

Gráfico que ilustra la jerarquía del software, desde el lenguaje máquina hasta los lenguajes de alto nivel.
Los lenguajes de alto nivel nos permiten dar instrucciones complejas sin pensar en bits y bytes.

Lenguaje de máquina

Cada CPU tiene un conjunto de instrucciones, que es una colección de patrones de bits (también llamados opcodes) que puede comprender. Cada opcode ejecuta una función específica utilizando valores de entrada de una ubicación determinada y produce un valor de salida en (otra) ubicación. La CPU posee áreas especiales de almacenamiento interno llamadas registros para guardar estos opcodes y datos.

Consideremos un ordenador simplificado que solo opera con bytes y tiene cuatro registros de un byte: A, B, C y D.

  • El opcode del comando se establece en el registro A.
  • El comando recibe entradas de tamaño de un byte en los registros B y C.
  • El comando establece una salida de tamaño de un byte en el registro D.

(La suma de dos bytes puede generar un desbordamiento —un resultado que no cabe en un byte—, pero ignoraremos este detalle para ilustrar el proceso).

Supongamos que los registros tienen los siguientes valores:

  • Registro A: el valor decimal 1 (binario 00000001) como opcode para la suma de dos enteros.
  • Registro B: el valor decimal 5 (binario 00000101).
  • Registro C: el valor decimal 3 (binario 00000011).

La CPU detecta la instrucción en el registro A, la decodifica y la ejecuta. En el proceso, lee los valores de los registros B y C y los pasa a un circuito de hardware interno capaz de realizar la suma de bytes. Una vez completada la operación, el registro D contendrá el valor decimal 8 (binario 00001000).

La CPU utiliza registros de esta manera para realizar sumas y otras operaciones matemáticas. Decodifica el opcode y transfiere el control a un circuito específico dentro de la CPU. La CPU también puede realizar comparaciones, como “¿es el valor en B mayor que el valor en C?”. Además, puede obtener (leer) valores de la memoria a los registros y almacenar (escribir) valores de los registros en la memoria.

Un ordenador almacena programas (instrucciones de máquina y datos) en la memoria y transfiere estas instrucciones y datos entre la memoria y la CPU.

Ensamblador (Assembler)

Escribir programas en lenguaje de máquina es extremadamente difícil. Es necesario especificar cada bit perfectamente, lo cual es un proceso muy laborioso. Por ello, se crearon lenguajes de bajo nivel, ligeramente más legibles, llamados lenguajes ensambladores o simplemente ensambladores. Estos lenguajes son específicos para cada diseño de CPU y permiten usar nombres de variables y etiquetas para definir el flujo de instrucciones y los datos.

Lenguajes de alto nivel

Dado que el ensamblador sigue siendo arduo, se desarrollaron lenguajes de alto nivel, aún más fáciles de usar para los humanos, siendo una excelente introducción a lenguaje de programación para principiantes.

Un programa escrito en un lenguaje de alto nivel se traduce a ensamblador mediante un programa llamado compilador, o es ejecutado directamente por un programa llamado intérprete. Algunos de los lenguajes más antiguos de este tipo son FORTRAN, LISP y C. Aunque difieren enormemente en diseño y aplicación, su función dentro de la arquitectura del ordenador es la misma.

En el trabajo práctico, a menudo se encuentra lo que se conoce como una “pila” (stack) de software.

  • Mainframe: IBM, COBOL, FORTRAN, etc.
  • Microsoft: Windows, ASP, C#, SQL Server.
  • JVM: Java, Scala, Groovy.
  • Open Source: Linux, lenguajes (Python, PHP, Perl, C, C++, Go), bases de datos (MySQL, PostgreSQL), web (Apache, NGINX).

Los programadores suelen especializarse en uno de estos ecosistemas y utilizan los lenguajes y herramientas correspondientes. Existen también tecnologías como TCP/IP y la web que permiten la comunicación entre estas pilas.


Y ahí lo tienes. Hemos viajado desde la idea más básica de un interruptor hasta la complejidad de los lenguajes de alto nivel. Ahora no solo sabes ‘qué’ hace tu código, sino ‘cómo’ la máquina lo interpreta en su nivel más fundamental.

Entender esta relación entre el hardware y el software es crucial. Te permite depurar problemas de rendimiento, optimizar el uso de la memoria y, en última instancia, convertirte en un mejor ingeniero de software.

Si te interesa este tema, te recomiendo encarecidamente la lectura de Code: The Hidden Language of Computer Hardware and Software.

Pero el viaje no termina aquí. Conceptos como el Sistema Operativo, la virtualización con Docker o la computación en la nube son los siguientes paso. Abordaré esos temas en futuras guías o, también puedes recibirlas si te suscribes a nuestro boletín gratuito.

Categorizado en:

Fundamentos Programación,