Ir al contenido

UD01 · Introducción a la programación

Esta unidad no va de Java. Va de aprender a pensar los problemas antes de escribirlos, que es la parte que no cambia cuando cambia el lenguaje. Los lenguajes de moda de dentro de diez años todavía no existen; lo que aprendas aquí te va a servir con todos ellos. Java aparece al final, y solo para saludar.

  • Qué es un algoritmo y en qué se diferencia de un programa.
  • Cómo se pasa de un problema a una solución: análisis, diseño, codificación y pruebas.
  • Cómo se representa un algoritmo: pseudocódigo y diagramas de flujo.
  • Qué paradigmas de programación existen y por qué te conviene conocerlos.
  • Cómo llega tu código hasta el procesador: compiladores, intérpretes y la JVM.
  • A programar de verdad, con Scratch.
  • A ejecutar tu primer programa en Java.

Casi nadie aprende a programar porque le guste escribir código. Se aprende porque hay un problema que resolver y el ordenador es la herramienta que lo resuelve más rápido, más veces y sin cansarse. El código es el último paso del proceso, y normalmente el más corto: en un desarrollo real, el tiempo se va en entender qué hay que hacer y en comprobar que lo que has hecho funciona.

Conviene empezar entendiendo con qué clase de máquina estás tratando. Un ordenador es rapidísimo y absolutamente literal: hace exactamente lo que le dices, en el orden en que se lo dices, sin interpretar tus intenciones y sin avisarte de que probablemente querías decir otra cosa. Esa literalidad es lo que lo hace útil —siempre obtienes el mismo resultado— y también lo que convierte cualquier ambigüedad tuya en un error suyo. Si le pides que divida entre cero, no razonará que eso no tiene sentido: se romperá. Si te olvidas de contemplar que el usuario escriba una letra donde esperabas un número, tampoco lo pensará por ti.

Por eso programar consiste, sobre todo, en quitar ambigüedad. Y ese trabajo se parece bastante a resolver un problema sin ordenador:

En la vida real En programación
Observas la situación y entiendes qué pasa Análisis: qué datos tienes y qué resultado se espera
Piensas cómo resolverlo Diseño del algoritmo: los pasos, en orden y sin ambigüedad
Lo haces Codificación: traduces el algoritmo a un lenguaje de programación
Compruebas que ha salido bien Pruebas: lo ejecutas con datos concretos y verificas el resultado

Una buena solución tiene que cumplir dos cosas, y en este orden:

  1. Ser correcta. Que resuelva el problema. Siempre, no solo con el dato con el que la probaste. Un programa que calcula bien la nota media de tus notas pero se descuadra cuando alguien tiene un cero no es «casi correcto»: es incorrecto.
  2. Ser eficiente. Que lo haga en un tiempo razonable y sin gastar recursos de más. Buscar un nombre en una agenda revisando una por una las 5.000 fichas funciona; buscarlo saltando directamente a la letra correspondiente funciona igual de bien y termina antes. Con 5.000 fichas da un poco igual, pero con cinco millones la diferencia es entre responder al instante o no responder.
  • Abstracción — quedarte con lo que importa e ignorar el resto. Para calcular el precio de un pedido necesitas los productos, sus precios y las cantidades; no necesitas el color de la caja ni si el cliente prefiere el reparto por la mañana. Elegir bien qué ignoras es medio problema resuelto.
  • Divide y vencerás — un problema grande es un montón de problemas pequeños. Nadie escribe un videojuego de una sentada: escribe el movimiento del personaje, luego los disparos, luego los enemigos, luego el marcador. Cada pieza se prueba por separado, y cuando algo falla sabes exactamente dónde mirar.
  • Encapsulación — cada parte esconde cómo hace su trabajo y solo enseña qué hace. Puedes cambiarla por dentro sin romper el resto del programa. Cuando enciendes la tele con el mando no necesitas saber qué ocurre dentro; solo que el botón enciende.
  • Modularidad — cada parte hace una cosa y tiene un nombre que lo dice. Un módulo que «calcula el total y además envía el correo y de paso guarda en la base de datos» es imposible de reutilizar y difícil de arreglar.

