Paradigmas de Programación
🚀 Clases en Vivo — Inicio: Domingo 6 de Septiembre ($200 MXN / clase). Aprende a programar desde cero con acompañamiento directo y construye el proyecto ShortURL.
En la Lección 3: Language Tour (L3) descubrimos la caja de herramientas de JavaScript para manipular textos, listas y objetos, además de blindar nuestras aplicaciones con try / catch.
Ahora que sabemos escribir código funcional, surge una pregunta fundamental: ¿Cómo organizamos programas grandes sin que se conviertan en un laberinto incontrolable? Aquí es donde entran los Paradigmas de Programación: diferentes filosofías y estilos para estructurar el pensamiento y resolver problemas en software.
En esta sesión intensiva de 4 horas, exploraremos los tres paradigmas indispensables de la industria: la Programación Orientada a Objetos (POO), la Programación Funcional y el superpoder de la Asincronía (Promises y async / await).
🗺️ Estructura de la Sesión
Cada una de nuestras sesiones semanales sigue una metodología pedagógica dividida en 5 fases:
Estructura de la Sesión├── ☕ Fase 1: Revisión del Tema Anterior y Conclusiones├── 🎯 Fase 2: Introducción al Tema y Fundamentos├── 💻 Fase 3: Práctica Asistida en Vivo├── 🗣️ Fase 4: Exposición, Debate y Debugging└── 🏠 Fase 5: Reto Semanal y Práctica en Casa☕ Fase 1: Revisión del Tema Anterior y Conclusiones
Comenzamos la sesión revisando el proyecto de analíticas de e-commerce y reflexionando sobre la organización del código.
1. Puesta en Común del Reto de la Lección 3
En la lección previa construimos el “Motor de Analíticas de Ventas”, combinando filter(), map(), reduce() y try / catch:
- Discusión en grupo: ¿Cómo sentiste la diferencia entre escribir un bucle
formanual y usarmap()ofilter()? - ¿Qué ventajas encontraste al envolver cálculos críticos dentro de
try / catch? - Si tuviéramos 50 tipos diferentes de productos con reglas complejas (garantías, envíos internacionales, devoluciones), ¿dónde colocarías esa lógica sin duplicar código?
2. El Puente Conceptual: ¿Qué es un Paradigma?
Un paradigma es simplemente una forma de ver y organizar el mundo a través del código:
- Programación Imperativa: Le dice a la computadora exactamente cómo hacer las cosas paso por paso (como una receta de cocina muy estricta).
- Programación Orientada a Objetos (POO): Modela el software agrupando datos y comportamientos en “cajas inteligentes” llamadas Objetos (como autos, cuentas bancarias o usuarios).
- Programación Funcional: Trata a las funciones como tuberías matemáticas puras que transforman datos sin alterar el estado global.
- Programación Asíncrona: Permite que nuestro programa realice tareas que toman tiempo (como descargar un archivo o consultar una base de datos) sin congelar la pantalla del usuario.
JavaScript es un lenguaje multiparadigma, lo que significa que puedes combinar lo mejor de cada mundo en un solo proyecto.
🎯 Fase 2: Introducción al Tema y Fundamentos Teóricos
Analicemos en profundidad los tres pilares estructurales del software moderno.
1. Programación Orientada a Objetos (POO): Clases e Instancias
Imagina los planos de un arquitecto para construir casas:
- La Clase (
class): Es el plano arquitectónico. Define qué propiedades tendrá la casa (número de habitaciones, color) y qué acciones se pueden hacer en ella (abrir puerta, encender luces). - La Instancia / Objeto: Es la casa real construida en el terreno. Con un solo plano puedes construir 100 casas distintas, cada una con su propio color y dueño.
// 1. El Plano (Clase)class Usuario { constructor(nombre, email) { this.nombre = nombre; // Propiedad this.email = email; // Propiedad this.activo = true; }
// Método (Acción que el usuario puede realizar) desactivarCuenta() { this.activo = false; return `La cuenta de ${this.nombre} ha sido desactivada.`; }}
// 2. Construimos una casa real a partir del plano (Instancia con "new")console.log(usuario1.nombre); // "Lucía Méndez"console.log(usuario1.desactivarCuenta());2. Programación Funcional: Funciones Puras e Inmutabilidad
En la Programación Funcional, pensamos en las funciones como licuadoras de cocina:
- Si colocas fresas y leche, siempre obtendrás jugo de fresa.
- La licuadora no cambia el color de las paredes de tu cocina (no tiene efectos secundarios).
- Una Función Pura es aquella que con las mismas entradas siempre devuelve la misma salida y no altera variables fuera de sí misma.
// Función Pura: No modifica nada externo, solo transforma y retornafunction aplicarDescuento(precioOriginal, porcentaje) { return precioOriginal - (precioOriginal * (porcentaje / 100));}
console.log(aplicarDescuento(100, 20)); // 80 (siempre dará 80)3. Asincronía: La Analogía del Restaurante y el Zumbador
¿Qué ocurre cuando vas a pedir comida a un restaurante rápido?
- Llegas al mostrador y pides tu hamburguesa.
- El cajero no te hace esperar parado 15 minutos en el mostrador congelando la fila de clientes.
- En su lugar, te entrega un zumbador electrónico (Buzzer): una Promesa de que tu comida estará lista en el futuro.
- Mientras la cocina prepara tu comida, tú te sientas a revisar tu teléfono (el programa sigue funcionando).
- Cuando la comida está lista, el zumbador vibra (
.then()oawait) y recoges tu pedido.
Flujo Asíncrono[Hacer Pedido] ──► [Recibir Promesa / Zumbador] ──► [Hacer otras cosas] ──► [¡Comida Lista! (await)]En JavaScript moderno usamos async / await para esperar promesas de forma limpia y legible:
// La palabra "async" convierte la función en un proceso asíncronoasync function prepararCafe() { console.log("1. Pidiendo café al barista...");
// "await" pausa esta función hasta que la promesa se complete, sin congelar el navegador await esperarSegundos(2);
console.log("2. ☕ ¡Café listo para disfrutar!");}🔍 Experimento en Vivo: Síncrono vs Asíncrono en la Consola
Vamos a experimentar la diferencia en vivo:
- Abre la consola de tu navegador (
F12). - Ejecuta este código con un temporizador asíncrono (
setTimeout):console.log("🟢 Paso 1: Inicio");setTimeout(() => {console.log("🟡 Paso 2: Tarea en segundo plano completada tras 2 segundos");}, 2000);console.log("🔴 Paso 3: Fin del script principal"); - Observa el orden en la consola: Verás que aparece primero el
Paso 1, de inmediato elPaso 3, y 2 segundos después elPaso 2. ¡JavaScript nunca se congeló!
💻 Fase 3: Práctica Asistida en Vivo
Abriremos la consola y resolveremos juntos 4 retos guiados combinando POO, funciones puras y asincronía.
🧩 Reto 1: Modelando una CuentaBancaria con POO
Objetivo: Crear una clase con estado interno protegido y métodos que validen reglas de negocio.
class CuentaBancaria { constructor(titular, saldoInicial = 0) { this.titular = titular; this.saldo = saldoInicial; this.historial = []; }
depositar(monto) { if (monto <= 0) { return "❌ El monto a depositar debe ser mayor a 0."; } this.saldo += monto; this.historial.push(`Depósito: +$${monto}`); return `Depósito exitoso. Saldo actual: $${this.saldo}`; }
retirar(monto) { if (monto > this.saldo) { return `❌ Fondos insuficientes. Intentaste retirar $${monto}, pero tu saldo es $${this.saldo}`; } this.saldo -= monto; this.historial.push(`Retiro: -$${monto}`); return `Retiro exitoso de $${monto}. Saldo restante: $${this.saldo}`; }
consultarEstado() { return { titular: this.titular, saldo: this.saldo, movimientos: this.historial }; }}
// Pruebas en consola:const miCuenta = new CuentaBancaria("Joul Medina", 500);console.log(miCuenta.depositar(200)); // Saldo: 700console.log(miCuenta.retirar(100)); // Saldo: 600console.log(miCuenta.retirar(1000)); // Fondos insuficientesconsole.log(miCuenta.consultarEstado());🧩 Reto 2: Tubería Funcional de Transformación de Datos
Objetivo: Encadenar funciones puras para limpiar y transformar una lista de precios en dólares a moneda local formateada.
const preciosUSD = [12.5, 45.0, 99.99, 5.0, 150.0];const TASA_CAMBIO = 18.5; // Pesos por dólar
// 1. Funciones puras independientesconst convertirAMonedaLocal = (precioUSD) => precioUSD * TASA_CAMBIO;const redondear = (monto) => Math.round(monto * 100) / 100;const darFormatoMoneda = (monto) => `$${monto.toFixed(2)} MXN`;
// 2. Tubería de procesamiento con map encadenadoconst preciosFormateados = preciosUSD .map(convertirAMonedaLocal) .map(redondear) .map(darFormatoMoneda);
console.log("Precios originales (USD):", preciosUSD);console.log("Precios procesados:", preciosFormateados);🧩 Reto 3: Creando y Resolviendo una Promesa Real
Objetivo: Crear una función que simule la descarga de un archivo con resolución exitosa o fallo aleatorio.
function descargarArchivo(nombreArchivo) { return new Promise((resolve, reject) => { console.log(`⏳ Descargando "${nombreArchivo}" desde el servidor...`);
setTimeout(() => { const conexionExitosa = true; // Cambia a false para probar el error
if (conexionExitosa) { resolve(`✅ Archivo "${nombreArchivo}" descargado con éxito (5.4 MB)`); } else { reject(new Error(`❌ Error de red al descargar "${nombreArchivo}"`)); } }, 2000); });}
// Consumo con .then() y .catch():descargarArchivo("reporte_anual.pdf") .then(mensajeExito => console.log(mensajeExito)) .catch(error => console.error(error.message));🧩 Reto 4: Sincronización de Procesos con async / await y try / catch
Objetivo: Coordinar dos tareas asíncronas consecutivas de forma limpia sin callbacks anidados.
function simularEspera(segundos) { return new Promise(resolve => setTimeout(resolve, segundos * 1000));}
async function procesarRegistroUsuario(nombreUsuario) { try { console.log(`1. Verificando disponibilidad de "${nombreUsuario}"...`); await simularEspera(1.5); console.log(" -> Nombre disponible.");
console.log("2. Guardando usuario en la base de datos..."); await simularEspera(1.5); console.log(" -> Usuario guardado.");
console.log("3. Enviando correo de bienvenida..."); await simularEspera(1.0); console.log(" -> Correo enviado.");
return `🎉 ¡Registro de ${nombreUsuario} completado con éxito!`; } catch (error) { return `⚠️ Falla en el proceso de registro: ${error.message}`; }}
// Ejecutamos la función asíncrona:procesarRegistroUsuario("joul_dev").then(resultado => console.log(resultado));🗣️ Fase 4: Exposición de Resultados, Debate y Debugging
Compartimos soluciones y analizamos las trampas más frecuentes al trabajar con clases y asincronía.
🐞 Las 4 Trampas Clásicas de Paradigmas y Asincronía
1. Olvidar la palabra clave new al crear un objeto
- El error: Escribir
const cuenta = CuentaBancaria("Ana", 100);sinnew. - Consecuencia:
TypeError: Class constructor CuentaBancaria cannot be invoked without 'new'. - Solución: Las clases siempre requieren
newpara reservar su espacio en memoria.
2. Olvidar la palabra await en una función asíncrona
- El error: Escribir
const datos = descargarArchivo("datos.csv");sinawait. - Consecuencia: En lugar de recibir el texto del archivo,
datoscontendrá un objetoPromise { <pending> }. - Solución: Siempre que llames a una función que devuelva una promesa dentro de una función
async, antepónawait.
3. Errores Asíncronos no Capturados (Unhandled Promise Rejection)
- El error: Llamar a una función asíncrona que falla sin envolver el
awaiten untry / catch. - Consecuencia: El navegador o Node.js emitirá una advertencia crítica de promesa no manejada.
- Solución: Todo código asíncrono con
awaitdebe vivir dentro de un bloquetry { ... } catch (error) { ... }.
4. Modificar variables globales dentro de funciones
- El error: Que una función altere un arreglo global en lugar de recibirlo como parámetro y devolver uno nuevo.
- Consecuencia: Rompe el principio de funciones puras y causa errores “fantasma” difíciles de rastrear.
🏠 Fase 5: Definición de Práctica en Casa / Reto Semanal
Para consolidar la POO y la Asincronía, construirás el simulador de una cocina digital.
🏆 Proyecto Semanal: “El Simulador Asíncrono de Restaurante y Cocina”
Descripción del Problema: Un restaurante necesita un sistema para gestionar pedidos. Cada pedido debe representarse como un objeto con su estado, y pasar por las etapas de cocina con retardos de tiempo reales.
Especificaciones Técnicas del Proyecto:
-
Clase
Pedido(POO):- Propiedades:
id,cliente,platillo,estado(inicia en"Recibido"),precio. - Métodos:
actualizarEstado(nuevoEstado): Cambia el estado del pedido y muestra un mensaje en consola.resumen(): Devuelve un texto con la información completa del pedido.
- Propiedades:
-
Proceso de Cocina Asíncrono (
async / await):- Crea una función asíncrona
cocinarPedido(pedido)que ejecute las siguientes etapas secuenciales con pausas de tiempo (setTimeouten Promesas):- Paso 1 (1 segundo): Cambiar estado a
"Preparando ingredientes". - Paso 2 (2 segundos): Cambiar estado a
"Cocinando en el fuego". - Paso 3 (1.5 segundos): Cambiar estado a
"Emplatando y decorando". - Paso 4 (1 segundo): Cambiar estado a
"¡Listo para entrega!".
- Paso 1 (1 segundo): Cambiar estado a
- Crea una función asíncrona
-
Control de Errores con
try / catch:- Si el platillo pedido es
"Veneno"o un texto vacío, la función debe lanzar unthrow new Error("Platillo no permitido en el menú")y el bloquecatchdebe reportar la cancelación del pedido.
- Si el platillo pedido es
-
Prueba en Consola:
- Crea 2 pedidos (ej.
Pedido 1: "Hamburguesa Gourmet",Pedido 2: "Pizza Margarita"), inícialos y observa cómo la consola narra el progreso de ambos en tiempo real.
- Crea 2 pedidos (ej.
📚 Recursos y Videos Recomendados
Para profundizar en POO, Programación Funcional y Asincronía:
🚀 Conclusión y Próximos Pasos
¡Excelente trabajo! Has dado un salto cuántico en tu madurez como desarrollador. Ahora comprendes cómo modelar entidades con Clases (POO), cómo escribir código predecible con Funciones Puras y cómo manejar tareas en segundo plano con Promesas y Async/Await.
Con estos fundamentos listos, en la próxima sesión daremos el paso hacia el desarrollo de aplicaciones completas: Lección 5: Stacks Tecnológicos & Arquitectura del Proyecto ShortURL (L5), donde diseñaremos nuestro gran proyecto de fin de curso.
🚀 Clases en Vivo — Inicio: Domingo 6 de Septiembre ($200 MXN / clase). Aprende a programar desde cero con acompañamiento directo y construye el proyecto ShortURL.