Simplest Thing That Works

I remember working for a .NET development shop back in 2005. .NET 2.0 was still in its nascent phase, and the team I was on was still relatievely new to .NET. We were all trying to figure out best practices, object design, etc. But we were good developers, and knew that it’s always best to go with libraries and frameworks that are already written, ones that will simplify the task at hand. The library that was popular among the team was CSLA.

Now I should mention right up front, for full disclosure, that I’m personally not a fan of CSLA. But everyone has their own opinion, and I know many teams have used CSLA to great success. The post below is not about CSLA, but rather about finding the right tool, and the right functionality.

But this goes to 11

There’s this famous scene in Spinal Tap, a mockumentary about a fictitious rock band, where the lead guitarist, Nigel Tufnel, explains to the reporter how his amp is louder because it goes to 11. When asked why he simply didn’t make 10 louder, Nigel is befuddled and again states the amp goes to 11, which is one more than 10. 11 must be louder, right?

When we discussed using CSLA in our team, one of the arguments that was given in its favor was CSLA had built-in support for remoting, a precursor to WCF. Our project, however, not only had no need for remoting, it would never need remoting. The fact that the framework supported remoting was of no concern to our application.

However, “this one goes up to 11.” “This supports remoting. And isn’t that cool?”

Yes, it’s cool - if we need remoting. Otherwise, we’re simply adding complexity for complexity’s sake.

Lots of amps set to 11

If you look out over the developer landscape, you’ll notice tool upon tool, framework upon framework, all offering some set of functionality, with promises to make your life as a developer easier. And most frameworks and tools will do exactly that. But, those tools may come at a cost in increased complexity.

On the web side of things, you have NPM, Grunt, Gulp, Bower, …, to help manage packages, files, workflows, etc. And you have jQuery, Bootstrap, Knockout, Angular, …, to make developing front ends that much easier. And the list goes on and on.

All of those various tools and frameworks have their place, and they can all bring additional power, and help you create applications that much faster. But they can also add unnecessary bloat. And complexity.

Before taking a dependency on a tool or framework, make sure the features it provides are what you actually need. For example, Ember.js has this amazing data store; it’s my favorite feature of that framework. But if you’re not making many Ajax calls and working with data, but rather need to simply update the front end dynamically, why choose that as your framework? Why not use jQuery? Or maybe Knockout?

Take only what you need to survive

As a perfect example, I am currently pecking out a sample NodeJS application. I dutifully sat down and started adding in various packages, started tweaking my Gulp file, and then stopped myself.

It’s a simple sample application.

Do I really need to worry about Gulp? No. Bower Installer will do the trick just fine for me, as all I need to do is copy out the CSS and JavaScript files.

Do I need to use LESS? Since I’m just going to be using the default Bootstrap theme, there’s no need for me to worry about pre-processors or the like. Could I use LESS? Sure, but I don’t need it to survive.

If the sample application starts to grow and become more complex, maybe I’ll revisit those decisions. But right now, I don’t need them. Why would I take a dependency on something that offers me features that I don’t need?

Instead, make 10 louder.


Running Ragnar

Our finish photo at Ragnar
Long road relays seem to be all the craze in running these days. Considering the basic concept is you get a bunch of your friends together and cover 200 miles in shifts, the appeal is pretty obvious. Well, obvious to runners anyway. ;-) Chances are if you’re a runner you’re familiar with this style of race, and you’re probably considering doing one. I just finished my first, and while I’m certainly no expert, I did learn some lessons that I wish I’d have known about before the race. So, I’m going to share them with you.

Clothes

You will want one outfit per leg. After all you run your leg, and then rest, either in your van or elsewhere, for the next few hours. You’re either going to be wearing wet, stinky clothes, much to the chagrin of your van-mates, or you’re going to be putting on wet running gear to head out for your next leg, which is certainly not something you want to do.

Ziplocs are your friends

2 gallon Ziploc bags are your friends. Not only are they a great way to group together gear, they’re also a great place to store those wet clothes we talked about above. They’ll not only keep the stink contained, they’ll make it easy to keep everything else nice and dry.

