wandres.dev
NIVEL DIOS: SÍNTESIS · pensar en máquinas

Seguir aprendiendo: Harel, SCXML, model checking y lo que viene

El track termina donde empieza la literatura. Esta lección ordena las fuentes primarias que siguen mereciendo el tiempo de lectura y explica qué resuelve cada una, desmonta la idea de que statechart designe una única semántica apoyándose en el catálogo de variantes y en la norma del W3C, recorre la escalera de verificación desde el recorrido exhaustivo del grafo hasta el model checking con lógica temporal, y traza las tres líneas por donde el modelado de estado se está moviendo: ejecución durable, tipos de sesión y la especificación revisable como artefacto central.

⏱ 20 min

Hay una asimetría entre lo que dura una librería y lo que dura una idea que conviene tener presente al decidir en qué invertir horas de estudio. El artículo en el que Harel definió los statecharts se publicó en 1987 y se lee hoy sin adaptación ninguna; el modelo de actores es de 1973 y describe con precisión lo que hace un sistema de mensajería moderno; los autómatas finitos son de los años cincuenta y siguen siendo el objeto sobre el que se construye todo lo demás. En ese mismo periodo han nacido y muerto varias decenas de bibliotecas de gestión de estado, algunas dominantes durante años. La conclusión práctica no es despreciar las herramientas —hay que usarlas y usarlas bien— sino repartir el estudio con conocimiento de causa: lo que se aprende de la API caduca, lo que se aprende del formalismo no. Esta lección es el mapa de lo que no caduca, y de las tres direcciones por donde este campo se está moviendo ahora mismo.

🎯 Al terminar esta lección sabrás
  • Elegir con criterio qué fuente primaria leer según el problema concreto que se tenga delante.
  • Entender por qué la palabra statechart no designa una única semántica y qué papel cumple la norma del W3C.
  • Situar cada peldaño de la escalera de verificación, desde el recorrido del grafo hasta el model checking.
  • Reconocer las tres líneas de evolución del campo y qué habilidad conviene cultivar para cada una.

Las fuentes primarias que siguen valiendo el tiempo

No hay que leerlo todo y desde luego no en este orden por obligación. La lista siguiente está ordenada por lo que resuelve cada texto, para que se pueda ir a buscar la respuesta concreta.

Si quieres entender de dónde salieron los statecharts y por qué tienen esa forma, la fuente es David Harel, Statecharts: A Visual Formalism for Complex Systems, en Science of Computer Programming, volumen 8, 1987. Es un artículo escrito para ingenieros de sistemas aeronáuticos, no para académicos, y ese origen se nota: cada construcción se justifica con un problema real que la notación plana no podía expresar sin explotar. Se lee en una tarde y reordena la cabeza.

Si lo que te interesa es el orden exacto en que ocurren las cosas, hay que ir a Harel y Naamad, The STATEMATE Semantics of Statecharts, en ACM TOSEM, 1996. Ahí es donde la notación deja de ser un dibujo y se convierte en un objeto ejecutable con reglas: qué estados se abandonan, en qué orden, cuándo se ejecutan las acciones y qué significa que dos transiciones compitan.

Si alguna vez discutes con alguien sobre qué hace un statechart en un caso raro, el texto que zanja la discusión —revelando que no hay una única respuesta— es Michael von der Beeck, A Comparison of Statecharts Variants, de 1994, que cataloga más de veinte variantes con semánticas distintas e incompatibles entre sí. La lección es incómoda y liberadora: statechart es una familia de notaciones, no una especificación, y por eso hace falta una norma.

📜

Harel 1987 · el origen

Por qué la jerarquía, las regiones y la difusión son exactamente las tres construcciones que hacían falta. Corto, claro y sin envejecer.

⚙️

Harel y Naamad 1996 · la semántica

El paso de dibujo a objeto ejecutable: conjuntos de salida y entrada, orden de acciones y resolución de conflictos.

🔀

Von der Beeck 1994 · las variantes

Más de veinte semánticas distintas bajo el mismo nombre. Leerlo cura de raíz la creencia de que statechart significa una sola cosa.

🎭

Agha 1986 · los actores

La formalización del modelo de Hewitt: identidad, mensajes asíncronos y creación dinámica como primitivas de cómputo.

