Volver OPIFEX

Fundamentos de Programación para Ingenieros que Vibecodean

Para ingenieros que usan IA para programar y les funciona, pero quieren entender QUÉ están haciendo, no solo que funcione.

1. Tipos de Datos — Los Materiales de Construcción

En ingeniería no mezclas acero con hormigón sin saber qué hace cada uno. En código es igual: cada dato tiene un tipo, y mezclarlos mal causa el 50% de los bugs.

Los básicos

// JavaScript
let nombre = "Adrián";           // String — texto, siempre entre comillas
let edad = 32;                    // Number — número (entero o decimal)
let esPadre = true;               // Boolean — verdadero o falso, sin más
let nulo = null;                  // Null — "esto existe pero está vacío"
let sinDefinir = undefined;       // Undefined — "esto ni se ha definido"
# Python — casi igual pero con matices
nombre = "Adrián"                 # str
edad = 32                         # int (entero)
precio_kg = 1.43                  # float (decimal)
es_padre = True                   # bool (ojo: True/False con mayúscula)
nulo = None                       # None (equivale a null)

Colecciones — donde se complica (y donde importa)

Arrays / Listas — una lista ordenada de cosas:

// JS: Array
let materiales = ["PGC", "PGU", "Triangle"];
materiales[0];  // "PGC" — los índices empiezan en 0, no en 1
materiales.length;  // 3
materiales.push("Viroc");  // añade al final
# Python: Lista
materiales = ["PGC", "PGU", "Triangle"]
materiales[0]  # "PGC"
len(materiales)  # 3
materiales.append("Viroc")  # añade al final

Objetos / Diccionarios — el tipo de dato más importante que vas a usar:

// JS: Objeto
let panel = {
  tipo: "PGC",
  espesor: 1.2,        // mm
  acero: "Z275",
  peso_m2: 10,          // kg/m²
  certificado: true
};

panel.tipo;       // "PGC"
panel.espesor;    // 1.2
panel["acero"];   // "Z275" — otra forma de acceder
# Python: Diccionario
panel = {
    "tipo": "PGC",
    "espesor": 1.2,
    "acero": "Z275",
    "peso_m2": 10,
    "certificado": True
}

panel["tipo"]     # "PGC"
panel.get("acero")  # "Z275" — más seguro, no explota si no existe

¿Por qué importa? Porque las APIs, bases de datos, configs... TODO devuelve objetos/diccionarios. Cuando ves esto:

{
  "status": "running",
  "balance": 1250.50,
  "positions": [
    {"symbol": "BTC", "size": 0.01, "pnl": 15.20}
  ]
}

Eso es un objeto con un array de objetos dentro. Si sabes leer esto, sabes leer el 90% del código que tocas.

Trampas comunes

// El clásico bug de tipos
"5" + 3      // "53" — ¡concatena como texto! No suma.
"5" - 3      // 2 — aquí sí resta. JavaScript es raro.
5 + 3        // 8 — esto sí es lo esperado

// Comparación
"5" == 5     // true — JS convierte tipos (peligroso)
"5" === 5    // false — comparación estricta (usa SIEMPRE esta)

2. Variables y Scope — Dónde Vive Cada Cosa

Declaración (JS)

const PI = 3.14159;      // Constante — no cambia nunca. Usa esto por defecto.
let contador = 0;         // Variable — puede cambiar. Usa cuando necesites reasignar.
var antiguo = "no uses";  // Antiguo — tiene bugs de scope. No lo uses.

Regla: usa const siempre. Solo usa let si necesitas reasignar. var nunca.

Scope — el muro entre habitaciones

const edificio = "Hotel Los Patios";  // Scope global — visible desde cualquier sitio

function calcularPeso() {
  const peso_panel = 10;  // Scope local — solo existe dentro de esta función
  console.log(edificio);  // ✅ Puede ver el global
  console.log(peso_panel); // ✅ Puede ver lo suyo
}

console.log(peso_panel);   // ❌ ERROR — no existe fuera de la función

Piénsalo como plantas de un edificio: desde la planta 3 ves la planta baja (global), pero desde la planta baja no ves lo que hay en la 3.

