⏱️ Lectura: 13 min
Si alguna vez escribiste un formulario con cinco banderas booleanas (isLoading, isError, isSuccess, isDirty, isSubmitting) y pasaste una tarde entera persiguiendo bugs porque dos de ellas quedaron en true al mismo tiempo, ya sabés intuitivamente qué problema resuelven los statecharts. La mayoría de las aplicaciones modernas son, en el fondo, máquinas de estado disfrazadas: la diferencia es que casi nunca las modelamos como tales, y por eso terminan pareciendo una telaraña de condicionales que nadie quiere tocar.
📑 En este artículo
- ¿Qué es un statechart, exactamente?
- El problema real: la explosión de estados en una app de e-commerce
- Anatomía de un statechart con un ejemplo de fetching
- XState: statecharts ejecutables en JavaScript
- Caso real: un checkout que no se rompe
- SCXML: el estándar W3C que casi nadie conoce
- Cuándo NO usar statecharts
- Statecharts y el ecosistema en 2026
- Preguntas frecuentes
- Referencias
El concepto fue formalizado en 1987 por el científico israelí David Harel en un paper titulado Statecharts: A Visual Formalism for Complex Systems, pensado originalmente para sistemas aeronáuticos donde un bug podía costar vidas. Casi cuatro décadas después, los statecharts vivieron un renacimiento gracias a librerías como XState en JavaScript, que llevaron este formalismo desde los simuladores de cazas F-16 hasta el formulario de login de tu próxima app SaaS. En este artículo vamos a desempacar qué son, por qué importan y cómo usarlos hoy en LATAM sin que tu equipo te mire raro.
¿Qué es un statechart, exactamente?
Un statechart es, en su forma más simple, una máquina de estado finita (FSM) con superpoderes. Una FSM clásica define un conjunto de estados, un conjunto de eventos, y reglas de transición: estando en el estado A, si llega el evento X, paso al estado B. Eso es todo. Una calculadora, un cajero automático o el menú de tu microondas son FSMs perfectamente válidas.
El problema es que las FSMs tradicionales no escalan. Si tu aplicación tiene 10 estados independientes y cada uno puede estar en 3 valores distintos, terminás con 310 = 59.049 combinaciones posibles. Modelar eso con una FSM plana es inviable. Harel lo llamó state explosion, y los statecharts son su antídoto. Suman tres ideas que cambian todo:
- Jerarquía — Un estado puede contener otros estados. Cuando estás en
Loading, podés a la vez estar enLoading.Optimistico enLoading.Pessimistic, sin duplicar transiciones. - Paralelismo (regiones ortogonales) — Una máquina puede estar en varios estados simultáneamente, en regiones independientes. El reproductor de música puede estar en
Playingy al mismo tiempo enBluetooth.Connected, sin que se interfieran. - Historia — Un estado padre puede recordar en qué subestado estuviste antes. Volvés a la pantalla anterior y aparecés exactamente donde la dejaste.
💭 Clave: La razón por la que tu código de UI tiene bugs raros no es que seas mal programador. Es que estás codificando una máquina de estado implícita con ifs y banderas. Cuando la hacés explícita, los bugs imposibles se vuelven literalmente imposibles de representar.
El problema real: la explosión de estados en una app de e-commerce
Imaginá un botón de “Agregar al carrito” en MercadoLibre o Rappi. A simple vista hace una sola cosa, pero en realidad puede estar en cualquiera de estos estados: ocioso, pidiendo confirmación, validando inventario, procesando pago, mostrando éxito, mostrando error de red, mostrando error de tarjeta, mostrando error de stock, en modo retry, deshabilitado por usuario no autenticado, etc. Modelarlo con booleanos es la receta perfecta para un bug en producción donde el botón queda spinning infinito porque dos banderas se desincronizaron.
Con un statechart, esos estados son mutuamente excluyentes por diseño. No es posible estar en Idle y Loading al mismo tiempo, porque el statechart solo puede estar en un estado dentro de cada región. El compilador no te va a permitir representar lo imposible. Esto se conoce como making illegal states unrepresentable, una idea que viene de los lenguajes funcionales como Elm o Haskell pero que los statecharts traen al mundo del JavaScript cotidiano.
Anatomía de un statechart con un ejemplo de fetching
Veamos el statechart más universal de todos: el ciclo de vida de una petición HTTP. Cualquier app que consuma una API atraviesa exactamente estos estados, y cualquier librería de fetching (React Query, SWR, Apollo) está implementando una versión de esta máquina por debajo:
stateDiagram-v2
[*] --> Idle
Idle --> Loading: FETCH
Loading --> Success: RESOLVE
Loading --> Failure: REJECT
Success --> Loading: REFETCH
Failure --> Loading: RETRY
Failure --> Idle: CANCEL
Cuatro estados, cinco transiciones. No importa cuántas banderas booleanas tenga tu componente: la verdad de su comportamiento se reduce a este diagrama. Y lo más interesante: cualquier persona del equipo, incluso QA o producto, puede leerlo. Los statecharts son una herramienta de comunicación tanto como de código, y esa es probablemente su ventaja más subestimada.
XState: statecharts ejecutables en JavaScript
El proyecto que popularizó los statecharts en el ecosistema JavaScript es XState, creado por David Khourshid y mantenido por Stately. La librería ronda los 28 mil stars en GitHub y se integra con React, Vue, Svelte, Solid y prácticamente cualquier framework que se te ocurra. Lo importante no es la sintaxis, sino que XState convierte el statechart en código ejecutable: el mismo objeto que describe la máquina es el que la corre en runtime.
Así se ve el ciclo de fetching de arriba en XState v5:
import { setup, createActor } from 'xstate';
const fetchMachine = setup({
actors: {
fetchData: fromPromise(async ({ input }) => {
const res = await fetch(input.url);
if (!res.ok) throw new Error('HTTP ' + res.status);
return res.json();
})
}
}).createMachine({
id: 'fetch',
initial: 'idle',
context: { data: null, error: null },
states: {
idle: {
on: { FETCH: 'loading' }
},
loading: {
invoke: {
src: 'fetchData',
input: ({ event }) => ({ url: event.url }),
onDone: {
target: 'success',
actions: assign({ data: ({ event }) => event.output })
},
onError: {
target: 'failure',
actions: assign({ error: ({ event }) => event.error })
}
}
},
success: {
on: { REFETCH: 'loading' }
},
failure: {
on: { RETRY: 'loading', CANCEL: 'idle' }
}
}
});
const actor = createActor(fetchMachine);
actor.subscribe((snapshot) => console.log(snapshot.value));
actor.start();
actor.send({ type: 'FETCH', url: '/api/users' });
Reparen en algo importante: no hay ningún booleano. No hay isLoading, no hay hasError. El estado actual es una sola variable (snapshot.value) que vale 'idle', 'loading', 'success' o 'failure'. Si te llega un evento RETRY mientras estás en 'success', la máquina lo ignora silenciosamente, porque RETRY solo está definido en 'failure'. Bug imposible.
Instalación en cualquier sistema operativo
XState no requiere herramientas nativas, así que la instalación es idéntica en Windows, macOS y Linux. Solo necesitás Node.js 18 o superior:
# Windows (PowerShell), macOS y Linux
npm install xstate
# o si usás pnpm
pnpm add xstate
# o yarn
yarn add xstate
Para visualizar tus máquinas en vivo, Stately ofrece un editor web gratuito en stately.ai que toma tu código XState y genera el diagrama automáticamente, manteniéndolo sincronizado con la implementación. Esto resuelve el viejo problema de los diagramas UML que se vuelven obsoletos al día siguiente de dibujarlos.
Caso real: un checkout que no se rompe
Para entender el valor de los statecharts, vale la pena pensar en un caso típico de LATAM: un checkout de e-commerce que tiene que manejar pago con tarjeta, pago con transferencia (Pix, Yape, SINPE Móvil), pago contra entrega y vouchers de descuento, todos opcionales y combinables. Si modelás esto con banderas booleanas vas a llegar a un componente de 800 líneas con un useEffect que tiene 12 dependencias y nadie se anima a tocar.
Con un statechart jerárquico podés expresarlo así: el estado padre es Checkout, con subestados SelectingPayment, EnteringDetails, Confirming, Processing y Done. Dentro de EnteringDetails hay regiones paralelas: una para los datos de pago y otra para el cupón de descuento, que pueden completarse en cualquier orden. La transición a Confirming solo se permite cuando ambas regiones están en estado válido. Toda la lógica de negocio queda en el statechart, y el componente React queda como una vista delgada que solo lee el estado actual.
💡 Tip: Antes de escribir el statechart, hacé el ejercicio de listar en una hoja TODOS los eventos que tu UI puede recibir (clicks, respuestas de API, timeouts, eventos del sistema). Si lográs completar la lista, ya tenés el 70% del statechart hecho. Los eventos faltantes son típicamente la fuente de los bugs en producción.
SCXML: el estándar W3C que casi nadie conoce
Entre 2005 y 2015, el W3C trabajó silenciosamente en una especificación llamada SCXML (State Chart XML) que estandariza la semántica de los statecharts ejecutables. El documento define con precisión cómo se procesan los eventos, en qué orden se ejecutan las acciones de entrada y salida, cómo se resuelven las transiciones cuando hay ambigüedad y todos los casos límite que un programador promedio jamás pensaría.
SCXML no es muy popular fuera de la academia y la industria aeroespacial, pero el valor de la especificación es que librerías como XState, Spring Statemachine (Java) o pytransitions (Python) implementan su semántica, lo que significa que un statechart bien diseñado se puede portar entre lenguajes sin cambiar el comportamiento. Apple, BMW y la NASA han usado SCXML en proyectos reales. La próxima vez que alguien te diga que los statecharts son una moda, podés responder que el estándar tiene una década y vuela en cohetes.
Cuándo NO usar statecharts
Como toda herramienta, los statecharts no son universales. Hay tres casos donde la complejidad adicional no se justifica:
- Componentes triviales — Un botón que solo abre un modal no necesita un statechart. Si tu componente tiene 2 estados y 1 transición, dejalo con
useState. - Equipos sin tiempo de aprendizaje — La curva inicial de XState es real (los conceptos de actor, contexto, guard, action, invoke se acumulan rápido). Si el equipo está bajo deadline brutal, no es el momento de introducirlos.
- Lógica puramente de cómputo — Si no hay transiciones, eventos asíncronos o estados mutuamente excluyentes, simplemente no hay máquina de estado que modelar.
Lo realmente útil es entrenar el ojo para detectar cuándo sí: si tu componente tiene tres o más banderas booleanas, o un useEffect con cinco dependencias, o un comentario que dice “// no sé por qué pero hay que verificar X primero”, casi seguro hay un statechart escondido pidiendo salir.
Statecharts y el ecosistema en 2026
El interés por los statecharts creció de forma sostenida desde 2020. XState pasó de ser una curiosidad académica a una opción mainstream en stacks de React serios. Frameworks como Robot (más liviano, ~1 KB), kingly.js (sin dependencias) y Statelyai (la suite comercial alrededor de XState) compiten por distintos nichos. En el mundo Elixir, GenStateMachine es parte de la librería estándar. En .NET, Stateless es una librería madura usada en producción desde hace años. En Python, transitions y pytransitions son la opción canónica.
Si trabajás en frontend en LATAM y todavía no exploraste statecharts, vale la pena dedicarle un sábado: la primera máquina de estado que escribís cambia para siempre cómo pensás los componentes. Es uno de esos conceptos que no podés des-aprender una vez que los entendés.
📖 Resumen en Telegram: Ver resumen
Preguntas frecuentes
¿Cuál es la diferencia entre una máquina de estado y un statechart?
Una máquina de estado finita (FSM) es plana: tiene estados y transiciones, pero ningún estado puede contener otros estados. Un statechart extiende la FSM con jerarquía (estados anidados), paralelismo (regiones ortogonales) e historia (recordar el último subestado visitado). En la práctica, esto evita la explosión combinatoria de estados que sufren las FSMs cuando crecen.
¿XState reemplaza a Redux o Zustand?
Resuelven problemas distintos. Redux y Zustand son contenedores de estado: te dan un único objeto global con reducers o setters. XState modela el comportamiento a través del tiempo: las transiciones permitidas, los efectos secundarios, las restricciones de orden. Muchos equipos usan ambos: XState para la lógica de cada feature compleja y Zustand para estado global compartido como el usuario autenticado.
¿Tiene sentido usar statecharts en backend?
Mucho. Cualquier flujo de negocio con estados (orden de pedido, suscripción, ticket de soporte, proceso de KYC) es un candidato natural. Spring Statemachine en Java, Stateless en .NET y AWS Step Functions son ejemplos de statecharts del lado servidor. La ventaja es la misma: imposibilitar transiciones inválidas y tener un diagrama que el equipo de producto puede leer.
¿Qué tan grande es la sobrecarga de XState en bundle size?
XState v5 pesa alrededor de 12 KB minified+gzipped, lo cual es razonable para una librería que reemplaza a tu lógica de estado. Si te importa cada KB, alternativas como Robot (~1 KB) o kingly.js (sin runtime, solo tipos) cubren casos más simples sin la suite completa de actores e invocaciones de XState.
¿Cómo testeo un statechart?
Esa es una de sus ventajas: podés testear la máquina independientemente del componente. Le mandás eventos, verificás el estado resultante, y listo. XState además provee @xstate/test que genera tests E2E automáticamente recorriendo todos los caminos del statechart, lo cual es prácticamente imposible de hacer con código convencional.
¿Vale la pena aprender SCXML directamente?
Para el día a día, no. La sintaxis XML es verbosa y la mayoría de los proyectos JavaScript usan XState. Pero leer la especificación SCXML del W3C te da una comprensión profunda de los casos límite (orden de eventos, transiciones internas vs externas, jerarquía de actores) que después aplicás en cualquier librería. Es buena lectura para fines de semana lluviosos.
Referencias
- statecharts.dev — Sitio comunitario que documenta el formalismo y sus aplicaciones modernas.
- W3C SCXML 1.0 — Especificación oficial del estándar State Chart XML, publicada por el W3C en 2015.
- Documentación de XState — Referencia oficial de la librería de statecharts más popular en JavaScript.
- XState en GitHub — Código fuente, ejemplos y discusiones de la comunidad.
- Statecharts: A Visual Formalism for Complex Systems (Harel, 1987) — El paper original que dio origen al concepto.
📱 ¿Te gusta este contenido? Únete a nuestro canal de Telegram @programacion donde publicamos a diario lo más relevante de tecnología, IA y desarrollo. Resúmenes rápidos, contenido fresco todos los días.
0 Comentarios