Phil and Scott (and the other Scott) announced the open source Nerddinner.com 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:
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 Nerddinner.com are full of strings:
<p> <label for="Title">Dinner Title:</label> <%= Html.TextBox("Title", Model.Dinner.Title) %> <%= Html.ValidationMessage("Title", "*") %> </p>
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?
Comments
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.
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.
Jafar Husain has a nice pair of articles about using lambda expressions to do this in C#3.0:
themechanicalbride.blogspot.com/...
themechanicalbride.blogspot.com/...
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.
Ex:
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: I only say LINQ because the Expression<T> class lives in System.Linq.Expressions.
The string alternative is handy on Views that haven't been strongly typed, but this should be frowned upon in itself.
<%= Html.TextBox(StringKeys.Title, Model.Dinner.Title) %>
<%= Html.ValidationMessage(StringKeys.Title, "*") %>
"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.
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.
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
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?
BARF.