Del BASIC al JavaScript: La Ironía del Código Espagueti Moderno

O cómo aprendimos a amar el GOTO otra vez, pero con nombres más elegantes

Editorial 494 vistas 5 minutos
foto de Del BASIC al JavaScript: La Ironía del Código Espagueti Moderno

Una Reflexión Desde la Commodore 64

Corría el año... bueno, eso no importa. Lo que importa es que muchos de nosotros aprendimos a programar en una época donde las cosas eran brutalmente simples. Una Commodore 64, 64KB de RAM y BASIC como lenguaje. Nada de frameworks, nada de transpiladores, nada de npm install. Solo tú, el manual y líneas numeradas.

Y resulta que, después de décadas de "evolución" en el desarrollo de software, hemos llegado a una conclusión incómoda: el código moderno es básicamente el mismo GOTO de siempre, pero con nombres más fancy.

El Pecado Original: El Temido GOTO

Durante años, el GOTO ha sido el villano de la programación estructurada. "¡Código espagueti!", gritaban los puristas. "¡Control de flujo incomprensible!", declaraban en sus papers académicos.

Y tenían razón. Esto era una pesadilla:

10 PRINT "Inicio del programa"
20 GOTO 100
30 PRINT "Esto nunca se ejecuta"
40 GOTO 200
50 PRINT "Tampoco esto"

100 PRINT "Haciendo algo importante"
110 IF X = 1 THEN GOTO 300
120 GOTO 400

200 PRINT "¿Cómo llegué aquí?"
210 GOTO 50

300 PRINT "Rama A"
320 GOTO 500

400 PRINT "Rama B" 
410 GOTO 600

500 PRINT "Continuando A"
510 GOTO 40

600 PRINT "Fin... ¿o no?"

Imposible de seguir. Un laberinto de saltos sin lógica aparente.

La Solución "Moderna": Funciones con Nombres Bonitos

Entonces llegaron las funciones, la programación estructurada y más tarde la programación orientada a objetos. "¡Ya no más GOTO!", celebraron. "¡Código limpio y mantenible!", prometieron.

Veamos cómo se ve el "código moderno":

async function procesarPedido() {
  const usuario = await obtenerUsuario()
  const productos = await validarProductos(usuario)
  const pago = await procesarPago(productos)
  const envio = await gestionarEnvio(pago)

  return await confirmarPedido(envio)
}

async function obtenerUsuario() {
  return await buscarEnBaseDatos('usuarios')
}

async function validarProductos(usuario) {
  const productos = await obtenerProductos()
  return await verificarDisponibilidad(productos, usuario)
}

async function procesarPago(productos) {
  const metodo = await seleccionarMetodoPago()
  return await cargarTarjeta(metodo, productos)
}

// ... y así sucesivamente

Momento. Analicemos esto:

  1. procesarPedido() dice: "Ve a obtenerUsuario()"
  2. obtenerUsuario() dice: "Ve a buscarEnBaseDatos()"
  3. Regresa a procesarPedido(), que dice: "Ahora ve a validarProductos()"
  4. validarProductos() dice: "Ve a obtenerProductos()"
  5. Luego dice: "Ve a verificarDisponibilidad()"
  6. Regresa y procesarPedido() dice: "Ahora ve a procesarPago()"

¿Te suena familiar? Es exactamente lo mismo que:

10 GOSUB 1000  ' Ve a obtener usuario
20 GOSUB 2000  ' Ve a validar productos  
30 GOSUB 3000  ' Ve a procesar pago
40 GOSUB 4000  ' Ve a gestionar envío
50 GOSUB 5000  ' Ve a confirmar pedido
60 END

1000 REM Obtener usuario
1010 GOSUB 6000  ' Ve a buscar en base de datos
1020 RETURN

2000 REM Validar productos
2010 GOSUB 7000  ' Ve a obtener productos
2020 GOSUB 8000  ' Ve a verificar disponibilidad
2030 RETURN

La Brutal Realidad: Solo Cambiaron los Nombres

La diferencia entre GOTO 1000 y await obtenerUsuario() es puramente cosmética:

| BASIC                 | JavaScript "Moderno"   |
| --------------------- | ---------------------- |
| `GOSUB 1000`          | `await miFuncion()`    |
| `RETURN`              | `return valor`         |
| Números de línea      | Nombres de función     |
| Un archivo secuencial | 47 archivos esparcidos |

