Tuesday, July 22, 2014

May #TMIL - A Touch of eval()

In a Rails app, I've got a Plan that belongs to a Subscription. The Plan has a duration, and the Subscription has an expiration. The expiration gets set in an after_create callback using the current time (DateTime.now) plus the Plan's duration. Then, there's an expired? method on the Subscription which checks if self.expiration < DateTime.now. Pretty straightforward, right? (code snippet below)

When updating seeds for the Plan, I was hoping to get away with using ActiveSupport conveniences, like 2.weeks, for the Plan's duration. However, 2.weeks evaluates, i.e. it is not stored as "2.weeks" in the database. Storing the value of 2.weeks.to_s (1209600, or the number of seconds in two weeks) also wouldn't work, since DateTime.now + 1209600 gives an unexpected result - it adds that many days.

The above makes sense, but this is Ruby, there's gotta be another way. How about serializing 2.weeks and storing it as a lambda in the database? The seemed to work in a console:

[5] pry(main)> now = DateTime.now
=> Tue, 22 Jul 2014 17:48:52 -0400
[6] pry(main)> duration = -> {2.weeks}
=> #<Proc:0x007fc18b3a14a8@(pry):2 (lambda)>
pry(main)> now + duration.call
=> Tue, 05 Aug 2014 17:48:52 -0400

Next, I added serialize :duration into my model, and did the RAILS_ENV=test rake db:drop db:create db:migrate db:seed rigamarole (since the helper tasks for this never seem to work as thoroughly for me) ... BOOM! I pry'ed in where the Plan's were getting created and tried to manually create one, and it appears that ActiveRecord won't let you serialize a proc (or lambda, a flavor of proc). While tempting to go down the rabbit hole of why, I knew there had to be an easier way than converting all my DateTime's into seconds, and done some other conversions, etc.

The solution? Store the Plan duration as a string, then use eval(). Since the Plan's will rarely change or get newly created, and tests are in place, this seemed like an appropriate use of what many consider to be an evil method. Ahh, I love writing in Ruby. Snippet below:

Sunday, June 29, 2014

April #TMIL - RSpec

As expected, this series of posts has drifted far off schedule. At least the drafts have been on time! Here are a few RSpec tips, preferences and best practices I've been accumulating after spending the last year using it in my daily work, finally realizing that's it much more art than science.
  • Start by writing an outline of your specs so that when you run them with the --format documentation, or -fd, option, you get a readable outline that clearly explains what the code should (or shouldn't) be doing. This can be more high level, or have a line for the happy/sad/edge paths of each method, or whatever works for you. I've found that using documentation format as a guide, along with organizing your tests using context/describe blocks, helps keep the code SOLID and intentions clear. You can make this the default, and enhance readability with --color, by adding a line for each one to a .rspec file.
  • Along with the above, driving from the outside in has been extremely useful in many situations for me. This Ruby Tapas episode provides a great example of this approach. I've found that starting with BDD leads to more reliable code and helps me to see relationships between objects and scenarios, though I try to avoid mocking (or get rid of them once the design is driven out). I like to start by describing what should happen as a series of Given-When-Then statements, e.g. Given I'm on the home page, When I sign in with valid credentials, Then I should see something awesome, then converting those into grouped specs, extracting helper methods, etc. While Cucumber more clearly enforces that syntax, the additional overhead of setting it up gets in the way, and I stick with Capybara in RSpec feature specs.
  • Add complete coverage, but don't over do it. If it feels like you're rewriting your code in the specs or you're testing parts of your framework, you're doing it wrong. This video has a great discussion of the idea that testing should be "as little as possible to achieve a given level of confidence."  
  • Don't forget about Mini Test as an alternative to RSpec. After all, it's in the standard library, complete with examples involving cheeseburgers! Brandon Hilkert's post also reminds us of other benefits, like using fixtures (especially if your factories' associations and traits are getting out of control).
  • Get to know VCR for recording HTTP interactions and Puffing Billy to record browser interactions. This way your specs never make real web requests, resulting in more deterministic tests, and so you don't have to deal with "stubbing the internet" and can run your test suite without an internet connection.
  • Be careful with mocks. I find them helpful when it's absolutely essential to know a message on another object gets called as a result of what you're testing. More succintly, "stubs are for queries and mocks are for commands." Or sometimes using them to drive out the design of collaborator objects (and to encourage decoupled code via dependency injection as suggested here). For example, mocking out a Song class when writing tests for your Playlist class then converting the mocks to real objects (and non-stubbed methods) when you've built your Song class. More often, I've found that when there's too much mocked or stubbed behavior necessary to set up a test, it's usually a sign the test is focused on the wrong thing, in the wrong place, or the code is too coupled. Opinions on the use and misuse of mocks vary greatly; I've found more success avoiding them when possible. More discussion on the use/misuse of mocks here, here and here. And here. This post by James Golick demonstrates some benefits of the mockist style and reminds one of the importance of having intergration tests (which you should regardless of your testing style) to avoid the common problems with mocking (i.e. mocked behavior allows false positives when the underlying interface has changed). 
  • Redo these exercises every now and then and see how much better and faster you're getting.
  • GuardGuard::LiveReload, and Guard::RSpec are essential for front end development. The basic setup of your Guardfile found in the Railscast will get you going. Just add the gems and bundle, then install the LiveReload browser extension (for Chrome, Safari or Firefox). You can add more plugins, like Guard::CoffeeScript, by running `guard init pluginname`. A list of plugins can be found on the Guard wiki. After enabling the extension in your browser while your development server is running, when you change a file, Guard will refresh your browser window and kick off your specs. Nice.
  • There are lots of other must-have's in your development group, a good overview can be found here. I also like to liberally use Pry and so-called "REPL Driven Development" as described by Pry core contributor Conrad Irwin. (Video | Slides
