When we write code in Ruby (on Rails) we often start with the behavior we’re trying to implement. This may begin as a non-technical description of a problem from an agile story.
The developer then begins thinking of how to implement the solution. Often a technical implementation quickly comes to mind. The editor is opened, code pours.
In Ruby Refactorings I plan to look at ways in which Ruby code can be refactored to be better1.
A Common Gotcha
I often see people following the process above: desired behavior leads to implementation leads to code. This is lacking a moment when we contemplate design in addition to implementation. We must not forget to think about what would be the ideal way to interact with this code. What would a beautifully designed interaction be like? Can we think what that would be? Then can we build it?
Let’s see the code!
Imagine our story tells us to display some piece of content for our dev site only and not on production. So we think we need to build a feature flag, and after some discussion we decide to create an environment variable that will be present where we want this enabled.
We immediately think of implementation:
And so we throw this in some views
1 2 3
<% if ENV['MY_FEATURE_FLAG'].present? do %> This is feature flag enabled code <% end %>
And this might be okay if you are using this in exactly one place. But very likely, we’ll need to use this again somewhere else.
So then quickly we have
if ENV['MY_FEATURE_FLAG].present? in multiple places throughout our code base.
I see some problems.
- If we decide to rename MY_FEATURE_FLAG we need to do it in multiple places. Is not DRY.
- Is our view the best place to be asking questions about our environment? No.
- Is this code beautiful and clear. It’s quite clear that it is checking the environment variable, but it is not beautiful.
- Is it easily testable? No, as part of a view, we can’t just easily test it as a method on a class.
Let’s take a moment to image how we might wish we could do this.
What if we could make the following work?
1 2 3
<% my_feature_enabled do %> This is feature flag enabled code <% end %>
This feels much more Ruby like to me. It feels clean and concise and beautiful. It clearly defines the behavior not the implementation.
Can we make this work?
1 2 3
def my_feature_enabled yield if ENV['MY_FEATURE_FLAG'].present? end
The following code can be placed in any Rails view helper. We now define our ENV variable in one place. This is much easier to change and we don’t repeat our selves.
We can easily test this by testing the #my_feature_enabled method.
I say this is better code!
Think about how we wish the code could be used (i.e the API) before writing the code. Once we have a good idea of we wish it would work, we can then look at making it work.
Better defined as code I subjectively prefer. ↩
blog comments powered by Disqus