Archive for May, 2008

Do you really need a data access layer with LINQ?

Lately I’ve been giving a lot of thought to using LINQ to access my database instead of using NHibernate. I’ve been a little confused as to how LINQ would work in a data access layer, but I’m starting to think it makes sense as a replacement to the data access layer.

This article was inspired by the Google App Engine. Using the Django framework for database access is stupidly simple. They’re able to focus on getting something done, which is good enough in a lot of cases. Not every project has to be an N-Tier enterprise application.

Primarily, I write eCommerce websites. Consider the following diagram, which gives you a rough idea of how I’ve traditionally structured my applications:

Traditional Architecture

Notice that a lot of code is being tested. The sweet side of me likes unit tests, but the wheat part of me is telling me to simplify code when possible to minimize the need for unit tests. I’ve traditionally wanted a lot of unit tests at the data access layer because it tends to be a source of a lot of issues due to it’s complexity. It’s complexity is a result of impedance mismatch.

Code that is a good candidate for unit testing:

  • Logic/utility/static functions
  • Code that will be used in a lot of places, and has a well defined contract
  • Code that needs the highest levels of reliability

Now consider what happens when we use LINQ and the ADO.NET Entity Framework. The impendence mismatch has been minimized because the entity framework has automatically written our model code to match the database. It has also been my experience that the queries that are not trivial are usually not re-used. In other words, query complexity is inversely proportional to the frequency of re-use.

The end result is that our code has been greatly simplified. Now our unit tests can focus on the business logic. We’ll actually have more time for unit testing, which should lead to more stable code where it is needed most.

Sure, our UI will contain what are basically database queries. The fact is that many pages simply need a specific set of data that will populate a drop down list for example. I know that it might give people a bad feeling (as it does to myself), but I think it’s something we need to get over. If you want to test the page, in most cases you can just run it, and see that it’s working. In conjunction with a good web testing tool, it would be easy to have high levels of reliability.

Linq Architecture

Obviously there are a lot of places where this is a bad idea. I’m certainly not condoning a complete lack of a data access layer for every application. I’m applying the 80/20 rule. Places it might not make sense, or where it’s gray:

  • A logic class that needs to make frequent, repeated database calls.
  • An application that requires a certain level of testability.
  • An application that contains some extremely common queries that may or may not be trivial.

Filtering the noise from above into a working plan

In this post I’ll talk about a few ways that you can deal with the common influx of requests that come in for a software team.

I used to work for a large company affectionately known at the Borg. I was fortunate to work in a division of the company whose product was a software package. This essentially meant that I worked for a software company.

Borg Cube

My current employer is a mid-sized business, and we’re not in the software business at all. My primary job function is writing custom software for certain customers, as well as creating the "glue" that holds together the software packages that we have purchased.

Luckily, we’re a growing company, so we’re starting to have a real software development team. With that comes with the pains of getting organized, and making sure we’re working on the right projects.

What do you do when the amount of work being requested from management greatly exceeds the amount of work your team can actually get done?

  1. Push back – This doesn’t have to be negative. The person requesting a new software project might not understand that you’re team is busy. It’s common to think of an IT department as overhead. They are usually not factored into the costs of new projects. A good manager will be able to explain the situation, and either delay the request, or drop it completely.

  2. Set up monthly meetings with the key management members - This gives people a forum where they must discuss the work they’re asking to be done. At this point, a good percentage of the work could disappear, because no one is willing to try to justify the importance of their project.

    Some of the projects that would normally be high priority are now not as important when compared relatively to all the work that needs to get done. This also gives management members time to negotiate directly with each other, and you won’t be caught in the middle of it.

  3. Create a visible schedule of tasks that need to be done – When a member of management wants their work done, they can look at the schedule and see that they are not alone. If they want something done, they may have to negotiate with someone that is already on the schedule. If they can do that, they probably deserve to be on there.

  4. Associate a cost with all work to complete – For any tasks that take longer than, say, 2 hours, require that the time be charged to a particular task. That time can then be equated with money. Since your time now has a set cost associated with it, people that need your time will have to pay for it. Actually money doesn’t have to be exchanged, but just associating costs will put the burden on the person requesting it. If they have to justify $100 worth of time to save $50, they might think twice.

Do you have any other tips for dealing with this situation?

