From n00b to ZeroCool / Profesionalización

Backend: el sótano donde vive la lógica (y por qué te conviene bajar)

Entiende el backend con casos reales: APIs, DB, auth, caché, jobs y colas. Guía práctica para elegir stack y sobrevivir producción.

Lo que vale la pena leer aquí

Son las 11:48 pm. Te aventaste el deploy “rápido” porque mañana hay demo y tu jefe ya dejó el “¿sí quedó?” en Slack. El front carga… pero la pantalla se queda pensando como si estuviera pegada a un módem de 2007.

Son las 11:48 pm. Te aventaste el deploy “rápido” porque mañana hay demo y tu jefe ya dejó el “¿sí quedó?” en Slack. El front carga… pero la pantalla se queda pensando como si estuviera pegada a un módem de 2007.

Cae el mensaje clásico: “¿Se cayó la API o es mi Wi‑Fi?”.

Ahí es cuando te acuerdas: el backend es el sótano de la app. Nadie lo enseña en el demo. Nadie lo presume en el pitch. Pero cuando algo truena, todo mundo baja a gritos.

Lo que te vas a llevar

  • Qué es backend en la vida real (no de diccionario) y qué piezas lo componen.
  • Cómo viaja una request: del click a tu server, a la DB, y de regreso en JSON.
  • Decisiones con colmillo: monolito vs microservicios, SQL vs NoSQL, caché sí/no, colas sí/no.
  • Un mapa mental para entender sistemas que ya están en producción y no perdonan.
  • Errores típicos del “primer backend” y cómo evitarlos sin volverte paranoico.

El sótano sí existe (aunque no lo veas)

Piensa en una app normal: una tienda, un SaaS chiquito, un sistema interno de ventas, un negocio que literal solo necesita “que funcione”. El usuario toca un botón y espera magia.

Esa magia casi siempre es un combo de:

  • API (REST/GraphQL/gRPC): recibe requests y responde.
  • Lógica de negocio: reglas, validaciones, permisos, cálculos, estados.
  • Base de datos: el registro oficial de “la verdad”.
  • Caché: para no pegarle a la DB por cada cosa.
  • Jobs/Workers: tareas que no deben vivir dentro de la request (emails, PDFs, pagos, thumbnails).
  • Colas: orden y reintentos para los jobs (RabbitMQ, SQS, Redis Streams, etc.).
  • Auth: login, sesiones, tokens, roles.
  • Observabilidad: logs, métricas, tracing; lo que te salva cuando “no reproduce”.

En México esto tiene un sazón extra: a veces corre en un VPS modesto porque el presupuesto se fue en marketing, o porque el cliente ya dijo “no le metas tanto, nomás que jale”. Y si tu app se usa con internet irregular (bodega, ruta, campo), tus timeouts y retries dejan de ser teoría.

Cómo armar (y entender) un backend sin romperte

1) Primero entiende el flujo: request → lógica → datos → respuesta

Antes de clavarte con el stack, dibuja el flujo con una historia real.

Ejemplo: “Crear pedido” en una tienda.

  1. Front manda POST /orders con carrito y dirección.
  2. Backend valida:
    • ¿Usuario autenticado?
    • ¿Hay inventario?
    • ¿Dirección válida?
    • ¿Reglas de negocio? (mínimo, zona, horarios)
  3. Backend escribe en DB (transacción si aplica):
    • orders, order_items, decrementa stock.
  4. Backend dispara procesos fuera de la request:
    • Enviar confirmación por email/WhatsApp.
    • Reservar guía de envío.
  5. Backend responde rápido: 201 Created con order_id.

Si tu request tarda 8 segundos porque te llevaste “generar PDF” adentro, el usuario le va a picar dos veces, te va a duplicar pedidos y soporte te va a odiar. Y tú vas a terminar haciendo un rollback a medianoche con una laptop vieja que ya suena como jet.

2) Define el contrato: APIs que no den pena

Un backend se vuelve serio cuando sus endpoints tienen contrato claro, errores consistentes y un plan decente para cambios.

Una forma simple y práctica:

  • Respuestas con estructura consistente.
  • Códigos HTTP bien usados.
  • Errores con code y message (y si se puede, details).

Ejemplo (Node/Express, pero aplica a cualquier stack):

// Respuesta OK
res.status(201).json({
  data: { orderId, status: "created" },
  meta: { requestId }
});

// Respuesta de error
res.status(409).json({
  error: {
    code: "OUT_OF_STOCK",
    message: "No hay inventario para el producto 123",
    details: { productId: 123 }
  },
  meta: { requestId }
});

