state-machine-design

安装量: 56
排名: #13159

安装

npx skills add https://github.com/melodic-software/claude-code-plugins --skill state-machine-design

State Machine Design Skill When to Use This Skill

Use this skill when:

State Machine Design tasks - Working on statechart and state machine modeling for lifecycle and behavior specification Planning or design - Need guidance on State Machine Design approaches Best practices - Want to follow established patterns and standards Overview

Design finite state machines and statecharts for modeling entity lifecycles, workflows, and system behavior.

MANDATORY: Documentation-First Approach

Before designing state machines:

Invoke docs-management skill for state machine patterns Verify implementation patterns via MCP servers (context7 for XState, etc.) Base all guidance on Harel statechart semantics State Machine Concepts Core Elements Element Description Example State Condition the system can be in Draft, Submitted, Paid Transition Change from one state to another Draft → Submitted Event Trigger for a transition Submit, Pay, Cancel Guard Condition that must be true [hasItems], [isValid] Action Side effect on transition sendNotification, updateDatabase Entry Action Action when entering state onEnter: startTimer Exit Action Action when leaving state onExit: stopTimer State Types public enum StateType { Initial, // Starting state (filled circle) Normal, // Regular state Final, // End state (circle with border) Composite, // Contains sub-states Parallel, // Concurrent regions History, // Remember last sub-state Choice // Decision point }

State Machine Notation PlantUML Syntax @startuml title Order State Machine

[*] --> Draft : Create

state Draft { Draft : entry / initializeOrder Draft : exit / validateOrder }

Draft --> Submitted : Submit [hasItems] Draft --> Cancelled : Cancel

state Submitted { Submitted : entry / reserveInventory }

Submitted --> Paid : ProcessPayment [paymentValid] Submitted --> Cancelled : Cancel / releaseInventory Submitted --> Draft : RequireChanges

state Paid { Paid : entry / confirmInventory }

Paid --> Shipped : Ship Paid --> Refunded : Refund

state Shipped { Shipped : entry / sendTrackingNotification }

Shipped --> Delivered : Deliver Shipped --> Returned : Return

Delivered --> Completed : Finalize Delivered --> Returned : Return

Returned --> Refunded : ProcessReturn

Completed --> [] Refunded --> [] Cancelled --> [*]

@enduml

Mermaid Syntax stateDiagram-v2 [*] --> Draft : Create

state Draft {
    direction LR
    [*] --> Empty
    Empty --> HasItems : AddItem
    HasItems --> HasItems : AddItem
    HasItems --> Empty : RemoveLastItem
}

Draft --> Submitted : Submit
Draft --> Cancelled : Cancel

Submitted --> Paid : PaymentReceived
Submitted --> Cancelled : Cancel
Submitted --> Draft : RequireChanges

Paid --> Shipped : Ship
Paid --> Refunded : Refund

Shipped --> Delivered : Deliver
Shipped --> Returned : Return

Delivered --> Completed : Finalize
Delivered --> Returned : Return

Returned --> Refunded : ProcessReturn

Completed --> [*]
Refunded --> [*]
Cancelled --> [*]

C# Implementation Patterns Simple State Machine public sealed class Order : Entity { public OrderStatus Status { get; private set; }

private static readonly Dictionary<(OrderStatus From, OrderEvent Event), OrderStatus> _transitions =
    new()
    {
        { (OrderStatus.Draft, OrderEvent.Submit), OrderStatus.Submitted },
        { (OrderStatus.Draft, OrderEvent.Cancel), OrderStatus.Cancelled },
        { (OrderStatus.Submitted, OrderEvent.Pay), OrderStatus.Paid },
        { (OrderStatus.Submitted, OrderEvent.Cancel), OrderStatus.Cancelled },
        { (OrderStatus.Submitted, OrderEvent.RequireChanges), OrderStatus.Draft },
        { (OrderStatus.Paid, OrderEvent.Ship), OrderStatus.Shipped },
        { (OrderStatus.Paid, OrderEvent.Refund), OrderStatus.Refunded },
        { (OrderStatus.Shipped, OrderEvent.Deliver), OrderStatus.Delivered },
        { (OrderStatus.Shipped, OrderEvent.Return), OrderStatus.Returned },
        { (OrderStatus.Delivered, OrderEvent.Finalize), OrderStatus.Completed },
        { (OrderStatus.Delivered, OrderEvent.Return), OrderStatus.Returned },
        { (OrderStatus.Returned, OrderEvent.ProcessReturn), OrderStatus.Refunded },
    };

public Result Transition(OrderEvent @event)
{
    if (!_transitions.TryGetValue((Status, @event), out var newStatus))
    {
        return Result.Failure($"Cannot {@event} order in {Status} status");
    }

    var oldStatus = Status;
    Status = newStatus;

    AddDomainEvent(new OrderStatusChangedEvent(Id, oldStatus, newStatus, @event));

    return Result.Success();
}

}

