Over the past weeks, I've had the opportunity to periodically devote my efforts to the design and maintenance of a home-grown website that I use(d) to track defects, issues, tasks, etc for my projects that I develop, among other things. This project has been a pet project for a long time and was, in fact, one of the very first projects that I ever created using the .NET platform.
Since the time of its inception (back in 2001/2002) I have learned a lot and have wanted to take my new-found intelligence and apply it to my old project. Unfortunately, the application had grown to a point that it wasn't feasible to simply go in with a small hand broom or a dust-vac and straighten things up a bit...it was going to take some heavy lifting.
I therefore put on the gloves and decided to rip the house down and start from a brand new foundation. I've blogged about some of these underpinnings periodically over the past months, but I wanted to share some of the insights and inroads I've made toward the completion of the project.
First of all, the application performed extremely well with a small number of users. Granted the application and its back-end database were on the same server. Being that the application is an ASP.NET application, I want to be able to accommodate many (100+ simultaneously). This application (now called DevTracker) is designed to be used by a team of developers and provide the experience that a user would expect from a Windows application. Well, my original design was not very flexible and would be hindered with more than just a handful of users. I had no clear separation of UI-logic and data access logic. Except for just a few objects, the lines were very blurred.
<RANT>
In fact, I think this is one of the dangers with ASP.NET development. Just like VB made it very easy for non-developers to be productive but at the same time create horrendous, terrible code, ASP.NET makes it very easy to create non-object-oriented websites. Pre-.NET, the push from Microsoft was the Distributed iNternet Application Architecture (DNA). This set of principles encouraged the separation and distinction of the logical layers (UI, Business, and Data) using technologies such as MTS and COM. I, along with many others, subscribed to these principles. With the advent of .NET (particularly ASP.NET) it seemed to be that the lines became more hazy. All of the sudden people were recommending bringing DataReaders up to the UI level and binding to them, of dropping Connections and Commands right on their .aspx pages and querying the database directly. For simple applications this might be fine, but I'd far from recommend it for anything that's gonna have to take a lot of load.
Sure, it used to be done before (even in the DNA days). People would bind to Recordsets and perform database queries right on their pages, but while the rest of the .NET world was moving forward with nice clean OOP, ASP.NET seemed to be left behind; though I hear things will be changing with v2.0. It's not as easy in an ASP.NET application to separate the layers - especially when it's so darned convenient to copout and do it the easy way.
I believe that developers feel that they need the raw performance available with DataReaders directly on their pages. They don't want the perceived overhead of offloading the work to another server (say a COM+ server) when that's the kind of work that an application server does best...probably better than anyone could do on their .aspx pages. What they don't always realize is that the physical distribution of the network can play a HUGE part in an application's performance. If the IIS server is the same box as the SQL server, there's no IO on the NIC, so it might make more sense to bind to a DataReader. However, if the IIS server is separate from the database server which is better? 1) performing a round trip to the database server for each DataReader.Read() call? or 2) having the application server gather all the information from the database right there and return it to the web server in one batch? People often confuse the issues. Few objects doesn't necessarily mean better performance.
Anyway, enough of that.
</RANT>
I wanted, in DevTracker, to design an optimal architecture that would cleanly support the physical separation of the application layers while at the same time allowing for optimal performance when located on a single machine. To accomplish this, as a developer I have to maintain a level of discipline - I can't simply decide to do something the quick and dirty way because in the event of component relocation I don't want the application to break.
Many of the services that are presently tightly coupled within DevTracker really affect the larger whole. These objects should be available outside the scope of the website, but still within the context of the “application“. For example, I'm wanting to design a Windows/MSN Messenger plugin that would display a user's set of issues, giving the user direct access to them. I also want to complete a Windows-based UI that feeds off of the same data. If all of these objects were directly within the ASP.NET application intertwined on my pages there would be no real way to get to them cleanly. Instead, by distributing the objects (or at least separating them), I can design interfaces (Web Services?) that expose the objects more naturally.
The best way I can envision to do this, and the obvious choice, is to make the libraries available within COM+. By leveraging the capabilities of Enterprise Services, I am able to offload much of the horsepower to a second server. That server therefore acts as a floodgate for all database activity, object JITA/pooling, connection pooling, security, and much more; relieving my IIS web server to do what it does best - serve pages. So far, this strategy has proven to be beneficial and highly performant. I'll let you all know what my performance tests yield in comparison.