6. Best Practices - iwannabebot/SharpFsm GitHub Wiki
Here are some best practices for defining conditions and side effects in SharpFsm:
Keep conditions pure, side effects focused, use the registry for reuse, name things clearly, handle errors, and test your logic. This leads to maintainable, robust, and readable FSMs in SharpFsm.
- Conditions should be pure functions:
- They should only inspect the context and return a boolean.
- Avoid side effects (e.g., logging, modifying state, calling external services) in conditions.
- Side effects should perform actions but not affect the outcome of the transition itself.
- Register commonly used conditions and side effects in the TransitionRegistry.
- Reference them by name in your FSM builder for clarity and maintainability.
- This avoids duplication and centralizes logic.
registry.RegisterCondition("IsAdmin", ctx => ctx.IsAdmin);
registry.RegisterSideEffect("Notify", ctx => notificationService.Notify(ctx.UserId));
- Design your context class to include only the data and services needed for evaluating conditions and executing side effects.
- Avoid making the context too broad or too tightly coupled to infrastructure.
- Use descriptive names when registering conditions and side effects.
- This improves readability and makes FSM definitions self-documenting.
registry.RegisterCondition("PaymentReceived", ctx => ctx.PaymentReceived);
registry.RegisterSideEffect("LogTransition", ctx => logger.Log("Transition occurred"));
- Side effects may interact with external systems and can throw exceptions.
- Consider wrapping side effects in try-catch blocks or handling errors at the FSM level to avoid breaking the FSM flow.
- Design side effects so that running them multiple times does not cause unintended consequences.
- This is especially important if transitions may be retried.
- Write unit tests for your condition and side effect functions to ensure correctness.
- This is easy since they are just delegates.
- Keep FSM definitions declarative.
- Place complex logic in the registry or in well-tested helper methods, not inline in the FSM builder.
// Good practice: Register and reference by name
registry.RegisterCondition("IsEligible", ctx => ctx.Age >= 18 && ctx.HasLicense);
registry.RegisterSideEffect("SendWelcomeEmail", ctx => emailService.Send(ctx.Email, "Welcome!"));
builder.AddTransition(State.Pending, State.Active)
.When("IsEligible")
.WithSideEffect("SendWelcomeEmail")
.Done();