public enum OrderStatus { Draft, Submitted, Paid, Shipped, Delivered, Completed, Cancelled, Returned, Refunded }

public enum OrderEvent { Submit, Cancel, Pay, RequireChanges, Ship, Refund, Deliver, Return, Finalize, ProcessReturn }

State Pattern Implementation public abstract class OrderState { public abstract OrderStatus Status { get; }

public virtual Result Submit(Order order) =>
    Result.Failure($"Cannot submit order in {Status} state");

public virtual Result Cancel(Order order) =>
    Result.Failure($"Cannot cancel order in {Status} state");

public virtual Result Pay(Order order) =>
    Result.Failure($"Cannot pay order in {Status} state");

public virtual Result Ship(Order order) =>
    Result.Failure($"Cannot ship order in {Status} state");

protected void TransitionTo(Order order, OrderState newState)
{
    order.SetState(newState);
}

}

public sealed class DraftState : OrderState { public override OrderStatus Status => OrderStatus.Draft;

public override Result Submit(Order order)
{
    if (!order.HasItems)
        return Result.Failure("Order must have items to submit");

    TransitionTo(order, new SubmittedState());
    order.ReserveInventory();
    return Result.Success();
}

public override Result Cancel(Order order)
{
    TransitionTo(order, new CancelledState());
    return Result.Success();
}

}

public sealed class SubmittedState : OrderState { public override OrderStatus Status => OrderStatus.Submitted;

public override Result Pay(Order order)
{
    TransitionTo(order, new PaidState());
    order.ConfirmInventory();
    return Result.Success();
}

public override Result Cancel(Order order)
{
    order.ReleaseInventory();
    TransitionTo(order, new CancelledState());
    return Result.Success();
}

}

Stateless Library Pattern using Stateless;

public sealed class OrderStateMachine { private readonly StateMachine _machine; private readonly Order _order;

public OrderStateMachine(Order order)
{
    _order = order;
    _machine = new StateMachine<OrderStatus, OrderEvent>(
        () => order.Status,
        status => order.SetStatus(status));

    ConfigureTransitions();
}

private void ConfigureTransitions()
{
    _machine.Configure(OrderStatus.Draft)
        .Permit(OrderEvent.Submit, OrderStatus.Submitted)
        .Permit(OrderEvent.Cancel, OrderStatus.Cancelled)
        .OnEntry(() => _order.InitializeOrder());

    _machine.Configure(OrderStatus.Submitted)
        .PermitIf(OrderEvent.Pay, OrderStatus.Paid,
            () => _order.PaymentIsValid)
        .Permit(OrderEvent.Cancel, OrderStatus.Cancelled)
        .Permit(OrderEvent.RequireChanges, OrderStatus.Draft)
        .OnEntry(() => _order.ReserveInventory())
        .OnExit(() => { /* cleanup if needed */ });

    _machine.Configure(OrderStatus.Paid)
        .Permit(OrderEvent.Ship, OrderStatus.Shipped)
        .Permit(OrderEvent.Refund, OrderStatus.Refunded)
        .OnEntry(() => _order.ConfirmInventory());

    _machine.Configure(OrderStatus.Shipped)
        .Permit(OrderEvent.Deliver, OrderStatus.Delivered)
        .Permit(OrderEvent.Return, OrderStatus.Returned)
        .OnEntry(() => _order.SendTrackingNotification());

    _machine.Configure(OrderStatus.Delivered)
        .Permit(OrderEvent.Finalize, OrderStatus.Completed)
        .Permit(OrderEvent.Return, OrderStatus.Returned);

    _machine.Configure(OrderStatus.Returned)
        .Permit(OrderEvent.ProcessReturn, OrderStatus.Refunded);

    // Terminal states
    _machine.Configure(OrderStatus.Completed);
    _machine.Configure(OrderStatus.Cancelled);
    _machine.Configure(OrderStatus.Refunded);
}

public bool CanFire(OrderEvent trigger) => _machine.CanFire(trigger);

public void Fire(OrderEvent trigger) => _machine.Fire(trigger);

public IEnumerable<OrderEvent> GetPermittedTriggers() =>
    _machine.GetPermittedTriggers();

}