When I did my race I meticulously packed each of my three outfits into three separate bags. What I discovered, though, was I wound up swapping things around from my original plans. Next time I’d keep tops in one, bottoms in another, and things like socks in a third. And then just toss your dirty stuff into a single Ziploc.

Find the right team

Make sure you know ahead of time what everyone’s goals are. I did my race with a friend, and we were originally thinking we’d be running a slightly faster training pace. It was only after we joined our team that we discovered everyone wanted to race their legs. We adjusted and rolled with the punches, but it would have been good to have those expectations ahead of time.

Go with people you’re comfortable changing around

Depending on the speed of your runners, you’re not necessarily going to have a lot of time at the exchanges to change. On top of that, the only place you will have to change in private is in a portapotty, and that’s not really the best place to be for anything but the original design of the equipment.

This means, often, the best place to change is going to be in the van. You can set up an area in the back seat, with a couple of towels, that can help give a shield to the person changing and keep the right parts covered. This isn’t to say that you have to give up all privacy, but being comfortable enough to simply have people not look goes a long way to making it easier to get out of those wet clothes or into the next outfit you’re going to wear.

Have a transition plan

As I mentioned above, there isn’t always a lot of time in the transition areas. You’ll want to have a plan in place on what you’re going to be doing in the transition area. There are three runners you need to support at all times - the one who just finished, the one who is about to start, and the runner that’s currently on the road. You’ll want to make sure you figure out how you’re going to balance all of those runners to make sure everyone has what they need.

Find a driver

If at all possible, have a dedicated driver. Having to run and drive, which I did, makes for a very long day.

Have everything at the ready

Try to keep everyone at some state of ready as you go from transition to transition. Trying to load a van to head to the next exchange can be a bit like herding cats, as someone realizes they need a headlamp, or a reflective vest, or a granola bar, or … This takes time, and makes it that much harder to get out to cheer on your runner, and get to the next exchange in a good amount of time.

Sort your gear

Make sure everyone has a headlamp, vest, and back light of their own. You don’t want to worry about trying to share them. And keep those in a separate bag, or maybe in the same bag with your socks (see above). This way you know where everything is at any given time.

Put your keys on a lanyard

Lost car keys are always a risk as everyone keeps hopping in and out of the van in sporadic order. In addition, you’ll be passing the keys around as different people are driving or going into the van. Having them on a lanyard, and around someone’s neck, decreases the chances you’ll lose it, and makes it easier to spot who has the keys.

Focus on sleep

When you’re packing, make sure you have a sleeping bag and a good pad (or small air mattress) to sleep on. You’re not going to have a lot of time to sleep, so you’ll want to make the best of it. Those little creature comforts will make all of the difference in the world. They’ll also give you the flexibility to sleep outside (maybe pack a small tent?) rather than the high school.

While we’re at it, an eye mask and earplugs are an absolute must. Trust me, you absolutely need them.

I didn’t have any of the above, and I was not a happy man come the following morning.

Always bring the map with you

Ragnar (I can’t speak to the others) does a good job of marking the course, but not always. There was one turn in particular where they had everyone running on one side of the road, but the sign to turn was on the opposite side - very easy to miss, and one runner I know did. Bring the map.

In fact, one thing you might want to consider is leaving someone at the challenging corner if you see it while driving along the route to help the runner make the turn. The little bit of lost time to pick up the person left behind is far less than risking losing a runner.

Make a point of cheering on your runner

And the other runners as well.

There’s not going to be a lot of runners out while you’re running, and not much in the way of support beyond those running the race. As a runner, you know how much support helps. Give that support to your runner, and the other teams while you’re at it. They’ll appreciate it.

Rent a house after the race

Chances are you’ll be away from home when you finish. You’re not going to want to drive right home afterwards, and why would you even if you could? I mean, you just finished a great race with your new best friends! You should celebrate it.

If you rent a big house you’ll be able to get showers (you’re going to want a shower!), beds, a kitchen for food, etc.

Have fun

This goes without saying, but enjoy the experience! It’s great being able to see the sun go down, and then come back up. It’s great being out on a country road, at night, running along. And you’ll share laughs, and a great time.