Para el modelo de actores, la fuente es Hewitt, Bishop y Steiger, en IJCAI 1973, y sobre todo el libro de Gul Agha, Actors: A Model of Concurrent Computation in Distributed Systems, de 1986, que es donde el modelo adquiere su forma matemática. Para la teoría de autómatas, Hopcroft, Motwani y Ullman es la referencia canónica y Sipser es la puerta de entrada más amable. Y para saber qué hizo Harel después, su libro Come, Let’s Play de 2003 propone especificar por escenarios en lugar de por estados, que es la crítica más seria que se le ha hecho al propio formalismo desde dentro.

💡
Leer un artículo fundacional no es arqueología

Existe el prejuicio de que los textos originales están superados por el material didáctico posterior, y en este campo ocurre lo contrario con una regularidad notable. Los tutoriales enseñan la notación ya decidida; el artículo original enseña qué alternativas se descartaron y por qué, que es precisamente la información que necesitas cuando tu caso no encaja en el molde. Harel explica por qué la jerarquía se resuelve con transiciones que suben y no con excepciones, y por qué la difusión de eventos a todas las regiones era preferible a la mensajería dirigida. Esas decisiones se siguen tomando hoy en cada librería nueva, y quien conoce el debate original las evalúa en minutos.

La norma y por qué existe

SCXML es Recomendación del W3C desde el 1 de septiembre de 2015, y su valor no está en el formato XML —que casi nadie escribe a mano— sino en su apéndice algorítmico: un pseudocódigo normativo que define paso a paso cómo se interpreta un statechart. Ahí quedan fijados el conjunto de estados que se abandonan y el que se entra, el orden documental para las acciones de entrada y el inverso para las de salida, el bucle de microsteps hasta alcanzar una configuración estable, y la regla que resuelve dos transiciones en conflicto a favor de la declarada en el estado más profundo.

Su utilidad práctica es la de cualquier norma: convierte una discusión de opiniones en una consulta. Cuando dos personas del equipo no se ponen de acuerdo sobre si una acción de salida debe ejecutarse antes que una de entrada, existe una respuesta normativa que no depende de la librería que uses. XState sigue esa semántica de cerca, y conocer el algoritmo permite predecir el comportamiento en los casos límite sin experimentar a base de pruebas.

Punto de la semántica Lo que fija la norma Por qué se discute sin ella
Orden de salidas del más profundo hacia la raíz cada implementación elegía el suyo
Orden de entradas de la raíz hacia el más profundo el contexto podía verse a medio actualizar
Conflicto de transiciones gana la del estado más profundo dos flechas válidas y ningún desempate
Fin de un macrostep cuando no queda ninguna sin guarda bucles infinitos con always mal puesto

Conviene saber que no es el único estándar. Las máquinas de estado de UML, definidas en la especificación de UML 2.5, cubren un territorio parecido con diferencias reales en los detalles —el tratamiento de los eventos diferidos, la semántica de los pseudoestados de unión y bifurcación— y son las que se encuentran en herramientas de modelado empresarial y en dominios regulados. Y hay implementaciones industriales vivas de SCXML fuera del mundo web, desde Apache Commons SCXML hasta el módulo de Qt, lo que significa que un modelo escrito con esta disciplina puede viajar entre plataformas mucho más lejos de lo que uno supondría.

La escalera de la verificación

Entre la prueba unitaria y la demostración formal hay cuatro peldaños, y la elección correcta casi nunca es el más alto.

flowchart TD
A[1 test de transicion: casos que se te ocurren] --> B[2 recorrido exhaustivo del grafo]
B --> C[3 propiedades: invariantes sobre entradas generadas]
C --> D[4 model checking: logica temporal sobre todos los entrelazados]
A --> E[coste minutos]
B --> F[coste horas]
C --> G[coste dias]
D --> H[coste semanas y formacion]
style B fill:#a6e3a1,color:#11111b
style D fill:#cba6f7,color:#11111b

El peldaño dos es el que casi nadie usa y el que mejor relación de coste tiene. Si la máquina es finita y su contexto está acotado, un recorrido exhaustivo del grafo es un model checker de andar por casa: enumera todos los caminos y comprueba invariantes en cada uno. Con eso ya se demuestran propiedades reales —que ningún camino llega a un estado sin salida, que no existe secuencia que cobre dos veces— sin aprender ninguna herramienta nueva.

// Un model checker de veinte lineas: todos los caminos, un invariante.
import { getSimplePaths } from '@xstate/graph'
import { cobro } from './cobro'