Estas cuatro ideas no son teoría de examen: son la diferencia entre un programa que puedes seguir modificando dentro de seis meses y uno que da miedo tocar.

Algoritmo: secuencia ordenada de pasos, descrita sin ambigüedad, que resuelve un problema.

La palabra viene de al-Juarismi, un matemático persa del siglo IX, así que el concepto es unos mil años más viejo que los ordenadores. Y lo usas a diario sin llamarlo así: una receta de cocina es un algoritmo, las instrucciones para montar una estantería son un algoritmo, y el procedimiento que te enseñaron en primaria para dividir a mano es un algoritmo muy bueno, porque funciona con cualquier par de números y siempre termina.

Todo algoritmo debe cumplir tres condiciones:

  • Preciso: cada paso indica exactamente qué hacer y en qué orden. «Añade sal al gusto» le sirve a una persona, pero no a una máquina: el gusto de quién, cuánta sal.
  • Definido: con las mismas entradas produce siempre el mismo resultado. Si ejecutas dos veces el mismo algoritmo con los mismos datos y obtienes cosas distintas, no puedes fiarte de él ni depurarlo.
  • Finito: termina. Un algoritmo que no termina no es un algoritmo, es un bucle infinito, y lo vas a escribir sin querer más de una vez este curso.

¿Y la diferencia con un programa? El algoritmo es la idea; el programa es esa idea escrita en un lenguaje que el ordenador puede ejecutar. La receta de una tortilla es la misma en castellano o en inglés, la cocine quien la cocine, en gas o en vitrocerámica: cambia el idioma y cambia la cocina, pero los pasos son los mismos. El algoritmo es independiente del lenguaje y de la máquina; el programa, no.

Esto tiene una consecuencia práctica muy concreta: el algoritmo que diseñes hoy te sirve igual en Scratch, en Java o en cualquier lenguaje que aprendas dentro de cinco años. Aprender un lenguaje nuevo es cuestión de semanas; aprender a diseñar algoritmos es lo que estás haciendo ahora y cuesta bastante más.

Un algoritmo que solo está en tu cabeza no se puede revisar, ni discutir, ni entregar a otra persona. Antes de escribir código se expresa de una forma que cualquiera pueda leer, y para eso hay dos técnicas clásicas.

Pseudocódigo. Lenguaje natural con estructura: ni castellano suelto ni un lenguaje de programación concreto. No tiene un estándar oficial —cada libro y cada profesor usa una variante—, y no pasa nada: lo único que importa es que quien lo lea entienda sin dudas qué hay que hacer. Estas son las convenciones que usaremos aquí:

INICIO
Leer numero
Si numero < 1 o numero > 100 entonces
Escribir "Fuera de rango"
Si no
Si numero módulo 2 = 0 entonces
Escribir "Par"
Si no
Escribir "Impar"
Fin_si
Fin_si
FIN

Fíjate en dos detalles que sí importan: la indentación (cada bloque va metido hacia dentro respecto del que lo contiene, para ver de un vistazo qué depende de qué) y el hecho de que cada Si tiene su Fin_si. Son las dos costumbres que después te van a salvar en Java.

Diagrama de flujo. El mismo algoritmo, dibujado. Se lee siguiendo las flechas, y cada forma significa una cosa concreta:

Símbolo Significa
Óvalo Inicio o fin del proceso
Rectángulo Una acción o cálculo
Rombo Una decisión: sale por «sí» o por «no»
Romboide Entrada o salida de datos
Flecha Por dónde continúa la ejecución

El diagrama gana cuando hay muchas decisiones encadenadas y quieres ver los caminos de un vistazo, o cuando tienes que explicarle el proceso a alguien que no programa —un cliente, por ejemplo—. El pseudocódigo gana cuando el algoritmo es largo, porque dibujar cincuenta cajas es incómodo y leerlas, peor.

Este es el diagrama del mismo problema: decidir si un número es par.