Grandmas Marathon

Background

18 months. That’s how long it’s been since my last marathon. I’ve battled many an injury: shin splints, back issues, and IT band, the last of which sidelined me since last January. It’s been a long struggle back, and fortunately I have many friends who’ve given me more love and support than I could possible ask for.

Grandma’s Marathon, a race which I’ve run in the past, a race which I love, and a race to which I have a connection, as my wife and I went to college at University of Minnesota Duluth (UMD), seemed like the perfect race for my triumphant return. Well, at least it seemed that way.

The race

First up, let’s talk a little bit about the race itself. It’s called [Grandmas][Grandma’s Marathon] because the title sponsor is a local restaurant/bar named, fittingly enough, Grandma’s. They’ve been the title sponsor since the second year the race has been held, which was 39 years ago. That made the 2016 running the 40th annual event, which also meant there was a cool medal. It’s all about the cool medals when you’re a runner.

Because it’s based in Duluth, MN, a town of 100,000 people, and sees a minimum of 15,000 people combined running the half or the full, it takes over the town. The hotels are in full gouge mode over the weekend, with even the Bates Motel asking for no less than $300/night, but they open up all of the local college campuses for the runners. There are signs up all over town referencing the runners. And everyone you talk to just assumes you’re there for the race. It’s a wonderful atmosphere.

Dorm room

Grandma’s is a mini-Boston. Granted, I’ve never run Boston, and probably won’t ever be fast enough to do so, but there are striking similarities. It’s a point to point, starting from a small town and running into the city. It’s a net downhill, with hills throughout, and a good climb at mile 22, called Lemon Drop Hill, although none of the hills are as bad as the ones you’d seen in Boston. And, until the end, there isn’t much in the way of turns, as it follows an old highway into town, meaning all of the turns are sweeping curves.

The weekend

Our 2016 experience started with my wife, Karin, our good friend, Susan, and myself all flying into Minneapolis, with intentions to drive to Duluth, on Thursday. We all happened to be flying in from different places, Karin from our house in Seattle, Susan from her house in Ottawa, and I from a conference in Boston. Originally we were all supposed to land within about 5 minutes of one another, but in what would set the tone for the weekend, things didn’t go as planned - my flight out of Boston was delayed a good couple of hours. Fortunately, Karin and Susan were able to find dinner, and I was able to eat on the plane, so we were able to grab the car and just start driving to Duluth. We avoided rush hour, and made good time into Duluth. We checked into the dorms and fell fast asleep.

Because Karin and I attended college in Duluth, and lived there for 4 years, we wanted to share a little bit of our past with Susan. This meant starting Friday morning, the day before the race, with breakfast at the Perkin’s we all would hang out at as college kids. We showed Susan a couple of neat views of Lake Superior, the lake we’d all be running along the following day.

The race finishes around the DECC, which is where the race expo is, and the last mile is where the race organizers “make you work for it”. You wind up running past the finishing line twice, before finally making the last turn towards it. There’s also a quick, but steep, hill to cross a bridge to get over to the DECC, and a couple of tight turns you want to be aware of in advance. We took the opportunity to walk the last mile and familiarize ourselves, particularly Susan, with the finish. This was the best 30 minutes we’d spend that day, and it’d pay dividends during the race. If you decide to do Grandma’s, I can’t suggest checking out that last mile enough, otherwise it will bite you - I promise.

The expo itself was your stock expo, with all of the various tchotchkes you might want to find. What made this unique was Dick Beardsley, a Minnesota boy who set the course record at 2:09:36, a record which stood for over 30 years, was signing autographs. I needed an autograph! I can tell you Dick is probably the nicest guy you’ll ever meet, and a great ambassador for the sport. He would talk to everyone for as long as they wanted, and truly relished the time to meet with fellow runners.

Me and Dick Beardsley. One of us has run a 2:09 marathon

After the expo, and realizing we’d walked about 10K, we decided it was time to find lunch and get off our feet. Lunch location? Erbert’s & Gerbert’s, a Duluth institution. We roamed back to campus to take over one of the lounges and watch Spirit of the Marathon, because you have to. We found dinner at a great little Italian restaurant to complete our carbo-loading. Then it was time for sleep, with visions of PRs dancing in our heads.

