Jeff and .NET

The .NET musings of Jeff Putz

Sponsors

News

My Sites

Archives

Real-world SignalR example, ditching ghetto long polling

One of the highlights of BUILD last week was the announcement that SignalR, a framework for real-time client to server (or cloud, if you will) communication, would be a real supported thing now with the weight of Microsoft behind it. Love the open source flava!

If you aren’t familiar with SignalR, watch this BUILD session with PM Damian Edwards and dev David Fowler. Go ahead, I’ll wait. You’ll be in a happy place within the first ten minutes. If you skip to the end, you’ll see that they plan to ship this as a real first version by the end of the year. Insert slow clap here.

Writing a few lines of code to move around a box from one browser to the next is a way cool demo, but how about something real-world? When learning new things, I find it difficult to be abstract, and I like real stuff. So I thought about what was in my tool box and the decided to port my crappy long-polling “there are new posts” feature of POP Forums to use SignalR.

A few versions back, I added a feature where a button would light up while you were pecking out a reply if someone else made a post in the interim. It kind of saves you from that awkward moment where someone else posts some snark before you.

image

While I was proud of the feature, I hated the implementation. When you clicked the reply button, it started polling an MVC URL asking if the last post you had matched the last one the server, and it did it every second and a half until you either replied or the server told you there was a new post, at which point it would display that button. The code was not glam:

// in the reply setup
PopForums.replyInterval = setInterval("PopForums.pollForNewPosts(" + topicID + ")", 1500);

// called from the reply setup and the handler that fetches more posts
PopForums.pollForNewPosts = function (topicID) {
	$.ajax({
		url: PopForums.areaPath + "/Forum/IsLastPostInTopic/" + topicID,
		type: "GET",
		dataType: "text",
		data: "lastPostID=" + PopForums.currentTopicState.lastVisiblePost,
		success: function (result) {
			var lastPostLoaded = result.toLowerCase() == "true";
			if (lastPostLoaded) {
				$("#MorePostsBeforeReplyButton").css("visibility", "hidden");
			} else {
				$("#MorePostsBeforeReplyButton").css("visibility", "visible");
				clearInterval(PopForums.replyInterval);
			}
		},
		error: function () {
		}
	});
};

What’s going on here is the creation of an interval timer to keep calling the server and bugging it about new posts, and setting the visibility of a button appropriately. It looks like this if you’re monitoring requests in FireBug:

image

Gross.

The SignalR approach was to call a message broker when a reply was made, and have that broker call back to the listening clients, via a SingalR hub, to let them know about the new post. It seemed weird at first, but the server-side hub’s only method is to add the caller to a group, so new post notifications only go to callers viewing the topic where a new post was made. Beyond that, it’s important to remember that the hub is also the means to calling methods at the client end.

Starting at the server side, here’s the hub:

using Microsoft.AspNet.SignalR.Hubs;

namespace PopForums.Messaging
{
	public class Topics : Hub
	{
		public void ListenTo(int topicID)
		{
			Groups.Add(Context.ConnectionId, topicID.ToString());
		}
	}
}

Have I mentioned how awesomely not complicated this is? The hub acts as the channel between the server and the client, and you’ll see how JavaScript calls the above method in a moment. Next, the broker class and its associated interface:

using Microsoft.AspNet.SignalR;
using Topic = PopForums.Models.Topic;

namespace PopForums.Messaging
{
	public interface IBroker
	{
		void NotifyNewPosts(Topic topic, int lasPostID);
	}

	public class Broker : IBroker
	{
		public void NotifyNewPosts(Topic topic, int lasPostID)
		{
			var context = GlobalHost.ConnectionManager.GetHubContext<Topics>();
			context.Clients.Group(topic.TopicID.ToString()).notifyNewPosts(lasPostID);
		}
	}
}

The NotifyNewPosts method uses the static GlobalHost.ConnectionManager.GetHubContext<Topics>() method to get a reference to the hub, and then makes a call to clients in the group matched by the topic ID. It’s calling the notifyNewPosts method on the client. The TopicService class, which handles the reply data from the MVC controller, has an instance of the broker new’d up by dependency injection, so it took literally one line of code in the reply action method to get things moving.

_broker.NotifyNewPosts(topic, post.PostID);

The JavaScript side of things wasn’t much harder. When you click the reply button (or quote button), the reply window opens up and fires up a connection to the hub:

var hub = $.connection.topics;
hub.client.notifyNewPosts = function (lastPostID) {
	PopForums.setReplyMorePosts(lastPostID);
};
$.connection.hub.start().done(function () {
	hub.server.listenTo(topicID);
});