Decisión que te ahorra bugs: si hoy no quieres versionar con /v1, mínimo deja un plan (header, compatibilidad, deprecación). Porque alguien —otra squad o tú en tres meses— va a consumir “como venga” y luego te va a meter un bug con un pull request de último minuto.

3) La base de datos: la verdad duele (y se paga)

La DB es donde se pelean consistencia, performance y costo.

Regla que se cumple en un chorro de proyectos:

  • Si tus datos son relacionales y quieres integridad: PostgreSQL.
  • Si vas empezando y no quieres sorpresas raras: PostgreSQL.
  • Si ya tienes una razón real (eventos masivos, documentos, escalado específico): entonces sí, evalúas NoSQL.

Modela pensando en consultas reales, no en “qué se ve bonito”:

  • ¿Qué lista se pinta siempre? (índices)
  • ¿Qué filtros? (índices compuestos)
  • ¿Qué reportes? (evita el SELECT * contra tablas gigantes a la hora pico)

Ejemplo de índice útil para “pedidos por usuario ordenados por fecha”:

CREATE INDEX IF NOT EXISTS idx_orders_user_created
ON orders (user_id, created_at DESC);

Dato de guerra: el bug caro no es el 500 que explota. Es el endpoint que “funciona” pero cada semana tarda un poquito más… hasta que llega un viernes de quincena y se convierte en sopa.

4) Auth: elige tu veneno (sessions vs JWT)

Autenticación es donde se te va el sprint si no decides desde el inicio.

  • Sesiones (cookie + server store): más fácil revocar, más control, ideal para web tradicional.
  • JWT: útil para APIs distribuidas y mobile, pero ojo con revocación y expiraciones.

Decisión práctica:

  • Si tu producto es B2B con dashboard web: sesiones suelen ser más tranquilas.
  • Si tienes mobile + múltiples servicios: JWT puede tener sentido, pero exige disciplina (rotación, expiración, refresh tokens).

Mini-checklist de seguridad que sí se siente en producción:

  • Passwords con bcrypt/argon2.
  • Rate limit en login.
  • Lockout o captcha después de intentos.
  • Logs de auth sin soltar datos sensibles.

5) Caché: ponlo cuando te duela, no por deporte

El caché es como la salsa: mejora todo… hasta que tapa el sabor real y ya nadie entiende qué está pasando.

Úsalo cuando:

  • Hay lecturas repetidas (catálogos, configuraciones, perfiles).
  • Tu DB ya está caliente y la latencia/costo sube.

Evítalo cuando:

  • Tus datos cambian cada segundo y no tienes estrategia de invalidación.

Ejemplo: cachear un catálogo por 60 segundos.

const key = `catalog:v1`;
let data = await redis.get(key);
if (!data) {
  data = await db.query("SELECT id, name, price FROM products WHERE active = true");
  await redis.set(key, JSON.stringify(data), { EX: 60 });
} else {
  data = JSON.parse(data);
}
res.json({ data });

Tradeoff real: TTL alto y el negocio te reclama precios viejos. TTL bajo y no ganas casi nada. Lo correcto es alinear con cómo cambia el catálogo (¿un admin? ¿un ERP? ¿un Excel que te mandan por WhatsApp?).

6) Jobs y colas: saca lo pesado de la request

Si tu backend hace cosas lentas dentro de una request, te compras:

  • timeouts
  • usuarios duplicando acciones
  • picos que tumban todo

Cosas típicas para worker:

  • Enviar email
  • Generar PDF
  • Procesar imagen
  • Webhooks
  • Reintentos de pago

Patrón base:

  • API recibe acción y guarda en DB.
  • Publica mensaje en cola.
  • Worker procesa, reintenta si falla, registra estado.

Las colas agregan complejidad, sí. Pero cuando llega el pico (campaña, mención en TikTok, o “hoy todo mundo pagó a la misma hora”), esa complejidad es justo lo que evita que production se te vaya al piso.

7) Observabilidad: si no lo puedes ver, no lo puedes arreglar

Mínimo viable:

  • requestId en cada request
  • logs estructurados (JSON si se puede)
  • métricas básicas: latencia p95, rate de errores, throughput

Ejemplo de log con contexto (lo que sí sirve a las 2am):

{
  "level": "error",
  "message": "db_timeout",
  "requestId": "a1b2c3",
  "userId": 42,
  "route": "POST /orders",
  "durationMs": 5120
}

Decisión práctica: si el equipo está chico, un stack “barato” y efectivo puede ser logs a CloudWatch/ELK, métricas a Prometheus/Grafana y tracing después. Pero el requestId desde el día 1. Neta.