3. Funciones — Las Máquinas de la Obra

Una función es una máquina: le metes material (parámetros), hace algo, y saca un resultado (return).

// Definir la máquina
function calcularPesoPanel(ancho, alto, peso_m2) {
  const area = ancho * alto;
  const peso = area * peso_m2;
  return peso;  // Lo que sale de la máquina
}

// Usar la máquina
const peso = calcularPesoPanel(2.24, 3.0, 10);
console.log(peso);  // 67.2 kg
# Python — igual pero sin llaves
def calcular_peso_panel(ancho, alto, peso_m2):
    area = ancho * alto
    peso = area * peso_m2
    return peso

peso = calcular_peso_panel(2.24, 3.0, 10)
print(peso)  # 67.2

Arrow functions (JS moderno)

// Forma clásica
function sumar(a, b) { return a + b; }

// Arrow function — lo mismo, más corto
const sumar = (a, b) => a + b;

// Las verás MUCHO en React (MMA Manager) y en callbacks
materiales.filter(m => m.espesor > 1.5);
materiales.map(m => m.tipo.toUpperCase());

Callbacks — funciones que llaman a otras funciones

// "Cuando termines de cargar los datos, ejecuta esta función"
fetch("/api/status")
  .then(response => response.json())     // callback 1: convierte a JSON
  .then(data => console.log(data))        // callback 2: usa los datos
  .catch(error => console.error(error));  // callback 3: si falla

Esto es como decirle al operario de grúa: "Cuando subas el panel, avísame (callback). Si se cae, para la obra (catch)."

4. Flujo de Datos — De Dónde Viene, Por Dónde Pasa, Dónde Acaba

Este es el concepto MÁS IMPORTANTE. Cuando algo falla, la pregunta siempre es: ¿dónde se rompió el flujo?

Ejemplo real: AlphaHunter

1. Hyperliquid API → envía datos de mercado (precio BTC, funding rates)
2. AlphaHunter (Python/Railway) → recibe, analiza con 5 familias de señales
3. Si 3+ señales GREEN → genera orden de trading
4. Orden → se envía a Hyperliquid API
5. Resultado → se guarda en base de datos
6. Dashboard (frontend) → pide datos al backend → los muestra

Si el dashboard no muestra posiciones, ¿dónde está el fallo? Puede ser en CUALQUIER paso. Saber trazar este flujo es debugging.

Ejemplo real: mideBC3

1. Usuario escribe mediciones en el frontend (HTML/JS)
2. Frontend valida los datos (¿son números? ¿faltan campos?)
3. Frontend envía datos a Supabase (backend/base de datos)
4. Supabase guarda en PostgreSQL
5. Cuando otro usuario abre el proyecto → Supabase devuelve los datos
6. Frontend los renderiza en la tabla

5. Async/Await — Esperar Sin Parar la Obra

En una obra, no paras TODO porque estás esperando un pedido de Triangle. Sigues con otra tarea y cuando llega el material, continúas. En programación es exactamente igual.

El problema

// ❌ Código síncrono (bloqueante) — imaginario
const datos = pedirDatosAlServidor();  // Tarda 2 segundos
console.log(datos);  // Muestra los datos

// Mientras espera esos 2 segundos, TODA la página se congela.
// No puedes hacer scroll, no puedes hacer clic. Inaceptable.

La solución: Promesas + Async/Await

Una Promesa es exactamente lo que suena: "te prometo que te daré un resultado... eventualmente."

// Una promesa tiene 3 estados:
// 🔄 Pending — esperando (el pedido está en camino)
// ✅ Resolved — éxito (el material llegó)
// ❌ Rejected — error (el pedido se canceló)

Async/Await es la forma limpia de trabajar con promesas:

// ✅ Con async/await — léelo como español
async function obtenerBalance() {
  try {
    const respuesta = await fetch("https://api.hyperliquid.xyz/info");
    const datos = await respuesta.json();
    console.log(datos.balance);
  } catch (error) {
    console.error("Error:", error);
  }
}
# Python con async — AlphaHunter usa esto
import aiohttp

