OdeToCode IC Logo

Reactive Web Development versus Continuations

Wednesday, May 24, 2006

There is an appealing simplicity to the following code.

While GetNextCustomer()


End While

The software’s goals are exposed. The essence remains free from the details of collecting data and rendering results. When a few bad customers raise food costs by ordering pizzas and then disappearing, even a pointy-haired boss can cut and paste the solution, which is to make customers pay before sending an order to the kitchen.

Unfortunately, only textual command line applications can come close to resembling this pseudo-code. We build graphical applications, and shred the logic across event handlers. We hide the essence of the software inside the details of button click events.

Events are wonderful for decoupling components, but they tend to increase the complexity of an application’s goal. Think of an online pizza store built using ASP.NET. The above code is broken out across multiple forms (or with AJAX, multiple event handlers in the same form). ASP.NET is fundamentally an event-driven framework, and we program in response to events. Using an MVC pattern can decouple the interface and the controlling logic, but is still reactive programming and re-portrays the same difficulties at a higher level of abstraction.

Web development is hard. What can we do?

One idea is to program the web with a continuation framework. One implementation of this idea is Seaside:

What if you could express a complex, multi-page workflow in a single method? Unlike servlet models which require a separate handler for each page or request, Seaside models an entire user session as a continuous piece of code, with natural, linear control flow. In Seaside, components can call and return to each other like subroutines; string a few of those calls together in a method, just as if you were using console I/O or opening modal dialog boxes, and you have a workflow. And yes, the back button will still work.

Ian Griffiths posts a stellar introduction to continuations for .NET developers in “Continuations for User Journeys in Web Applications Considered Harmful”. As the title suggests, Ian also lists reasons why continuations are a bad idea. Ian ends with the following:

“My final objection is a bit more abstract: I think it’s a mistake to choose an abstraction that badly misrepresents the underlying reality. We made this mistake with various distributed object model technologies last decade.”

I think Ian raises valid points. The syntax of a general-purpose programming language, however expressive it is, doesn’t seem like a big enough blanket to hide all the complexities in modern web applications. Before Ian’s post, Don Box pointed to Windows Workflow as a “continuation management runtime”, and this idea is exciting.

Windows Workflow is a multifaceted technology. You can look at WF as a tool to manage long-running and stateful workflows with pluggable support for persistence services, tracking services, and transactions. You can also look at WF as a visual tool for building solutions with a domain specific language. These two faces of WF are particularly appealing to anyone who wants to bring the essence of an application back to the surface where it belongs.

The one thorn here is our old nemesis: the web browser’s back button. In a perfect world, we could model workflows for the web using simple sequential workflows like the one shown in this post. Unfortunately, typical WF solutions will look for specific types of events at specific steps in the workflow process. The browser’s back button puts users on a previous step, but there is no way to reverse or jump to an arbitrary step in a sequential workflow. Sequential workflows march inevitably forward. Jon Flanders has an ASP.NET / WF page-flow sample that avoids this problem by using a state machine workflow and a “catch all” event that takes a discriminator parameter. This sounds like a Windows message loop, which isn’t great, but as Jon mentions the current level of integration is a bit ad hoc. (It would be interesting if WF provided the ability to fork or clone a workflow instance when it idles so that one could backtrack by moving to a previosuly cloned instance, similar to the way Seaside maintains previous execution contexts).  

I hope the ASP.NET and Windows Workflow teams can work to make these two technologies fit together seamlessly and provide rich support from Visual Studio. It would be a joy to handle business processes with a domain specific language in a visual designer, and generate some skeletal web forms where we can finish off the sticky web details with C# and VB. This strikes me as a good balance.