Let’s do something terrible by hand. First, here’s our data. It comes from a database.
Now when working with these people, we probably could get away with doing something like this for a while:
Which is fine. Until you want to find out what people are on the Muffin Project:
But as you keep working, you might be getting a feeling of deja-vu. The two methods above are very similar. You might be inspired by other Ruby libraries which give you a tiny DSL or at least allow you to pass blocks into methods to be more expressive.
Here’s the complete code smelly example.
We’re having a meeting between the admins and people who are on the Muffin Project. The only person not matching these rules in this case is Bob Barker (bbarker). He must be busy enjoying retirement eating pie, who knows.
Let’s take a look at Faraday. Faraday uses blocks to great effect to communicate intent just like most libraries in Ruby. In Faraday, this is how a HTTP POST is done using Faraday:
This is kind of nice! You can get more than one thing done at a time and it doesn’t require a lot of temporary variables. Let’s see if we can use blocks like this. We’ll get to blocks in a miniute. Let’s first refactor a little bit first.
There’s a certain similarity between the two selects. We really want to get “admins” and “project people” all together, so let’s just do that. We’ll create two methods that essentially replace the instance methods but can be used in the future for other rules. We’ll call them .with_roles and .with_projects.
Next, we’ll create a method that takes a block.
The &block argument and yield block is optional. You could write this as:
But in that case, the block is optional, so you’ll want to check for block_given?. For this example, it’s easier for us to require a block to make this a shorter post … err, well I guess it’s longer now.
In any event, this method’s job is to filter results (users) with whatever code is passed in. Then it uniques the collected array because user IDs are assumed here to be unique. Finally, it returns just user_ids like it’s name implies.
The usage of this user_ids method that takes a block ends up reading very well.
Here’s the completed, less smelly example.
This is pretty procedural. I’ll leave it to you to put it into a class, maybe add something better than a “plus” operator to combine the user list together. Maybe a UserList abstraction class could help get away from hashes too.
I like going down these paths because you end up with more expressive code that is flexible to change. At the same time, little hints of DSLs come out when using blocks to this effect. This is starting down the path of a Ruby DSL. I’ll be posting about that pretty soon.
I’ve been thinking about the problems with The Cloud outside it being a raging buzzword. It really comes down to Control and Connectivity. That’s the problem but allow me to elaborate.
Google Wave is a great example of control loss. If you really put a lot of energy, stock and trust into Google Wave as a content store for your team, brain or idea then you might feel deflated by its cancellation. Even as an idea and a disruptive alternative to E-mail or SMTP crappiness, it’s a shame it had to die. So what now? Wait for an open source version? Host your own?
The idea was to “put it in the cloud” and forget about it. But when the cloud changes outside your control, you have to be aware of it again. Now you really have to think about the cloud itself. It’s not such a vague black box which is what the cloud diagram really means.
Another example of control is YouTube. I use YouTube favorites as a persistent list. I see a cool video, I favorite it and I feel like I sort of own it, or at least it’s in a list that I can refer to later. But take a look at this:
What were those things? Who knows! Now, I have to think about “the cloud” again. These are temporary videos that someone else ultimately controls. I’m just adding references to a list. I don’t own the clips. They are transient. They are ephemeral. I’m out of control again. I don’t even know what media I’ve lost. Do I mitigate again? Do I suck down a list periodically and do a diff?
I recently got a Roku box for my TV. It’s a great box. During registration it does a bunch of sign up and account creation. But it doesn’t work without uPNP enabled on the router. This isn’t even a connectivity outage thing, it’s a connectivity assumption that I have a certain kind of firewall that can’t have holes punched in it … or that I’m not capable of punching the holes myself. I don’t even really know why Roku does this uPNP thing. All I know is, it wouldn’t even finish the setup until I made this change. Now here’s a device that doesn’t work without connectivity or a clear path to connectivity.
Think about how picky that is for a second. If it’s not picky then think about how many technical barriers there are to pure or uniform Internet. Everyone brings their own quilted environment and it’s a mess.
On a Ruby Rogues podcast about Passion, Avdi continued to enlighten and entertain me with his insights. I’ve really been enjoying his speaking style and voice lately through tapas and talks. If he reads this, I hope he understands I don’t disagree with what he is saying; I thought he would enjoy a related story.
Honestly, this topic is so massive I don’t think I can really offer too much more than the Rogues did on the podcast so I encourage you to listen to the episode yourself. It has almost nothing to do with programming or Ruby. I feel that philosophies and stories about passion are so close to the difficult and inevitable goal of “master yourself”, which is both complicated and personal, I can just barely approach the topic and then a rat’s nest of anecdotes and advice explodes all around us.
With that context laid out, here are a few stories.