wandres.dev
ELEGIR ARQUITECTURA · el árbol de decisión

El árbol de decisión: signal, máquina o arquitectura

Separadas las clases de estado, queda la segunda decisión de arquitectura: para el estado que el cliente posee, qué disciplina de mutación imponer. Esta lección construye el árbol que opera un nivel por encima del árbol de librerías del Nivel 23: no pregunta qué librería, sino cuánta estructura merece el problema. Sus tres hojas son las tres grandes familias del track —un signal o store ligero para datos simples que solo cambian, una máquina de estado para flujos con modos excluyentes y transiciones prohibidas, y una arquitectura formal unidireccional para dominios grandes que exigen auditoría, testeo exhaustivo y trazabilidad—. Fija las preguntas que ramifican el árbol (hay transiciones, cuánta derivación, cuánta escala), lo recorre con ejemplos, y establece que la elección no es de gusto sino de coste: cada peldaño de disciplina compra garantías y cobra ceremonia.

⏱ 18 min

La lección anterior partió el estado en cuatro clases y dejó tres de ellas casi resueltas: el servidor a una cache, la URL al router, la UI efímera a un useState local. Queda la clase con más matiz y más consecuencias: el estado de dominio que el cliente posee. Para él la pregunta no es dónde vive, sino cómo se muta —con cuánta disciplina, con cuántas barandillas—. Este es el segundo árbol del nivel, y opera un peldaño por encima del árbol de librerías del Nivel 23. Aquel decidía entre Zustand, Jotai y Redux Toolkit; este decide algo anterior y más profundo: si tu problema pide la libertad de un signal, la red de seguridad de una máquina de estado, o el flujo unidireccional estricto de una arquitectura formal. Elegir bien esa disciplina es la diferencia entre un estado que te ayuda y uno que te traiciona.

🎯 Al terminar esta lección sabrás
  • Formular las tres preguntas que ramifican el árbol: hay transiciones, cuánta derivación, cuánta escala.
  • Situar las tres familias del track como hojas: signal o store, máquina de estado, arquitectura formal.
  • Recorrer el árbol con ejemplos y ver por qué cada rama cae donde cae.
  • Entender que subir de disciplina compra garantías y cobra ceremonia: es un intercambio, no una mejora.

Las tres preguntas que estructuran la decisión

El árbol se recorre con tres preguntas encadenadas, y su orden importa porque cada una descarta un espacio del problema antes de la siguiente. La primera es la más decisiva: este estado modela modos excluyentes con reglas de transición. Es decir, hay un puñado de estados en los que el sistema puede estar —ocioso, cargando, con error, listo— y transiciones que solo son legales entre ciertos pares, de modo que existen combinaciones imposibles que ningún dato debería poder representar. Si la respuesta es sí, tu problema tiene forma de flujo, y la rama de las máquinas del bloque de Niveles 9 a 16 lo espera. Si es no —el estado son simplemente datos que cambian de valor sin un grafo de modos—, sigue la segunda pregunta.

La segunda afina los datos que solo cambian: cuántas piezas hay y cuánta derivación las relaciona. Un puñado de valores independientes que se leen y se escriben pide lo mínimo: un signal o un store plano. Una red de valores que se computan unos de otros —lo que el bloque de Niveles 4 a 8 llamó grafo de derivación— pide una herramienta que gestione esas dependencias, como los átomos de Jotai. La tercera pregunta es ortogonal a las dos anteriores y puede empujar cualquier hoja hacia arriba: el dominio es grande, el equipo amplio y la corrección exige auditoría. Un dominio pequeño con tres desarrolladores no necesita la ceremonia de una arquitectura formal aunque tenga transiciones; un dominio financiero con cuarenta manos y requisitos de trazabilidad la necesita aunque cada pieza parezca simple.

💡
La primera pregunta es cualitativa; la tercera, de contexto

No confundas los ejes. Que haya transiciones es una propiedad del problema: o las hay o no las hay, y no depende del tamaño de tu equipo. Que el dominio merezca una arquitectura formal es una propiedad del contexto: el mismo carrito de la compra pide un store ligero en una tienda de una persona y una arquitectura auditable en un banco. Por eso la primera pregunta ramifica la forma y la tercera decide la escala. Mézclalas y acabarás montando Redux para un contador porque el equipo es grande, o un signal suelto para un flujo de pago porque el equipo es pequeño: dos errores simétricos que el árbol, bien recorrido, evita.

Las tres familias como hojas del árbol

Cada hoja es una de las grandes familias que el track construyó, y el árbol solo hace explícito cuándo cada una es la respuesta correcta.

Signal o store ligero

Para datos que solo cambian de valor, sin modos ni transiciones. La libertad máxima y la ceremonia mínima: escribes y lees. Es el bloque de Niveles 4 a 8 encarnado en Zustand, un signal o Jotai si hay derivación.

🚦

Máquina de estado