Now, let me back up just a little bit to talk about the weather obsessing that is standard for any race. When we first started looking it looked like it might be a touch warm (highs right around 70F), but otherwise OK. Then it looked like it’d be hot. And then rain. The night before it looked like the rain was going to miss us, and we were back to a little warm, no wind. We thought everything would be good.

So we thought…

The start

Grandma’s Marathon uses a flag system to indicate the weather risk - green, yellow, red, and then black, with black meaning “extremely high risk”.

Karin boarded her 4:45 bus for the half marathon, which starts at 6:15a. Her race temps were a bit warm, but she finished the race just as they put out the yellow flag. She had a great race, even if it was a bit slower than her previous race here.

As for me and Susan, well… Things started out looking promising. We boarded the bus nice and early, and were among the first to arrive at the starting space, a car dealership. We got a picture by the starting corrals, took pictures of the green (yes, green) flag, indicating good race conditions, and found a nice spot on the grass to chill before the race. Because we were among the first to arrive, we had first crack at the portapotties, which is every runner’s dream. We went through our normal pre-race routines, and chatted about strategy and expectations.

Green flag

We waited for about as long as we could before fighting our way down to gear check, and then into the corral area. As we pushed our way towards our areas in the corral, we heard the announcer, who clearly wasn’t a runner, talk about how beautiful the day was, at a pleasant 68 degrees. 68 degrees is about 20 degrees too warm for most runners I know. About 10 minutes later, he announced it was 72. What he didn’t add was the fact the humidity was around 80%. It was going to be a slog, and I was beginning to sweat just standing there. I didn’t know that heat that was ahead of me.

A bit of background on me. I’ve run 3 marathons in the past, and I’ve yet to run what I’d call a good race. In each race I had some form of a collapse, at varying spots along the race. I know I have a 3:59 in me, but I’ve yet to coax it out of my body. Going into the race, this was my goal. This was my race. This was my time. Mother Nature, unfortunately, had other ideas.

The first 10K

I bid Susan farewell at the 4:00 “corral”(1), and let her fight the rest of the way to her 3:45 area. When I got there I started looking around for the 4:00 pacer, along with the rest of the runners in the area, to no avail. I discovered later that all pacers under 4:15 were towards the front of the starter’s chute, which did nothing to help those of us who lined up where we were supposed to line up. Grandma’s gets nearly everything right during race weekend, but this was a huge blunder on their part. It was at this point I realized I wasn’t going to have a pacer, and thus wasn’t going to have a pack to run with.

It was the latter part that really bothered me. I’m a social runner. I like to chat, to have comradery, to share the experience with those around me. When there’s a pacer, there’s automatically a pack and a sense of community. Without a pacer, well, it’s every runner for themselves. So while I did chat with a few runners at the start, once the gun went off and we reached the start line, everyone went off by themselves.

I have to say I’m rather proud of myself. I have a history of going out too fast, which is easy to do on this course, as the first couple of miles are downhill. Plus, considering the lack of a community, I could have easily latched on to a runner who was going too fast. But, when the one woman I was talking with took off a bit faster than the 9:09 pace I wanted, I let her go off and do her own thing, and settled into my pace.

And find my pace I did. I went through the first 10K at about 17 total seconds fast, or about a 9:06 pace. My overall pace from mile to mile didn’t vary by more than 8 seconds. I could not be happier with how that first 10K went. And while that green flag was a yellow flag at the first water station, I was still feeling good.

But… When I saw that yellow flag at 5K I knew this was a sign of things to come. I knew at some point we were going to see that red flag. It was too early in the day, the sun was bright overhead, and it was only going to get warmer. My body, however, felt great at the 10K mark. I was going to ride this wave for as long as I could.

The second 10K

Around that 10K mark I passed the 4:15 pace group, which I thought was rather strange. I didn’t know what had happened with the pace groups until after the race, but passing a pace group of any sort does give you a bit of a burst of energy, which I took. I did give a thought to falling in with the group, knowing the heat was only going to continue to beat me down over the course of the day, but again - my body was feeling good.