async def obtener_balance():
    try:
        async with aiohttp.ClientSession() as session:
            async with session.get("https://api.hyperliquid.xyz/info") as resp:
                datos = await resp.json()
                print(datos["balance"])
    except Exception as e:
        print(f"Error: {e}")

Analogía de obra:

  • fetch() = hacer el pedido a Triangle
  • await = "espero a que llegue, pero mientras el resto de la obra sigue"
  • try/catch = "si el pedido falla, no para la obra entera, solo gestionamos el problema"
  • Sin await = enviar 50 pedidos a la vez y procesar cada uno cuando llegue

Error clásico

// ❌ Olvidar el await
async function mal() {
  const datos = fetch("/api/status");  // Sin await
  console.log(datos);  // Imprime "Promise {<pending>}" — no los datos
}

// ✅ Con await
async function bien() {
  const datos = await fetch("/api/status");
  const json = await datos.json();
  console.log(json);  // Ahora sí, los datos reales
}

6. APIs y Endpoints — El Tema que Flaqueabas

¿Qué es una API?

API = Application Programming Interface. Es la puerta de entrada a un servicio.

Analogía: un restaurante. Tú (cliente/frontend) no entras en la cocina (servidor/backend). Le dices al camarero (API) lo que quieres, y él te trae el plato.

¿Qué es un Endpoint?

Un endpoint es una dirección específica dentro de una API. Cada endpoint hace una cosa concreta.

https://api.alphahunter.com/api/status     ← endpoint de estado
https://api.alphahunter.com/api/positions  ← endpoint de posiciones
https://api.alphahunter.com/api/signals    ← endpoint de señales

Es como las extensiones de teléfono de una empresa: Extensión 100 → Recepción (status), Extensión 200 → Contabilidad (positions), Extensión 300 → Producción (signals).

Métodos HTTP — Qué Quieres Hacer

GET    → LEER datos       → "Dame el estado actual"
POST   → CREAR datos      → "Guarda esta nueva medición"
PUT    → ACTUALIZAR datos → "Cambia el precio de este material"
DELETE → BORRAR datos     → "Elimina esta partida"

Ejemplo real con mideBC3 y Supabase:

// GET — Obtener todas las mediciones de un proyecto
const resp = await fetch(
  "https://tuproyecto.supabase.co/rest/v1/mediciones?proyecto_id=eq.5",
  { headers: { "apikey": "tu-clave-supabase" } }
);
const mediciones = await resp.json();

// POST — Crear una nueva medición
const resp = await fetch(
  "https://tuproyecto.supabase.co/rest/v1/mediciones",
  {
    method: "POST",
    headers: {
      "apikey": "tu-clave-supabase",
      "Content-Type": "application/json"
    },
    body: JSON.stringify({
      proyecto_id: 5,
      partida: "01.01",
      descripcion: "Panel LSF e=1.2mm",
      cantidad: 45.5,
      precio: 1.43
    })
  }
);

Request y Response

Cada llamada a una API tiene dos partes:

Request (lo que envías):
→ URL: https://api.alphahunter.com/api/status
→ Método: GET
→ Headers: { "Authorization": "Bearer tu-token" }
→ Body: (vacío en GET, con datos en POST)

Response (lo que recibes):
← Status Code: 200
← Headers: { "Content-Type": "application/json" }
← Body: { "status": "running", "balance": 1250.50 }

Status Codes — El Semáforo

2xx → ✅ Todo bien
  200 OK — éxito
  201 Created — se creó algo nuevo
  204 No Content — éxito pero sin datos que devolver

3xx → ↪️ Redirección
  301 Moved — la URL cambió permanentemente
  304 Not Modified — no ha cambiado desde la última vez

4xx → ❌ Error TUYO (del cliente)
  400 Bad Request — enviaste datos mal formados
  401 Unauthorized — no tienes permiso (falta token/API key)
  403 Forbidden — tienes token pero no permisos suficientes
  404 Not Found — ese endpoint no existe
  429 Too Many Requests — estás pidiendo demasiado rápido (rate limit)