XState Pattern (TypeScript) import { createMachine, assign } from 'xstate';

interface OrderContext { items: LineItem[]; customerId: string; paymentId?: string; trackingNumber?: string; }

type OrderEvent = | { type: 'ADD_ITEM'; item: LineItem } | { type: 'REMOVE_ITEM'; itemId: string } | { type: 'SUBMIT' } | { type: 'PAY'; paymentId: string } | { type: 'CANCEL' } | { type: 'SHIP'; trackingNumber: string } | { type: 'DELIVER' } | { type: 'RETURN' } | { type: 'REFUND' };

const orderMachine = createMachine({ id: 'order', initial: 'draft', context: { items: [], customerId: '', } as OrderContext,

states: { draft: { entry: 'initializeOrder', on: { ADD_ITEM: { actions: assign({ items: ({ context, event }) => [...context.items, event.item], }), }, REMOVE_ITEM: { actions: assign({ items: ({ context, event }) => context.items.filter(i => i.id !== event.itemId), }), }, SUBMIT: { target: 'submitted', guard: 'hasItems', }, CANCEL: 'cancelled', }, },

submitted: {
  entry: 'reserveInventory',
  exit: 'onSubmittedExit',
  on: {
    PAY: {
      target: 'paid',
      guard: 'paymentValid',
      actions: assign({
        paymentId: ({ event }) => event.paymentId,
      }),
    },
    CANCEL: {
      target: 'cancelled',
      actions: 'releaseInventory',
    },
  },
},

paid: {
  entry: 'confirmInventory',
  on: {
    SHIP: {
      target: 'shipped',
      actions: assign({
        trackingNumber: ({ event }) => event.trackingNumber,
      }),
    },
    REFUND: 'refunded',
  },
},

shipped: {
  entry: 'sendTrackingNotification',
  on: {
    DELIVER: 'delivered',
    RETURN: 'returned',
  },
},

delivered: {
  on: {
    RETURN: 'returned',
  },
  after: {
    // Auto-complete after 14 days
    '14d': 'completed',
  },
},

returned: {
  on: {
    REFUND: 'refunded',
  },
},

completed: { type: 'final' },
cancelled: { type: 'final' },
refunded: { type: 'final' },

}, }, { guards: { hasItems: ({ context }) => context.items.length > 0, paymentValid: ({ event }) => event.type === 'PAY' && !!event.paymentId, }, actions: { initializeOrder: () => console.log('Order initialized'), reserveInventory: ({ context }) => console.log(Reserving ${context.items.length} items), confirmInventory: () => console.log('Inventory confirmed'), releaseInventory: () => console.log('Inventory released'), sendTrackingNotification: ({ context }) => console.log(Tracking: ${context.trackingNumber}), }, });

Design Best Practices State Design Guidelines Name states as conditions: Submitted not Submit Name events as commands: Submit not Submitted Use guards for conditional transitions Keep states atomic: One responsibility per state Document entry/exit actions Consider terminal states (final states) Common Patterns Pattern Use Case Linear Simple sequential flow Choice Conditional branching Parallel Concurrent activities Hierarchical Complex nested states History Resume from last state Workflow

When designing state machines:

Identify entity: What has the lifecycle? List states: What conditions can it be in? Define events: What triggers state changes? Map transitions: State + Event → New State Add guards: What conditions must be true? Define actions: What happens on transitions? Draw diagram: Visualize for review Implement: Choose appropriate pattern References

For detailed guidance:

Last Updated: 2025-12-26

返回排行榜