That's all for now, happy spec'ing!

Saturday, May 17, 2014

March #TMIL

My how the time flies. Still, I'd rather be late than abandon my New Year's resolution early! Here are some notes that have been sitting in this draft for the last two months.

Two quick tips

  • PC Keyboard Hack is a must-have extension for me. I find it's much nicer on your hands to avoid using the Return key on the right side of the keyboard. (You can make some remappings in the Keyboard->Modifier Keys panel in the OS X system preferences; however, Return is not an available choice for remapping Caps Lock.) 
  • Enable control-R backsearch in irb by adding this code to your ~/.editrc file :
    • bind "^R" em-inc-search-prev
    • Source

Class macros in Ruby

The explanation of class macros in Metaprogramming in Ruby by Paolo Perrotta really helped me understand the concept (and review and dive deep on many others - its explanation of the Ruby object model and coding idioms is great.). Let's say you manage the code for a death metal record label's applications, and the company decides to add folk rock artists to its roster. You'll need to make your code more generic, and warn developers that the method they called is now deprecated, then tell them what the new one is.

Perotta reminds the reader that although classes are typically thought of as containers for methods, when you open a class by creating a new instance (here, a Guitarist), other code will be executed. In this case, there is a direct call to the class method ::deprecate which then uses Module#define_method to dynamically add the deprecated methods to the class definition; the deprecated method then warns the user and calls the correct method. Another familiar class macro is attr_accessible in Rails 3, or Ruby's attr_accessor.

To begin making changes, the Guitarist class will now need a guitar, not an axe. The Guitarist will also play instead of shred. (Maybe you'll want more specific sub-classes for each genre, or add functionality with modules like Shreddable or Strummable, but that's a further step.)

class Guitarist
  def guitar

    # ...
  end

  def play(song)
    puts "Playing #{song}."
    # ...
  end

  def self.deprecate(old_method, new_method)
    define_method(old_method) do |*args, &block|
      warn "Warning: #{old_method}() is now deprecated. Use

            #{new_method}()."
      send(new_method, *args, &block)
    end
  end

  deprecate :axe, :guitar
  deprecate :shred, :play
end

g = Guitarist.new
g.shred(Song.new("Like a Rolling Stone")

# outputs the following:
# => "Warning: shred() is deprecated. Use play()."
# => "Playing Like a Rolling Stone."


That's all for this month, more to come.