views:

62

answers:

3

Hi the wise folks at SO. This is an SOS.

I'm in a deep trouble. In my web application there is an object (Say it is a request for something). User submits his/her request. After this it comes to the people who can approve/disapprove that request. During the period from submission to approval/disapproval many actions can be taken on the request. I have to present user with actions panel (collections of links) using which he/she can modify the state of the request.

Now based on which stage of processing the request is some actions are not allowed. Also if some action has already been taken it excludes the possibility of other actions.

Overall it creates a pretty complex matrix of allowed/forbidden actions that my tiny head is not able to take care of it.

I've create some static classes/methods which returns the arrays of allowed actions based on the state of the request. There are about 20 states that a application can be in. I've taken care based on state to remove/disable links for actions that are not possible in that state. Now problem arises is that suppose request is in state X.

Now if in past action l has been taken on request we may not allow l or based on this some arbitrary actions m,n,o.

After writing all the methods to get arrays of links for 20 states, I have to filter the arrays based on the past history of actions (which is stored in sql db) which is very very big task.

Please suggest me some pattern which is easier to implement and efficient. It is getting on my nerves.

A: 

Sounds like a job for a state machine workflow, or a few giant nested switches (which ever you prefer).

leppie
@leppie exactly the thing I was planning to do. but the problem is that the environment i'm working with is pretty constrained and I cannot get permission to use sql persistance/tracking for state machine wf. Without that WF is useless and I've to do this plumbing manually.
TheVillageIdiot
definitely a state machine. check out the following tutorial: http://blog.8thlight.com/articles/2006/11/17/understanding-statemachines-part-1-states-and-transitions
Martin DeMello
@aman if you cannot persist the state (weird limitation!) you could still implement the state machine pattern, augmented with a function that examines the state of the system and reconstructs your state machine state. that way you've cleanly separated the logic of "what state is the object in now?" from the logic of "what can we do from this state"
Martin DeMello
A: 

First thing that came into my mind: Statemachine. Each State is some kind of object. All states have some method "processRequest" that transits the execution into the next state.

The second thing that came into my mind - theses states have to be organized like a tree or graph. The graph represents the history of requests. You start in the initial State. You get Request A, you proceed to State A. After that, you get request B, you proceed to AB. Wether state AB is equal to BA is not clear by your description.

That way, you get far more states then your 20 states you have now, but each state includes the history. I'd suggest a naming convention after the path you had to take to get there (like AB before). And perhaps you can reuse state A and B in AB, to minimize coding.

Tobias Langner
+1  A: 

As I understand you have a real-world workflow scenario. In this case I would:

  1. Model entire state as a single entity if possible (a single row with fixed number of fields). I would not model this as a set of actions.

  2. Model each action as some change in the row. It is quite obvious when user enters some data, but I would also model each acceptance as either - a boolean field or a state field - depending on whether the acceptance is done by independent departments or it is a cascade of acceptance in a single department.

  3. Also there may be a situation when an acceptance is given for some particular parameter and the parameter may change in the future, requiring new acceptance. In this case I would model such scenario as two fields. On for the parameter value and the second one for the accepted value. I would make the decision on whether an acceptance is still needed based on the difference of this two fields. This allows for implementing some thresholds.

  4. Having a state modeled as a single row I would implement independent predicates for action allowance.

I think that point 4 is the most important one. If your are able to implement independent predicates for enabling actions then you will be able to easily modify them in the future.

Having 1-3 properly implemented you will be able to easily implement acceptance revoking, which may be required and in this case may make overall code size smaller.

agsamek