Making Ruby all Clojury

So, I've been nerding out to Clojure for about a year. It's a really fantastic language (yes, I know what Lisp is) with an elegant and pragmatic marriage of some really progressive ideas. I feel like I'm waiting to enter the Trough of Disillusionment, but it's just not happening. Instead I've seemingly bypassed the valley and have ended up trotting up a mountain of productivity.

But alas, since these days I mostly write Ruby at work I'm resigned to dress my Hickeyisms in red. I've found a sneaky way to write Clojure with Ruby that I'd like to share. Maybe it will help you de-complect your Ruby code too!

Object Objections

With typical Ruby code we have a bunch of icky OOP concepts like inheritance and polymorph-something to deal with. Singleton this, Visitor that. You probably have some app with a zillion objects all storing and changing state and interacting in non-deterministic ways.

Your unit tests (if you can call them that) require complicated test "harnesses" loaded with fixtures, dependency injection and a lot of other boring boilerplate. Have fun with that.

The Zen of functional programming is in murdering controlling state and mutation. Imagine a glorious developers's paradise where side effects don't exist and everyone understands Monads. Unfortunately only 3 people understand Monads so we'll avoid them for now.

What we want is something pragmatic. A set of features which allow us to write side-effect free, pure functions and occasionally step off the one true path of the Haskell acolytes.

With Clojure, you get this goodness for free. But what can be done about Ruby? Let's take a look.

Namespaces

Drop That Class!

class Car
  attr_accessor: :make, :model

end
cars = [{ make: :honda, model: :civic }]

def

Functions

If you're not really familiar with Functional Programming, one of the key ideas is using (duh) functions as the primary Lego blocks of your software.

Immutability

In Ruby you can

ORMS

Imagine if the need to shoehorn model objects and their relationships onto databases didn't exist. If you're program deals with data directly, you can basically just throw out that ugly ORM baby with the poopy bathwater.

In Ruby, I've been using Arel over ActiveRecord as an excellent query builder. You can also just use SQL (gasp!). Ignore the OOP Zealots—SQL is often abstract enough. A lot of database queries return subsets of an item's properties anyway.

Compare

SELECT AVG(age) FROM people;

with

Person.average(:age)

What does the second level of abstraction really buy you? Trigger warning! Few things are as problematic as needless abstraction in software.

And don't forget you can wrap these things in functions.

def avg_user_age
  qry 'SELECT AVG(age) FROM people'
end

Further reading:

  1. http://awardwinningfjords.com/2015/03/03/my-weird-ruby.html
  2. https://code.google.com/p/tokland/wiki/RubyFunctionalProgramming
  3. http://www.slideshare.net/tokland/functional-programming-with-ruby-9975242