Steve Michelotti recently found a very subtle bug in MvcContrib.FluentHtml. It provides us with a rather interesting case of applying the Principle Of Least Astonishment (a.k.a. Rule Of Least Surprise).
It turns out that FluentHtml’s select helper lets the user express his intent vaguely. Consider whether this test should pass:
[Test] public void when_determining_selected_values_select_should_ignore_selected_method_if_any_options_are_marked_selected() { var list = new List<SelectListItem> { new SelectListItem { Text = "Acura", Value = "1", Selected = true }, new SelectListItem { Text = "BMW", Value = "2" }, }; var select = new Select("foo.Bar").Selected(2).Options(list); var optionNodes select.ToString().ShouldHaveHtmlNode("foo_Bar").ShouldHaveChildNodesCount(2); optionNodes[0].ShouldBeSelectedOption(1, "Acura"); optionNodes[1].ShouldBeUnSelectedOption(2, "BMW"); }
See what we have done here? We have allowed the user to express which options should be selected in two, possibly contradictory ways. In the call to Options, the user has specified that Acura should be selected. In the call to Selected, she has specified that Honda should be selected. How should we interpret what she really wants?
The first path to consider is to change the API to remove the chance for vaugeness. In most cases this is highly preferable. In this case, however, the cat is already out of the bag so to speak. That is, changing the API in this way would be a big breaking change. Furthermore, it is deliberate and I believe very useful that the API offers a lot of ways to specify select options.
That leaves us to invoke the Rule Of Least Surprise. When a user specifies vague intent, in the manner that we have described, I can see five reasonable outcomes:
- Selected items are only those expressed via Selected
- Selected items are only those expressed via Options
- Selected items are a union of those expressed via Selected and Options
- Selected items are only those expressed via Options or Selected, whichever is called last
- Selected items are only those expressed via Options unless none, then those expressed via Selected
I will reject #4 out of hand. FluentHtml helpers are essentially builders. And with builders, order should never be important. #1 and #2 are the next to go. I cannot think of a better argument for either, and so the choice would be arbitrary. It’s a rather close call between #3 and #5, but I will choose #5. Here is the thinking. If the user has specified selected items within the options themselves, then calling Selected is clearly a mistake on his part and he should expect it to be ignored. On the other hand, if he did not specify selected items within the options list, then he could reasonably expect the call to Selected to be honored.
Would you make a different choice?