5xx → 💥 Error DEL SERVIDOR
  500 Internal Server Error — el servidor petó
  502 Bad Gateway — Railway/proxy no puede conectar con tu app
  503 Service Unavailable — el servicio está caído

Cuando AlphaHunter devuelve 502, no es tu código — es Railway. Cuando devuelve 500, SÍ es tu código.

7. JSON — El Idioma Universal

JSON = JavaScript Object Notation. Es el formato en que se comunican TODAS las APIs, bases de datos, y configuraciones modernas.

Ya lo lees sin saberlo. Cada vez que ves esto, es JSON:

{
  "proyecto": "Hotel Los Patios",
  "cliente": "Estruconsa",
  "modulos": [
    {
      "id": 1,
      "tipo": "habitacion",
      "dimensiones": { "ancho": 2.24, "largo": 3.80, "alto": 3.0 },
      "peso_kg": 1200,
      "estado": "fabricacion"
    },
    {
      "id": 2,
      "tipo": "baño",
      "dimensiones": { "ancho": 2.24, "largo": 2.40, "alto": 3.0 },
      "peso_kg": 800,
      "estado": "diseño"
    }
  ],
  "presupuesto_total": 125000.00,
  "iva_incluido": false
}

Reglas de JSON:

  • Las claves SIEMPRE van entre comillas dobles "clave"
  • Strings entre comillas dobles "texto"
  • Números sin comillas 42, 3.14
  • Booleanos: true / false (minúsculas)
  • Null: null
  • NO permite comentarios (a diferencia de JS)
  • NO permite coma final {"a": 1,} ← esto falla

Convertir entre JSON y código:

// Objeto JS → JSON (para enviar)
const panel = { tipo: "PGC", espesor: 1.2 };
const json = JSON.stringify(panel);
// '{"tipo":"PGC","espesor":1.2}'

// JSON → Objeto JS (para usar)
const texto = '{"tipo":"PGC","espesor":1.2}';
const objeto = JSON.parse(texto);
objeto.tipo;  // "PGC"
import json

# Dict → JSON
panel = {"tipo": "PGC", "espesor": 1.2}
texto = json.dumps(panel)

# JSON → Dict
texto = '{"tipo": "PGC", "espesor": 1.2}'
panel = json.loads(texto)
panel["tipo"]  # "PGC"

8. Arquitectura — Frontend, Backend, Base de Datos

La analogía del edificio

🏗️ ARQUITECTURA DE SOFTWARE = ARQUITECTURA DE UN EDIFICIO

┌─────────────────────────────────────┐
│          FRONTEND (Fachada)          │  ← Lo que ve el usuario
│  HTML = Estructura (hormigón)       │     Navegador web
│  CSS = Acabados (pintura, azulejos) │     React, HTML, Three.js
│  JS = Instalaciones (electricidad)  │     Interactividad
└──────────────┬──────────────────────┘
               │ APIs (tuberías/conductos)
               │ HTTP requests
┌──────────────▼──────────────────────┐
│          BACKEND (Estructura)        │  ← La lógica, lo que no se ve
│  Servidor que procesa peticiones    │     Python (AlphaHunter)
│  Reglas de negocio                  │     Node.js (Express)
│  Autenticación                      │     Railway, VPS
└──────────────┬──────────────────────┘
               │ Queries SQL
               │
┌──────────────▼──────────────────────┐
│       BASE DE DATOS (Cimientos)      │  ← Donde viven los datos
│  PostgreSQL, SQLite, Supabase       │     Permanente
│  Tablas, filas, columnas            │     El almacén
└─────────────────────────────────────┘

Ejemplos de arquitecturas reales

Tipo de proyectoFrontendBackendBase de datos
Bot de tradingDashboard (HTML/JS estático)Python en RailwaySQLite/archivos
App de medicionesHTML5 + JSSupabase (serverless)PostgreSQL (Supabase)
Configurador 3DThree.js + ViteNo tiene (todo en frontend)LocalStorage
Juego webReact + TSNo tiene (GitHub Pages)Zustand (memoria)
Panel de gestiónFrontend webSQLite + APISQLite

