tags:

views:

87

answers:

3

Let's say we have a web app out there that is supposed to have a user fill out a form, and then it creates a ticket in the backend workflow engine. This form is going to continue to be the portal for the customer to view what's going on. Some forms go straight to ticket creation; others have to get approved by someone else before generating a ticket, and they can also be denied. This thing sends out emails, tracks answers to the questions of the form, tracks any uploaded attachments, and also logs "updates" as various actions are made to change the state of the form.

The business logic to decide what all to do when the form is first submitted or saved is starting to get hairy and I'm looking on ways to refactor it. I've started to look at state/strategy patterns, but it seems like all the logic just needs to get lumped together in one place eventually anyway. Plus, with all the dependencies on answers/attachments/log entries, it makes it complicated to inject mocks into because it has so much that it has to track.

Here's a pseudocode-ish layout of the form object's "save" functionality, simplified down...it's starting to get nasty and I'm trying to see if I can make it cleaner somehow.

if(this.isvalid)
{
    if(isNewForm && !this.needsApproval) //just created, so start up a ticket
    {
     CreateTicket();
    }

    if(!isNewForm && justApproved) //pulled from the DB earlier, and was just approved
    {
     CreateTicket();
    }

    if(!isNewForm && justDenied) //pulled from the DB earlier, and was just denied
    {
     this.needsApproval = false;
     this.closed = true;
    }

    if(isNewForm)
    {
     SendNewFormEmail();
     if(this.NeedsApproval)
     {
      SendNeedsApprovalEmail();
     }

     this.CommentEntries.Add("Request submitted.");
    }
    else if(justApproved)
    {
     SendApprovalEmail();
     this.CommentEntries.Add("Request approved.");
    }
    else if(justDenied)
    {
     SendDenialEmail();
     this.CommentEntries.Add("Request denied.");
    } 

    this.Save();

    this.Answers.Save();
    this.Attachments.Save();
    this.CommentEntries.Save();
}
+2  A: 

I've been thinking about state machines alot lately and I found the following proposal very promising. I wish I could tell you it works really great but I have not gotten that far yet. I can tell you that it looks better than any solution I've tried to date. Here's the link.. Hierarchical State Machine

Arnold Spence
A: 
if (isNewForm) {

   if (JustDenied) {
      ...
   }

   if (JustApproved) {
      ....
   }

} else {
   ... not a new form ...
}

I'm not sure how your handling JustDenied, but perhaps:

switch (FormState) {
case JustApproved:
   ....
case JustDenied:
   ....
}

Its psuedo code, so hard to say if that would work. But, yes, I agree that what you posted is starting to resemble pasta.

Tim Post
A: 

I think this is an excellent candidate for Workflow Foundation.

Problem is not to write a complicated state machine, it's dealing with the dynamics of a business (which can also seem like pasta sometimes ;)). The rules change, code needs to be changed, and as you spotted this yourself, maintainability can easily become a nightmare here...

Jeroen Landheer