19 December 2009 1:48p Pacific

Preventing mission creep in your Views, or, ignorance is bliss

by Matt Sherman

An important concept in MVC is that Views are meant to be “dumb” – and by that I mean, your View should only care about outputting a user interface, and should know very little about business logic.

You want this for a few reasons. For example, you might create alternate Views for different kinds of output, such as for a mobile device. You shouldn’t have to re-implement any business logic to do that.

And down the road, when your logic inevitably changes, you shouldn’t have to worry about changing it in more than one place. Not only is that tedious and time-consuming, but you open up the risk of having inconsistent behavior. It violates DRY.

How might this happen? Here’s an example.

Let’s say you have a social app which displays user profiles. If a user is looking at their own profile, you might want to offer them a link to edit it. So your View would have something like:

Simple enough, and it might not raise any red flags at the time. Then, however, you realize that administrators should be able to edit profiles as well. Now your View code becomes:

See where this is going? A month later, you realize that “moderators” need the same ability. And if a profile has been suspended, perhaps the user should no longer see that link. And maybe you want to offer a “preview” mode, where the link is hidden. Etc.

Your View is now handling business logic. It becomes unreadable and untestable, and you are blurring the separation of concerns.

The best way to avoid this is, first, have a ViewModel (the above code already assumes that). Second, add properties to that ViewModel that describe only what the View should show, without regard for why. The usage becomes:

Now, your View doesn’t know anything about Users, Roles or anything like that. It’s simply following orders that describe what to output. For Views, ignorance is bliss.

Meanwhile, back in your ViewModel class, the property might be something like:

(Another practical benefit: you can’t set a breakpoint in a View. By encapsulating the logic in the ViewModel, you can debug and write tests to your heart’s content.)

So next time you need to put an if-then in your View, resist the urge to let the View make the decision. No matter how simple, push the logic back into the ViewModel, where it belongs.

Comments

20 December 2009 10:52p Pacific #

Adrian
I was just wondering, shouldn't the ProfileViewModel object be a container and the business logic be manipulated in your Controller?

As it stands the business logic would be spread across both your Controller and the ViewModel.

Adrian Australia |

20 December 2009 11:01p Pacific #

Aaron Jensen
I'd go one step further than Adrian actually, just as the view is dumb, the controller should also be dumb. I'd put the logic in another model (could be a domain model, could be a reporting model, could be a security model) and do the mapping in the controller.

To give you an example as to why this is a good idea, think about the scenario where you have more than one "edit" link on different screens. Your logic is encapsulated in the ViewModel for *one* screen when really it is likely a more general concern.

I typically keep ViewModels nearly as dumb as Views.

Aaron Jensen United States |

20 December 2009 11:13p Pacific #

sirrocco
Actually you CAN set a breakpoint in the view , just have the cursor somewhere in the if statement and hit F9 , it should work.

But your point is still valid Smile

sirrocco Romania |

21 December 2009 5:05a Pacific #

Matt Sherman
That's a new one for me!

Matt Sherman United States |

20 December 2009 11:13p Pacific #

Michael Stum
I'm not even sure if that boolean check should be part of the View Model. I think that the View Model should contain mostly read-only fields and some formatting logic (i.e. "Negative Numbers are displayed with css-class xyz"), but I'd rather but the "EnableLink?" Logic in the controller that creates the ViewModel and passes it into the view.

But generally, I strongly agree. The View should just output whatever is in the viewmodel and not ask any questions about the why.

Michael Stum United States |

21 December 2009 12:09a Pacific #

Jag Reehal
Good post.

I also did a blog post on how to keep logic out of your views which shows how you can refactor if's in your views.

www.arrangeactassert.com/asp-net-mvc-view-best-practices-keep-logic-out-of-your-views

Cheers,

Jag

Jag Reehal United Kingdom |

21 December 2009 3:57a Pacific #

Richard Kimber
In your example, how are you accessing the Request object? I would have thought that the EnableEditLink method would work better as a HtmlHelper, then it's not restricted to a single ViewModel.

Rich

Richard Kimber United Kingdom |

21 December 2009 8:34a Pacific #

Aaron Jensen
I would strongly advise against putting things like this in a Helper. The Helper is a Helper, it should be just as dumb as the view. It's a slippery slope between stuff like this and just accessing your db in the helper. Like I said, these things should be done in the layer that the controller accesses and passes back to the view as a flag.

Aaron Jensen United States |

21 December 2009 8:34a Pacific #

Guy
Your penultimate sentence: <<So next time you need to put an if-then in your View>> I think should read: ...to put in multiple if-then...

Your "good" example still has an "if" statement in it.

Guy United States |

21 December 2009 9:58a Pacific #

Matt Sherman
Fair enough! It can be encapsulated further.

Matt Sherman United States |

21 December 2009 9:01a Pacific #

Aaron Jensen
I forgot to mention one of the most important reasons to not put this in your view model or a helper.

I assume you want to do this same check in the actual "Edit" action, right? I mean, a hidden link can still be clicked if it's emailed to someone. Putting the logic in the view model or an html helper makes it rather awkward to use within the controller itself.

Aaron Jensen United States |

21 December 2009 10:00a Pacific #

Matt Sherman
That's true, it's part of the greater issue that one shouldn't depend on anything client-side in terms of validation. The "Edit" method behind that link needs to have similar logic.

Matt Sherman United States |

4 January 2010 12:47a Pacific #

pingback
Pingback from blog.vittrup-graversen.dk

NoteToMySelf » Another posting about MVVM

blog.vittrup-graversen.dk |

Comments are closed

Tell others

TwitterTweet this page
Digg!Digg this page
TwitterAdd to Google Reader

Experimental! Let me know how it works for you.

Shorten this page's URL

Learn more about the TinyASP URL shortener

ASP.Net jQuery Controls

Implement jQuery effects using familiar ASP.Net server controls. Learn more...

Recent posts

How about jQuery-style “property methods” for C#?

A few more reasons to use Progressive Enhancement

Net neutrality and preserving the dinosaurs

IE8 becomes #1 browser, Chrome up, Firefox plateaus

more...  

About us

ClipperHouse.com is brought to you by Matt Sherman and Fernando Chilvarguer, among others. Contact us here.