# 09. Estado

Cómo diseñar estado, ciclos de vida, state machines, optimistic locking y eventual consistency — sin magia y sin flags accidentales.

- **Author:** Fedor Chishchin
- **Level:** advanced
- **Reading time:** ~25 minutos de lectura
- **Published:** 2026-05-23
- **Source:** https://fedorthinks.com/es/learn/software-architect-09-state

---

## 1. La idea central

Si un objeto tiene ciclo de vida, diséñalo como state machine — no como un montón de flags booleanos.

### El estado tiene que ser explícito

> Un semáforo se entiende porque tiene un conjunto limitado de estados y transiciones permitidas. Si todas las luces se prendieran a la vez, los conductores discutirían en el cruce.

Order, payment, delivery, subscription, ticket, deployment — son entidades con lifecycle. Tienen estados y transiciones: `draft`, `pending_payment`, `paid`, `cancelled`, `refunded`. El trabajo arquitectónico es definir las transiciones permitidas y el owner de cada una.

Cuando aparecen flags como `isPaid`, `isCancelled`, `isRefunded`, `isArchived` en lugar de una state machine, el sistema llega rápido a combinaciones imposibles: pagado y cancelado a la vez, entregado sin pago, refund sin capture.

### La concurrency es parte del modelo

> Si dos personas editan un documento al mismo tiempo sin reglas, no gana quien tenga razón — gana el último que guardó.

En un sistema real, varios procesos pueden cambiar el mismo estado: el usuario, un worker, un webhook, un admin, un retry. Hacen falta optimistic locking, un version field, transactions, unique constraints u operaciones compare-and-swap.

El arquitecto está obligado a preguntar: quién puede cambiar este estado, cómo se resuelven las races, qué operaciones son idempotentes y qué cuenta como estado final.

## 2. Ejemplo y antiejemplo

Un buen estado se explica con un diagrama. Un mal estado se explica con una lista de excepciones.

### Ejemplo: payment lifecycle

> Una operación bancaria pasa por etapas. No puedes devolver el dinero primero y decidir después si fue cobrado.

Un payment puede pasar de `created` a `authorized`, y luego a `captured` o `voided`. Un refund solo es posible después de `captured`. El webhook del proveedor no escribe campos arbitrarios — dispara una transición que valida el estado actual y el version.

Ese enfoque convierte a los edge cases en parte del modelo, no en un montón de `if` regados por todo el código.

### Antiejemplo: flags en lugar de ciclo de vida

> Un formulario con diez checkboxes parece flexible — hasta que dos de ellos se contradicen.

El order tiene `paid_at`, `cancelled_at`, `failed_at`, `refunded_at`, `completed_at`, pero ningún status claro. Distintas partes del código interpretan las combinaciones de manera distinta. Soporte ve una cosa, contabilidad otra, el API una tercera.

Eso no es flexibilidad. Es una state machine implícita sin reglas.

#### Autoevaluación

- ¿Qué estados tiene esta entidad?
- ¿Qué transiciones están prohibidas?
- ¿Quién es el owner de la transición: el usuario, el sistema o un proveedor externo?
- ¿Cómo nos protegemos contra retries y races?

  Siguiente módulo: [Sistemas distribuidos](./software-architect-10-distributed-systems).
