Anatomy of an ASP.NET site for amusement park fanboys
This is a post I've meant to write for a very long time. Since 1998, my part-time job of sorts has been to maintain a number of community sites. One of those, started ten years ago, was Guide to The Point. "The Point" in this case is Cedar Point, an amusement park an hour west of Cleveland and about two hours from Detroit. It's home to more roller coasters than any other place on earth, and for people how grow up in the region, it's a summer ritual. In 2004, I joined forced with a friend doing another site, and we called it PointBuzz, inspired in name by my woefully neglected general coaster enthusiast site CoasterBuzz. These sites have become a business to a certain degree, since the ad revenue isn't exactly small coin. And if you can make money doing something you enjoy, why not?
Late last year we rebuilt the site. The old version was still running on v1.1 of .NET, and frankly a lot of the code was vintage 2001 stuff built on the beta of .NET. Our goals for rebuilding it were to concentrate on what we were good at: news, forums and photos. Our previous attempt ended up being a huge array of content that, frankly, was just as easily found on the official Cedar Point site and we didn't really have time to maintain it. A secondary goal was to boost performance (the site peaks around a million page views a month, sometimes as much as 100k a day) and get the code base into something maintainable. Let's face it, in 2001 I barely understood what OOP was, and even in 2004, prior to writing my book and having experience in a giant company, I had a lot to learn. The app as a whole was rather fragile when it came time to change something.
Naturally the first priority for me was rewriting POP Forums. The benefit of experience is that I know how many things I did poorly in the previous version from late 2003. I've tried to eliminate much of that legacy, but there are still things I find in my code, often inconsequential, that should be different, like checking for a string to be empty or null instead of String.IsNullOrEmpty(). I spent literally years trying to make it work with Membership and Profile in a way that I liked, and generally it did, but I abandoned that cause. You had to give stuff up too often when making efficient database calls, and that annoyed me. It's not that there aren't logical architectural solutions, it's that I was spending all kinds of time worrying about it, when I was the first and primary user of the app!
What was important to me was using a little AJAX where it made sense, and using the ASP.NET AJAX framework for any client script I had. The version you can download doesn't have it yet, but the version running on PointBuzz does, and I'm very pleased with the way you can encapsulate it and reuse it. The primary use is to load stuff into the page, like user profile data, dynamically. Most forums who you the user's name, number of posts, astrological sign and other useless shit that doesn't advance discussion, and I've always been annoyed by that. (Heck, you've been able to turn off signatures and profiles in my app, also annoying, since 2003.) So I just load that when a user chooses to view it. I also do first post previews this way, but not as tool tips the way vBulletin does (because I find that annoying too). Finally, I refactored the mess that is my rich text control, dating back to 2000 at least, so that it uses the AJAX framework.
The forum app does a whole lot of caching, but not to an extent that it isn't necessary. In old versions, I found that it wasn't holding on to much because the cache collection got enormous and it was always cycling items out. I also didn't cache on a paged basis, so if you viewed a topic with 1,000 posts, it read and cached the whole thing. That was silly. I've found that nearly all of the performance tweaks have to do with the database and caching, which I guess is certainly no surprise.
Custom controls were also a big part of it, using list controllers to handle UI elements based on the data they created. I had mixed success with this, because the thread page still has a lot of code in it because of all the stuff going on. On the other hand, the forum index page is pretty lean in code-behind. Doing custom templated controls also helps, because you can easily drop in an ad, for example, in between forums, topics or posts.
I prototyped a search engine for the forum way, way back in 2004, and after some tweaking I got something I'm pretty happy with. The SQL is incredibly ugly, but the performance isn't bad. Basically, when a post is updated, it's marked for indexing. A background thread on a timer dissects all of the words, throws out the junk and scores them on frequency and appearance in the title. I think the scoring formula needs some work, but most of the time I get pretty relevant results.
Honestly I could probably talk about the forum as a stream of consciousness forever, so I'll move on to photos. The truth is, we have too many. Walt, my partner on the site, went through a document everything phase, and we have over 6,000 photos to prove it. This is honestly not a totally solved problem. We have categories and albums as units of navigation, and we also have tags. The truth is that people generally go to photos of the roller coasters or to albums we link to from news items. We don't know if that's good enough, and we have thousands of photos untagged.
From a code standpoint, we started testing the photo app months before re-launching with live data. Contrary to the advice a lot of people gave me, I decided to store the photos in the database. My reasoning had mostly to do with ease of backing up. HttpHandlers serve the images and the thumbnails, and frankly I've not encountered any performance issues at all. I also kept permissions for editing the photo collection as abstract as possible. There's a simple HttpModule that does the required plumbing to map forum user data into the photo app. I can just as easily wire it up to anything else.
The news management is nothing special, and as such doesn't exist as its own project. The only interesting thing is that it will replace the first post of a special forum topic with a user control that has the news item in it, so essentially there are two views of it, either in the forum or the regular news page.
That's really the bulk of the site. The forum is used for all the member handling junk and e-mail.
Incidentally, I do hope to have another beta of the forum out soon. In addition to the items I listed on the PF site, I've also rewritten the private messaging.
A question I get a lot is, "Why not just use stuff that's already out there?" Aside from being my own code monkey, all of the stuff out there tries to be too many things to too many people. I don't have excessive database tables to deal with, superfluous UI, rigid style elements, etc. The forum is a lot of code, sure, but overall the rest of this stuff isn't hard to roll on your own. If you've got the skills, why not?