Speeding up your ASP.NET Application

I read a post titled "Improve Web Application Performance". I expected to have a lot of information to add, but it’s actually pretty comprehensive. I recommend reading it if you’re developing a web application. One of my biggest complaints about most websites is that they’re way too slow. In this day and age there is really no reason for that.

Analog Stopwatch

The only other optimization I have used in the past that isn’t mentioned in the post, is removing whitespace. While it can make your life a little harder because of some layout glitches it might cause (which are fixable), it can often have a pretty big effect on your page sizes. On one of my websites, I saw an average of a 10-20% decrease in page sizes, even when gzip compression was turned on.

The easiest way to remove whitespace from your pages is to use an HTTP module. One solution is available here for free. You simply add the binary DLL, and reference it in your web.config file. It couldn’t hurt to give it a try the next time you’re writing an ASP.NET application.

Quick and dirty reporting with the Google Chart API

On a recent project, I need a quick and dirty report that would give a breakdown of statistics for orders that have been placed. I didn’t need any fancy drill down, hover help, or transition effects. This sounds like a perfect use for the Google Chart API! There is no limit on use. All you have to do is construct a URL containing your data, and that is the URL for an image containing your chart. Here is a sample of a chart that we’re going to generate in this post:

Pie Sample

First, we need a quick way to generate the data. I used a SQL Server stored procedure, because I knew it would only take a matter of minutes to create. Here is an example of how I retrieved the data for 2 report sections:

--Paper Breakdown
Select IsNull(p.PaperName + ' (' + Cast(Count(o.PaperId) as VarChar(Max)) + ')', 'Unspecified'),
	count(o.PaperId)
From Orders o
Left Outer Join Papers p on o.PaperId = p.Id
Group By p.PaperName
Having Count(o.PaperId) > 0
--Style Breakdown
Select IsNull(s.Sku + ' (' + Cast(Count(o.StyleId) as VarChar(Max)) + ')', 'Unspecified'),
	count(o.StyleId)
From Orders o
Left Outer Join Styles s on o.StyleId = s.Id
Group By s.Sku
Having Count(o.StyleId) > 0

Then, I simply had to call the stored procedure, and put the data into a DataSet called "_data" (code not shown). Then, I wrote a quick method to get the URL for a Google chart:

private static string getPieChartUrl(DataTable dt)
{
	if (dt.Rows.Count == 0)
		return "";
	StringBuilder sb = new StringBuilder();
	sb.Append("http://chart.apis.google.com/chart?chs=600x200&cht=p"); //Base URL
	//Pie slice data
	StringBuilder sliceData = new StringBuilder();
	foreach (DataRow currRow in dt.Rows)
		sliceData.Append(currRow[1] + ",");
	sliceData.Remove(sliceData.Length - 1, 1); //Remove the trailing comma
	sb.AppendFormat("&chd=t:{0}", sliceData);
	//Pie label data
	StringBuilder labelData = new StringBuilder();
	foreach (DataRow currRow in dt.Rows)
		labelData.Append(currRow[0] + "|");
	labelData.Remove(labelData.Length - 1, 1); //Remove the trailing comma
	sb.AppendFormat("&chl={0}", labelData);
	return sb.ToString();
}

My ASPX page then has 2 image controls:

<h2>Breakdown by Paper Type</h2>
<asp:Image runat="server" ID="imgPiePapers" />
<h2>Breakdown by Style SKU</h2>
<asp:Image runat="server" ID="imgPieStyles" />

Then, simply wire up the data:

imgPiePapers.ImageUrl = getPieChartUrl(_data.Tables[0]);
imgPieStyles.ImageUrl = getPieChartUrl(_data.Tables[1]);

Disable auto id’s when copying ASP.NET controls

Don’t you hate it when you copy an ASP.NET server control without an ID, only to have it add one when you paste it?

For example, look at this code:

<asp:RequiredFieldValidator runat="server" />
<asp:RequiredFieldValidator ID="RequiredFieldValidator1" runat="server" />

I took the first line, copied it and pasted it, and got the second line. It’s rare that I need to reference a validator in my CodeBehind.

Here is the option to disable this functionality in the Visual Studio options (Tools->Options):

Disable Auto Ids Visual Studio

Simply uncheck the “Auto ID elements on paste in Source view” option.