Para flujos con modos excluyentes y transiciones prohibidas. Cambia libertad por seguridad: hace irrepresentables los estados imposibles. Es el bloque de Niveles 9 a 16, con XState como su forma idiomática.

🏛️

Arquitectura formal

Para dominios grandes que exigen auditoría, testeo exhaustivo y trazabilidad de cada cambio. Flujo unidireccional estricto: Redux, Elm, TCA o MVI del bloque de Niveles 17 a 31. Máxima disciplina, máxima ceremonia.

Las hojas no son excluyentes entre sí a escala de app: una arquitectura formal puede alojar máquinas para sus flujos, y una máquina puede llevar signals en su contexto. El árbol decide por pieza de estado, no por aplicación entera. Un mismo producto tendrá un store ligero para las preferencias, una máquina para el asistente de alta y —si su dominio lo justifica— una arquitectura formal para el núcleo transaccional. Recorrer el árbol es una operación local que repites por cada flujo, no un veredicto único que firmas al empezar el proyecto.

// Las hojas anidan: una arquitectura formal aloja maquinas,
// una maquina lleva signals o valores planos en su contexto.
const maquinaPago = createMachine({
  context: { intentos: 0 },      // estado plano dentro de la maquina
  initial: 'idle',
  states: { idle: {}, cobrando: {}, error: {}, ok: {} },
});
// y el reducer de una arquitectura formal puede delegar este flujo a la maquina
flowchart TD
A[estado de dominio del cliente] --> B{hay modos excluyentes con transiciones?}
B -->|si: un flujo con fases y aristas prohibidas| M[maquina de estado]
B -->|no: son datos que solo cambian| C{cuanta derivacion los relaciona?}
C -->|pocos valores planos| S[signal o store ligero]
C -->|un grafo interdependiente| D[atomos derivados]
M --> E{dominio grande y auditable?}
S --> E
D --> E
E -->|si: equipo amplio y trazabilidad| F[arquitectura formal unidireccional]
E -->|no| G[quedate en la hoja minima]
style S fill:#a6e3a1,color:#11111b
style D fill:#94e2d5,color:#11111b
style M fill:#89b4fa,color:#11111b
style F fill:#cba6f7,color:#11111b
style G fill:#a6e3a1,color:#11111b

Un ejemplo recorrido fija el método. Un modal de confirmación: sin transiciones reales, un booleano —hoja del signal—. Un reproductor de vídeo con estados ocioso, cargando, reproduciendo, pausado y error, donde reproducir desde error no tiene sentido: modos excluyentes, hoja de la máquina. El núcleo de una plataforma de trading con decenas de acciones auditables, equipo grande y necesidad de reconstruir cualquier estado pasado: hoja de la arquitectura formal. Tres piezas del mismo producto, tres hojas distintas, y ni una decisión tomada por moda.

Subir de disciplina es un intercambio, no una mejora

El error de lectura más común de este árbol es verlo como una escala de calidad, donde la arquitectura formal sería la opción seria y el signal la de juguete. Es falso. Cada peldaño hacia arriba compra una garantía concreta y cobra un precio concreto, y elegir bien es saber si necesitas lo que compras más de lo que te molesta lo que pagas.

// La misma pieza de estado, tres disciplinas, tres costes.
// 1. Signal: libertad total, cero garantias estructurales.
const abierto = signal(false);
abierto.value = true; // nada impide ninguna transicion

// 2. Maquina: las transiciones ilegales no compilan como eventos validos.
type Estado = 'ocioso' | 'cargando' | 'error' | 'listo';
const transiciones: Record<Estado, Estado[]> = {
  ocioso: ['cargando'], cargando: ['error', 'listo'], error: ['cargando'], listo: [],
}; // reproducir desde 'listo' no existe: estado imposible, irrepresentable

// 3. Arquitectura formal: cada cambio es una accion serializable y auditable.
type Accion = { type: 'cargar' } | { type: 'exito'; datos: Datos } | { type: 'fallo' };
function reducer(estado: Estado, accion: Accion): Estado { /* ... */ }

La máquina compra la imposibilidad de estados ilegales —el gran regalo del bloque de statecharts— y cobra el coste de declarar por adelantado todos los modos y aristas. La arquitectura formal compra trazabilidad total, testeo exhaustivo y viaje en el tiempo, y cobra la ceremonia de acciones, reducers y selectores que el Nivel 22 diseccionó. El signal no compra ninguna garantía estructural y por eso no cobra ceremonia alguna. Ninguno es mejor en abstracto; cada uno es mejor para un problema con una forma y un contexto concretos.

⚠️
No subas de peldaño sin un dolor que lo pague

La disciplina que no resuelve un problema real no es gratis: es puro impuesto. Montar una máquina para un booleano te obliga a declarar estados y transiciones que no existen; montar una arquitectura formal para media docena de banderas te hace escribir acciones y reducers para cambios que un set resolvía en una línea. El síntoma de haber subido de más es la ceremonia sin beneficio: mucho código de infraestructura rodeando muy poca lógica de dominio. Sube solo cuando sientas el dolor que el peldaño superior alivia —estados imposibles que se cuelan, cambios que no puedes rastrear, un equipo que diverge— y no un minuto antes.

