Ducktyping. Quack.

I was working on one of our projects when I happened to run across some code that set off my rubber ducky detector. It’s a page that displays the days production quantities or displays an estimate if it’s too early in the day to tell. Both cases have very similar views and they share a common interface. Our controllers were too fat and our views knew too much.

Here’s the culprit.

class ProductionRunsController < ApplicationController
  def print_recipes
    @date = date_query
    @production_run = production_run_for_date(@date)
    @projection_run = ProductionRunProjection.new(@date) unless @production_run
  end
end
# view
<h1>Print Recipes <%= @date.strftime("%A %b. %e, %Y") %></h1>
<% if @production_run %>
  <%= render 'production_run', object: @production_run %>
<% else %>
  <%= render 'projection_run', object: @projection_run %>
<% end %>

We have this one view that renders either a projection_run or a production_run depending on if a user has a production run on that date or not. The code works but I have a few problems with it.

  • We have 3 instance variables in 1 controller action. One of which will always be nil! We literally have a variable holding nil. This totally breaks Sandi Metz rule of having 1 instance variable per action. Hard

  • More importantly, what happens later on down the road if the client we’re building this for wants past_runs to be formatted differently? Continuing this pattern, it would probably look something like this.

class ProductionRunsController < ApplicationController
  def print_recipes
    @date = date_query
    @past_run = past_run_for_date(@date)
    @production_run = production_run_for_date(@date)
    @projection = ProductionRunProjection.new(@date) unless @production_run
  end
end
# view
<h1>Print Recipes <%= @date.strftime("%A %b. %e, %Y") %></h1>
  <%= render 'past_run', object: @past_run if @past_run %>
  <%= render 'production_run', object: @production_run if @production_run %>
  <%= render 'projection_run', object: @projection_run if @projection %>

As the conditions that the client gives get greater and greater, this view will get more ifs and more variables in the action. As a best practice, it is good to have the least amount of logic in the views as possible and this has a lot.

A more elegant solution involves two patterns: the facade pattern and duck typing.

The facade pattern



The facade pattern is pretty much what it sounds like. We’re hiding logic in some sort of object and asking that object to do work for us rather than the controller. Doing this allows us to stick to one variable and please the ever lovely Sandi Metz. A quick refactoring might looking something like this:

class ProductionRunsController < ApplicationController
  def print_recipes
    @facade = ProductionRunFacade.new(@date)
  end
end

class ProductionRunFacade
  attr_reader :date

  def initialize(date)
    @date = date
  end

  def production_run
    @_production_run ||= production_run_for_date(date)
  end

  def projection
    @_projection_run ||= projection_run_for_date(date)
  end

  private

  def production_run_for_date
    #some logic
  end

  def projection_run_for_date
    #some logic
  end
end
# view
<h1>Print Recipes <%= @facade.date.strftime("%A %b. %e, %Y") %></h1>
#stuff omitted
<% if @facade.production_run %>
  <%= render @facade.production_run %>
<% else %>
  <%= render @facade.projection %>
<% end %>

It’s getting there but it could use a bit more love. Let’s move the date logic from the view to the facade.

class ProductionRunFacade
  attr_reader :date

  #code omitted

  def formatted_time
    date.strftime("%A %b. %e, %Y")
  end
end
# view
<h1>Print Recipes <%= @date.formatted_time %></h1>

Here’s a small win! and it’s all about those small wins. We can take this a step farther but first let’s talk about Duck Typing.

Duck Typing


Sandi can explain duck typing better than I can. In her words,

Duck types are public interfaces that are not tied to any specific class. These across-class interfaces add enormous flexibility to your application by replacing costly dependencies on class with more forgiving dependencies on messages.

Duck types objects are chameleons that are defined more by their behavior than by their class. This is how the technique get its name; if an object quacks like a duck and walks like a duck, then its class is immaterial, it’s a duck.

An example that you may all be familiar with is the [] operator.

array = [0,1,2,3,4]
string = "hello world"
array[0] #returns 0
string[0] #returns h
array[1..-1] #returns [1,2,3,4]
string[1..-1] #returns "ello world"

We can call the [] operator an both an array and a string, [] is the quack and both objects are ducks.

Now let’s apply this to our code.

class ProductionRunFacade
  attr_reader :date

  def initialize(date)
    @date = date
  end

  def run
    @_run ||= production_run || projection_run
  end

  def formatted_time
    date.strftime("%A %b. %e, %Y")
  end

  private

  def production_run
    #some logic
  end

  def projection_run
    #some logic
  end
end
# view
<h1>Print Recipes <%= @facade.formatted_time %></h1>
<%= render @facade.run %>
<% end %>

There are a couple things that happened here. First, @production_run and @projection_run became one variable called @run. Secondly, we no longer have any measly ifs in our view anymore, we only call render on @facade.run. What is this magic? Here we are using the power of duck typing and trusting that ProductionRun and ProjectionRun have implemented to_partial_path which render calls. Because of this trust we no longer care what the object is but care about the messages it sends.

With this new architecture, adding new potential runs is made extremely easy. Actually, let’s implement past_runs as well! It’s only a few additional lines of code.

class ProductionRunFacade
  attr_reader :date

  def initialize(date)
    @date = date
  end

  def run
    @_run ||= production_run || projection_run || past_run
  end

  def formatted_time
    date.strftime("%A %b. %e, %Y")
  end

  private

  def past_run
    #some logic
  end

  def production_run
    #some logic
  end

  def projection_run
    #some logic
  end
end

Done. We don’t have to add any more ifs in our view and we don’t have to add any additional instance variables in our controller. Easy as quack.

Noob to Wizard: The Journey

cover

