Result<T>: Directing Workflow With A Return Status And Value

I often code user interfaces that have some sort of cancel button on them. For example, in my upcoming ‘Decoupling Workflow’ presentation, I have the following screen:

New Employee - Info

Notice the nice cancel button on the form. The trick to this situation is that I need to have my workflow code understand whether or not I clicked Next or clicked Cancel. Depending on the button that was clicked, I need to do something different in the workflow.  If I click cancel, throw away all of the data that was entered on the form. If I click next, though, I need to store all of the data and continue on to the next screen.

The Result<T> and ServiceResult

In the past, I’ve handled these types of buttons in many, many different ways. I’ve returned null from the form, I’ve checked the DialogResult of the form, I’ve done out parameters for methods, and I’ve done specific properties on the form or the form’s presenter to tell me the status vs the data. Recently, though, I’ve begun to settle into a nice little Result<T> class that does two things for me:

  1. Provides a result status – for example, a ServiceResult enum with Ok and Cancel as the two options
  2. Provides a data object (the <T> generic in Result<T>) for the values I need, if I need them

Here is the code for my ServiceResult and my Result<T> object.

public enum ServiceResult

{

 Ok = 0,

 Cancel = 1

}

 

public class Result<T>

{

 public ServiceResult ServiceResult { get; private set; }

 public T Data { get; private set; }

 

 public Result(ServiceResult serviceResult): this(serviceResult, default(T)){}

 

 public Result(ServiceResult serviceResult, T data)

 {

   ServiceResult = serviceResult;

   Data = data;

 }

}

Putting Result<T> To Work

With this simple little solution, I can create very concise and clear workflow objects that know how to handle the cancel button versus the next button. The code becomes easier to read and understand, and makes the real workflow that much easier to see. The workflow code that runs the “Add New Employee” process for the screen shot above, is this:

public void Run()

{

 Result<EmployeeInfo> result = GetNewEmployeeInfo.Get();

 if (result.ServiceResult == ServiceResult.Ok)

 {

   EmployeeInfo info = result.Data;

   Employee employee = new Employee(info.FirstName, info.LastName, info.Email);

 

   Employee manager = GetEmployeeManager.GetManagerFor(employee);

   manager.Employees.Add(employee);

 }

 

}

Notice the use of Result<EmployeeInfo> in this code. I’m checking to see if the result.ServiceResult is Ok before moving on to the use of the data. The GetNewEmployeeInfo class return a Result<EmployeeInfo> object from the .Get() method. The EmployeeInfo object contains the first name, last name, and email address of the employee as simple string values (and in the “real world”, the EmployeeInfo object would probably contain the input validation for these).

Because Result<T> is a generics class and returns <T> from the .Data property, I can specify any data value that I need and it returned from the presenter in question. This is where the real flexibility of the Result<T> object comes into play. When I have verified that the user clicked OK, via the result.ServiceResult property, I can then grab the real EmployeeInfo object out of the result.Data parameter which isstrongly typed to my EmployeeInfo class. Once I have this data in hand, I can do what I need with it and move on to the next step if there are any.

Conclusion

Having tried many different approaches to workflow code, I’m fairly well settled into this pattern right now. That doesn’t mean it won’t evolve, though. The basic implementation would cover most of what I need right now, but could easily be extended to include different “status” values instead of just the ServiceResults of OK and Cancel. Overall, though, this simple Result<T> class is saving me a lot of headache and heartache trying to figure out what to return from a method so that a workflow can figure out if the user is continuing, cancelling, or whatever.


Post Footer automatically generated by Add Post Footer Plugin for wordpress.

About Derick Bailey

Derick Bailey is an entrepreneur, problem solver (and creator? :P ), software developer, screecaster, writer, blogger, speaker and technology leader in central Texas (north of Austin). He runs SignalLeaf.com - the amazingly awesome podcast audio hosting service that everyone should be using, and WatchMeCode.net where he throws down the JavaScript gauntlets to get you up to speed. He has been a professional software developer since the late 90's, and has been writing code since the late 80's. Find me on twitter: @derickbailey, @mutedsolutions, @backbonejsclass Find me on the web: SignalLeaf, WatchMeCode, Kendo UI blog, MarionetteJS, My Github profile, On Google+.
This entry was posted in .NET, AppController, C#, Presentations, Principles and Patterns, Workflow. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • Brad

    (Off topic) What tool did you use to draw up the UI diagram?

  • Havagan


    As a Los Techies blogger shouldn’t you be using IServiceResult and not the evil Enum?

    Why not use events for failure and success? The EmployeeInfo could be part of a custom EventArgs class.

  • http://www.lostechies.com/members/derick.bailey/default.aspx derick.bailey

    @Brad,

    http://www.Balsamiq.com – I love that tool! it’s so easy to create quick wireframes without getting in the way of the creative process.

    @Havagan

    LOL! no… i was going to use an IServiceResultFactory with a Fluent Interface DSL to configure the Result Factory implementations via an external Ruby on Rails REST service, injected via a message oriented architecture. … um. yeah. that’s it. :)

    I’ve never used events for workflow results status, because i think it makes the code more difficult to understand. You end up with code like this:

    public void someservice_resulthandler(ServiceResult result)
    {
    serviceResult = result;
    }

    public void Run()
    {
    //do the workflow stuff here
    if (serviceResult == OK)
    //do other stuff here
    }

    the separation of workflow logic from the results just makes it more difficult to understand how the result gets set. plus, it forces me to remember that i need to listen to that event instead of intellisense telling me that there is a return value on the method call.

    of course, there’s no technical reason why you shouldn’t do this. it’s purely a preference on readability/understandability, which comes from training and expectations in a codebase. every team has their own standards on what understandability is.