OeditusCredo.Check.Refactoring.SuggestFSM
(OeditusCredo v0.6.0)
View Source
Basics
This check is disabled by default.
Learn how to enable it via .credo.exs.
This check has a base priority of low and works with any version of Elixir.
Explanation
Modules that manage entity lifecycle through plain imperative code --
branching on a status/state field, manually setting it to new values,
scattering guards across multiple function heads -- should consider using
a proper finite state machine instead.
Suggested replacements:
Finitomata-- an Elixir FSM library with PlantUML/Mermaid diagram input, callbacks, supervision, history, and telemetry.:gen_statem-- the OTP built-in state machine behaviour.
Bad:
defmodule MyApp.Order do
use Ecto.Schema
schema "orders" do
field :status, Ecto.Enum, values: [:draft, :pending, :paid, :shipped, :delivered]
end
def pay(order) do
case order.status do
:draft -> {:error, :not_ready}
:pending -> Ecto.Changeset.change(order, status: :paid)
:paid -> {:error, :already_paid}
_ -> {:error, :invalid}
end
end
endGood:
defmodule MyApp.OrderFSM do
@fsm """
draft --> |submit| pending
pending --> |pay| paid
paid --> |ship| shipped
shipped --> |deliver| delivered
"""
use Finitomata, fsm: @fsm, syntax: :flowchart
@impl Finitomata
def on_transition(:pending, :pay, _payload, state),
do: {:ok, :paid, state}
endCheck-Specific Parameters
Use the following parameters to configure this check:
:exclude_test_files
Set to true to skip test files (default: false)
This parameter defaults to nil.
:status_field_names
Field names to watch (default: [:status, :state])
This parameter defaults to nil.
:min_states
Minimum distinct status values to trigger (default: 3)
This parameter defaults to nil.
General Parameters
Like with all checks, general params can be applied.
Parameters can be configured via the .credo.exs config file.