Nota: No todos los proyectos necesitan backend separado. Supabase actúa como backend+BD a la vez (Backend as a Service). Un juego web puede tener todo en el navegador.

Cliente-Servidor

TU NAVEGADOR (Cliente)              RAILWAY/VPS (Servidor)
┌─────────────┐    request    ┌─────────────┐
│  Chrome      │ ───────────► │  Tu app     │
│  Firefox     │              │  Python/Node │
│  Safari      │ ◄─────────── │             │
└─────────────┘    response   └─────────────┘

El cliente PIDE. El servidor RESPONDE. Siempre.
El cliente nunca accede a la BD directamente.

9. MVC — Separar Responsabilidades

¿Qué significa MVC y por qué te importa?

MVC = Model - View - Controller

MODEL (Modelo)     → Los datos y la lógica de negocio
                      Dimensiones del módulo, materiales, cálculos de peso

VIEW (Vista)       → Lo que se ve en pantalla
                      El render 3D en Three.js, los formularios, los botones

CONTROLLER         → El intermediario
                      "El usuario pulsó 'añadir módulo' → dile al modelo que
                       cree uno → dile a la vista que lo pinte"

Sin MVC (monolito):

// ❌ Todo mezclado en un archivo de 2000 líneas
botonAñadir.onclick = function() {
  modulos.push({ancho: 2.24, largo: 3.80});  // Datos
  scene.add(new THREE.Mesh(...));              // 3D
  document.getElementById("lista").innerHTML += "..."; // HTML
  calcularPrecio();                            // Lógica
  actualizarResumen();                         // Más HTML
}

Con MVC:

// ✅ model.js — solo datos
class ModuloModel {
  constructor(ancho, largo, alto) {
    this.ancho = ancho;
    this.largo = largo;
    this.alto = alto;
  }
  getPeso() { return this.ancho * this.largo * 10; }
  getPrecio() { return this.getPeso() * 1.43; }
}

// ✅ view.js — solo render
class ModuloView {
  render3D(modulo, scene) { /* Three.js */ }
  renderLista(modulos) { /* HTML */ }
  renderResumen(total) { /* HTML */ }
}

// ✅ controller.js — coordina
class ModuloController {
  añadirModulo(ancho, largo, alto) {
    const modulo = new ModuloModel(ancho, largo, alto);
    this.modulos.push(modulo);
    this.view.render3D(modulo, this.scene);
    this.view.renderLista(this.modulos);
    this.view.renderResumen(this.calcularTotal());
  }
}

Ventaja: Si quieres cambiar cómo se ve el 3D, tocas SOLO la vista. Si cambian los precios, tocas SOLO el modelo. Nada se rompe en cascada.

10. Git — Control de Versiones

Probablemente ya lo usas. Entender qué hace internamente ayuda.

Conceptos

WORKING DIRECTORY → Los archivos en tu carpeta, tal cual
STAGING AREA      → "Esto es lo que quiero guardar" (git add)
REPOSITORY        → El historial completo de cambios (git commit)
REMOTE            → La copia en GitHub (git push)
# Flujo normal
git status              # ¿Qué ha cambiado?
git add .               # Marca TODO para guardar
git add archivo.js      # Marca solo ese archivo
git commit -m "fix: corregido cálculo peso panel"  # Guarda snapshot
git push                # Sube a GitHub

# Ver historial
git log --oneline       # Lista de commits
git diff                # Ver qué ha cambiado antes de commit

# Branches — líneas paralelas de trabajo
git branch nueva-feature    # Crear rama
git checkout nueva-feature  # Cambiar a esa rama
git checkout -b fix/bug-123 # Crear y cambiar en un paso

# Merge — unir ramas
git checkout main           # Volver a la principal
git merge nueva-feature     # Traer los cambios

Analogía: Git es como tener fotos de la obra cada día. Si algo sale mal, puedes volver a la foto del martes y ver qué cambió. Las branches son como tener dos cuadrillas trabajando en zonas distintas — cuando terminan, juntas el trabajo (merge).

Convención de commits