Diagrama de flujo que comprueba si un número entre 1 y 100 es par o impar

Todo desarrollo, sea de tres líneas o de trescientos mil, recorre las mismas fases. Cambia cuánto tiempo dedicas a cada una y cuántas veces vuelves atrás, pero el recorrido es este.

  1. Análisis. Entender el problema. Termina cuando puedes responder a dos preguntas: ¿qué datos necesito? (entradas) y ¿qué resultado se espera? (salidas). Si no sabes responderlas, no sigas: pregunta. La mayor parte de los desastres de un proyecto no vienen de programar mal, sino de haber programado muy bien lo que no era.

  2. Diseño. Construir el algoritmo, normalmente descomponiendo el problema en partes más pequeñas hasta que cada parte sea evidente. Antes de dar el diseño por bueno se hace una traza: recorrer los pasos a mano, con datos concretos, anotando qué vale cada dato en cada momento. Es hacer tú de ordenador. Es aburrido, y es donde aparecen la mitad de los fallos.

  3. Codificación. Traducir el algoritmo al lenguaje elegido respetando su sintaxis, que son sus reglas de escritura. El resultado es el código fuente. Si el diseño está bien hecho, esta fase es casi mecánica.

  4. Pruebas. Ejecutarlo con datos normales, con datos límite (el cero, el valor máximo, la lista vacía) y con datos absurdos (letras donde esperas números, valores negativos). Un programa solo está probado cuando has intentado romperlo tú, porque si no lo haces tú lo hará el usuario el primer día.

  5. Explotación y mantenimiento. El programa se instala y se usa. A partir de ahí hay que corregir los fallos que aparezcan, adaptarlo cuando cambie algo a su alrededor —una ley, un formato, un sistema operativo— y añadir lo que vayan pidiendo.

Las fases no son una escalera de un solo sentido. Es normal estar probando y descubrir que el análisis tenía un agujero, y volver al principio. Lo que no es normal —ni sale gratis— es saltarse fases enteras para «ir más rápido».

Las fases anteriores se organizan de distintas maneras según el proyecto, y a cada forma de organizarlas se le llama modelo de ciclo de vida. Los clásicos son:

  • En cascada — una fase detrás de otra, sin volver atrás: no empiezas a diseñar hasta tener el análisis cerrado y firmado. Es simple de explicar y de planificar, y por eso se usó muchísimo. Su problema es que obliga a acertar los requisitos a la primera, y eso casi nunca pasa: el cliente no sabe del todo qué quiere hasta que ve algo funcionando. Cuando el fallo aparece al final, ya te has gastado el presupuesto.
  • Por prototipos — se construye primero una maqueta rápida, muchas veces desechable, para concretar con el cliente qué quiere de verdad. Después se desarrolla en serio. Se acepta tirar trabajo a la basura a cambio de no construir el producto equivocado.
  • Incremental — se entrega pronto una versión pequeña que funciona y se le van añadiendo capacidades en sucesivas entregas. El cliente ve resultados desde el principio y puede corregir el rumbo. Un procesador de textos empieza permitiendo escribir y guardar; la corrección ortográfica llega en la tercera entrega.
  • En espiral — como el incremental, pero analizando riesgos en cada vuelta antes de seguir. Pensado para proyectos grandes y caros, donde equivocarse sale muy caro.

Hoy, en la industria, lo habitual son los métodos ágiles (Scrum, Kanban): ciclos cortos de una o dos semanas, entregas continuas, contacto permanente con el cliente y requisitos que se ajustan sobre la marcha. En el fondo son modelos incrementales llevados al extremo, apoyados en herramientas que permiten integrar y desplegar cambios a diario. Lo verás en Entornos de Desarrollo y, sobre todo, cuando salgas a la FCT: es lo que te vas a encontrar en la empresa.

Paradigma: un modelo para diseñar y estructurar programas. Determina cómo piensas la solución, no solo cómo la escribes.