The important part to look at here is the creation of the notifyNewPosts function. That’s the method that is called from the server in the Broker class above. Conversely, once the connection is done, the script calls the listenTo method on the server, letting it know that this particular connection is listening for new posts on this specific topic ID.

This whole experiment enables a lot of ideas that would make the forum more Facebook-like, letting you know when stuff is going on around you.

Portable class libraries and fetching JSON

After much delay, we finally have the Windows Phone 8 SDK to go along with the Windows 8 Store SDK, or whatever ridiculous name they’re giving it these days. (Seriously… that no one could come up with a suitable replacement for “metro” is disappointing in an otherwise exciting set of product launches.) One of the neat-o things is the potential for code reuse, particularly across Windows 8 and Windows Phone 8 apps.

This is accomplished in part with portable class libraries, which allow you to share code between different types of projects. With some other techniques and quasi-hacks, you can share some amount of code, and I saw it mentioned in one of the Build videos that they’re seeing as much as 70% code reuse. Not bad.

However, I’ve already hit a super annoying snag. It appears that the HttpClient class, with its idiot-proof async goodness, is not included in the Windows Phone 8 class libraries. Shock, gasp, horror, disappointment, etc. The delay in releasing it already caused dismay among developers, and I’m sure this won’t help.

So I started refactoring some code I already had for a Windows 8 Store app (ugh) to accommodate the use of HttpWebRequest instead. I haven’t tried it in a Windows Phone 8 project beyond compiling, but it appears to work.

I used this StackOverflow answer as a starting point since it’s been a long time since I used HttpWebRequest, and keep in mind that it has no exception handling. It needs refinement. The goal here is to new up the client, and call a method that returns some deserialized JSON objects from the Intertubes. Adding facilities for headers or cookies is probably a good next step. You need to use NuGet for a Json.NET reference. So here’s the start:

using System.Net;
using System.Threading.Tasks;
using Newtonsoft.Json;
using System.IO;

namespace MahProject
{
    public class ServiceClient<T> where T : class
    {
        public ServiceClient(string url)
        {
            _url = url;
        }

        private readonly string _url;

        public async Task<T> GetResult()
        {
            var response = await MakeAsyncRequest(_url);
            var result = JsonConvert.DeserializeObject<T>(response);
            return result;
        }

        public static Task<string> MakeAsyncRequest(string url)
        {
            var request = (HttpWebRequest)WebRequest.Create(url);
            request.ContentType = "application/json";
            Task<WebResponse> task = Task.Factory.FromAsync(
                request.BeginGetResponse,
                asyncResult => request.EndGetResponse(asyncResult),
                null);
            return task.ContinueWith(t => ReadStreamFromResponse(t.Result));
        }

        private static string ReadStreamFromResponse(WebResponse response)
        {
            using (var responseStream = response.GetResponseStream())
                using (var reader = new StreamReader(responseStream))
                {
                    var content = reader.ReadToEnd();
                    return content;
                }
        }
    }
}

Calling it in some kind of repository class may look like this, if you wanted to return an array of Park objects (Park model class omitted because it doesn’t matter):

