Glad You're Ready. Let's Get Started!

Let us know how we can contact you.

Thank you!

We'll respond shortly.

  • Blog Navigation
Oh, the programs you'll DRY!

Someone just told you your code isn’t DRY, and you have no idea what they’re talking about. You’re fresh out of college, and you’re starting to fear that your Computer Science degree left you woefully unprepared for the challenge of real-world software engineering.

“DRY means ‘Don’t Repeat Yourself.’ Look, it’s basically the same code in all of these methods,” your coworker tells you. Your coworker has been out of college for 9 months, so you take another look at your code. You’re writing an application to create widgets, and you’ve just finished a feature that made it possible to create a new type of widget.

class WidgetFactory
  def foo_widget'widget')

  def bar_widget'widget')

  def baz_widget'widget')

  def fuz_widget‘widget’)

On closer inspection, you agree with your coworker that there’s a definite pattern, but you can’t imagine what you could do about it. “We could use a little bit of metaprogramming to DRY this up,” your coworker says, and then blows your mind with the following refactoring:

module WidgetMethodGenerator
  def widgets(*widget_types)
    widget_types.each do |widget_type|
      define_method "#{widget_type}_widget" do 'widget'

class WidgetFactory
  extend WidgetMethodGenerator

  widgets "foo", "bar", "baz", "fuz"

You had never before imagined that Ruby had such power. Suddenly you can start to fathom how all of those magical methods in Rails must be implemented. And your WidgetFactory code is so clean! It will be so easy to create the factory method for the next widget type that comes along! Your coworker is so pleased to have shown you the secret, magic power of metaprogramming. You’re off and away. Oh, the places you’ll go!


Three years have passed. You’re still working on the same application. You’ve spent the last year refactoring away all of the meta-programming madness of your first year. You shake your head at your former self every time you bump into a needless define_method, method_missing, or instance_eval.

Your product owner asks you to implement a new feature in your application: force your users to confirm every widget creation with a captcha. For the past several months, your application has been plagued by widget spam bots.

You’re pair programming with a new college grad on implementing the confirmation modal when you write the following cucumber step definition:

When /^you create a new widget and confirm with a captcha$/ do
  fill_in “Widget Description”, with: “foo bar”
  click_button “Submit”
  within(“#widget_confirmation_modal”) do
    fill_in “#captcha”, with: “HERP DERP”
    click_on “Confirm”

After you and your pair implement the new feature and get your acceptance test passing, you run your entire build – only to discover that a hundred other features have broken. It turns out there were a lot of tests that created a widget, and when you dig into them, you realize they all do it slightly differently. Some of them `click_button “Submit”`. Others `click_link_or_button “Submit”`. Still others `find(“#widget_submit”).click`. And on and on.

The knowledge of how to create a widget in the UI was smeared throughout your test suite. It dawns on you that DRY isn’t about the repetition of structure, it’s about the duplication of knowledge. In this case, the more code that knew about how to create a widget, the more difficult it became to change the way widgets are created.

Your pair learns this lesson with you. You hope it’s better than the lesson you learned when you were fresh out of college. Oh, the programs you’ll DRY!

Post a Comment

Your Information (Name required. Email address will not be displayed with comment.)

* Copy This Password *

* Type Or Paste Password Here *

Share This