Ash StateMachine
TLDR;
Ash StateMachine 은 상태 변경이 가능한 케이스를 명시하고, 미리 선언된 상태 변경만 가능하도록 한다.
왜 쓸까?
예를 들면, “새로 생성 → 진행 중 → 완료” 처럼 정해진 workflow 가 있다면, 로직으로 if/else 를 사용하는 것보다 상태머신으로 선언해 두는 게 안전하고 읽기 쉽다.
예제: Task
요구사항:
기본 상태는
:new:start액션이:new → :in_progress:finish액션이:in_progress → :done언제든
:cancel로:canceled
1) state 및 transition 정의
defmodule MyApp.Todo.Task do
use Ash.Resource,
extensions: [AshStateMachine]
attributes do
# ...
end
state_machine do
initial_states [:new, :in_progress, :done, :canceled]
default_initial_state :new
transitions do
transition :start, from: :new, to: :in_progress
transition :finish, from: :in_progress, to: :done
transition :cancel, from: [:new, :in_progress], to: :canceled
end
end
Resource 의 extension 에 추가한다.
state_machine 블록에서 기본 설정
transitions 블록에서 가능한 상태변경을 정의한다.
개인적으로 상태변경에 이름을 부여할 수 있다는 점도 마음에 든다.
2) 액션에서 상태 변경
actions do
defaults [:create, :read, :update]
update :start do
change transition_state(:in_progress)
end
update :finish do
change transition_state(:done)
end
update :cancel do
change transition_state(:canceled)
end
end
end
- 단순하다. transition_state 를 호출하고 변경을 원하는 상태만 명시하면 끝이다.
State 컬럼은 어떻게 관리하는가?
확장을 켜면 기본으로
:stateattribute 가 생성된다.이름을 바꾸려면
state_attribute(:alternative_state)를 사용하면 된다.
허용되지 않는 변경을 하는 경우?
- Changeset Validation 에서 error 를 기록한다.
마무리
내 경우 상태값이 10개가 넘는 케이스가 있어서 처음 적용해 보았다.
하지만 상태관리를 복잡하게 하지 않는다고 해도 충분히 사용할 가치가 있다고 생각한다.
Ash 를 사용하는 이유와 비슷하게, 상태변경을 위한 구현을 하는게 아니라 선언적으로 상태관리를 할 수 있다는 점이 가장 큰 장점이라고 생각한다.
Reference
- Ash StateMachine hex docs [link]