const caminos = getSimplePaths(cobro, {
  events: [{ type: 'PAGAR' }, { type: 'CANCELAR' }, { type: 'CADUCA' }],
})

for (const camino of caminos) {
  // Seguridad: en ningun camino se cobra dos veces.
  const cobros = camino.steps.filter((s) => s.state.matches('cobrando')).length
  const exitos = camino.steps.filter((s) => s.state.matches('hecho')).length
  if (exitos > 0 && cobros > 1) {
    throw new Error(`Camino inseguro: ${camino.steps.map((s) => s.event.type).join(' ')}`)
  }
  // Ausencia de agujeros negros: todo final del camino sale o es final.
  const ultimo = camino.state
  if (!ultimo.status.includes('done') && ultimo.can({ type: 'PAGAR' }) === false) {
    console.warn('Estado sin salida alcanzable', ultimo.value)
  }
}

La razón por la que este peldaño se salta tan a menudo es puramente cultural: se percibe como testing exótico cuando es lo contrario, un bucle sobre una lista. Merece la pena instalarlo en el proceso de integración continua desde el primer día, porque su valor crece justo cuando más falta hace: cada estado nuevo que alguien añade multiplica los caminos, y es exactamente entonces cuando el recorrido exhaustivo encuentra lo que nadie iba a probar a mano.

El peldaño cuatro empieza a justificarse cuando varias máquinas se coordinan y el fallo cuesta dinero o seguridad, porque ahí el problema deja de ser el grafo de una máquina y pasa a ser el entrelazado de varias. La lógica temporal, que Pnueli introdujo en 1977 para razonar sobre programas, distingue dos familias de propiedades que conviene saber nombrar. Las de seguridad dicen que algo malo no ocurre nunca: nunca se cobra dos veces, nunca se entrega sin haber cobrado. Las de viveza dicen que algo bueno acaba ocurriendo: toda solicitud acaba resuelta, ningún reembolso queda pendiente para siempre. Los tests corrientes cubren razonablemente las primeras y son casi ciegos a las segundas, porque una propiedad de viveza se viola con una ejecución infinita que ninguna prueba concreta recorre.

Técnica Qué demuestra Coste de entrada Cuándo compensa
Test de transición casos concretos ninguno siempre, es la base
Recorrido exhaustivo invariantes en todo camino bajo máquina finita con contexto acotado
Propiedades generadas invariantes con datos arbitrarios medio contexto rico, reductores puros
Model checking seguridad y viveza sobre entrelazados alto varios actores, dinero o seguridad

Las herramientas del último peldaño son estables y bien documentadas: TLA+ con su verificador TLC, que Lamport describió en Specifying Systems, es el estándar de facto para protocolos distribuidos y su uso industrial está documentado en el artículo de Newcombe y otros sobre métodos formales en Amazon Web Services, publicado en CACM en 2015. SPIN con Promela y NuSMV son las alternativas clásicas del mundo académico e industrial. Todas chocan contra el mismo muro —la explosión del espacio de estados— y todas lo esquivan con las mismas dos familias de trucos: métodos simbólicos y verificación acotada.

📝
El obstáculo no suele ser la herramienta, es el modelo

Quien intenta verificar formalmente un sistema descubre pronto que la parte difícil no es aprender la sintaxis del verificador, sino escribir un modelo abstracto lo bastante pequeño para que la comprobación termine y lo bastante fiel para que el resultado signifique algo. Esa habilidad —decidir qué se abstrae y qué se conserva— es exactamente la que se ha entrenado durante todo este track modelando statecharts. Quien ya sabe distinguir un modo de un dato tiene la mitad del trabajo hecho, y esa es la razón por la que el salto al peldaño cuatro es mucho menor de lo que su fama sugiere.

Hacia dónde va el modelado de estado

Ejecución durable

Temporal, Restate y la familia de motores de workflow durable resuelven lo que un statechart en memoria no puede: sobrevivir al reinicio del proceso. La convergencia con el event sourcing es evidente y todavía está a medio hacer.

🔒

Tipos que verifican protocolos

El patrón type-state en Rust y Swift ya deja que el compilador rechace la llamada ilegal. La línea de investigación de los tipos de sesión, iniciada por Honda en los noventa, apunta a tipar la conversación entera entre dos partes.

🖼️

El modelo como artefacto central

Cuando escribir código se abarata, lo escaso pasa a ser la especificación pequeña, formal y revisable. El diagrama deja de ser documentación y se convierte en el objeto que se aprueba.