public class ParkRepo
{
    public async Task<Park[]> GetAllParks()
    {
        var client = new ServiceClient<Park[]>(http://superfoo/endpoint);
        return await client.GetResult();
    }
}

And then from inside your WP8 or W8S app (see what I did there?), when you load state or do some kind of UI event handler (making sure the method uses the async keyword):

var parkRepo = new ParkRepo();
var results = await parkRepo.GetAllParks();
// bind results to some UI or observable collection or something

Hopefully this saves you a little time.

Review: Microsoft Surface RT

Being the ever cautious fan of technology, I ordered a Surface RT within minutes of it going live on Microsoft’s store. I received it Friday, and spent the weekend with it, and wrote a review. I posted that review on my personal blog.

TL;DR: It’s a pretty cool device, but has spots of weirdness that need to be addressed.

.NET development on Macs

I posted the “exciting” conclusion of my laptop trade-ins and issues on my personal blog. The links, in chronological order, are posted below. While those posts have all of the details about performance and software used, I wanted to comment on why I like using Macs in the first place.

It started in 2006 when Apple released the first Intel-based Mac. As someone with a professional video past, I had been using Macs on and off since college (1995 graduate), so I was never terribly religious about any particular platform. I’m still not, but until recently, it was staggering how crappy PC’s were. They were all plastic, disposable, commodity crap. I could never justify buying a PowerBook because I was a Microsoft stack guy. When Apple went Intel, they removed that barrier. They also didn’t screw around with selling to the low end (though the plastic MacBooks bordered on that), so even the base machines were pretty well equipped. Every Mac I’ve had, I’ve used for three years. Other than that first one, I’ve also sold each one, for quite a bit of money.

Things have changed quite a bit, mostly within the last year. I’m actually relieved, because Apple needs competition at the high end. Other manufacturers are finally understanding the importance of industrial design. For me, I’ll stick with Macs for now, because I’m invested in OS X apps like Aperture and the Mac versions of Adobe products. As a Microsoft developer, it doesn’t even matter though… with Parallels, I Cmd-Tab and I’m in Windows.

So after three and a half years with a wonderful 17” MBP and upgraded SSD, it was time to get something lighter and smaller (traveling light is critical with a toddler), and I eventually ended up with a 13” MacBook Air, with the i7 and 8 gig upgrades, and I love it. At home I “dock” it to a Thunderbolt Display.

From HttpRuntime.Cache to Windows Azure Caching (Preview)

I don’t know about you, but the announcement of Windows Azure Caching (Preview) (yes, the parentheses are apparently part of the interim name) made me a lot more excited about using Azure. Why? Because one of the great performance tricks of any Web app is to cache frequently used data in memory, so it doesn’t have to hit the database, a service, or whatever.

When you run your Web app on one box, HttpRuntime.Cache is a sweet and stupid-simple solution. Somewhere in the data fetching pieces of your app, you can see if an object is available in cache, and return that instead of hitting the data store. I did this quite a bit in POP Forums, and it dramatically cuts down on the database chatter. The problem is that it falls apart if you run the app on many servers, in a Web farm, where one server may initiate a change to that data, and the others will have no knowledge of the change, making it stale. Of course, if you have the infrastructure to do so, you can use something like memcached or AppFabric to do a distributed cache, and achieve the caching flavor you desire.

You could do the same thing in Azure before, but it would cost more because you’d need to pay for another role or VM or something to host the cache. Now, you can use a portion of the memory from each instance of a Web role to act as that cache, with no additional cost. That’s huge. So if you’re using a percentage of memory that comes out to 100 MB, and you have three instances running, that’s 300 MB available for caching. For the uninitiated, a Web role in Azure is essentially a VM that runs a Web app (worker roles are the same idea, only without the IIS part). You can spin up many instances of the role, and traffic is load balanced to the various instances. It’s like adding or removing servers to a Web farm all willy-nilly and at your discretion, and it’s what the cloud is all about. I’d say it’s my favorite thing about Windows Azure.

The slightly annoying thing about developing for a Web role in Azure is that the local emulator that’s launched by Visual Studio is a little on the slow side. If you’re used to using the built-in Web server, you’re used to building and then alt-tabbing to your browser and refreshing a page. If you’re just changing an MVC view, you’re not even doing the building part. Spinning up the simulated Azure environment is too slow for this, but ideally you want to code your app to use this fantastic distributed cache mechanism.

So first off, here’s the link to the page showing how to code using the caching feature. If you’re used to using HttpRuntime.Cache, this should be pretty familiar to you. Let’s say that you want to use the Azure cache preview when you’re running in Azure, but HttpRuntime.Cache if you’re running local, or in a regular IIS server environment. Through the magic of dependency injection, we can get there pretty quickly.

First, design an interface to handle the cache insertion, fetching and removal. Mine looks like this:

public interface ICacheProvider
{
    void Add(string key, object item, int duration);
    T Get<T>(string key) where T : class;
    void Remove(string key);
}

Now we’ll create two implementations of this interface… one for Azure cache, one for HttpRuntime:

public class AzureCacheProvider : ICacheProvider
{
    public AzureCacheProvider()
    {
        _cache = new DataCache("default"); // in Microsoft.ApplicationServer.Caching, see how-to 
    }
   