feat: nueva funcionalidad        → "feat: añadido cálculo de izaje"
fix: corrección de bug           → "fix: corregido NaN en precio unitario"
refactor: mejorar sin cambiar    → "refactor: migrar cálculos a módulo separado"
docs: documentación              → "docs: actualizar README con instrucciones deploy"
style: formato/estilo            → "style: formatear con prettier"
chore: mantenimiento             → "chore: actualizar dependencias"

11. Debugging — Encontrar Dónde Se Rompe

console.log — Tu mejor amigo

async function cargarPosiciones() {
  console.log("1. Iniciando carga...");

  const resp = await fetch("/api/positions");
  console.log("2. Response status:", resp.status);

  const datos = await resp.json();
  console.log("3. Datos recibidos:", datos);
  console.log("3b. Tipo:", typeof datos);
  console.log("3c. Nº posiciones:", datos.length);

  datos.forEach(pos => {
    console.log("4. Posición:", pos.symbol, pos.pnl);
  });
}

Si ves el "1" pero no el "2", el problema es el fetch. Si ves el "2" con status 500, el problema es el servidor. Así acorralas el bug.

Leer errores

TypeError: Cannot read properties of undefined (reading 'balance')
│           │                      │                        │
│           │                      │                        └─ La propiedad que buscas
│           │                      └─ El objeto es undefined
│           └─ No puede leer propiedades
└─ Tipo de error: estás tratando algo como objeto que no lo es

Traducción: Algo que esperabas que fuera un objeto con .balance es undefined. Probablemente el fetch falló o no esperaste con await.

Errores comunes y qué significan

ReferenceError: x is not defined     → Variable no existe (typo o scope)
TypeError: x is not a function       → Estás llamando algo que no es función
SyntaxError: Unexpected token        → Error de escritura (falta }, coma, etc.)
CORS error                           → El servidor no permite peticiones desde tu dominio
404 Not Found                        → La URL/endpoint no existe
ECONNREFUSED                         → El servidor no está corriendo

12. Entorno de Desarrollo — Por Qué Necesitas Cada Cosa

Node.js

No es un framework ni una librería. Es un runtime — permite ejecutar JavaScript fuera del navegador. Como Python tiene el intérprete python, JavaScript tiene node.

node archivo.js          # Ejecuta JS fuera del navegador
node -v                  # Ver versión instalada

npm (Node Package Manager)

El almacén de piezas. Como pedir materiales a un proveedor:

npm install three        # Instala Three.js (3D para Modular Designer)
npm install zustand      # Instala Zustand (estado para MMA Manager)
npm install              # Instala TODO lo que dice package.json

package.json = la lista de materiales del proyecto. node_modules/ = el almacén donde se guardan. (Por eso node_modules pesa tanto — es literalmente TODAS las dependencias.)

Vite

Servidor de desarrollo que hace que tu código se actualice en el navegador al instante cuando guardas un archivo. Sin Vite, tendrías que recargar manualmente cada vez.

npm run dev    # Arranca Vite → abre localhost:5173
npm run build  # Empaqueta todo para producción → carpeta dist/

npm run dev = la obra en construcción (andamios, cambios en directo)
npm run build = la obra terminada (limpia, optimizada, lista para entregar)

13. Deploy — De Tu PC al Mundo

GitHub Pages (frontends estáticos)

Tu código → git push → GitHub → GitHub Pages sirve los archivos
Solo HTML/CSS/JS. No ejecuta Python ni Node en el servidor.
Gratis. Ideal para: MMA Manager, opifex.es

Railway (backends)

Tu código → git push → Railway detecta el lenguaje → Crea contenedor Docker
→ Instala dependencias → Ejecuta tu app → Le da una URL pública
Pago por uso. Ideal para: AlphaHunter (Python que necesita correr 24/7)

Hostinger (webs estáticas + FTP)

Archivos → FTP upload → Hostinger sirve desde su servidor
Como GitHub Pages pero con dominio propio y más control.

La diferencia clave

ESTÁTICO (GitHub Pages, Hostinger):
→ Solo sirve archivos. No ejecuta código del servidor.
→ Tu JS se ejecuta en el NAVEGADOR del usuario.

