Tuesday, June 18, 2013

Don't Ask, Tell

I just read Michael Feathers' post Avoid Null Checks by Replacing Finders with Tellers and it really made me think about how I write code.

Nulls Be Ugly

I am going to concur with Michael, null checking looks ugly. I hate null checking so much that often I will change a null check like in his example to a one or two liner return just so the ugly is minimized:

So what he suggests is rather than ask the object for state, pass a message to the object that it can handle. I've been reading/hearing about the whole message passing idea in OOP languages lately (especially in Ruby) and although I understand the concept, it's nice to have it illustrated in the post in a useful way.

Not Hip At All

So there's a little bit of a love-fest going on in the post with Ruby. Or is it a hate-fest with Java? Either way, I looked at both versions and thought, this probably wouldn't look bad in C#.

Poor C# isn't even close to as hip as Ruby nor does it share the kind of heritage that Java has with 'nix OSs but it has had lambdas for several years now and the syntax is quite good. When I started replicating the code in question, I came up with this:

I'd say that it's as readable as the Ruby counterpart:

Going Deeper

Being pleased with myself, I decided to replicate what a common data source implementation would look like and came to Michael's sad conclusion that we usually ask for the null check pattern so much that most base/system code is infected with it:

This can be mitigated a bit by calling something that returned an IEnumerable or IList:

It might not be as fancy a solution as in Ruby but it'll have to do for now.

There are a lot of interesting comments on Michael's post so if you're interested in more about this pattern, I suggest seeing what others have to say about it. One interesting comment mentions including a way to actually have an "else" clause in case the Person object didn't exist. I imagine you could do that with a second lambda but there may be a more intelligent way.

My whole C# solution is posted on GitHub for those that are interested. Thanks for reading.

Wednesday, June 5, 2013

Yay RabbitMQ Part 1

RabbitMQ Logo
One thing I've been working with a lot lately is RabbitMQ. It was a bit confusing to work with at first but I think a lot of that was primarily because there was already a code base in place that was using it. Now that I've had a chance to understand the why's and hows, I thought I'd share some of my experiences with it.

Why Queues Or RabbitMQ?

Any kind of process that doesn't need a UI response is an excellent candidate for a queue. There are many blog posts out there about queue architecture and RabbitMQ but here are the more popular ones:

  • Send an email
  • Log actions to a database/Hadoop cluster
  • Fire events that other services can react to
  • Queue up reports to run

There are other other queuing systems out there like MSMQ, ZeroMQ, ActiveMQ, etc. but RabbitMQ seems to be the fastest with durable message support. RabbitMQ also has some great library support out there for many different languages including my current language of choice, .Net.

How Does It Work?

Setting up a cluster is beyond the scope of this post but I'll just mention that it can run on Windows or Linux as it ultimately runs on top of Erlang. This makes for an easier install, simple administration and great options (you can even cluster Windows and Linux boxes together... though I wouldn't recommend it). One other note is to make sure you have the admin plugin installed as this is a major selling point for RabbitMQ as it not only looks good, it's highly functional.

Email And Exchanges (no, not that Exchange)

The best thing I've seen RabbitMQ compared to is an email system. What do you need to send an email? Well, you need an email address for one thing. And usually you'll have a subject with the message. Once you have those things, you can send an email to someone.

To send a message through a RabbitMQ cluster, you need an exchange and a routing key. An exchange is like an email account in that it has a unique name on the cluster and its job is to receive messages. A routing key is much like the subject on the message, it's there to tell more about the message.

Queues, Queues, Queues

You can send an email to an address but unless there's a client pulling the messages, the email account just gets full of unread email. In order to read those emails, you connect an email client to the account and start reading messages.

With RabbitMQ the email client is much like a queue. When you create a queue, you tell it what exchange to listen to and then start pulling messages off.

So what about the email subject and the routing key? Here's where the abstraction starts to leak a little bit but bear with me.

When you first connect an email client to an email account, everything comes through the inbox. If you get a lot of messages that are similar, you usually want to create rules to place the messages in a specific folder or tag. If your senders are nice enough, you can filter on the subject line. This doesn't happen often but let's just assume that they're super nice.

Routing keys are like those really reliable subject lines. When you create a queue, you define what exchange and routing key to subscribe to. If you want all the messages (like the inbox), you can use a single routing key and everything sent to the exchange will go to the one queue. If you create a queue with a specific routing key, only messages sent through the exchange with that routing key will get sent to the queue. You can even use wildcards with topic queues to do some fancier routing.

Makes Sense, Now What?

One exchange and two queues with different routing keys.
So here's what I've covered conceptually in the image above. The my.queue queue is pulling messages from the my.exchange exchange that have a routing key of my.key. The my.other.queue queue is pulling messages from the same exchange, but only messages with a my.other.key routing key.

It took me a while to understand this overview of how everything works so hopefully you won't have to go through the confusion that I went through. With this knowledge in place, you're ready to learn how to actually code against a cluster. Since I'm not crazy about super long posts, I'm going to leave that to another time which is hopefully in the not-too-distant future. Thanks for reading and if there's anything you'd like me to cover, please leave a comment.