    private readonly DataCache _cache;
    public void Add(string key, object item, int duration)
    {
        _cache.Add(key, item, new TimeSpan(0, 0, 0, 0, duration));
    }
   
public T Get<T>(string key) where T : class
    {
        return _cache.Get(key) as T;
    }
    public void Remove(string key)
    {
        _cache.Remove(key);
    }
}

public class LocalCacheProvider : ICacheProvider
{
    public LocalCacheProvider()
    {
        _cache = HttpRuntime.Cache;
    }
    private readonly System.Web.Caching.Cache _cache;
    public void Add(string key, object item, int duration)
    {
        _cache.Insert(key, item, null, DateTime.UtcNow.AddMilliseconds(duration), System.Web.Caching.Cache.NoSlidingExpiration);
    }
    public T Get<T>(string key) where T : class
    {
        return _cache[key] as T;
    }
    public void Remove(string key)
    {
        _cache.Remove(key);
    }
}

Feel free to expand these to use whatever cache features you want.

I’m not going to go over dependency injection here, but I assume that if you’re using ASP.NET MVC, you’re using it. Somewhere in your app, you set up the DI container that resolves interfaces to concrete implementations (Ninject call is a “kernel” instead of a container). For this example, I’ll show you how StructureMap does it. It uses a convention based scheme, where if you need to get an instance of IFoo, it looks for a class named Foo. You can also do this mapping explicitly. The initialization of the container looks something like this:

ObjectFactory.Initialize(x =>
            {
                x.Scan(scan =>
                        {
                            scan.AssembliesFromApplicationBaseDirectory();
                            scan.WithDefaultConventions();
                        });
                if (Microsoft.WindowsAzure.ServiceRuntime.RoleEnvironment.IsAvailable)
                    x.For<ICacheProvider>().Use<AzureCacheProvider>();
                else
                    x.For<ICacheProvider>().Use<LocalCacheProvider>();
            });

If you use Ninject or Windsor or something else, that’s OK. Conceptually they’re all about the same. The important part is the conditional statement that checks to see if the app is running in Azure. If it is, it maps ICacheProvider to AzureCacheProvider, otherwise it maps to LocalCacheProvider.

Now when a request comes into your MVC app, and the chain of dependency resolution occurs, you can see to it that the right caching code is called. A typical design may have a call stack that goes: Controller –> BusinessLogicClass –> Repository. Let’s say your repository class looks like this:

public class MyRepo : IMyRepo
{
    public MyRepo(ICacheProvider cacheProvider)
    {
        _context = new MyDataContext();
        _cache = cacheProvider;
    }

    private readonly MyDataContext _context;
    private readonly ICacheProvider _cache;