🧩

Composición verificada

Lo que hoy se comprueba de una máquina —alcanzabilidad, cobertura— se comprobará de sistemas de actores. Es el problema abierto más interesante, y también el más difícil por razones teóricas.

La primera línea merece un apunte porque es la que hoy tiene el hueco más visible. Un statechart en memoria muere con su proceso, y buena parte de los procesos de negocio duran días o semanas: una devolución, una contratación, una verificación de identidad. Los motores de ejecución durable resuelven la persistencia y la reanudación pero ofrecen un modelo de comportamiento pobre, normalmente código secuencial con puntos de guardado; los statecharts ofrecen el modelo y no la durabilidad. La convergencia entre ambos —un grafo revisable cuya configuración se persiste y se reanuda— es un espacio de diseño todavía abierto, y quien sepa modelar bien va a encontrarlo cómodo cuando madure.

De las cuatro, la tercera es la que más conviene interiorizar porque cambia el valor relativo de las habilidades. Durante décadas el cuello de botella fue producir código; en esa economía, una especificación formal era un coste añadido que había que justificar. Cuando el código se genera barato, el cuello de botella se desplaza a decidir qué debe hacer el sistema y a comprobar que lo generado lo hace. Un statechart pequeño, con nombres de dominio y sin celdas vacías, es exactamente el artefacto que sirve para las dos cosas: es lo bastante formal para generar desde él y lo bastante legible para que una persona lo apruebe. La habilidad que sube de precio no es escribir la máquina, es saber cuál es la máquina correcta.

El formalismo sobrevive a las herramientas porque no describe la herramienta, describe el problema

Vale la pena terminar el track con la razón profunda por la que estas ideas duran, porque esa razón es también un criterio para decidir qué estudiar durante el resto de una carrera. Una biblioteca es una respuesta a un problema técnico en un contexto tecnológico concreto: cuando cambia el contexto —el lenguaje, el entorno de ejecución, las restricciones de rendimiento— la respuesta deja de aplicar y hay que sustituirla. Un formalismo, en cambio, no responde a un problema técnico sino a uno cognitivo: cómo puede una persona razonar con certeza sobre un sistema cuyo comportamiento no cabe en su cabeza. Ese problema no depende de la tecnología porque no está en la máquina, está en nosotros, y nuestras limitaciones no han cambiado desde 1987 ni van a cambiar. Por eso la quíntupla sigue siendo útil, por eso las tres construcciones de Harel siguen siendo exactamente las tres que hacen falta, y por eso el modelo de actores describe igual de bien un sistema de mensajería de hace cincuenta años y uno de ahora. La consecuencia para quien está terminando este recorrido es directa y es lo más valioso que se lleva: lo que ha aprendido no se le va a quedar obsoleto, y además le da un instrumento de medida para todo lo que venga después. Ante cada herramienta nueva que prometa gestionar el estado, tendrá tres preguntas que ninguna presentación comercial responde por sí sola —qué estados hace imposibles, qué garantiza sobre el orden, y qué puedo demostrar de un sistema construido con esto— y las respuestas a esas preguntas separan en un minuto lo que es un avance real de lo que es una sintaxis distinta para el mismo problema sin resolver. Esa capacidad de discriminar, y no el dominio de ninguna API concreta, es lo que este track ha estado construyendo desde el primer nivel.

⚔️ Diseña tu plan de estudio de los próximos seis meses
  1. Lee el artículo de Harel de 1987 entero y anota las tres construcciones que introduce junto al problema concreto que cada una resolvía. Compáralas con lo que usas.
  2. Abre el algoritmo de interpretación de SCXML y sigue a mano el orden de salidas y entradas para una transición que cruza tres niveles de tu propia máquina.
  3. Escoge tu máquina más crítica y sube un peldaño en la escalera de verificación: si estás en tests concretos, implementa el recorrido exhaustivo con invariantes.
  4. Escribe dos propiedades de tu sistema, una de seguridad y una de viveza, en lenguaje natural preciso. Comprueba cuál de las dos no cubre ninguna prueba actual.
  5. Especifica en TLA+ el protocolo más pequeño de tu sistema que tenga dos partes coordinándose, aunque sea un ejercicio desechable. El objetivo es el modelo, no el resultado.
  6. Escoge una de las cuatro líneas de evolución y sigue durante seis meses una sola fuente sobre ella. Al final, escribe tú la lección que te habría gustado leer hoy.