La lógica de control es idéntica: "Deja lo que estás haciendo, ve a ejecutar esto otro y regresa con el resultado".

El Nuevo Infierno: Código Espagueti Distribuido

Pero espera, porque la cosa se pone peor. Al menos en BASIC todo estaba en un archivo, en orden secuencial. El JavaScript moderno es un nuevo tipo de tortura:

Archivo: main.js

import { inicializarApp } from './utils/init.js'
import { procesarPedido } from './services/pedido.js'

async function init() {
  await inicializarApp()
  await procesarPedido()
}

init()

Archivo: services/pedido.js

import { Usuario } from '../models/Usuario.js'
import { PagoService } from '../external/pagos.js'
import { validarProductos } from '../validators/productos.js'

export async function procesarPedido() {
  const usuario = await Usuario.obtener()
  const productos = await validarProductos(usuario)

  return await PagoService.procesar(productos)
}

Archivo: validators/productos.js

import { StockService } from '../services/stock.js'
import { ProductoRepository } from '../repositories/productos.js'

export async function validarProductos(usuario) {
  const productos = await ProductoRepository.obtenerPorUsuario(usuario.id)

  return await StockService.verificar(productos)
}

¡Es una búsqueda del tesoro! Para entender qué hace el programa necesitas:

  1. ✅ Encontrar el archivo de entrada (¿cuál es?)
  2. ✅ Seguir los imports como si fueran GOTOs
  3. ✅ Saltar entre archivos como un pinball
  4. ✅ Mantener en tu cabeza el estado de 15 funciones simultáneamente
  5. ✅ Rezar para que no haya imports circulares

La Nostalgia de la Simplicidad

Recordemos cómo era programar en la Commodore 64:

10 REM *** SISTEMA DE INVENTARIO ***
20 REM *** POR: TU NOMBRE ***
30 REM *** FECHA: 1985 ***
40 CLS
50 PRINT "=== INVENTARIO DE LA TIENDA ==="
60 PRINT
70 GOSUB 1000  ' MOSTRAR MENU
80 GOSUB 2000  ' PROCESAR OPCION
90 IF OPCION <> 9 THEN GOTO 70
100 PRINT "¡ADIOS!"
110 END

1000 REM *** MOSTRAR MENU ***
1010 PRINT "1. AGREGAR PRODUCTO"
1020 PRINT "2. BUSCAR PRODUCTO"  
1030 PRINT "3. LISTAR PRODUCTOS"
1040 PRINT "9. SALIR"
1050 PRINT "OPCION: ";
1060 INPUT OPCION
1070 RETURN

2000 REM *** PROCESAR OPCION ***
2010 IF OPCION = 1 THEN GOSUB 3000
2020 IF OPCION = 2 THEN GOSUB 4000
2030 IF OPCION = 3 THEN GOSUB 5000
2040 RETURN

3000 REM *** AGREGAR PRODUCTO ***
3010 PRINT "NOMBRE DEL PRODUCTO: ";
3020 INPUT NOMBRE$
3030 PRINT "PRECIO: ";
3040 INPUT PRECIO
3050 PRINT "PRODUCTO AGREGADO!"
3060 RETURN

¿Qué podías hacer?

  • LIST - Ver todo el código de un vistazo
  • RUN - Ejecutar inmediatamente
  • GOTO 1000 - Saltar a cualquier línea para debugging
  • ✅ Todo en un archivo, orden lógico
  • ✅ Variables globales (sin vergüenza)
  • ✅ Flujo de control obvio

El Equivalente Moderno: Un Calvario

El mismo programa hoy requeriría:

proyecto/
├── package.json
├── webpack.config.js  
├── babel.config.js
├── .eslintrc.json
├── src/
│   ├── index.js
│   ├── components/
│   │   ├── Menu.js
│   │   ├── ProductForm.js
│   │   └── ProductList.js
│   ├── services/
│   │   ├── ProductService.js
│   │   └── StorageService.js
│   ├── utils/
│   │   ├── validators.js
│   │   └── formatters.js
│   └── styles/
│       ├── main.css
│       └── components.css
├── tests/
│   ├── unit/
│   └── integration/
└── node_modules/ (3,000 carpetas)