It’s been around six months since I quit my job as a PSI Analyst. For those of you unfamiliar with the terminology, it’s pretty much a glorified title for an Excel technician. I lasted a mere 3 months before the banal, repetitive tasks took their toll on me, slowly killing my sanity with every vlookup I did. There were more than a few reasons why I quit, but most of all, the corporate life wasn’t for me. I couldn’t imagine kissing ass for the rest of my life to get that 3% promotion every year. I couldn’t imagine doing something I didn’t enjoy for the rest of my life. I couldn’t imagine not being challenged… ever. So I quit.

I quit before I had anything lined up, but I knew I wanted to code. Luckily I had extremely supportive friends who had every intention of helping me reach my goal (shoutout to @alexiomota and @Yanyeeli ). They helped me research coding schools and vet the ones that would fit my needs. They answered any question to the best of their ability and helped me figure out what I wanted to do. Who knows what I would be doing if it weren’t for them!

A few weeks and interviews later, I got into the school of my choice, Metis. Unfortunately, after Kaplan acquired Dev Boot Camp, they have decided to streamline Metis as a Data Science school and removed Metis’s Ruby on Rails and UX-Front End Development courses. Regardless, my time at Metis was everything I wanted and more (shoutout to @tabfugnic, @dgalarza, harry (please excuse his lack of twitter), and @thoughtbot ).

Although it’s not a literal bootcamp, there was nothing easy about attending a coding “boot camp.” There were around 5 hours of lecture and 3 hours of practice problems almost every day. On top of that, in order to network, we attended meetups to mingle with other developers and expand our networks. If we weren’t able to follow along with the day’s material, there was studying to be done after class. Worst of all, I lost 3 hours commuting back and forth from school. “Easy” was never a word that came up when describing those 3 months. But if I were to go back in time and had the chance to do it over again, I would do it in a heartbeat. Not because I’m some sort of sick masochist or because I have $12,000 to just throw around. Not because the material is impossible to learn independently but because the experience taught me what I was capable of and, more importantly, because of the amazing people I met.

Having thoughtbotters as my instructors was invaluable. Not only are they passionate developers, but they are regarded by many to be some of the best in their trade. This was like having Sir Lancelot teaching me to fence or having Michael Jordan teaching me to shoot. They were able to answer questions based on previous experiences, teach us best practices, and show us how to write clean code. The best thing of all, though, was that they stayed connected and truly developed a relationship with us students.

Six months after I quit my job and started down this path, I’ve landed my first development job as a developer at Wizard Development and it’s everything I wanted. I have amazing co-workers, I’m challenged every day, I have a voice in my team, and I get 20% time to write this post. I get freedom to do things the way I see fit and get to learn on the job. I’m pretty much living the dream.

Out of everything I’ve learned thus far, the most important thing I’ve learned was just how much I rely on others and to embrace it. Looking back, I would never have gotten to this point without the help of friends I’ve had and the friends I’ve made along the way. Being a developer is great because I’m challenged every day and the things that I can learn are limitless. Best of all, the coding community is unrivaled. I’ve received so much help from others and I want to learn enough so that I can do the same and bring people through the same journey that I did. So if you have any questions about anything feel free to reach out to, eli@wizarddevelopment.com

Cleaning up your views with Simple Delegators

cover

While working on my pet project for matching tennis partners I decided to make a match history page. It displays a player’s recent matches and some information pertaining to them: who played when, who won, and how much that win affected their score on the site. I also wanted each match history log to be separated by color-coded boxes.

This was the end result:
Match-History-Image

The first solution I came up with used a bunch of if statements and some messy view logic:

# (most of the view omitted)

<% @matches.each do |match| %>
  <div class=<% match.winner == current_user ? "winning_class" : "losing_class" %>>
    <div><%= match.challenger %> vs <%= match.defender %></div>
    <div><%= match.match_at %></div>
    <% if match.winner == current_user %>
      <div>+ <%= match.elo_difference></div>
    <% else %>
      <div>- <%= match.elo_difference></div>
    <% end %>
    <%= link_to "Match Details", match %>
  </div>
<% end %>

But we’re doing Ruby, and this is some ugly Ruby. There’s a lot of logic in the views… and a ternary? Am I insane?

Enter Simple Delegators:

A concrete implementation of Delegator, this class provides the means to delegate all supported method calls to the object passed into the constructor and even to change the object being delegated to at a later time with #__setobj__.

Using this, we can make decorators to clean up our views.

Let’s start with the controller:

def index
  @matches = Match.all.map do |match|
    if match.winner == current_user
      WinningMatch.new(match)
    else
      LosingMatch.new(match)
    end
  end
end

Then we can make these decorated matches:

class WinningMatch < SimpleDelegator
  attr_reader :match

  def initialize(match)
    @match = match
    super(@match)
  end

  def match_outcome_class
    "match-stats-winner"
  end

  def elo_delta
    "+ #{match.elo_delta}"
  end

  def win_or_lose
    "won"
  end
end

We would do exactly the same for LosingMatch.

We end up with an array of matches in our #index action. Each match could either be a LosingMatch or a WinningMatch. Through the magic of duck typing, we can call the same method on either WinningMatch or LosingMatch and they’ll know what to return.

So, in the end, we can create a partial like this:

<li class="<%= match.match_outcome_class %>">
  <div class="match-stats">
    <p class="username"><%= match.challenger_username %> vs. <%= match.defender_username %></p>
    <p><%= match.match_at.strftime("%F") %></p>
    <p><%= match.win_or_lose %></p>
    <p><%= match.elo_delta %> </p>
    <p class="match-link"><%= link_to "Match Details", match %></p>
  </div>
</li>

This is pretty cool! We were able to take out the various if statements and employ SimpleDelegators and duck typing to create a clean partial with absolutely no branching. I’d call that an enormous win.