    public SomeType Get(int someTypeID)
    {
        var key = "somename-" + someTypeID;
        var cachedObject = _cache.Get<SomeType>(key);
        if (cachedObject != null)
        {
            _context.SomeTypes.Attach(cachedObject);
            return cachedObject;
        }
        var someType = _context.SomeTypes.SingleOrDefault(p => p.SomeTypeID == someTypeID);
        _cache.Add(key, someType, 60000);
        return someType;
    }
... // more stuff to update, delete or whatever, being sure to remove
// from cache when you do so
 

When the DI container gets an instance of the repo, it passes an instance of ICacheProvider to the constructor, which in this case will be whatever implementation was specified when the container was initialized. The Get method first tries to hit the cache, and of course doesn’t care what the underlying implementation is, Azure, HttpRuntime, or otherwise. If it finds the object, it returns it right then. If not, it hits the database (this example is using Entity Framework), and inserts the object into the cache before returning it.

The important thing not pictured here is that other methods in the repo class will construct the key for the cached object, in this case “somename-“ plus the ID of the object, and then remove it from cache, in any method that alters or deletes the object. That way, no matter what instance of the role is processing the request, it won’t find the object if it has been made stale, that is, updated or outright deleted, forcing it to attempt to hit the database.

So is this good technique? Well, sort of. It depends on how you use it, and what your testing looks like around it. Because of differences in behavior and execution of the two caching providers, for example, you could see some strange errors. For example, I immediately got an error indicating there was no parameterless constructor for an MVC controller, because the DI resolver failed to create instances for the dependencies it had. In reality, the NuGet packaged DI resolver for StructureMap was eating an exception thrown by the Azure components that said my configuration, outlined in that how-to article, was wrong. That error wouldn’t occur when using the HttpRuntime.

That’s something a lot of people debate about using different components like that, and how you configure them. I kinda hate XML config files, and like the idea of the code-based approach above, but you should be darn sure that your unit and integration testing can account for the differences.

Software development is (mostly) a trade, and what to do about it

(This is another cross-post from my personal blog. I don’t even remember when I first started to write it, but I feel like my opinion is well enough baked to share.)

I've been sitting on this for a long time, particularly as my opinion has changed dramatically over the last few years. That I've encountered more crappy code than maintainable, quality code in my career as a software developer only reinforces what I'm about to say.

Software development is just a trade for most, and not a huge academic endeavor.

For those of you with computer science degrees readying your pitchforks and collecting your algorithm interview questions, let me explain. This is not an assault on your way of life, and if you've been around, you know I'm right about the quality problem. You also know the HR problem is very real, or we wouldn't be paying top dollar for mediocre developers and importing people from all over the world to fill the jobs we can't fill.

I'm going to try and outline what I see as some of the problems, and hopefully offer my views on how to address them.

The recruiting problem

I think a lot of companies are doing it wrong. Over the years, I've had two kinds of interview experiences. The first, and right, kind of experience involves talking about real life achievements, followed by some variation on white boarding in pseudo-code, drafting some basic system architecture, or even sitting down at a comprooder and pecking out some basic code to tackle a real problem. I can honestly say that I've had a job offer for every interview like this, save for one, because the task was to debug something and they didn't like me asking where to look ("everyone else in the company died in a plane crash").

The other interview experience, the wrong one, involves the classic torture test designed to make the candidate feel stupid and do things they never have, and never will do in their job. First they will question you about obscure academic material you've never seen, or don't care to remember. Then they'll ask you to white board some ridiculous algorithm involving prime numbers or some kind of string manipulation no one would ever do. In fact, if you had to do something like this, you'd Google for a solution instead of waste time on a solved problem.

Some will tell you that the academic gauntlet interview is useful to see how people respond to pressure, how they engage in complex logic, etc. That might be true, unless of course you have someone who brushed up on the solutions to the silly puzzles, and they're playing you.

But here's the real reason why the second experience is wrong: You're evaluating for things that aren't the job. These might have been useful tactics when you had to hire people to write machine language or C++, but in a world dominated by managed code in C#, or Java, people aren't managing memory or trying to be smarter than the compilers. They're using well known design patterns and techniques to deliver software.

More to the point, these puzzle gauntlets don't evaluate things that really matter. They don't get into code design, issues of loose coupling and testability, knowledge of the basics around HTTP, or anything else that relates to building supportable and maintainable software. The first situation, involving real life problems, gives you an immediate idea of how the candidate will work out. One of my favorite experiences as an interviewee was with a guy who literally brought his work from that day and asked me how to deal with his problem. I had to demonstrate how I would design a class, make sure the unit testing coverage was solid, etc. I worked at that company for two years.

So stop looking for algorithm puzzle crunchers, because a guy who can crush a Fibonacci sequence might also be a guy who writes a class with 5,000 lines of untestable code. Fashion your interview process on ways to reveal a developer who can write supportable and maintainable code. I would even go so far as to let them use the Google. If they want to cut-and-paste code, pass on them, but if they're looking for context or straight class references, hire them, because they're going to be life-long learners.

The contractor problem

I doubt anyone has ever worked in a place where contractors weren't used. The use of contractors seems like an obvious way to control costs. You can hire someone for just as long as you need them and then let them go. You can even give them the work that no one else wants to do.

In practice, most places I've worked have retained and budgeted for the contractor year-round, meaning that the $90+ per hour they're paying (of which half goes to the person) would have been better spent on a full-time person with a $100k salary and benefits.

But it's not even the cost that is an issue. It's the quality of work delivered. The accountability of a contractor is totally transient. They only need to deliver for as long as you keep them around, and chances are they'll never again touch the code. There's no incentive for them to get things right, there's little incentive to understand your system or learn anything. At the risk of making an unfair generalization, craftsmanship doesn't matter to most contractors.

The education problem

I don't know what they teach in college CS courses. I've believed for most of my adult life that a college degree was an essential part of being successful. Of course I would hold that bias, since I did it, and have the paper to show for it in a box somewhere in the basement. My first clue that maybe this wasn't a fully qualified opinion comes from the fact that I double-majored in journalism and radio/TV, not computer science. Eventually I worked with people who skipped college entirely, many of them at Microsoft. Then I worked with people who had a masters degree who sucked at writing code, next to the high school diploma types that rock it every day. I still think there's a lot to be said for the social development of someone who has the on-campus experience, but for software developers, college might not matter.

As I mentioned before, most of us are not writing compilers, and we never will. It's actually surprising to find how many people are self-taught in the art of software development, and that should reveal some interesting truths about how we learn. The first truth is that we learn largely out of necessity. There's something that we want to achieve, so we do what I call just-in-time learning to meet those goals. We acquire knowledge when we need it.

So what about the gaps in our knowledge? That's where the most valuable education occurs, via our mentors. They're the people we work next to and the people who write blogs. They are critical to our professional development. They don't need to be an encyclopedia of jargon, but they understand the craft. Even at this stage of my career, I probably can't tell you what SOLID stands for, but you can bet that I practice the principles behind that acronym every day. That comes from experience, augmented by my peers. I'm hell bent on passing that experience to others.

Process issues

If you're a manager type and don't do much in the way of writing code these days (shame on you for not messing around at least), then your job is to isolate your tradespeople from nonsense, while bringing your business into the realm of modern software development. That doesn't mean you slap up a white board with sticky notes and start calling yourself agile, it means getting all of your stakeholders to understand that frequent delivery of quality software is the best way to deal with change and evolving expectations.

It also means that you have to play technical overlord to make sure the education and quality issues are dealt with. That's why I make the crack about sticky notes, because without the right technique being practiced among your code monkeys, you're just a guy with sticky notes. You're asking your business to accept frequent and iterative delivery, now make sure that the folks writing the code can handle the same thing. This means unit testing, the right instrumentation, integration tests, automated builds and deployments... all of the stuff that makes it easy to see when change breaks stuff.

The prognosis

I strongly believe that education is the most important part of what we do. I'm encouraged by things like The Starter League, and it's the kind of thing I'd love to see more of. I would go as far as to say I'd love to start something like this internally at an existing company.

Most of all though, I can't emphasize enough how important it is that we mentor each other and share our knowledge. If you have people on your staff who don't want to learn, fire them. Seriously, get rid of them. A few months working with someone really good, who understands the craftsmanship required to build supportable and maintainable code, will change that person forever and increase their value immeasurably.

.NET development on a Retina MacBook Pro with Windows 8

I remember sitting in Building 5 at Microsoft with some of my coworkers, when one of them came in with a shiny new 11” MacBook Air. It was nearly two years ago, and we found it pretty odd that the OEM’s building Windows machines sucked at industrial design in a way that defied logic. While Dell and HP were in a race to the bottom building commodity crap, Apple was staying out of the low-end market completely, and focusing on better design. In the process, they managed to build machines people actually wanted, and maintain an insanely high margin in the process.

I stopped buying the commodity crap and custom builds in 2006, when Apple went Intel. As a .NET guy, I was still in it for Microsoft’s stack of development tools, which I found awesome, but had back to back crappy laptops from HP and Dell. After that original 15” MacBook Pro, I also had a Mac Pro tower (that I sold after three years for $1,500!), a 27” iMac, and my favorite, a 17” MacBook Pro (the unibody style) with an SSD added from OWC.

The 17” was a little much to carry around because it was heavy, but it sure was nice getting as much as eight hours of battery life, and the screen was amazing. When the rumors started about a 15” model with a “retina” screen inspired by the Air, I made up my mind I wanted one, and ordered it the day it came out. I sold my 17”, after three years, for $750 to a friend who is really enjoying it.

I got the base model with the upgrade to 16 gigs of RAM. It feels solid for being so thin, and if you’ve used the third generation iPad or the newer iPhone, you’ll be just as thrilled with the screen resolution. I’m typically getting just over six hours of battery life while running a VM, but Parallels 8 allegedly makes some power improvements, so we’ll see what happens. (It was just released today.)

The nice thing about VM’s are that you can run more than one at a time. Primarily I run the Windows 8 VM with four cores (the laptop is quad-core, but has 8 logical cores due to hyperthreading or whatever Intel calls it) and 8 gigs of RAM. I also have a Windows Server 2008 R2 VM I spin up when I need to test stuff in a “real” server environment, and I give it two cores and 4 gigs of RAM.

The Windows 8 VM spins up in about 8 seconds. Visual Studio 2012 takes a few more seconds, but count part of that as the “ReSharper tax” as it does its startup magic. The real beauty, the thing I looked most forward to, is that beautifully crisp C# text. Consolas has never looked as good as it does at 10pt. as it does on this display. You know how it looks great at 80pt. when conference speakers demo stuff on a projector? Think that sharpness, only tiny. It’s just gorgeous.

Beyond that, everything is just so responsive and fast. Builds of large projects happen in seconds, hundreds of unit tests run in seconds… you just don’t spend a lot of time waiting for stuff. It’s kind of painful to go back to my 27” iMac (which would be better if I put an SSD in it before its third birthday).

Are there negatives? A few minor issues, yes. As is the case with OS X, not everything scales right. You’ll see some weirdness at times with splash screens and icons and such. Chrome’s text rendering (in Windows) is apparently not aware of how to deal with higher DPI’s, so text is fuzzy (the OS X version is super sharp, however). You’ll also have to do some fiddling with keyboard settings to use the Windows 8 keyboard shortcuts.

Overall, it’s as close to a no-compromise development experience as I’ve ever had. I’m not even going to bother with Boot Camp because the VM route already exceeds my expectations. You definitely get what you pay for. If this one also lasts three years and I can turn around and sell it, it’s worth it for something I use every day.

Win8VMinParallels

POP Forums v10 for ASP.NET MVC 4 posted to CodePlex

Download it here!

This is the RTW source for POP Forums v10, with the mobile special sauce. It requires ASP.NET MVC 4 RTM, which you can download here. The project and solution files require Visual Studio 2010 or 2012. If you need an MVC3 version, please enjoy v9.2.1 The database has been tested and known to work on SQL Server 2008 and later, as well as Windows Azure SQL Database. The app runs great in Windows Azure Web Sites. Of course, feel free to submit bugs to the issue tracker.

See a live demo here: http://popforums.com/Forums

Read the documentation for installation and integration.

While the app will run fine on .NET 4.5, you'll need to replace the Ninject reference to the 4.5 build (go to Ninject.org to get it) and change the target framework in each project to 4.5.

Upgrading?

You can mostly just replace the files, though /Areas/PopForums/Home has been replaced by /Areas/PopForums/ForumHome. The database is unchanged from v9.2.x. If you're upgrading from v9.0.x or v9.1.x, please see the scripts included in the SQL data project.

What's new?

