Jared Rader

Practical Object-Oriented Refactoring

This post first appeared on the Bloc blog in January 2015

As code bases grow, the need to refactor grows with it. A couple weeks ago, I saw an opportunity to refactor Bloc’s scheduled emails, which we activate in a Rakefile.

The Rakefile looked something like this:

task :send_greeting_email => :environment do
  Enrollment.starting_in_the_next_two_weeks.each do |enrollment|

    EnrollmentMailer.program_coordinator_greeting(enrollment).deliver
  end
end

task :send_get_started_emails => :environment do
  starting_enrollments = Enrollment.where('course_start_date > ? AND course_start_date < ?', Time.now, Time.now).where(sent_get_started_email: false)

  starting_enrollments.each do |enrollment|
    EnrollmentMailer.get_started(enrollment).deliver
  end
end

task :send_final_day_email => :environment do
  Enrollment.active.graduating_on(Date.today).each do |enrollment|
    EnrollmentMailer.graduation_letter(enrollment).deliver
    MentorMailer.confirm_grad(enrollment).deliver
  end
end

Plus several more notifications.

I wanted to test the code in this file, but as it is, it’s not very friendly to testing. However, there was a pattern among all these scheduled emails - grabbing specific enrollments and performing certain email actions. Sounds like a great use case for a service object.

A Functional Approach to Verbal Math in Ruby

Inspired by my functional approach to solving the verbal math problem in JavaScript, I decided to implement a similar approach in Ruby.

My first solution took advantage of Ruby’s everything-is-an-object nature, sending number objects symbols and values, which made solving the problem pretty easy.

However, it’s possible to take a functional approach in Ruby that is nearly equivalent to how you could solve this problem in JavaScript. And then, you can even combine this with Ruby’s object-oriented nature and metaprogramming capabilities to create a truly elegant solution.

While JavaScript has anonymous functions, Ruby has something similar in blocks, procs, and lambdas.

Here’s a language conversion to illustrate how you can achieve very similar functionality in Ruby and JavaScript (Check out my last post where I explain the JavaScript function in-depth):

JavaScript:

function plus(amount) {
  function add(number) {
    return number + amount;
  }
  return add;
}

Verbal Math in JavaScript

I’m a fan of this fluent calculator exercise (I covered my solution using Ruby in my last blog post), and on another flight, I decided to implement a solution in JavaScript. Ruby’s object-oriented nature and metaprogramming capabilities made the task fairly simple; how would it go in JavaScript?

Recall that this exercise requires one to be able to verbally enter math operations, i.e. one(plus(one())), and return the correct integer result.

In Ruby, because most everything is an object, I was able to call methods on my integers, like 1.send(:+, 1). In JavaScript, integers are just primitive data types - not objects that can receive messages. But JavaScript’s ability to return functions allows us to achieve the same ability.

Again, I started off with the one() function. I knew one() would need to optionally take an argument, which would be an operator function. If no operator function was passed, I simply return 1. Otherwise, I need to return an operation on 1:

function one(opFunc) {
  if (opFunc == undefined) {
    return 1;
  } else {
    // as yet unwritten code
  }
}

Verbal Math In Ruby

Came across an interesting code challenge on Code Wars a while back. It involved defining methods in a way to be able to type mathematical operations verbally, i.e. one plus one which would return 2.

I pondered over this for a while, and on a flight back from San Francisco came up with a neat solution and even learned a couple interesting things about metaprogramming.

I started with defining one. I know that I’ll want to potentially pass an argument to one. If I don’t have an argument, I’ll just want to return the integer 1. Simple enough. I can just give my method definition argument a default value of nil, check whether I have an operator, and if I don’t, simply return the integer 1:

def one(operator_method = nil)
  if operator_method
    # as yet undefined code
  else
    1
  end
end

Ok, so what should happen when I get an operator? I decided to find a way to implement plus.