Friday, June 22, 2012

When Should I Use An ORM?

I think like everyone, I go through the same journey whenever I find out about a new technology..

Huh? –> This is really cool –> I use it everywhere –> Hmm, sometimes it’s not so great

Remember when people were writing websites with XSLT transforms? Yes, exactly. XML is great for storing a data structure as a string, but you really don’t want to be coding your application’s business logic with it.

I’ve gone through a similar journey with Object Relational Mapping tools. After hand-coding my DALs, then code generating them, ORMs seemed like the answer to all my problems. I became an enthusiastic user of NHibernate through a number of large enterprise application builds. Even today I would still use an ORM for most classes of enterprise application.

However there are some scenarios where ORMs are best avoided. Let me introduce my easy to use, ‘when to use an ORM’ chart.

When_to_use_an_ORM

It’s got two axis, ‘Model Complexity’ and ‘Throughput’. The X-axis, Model Complexity, describes the complexity of your domain model; how many entities you have and how complex their relationships are. ORMs excel at mapping complex models between your domain and your database. If you have this kind of model, using an ORM can significantly speed up and simplify your development time and you’d be a fool not to use one.

The problem with ORMs is that they are a leaky abstraction. You can’t really use them and not understand how they are communicating with your relational model. The mapping can be complex and you have to have a good grasp of both your relational database, how it responds to SQL requests, and how your ORM comes to generate both the relational schema and the SQL that talks to it. Thinking of ORMs as a way to avoid getting to grips with SQL, tables, and indexes will only lead to pain and suffering. Their benefit is that they automate the grunt work and save you the boring task of writing all that tedious CRUD column to property mapping code.

The Y-axis in the chart, Throughput, describes the transactional throughput of your system. At very high levels, hundreds of transactions per second, you need hard-core DBA foo to get out of the deadlocked hell where you will inevitably find yourself. When you need this kind of scalability you can’t treat your ORM as anything other than a very leaky abstraction. You will have to tweak both the schema and the SQL it generates. At very high levels you’ll need Ayende level NHibernate skills to avoid grinding to a halt.

If you have a simple model, but very high throughput, experience tells me that an ORM is more trouble than it’s worth. You’ll end up spending so much time fine tuning your relational model and your SQL that it simply acts as an unwanted obfuscation layer. In fact, at the top end of scalability you should question the choice of a relational ACID model entirely and consider an eventually-consistent event based architecture.

Similarly, if your model is simple and you don’t have high throughput, you might be better off using a simple data mapper like SimpleData.

So, to sum up, ORMs are great, but think twice before using one where you have a simple model and high throughput.

Tuesday, June 19, 2012

Use AutoResetEvent To Unit Test Multi-Threaded Code

I’ve been guilty of using a very nasty pattern recently to write unit (and integration) tests for EasyNetQ. Because I’m dealing with inherently multi-threaded code, it’s difficult to know when a test will complete. Up to today, I’d been inserting Thread.Sleep(x) statements to give my tests time to complete before the test method itself ended.

Here’s a contrived example using a timer:

[Test]
public void SampleTestWithThreadSleep()
{
var timerFired = false;

new Timer(x =>
{
timerFired = true;
}, null, someAmountOfTime, Timeout.Infinite);

Thread.Sleep(2000);
timerFired.ShouldBeTrue();
}

I don’t know what ‘someAmountOfTime’ is, so I’m guessing a reasonable interval and then making the thread sleep before doing the asserts. In most cases the ‘someAmountOfTime’ is probably far less than the amount of time I’m allowing. It pays to be conservative in this case :)

My excellent colleague Michael Steele suggested that I use an AutoResetEvent instead. To my shame, I’d never spent the time to really understand the thread synchronisation methods in .NET, so it was back to school for a few hours while I read bits of Joseph Albahari’s excellent Threading in C#.

An AutoResetEvent allows you to block one thread while waiting for another thread to complete some task; ideal for this scenario.