La diferencia de fondo entre unos y otros se resume en una pregunta: ¿le explicas a la máquina cómo hacer las cosas, paso a paso, o le describes qué quieres y dejas que ella resuelva el cómo? Es la diferencia entre darle a alguien las indicaciones de giro a giro para llegar a un sitio y decirle simplemente la dirección.

Describes cómo hacerlo: una secuencia de instrucciones que van cambiando el estado del programa. Es el enfoque más cercano a cómo funciona realmente el procesador, y dentro de él hay tres etapas históricas:

  • No estructurada: los primeros lenguajes, con saltos goto a cualquier parte del programa. El resultado se llamó código espagueti con toda la razón: imposible de seguir y de modificar. Es historia, y por buenas razones.
  • Estructurada: se demostró que cualquier programa puede escribirse con solo tres estructuras de control —secuencia, selección y repetición— y se añadieron las funciones para agrupar código reutilizable. Es la base de todo lo que viene después, y lo que trabajarás en la UD04.
  • Orientada a objetos: el programa se organiza en objetos que juntan datos y comportamiento, y que se comunican entre ellos. Es el paradigma del módulo a partir de la UD03, y el que domina el desarrollo profesional.

Escribes IO.println("Hola") y aparece un texto en pantalla. Entre una cosa y la otra hay más de lo que parece, y entenderlo explica cosas que si no parecen magia o manía.

Un procesador solo entiende lenguaje máquina: números binarios que codifican operaciones elementales —suma esto, mueve aquello, salta allá—. Programar así fue lo que se hizo al principio, y era exactamente tan malo como suena: cada programa servía para un único modelo de máquina, había que memorizar combinaciones de ceros y unos, y modificar cualquier cosa era una tortura.

El ensamblador mejoró la vida sustituyendo esos números por mnemotécnicos (MOV, ADD, MUL), que son palabras cortas para cada instrucción del procesador. Se lee muchísimo mejor, pero sigue siendo un lenguaje de bajo nivel: cada instrucción corresponde a una del procesador, así que sigues atado al hardware concreto y tienes que conocer la máquina por dentro. Hoy se usa en casos muy específicos —controladores, sistemas empotrados, optimizaciones extremas—, no para escribir aplicaciones.

Los lenguajes de alto nivel se parecen al lenguaje humano y son independientes del hardware: escribes precio * 1.21 en lugar de mover registros. Como el procesador no los entiende, hace falta traducirlos, y ahí hay dos estrategias:

Compilado Interpretado
Cuándo se traduce Antes de ejecutar, el programa entero Durante la ejecución, instrucción a instrucción
Qué produce Un fichero ejecutable Nada: se ejecuta al vuelo
Velocidad de ejecución Mayor Menor
Errores de sintaxis Aparecen al compilar, antes de ejecutar Aparecen al llegar a esa línea, ya en marcha
Para ejecutarlo hace falta Solo el ejecutable Tener el intérprete instalado
Ejemplos C, C++, Rust, Go Python, JavaScript, PHP

La diferencia práctica más importante para ti no es la velocidad, es cuándo te enteras de los fallos. En un lenguaje compilado, un error de escritura te lo dice el compilador antes de que el programa llegue a arrancar. En uno interpretado, puede pasar inadvertido hasta que un usuario entra justo en esa línea, seis meses después.

Java hace un recorrido en dos etapas, y esta es la idea clave de la unidad:

  1. Escribes el código fuente en un fichero .java. Es texto plano: se puede escribir con cualquier editor.

  2. El compilador lo traduce a bytecode (ficheros .class): un código intermedio, muy parecido a instrucciones máquina pero que no pertenece a ningún procesador concreto. No lo puede ejecutar directamente ningún ordenador.

  3. La máquina virtual de Java (JVM) lee ese bytecode y lo va traduciendo al lenguaje máquina real del ordenador donde estás. La JVM es un programa normal, y hay una versión distinta para cada sistema y arquitectura.

¿Para qué tanta vuelta? Para que el mismo fichero .class funcione en Windows, en macOS, en Linux o en un servidor sin tocar una línea ni recompilar nada. Lo que cambia de un sitio a otro es la JVM, que ya está escrita; tu programa, no. Es la idea que hizo famoso a Java: write once, run anywhere.

