and Two Views of ASP.NET MVC Views

Wednesday, March 11, 2009

Phil and Scott  (and the other Scott) announced the open source project and their free ASP.NET MVC eBook today. Actually, the free eBook is a single chapter of 185 pages, which is at least 50 pages longer than any chapter in Tolstoy’s War and Peace (and over half the size of my entire workflow book). Amazing.

In any case, I was looking through the code this evening and a thought struck me. You can divide the nascent world of ASP.NET MVC developers into two camps:

Taxonomy of String People

The people who use strings don’t love to use strings – they just use them to get work done. But the people who hate strings really hate strings. They’d rather be caught using goto label than ever type a string literal, and they exterminate string literals from as many places as possible.

The views in are full of strings:

    <label for="Title">Dinner Title:</label>
    <%= Html.TextBox("Title", Model.Dinner.Title) %>
    <%= Html.ValidationMessage("Title", "*") %>

The “Title” string is significant – it has to match up with the name of a controller parameter or the name of a model property when data movies in and out of the controller. A typo in the view, or in a model, can create bugs. Compare the “stringy” views to the views in another open source MVC application - CodeCampServer:

<%=Html.Input(a => a.AttendeeID)%>
<%=Html.Input(a => a.ConferenceID)%>

This is another example of using LINQ expressions to implement “reflection without strings”. A typo here yields a compiler error. The technique is quite powerful and implementations are popping up everywhere, including inside the MVCContrib project.

Errors can be caught with either approach, but you can catch errors earlier and perform safer refactorings if you take Nancy Regan’s advice and Just Say No (to magic strings).

I’m curious – which approach do YOU prefer?

Stan Wednesday, March 11, 2009
What's the performance impact of using those linq expressions? Don't they have to compile each one? Seems like that could be a hefty price to pay.
Scott Hanselman Wednesday, March 11, 2009
Ya, I went back and forth on this. In this case, the "Title" is really the name of the Field, so it could be "Poo," but as you point out it's coincedentally (and conventionally) the name of the field. I would want to really perf test the strongly typed stuff, but I think it's good we have the choice.

My personal opinion is this. Compilation is just the FIRST Unit Test. I feel *less bad* about using Strings when I have great Unit Tests. They will catch my goofs. If they don't, I need more tests.
Haacked Wednesday, March 11, 2009
We also have expression based helpers in the MvcFutures project.

I have to admit, I like strings. After all, what is it exactly that we're sending down the wire. Strings!

Then again, I also like the expression-based helpers. They give you nice Intellisense and refactoring support.

But ultimately, we have to face the fact that we need to test the UI and that strong typing is not a panacea.

For example, even with expression based helpers. What happens when I include a bit of jQuery that modifies an element by name or ID. A refactoring is not going to catch that.
Gunnar Wednesday, March 11, 2009
I prefer stringless approach.
Samuel Jack Wednesday, March 11, 2009
I do my best to avoid using strings, especially when calling raising Property Changed events.

Jafar Husain has a nice pair of articles about using lambda expressions to do this in C#3.0:

ILog Wednesday, March 11, 2009
I loved objects before starting web programming. Now I love strings, but hate when the rules of their usagage are non-humanic :)
Joshua Flanagan Wednesday, March 11, 2009
I would guess that the divide closely matches up with "people that live by ReSharper, and those that dont".

We go the static reflection route for all strings that have a "meaningful" value. A string is meaningful in this context if its value has to exactly match up with a property/parameter name in compiled code.
To answer Phil's question - our static reflection helpers do not auto-generate element IDs to be used with jQuery. If we need to target an element for jQuery, we will tack on an ID using a regular string - because that string is not meaningful to the compiled code, it only matters to the javascript.
TextBoxFor(a => a.AttendeeName).ElementID("attendeeNameInput")

In this case, the name attribute of the input is generated, because it must exactly match up with the AttendeeName property on the model. But the ID attribute is just a string that has to match with string used in the javascript.
alberto Wednesday, March 11, 2009
+1 on strongly typed. Oh, and you meant lambdas, not LINQ. ;)
scott Wednesday, March 11, 2009
@Stan: I don't know the performance impact. Would be interesting to measure, as it does require quite a bit of code to inspect the expressions (and yes they do get .Compiled).

@alberto: I only say LINQ because the Expression<T> class lives in System.Linq.Expressions.
Hernan Garcia Wednesday, March 11, 2009
I don't mind using strings for fields id's or any other view element but I try to avoid using magic strings that have to be translated into code like the action of a controller if I can. On performance issues. In this particular scenario I will heavily cache the views anyway, so I won't be worry about it. In other context may be an issue, but as with everything it needs to be measured. And yes you still need to test everything. I guess the string debate has more to do with having proper support for refactoring tools than anything else in my case. I'm thinking more and more than views should use some dynamic language anyway but that is another issue.
Andrew Gunn Wednesday, March 11, 2009
I prefer using the LINQ expression approach - it makes everything more robust. You can even do the same for form/anchor tags and point them to specific controller actions.

The string alternative is handy on Views that haven't been strongly typed, but this should be frowned upon in itself.
george Wednesday, March 11, 2009
I prefer strings I guess, but to avoid typo's I always put the strings as constants/variables in a centralized "storage", e.g. a set of common-classes. So your string-sample would look something like:

<%= Html.TextBox(StringKeys.Title, Model.Dinner.Title) %>
<%= Html.ValidationMessage(StringKeys.Title, "*") %>
Kevin Dente Wednesday, March 11, 2009
"I feel *less bad* about using Strings when I
have great Unit Tests"

Really? So you have unit tests for your views? I don't see any in the source.

Eric Hexter Wednesday, March 11, 2009
I fall in the strongly typed camp.... strings are bad and I am really bad at typing the same string multiple times. I need the refactoring support supplied by strongly typing my view helpers.

Bahador Wednesday, March 11, 2009
I really hate strings ;)

On the other hand, if there is enough unit tests in the framework *and* you can discipline your team into writing them when adding new features, the strings are acceptable.
Jeffrery Palermo Thursday, March 12, 2009
Hehe. You know where I fall. Eric Hexter and I did the Html.Input() CodeCampServer views. Works out nicely and drives ModelState validation as well.

Once Dynamic Data comes out, we'll be able to delete a lot of code driving that.

The expressions also help to drive WatiN tests for full system testing. Otherwise those tests are brittle
Bryan Watts Thursday, March 12, 2009
I want language support for static reflection, to which all this is an approximation.
Blargo Thursday, March 12, 2009
<%=Html.Input(a => a.AttendeeID)%>

In my opinion that is pretty obscure. What does that generate? A text input with the numeric attendee ID? Why would you ever let a user directly edit that? What does the 'a' variable stand for? Are there built-in error validation messages? Does the Input method generate a label also? If so, where does it get it's caption from?

While this might win points for fewest characters typed, it's not readable or understandable at all. Look, you may think you're clever and obtuse and what not, but what about the guy who has to come through later and read your lambada-infused (abused is more like it) "shortcut" code?


Comments are now closed.
by K. Scott Allen K.Scott Allen
My Pluralsight Courses
The Podcast!