Modeling Explicit Workflow With Code, In JavaScript And Backbone Apps

This post has been revised and reposed on blog.


A long time ago, in what seems to be a previous life at this point, I wrote a small blog post about modeling and creating an explicit return value from a dialog form in a Windows application. Fast forward a lifetime (3 years) and I’m finding that this knowledge and experience is resurfacing itself on almost a daily basis with my work in Backbone and Marionette. In fact, I’ve used almost this exact pattern that I first used in WinForms, with several Backbone applications now. But I found it to be rather limiting in how I was able to implement it, because of the language and runtime differences. What I’ve settled on, though, is giving me the same benefit of explicit modeling, semantics, and encapsulating workflow: events.

A Poorly Constructed Workflow

It seems to be common in the JavaScript applications world, to have very poorly defined and constructed workflow in applications. We take one object and build some functionality. Then when the next part of the app needs to fire up, we call the object that runs it directly from the first object. Then when the next part of the app is requested, we call that object from the second one. And we continue on down this path ad-infinitum, creating a mess of tightly coupled concerns, tightly coupled concepts, tightly coupled objects, and a brittle and fragile system that is dependent entirely on the implementation details to understand the higher level concept.

For example, might have a human resources application that allows you to add a new employee and select a manager for the employee. After entering a name and email address, we would show the form to select the manager. When the user clicks save, we create the employee. A crude, but all too common implementation of this workflow might look something like this:

Can you quickly and easily describe the workflow in this example? If you can, then you’re a better person than I am. I have to spend time looking at the implementation details of both views in order to see what’s going on and why. I have to piece together the bits from multiple places and form a more coherent high level overview in my head. It’s not easy for me to see what’s going on because every time I look at another part of the code, I have to put together the pieces again to make sure I am not breaking someone from the other parts.

Too Many Concerns

We’ve mixed two different concerns in to very few objects, and we’ve taken those concerns and split them apart in some rather un-natural ways at that.

The first concern is the high level workflow:

  1. enter employee info
  2. select manager
  3. create employee

The second concern is the implementation detail:

  1. Show the EmployeeInfoForm
  2. Allow the user to enter a name and email address
  3. When “next” is clicked, gather the name and email address of the employee.
  4. Then show the SelectManagerForm with a list of possible managers to select from.
  5. When “save” is clicked, grab the selected manager
  6. Then take all of the employee information and create a new employee record on the server

And I haven’t even gone through any of the secondary and third level workflow in this. What happens when the user hits cancel on the first screen? Or on the second? What about invalid email address validation? If we start adding in all of those steps to the list of implementation details, this list of steps to follow is going to get out of hand very quickly.

By implementing both the high level workflow and the implementation detail in the views – the details and implementation – we’ve destroyed our ability to see the high level workflow at a glance. That will cause problems for us as developers, because we will forget some of those details when changing the system, and we will break things.

Modeling An Explicit Workflow In Code

What we want to do, instead, is get back to that high level workflow with fewer bullet points and very little text in each point. But we don’t want to have to dig through all of the implementation details in order to get to it. We want to see the high level workflow in our code, separated from the implementation details. This makes it easier to change the workflow and to change any specific implementation detail without having to rework the entire workflow.

Wouldn’t it be nice if we could write this code, for example:

In this pseudo-code example, we can more clearly see the high level workflow. When we complete the employee info, we move on to the selecting a manager. When that completes, we save the employee with the data that we had entered. It all looks very clean and simple. We could even add in some of the secondary and third level workflow without creating too much mess. And more importantly, we could get rid of some of the nested callbacks with better patterns and function separation.

But let’s see what this would really look like in code that we could execute:

Yeah – turns out this is code that we can actually run, and it can be implemented fairly easily with a couple of Backbone views and a model for the details:

I’ve obviously omitted some of the details of the views and model, but you get the idea.

The Benefits

There are a number of benefits to writing code like this. It’s easy to see the high level workflow. We don’t have to worry about all of the implementation details for each of the views or the model when dealing with the workflow. We can change any of the individual view implementations when we need to, without affecting the rest of the workflow (as long as the view conforms to the protocol that the workflow defines). And there’s probably a handful of other benefits, as well.

But the largest single benefit of all these, in my experience, is being able to see the workflow at a glance. 6 months from now – or if you’re like me, 6 hours from now – you won’t remember that you have to trace through 5 different Views and three different custom objects and models, in order to piece together the workflow that you spun together in the sample at the very top of this post. But if you have a workflow as simple as the one that we just saw, where the workflow is more explicit within a higher level method, separated from the implementation details… well, then you’re more likely to pick up the code and understand the workflow quickly.

The Drawbacks

Everything has a price, right? But the price for this is fairly small. You will end up with a few more objects and a few more methods to keep track of. There’s a mild overhead associated with this in the world of browser based JavaScript, but that’s likely to be so small that you won’t notice.

The real cost, though, is that you’re going to have to learn new implementation patterns and styles of development in order to get this working, and that takes time. Sure, looking at an example like this is easy. But it’s a simple example and a simple implementation. When you get down to actually trying to write this style of code for yourself, in your project, with your 20 variations on the flow through the application, it will get more complicated, quickly. And there’s no simple answer for this complication in design, other than to say that you need to learn to break down the larger workflow in to smaller pieces that can look as simple as this one.

But It’s Worth It

In the end, in spite of potential drawbacks and learning curves, making an effort to explicitly model your workflow in your application is important. And it really doesn’t matter what language your writing your code in. I’ve shown these examples in JavaScript and Backbone because that’s what I’m using on a daily basis at this point. But I’ve been applying these same rules to C#/.NET, Ruby and other languages for years. The principles are the same, it’s just the implementation specifics that change.

Help Me Improve The Marionette Wiki