Robust Software

Tales of a code samurai

Why Rack Should Matter to .NET Developers

There’s been a lot of talk in the .NET community about Sinatra clones, namely Nancy and Nina in recent times but there are several others as well. Unfortunately, all these frameworks are missing the underlying reason that Sinatra is awesome and that is Rack. Sinatra packs a hell of a lot of functionality yet weighs in at 1198 lines of code including documentation. The main reason for that is the fact it is building on top of Rack which has allowed the authors to concentrate on creating a framework without having to worry about the details of dealing with server requests. So what is Rack, why you should care and why does it matter to you as a .NET developer.

What is Rack?

Rack is a layer of abstraction which sits between servers and frameworks. What it brings as a result is greater interoperability between HTTP server implementations and web frameworks. As the author of a HTTP server if you get your server to speak Rack you can now host applications written in several Ruby frameworks, Sinatra and Rails being two of the most well known. As a web framework author if you get your framework to speak Rack your application can now be hosted on several types of HTTP server.

This greatly reduces the barrier to adoption for both servers and frameworks. Rather than the previous method of having to write an adapter for each server or framework you wished to be compatible with; you are now able to write a single adapter for Rack and be hosted by several types of server or host multiple frameworks depending on which side of the boundary you are sitting.

Needless to say, the Ruby community has jumped all over this. It removes the duplication of effort that was previously required to get the same level of interoperability allowing the Ruby community to focus on innovation. For example, Sinatra did not exist before Rack. Rack didn’t make Sinatra possible but it made it much easier to create. Dealing with HTTP servers had been done for them. They could instead focus on turning requests into responses in an elegant manner.

Why should you care?

First, lets talk about testing. Rack is entirely Ruby based at its core. That means that when you are testing your application you can mimic a real HTTP request being invoked and see what response your application turns that into. Let me show you an example of that being done using RSpec against a simple Sinatra application:

1
2
3
get '/hello/:person' do |person|
  "Hello, #{person}"
end

We can test how that application will respond to a HTTP request using RSpec:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
describe Server, 'making a hello request' do
  include Rack::Test::Methods

  let(:app) {subject}

  describe 'saying hello to world' do
    before do
      get '/hello/world'
    end

    it 'should respond "Hello, world"' do
      last_response.body.should == 'Hello, world'
    end
  end
end

I have commented the full source for these examples up on Github if you want further explanation of what is happening here.

We’ve just written an integration test for our application without having to deploy to a server or create our own abstraction of HTTP. This same type of test will work for any application written using a Rack-based framework. Just think of how painful the same thing is in .NET currently. Not only does Rack give us greater interoperability between servers and frameworks, it gives us a way to test them easily as well.

Rack also has the concept of middleware. These are modules built on top of Rack that can then be utilised by any application based upon Rack. This again reduces duplication of effort within the community. Things that can be implemented in the Rack layer, for example caching, are and that removes the need for functional clones for each Rack-based framework that wants the same functionality.

Why it matters to you as a .NET developer

If you’re thinking “well I don’t do integration tests, write HTTP servers or web frameworks, why should I care?” I’ll tell you why you should. For the frameworks you use, a .NET equivalent to Rack would eliminate a large amount of tedious and brittle code that adds no direct value to a framework. This would allow the developers of frameworks to focus their time on refinement giving you more powerful and stable tools to work with. You may not use it yourself but you will benefit from its existence within .NET.

A .NET equivalent to Rack would open the door for a whole new generation of web frameworks to be written. The barrier for writing a quality web framework would be lowered as the nuts and bolts of request and response handling would be a solved problem. We could see some real innovation in .NET rather than a mass of clones of frameworks from other languages.

The door would also be opened for existing servers, such as Apache, to be used for hosting .NET applications and enable entirely new servers to be created. IIS would have competitors. This alone makes it worthwhile. It would make the choice of .NET as a platform less tied, if at all, to choosing Microsoft as a vendor. Even more so than Mono does today, particularly in the web space.

There is a discussion going on right now about creating or choosing a single, common abstraction around HTTP, like Rack, for .NET. Get involved in this discussion and contribute some of your time. This is an opportunity to vastly improve the .NET ecosystem. We cannot afford to miss it.