I mentioned earlier I’d run 3 marathons, and during each marathon you learn different lessons. My last marathon, Carlsbad, was an unmitigated disaster, with me having to push to finish under the 5:00 mark.(2) At mile 10 of that race my quads were shredded and I didn’t have anything. But I decided to push it, and when I hit mile 16 I had nothing left. I walked about 8 of those last 10 miles.

With that lesson in mind, I’d already made the decision to do check-ins with my body at every 10K, and adjust as needed. I cruised through that first 10K, and was settled in for a good race. I found my pace, my stride, and knew the effort that was needed to maintain right around that 9:09 pace. My watch showed me at 9:06, and all was good.

Then things started to change. I went through mile 7 and 8 a touch slow, but nothing that had me overly concerned. I noticed the overall pace on my watch start to creep up to 9:07. Then 9:08. And then I went through mile 10, at the same effort I’d done the previous 9 miles, at a 9:21 pace. It was at this point when I realized it just wasn’t going to be there. Now, yes, 12 seconds off pace isn’t much. But with the temperature starting to rise, and the sun still beating down, I decided to just settle in and enjoy the run rather than shooting for a PR. In the end this turned out to be a good decision, as the 11-mile water station flew what I was expecting to see: red flag. Yes, it was that hot.

From here forward it was all about keeping cool, staying positive, and enjoying the race as best as I could. I was going to listen to my body, try to run from balloon to balloon (mile to mile), and walk through the water stations. Unfortunately, I did wind up walking more than I’d hoped, but I was able to run a lot more than I could at Carlsbad, further reinforcing my decision to bag the PR at mile 11.

Staying cool

At this point I’d like to thank the race organizers for doing an amazing job with the aid stations, and the good people of Duluth, MN for helping keep us cool. The aid stations are easily the best I’ve ever seen at a race, and I’ve experienced many races in my time. Every single station was well staffed and supplied. You had plenty of time to get your water or PowerAde. The layout was water, PowerAde, ice, sponge, water. Yes - two water tables at each station, and PowerAde at each station. I don’t know of another race that does that. And the sponges and ice were plentiful as we all tried to keep ourselves cool, or as cool as we could.

The good people of Duluth did their best as well, setting out cooling showers, or just simply hanging outside of their house with a hose. They all understood to not simply douse the runners, but rather let the runners come to them. One of my highlights was around mile 22, when I went running towards a guy with a hose and said “HIT ME!”, which he did with about 4 gallons of water. It was amazing!

But, back to the race. I hit the halfway mark at 2:02, which made me smile, knowing I had a good time until then, but also knowing what was ahead of me time wise. At mile 15, there was a loud BANG. Turned out the blue balloons, indicating the half marathon miles, exploded from the heat. The explosions were repeated by many of the balloons, although this was the only one I witnessed. My running partner in crime, Susan, also said she heard one. See the explosions or not, you noticed the aftermath as there were few blue balloons left on the course as the day wore on.

A happier time at the 25 mile mark

The finish

The turn into the city was welcomed by everyone, as the fans really start to pick up during that stretch, carrying you through to the finish. The mile through downtown Duluth is amazing, with an energy that can’t be described, as the fans, three to four deep, cheer you through towards that last mile.

Remember that last mile? Boy was I glad we walked through it the day before, as I knew exactly what to expect when we turned left on 5th to cross the bridge towards the DECC. I focused on doing the loop behind the DECC, past the USS Irvin, past the finish line for the second time, and then around one last little loop to head into the finish - at 4:41, and in 79-degree heat. I’ve never been so happy to see 4:41 on my watch, as I had to fight to get it below 4:45.

I crossed the finish line in full celebration mode, knowing what I’d overcome that day. I was decorated with my medal, found my finisher’s shirt, and was then embraced by Susan, with a very knowing expression of “we survived!” As it turned out Susan was about 25 minutes off the time she was hoping for, and battled to get there as well. Susan then led me to Karin, and another wonderful embrace.

