Spring Statemachine utilizando Kotlin
O conceito de máquinas de estado finita ou autômato finito é muito antigo. Fazendo uma lida rápida sobre o assunto encontramos algumas definições, dentre elas:
FSM- do inglês Finite State Machine é um modelo matemático usado para representar programas de computadores. O conceito é concebido como uma máquina abstrata que deve estar em um número finido de estados.
Então vamos lá, um pouco de história…
A descrição de autômatos finitos nasceu em 1943 quando Warren McCulloch e Walter Pitts escreveram um artigo sobre isso e mais tarde, George H. Mealy introduziu o conceito de máquina de estado que ficou conhecido como Máquina de Mealy em 1955.
Um ano depois em 1956 Edward F. Moore apresentou um artigo ao qual descreveu o que é conhecido hoje como Máquina de Moore. Se você já leu um pouquinho sobre, vai reconhecer esses nomes aqui citados.
Mas, qual o propósito desse framework?
O Spring Statemachine(SSM) é um framework que utiliza conceitos sobre máquinas de estados e prover algumas features relacionadas.
Neste post irei fazer uma demonstração prática em Kotlin baseada na documentação do Spring Statemachine, alguns exemplos mais detalhados você poderá encontrar aqui.
Para aplicar o projeto busquei em um site focado em padrões de projeto e refatoração, o Refactoring Guru, e nele contém um exemplo que apresenta o padrão de projeto State, disponível aqui.
O problema
Temos um documento que pode assumir alguns estados, dentre eles:
- RASCUNHO, MODERACAO e PUBLICADO.
Esses estados são definidos a partir de eventos e podemos definir esses eventos como:
- PUBLICADO_POR_ADMINISTRACAO
- PUBLICADO_POR_USUARIO
- REVISAO_OU_FALHA, APROVADO ou EXPIROU.
Guarde o nome desses estados e eventos por que vamos utiliza-los em breve para a implementação da nossa máquina de estados.
Ilustração do Problema
Vamos adicionar a dependência do projeto Spring Statemachine no Maven.
Com a dependência configurada e o projeto OK, vamos partir para a implementação. Precisamos agora criar as enumerações que representam os estados e os eventos da nossa máquina de estados. Para representar os estados crie a enum DocumentoStates e nele adicione os estados da sua máquina.
E, para representar os eventos crie a enum DocumentoEvents.
Agora que definimos nossas Enums vamos criar a classe de configuração que irá representar a máquina de estados e nessa classe iremos implementar a configuração dos estados, transições, eventos e guardas.
Chamei a classe de DocumentoStateConfig e nela adicionei as seguintes anotações @Configuration e @EnableStateMachine. Além disso, estendi a classe EnumStateMachineConfigurerAdapter e passei como parâmetro as Enums que representam os estados e os eventos da máquina de estados.
No primeiro método a ser sobrescrito, vamos implementar a configuração inicial e o listener que irá identificar as transições dos estados da nossa máquina de estados.
No método getListener() estamos criando uma instância da classe StateMachineListenerAdapter e tornando essa classe um Bean gerenciado pelo Spring, com a anotação @Bean.
O segundo método que iremos sobrescrever é esse abaixo, nele dizemos quem é o estado inicial e quais os estados que fazem parte da máquina. É possível adicionar um evento quando o estado chegar no estado PUBLICADO, nesse caso estamos enviando um e-mail.
Para essa action funcionar é necessário implementar a interface Action e sobrescrever o método execute, para isso vamos criar a classe EnviarEmailAction.
Agora precisamos definir as transições, quando um evento ocorrer, o estado saíra de seu estado (source) e irá para o estado destino (target). Também é possível adicionar guards para validar se o evento será ou não executado.
Depois que definimos quais os fluxos de estados a partir dos eventos, vamos implementar o método responsável por verificar as mudanças de estado. Crie uma classe que estende a classe StateMachineListenerAdapter e implemente o método stateChenged.
Para verificar o fluxo dos estados a partir dos eventos, vamos colocar a máquina de estados para funcionar.
Como resultado obtemos o log ao executar o código acima e a explicação do passo a passo é:
- É configurado um estado inicial RASCUNHO.
- Quando o evento PUBLICADO_POR_USUARIO ocorreu o estado saiu de RASCUNHO para MODERACAO.
- Em seguida o evento aprovado foi disparado e com isso o estado foi de MODERACAO para PUBLICADO
- o envio do email ocorreu devido a mudança de estado do item 3.
- Com o evento EXPIROU o estado foi de (source) PUBLICADO para (target) RASCUNHO
Conclusão
O Spring State Machine é uma boa pedida quando você quer representar parte do seu sistema como estados finitos ou dividir a parte mais complexa em tarefas menores e gerenciáveis.
O principal ganho ao utilizar uma solução como o Spring State Machine é evitar que o código das transições e dos estados fiquem dispersos em seu código tornando assim a manutenção cada vez mais difícil. Dessa forma a consistência do seu software se torna muito melhor e o controle sobre os eventos e estados se concentram em um único ponto, ou seja, temos um único ponto de mudança.
Com certeza ainda é possível explorar outros pontos do projeto Spring State Machine. Este post tem o intuito de apresentar o conceito de uma forma breve e realizar um pequeno estudo de caso utilizando a linguagem de programação Kotlin.