Here’s my new test:

[Test]
public void SampleTestWithAutoResetEvent()
{
var autoResetEvent = new AutoResetEvent(false);
var timerFired = false;

new Timer(x =>
{
timerFired = true;
autoResetEvent.Set();
}, null, someAmountOfTime, Timeout.Infinite);

autoResetEvent.WaitOne(2000);
timerFired.ShouldBeTrue();
}

If you create an AutoResetEvent by passing false into its constructor it starts in a blocked state, so my test will run as far as the WaitOne line then block. When the timer fires and the Set method is called, the AutoResetEvent unblocks and the assert is run. This test only runs for ‘someAmountOfTime’ not for the two seconds that the previous one took; far better all round.

Have a look at my EasyNetQ commit where I changed many of my test methods to use this new pattern.

Monday, June 04, 2012

EasyNetQ: Introducing the Advanced API

EasyNetQ is an easy to use .NET API for RabbitMQ. Check out our new homepage at easynetq.com.
EasyNetQ's mission is to provide the simplest possible API for RabbitMQ based messaging. The core IBus interface purposefully avoids exposing AMQP concepts such as exchanges, bindings, and queues; instead you get a Publish method and a Subscribe method, and a Request method and a Respond method, simple to use bus also a rather opinionated take on the most common messaging patterns.
For users who understand AMQP and want the flexibility to create their own exchange-binding-queue topology this can be quite limiting; you still want to use EasyNetQ’s connection management, subscription handling, serialization, and error handling, but you want to do something outside of EasyNetQ’s pub/sub request/response patterns. For these users we’ve provided the ‘advanced’ API.
The advanced API is implemented with the IAdvancedBus interface. An instance of this interface can be accessed via the Advanced property of IBus:
var advancedBus = RabbitHutch.CreateBus("host=localhost").Advanced;

Yes, I stole that idea from RavenDb, thanks Ayende  :)
To create a bespoke exchange-binding-queue topology use the classes in the EasyNetQ.Topology namespace. In this example I’m binding a durable queue to a direct exchange:
var queue = Queue.DeclareDurable("my.queue.name");
var exchange = Exchange.DeclareDirect("my.exchange.name");
queue.BindTo(exchange, "my.routing.key");

Once you’ve defined your topology, you can use the Publish and Subscribe methods on the IAdvancedBus. To publish, first create a new message. Note we have a new Message<T> class that exposes the AMQP basic properties:
var myMessage = new MyMessage {Text = "Hello from the publisher"};
var message = new Message<MyMessage>(myMessage);
message.Properties.AppId = "my_app_id";
message.Properties.ReplyTo = "my_reply_queue";

Now we can publish our message to the exchange that we declared above:
using (var channel = advancedBus.OpenPublishChannel())
{
    channel.Publish(exchange, routingKey, message);
}

Here’s how we subscribe to the queue we defined:
advancedBus.Subscribe<MyMessage>(queue, (msg, messageReceivedInfo) => 
    Task.Factory.StartNew(() =>
    {
        Console.WriteLine("Got Message: {0}", msg.Body.Text);
        Console.WriteLine("ConsumerTag: {0}", messageReceivedInfo.ConsumerTag);
        Console.WriteLine("DeliverTag: {0}", messageReceivedInfo.DeliverTag);
        Console.WriteLine("Redelivered: {0}", messageReceivedInfo.Redelivered);
        Console.WriteLine("Exchange: {0}", messageReceivedInfo.Exchange);
        Console.WriteLine("RoutingKey: {0}", messageReceivedInfo.RoutingKey);
    }));

Note that we also get an IMessageReceivedInfo instance that gives us information about the message context, such as the exchange, the routing key and the redelivered flag.
So as you can see, you get a lot more control and access to various AMQP entities, but still with much less complexity than using the RabbitMQ .NET C# client directly.
For more on the advanced API check out the EasyNetQ documentation. Happy messaging!