Vamos a programar de verdad, pero sin sintaxis. Scratch es un lenguaje visual creado por el MIT en el que las instrucciones son bloques de colores que encajan como piezas. Funciona en el navegador, no hay nada que instalar y no existe el punto y coma olvidado.

Que sea un lenguaje pensado para niños no lo convierte en un juguete para ti: todos los conceptos que vas a usar en Java durante el curso están ahí. La diferencia es que aquí no puedes equivocarte escribiendo —los bloques que no encajan, no encajan—, así que toda tu atención va a lo único que importa ahora mismo: la lógica. Cuando en la UD04 aparezca un while, no vas a estar aprendiendo qué es un bucle; solo cómo se escribe.

Un proyecto de Scratch tiene tres piezas:

  • El escenario, el fondo donde ocurre todo, con sus coordenadas: la x va de −240 a 240 y la y de −180 a 180, con el (0, 0) en el centro.
  • Los objetos (sprites): cada personaje, con sus disfraces (sus aspectos), sus sonidos y su propio programa. Que cada objeto tenga su código es más importante de lo que parece: es exactamente la idea que en la UD03 se llamará objeto, con sus datos y su comportamiento.
  • Los bloques, agrupados por categorías y por color: Movimiento, Apariencia, Sonido, Eventos, Control, Sensores, Operadores, Variables y Mis bloques.

En clase construiremos paso a paso un juego de naves espaciales. Cada paso añade una estructura de programación nueva, y esta es la razón real del orden:

  1. La nave se mueve. Un bucle por siempre con cuatro si … entonces dentro que comprueban las teclas W, A, S y D y suman o restan a la posición. Ya tienes repetición y selección en el primer paso.

  2. La nave dispara. El disparo es otro objeto que se coloca sobre la nave y sube hasta tocar el borde. Aparece repetir hasta que, que es un bucle con condición de salida.

  3. Los torpedos se acaban. Solo hay tres, así que hace falta una variable que los cuente y una condición que compruebe si queda alguno antes de disparar. Primera vez que el programa recuerda algo entre una acción y otra.

  4. Los enemigos aparecen y se mueven. Salen por arriba en una posición aleatoria, con un ángulo aleatorio. Entra el azar, que en Java será Math.random(), y entra también un bloque propio (definir inicio) que agrupa lo que hay que hacer cada vez que reaparece un enemigo: eso es una función, con su nombre y su reutilización.

  5. Las cosas chocan. Los sensores (¿tocando disparo?) detectan las colisiones, y la explosión se anima alternando dos disfraces.

  6. La partida termina. Cuando un enemigo toca a la nave, se envía un mensaje y todos los objetos que lo reciben reaccionan. Comunicación entre objetos, tal cual la usarás en la UD03.

  7. El enemigo final. Aparece tras eliminar a diez enemigos, se mueve aleatoriamente y aguanta ocho impactos antes de explotar. Junta todo lo anterior: variables, condiciones, mensajes y funciones.

Toda la construcción, con capturas de los bloques y los nueve ejercicios de ampliación, está en la presentación de clase:

En Scratch En Java (lo verás en…)
Bloques de Eventos (al hacer clic en 🏳) Métodos que responden a algo que ocurre — UD09
por siempre, repetir hasta que Bucles while y for — UD04
si … entonces / si no if / else — UD04
Variables (dar a torpedos el valor 3) Variables y tipos de datos — UD02
Mis bloques (definir inicio) Métodos y funciones — UD04
Objetos con sus disfraces y su código Clases y objetos — UD03
enviar mensaje / al recibir Comunicación entre objetos — UD03
número aleatorio entre 1 y 10 Math.random() — UD04
Clones de un objeto Instancias de una clase — UD03

