A pattern that’s regularly used with FubuMVC is the one model in, one model out pattern. This is also known as OMIOMO and, my personal favorite, the “thunderdome” pattern. It took me a little while to understand why this pattern is in place and seems to be a gotcha when I come back to FubuMVC after an extended period of time. I’m going to write about why I use this pattern, to document it for both others, and my future self.
From the articles I can find online, the thunderdome pattern was created as a way to increase testability of your actions. By only allowing a single model in, it’s very easy to setup the context of the test. It also removes the need to rely on the HttpContext inside the actions. In FubuMVC, if information is needed from the HttpContext, a property can be added to the input model and it’s the responsibility of model binding to set that property to the corresponding value in the HttpContext. (Model Binding will be the topic of another post.)
Once you decide to use the thunderdome pattern, it’s not a big step to make each of the actions take a unique input model. If each behavior chain has a unique input model, then each behavior chain can be identified by its input type. This is a great way, in my opinion, to take advantage of static typing and make it work for you.
In FubuMVC, this is the most common way to identify behavior chains. Since each behavior chain is associated to a route, it’s the most common way to build URLs, also.
It’s important to note that the thunderdome pattern is not the only way to use FubuMVC. All of the combinations of One/Zero model in One/Zero model out patterns are supported. I can see using a one model in, zero model out for use of services where you only care about the HTTP Response code. (If you want to do this with the thunderdome pattern, you can just return an HttpStatusCode from your action. There’s a built in convention in FubuMVC to handle this return type.)
I don’t use either of the patterns which do not have an input model. If I have an action that doesn’t have any input, then I typically have it accept an empty “marker” input model, anyway. This gives me the ability to uniquely identify it if I ever need to create a link to it, or for any other reason.