james mckay dot net
because there are few things that are less logical than business logic

Posts tagged: C#

First impressions of MSpec

For several years now, I’ve used Gallio and MbUnit for unit testing, but just the other day I was introduced to MSpec. I’ve been posting some of my initial thoughts about it on Twitter and I thought I’d better expand on them here. The idea is that you should be able to express your tests succinctly in a language that is supposedly closer to English than to C#.

Something like this:

[Subject(typeof(LogoController))]
public class when_index_action_is_invoked
{
    static LogoController controller;
    static ViewResult result;

    Establish context = () => {
        controller = new LogoController();
    };

    Because of = () => result = controller.Index();

    It should_return_a_ViewResult_with_default_view_name = () => {
        result.ViewName.ShouldBeEmpty();
    };
}

Whoa there. Just what’s going on here?

Whatever it’s doing, it completely subverts the C# language, gives the finger to Resharper and StyleCop, and throws out every best practice and coding convention in the book. Multiple classes per file. All lower-case names, with underscores. And for class and class property names, which should be nouns, you get verbs (Establish), pronouns (It) and prepositions (Because of). It’s like waking up one morning and discovering that the word “the” is no longer the definite article, but now means Gatwick Airport.

When I see code like this, it reminds me of one thing in particular.

Why’s (Poignant) Guide to Ruby.

Chunky bacon!Now I’ve no idea where Joel Spolsky got the idea that Python is for Asperger’s geeks, but he was definitely onto something when he said that Ruby is for tear-streaked emo teenagers, because the Poignant Guide is the very manifesto for that particular stereotype. With the aid of talking cartoon foxes making inexplicable remarks about chunky bacon, _why devotes 176 pages to the thesis that if your code looks sufficiently like English, it automatically qualifies as a Mills and Boon novel.

I say this because MSpec was, in fact, heavily influenced by RSpec, a similar framework for Ruby, and I can’t help getting the impression that throwing out all the .NET conventions looks like an attempt to make C# look more like Ruby — in a kind of Ruby-that-tries-to-look-like-English way.

The principles behind MSpec seem sound enough. A typical unit test should have three phases to it: Arrange (set up your sample data and context), Act (carry out the action under test), and Assert (make sure that you get the correct results). MSpec represents these as the Establish, Because of, and It clauses respectively. One advantage is that every assertion is treated as a separate test, so you can have multiple Asserts for a single context and action, and see their outcomes separately in your reports.

Is it any better than the conventional way of writing tests? One of the claims of MSpec is that it is designed to reduce noise in tests. I’m not sure that it does. In effect, each MSpec class performs the same work as a single test method in MbUnit, and in fact the framework is coercing a C# class to behave as if it were a function. This, along with lower case identifiers with underscores, and multiple classes per file, look like examples of dragging Ruby conventions kicking and screaming into the .NET world, and this inevitably introduces a lot of cognitive dissonance, which can be quite confusing until you’ve figured out what’s going on. It also makes me worry how many leaky abstractions are involved, and I doubt if it reduces the amount of code that you have to write overall.

Long lines are another thing that worry me — the MSpec best practices say that you should have only one line of code in your Because and It clauses, and as a result, some of the MSpec code I’ve encountered extends well past 80 columns. I hate long lines of code with a passion because having to scroll left and right all the time dramatically reduces readability and makes it much harder to diff your code in source control.

Of course, these are just my initial impressions. Perhaps in a few months’ time, you may find me in slim-fit jeans and a tight T-shirt, my eyes hidden behind long side-swept bangs, and tears streaming down my cheeks at the poignancy of MSpec. But as far as I can see at the moment, it’s a bit of an acquired taste.

Keep the number of projects in your solution to a minimum

There are a lot of common practices among .NET developers that get touted as “best practices” although they are nothing of the sort. A lot of them seem to be leftovers from the days about ten years ago when there was a lot of hype about n-tier although the people promoting n-tier didn’t properly understand the problems that n-tier was supposedly trying to solve. One such example is too many projects in a single solution.

In general, you should always aim to keep the number of projects in your solution to an absolute minimum. For a simple web application, your solution requires exactly two projects: the application itself and your unit tests. For an application with a web front end and a console application, your solution requires four projects: the shared components, the web front end, the console application, and your unit tests. Products that deploy different applications to different servers may need one or two more for shared components, for instance, but the number should still be kept as small as possible.

Your solution does not — I repeat, does not — require separate projects for your controllers, your model, your business services, your repository, your shared components, your interfaces, and your wrappers round third party web services.

Your solution does not require multiple unit test projects. Some people create a separate unit test project for every main project in their solution. This is completely unnecessary: why not have a single unit test project for all of them? Of course, it may be worth having one project for fast unit tests, and another one for slower tests that need to run against a database, but over and above that, reasons for creating extra test projects are few and far between.

Your solution does not require multiple front end applications of the same type for deployment on the same server. You may need a back-end admin application on one server and a front-end public facing website on another, but you don’t need two back-end admin web applications for the same solution.

There are three reasons why too many assemblies are harmful:

1. Too many assemblies slow down compilation. When you have to compile a single project that references thirty external dependencies, the C# compiler only has to pull in these referenced assemblies once. When you have to compile thirty projects that reference thirty external dependencies each, the C# compiler has to pull in all thirty dependencies every time — a grand total of nine hundred referenced assemblies. This adds a lot of time onto your edit-compile-test-loop, which in turn knocks you right out of the zone and makes the whole development process feel like wading through treacle.

2. Too many assemblies make dependency management a pain. If you have to add a third party reference to thirty different projects, it is a massive, painful violation of DRY. If you have to swap out one reference for another, it is painful. If you have to add a third party reference to only a subset of those thirty, it is even more painful because you have to work out which assemblies require it and which don’t. And don’t even get me started on the problems you might face if you end up with two different projects referencing the same assembly from two different places within the bowels of your third party dependencies directory.

3. Too many front-end projects in particular make configuration and release management a pain. If you have two web front end projects for deployment on the same server, you have to configure them both together and deploy them both together. The more configuration you have to manage, the greater your risk of making a mistake. When you add a new configuration option, you have to update several different applications, and you increase the risk that you might miss one. If you have to change Copy Local from False to True for some assembly or other, you have to go through all your front end applications to make sure this is done correctly. Again, it’s a violation of DRY.

The main reason why people advocate a lot of projects in their solution is to attempt to keep the different logical parts of their code separate, so, for instance, they aren’t referencing System.Web from within the data access layer, or the data access layer directly from the UI, and they aren’t introducing circular dependencies. In practice, it simply isn’t worth it. If dependencies between your classes and namespaces really bothers you, a far simpler alternative is to buy a licence for NDepend instead. Certainly, you should have a very, very good reason to add a new project to your solution, and you should look to see what you can consolidate wherever you can.