DINÁMICO (Railway, VPS):
→ Ejecuta código en el servidor (Python, Node).
→ Puede acceder a bases de datos, APIs externas, cron jobs.
→ AlphaHunter NECESITA esto porque ejecuta lógica 24/7.

14. React y Estado — Para MMA Manager

Si usas React con TypeScript, estos son los conceptos clave:

Componentes

Un componente = un bloque reutilizable de UI. Como un panel LSF prefabricado.

// Un componente simple
function FighterCard({ nombre, peso, record }) {
  return (
    <div className="card">
      <h3>{nombre}</h3>
      <p>{peso} kg</p>
      <p>{record}</p>
    </div>
  );
}

// Usarlo
<FighterCard nombre="Jon Jones" peso={93} record="27-1" />
<FighterCard nombre="Islam Makhachev" peso={70} record="26-1" />

Estado (State) y Zustand

El estado es la memoria de tu aplicación en un momento dado. Zustand lo gestiona:

// store.js — la "base de datos" en memoria
import { create } from 'zustand';

const useGameStore = create((set) => ({
  dinero: 100000,
  fighters: [],
  contratarFighter: (fighter) => set((state) => ({
    fighters: [...state.fighters, fighter],
    dinero: state.dinero - fighter.coste
  }))
}));

// En un componente
function Dashboard() {
  const dinero = useGameStore(state => state.dinero);
  const contratar = useGameStore(state => state.contratarFighter);

  return <p>Dinero: ${dinero}</p>;
}

Cuando dinero cambia, React automáticamente re-renderiza los componentes que lo usan. No tienes que actualizar el HTML manualmente.

Glosario Rápido

TérminoQué esAnalogía
APIInterfaz para comunicar sistemasCamarero entre cocina y cliente
EndpointURL específica de una APIExtensión telefónica
JSONFormato de datos universalEl idioma que hablan todas las APIs
Async/AwaitEsperar sin bloquearPedir material y seguir trabajando
PromiseValor futuroAlbarán de pedido en camino
CallbackFunción que se ejecuta después"Cuando llegue el material, avísame"
FrontendLo que ve el usuarioFachada del edificio
BackendLógica del servidorEstructura y cimentación
Base de datosAlmacén de datos permanenteArchivo de planos de la obra
HTTPProtocolo de comunicación webEl idioma de las peticiones
GET/POSTLeer/Crear datosPedir un informe / Enviar un pedido
Status codeResultado de la peticiónSemáforo (200=verde, 404=rojo)
npmGestor de paquetes JSProveedor de materiales
node_modulesDependencias instaladasAlmacén de la obra
ViteServidor de desarrolloAndamio con vista en directo
BuildEmpaquetar para producciónRetirar andamios, limpiar obra
DeploySubir a producciónEntrega de llaves
GitControl de versionesFoto diaria de la obra
BranchLínea paralela de trabajoDos cuadrillas en zonas distintas
MergeUnir ramasJuntar el trabajo de las cuadrillas
CommitGuardar snapshotFoto del estado actual
ComponentBloque de UI reutilizablePanel LSF prefabricado
StateDatos en memoria de la appEstado actual de la obra
ScopeVisibilidad de variablesCada planta ve la baja, no al revés
RuntimeMotor que ejecuta códigoLa grúa que mueve las piezas
CORSRestricción de seguridad webPermiso de acceso entre dominios
MiddlewareCódigo entre request y responseControl de acceso en la puerta
Token/API KeyCredencial de accesoTarjeta de acceso a la obra
Rate limitLímite de peticiones"Solo 100 camiones al día"
DockerContenedor aisladoCaseta de obra portátil
Environment variableConfig secreta (.env)Código de la caja fuerte
TypeScriptJS con tipos obligatoriosJS con planos detallados

Siguiente Paso

No intentes memorizar esto. Tenlo como referencia. Cuando estés trabajando en un proyecto y algo no te cuadre, busca la sección relevante. Con el tiempo, estos conceptos se van quedando solos.

Febrero 2026 — OPIFEX