After the obligatory post-race photos, the two of them had been in the area for a while, and had already found their first round of post-race refreshments. They helped me find what I needed (a chocolate milk and banana to start), and my gear. Grandma’s offers changing tents, which both Susan and I took advantage of, getting out of our clothes which were soaking wet. Next stop: beer tent, for a well- earned cold one. Karin, who’d been hanging out in the finishing area the longest, then declared she was hungy, which sent us off on a search for food. Needless to say Canal Park, where the race finishes, was absolutely packed. But with a little bit of a walk we were able to find a restaurant that had immediate seating. We settled in, had a couple of bites, and beer number two. :-) We swapped stories, commiserated, and slowly started to recover from a long, hot, but successful day.

Grandma’s remains my favorite marathon, and the heat does nothing to change my opinion of this great race. Yeah, it was hot, but the organizers handled it with aplomb. The only issue was the pacers, which I mentioned above. If you are going to run this race, book your hotel, and your pre-race meal, nice and early.

And pray for rain.

The finish

(1) There aren’t corrals, just signs denoting the expected finishing times

(2) Speed is relative. For some, 4:00 is slow. To me, 5:00 is slow. To each their own strengths, etc.


Anonymous Methods, Lambdas and LINQ

… oh my!

Lately, one of the most common questions I’ve received from my students is, basically, “What in the world is this syntax, and what does it mean?”

1
dc.Categories.OrderBy(c => c.Name);

Well - it’s a lambda statement. But of course if you haven’t seen one, you need a bit more information than that.

Quite frequently, a full explanation would simply take too long, or send the class down another path far away from the topic at hand. What I want to do with this post is answer that question fully.

I’m going to answer the question by using one of my biggest philosophies when it comes to training, which is to explain it in the way that I understood it, in whatever method it was that made it finally click for me. In this case, that means stepping all the way back to the beginnings and showing essentially the progression that got us to where we are today.

That’s going to take a little while, so bear with me.

Trust me, we’ll get there.

Let’s take a simple class called Customer that’s defined below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Customer
{
public Customer(string firstName, string lastName)
{
this.FirstName = firstName;
this.LastName = lastName
}
public string FirstName { get; set; }
public string LastName { get; set; }
public override string ToString()
{
return LastName + ", " + FirstName;
}
}

Pretty straight forward. Couple of properties, a simple constructor. Looks good. Now let’s create a couple, put them into a list, and display them.

1
2
3
4
5
6
7
8
9
10
11
public static void Main()
{
List<Customer> customers = new List<Customer>();
customers.Add(new Customer("Susan", "Ibach"));
customers.Add(new Customer("Christopher", "Harrison"));
customers.Add(new Customer("Dave", "Baxter"));
foreach(Customer customer in customers) {
Console.WriteLine(customer);
}
}

Again - pretty straight forward. And the output will of course be exactly what we’d expect:

1
2
3
Ibach, Susan
Harrison, Christopher
Baxter, Dave

Now let’s see if we can sort those customers. Fortunately, List has a a Sort method. Let’s update line 7 to call sort (code below) and run it to see what happens.

1
customers.Sort(); // Line 7

Result:

1
Unhandled Exception: System.InvalidOperationException: Failed to compare two elements in the array. ---> System.ArgumentException: At least one object must implement IComparable.

Well that wasn’t ideal… In a nutshell, what the runtime is trying to tell us is that we told it to sort a list of customers, but it has no idea how to sort our customers. Makes sense. How do we tell it to sort our customers? Well – by implementing IComparable.

IComparable is an interface with one method – CompareTo(object). CompareTo returns an integer based on the following criteria:

Current object (this) is less than the other object, return a negative number
Current object (this) is equal to the other object, return 0
Current object (this) is greater than the other object, return a positive number

One thing that you’ll notice is that every primitive type (and strings) in .NET already implement IComparable. This means we can take advantage of their implementation. Let’s update our Customer class to implement IComparable and sort by LastName.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Customer : IComparable
{
// existing code
public int CompareTo(object obj)
{
// put all NULL objects at the topic
if(obj == null) return 1;
Customer otherCustomer = obj as Customer;
if(otherCustomer != null) // obj is a customer
return this.LastName.CompareTo(otherCustomer.LastName);
else
throw new ArgumentException
("Object is not a Customer", "obj");
}
}