  • Uses a very light weight CSS and Javascript package to provide a touch-friendly interface for mobile devices.
  • Numbers are formatted (sensitive to culture) when 1,000 or higher.
  • CSS is more integration friendly, and specific to the ForumContainer element.
  • Mail delivery from queue is now parallel, so you can specify a sending interval, and the number of messages to process on each interval.
  • Background "services" refactored, and will only run with a call on app start to PopForumsActivation.StartServices(). This is partly to facilitate future use in Web farms/multiple Web roles in Azure.
  • Update to jQuery v1.7.1.
  • Replaced use of .live() with .on() in script, pursuant to jQuery update, which deprecates .live().
  • Renamed HomeController to ForumHomeController, to make lives easier when integrating into an MVC app.
  • Dependency resolution no longer requires that you set Ninject as the container for the entire MVC app. The controllers now resolve their dependencies in their constructors, so you're free to set up any DI container in your global.asax.
  • The included single-server SQL data layer now uses the base classes and interfaces for (DbConnection, DbCommand, etc.) instead of the specific SQL flavors, for easier refactoring in case you want to build an Oracle version or something.
  • FIX: Bug in topic repository around caching keys for single-server data layer.
  • FIX: Pager links on recent topics pointed to incorrect route.
  • FIX: Deleting a post didn't update last user/post time.
  • FIX: Ditched attempt at writing to event log with super failures, since almost no one has permission in production.
  • FIX: Bug in grayed-out fields in admin mail setup.
  • FIX: Weird color profiles would break loading of images for resize.
  • FIX: TOS text on account sign-up was double encoded.

Known issues