Java nació en 1991 dentro de Sun Microsystems, en un proyecto que buscaba un lenguaje para programar pequeños dispositivos electrónicos: electrodomésticos, mandos, aparatos de televisión. El problema de ese mercado era que cada aparato llevaba un procesador distinto, y cambiar de aparato obligaba a reescribir el programa entero. De ahí nació la obsesión por la independencia de la plataforma que acabó siendo su gran virtud, aunque el negocio de los electrodomésticos no saliera.

En 1995 se presentó públicamente ya como Java y encajó con lo que estaba pasando: internet se estaba llenando de ordenadores distintos que necesitaban ejecutar el mismo software. En 2010 Oracle compró Sun, y hoy la implementación de referencia es OpenJDK, libre y de código abierto, sobre la que distintas empresas publican sus propias versiones.

Desde 2017 sale una versión nueva cada seis meses, y una versión LTS —soporte extendido, la que adoptan las empresas— cada dos años: Java 8, 11, 17, 21 y Java 25, publicada en septiembre de 2025. Es la que vamos a usar, y conviene que sepas por qué se insiste tanto: buena parte del código Java que encontrarás por internet está escrito para versiones de hace diez o quince años, y hace las cosas de una forma que hoy ya no es la recomendada.

  • Independiente de la plataforma, gracias al bytecode y la JVM.
  • Orientado a objetos, con programación funcional disponible desde Java 8.
  • Fuertemente tipado: cada dato tiene un tipo declarado y el compilador comprueba que lo usas de forma coherente. Es más pesado de escribir y evita una cantidad enorme de errores antes de ejecutar nada.
  • Gestión de memoria automática: el recolector de basura libera solo la memoria que ya no se usa. Tú no reservas ni liberas memoria a mano, que es de donde salía una parte enorme de los fallos graves —y de los agujeros de seguridad— en lenguajes como C.
  • Una biblioteca estándar enorme y un ecosistema gigantesco de librerías y herramientas. Buena parte de aprender Java consiste en aprender a encontrar y usar lo que ya existe, no en escribirlo tú.

Para programar necesitas el JDK (Java Development Kit), que incluye el compilador, la JVM y las bibliotecas. Para solo ejecutar programas basta con el entorno de ejecución, pero a ti te hace falta el JDK completo.

Crea un fichero llamado Hola.java con esto dentro:

Hola.java
void main() {
IO.println("¡Hola, DAM!");
}

Y ejecútalo desde un terminal, en la carpeta donde lo hayas guardado:

Ventana de terminal
java Hola.java

Ya está. Ni compilar a mano, ni crear un proyecto, ni abrir un IDE.

Lo que ocurre por debajo es lo que acabas de estudiar: Java compila tu fichero a bytecode en memoria y la JVM lo ejecuta, todo en un solo paso. Sigue habiendo compilación; simplemente no tienes que pedirla tú.

Hola.java
void main() {
IO.println("¡Hola, DAM!");
}

Tres líneas, y todo lo que ves se puede explicar hoy mismo: un bloque de código con un nombre (main) y una instrucción que escribe un texto.

Pídele a una IA (Claude, ChatGPT, Copilot…) esto:

Escríbeme un “Hola mundo” en Java.

Casi seguro que te devolverá la versión clásica con public class y static.

Tu tarea: pregúntale por qué no ha usado la sintaxis de Java 25 y comprueba si sabe rectificar. Fíjate en si te da la razón sin más o si te explica algo con sentido.

Currículo oficial del móduloRA1 — 8 h · 1º trimestre

Resultados de aprendizaje y criterios de evaluación que se trabajan en esta unidad, según la ORDEN de 16 de junio de 2011 (BOJA núm. 142). Ver el mapa completo del módulo.

Unidad de fundamentos: algoritmos, paradigmas y ciclo de vida del software, con Scratch como primer entorno. Java aparece solo al final, con un «hola mundo».

RA1Reconoce la estructura de un programa informático, identificando y relacionando los elementos propios del lenguaje de programación utilizado.

  • a) Se han identificado los bloques que componen la estructura de un programa informático.

© 2026 Carlos Barroso · Contenido bajo CC BY-NC-SA 4.0