The breakdown looks a bit like this:

Line 8 - see if the object is null. If it is, move it to the top of the list.
Line 10 - convert the object to a customer
Line 11 - if it turns out that obj is a Customer, use the CompareTo method on String.
Line 13 - if it turns out that obj is not a Customer, throw an ArgumentException.

If we run the code again, we now get the result that we were hoping for:

1
2
3
Baxter, Dave
Harrison, Christopher
Ibach, Susan

Cool.

But…. If you look at the CompareTo implementation, we’re having to cast the obj parameter to Customer. Why can’t we just tell the IComparable interface that we want people to pass in a Customer and be done with it?

Fortunately – we can. The way that we do this is by using generics. In a nutshell, generics allow you to pass a type as you would a variable. So at design time we tell IComparable prepare itself for Customer objects. Let’s update our Customer class again.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class Customer:
IComparable, IComparable<Customer>
{
// existing code
public int CompareTo(object obj)
{
// put all NULL objects at the top
if(obj == null) return 1;
Customer otherCustomer = obj as Customer;
if(otherCustomer != null) // obj is a customer
return this.CompareTo(otherCustomer);
else
throw new ArgumentException("Object is not a Customer", "obj");
public int CompareTo(Customer other)
{
// put all NULL objects at the top
if(other == null) return 1;
return this.LastName.compareTo(other.LastName);
}
}
}

Cool - we have a Customer class that can be sorted.

But… It can only be sorted one way - by LastName. If we wanted to sort by FirstName, well - that’d require updating our class. Having to update our class every time we need a different sort order would be a pain.

Fortunately – we don’t have to. The .NET framework also includes an IComparer interface. The difference between IComparable and IComparer is that IComparable is for sorting that specific class (which is why Customer implemented IComparable), while IComparer is for sorting other classes - a utility if you will. Let’s create a class that can sort Customer objects by FirstName.

1
2
3
4
5
6
7
8
9
10
11
12
public class CustomerSorter : IComparer<Customer>
{
public int Compare(Customer lhs, Customer rhs)
{
// put nulls at the top of the list
if(lhs == null) return -1;
if(rhs == null) return 1;
return lhs.FirstName.CompareTo(rhs.FirstName);
}
}

The main difference, besides calling CompareTo on FirstName, is that we have two parameters of type Customer and we’re comparing one to the other. But the logic is still basically the same.

To use the new sorter, we simply pass a new instance of the object into the Sort method on List.

1
2
3
// all other code identical
customers.Sort(new CustomerSorter());

When we run the code now, we get everything sorted by FirstName.

1
2
3
Harrison, Christopher
Baxter, Dave
Ibach, Susan

Cool.

But… If we have to create a new class every single time we need to change the sort order, well – that’s going to stink. There’s gotta be a better way.

Fortunately, there is. The .NET Framework gives us the ability to use delegates, which allow us to pass methods like we would objects.

Let’s take a look at our new Compare() method that we created on our CustomerSorter class. You’ll notice that it takes two parameters, each of type Customer, and returns an integer. That’s it. And when we call Sort and pass in the CustomerSorter, it simply calls that method. Why can’t we just pass a method into Sort?

This is where that delegate, an object that points to a method, comes into play. Since it can be used like an object and passed in as a parameter, we can just tell Sort to call that method directly. This is really the same thing we were doing before by passing in an instance of CustomerSorter to the Sort method, only this time we’re just passing in a method.

Our method just needs to match the same signature – two Customer parameters and return an integer.

Let’s add a method to our Program class that will use the same logic as our CustomerSorter.

1
2
3
4
5
6
7
8
9
10
// added to Program class
private static int SortByFirstName(Customer lhs, Customer rhs)
{
// put nulls at the top of the list
if(lhs == null) return -1;
if(rhs == null) return 1;
return lhs.FirstName.CompareTo(rhs.FirstName);
}

Want to know a secret? I simply copied and pasted from CustomerSorter class and changed public to private, instance to static, and the name to SortByFirstName.