  • A potential race condition exists that could prevent the app from starting in ASP.NET v4.5. See the issue:ServiceModule has potential race condition in ASP.NET v4.5
  • There is apparently a bug in the MVC 4 framework around the internal caching of views (not output cache, but instances of the views). You can read about it here. Because you probably get fewer requests that result in mobile views, it's possible that these expire from the cache and the framework falls back to the standard views. This will break POP Forums because the mobile views have an extra section for the pullout menu. The fix is described in the issue tracker link, and it requires adding a line to your global.asax. We're waiting to see how the MVC team handles this before committing any new code.
A debugging experience with "highly compatible" ASP.NET 4.5

I have to admit that I will pretty much upgrade software for no reason other than being on the latest version. I won't do it if it's super expensive (Adobe gets money from me about once every three or four years at best), but particularly with frameworks and stuff generally available as part of my MSDN subscription, I'll be bleeding edge. CoasterBuzz was running on the MVC 4 framework pretty much as soon as they did a "go live" license for it.

I didn't really jump in head-first with Windows 8 and Visual Studio 2012, in part because I just wasn't interested in doing the reinstalls for each new version. Turns out there weren't that many revisions anyway. But when the final versions were released a week and a half ago, I jumped in.

I saw on one of the Microsoft sites that .Net 4.5 was a "highly compatible in-place update" to the framework. Good enough for me. I was obviously running it by default in Windows 8, and installed it on my production server. I suppose it's "highly compatible," except when it isn't.

Three of my sites are running with various flavors of the MVC version of POP Forums. All of them stopped working under ASP.NET 4.5. It was not immediately obvious what the problem might be beyond an exception indicating that there were no repository classes registered with Ninject, which I use for dependency injection in the forums. This was made all the more weird by the fact that it ran fine locally in the dev Web host.

My first instinct was to spin up a Windows Server VM on my local box and put the remote debugger on it. (Side note: running multiple VM's on a Retina MacBook Pro with 16 gigs of RAM is pretty much the most awesome thing ever. I can't believe this computer is for real, and not a 50-pound tower under my desk.) What might have been going on in IIS that doesn't happen in Visual Studio?

In the debugging process, I realized that I might be looking in the wrong place. POP Forums creates a Ninject container using a method called from a PreApplicationStartMethod attribute, and at that time registers a module (what Ninject uses to map interfaces to implementations) that maps all of the core dependencies. It also creates an instance of an HttpModule that originally hosted the "services" (search indexing, mailer, etc.), but now just records errors.

That's all well and good, but the actual repository mapping, where data is actually read or persisted, happens in Application_Start() in global.asax. The idea there is that you can swap out the SqlSingleWebServer repos for something tuned for multiple servers, Oracle or something else. Of course, if I used something like StructureMap, which does convention-based mapping for dependency injection (a class implementing ISettingsRepository called SettingsRepository is automagically mapped), I wouldn't have to worry about it.

In any case, the HttpModule, being instantiated before Application_Start() gets to run, would throw because there was no repo mapped where it could get settings from the database. This makes total sense. The fix is sort of a hack, where I don't setup the innards of the HttpModule until a call to its BeginRequest is made. I say it's a hack, because its primary function, logging exceptions, won't work until the app has warmed up.

Still, this brings up an interesting question about the race condition, and what changed in 4.5 when it's running in IIS. In ASP.NET 4, it would appear that the code called via the PreApplicationStartMethod was either failing silently, and running again later, or it was getting to that code after Application_Start was called.

In any case, weird thing. The real pain point I'm experiencing now is a bug in MVC 4 that is extremely serious because it renders the mobile/alternate view functionality very much broken.

Recruiterisms

Once you get your name out there in the world of software, you’re pretty much out there for eternity. This means that your name and contact details will find their way into the databases of recruiters and staffing firms everywhere.

The truth is that it’s good to be “loved,” but as is the case with dating, it doesn’t mean that you’ll get what you need. After being at this for more than a dozen years, working at everything from a tiny private company up to the Microsoft mothership, it’s interesting to note that all of my best jobs came from either me applying for them, or being contacted directly from the hiring company. In other words, staffing firms have yet to offer any real value for me. There is one that got me close to a good find, until the company decided to promote someone internally.

In any case, if you’re a recruiter, and especially a recruiter for a staffing firm, here are some helpful tips.

