I’m developing sales promotion system and I just stepped on something that could be probably handled with state machine pattern, but I have no experiences with state machines yet. Maybe the state machine is totally useless in this situation 🙂 So I have a sales promotion which has some duration, some assigned customers, products, discounts etc. Each promotion also has it’s state. There’s about 5 states. The transitions between states are strictly defined – it’s not possible to change state 1 to state 3 directly – user has to change state to 2 first. There’re some limitations like ‘it’s not possible to add more products when promotion is in state 3-5’. Or limitations like ‘only super-users can edit promotion costs when it’s in state 3-5’.
I just read about http://www.codeplex.com/SimpleStateMachine , but I’m not sure if it isn’t too complex for this case. I could handle the state logic in my service layer using things like:
if (promotion.state == statesRepository.GetState3() && false == loggedUser.IsInRole('superUser')){ throw new PromotionStateException('user not allowed to edit promotion in this status'); } ...
or
public void ChangePromotionStatus(promotion, newStatus){ if (promotion.Status == status1 && newStatus != statesRepo.GetState2()){ throw new StateTransitionException('unable to change from status 1 to ' + newStatus); } }
But I don’t like this kind of code – there must be some better approach 🙂 Does anybody have an advice? I could separate the concerns of course and develop services like PromotionStatusChangeReviewService, PromotionEditPermissionService etc to make the code less coupled, but there’s probably some better solution I can’t see at the moment.
Five states isn’t too complex for a state machine, but I think you’re running into some problems by trying to make a few of the transitions be handled specially or explicitly. Here’s some tips:
State machines aren’t helpful unless you can label the states in a meaningful way. ‘status 3’ means nothing; you need to call it something useful like ‘Promoted’, ‘Active’, ‘Completed’, et cetera.
Part of the State Machine pattern assumes that you have a detached entity that understands the states and how to transition between them. You shouldn’t have a method like the
ChangePromotionStatus()in your example, for instance, where it blows up if the state shouldn’t be allowed. The state machine should simply prevent transitions that can’t occur.If the number of possible transitions is small and well-defined, and it makes sense to label them, I’d also recommend naming the transitions as well. This is probably especially useful if the transitions all do the same thing but in slightly different ways.