Now we just need to tell the Sort method to use our new SortByFirstName method.

1
2
3
// identical code except for Sort call
customers.Sort(SortByFirstName);

And as before, the result is the same - sorted by FirstName.

Cool.

But… If we need to sort in several different orders, we don’t want to have to create a method each and every time. Wouldn’t it be nice if we could just inject the logic right into the call to Sort?

Fortunately, we can. We do this by creating an anonymous method. An anonymous method is a method that has no name. We just create the method signature by using a delegate, and pass it right into the Sort method.

1
2
3
4
5
6
7
// identical code except for the Sort method
customers.Sort(delegate(Customer lhs, Customer rhs) {
if (lhs == null) return -1;
if (rhs == null) return 1;
return lhs.FirstName.CompareTo(rhs.FirstName);
});

Just as before, we have the same logic (yes, I copied and pasted). We’re just declaring the method just as we normally would with only a couple of differences. First, we’re using the keyword delegate instead of using a method name. Second, we’re not specifying a return type. The reason is that Sort already knows what the return type is – an integer – so the compiler doesn’t require it.

And, as before, the result is the same – sorted by FirstName.

Cool.

But… Why do we have to specify the types of the parameters? After all, we already told the list right up front that we were using Customer objects.

Fortunately, we don’t. This is where lambda expressions come into play. A lambda expression is just like an anonymous method, only with a couple more assumptions. In our case, since we know, and the compiler knows, that we are only dealing with Customer objects, and we need to return an integer, we’re just going to declare our variables and move on.

1
2
3
4
5
6
7
// identical code except for call to Sort
customers.Sort((lhs, rhs) => {
if (lhs == null) return -1;
if (rhs == null) return 1;
return lhs.FirstName.CompareTo(rhs.FirstName);
});

The main difference between this and our anonymous method is the syntax and the fact that we’re not declaring data types. Since everyone, including the compiler, knows that lhs and rhs can only be Customer objects we don’t have to declare it. The => is just the syntax to indicate the start of the method, or lambda expression.

And, as before, the result is the same – sorted by FirstName. Cool.

But… What about the normal situation where all we want to do is just say, “Hey .NET - sort this by ___ for me.”? Do we really have to create a method, even in a lambda expression, every single time?

Fortunately, we don’t. This is where Language Integrated Query (LINQ) comes into play.

In each of our method implementations, our code has simply taken advantage of the logic in the String class. LINQ will do the same thing for us. We simply tell LINQ, “Hey – sort by this”, and it’ll handle the translations for us.

The first step to using LINQ is to leave behind the Sort method that we’ve come to know and love. Unfortunately, Sort doesn’t support LINQ.

When Microsoft introduced LINQ, they also introduced something called extension methods. Extension methods are a way of adding a method to an existing class without having to inherit from that class. The method that was added to the List class, or more specifically IEnumerable, for LINQ was OrderBy.

With OrderBy we can, by using a lambda statement, simply tell LINQ the property we want to sort by. So the new code looks like this:

1
2
3
4
5
6
// updating the foreach loop
// all other code remains the same
foreach (Customer customer in
customers.OrderBy(c => c.FirstName)) {
Console.WriteLine(customer);
}

Couple of things to notice here.

First up is that unlike Sort, OrderBy is volatile, meaning that it’s going to return the sorted list rather than updating the list like Sort did.

Second is the fact that we’re not returning an integer. Again, LINQ will handle the translation for us. As long as we specify a property that implements IComparable it will use that for the sorting.

Third is that LINQ uses deferred execution. In other words, it won’t actually do the sort until we use the results. In this case, we’re doing this when we use the foreach loop.

And now when we run the code we of course get the same results.

Cool.

And that’s what that lambda statement is all about. It’s really just letting someone else create the query for us based on a couple of assumptions about our code and the types that we’re using.

From here, things actually get cooler. We of course have LINQ syntax, which allows us to write something similar to a SQL query. And, LINQ can also translate the queries for other environments, like SQL.

But for now, we’ll leave it here, with a very propeller head view of lambda statements. Hopefully this helped bring together what’s happening behind the scenes, and why we’re able to take the shortcuts we can take.