ARCast.TV - DinnerNow - Architecture Overview and Workflow

The Discussion

  • User profile image

    ARCast.TV - DinnerNow - Architecture Overview and Workflow

    Announcer: It's Thursday, July 12, 2007, and you're watching ARCast TV.
    Ron Jacobs: Man, I'm hungry. I need some dinner -- now. Hey, welcome back to ARCast, this is your host, Ron Jacobs, and today we are going to talk to the team that built DinnerNow. Actually, not just today but over the next few episodes of ARCast, we're going to look at this sample application, DinnerNow, that shows how you use the pieces of.NET 3.0 together -- Workflow, CardSpace, Windows Communication Foundation -- just a whole ball of wax that's all put together into an application you can download, get all the source code, and see how it's designed. It's a great example, and so today we have Matt Winkler. He's going to be talking about an architecture overview and how Workflow is used in the DinnerNow application.

    Hey, welcome back to ARCast. This is your host, Ron Jacobs, and today I am here in Redmond where I'm chatting with a colleague of mine, Matt Winkler, and welcome, Matt, to ARCast.
    Matt Winkler: Thank you, it's good to be here.
    Ron: Now, I wanted to have you on the show today to talk about this little DinnerNow thing you guys did. So, first off, what is DinnerNow?
    Matt: Normally what we do in our group, we have different evangelists that are all kind of focused on one technology.
    Ron: OK.
    Matt: And so we go really deep in that technology. Mine, for instance, is Windows Workflow Foundation.
    Ron: Right.
    Matt: But what we really felt we were lacking, we didn't have a kind of all-up story kind of showing off the whole platform, how we use these different pieces and parts together. And so what we wanted to do, we set out to build kind of a sample application that really showed off all of the different technologies that we have available.

    So things on the presentation layer, like WPF or ASP.NET Ajax; things on the surface layer, like WCF and Windows Workflow Foundation; and then we also wanted to do things to show how we make applications more manageable, so we built PowerShell on top of that, and MMC consoles -- about the only thing it doesn't do in v1 is flush the toilet.
    Ron: [laughs]
    Matt: We really want to get that in there for v2, though.
    Ron: Great, great. Good addition. All right, so the idea is that you put this whole thing together, make the source code available, people can go and download this and check it out.
    Matt: Yes. So they can go right now to, and that has a pointer to CodePlex, which is where we have the source code hosted. We've done two public releases and we've got a third that's coming. In the third release we're going to do a big refactoring and clean up a lot of the stuff that we kind of threw together to get the demo out the door. So they can download that, it'll install, it'll check to make sure you've got all the right dependencies on your machine, and get up and running shortly.
    Ron: Ah, OK. Very cool. So, DinnerNow, I assume it has something to do with food -- which I'm always in favor of -- so, what's the scenario of DinnerNow?
    Matt: The scenario is that I'm hungry and I want to order food, as a consumer.
    Ron: Yeah.
    Matt: And so I go to a website and I say, "Gosh, I'd really like an appetizer from this place, my entree from this place, and then I'd like dessert from this other place down the street, because they've got really good cheesecake." So I'm going to pay for that, orders are going to get transmitted, and then hopefully, in 30 minutes or so, a driver's going to show up at my door with all of those items. So that's the consumer experience.
    Ron: OK. Go right ahead.
    Matt: Going to a website, ordering food. What then happens on the backend is that an order is received, it's sent to the individual restaurants, the restaurants are going to work on that separately, because I'm getting cheesecake from one place and a burger from another...
    Ron: OK.
    Matt: At some point the food's going to be ready, a driver is going to be notified that he needs to pick the orders up, so he'll go pick those up and then drop them off. And we kind of need to manage the state of the order throughout the whole process; we need to manage it both at the restaurant level, as well as, for the consumer, "Where is my order at?"
    Ron: OK.
    Matt: That's going to either be delivered or not, but at the individual restaurant level, you're going to have things like: it's cooking; it's ready for pickup; it's out for delivery; and then ultimately, it could be delivered.
    Ron: Oh, OK. Or I could maybe cancel it?
    Matt: Right, it could also be cancelled. That's not good for revenue, so...
    Ron: No, no, bad thing. All right. So the idea is that this business DinnerNow kind of makes money by being the middleman -- giving the restaurant a web front-end, a way to take orders and kind of expand their business by doing this -- and they get a piece of the pie, if you will.
    Matt: Right.
    Ron: To stick with the food...
    Matt: Yes, to stick with the food analogy.
    Ron: [laughs]
    Matt: But the other thing that we did -- we built the web experience that the consumer has...
    Ron: OK.
    Matt: We also built a kiosk experience for the restaurants to have. This is where the restaurant would receive the order, they would update the order, say, "Hey, we're done cooking, now it's out for delivery..."
    Ron: OK.
    Matt: ...And kind of find out all of that information. So we built that as a WPF application.
    Ron: Oh, OK. So that'd be something kind of running in the back of the restaurant that people would update with.
    Matt: Right. So in the back of the restaurant, you would go and look at this kiosk application and say, "Ah, there's three more orders, what are they?"
    Ron: OK. Well, what if the restaurant already had a fancy system in place for tracking orders and status and things like that, maybe it could have some integration with services and that sort of thing?
    Matt: Right. So all the WPF application is doing is calling out to a service and saying, "Hey, I'm Restaurant Blah. Give me all of my orders."
    Ron: All right, so you could integrate it at a service level.
    Matt: Certainly. You can integrate it at a service level, you could get much more sophisticated on the workflow side of things...
    Ron: Yeah.
    Matt: ...And actually send out notifications, so that you didn't have a polling interface at the restaurant.
    Ron: Right, right.
    Matt: Those are all ideas we could do. The idea of sending out notifications gets a bit problematic. The idea of addressing a kiosk might be a little more tricky because it might be a small restaurant, they're behind a firewall -- so sending notifications becomes a little more tricky.
    Ron: Oh, OK. All right, so I wonder if we could just very quickly take a look at your amazing architecture diagram here. Let me...
    Matt: Certainly.
    Ron: Let's do that.
    Matt: Right. So here we've got our architecture diagram. As you can see we used a very sophisticated tool -- one note -- in order to build this. And this started out, really, as a migration from a whiteboard drawing that we had done. But we actually found that this was good to keep all the developers on the same page. To know, "Hey, which database do I need to talk to?" -- at one point in development we had a few more databases -- "Which services do I need to talk to?" Just to give a developer, "Hey, there's a problem here, where do I need to go in and find it?"

    But what we've got going on here -- these are our different UIs. These are the different experiences that an end user is going to have. We have our web application, this is written in ASP.NET Ajax; we have our WPF application, this is that kiosk application that we were talking about; we have a Vista sidebar gadget -- again, going with the idea of throwing in all the tools that we had in our arsenal. We wanted to be able to give the end user, the consumer, a way to know what was going on with his order, without having to go to a website and say, "Check my status."

    So you have a nice little Vista sidebar gadget that sits in your sidebar; it's got Virtual Earth integration, so it goes out and you can see where your driver's at, because he's got a GPS in the car. We also wrote a mobile application that sits on a PocketPC or a smartphone device, and it's going to allow the driver to interact with the system.

    And so these are all cool. These are all the front-ends, but they're kind of useless without some kind of communication. And so this is what is really represented by all of the triangles on here. These are our different services, and we've got a lot of different services. For the Vista sidebar gadget, we're really just returning POX, plain old XML, because the way you program gadgets is primarily through JavaScript. And so we're just returning some XML, and that's what it's using to figure out where on the map it needs to go.

    For our kiosk application, what we're doing, we're using HTTP to poll and find out about orders. So this is where we're saying, "Give me all the orders that are valid for my restaurant." And then when we need to change the order, when we need to update the order status, we're sending a one-way message over MSMQ, to give us that durable, one-way messaging.

    The same thing is happening with the website. All of the search is provided through web services. We're exposing those over an HTTP interface; just kind of normal, plain WCF services that we're returning here. So when I go and search for hot dogs and French fries, I get hot dogs and French fries back via that service call.

    We're doing authentication here via CardSpace, and so we're allowing a user to provide their card, register their card, and use that to authenticate. One of the scenarios we're looking at in the future is having a managed card that's a discount card. So, think of like the loyalty card you have at your supermarket. An STS would issue that managed card; you would then present that to DinnerNow in order to claim your discount, or get your loyalty points or whatever.

    And then, also, because this is a high throughput web application, we don't want it to waste any time processing orders, because, in a real world, these are all going to be on different machines, we're using MSMQ again, that when an order gets placed here, we're just dropping that on a queue in order to be processed, potentially on a different machine. In this case, of course, as a demo, it's all on one machine.

    So what's happening, once that order comes in, we've got workflows. And we really have two different workflows in this scenario. We have a workflow whose job it is to split the order coming in. So we're going to come in, we're going to get this customer order that's going to say, "I want appetizer, entre, and dessert, all from three different restaurants." We need to take that and we need to split that into three different orders, and then we send that off into a restaurant order process that is a state machine.

    The difference between a sequential and a state machine is that a sequential workflow is really good for deterministic processes; for moving from A to B, making some decision on C or D, and then doing E. But when people are involved, a state machine may map much better to that problem, because the path through that process may be a lot more non-deterministic. So if you think about cooking, we may overcook the meat, and we may have to do that again.

    Well, in a sequential workflow, that's a bit hard to do, because we have to kind of loop back up, and at each stage, we have to loop back up. Whereas with a state machine, we can just define that it's in the cooking state, it's in the ready to be picked up state...
    Ron: Or it went to the burned state. [laughs]
    Matt: Or it went to the burned state. Or it could go from the ready to be picked up state back to the cooking state, because the chef looked at it and said, "No, this isn't good enough."

    And so we have a state machine that manages each of those individual restaurant orders. And this is really what this kiosk app is interacting with. So when I say, "Here, I need to update the order status from cooking for ready to pick up, " we're sending a message here that's causing a state transition.

    That's also what the delivery app is doing. When the driver says, "Yes, this is delivered, " we're going to send a message to that state machine to get it to move to the completed state. And we'll go into what's going on with this workflow here, but I want to kind of show the rest of what's going on in this scenario.

    We have two different databases. We have our DinnerNow database. This maintains all of the information about DinnerNow -- restaurants, customers, items, food. All of that good stuff gets stored there. And then we have a workflow database, which is where we're keeping our persistence and tracking store for the workflows.

    And that was just a design decision, to keep this database pretty clean and keep all of these tables over here, so that when people were working on this--because this database was subject to some churn when we were building it--we didn't want them going in and accidentally dropping a persistence table, because that would be bad.

    So, the other thing that's kind of interesting about this scenario is that we really wanted to also highlight the management side of things, so kind of an aspect of development that is neglected sometimes. We built a set of PowerShell commandlets that either against the databases or against the WMI providers to find out information like "How many times have we called this service?" Our queries against SQL will say, "How many orders are in process," or "What workflow is at what state?"

    And we service that via PowerShell, and so that's a really nice way to administer the system and find out what's going on, especially if you like command lines. And then, on top of that, we built an MMC plug-in that gives a lot of the same information that we can see in PowerShell, but presents it graphically.

    So one of the things that we do here is re-host the workflow designer. So that, for a given order, you can see, "Ah, it is in this state, and it's been there for 20 minutes." And so this would be a tool that a system administrator could use to monitor the health of the application, and also, we could take action based on this.
    Ron: So, Matt, this is not a trivial little sample app. I should say, it looks fairly substantial, and realistic, that you built all this stuff into. So you're the workflow guy, kind of the workflow specialist. And for each of these videos, we're going to drill into what makes the workflow or whatever cool about this.

    You talked a little bit about the two kinds of workflows, sequential and stateful, that you've used in this. So where do we begin on the workflow? What's interesting about it?
    Matt: There are a couple of things that are interesting about the workflow in this scenario. One is that we're integrating with WCF. And so what we're doing is that we're allowing a WCF call to instantiate a workflow. So if we think about when we receive the order from the website, we're calling a WCF method, and that is instantiating the workflow. So that's starting up this sequential workflow, whose job it is to go and split the orders.

    Then we're also using WCF to interact with that state machine workflow. So if you think about a state machine, a state machine is a pretty simple things. It has a number of states. In each of the states, you say you're waiting for any number of events. What we've done is we've tied the WCF calls to raise that event so that we can interact with the state machine.
    Ron: And this is a good point, because some people might be like, "Hey, well, WF, WCF, don't they work together?" And the answer in V1 is... Eh, kind of. [laughs]
    Matt: The answer in V1 is that you've got to roll your own code.
    Ron: OK, yeah.
    Matt: And some of the common challenges are managing instantiation...
    Ron: Yeah.
    Matt: Managing correlation of messages that come back in; how do you get those to a workflow that's already running? If you've just got a workflow that you want to fire and forget, it's a pretty simple thing to do.
    Ron: Right.
    Matt: You just kind of manage that instantiation inside of the one service call.
    Ron: OK.
    Matt: Where it gets a little more tricky is how you route the messages back to the workflow themselves.
    Ron: All right, but you've got a good example of this in your working code?
    Matt: Right. So we've got an example of how to do this. It's also going to be one of the features that's coming in the Orcas release, is moving WF and WCF much closer together. So we will, in the future, be porting Diner now to Orcas to show off the lines of code that you save by using Orcas.
    Ron: Oh, very, very nice. So you're going to show us some code in the designer, and that sort of thing?
    Matt: Sure.
    Ron: Let's take a look at that then. All right, what are we seeing here?
    Matt: This is the sequential workflow. But before we get into that, I want to go through the service itself. This is a standard WCF service. We have an interface around here somewhere. Here is the "place order" method. What we're doing here, we're creating a workflow instance ID.

    One of the things that we can do in workflow when we create the workflow is give it a workflow ID, as opposed to allow it to be assigned automatically. This is important, because we'll take this and store this. This is what allows us to keep track of... when I talked about that problem of correlation, this is one of the things that we're going to need to do to solve that. So we create that, and then just like a normal workflow, we create a workflow instance. We pass it in the type of diner now.

    That's going to start it up, and then it's going to return, so the WCF method will return. Let's look at what this workflow actually does. The first thing it's going to do is save the order off. One of the parameters in the workflow is the actual incoming order here. What we're passing in, this is actually of type CustomerOrder, so this is what's coming from the website.
    Ron: OK.
    Matt: We're going to pass that in. We're going to save that, so we've written a custom activity that saves that order off. Then we have another custom activity that splits the order. If we look at what the properties are here, we have this incoming order, and we've bound that to the parameter that's coming in.

    If we look at how this is bound, what we see we're doing, we've created a member on the actual workflow class -- IncomingOrder. That is the parameter we're passing in, so we've mapped to that. Then we have split orders. The difference is, if we were to look at the type, is that split orders is actually an array of restaurant orders, so you can see that down here.

    So what happens between input and output is actually going through the order, and splitting it up. If there are three different restaurants involved in the order, we're going to split that into three separate restaurant orders. Then we're using this activity that's called a replicator activity. What a replicator activity allows you to do is operate on N number of objects, where N is not something you know at design time.

    If you think of a while loop, you say, "I'm going to do this while i < 5". You can also do it while i < N, and get some level of not knowing how many times you're going to do this. The nice thing about the replicator is you can actually execute those child activities in parallel. So with a normal parallel activity and workflow, I have a fixed number of branches at design time.

    So I have three. I'm going to go get approvals from three different people. The parallel activity is kind of fixed that way. But with a replicator, what you can do is actually do N number of tasks in parallel. And it's called a replicator because you do the same task N times, just with a different set of data.

    So what we're doing here, inside this replicator, we went ahead and we configured it so that its execution type is going to be parallel. And then there's this initial child data, and this is the set of objects that it operates on. So what we're passing in here, this is the array of customer orders. This is what we're going to replicate and do N number of times, depending on how many orders there are.

    And then what are we going to do N times? Well, what we're going to do, we're going to actually invoke a workflow. So we're going to create a child workflow, and the workflow that we're invoking, as we'll see later, is this "process restaurant order." So this is the state machine. And what we're doing is we're firing those off.

    So those are going to then operate, in parallel, on a different thread than this workflow. So we're going to spin up three different child workflows...
    Ron: OK. So the burger state machine workflow, the cheesecake one spins up, and my French fries, or whatever else I got, so that when the restaurants go to do status, they can all do it independently. OK, got it.
    Matt: So we've spun up, in this case, three different child workflows.
    Ron: Yeah.
    Matt: Now, why didn't we just use a while? Well, a while is going to block here, because we're going to go through, we're going to invoke that, and then we're going to say, "Hey, I'm waiting for that to be done."
    Ron: Ah, yes.
    Matt: So that means I could get my burger. I'd have to wait for the burger to go get done. Then I do the fries.
    Ron: Oh, right. That's not going to work.
    Matt: That's not good, because I want my food quicker than that.
    Ron: And I want it hot. [laughs]
    Matt: Right.
    Ron: [laughing] OK.
    Matt: So what we're doing here is we're doing these in parallel. So we're spinning each one of these up, and then, later on, what we see is we have this "handle external event."
    Ron: OK.
    Matt: So in each of the branches, we're waiting to receive an event. And the event we're waiting to receive is that the child workflow has completed.
    Ron: Oh, OK.
    Matt: So let's look at this a little bit.
    Ron: Now, this is important, because we said there's three things, they're all running in parallel, and each of the three branches is going to start this workflow, do a few things, and then it's going to wait until the state machine workflow says, "I'm done."
    Matt: Right.
    Ron: OK.
    Matt: So in this case, it's going to be that the individual restaurant order has been delivered. That's going to mark that as done.
    Ron: Oh, OK. OK. Got you.
    Matt: And so, let's see what we're doing here... I'm going to look in order service. And what I'm doing, I'm binding to the "workflow completed" event, because what I want to do is catch when that workflow is completed. And so what we do is we look at, in that event, we say, "Hey, was the workflow type 'process order'?" Because I don't care if the sequential workflow finishes, I only care if the state machine workflow finishes.
    Ron: Oh, OK.
    Matt: And if it is, what I do is I raise a completed event. And let's go and look at this real quick. So what "raise completed" does, it just creates a new set of sub-"workflow completed" event arguments. And this contains a couple of things, including the parent ID and the child ID.
    Ron: OK.
    Matt: So the idea of the work-flow that kicked off. And then we just go ahead and raise that and pass that in. But what is interesting about this, because when we think about this, we have got three branches now.
    Ron: Yes.
    Matt: We have a bit of a problem, because we were waiting on three of the same events.
    Ron: All right.
    Matt: I am not waiting on three different types of events. So how do I make sure that if the dessert is the one that finishes, that the event is routed to the branch of that replicator that was the dessert.
    Ron: OK.
    Matt: Because, normally what would happen, we would be just listening for an event. But in three different places, I am listening for that same event. So how do we route to the right instance of that 'handle external event activity.'
    Ron: You have got three threads that are basically listening for this event.
    Matt: Well, no. I have got three workflows out executing.
    Ron: Oh, OK.
    Matt: I have got a parent workflow that is waiting for anyone of those three to complete.
    Ron: Oh, yes.
    Matt: It is waiting to receive three of the same messages.
    Ron: Oh, OK, got you.
    Matt: And so how do I route back to the right instance of that replicator, and the way we do that is through correlation. So we look at this, with this idea of correlation initializers and establishing a correlation alias, and what this lets me do is get finer grained control. I am going to go to the white board real quick.
    Ron: OK.
    Matt: Make sure I don't kill myself on these wires here. Let's draw this up, because we have kind of been talking conceptually. [drawing on board] Let's just think about the parallel case. And so in all of these I am waiting for the same event. So we will just call this [phone rings] event.

    So I am waiting for the same event in each one of these, and normally what happens when I have an 'handle external event, ' what we were doing is, we are creating a queue, and the queue is named the event that we were waiting for.
    Ron: OK.
    Matt: Inside the workflow runtime I know with workflow ID, blah. I have this queue that I am waiting for this event. That is not good enough in this case, because I need to be able to route that event to either this one or this one or this one, but not all of them.
    Ron: Yes.
    Matt: And so by using correlation what we can do is, we'll actually create three different queues, one for each of these.
    Ron: Ah, OK.
    Matt: So but what they will be named, will be, will have added to it, an additional ID for this activity. So that is how we know. So then, we have got another ID here. So now what I am doing in the code is, I am raising an event that has this activity ID, because I did this thing called the correlation initializers. I said I want to, basically this 'handle external event' is going to wait until the events are received with the right piece of data in there.
    Ron: OK.
    Matt: And in this case I am using the child work-flow IDs, that piece of data.
    Ron: Yes, yes.
    Matt: So what I can do is append each one of these queues to the piece of data that we were waiting for. In this case it is a grid that is the child work-flow ID.
    Ron: But you could choose anything you want?
    Matt: It could be an order number, it could be a customer name, it could be anything. But now what I have done is, I have created three different queues. So when I raised that event that has this...
    Matt: It can be an order number, it can be a customer name...
    Ron: Oh, OK.
    Matt: ...It can be anything, but now what I've done is I've created three different cues. So when I raise that event that has this order ID, the work time run flow is going to look at that and use that to figure out which one of these three it needs to go to.
    Ron: Aha. OK.
    Matt: So that's kind of a nice pattern to handle parallel work and where you want to wait for that work to actually get done before you're ready to move on with your processing because if we go back to this workflow, what that allows us to do is fire off three different child workflows when all of them are done, then we can let this workflow complete. Or then we can do a final piece of work like send out an email saying, "Thanks for your order, it's now been delivered, " or really anything that we wanted to do.
    Ron: So you have, right after the sub workflow completes, you have "Log Two, Console Activity Two"?
    Matt: Yes.
    Ron: But that's still in the replicator part?
    Matt: Right.
    Ron: So what's going to happen is, as each one completes, you know, "Dessert Completed," "The Burger Completed," "The Fries Completed." You'll see each one of those happening. When the whole replicator completes, then you get "Log Two, Console Activity One" which is like everything is done, the whole order is complete.
    Matt: Yes.
    Ron: Oh, OK.
    Matt: So that's kind of a nice way to handle working in parallel where you've got some chunk of work that you want to do. But you want to have that messaging pattern of, send a message out to start and receive a message back when you're done. In this case, the way we're sending the message is we're calling "Invoke Workflow" and it's starting it up. The message that we're receiving back in is, "The workflow completed."
    Ron: Yeah OK.
    Matt: Which we're then using correlation to route to the specific instance.
    Ron: Ah, very nice. OK.
    Matt: So now let's go look at the actual state machine workflow.
    Ron: Yeah.
    Matt: What we've got here is really just the normal state machine. We have a number of states. In each state we can have an initialize and a finalize. In this case, what the initialize is doing it's writing out some debug information, saying, "Hey we're there," and then it's updating the order status. When it moves into the cooking state, the first thing it's going to do is update in the database, "Hey this order is now cooking."
    Ron: OK.
    Matt: Then once we complete that initialization activity, we sit and we wait. We wait for different types of events.
    Ron: OK.
    Matt: So in this case, I'm saying I want to wait for the order to be cooked. So I'm waiting for the "Cooking Completed" event. When that happens, the next thing I'm going to do is set the state to "Order Ready for Pickup." That's all I have to do. I could do some other things here if I wanted to. I could check the temperature; I could send a reminder email, or a reminder notification. Very simply put, a state machine's job is to sit around and wait for some type of event. When that event happens, do a little bit of work and then transition to another state.
    Ron: Right.
    Matt: And that's what we're doing here. So we're waiting for either the "Order Cooked" event or an "Order Cancelled While Cooking" event which would transition us to the canceled state.
    Ron: Aha. OK.
    Matt: This is how we move through the state machine. What we could do here is get a much more sophisticated behavior of "Driver Called with a Delay" in this "Out for Delivery" state that would bring it back to cooking because we need to cook up a second burger and send it out with a different driver. What a state machine really lets you do is model those processes that people are involved in because we usually tend to mess them up, or at least make them flow in a non-linear fashion.
    Ron: It's all of the complications of the real world, you know. The driver got pulled over by the police and now we need to cook another burger. [laughs]
    Matt: Exactly.
    Ron: I like that, OK.
    Matt: And so those are the things that we're doing with the workflow here. I don't think there's anything else to show here...

    One of the things that we did do, we did create a number of custom activities to map to the different pieces of logic that we wanted to use within the application. So things like, updating the order status, saving the order to the database, calling out to other services. We have a service for notifying the driver, and so that's going to be what allows the driver to get a message on his mobile device saying -- "Hey, you need to go pick this thing up."

    We really tried to take all of those different pieces of functionality, those common building blocks, and wrap those in activities, so that wherever we wanted to use them in a workflow, we could.
    Ron: You know, what I love about this, is that you took something that looks very, very simple when you look at it from a workflow point of view, but if you think about, what would it have taken to create this without workflow? And you think about all of the various bits of code that people would have built, and the solution becomes monumentally more complex. And I find it takes a little bit of a shift of thinking to get people into thinking about using a workflow to solve this, but it fits very nicely.
    Matt: Right, and there are a couple of different things that workflow buys us here. And first and foremost is really the support for a long-running process. So, as I built this I didn't really need to worry about where am I going to store all this information, how am I going to update when I move from state to state. I'm just going to wire up my events to the state machine, allow that to transition, and then rely on the persistent service to store that all off on a database for me.

    If we think about, where we get into more complicated scenarios where I'd want to have a timeout, or an alert if the order had gone undelivered for more than twenty minutes. And we want to handle that logic in a normal imperative code solution, that starts to get tricky. Because now we have to start, do we have a job that polls SQL every five minutes, to see if there's something in this alert state? You know, really what workflow buys us here is the ability to not think about that.

    The other thing that we get is this idea of being able to visualize the process. And so if we talk about that MMC console that we built. So this is inside MMC.
    Ron: Oh yeah, I am going to take a look at this one, because this is fantastic. I can just imagine, if you had a business like this, you're going to have the call center, right? People calling up like, where is my burger? And you've got to deal with that.
    Matt: Right, and so what we did here, this is all built on top of the tracking store. We're saying which workflows are running, and in this case they're not the most friendly things. We're just displaying the grids.
    Ron: Yeah, yeah. What's your order number? Well it's 74F04TV... [laughs]
    Matt: We know, it's not going to be duplicated anywhere, that's the nice thing. But we could certainly display something more friendly here. But what we can see is, OK, this is the state that the order's in right now. And you'll see that this state is highlighted in yellow. And if we had this hooked up and we had a load running on the system, what you would actually see is, you could actually watch this transition in real time. And see this move from state A to state B as it happens.

    So this gives you a really nice way of getting some insight into where is this thing at, in the process. And again, this is all just pulling off of the tracking database. So what did I do to enable that? I added a line to my config, saying I want a tracking service and I just want to use the default profile; which means all of the events of activities and workflows -- I am going to track those all out to the database.
    Ron: OK. Some of the benefit you get here comes from really just thinking about the principles of a workflow, whether or not you use the workflow engine -- you have used this one or some other one -- there is some substantial benefit architecturally. The thinking about these jobs as workflow jobs that could be run and so forth. But then, putting -- why would you not take advantage of this -- when certainly it is included in.NET 3.0. It is free for anybody who wants to take it and use it. Great resource. So it sounds like just a fantastic solution.
    Matt: The other thing that occurred to me -- although in this scenario time is of the essence, "I have ordered my burger, I want it now" -- but you could easily imagine, because this architecture would support this, maybe they say, "Hey, we kind of want to get into catering too." So you throw on a big party next Saturday night, five days from now, but I want to place my order now. This system could handle it with the exact same architecture in place.

    Right, and that's the kind of the other thing that Windows Workflow Foundation buys you, is the ability to have flexibility in your process. So how would we do that? Well, we would just go into that process order, that sequential workflow, and maybe say, "OK, when does the customer want it? OK. I will delay it for five days, and then I will wake up Saturday morning and send that off."

    Again, how have we managed that in the past? We write a row in SQL, we have some kind of job, maybe we use Windows Task Scheduler, maybe we use something in SQL to run a job every five minutes; and all of a sudden what has become a really nice process that we drew at the beginning, is now in two different places.

    We have got this little bit that manages notifications and what happens? That is only going to get more complicated. And so now you have got developers who are focused on, "I am going to build out this really nice framework of notifications and there will be a configurable XML file that says that I am waiting on this or this and these are the priorities for my delays."

    And that is not delivering value. It is certainly solving a problem and doing it creatively and doing fun coding, but the real value we deliver is in solving business problems. And with something like this I focus on the business problem. I focus on how does the real world process map to the process I want in code, and push a lot of those other things, a lot of that plumbing off to the side.

    We had the same thing with WCF. When I wrote this, I really didn't care about what my transport was. But then I talked to the guy who was doing the website and he said, "Well, it is going to be a high throughput website. We want to use MSMQ." In the past, how do I do that? Oh no, I've got to change everything to use System.messaging.

    Ron: Right, right.
    Matt: With WCF all that plumbing is kind of abstracted away, so that when I am solving the problem, I focus on solving the problem, not the limitations.
    Ron: Nice, see I told you. It is about solving the business problem, and thank you, Matt. That was so well articulated. I could not have said it better myself. So thanks again for joining us today on ARCast.
    Matt: Good. Thank you.
    Ron: I hope you enjoyed that look at the DinnerNow application and Matt Winkler. I think I'm really, finally, getting the way this workflow comes together. It's interesting to look at an architecture like this. But to really understand it, you need to see it used in context. And all this talk about dinner -- well, that's just made me hungry. So it's time to eat.
    Announcer: ARCast TV is a production of the Microsoft Architecture Strategy Team,
  • User profile image


Add Your 2 Cents