January 2010 - Posts
There are times where I've decided that I didn't want to get too deep into a mess of markup in my views, which drives me to writing a simple HtmlHelper extension method. It's a convenient and quick way to introduce slightly more robust display logic into the view.
But first off, if I may get up on my soapbox, I'd like to address the criticism around MVC views in general. I keep reading over and over again how some feel this is a step backward. That's nonsense. What we're doing in a view is not spaghetti code. We're not jumping around from place to place with data access and business rules mixed into the mess, like ASP.old. It just ain't the same thing. It's also not any worse/messy than using WebForms controls. Those are full of templates a bazillion properties to set, and you might still not get the HTML rendered that you'd really like.
In any case, let's say that I'm building a table of images. I can't just do a simple foreach loop because there are new rows to start. I could work in similar logic to what I'm about to show you in the view itself, but it won't be reusable, and will look a little messy (though really not that bad). The logic, then, is that we want to build a table, and split the series every so often to start a new row. Ignoring for a moment the markup components of a table and its rows and cells, we fundamentally only need to repeat the individual cells and end/start rows. This is my first stab at just such a helper:
public static void SeriesSplitter<T>(this System.Web.Mvc.HtmlHelper htmlHelper, IEnumerable<T>
items, int itemsBeforeSplit, Action<T> template, Action seriesSplitter)
{
if (items == null)
return;
var i = 0;
foreach (var item in items)
{
if (i != 0 && i % itemsBeforeSplit == 0)
seriesSplitter();
template(item);
i++;
}
}
As you can see, there isn't much to it. The first parameter extends the HtmlHelper class (the Html property of a ViewPage), the second takes the enumerable series you want to split up, the third says how many items to display before doing the split, and finally we take some Action objects to render. We're still doing a foreach, but if we get to a number of items that's divisible by the parameter you supplied, we pop in the splitter markup as well. In the view, your markup ends up looking something like this:
<table>
<tr>
<% Html.SeriesSplitter(Model.Photos, 4, photo => { %>
<td><img src="<%=ResolveUrl("~/Thumbnail.ashx?id=" + photo.ID)%>"
alt="<%=Html.Encode(photo.Title)%>" /></td>
<%}, () => { %></tr><tr><% }); %>
</tr>
</table>
What's particularly fun is that even the HTML validates right in Visual Studio (I take the small wins. :)). Here you can see we're making a table that does four cells at a time, and if it has to start a new row, it drops in those tr elements. Piece of cake, and still pretty clear to read.
Every once in awhile, I feel like I've changed enough stuff around
the technology that I'm using to take a sort of inventory. Mostly I
just want to be able to refer back to it the next time I feel compelled
to do so.
In terms of hardware, the last year or so has been full of upgrades.
Last March I replaced my laptop with a 17" MacBook Pro, because I
desperately wanted more screen resolution. It's not the size that's
special, it's the resolution. The 15" model I had for three years at
that point was also restricted to 2 gigs of RAM, which was less than
ideal.
On the desktop, I just replaced my three-year-old Mac Pro after
three years. It's not that it was inadequate in any way at all. In
fact, it was still pretty ridiculous in terms of its computing power. I
replaced it because I wanted a bigger screen at a higher
resolution (see the pattern forming here?), and the new 27" iMacs were
the ticket. I was able to sell the old computer and buy the new one for
about $400 difference. So for that amount, I gained a giant and bright,
high resolution LED-lit screen, a computer newer by three years and
only "lost" two CPU cores. On top of that, I still have the old 20"
Dell monitor, and it sites next to it. I've got nearly 6 million pixels
to spread out multiple instance of Visual Studio, Photoshop, browsers,
chat, etc. It's also the best video editing setup I've ever had.
In other more peripheral categories, I have an Iomega 1.5 TB USB
drive where I'm storing video, the Time Machine drive on the router is
still the 1 TB no-name I got from NewEgg, I still use the gross (thank
God it's black) Microsoft ergonomic keyboard that has been out for
years (same one at work, used by nearly everyone). Since I couldn't
wait to spend money in the company store, I also scored an Explorer
Mouse to replace the even more disgusting one I had for five years. It
glows blue when you wake it up. :)
The Web server at The Planet, tucked away somewhere in Dallas, is
the same one I've had now for over six years. It's a P4 2.4 GHz with a
pair of 40 gig hard drives and a gig of RAM. I can't believe it's still
running. As traffic has picked up, it has shown some cracks here and
there, in part because of my own poor coding, and partly because it's
just so ancient. I would like to replace it, but I'm waiting for
CoasterDynamix to pick up and move to their new site. I've been toying
with the idea of going to SoftLayer,
but haven't researched them thoroughly. I haven't had any real issues
with The Planet, except for one recently, but I guess I just feel like
a change.
Software has changed dramatically over the years. Chief among those
changes is that I don't use a physical PC at home. I'm using Parallels
5 to host instances of Windows 7. Dedicating 4 gigs of memory to it has
been awesome, and Parallels has gotten to the point where it even
supports all of the eye candy and what not within Windows. As much as I
hated Vista, 7 is such an enormous improvement. They really spent time
thinking about little usability things, like snapping windows to the
side to do split screens, for example. I started to toy with it going
back as far as to before my interview, but once it came installed on
the new box at work, I became a fan.
I'm still using Visual Studio 2008 at this point, not 2010. Even
though I could get super new builds, I'm not sure I'd want to commit
until ReSharper is updated to support it. I'm just too reliant on
ReSharper now to go without.
For Web development, I'm mostly building on top of ASP.NET MVC, and
will probably upgrade to the new version once it's released. MouseZoom
will be MVC, except of course the forum since I'm certainly not going
to rewrite that. I use NUnit for unit testing and Moq for mocking
(neither of which I'm doing much of on MouseZoom since it's almost
entirely composed of existing components). At work we use xUnit and
Moq. For data, we've been experimenting with NHibernate, but for my
home projects I've been sticking to LINQ to SQL. On the client side,
the big story is still jQuery and its various plug-ins.
For Web browsers, I'm pretty sold on Google Chrome now. After using
Firefox for years, it just seems to have become a dog, and I'm not sure
why. Maybe it's the history that needs to be cleared out? I dunno,
since Chrome is hooked right into Google search, I love that I can
start typing something and pretty much get to where I want to go. I
still use Firefox for Firebug though, as Google's tool isn't quite as
slick. The Mac version still has some quirks (like a bookmark manager
that only half-works), but it'll get there.
Adium is my chat client at home. It just works and is updated
frequently. At work, when I use something at all, I use the Gmail chat
with AIM enabled. Other than checking in with Diana, I don't interact
that often with people while at work.
On the video front, I upgraded to the latest version of Final Cut
Studio last fall, and I dig it. The latest version of Compressor in
particular is impressive, and still super fast even with the dual-core
CPU. The ProRes codec is what I've been using to edit with, transcoding
the H.264 stuff recorded by my camera. Works exceptionally well in
terms of performance and holding on to as many bits as possible.
I've talked plenty about the cameras, so I'll skip that, except to
say that I may endeavor to buy a shoulder rig so I can properly shoot
video before the baby is born.
When I stop and look at what we have available today, I'm really
astounded at how far things have come these days. Cultural implications
aside (i.e., real life social behavior), I'm amazed at what an iPhone
can do. It's a computer, plain and simple, that can do far more than
even a top of the line PC from ten years ago. That's crazy.
Wow, so I keep talking about how I want to write more, particularly now that I'm an "insider" working in Redmond, and yet it has been a month since my last post. But hey, I've been here two months and I just finally spent some time in downtown Seattle for the first time last weekend, so get off my case. :)
Anyway, as is typical in the professional world of software development, I've seen a great deal of debate about whether or not ASP.NET MVC is the second coming or a step backward. There are also peripheral discussions about what Microsoft sees as the future, but given the outright declaration of that guy with the red shirt and the fact that we've got new versions of Webforms and MVC on the way this year, I think it's pretty clear that you use whatever the best tool for the job is. Isn't it funny how that comes up with every religious debate about development tools?
In any case, there are a few themes to the online chatter around MVC that don't give it proper credit. I'm not suggesting that these are stupid people, but rather people who don't have the whole picture for one reason or another. This isn't an exhaustive list I'm sure, but it is noise that may prevent you from investigating the framework further, or inspire you to spread misinformation. There's a positive theme that builds up here, as you'll see.
ASP.NET MVC is too primitive.
Generally I think this statement is made in the context of MVC's lack of server controls. Some people don't like generating markup, particularly those who've enjoyed the drag-and-drop RAD nature of ASP.NET. Let's face it, when we first saw demos of ASP.NET v1 prior to its release, it looked a lot like VB6, solving problems around the stateless nature of HTTP and letting us build stuff quickly. Behold the editable DataGrid, right?
The thing is, I would observe that as time went on, people weren't using these features out in the wild, particularly with big, sprawling, public facing apps. (I'd like to see the DataTable class stricken from the .NET Framework.) Personally, I almost always used Repeater controls, or variations on them I wrote myself, so I'd have more control over how the markup was rendered. And I almost never used in-place editing either, partly because I wasn't building Excel on the Web, and partly because getting your head around the event model was sometimes a pain.
So MVC goes minimal on the UI end of things by rendering simple HTML via the HtmlHelpers, and there's a remarkably simple state bag to hold on to your goodies when your server side validation says something isn't right. That you can simply wire up objects to those helpers without all of the "MyTextBox.Text = myObject.Foo" and the reverse nonsense in event handlers is a huge time saver. Give it a try!
MVC is a step backward to ASP.OLD and spaghetti code.
This is a pretty huge perception problem. I have to admit though, the first time I saw it demo'd, I thought the same thing. I remember the horror of ASP and trying to debug it, and this looked the same. That was because I didn't truly appreciate what Model-View-Controller really meant. After reading through a Ruby On Rails tutorial and reading various articles about the MVC pattern, something clicked in my head and I investigated further. Then I drank the Kool-Aid® at various Mix conferences and I was hooked.
But back to the Italian food, the biggest thing that colors your perception is that there are a lot of really bad examples of what a view should look like. That doesn't mean that it's conceptually broken. Remember that the MVC pattern facilitates the famous separation of concerns, meaning a view should not participate in any logic except perhaps some very basic display logic (most often, looping through some enumerable set of data). If you see some example on the Internets of a view that is calculating salaries, or worse, hitting a database, politely post on that site: "MVC: ur doin it wroung."
It's a lot of work deciding how to split everything up.
Again, I think that's only true if you aren't doing it right. Admittedly, it takes some practice to decide where things go, but after awhile it becomes pretty obvious. If you're dealing with a view, ask yourself if it's doing anything more than displaying stuff. If you're dealing with a controller, ask yourself if it's doing anything more than coordinating what to show the user, and shuttling data between the views and the models. If you're dealing with models (which is a pretty nebulous umbrella term in a lot of texts), ask yourself if it's doing any decision making about what to display or how to display it.
Don't be intimidated over the many related subjects around this concern soup. Dependency injection isn't that hard to get down, and like anything it takes practice to fully grasp why you'd want to soak up its awesomeness (see: Loose coupling).
In fact, the "ah ha" moments really may not come until you've forced yourself to sit down and do an end-to-end science project. While I understand that test driven development is a huge leap that's hard to make, unit testing can make your life easier even if it's slightly after the fact. In order to unit test, you have to figure out how to decouple your bits. That subject is too enormous here to cover, so you'll have to take it on faith until you try it.
Ugh, but it takes so long to do everything "right."
Think about how much time you may spend debugging a code-behind or a custom server control. If we share any experience, it's probably around those hours we'll never get back. Now imagine that you have some tight model that just does what it does, probably interacting with a database (or rather an interface that in production happens to be a database). Imagine you have a controller that takes the request, feeds its data to the model, then sends the model's data to a view to be rendered. Each phase of that can be looked at in total isolation. The points of failure are much easier to narrow down. And because it can be looked at in isolation, each part can also be tested in isolation. The speed at which you can debug this arrangement is far greater than what you do in Webforms.
The bottom line is that MVC is just... different. I happen to be a strong advocate of it because it gets back to the basics of what HTTP truly is, without a huge mess of abstraction on top of it to hide the way it works. That's important these days, because we trust the browser to do more work than ever now. The framework also gets us thinking about (but doesn't force us) how to do things in a way that is testable, more maintainable, and ultimately, more simple.
If you don't think you like MVC, but haven't really looked into it, go check out the learning page on ASP.NET/mvc. Read the tutorials, view the video (that Hanselman guy is a trip).
More Posts