Para ejecutar:

npm install
npm run build
npm run dev

Para entender el flujo:

  1. 🔍 Buscar el entry point en package.json
  2. 🔍 Seguir los imports como breadcrumbs
  3. 🔍 Entender webpack, babel y el build process
  4. 🔍 Debugging con sourcemaps
  5. 🤯 Abandonar y buscar documentación

La Ironía Suprema

Los programadores modernos critican el GOTO, pero hacen esto diariamente:

// "Clean Code" moderno
class UserService {
  async getUser(id) {
    return await this.repository.findById(id)
  }
}

class UserRepository {
  async findById(id) {
    return await this.database.query(`SELECT * FROM users WHERE id = ?`, [id])
  }
}

class Database {
  async query(sql, params) {
    return await this.connection.execute(sql, params)
  }
}

// Para obtener un usuario:
const user = await userService.getUser(123)

Traducido a BASIC honesto:

10 GOSUB 1000  ' UserService.getUser()
20 END

1000 GOSUB 2000  ' UserRepository.findById()
1010 RETURN

2000 GOSUB 3000  ' Database.query()
2010 RETURN  

3000 REM Aquí sí hace algo útil
3010 PRINT "SELECT * FROM users WHERE id = 123"
3020 RETURN

¡Es el mismo patrón! Solo que ahora necesitas:

  • ✅ Entender inyección de dependencias
  • ✅ Configurar un ORM
  • ✅ Instalar 47 librerías
  • ✅ 3 clases para hacer un SELECT

La Moraleja

No estoy abogando por volver al GOTO descontrolado. La programación estructurada trajo beneficios reales:

  • ✅ Reutilización de código
  • ✅ Modularidad
  • ✅ Testabilidad
  • ✅ Mantenimiento (cuando está bien hecho)

Pero debemos ser honestos: hemos reemplazado la simplicidad brutal del BASIC por una complejidad que a menudo es innecesaria.

Lecciones de la Commodore 64

Los programadores que aprendimos en esa época desarrollamos algo valioso: la capacidad de ver el flujo de control directamente.

En BASIC:

  • Cada línea tenía un número - sabías exactamente dónde estabas
  • LIST 100-200 te mostraba el código que necesitabas
  • GOTO 150 te llevaba exactamente donde querías ir
  • No había capas de abstracción ocultando la lógica

En JavaScript moderno:

  • Las funciones están esparcidas por múltiples archivos
  • Los imports crean dependencias que hay que rastrear mentalmente
  • Los async/await crean el mismo "salta para allá" del GOTO
  • Las abstracciones a veces ocultan más de lo que ayudan

El GOTO Nunca Se Fue

El GOTO no desapareció - solo se volvió más sofisticado y se escondió detrás de nombres elegantes.

await obtenerDatosDelServidorYProcesarlosConValidacionCompleta() es básicamente GOSUB 2000 con un nombre más largo.

La diferencia es que ahora:

  • ✅ Los nombres son descriptivos (mejor para el mantenimiento)
  • ✅ Hay scope y encapsulación (mejor para la organización)
  • ✅ Hay herramientas mejores (debugging, testing, etc.)

Pero también:

  • ❌ Múltiples archivos crean complejidad innecesaria
  • ❌ Over-engineering es la norma
  • ❌ Simple problems get complex solutions
  • ❌ La curva de aprendizaje es astronómica

Reflexión Final

Tal vez la verdadera lección no es que el GOTO era malo, sino que cualquier paradigma llevado al extremo se vuelve problemático.

El BASIC de la Commodore 64 nos enseñó algo que hemos olvidado: a veces la simplicidad brutal es mejor que la complejidad elegante.

No todo necesita ser un microservicio. No todo necesita 15 capas de abstracción. No todo necesita un framework.

A veces, solo necesitas un simple:

10 PRINT "HELLO, WORLD!"
20 END

Y eso está perfectamente bien.

Contáctanos por WhatsApp

¡Comunícate con nosotros para trabajar con tu nueva gran idea! Responderemos a la brevedad.

Enviar mensaje
Horario de atención: 9am - 6pm
ES EN

Copyright © 2025 Código Móvil!!. Todos los Derechos Reservados.