Backend: el sótano donde vive la lógica (y por qué te conviene bajar) - visual explicativa 1
Visual de apoyo: Lo que te vas a llevar

Screenshots sugeridos

  • Diagrama simple del flujo request → API → DB → cola → worker.
  • Captura de Postman/Insomnia con un POST /orders y respuesta de error consistente.
  • Screenshot de una tabla en DB con índices (pgAdmin / DBeaver) mostrando idx_orders_user_created.
  • Pantalla de logs filtrados por requestId (CloudWatch, Kibana o terminal con jq).
  • Gráfica de latencia p95 y rate de errores en Grafana.

Errores comunes (y cómo salir del hoyo)

Error 1: “Todo en un endpoint, todo sincronizado”

Síntoma: POST /checkout tarda 12s, a veces truena, a veces duplica.

Arreglo:

  • Responde rápido.
  • Mueve email/PDF/webhooks a jobs.
  • Usa idempotency keys en operaciones críticas.

Ejemplo de header para idempotencia:

  • Cliente manda Idempotency-Key: <uuid>
  • Backend guarda la key y evita duplicados si se repite.

Error 2: “La DB aguanta, total es Postgres”

Síntoma: reportes pesados tumban al sistema.

Arreglo:

  • Índices donde toca.
  • Queries con EXPLAIN.
  • Mueve analytics/reportes a réplicas o a un almacén dedicado (cuando ya sea necesario, no por FOMO).

Error 3: “JWT para todo” sin estrategia de revocación

Síntoma: alguien se sale de la empresa y su token sigue válido.

Arreglo:

  • Expiración corta + refresh tokens.
  • Lista de revocación o rotación de secrets.
  • Para B2B, considera sesiones.

Error 4: “Cacheé y ahora nadie sabe por qué sale viejo”

Síntoma: cambias el precio en admin pero la app sigue mostrando el anterior.

Arreglo:

  • TTL razonable.
  • Invalidación por evento (actualizas producto → borras catalog:v1).
  • No caches cosas que son fuente de pleito con negocio.

Error 5: “En mi máquina sí jala”

Síntoma: en local todo bien; en production truena por variables, red, permisos.

Arreglo:

  • .env.example y config centralizada.
  • Health checks.
  • Logs con contexto.
  • Smoke tests chiquitos post-deploy.
Backend: el sótano donde vive la lógica (y por qué te conviene bajar) - visual explicativa 2
Visual de apoyo: El sótano sí existe (aunque no lo veas)

Checklist final (para bajar al sótano sin romperte el cuello)

  • Tengo un flujo claro request → lógica → DB → respuesta.
  • Mis endpoints tienen errores consistentes (code, message, requestId).
  • DB con índices alineados a consultas reales (y al menos revisé con EXPLAIN).
  • Auth decidido (sesiones o JWT) con plan de expiración/revocación.
  • Lo pesado va a jobs + cola (o al menos está listo para sacarse).
  • Caché con TTL e invalidación pensada (no “cachea y reza”).
  • Logs con requestId y métricas básicas (latencia p95, errores).
  • Tengo un plan de rollback (porque producción no perdona).

FAQ

1) ¿Backend es lo mismo que servidor?

No exactamente. El servidor es la máquina/infra. Backend es el sistema que corre ahí: APIs, lógica, DB, workers, colas, auth, etc.

2) ¿Qué lenguaje es “mejor” para backend?

El que tu equipo pueda mantener y operar sin sufrir. Node, Java, Go, Python, .NET, Ruby… lo que pesa es el setup, las prácticas, la observabilidad y la disciplina en producción.

3) ¿Monolito o microservicios para empezar?

Monolito bien hecho, casi siempre. Microservicios cuando tengas razones reales: equipos múltiples, dominios separados, escalado distinto o dolor comprobado (no por moda).

4) ¿Cuándo meto Redis?

Cuando tengas lecturas repetidas o necesites rate limiting/sesiones/una cola simple. Si lo metes “porque todos lo usan”, luego pagas con invalidación y bugs fantasma.

5) ¿Cómo sé qué está lento: mi API o mi DB?

Mide por partes: latencia por endpoint, tiempo de query, p95, y agrega requestId. Si no tienes esas señales, estás adivinando con fe.

Siguiente episodio: teaser

La puerta del sótano se abre con una llave: HTTP y APIs. Diseñar endpoints que aguanten producción es menos “arte” y más workflow: códigos de estado, timeouts y el arte de decir “no” con un 429.