Máquinas de Estado: El Fin de los Bugs Imposibles en tu Interfaz
El problema de las variables booleanas
En el desarrollo frontend, manejar la interfaz de usuario parece sencillo hasta que la aplicación empieza a crecer. Agregamos un botón de pago, un indicador de carga y un mensaje de error. Para controlar qué se muestra en pantalla en cada momento, solemos recurrir a la solución más rápida: crear variables booleanas.
Creamos variables como isLoading, hasError y isSuccess. Al principio, la lógica funciona. Pero a medida que el código se vuelve más complejo, un pequeño fallo de sincronización puede dejarnos con isLoading = true y hasError = true al mismo tiempo.
Una máquina de estados funciona como botones entrelazados: estar en un estado bloquea automáticamente combinaciones inválidas.
La interfaz entra en un estado contradictorio. Muestra el ícono de carga girando por encima del mensaje de error rojo, o permite al usuario hacer clic en "Pagar" cuando la transacción ya está en proceso. Acabamos de crear un estado imposible.
La solución: Máquinas de Estado Finito (FSM)
Para mitigar este problema de raíz, la arquitectura de software utiliza las Máquinas de Estado Finito. El concepto central es establecer una regla estricta: el sistema solo puede estar en un único estado a la vez.
Como analogía, funciona de manera similar a un panel de botones mecánicos entrelazados. Si el sistema entra en el estado de "Cargando" (presionando ese botón), el propio mecanismo físico hace saltar hacia afuera los botones de "Éxito" y "Error". Es mecánicamente imposible tener dos botones hundidos al mismo tiempo, reduciendo enormemente la necesidad de lidiar con combinaciones de variables booleanas sueltas.
Transiciones estrictas
Además de garantizar la exclusividad, las máquinas de estado definen transiciones. Establecemos reglas claras sobre cómo el sistema puede moverse de un punto a otro.
Desde el estado inicial de "Reposo", el camino permitido es hacia "Cargando". El sistema bloquea intentos de saltar directamente a "Éxito" sin pasar por el proceso correspondiente. Si ocurre un error, el sistema pasa a "Error" y define claramente si el usuario puede volver a intentar la acción o si el proceso queda bloqueado.
Un código predecible
Implementar este modelo mental (ya sea con librerías específicas como XState o estructurando mejor nuestros componentes) nos da un control superior sobre la interfaz.
Pasamos de tener un código frágil, lleno de condicionales impredecibles, a construir un sistema robusto donde se minimizan drásticamente los casos de estados contradictorios.