El árbol se recorre por pieza, no por proyecto

Una lectura equivocada del árbol sería recorrerlo una sola vez, al empezar, y declarar una disciplina única para toda la aplicación: esta app es de máquinas, aquella es de Redux. Pero el árbol clasifica piezas de estado, no proyectos, y una misma aplicación aloja piezas de formas distintas que caen en hojas distintas. Lo normal y sano es que un producto tenga un store ligero para sus preferencias, una máquina para su asistente de alta y, si el dominio lo pide, una arquitectura formal para su núcleo transaccional, todo a la vez. Recorrer el árbol es una operación local que repites por cada flujo, no un veredicto único que firmas al arrancar.

Y como los problemas cambian de forma con el tiempo, la hoja de una pieza tampoco es permanente. Un dato que hoy es un simple valor —hoja del signal— puede desarrollar modos el día que le añades estados de carga y error que no pueden coexistir, y entonces cruza a la rama de las máquinas. La señal de que una pieza se quedó en la hoja equivocada es la misma que enseñó el bloque de statecharts: booleanos que se contradicen, condiciones que existen solo para prohibir combinaciones imposibles. Cuando aparezca, vuelve a recorrer el árbol para esa pieza y déjala subir de rama; no toques por ello las demás.

📝
La forma del problema manda sobre la costumbre del equipo

El sesgo más difícil de vencer al recorrer el árbol no es técnico sino cultural: el equipo que domina una herramienta tiende a verla en todos los problemas. Un equipo de Redux mete flujos en reducers donde una máquina sería más clara; un equipo de XState modela con máquinas datos que un signal resolvería sin ceremonia. El árbol existe precisamente para interrumpir ese reflejo y devolver la decisión a la forma del problema. Cuando notes que siempre eliges la misma hoja, sospecha: o tus problemas son asombrosamente uniformes, o dejaste de mirarlos y empezaste a aplicar la costumbre.

La arquitectura no mide potencia, mide cuánta libertad estás dispuesto a ceder

El árbol de este nivel parece un mapa de herramientas y es en realidad un mapa de renuncias. Cada rama hacia arriba es una libertad que entregas a cambio de una garantía, y entender la arquitectura de estado es entender que esas dos cosas son la misma moneda vista por sus dos caras. El signal te da libertad absoluta: cualquier valor, en cualquier momento, desde cualquier sitio. Esa libertad es exactamente su riesgo, porque nada impide la transición ilegal, el estado imposible, la mutación desde el rincón que nadie audita. La máquina de estado toma parte de esa libertad —te prohíbe las transiciones que no declaraste— y te devuelve a cambio una imposibilidad: los estados ilegales dejan de existir, no porque los evites con cuidado sino porque el sistema no sabe representarlos. La arquitectura formal toma casi toda la libertad restante —te obliga a expresar cada cambio como una acción explícita que fluye en una sola dirección— y te devuelve trazabilidad perfecta: cualquier estado pasado se reconstruye, cualquier cambio se explica, cualquier bug se reproduce. Por eso la pregunta correcta nunca fue qué arquitectura es más potente, sino cuánta libertad te sobra y cuánta garantía te falta. Un problema simple no necesita ceder libertad porque no tiene forma de hacerse daño con ella; un flujo de pago la necesita ceder toda porque el daño de un estado imposible se mide en dinero real. El arquitecto maduro no busca la disciplina máxima ni la mínima, sino la exacta: la que cede justo la libertad que sobra para comprar justo la garantía que falta, ni un peldaño más. Esa calibración —no la elección de librería, no el dominio de una API— es la competencia que este track entero perseguía, porque es la única que no caduca cuando cambian las herramientas: los nombres de las hojas envejecerán, pero la ley de que toda garantía se paga en libertad cedida seguirá gobernando cada decisión de estado que tomes.

⚔️ Recorre el árbol con tres flujos de distinta forma
  1. Elige tres piezas de estado de dominio de tu app que sospeches de formas distintas: una simple, una con modos, una crítica.
  2. A cada una, aplícale la primera pregunta —hay transiciones excluyentes— y separa las que tienen forma de flujo de las que son datos que solo cambian.
  3. A las que son datos, aplícales la segunda pregunta —cuánta derivación— y decide entre signal plano y átomos.
  4. A las tres, aplícales la tercera —dominio grande y auditable— y comprueba si alguna asciende a arquitectura formal por contexto y no por forma.
  5. Para cada hoja resultante, nombra la garantía que compras y la ceremonia que pagas, y decide con honestidad si el cambio te compensa.
  6. Localiza en tu código actual una pieza que esté un peldaño por encima de su hoja y estima cuánta ceremonia sin beneficio te costaría bajarla.