  • “I came across your resume.” Of course you did. And because every recruiter starts every phone call or e-mail this way, I associate the phrase with the usual outcome: “I haven’t bothered to look if the required skills for this gig I can’t fill match your own, but let’s talk.”
  • You wouldn’t pitch a solution architect job to a junior developer, so why do you pitch junior developer jobs to solution architects? If you have the resume in front of you, I think you can gauge where the person is in their career.
  • Keyword matches suck. It appears now that some firms gather huge amounts of candidate profiles, match them with keywords for job openings, and then farm out cold calls to a call center in India. No one ever looks deeper to see if there’s a good match, so a huge amount of noise is created. You know what? It all sounds the same, and I ignore the noise.
  • Geography. I understand that there is a segment of the population happy to just move anywhere at any time to pick up some crappy contract job. All the more reason you’ll get black listed if you pitch a non-remote job in Madison or Phoenix to me in Cleveland. Not only will I not do it, but this “class” of developer is responsible for a huge amount of the crap out in production systems, devoid of any craftsmanship or maintainability. It’s the difference between eHarmony and AdultFriendFinder.
  • The money doesn’t matter, except when it does. People in our line of work want to be paid what they’re worth, and frankly it shouldn’t be a big part of the conversation. Markets with shallow talent pools in particular work to the workers’ advantage. Make sure your clients understand this.
  • If you can’t be up front about who the company is, or where they’re located, don’t bother. I understand why you may want to keep that information, but none of those concerns are shared by the person you want to get hired. Remember, you’re likely competing with a dozen other calls Joe Software had this week.
  • E-mail. Software people (the good ones, at least) are all about making things efficient. Calling them with vague statements about an “exciting opportunity” is a total waste of time. Phone tag is a waste of time. We want to filter out the crap quickly, and we can’t do that if we have to call. It’s inefficient. If you want to have a nice relationship and take us out to lunch, great, but don’t be inefficient. It’s absurd to leave a voicemail message and not e-mail in 2012.
  • If you want me to take a test on whether or not I know some obscure method in the .NET Framework, you probably don’t get it, and I won’t talk to you. I have an open source project with over 20,000 lines of code that you or your client can look at. I have stuff in production on the Web. Let’s talk about what’s real.

Putting all of that aside for a moment, let me frame the most important thing you have to do. You absolutely must make us understand why the job is interesting. I want to work with great people, I want to be fairly compensated, I want a solid culture that is results-oriented and not about face time, but more than anything, I want work that is interesting. That’s what gets me out of bed in the morning.

I married my wife because she’s interesting. I had a child because parenthood is interesting. I like video and photography because it’s interesting. I ride roller coasters because the machines are interesting. There isn’t much I do in life that wouldn’t qualify as interesting. Why would I want to do work that isn’t interesting? That’s the key not just for recruitment, but for retention.

More Posts « Previous page - Next page »