<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.9.0">Jekyll</generator><link href="http://ablogaboutcode.com//atom.xml" rel="self" type="application/atom+xml" /><link href="http://ablogaboutcode.com//" rel="alternate" type="text/html" /><updated>2020-10-17T23:48:37+00:00</updated><id>http://ablogaboutcode.com//atom.xml</id><title type="html">a.blog.about.code</title><subtitle>{ topic: &quot;code&quot;, type: &quot;blog&quot;, author: &quot;pan thomakos&quot; }</subtitle><author><name>Pan Thomakos</name></author><entry><title type="html">Productivity Engineering</title><link href="http://ablogaboutcode.com//2017/05/26/productivity-engineering" rel="alternate" type="text/html" title="Productivity Engineering" /><published>2017-05-26T00:00:00+00:00</published><updated>2017-05-26T00:00:00+00:00</updated><id>http://ablogaboutcode.com//2017/05/26/productivity-engineering</id><content type="html" xml:base="http://ablogaboutcode.com//2017/05/26/productivity-engineering">&lt;p&gt;On June 24th I’m giving a talk titled Developer Productivity Engineering (DPE) at &lt;a href=&quot;http://goruco.com/#speakers&quot;&gt;GORUCO&lt;/a&gt;. DPE is a framework that applies the principles of &lt;a href=&quot;https://en.wikipedia.org/wiki/Site_reliability_engineer&quot;&gt;Site Reliability Engineering&lt;/a&gt;, developed at Google, to improving productivity through automation.&lt;/p&gt;

&lt;p&gt;While putting together my intro for this talk I realized that there are a few terms in the orbit of “productivity engineering” and it can often be confusing to know what’s what.&lt;/p&gt;

&lt;p&gt;You may have seen any one of these terms in a job description recently:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;DevTools Engineer&lt;/li&gt;
  &lt;li&gt;Platform Engineer&lt;/li&gt;
  &lt;li&gt;Release Engineer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Companies all tend to define these roles a little differently. I’m not going to try to clearly demarcate each title, but I think I’ve got a pretty good working definition and some distinctions that might help.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Platform engineers&lt;/strong&gt; build systems on which other engineers build applications. Some canonical project examples might include implementing an event or queueing framework; or a scaling and maintaining a container orchestration cluster.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DevTools engineers&lt;/strong&gt; build tools that help other engineers do their work. Some canonical project examples might include CLI scripts or IDE extensions; or a continuous integration and build service.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Release engineers&lt;/strong&gt; build systems and create processes that enable engineers to ship code. Some canonical project examples might include automating a mobile release pipeline; or building a service to enable blue-green deployments.&lt;/p&gt;

&lt;p&gt;Some organizations do not distinguish between these roles, they will often have a single Platform team. Other organizations are so large that they will have multiple siloed teams for each of these roles.&lt;/p&gt;

&lt;p&gt;So where does productivity engineering fit in?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Productivity engineers&lt;/strong&gt; build systems, create processes, and facilitate development efforts that enable other engineers to be more productive.&lt;/p&gt;

&lt;p&gt;In a smaller company a productivity engineering team might own all of the example projects I listed above. In a larger organization the owned projects list may be smaller, but the team’s contributions as facilitators and contributors to other teams will likely be much broader.&lt;/p&gt;

&lt;p&gt;Productivity engineering is less focused on a single part of the development pipeline, and is instead focused on the bottlenecks in an organization. If the most pressing productivity slow-downs happen to be in a particular platform service that is not scaling, then productivity engineers have a role to play there.&lt;/p&gt;

&lt;p&gt;At least thus far, this is how I see productivity engineering fitting into an engineering organization. The DPE framework is really a way of identifying, measuring, and prioritizing the work that will make everyone more productive.&lt;/p&gt;</content><author><name>Pan Thomakos</name></author><summary type="html">On June 24th I’m giving a talk titled Developer Productivity Engineering (DPE) at GORUCO. DPE is a framework that applies the principles of Site Reliability Engineering, developed at Google, to improving productivity through automation.</summary></entry><entry><title type="html">Deploy Env Vs Rails Env</title><link href="http://ablogaboutcode.com//2017/04/07/deploy-env-vs-rails-env" rel="alternate" type="text/html" title="Deploy Env Vs Rails Env" /><published>2017-04-07T00:00:00+00:00</published><updated>2017-04-07T00:00:00+00:00</updated><id>http://ablogaboutcode.com//2017/04/07/deploy-env-vs-rails-env</id><content type="html" xml:base="http://ablogaboutcode.com//2017/04/07/deploy-env-vs-rails-env">&lt;p&gt;Reading through &lt;a href=&quot;https://www.schneems.com/2017/03/21/config-behavior-versus-credentials/&quot;&gt;Config: Behavior versus Credentials&lt;/a&gt; I was struck that, at Strava, we ran into this very same problem in our early Rails days. It didn’t take us long to realize:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RAILS_ENV&lt;/code&gt; is meant to configure the behavior of the Rails framework - not your application.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The clearest example of this distinction, as &lt;a href=&quot;https://twitter.com/schneems&quot;&gt;Richard Schneeman&lt;/a&gt; points out, is credentials. You do not want to tie credentials to a Rails environment. Credentials, regardless of how you manage them, should be configured based on the deployment environment.&lt;/p&gt;

&lt;p&gt;On the other side of this spectrum is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ActiveSupport&lt;/code&gt; autoloading. Autoloading is a framework responsibility. You should tie autoloading behavior to the Rails framework environment - not to your deployment environment.&lt;/p&gt;

&lt;p&gt;In practice, what does this mean? You effectively should specify two environment variables when running your application:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    RAILS_ENV=production DEPLOY_ENV=production ./run

    RAILS_ENV=production DEPLOY_ENV=staging ./run
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In reality the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DEPLOY_ENV&lt;/code&gt; might be a set of environment variables or a pointer to a configuration store. The core concept is that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DEPLOY_ENV&lt;/code&gt; is a different dimension of configuration than &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RAILS_ENV&lt;/code&gt;.&lt;/p&gt;</content><author><name>Pan Thomakos</name></author><summary type="html">Reading through Config: Behavior versus Credentials I was struck that, at Strava, we ran into this very same problem in our early Rails days. It didn’t take us long to realize:</summary></entry><entry><title type="html">How Strava Merges Code</title><link href="http://ablogaboutcode.com//2017/03/28/how-we-merge-code-at-strava" rel="alternate" type="text/html" title="How Strava Merges Code" /><published>2017-03-28T00:00:00+00:00</published><updated>2017-03-28T00:00:00+00:00</updated><id>http://ablogaboutcode.com//2017/03/28/how-we-merge-code-at-strava</id><content type="html" xml:base="http://ablogaboutcode.com//2017/03/28/how-we-merge-code-at-strava">&lt;p&gt;I wrote a post for Strava’s Engineering Blog about how we merge code:&lt;/p&gt;

&lt;h2 id=&quot;butler-merge-queue---how-strava-merges-code&quot;&gt;&lt;a href=&quot;http://labs.strava.com/blog/butler-merge-queue-how-strava-merges-code/&quot;&gt;Butler Merge Queue - How Strava Merges Code&lt;/a&gt;&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;For close to a year, a large portion of our repositories on GitHub have been using a fast-forward-only &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;master&lt;/code&gt; branch that is guaranteed to be green (all CI tests have passed) and that is guaranteed to have only Pull Request (reviewed) code in it. Developers fire-and-forget a Slack slash command that squashes their commits, runs all tests, merges their Pull Requests, and cleans up their Git branch. This is the story of how we got there.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href=&quot;http://labs.strava.com/blog/butler-merge-queue-how-strava-merges-code/&quot;&gt;Read more…&lt;/a&gt;&lt;/p&gt;</content><author><name>Pan Thomakos</name></author><category term="News" /><category term="productivity" /><category term="git" /><summary type="html">I wrote a post for Strava’s Engineering Blog about how we merge code:</summary></entry><entry><title type="html">Overwriting Console Output Using Curses in Ruby</title><link href="http://ablogaboutcode.com//2013/04/01/overwriting-console-output-using-curses-in-ruby" rel="alternate" type="text/html" title="Overwriting Console Output Using Curses in Ruby" /><published>2013-04-01T00:00:00+00:00</published><updated>2013-04-01T00:00:00+00:00</updated><id>http://ablogaboutcode.com//2013/04/01/overwriting-console-output-using-curses-in-ruby</id><content type="html" xml:base="http://ablogaboutcode.com//2013/04/01/overwriting-console-output-using-curses-in-ruby">&lt;p&gt;&lt;a href=&quot;http://translate.google.com/?hl=en&amp;amp;tab=TT&amp;amp;authuser=0#el/en/%CE%9A%CE%B1%CE%BB%CF%8C%20%CE%BC%CE%AE%CE%BD%CE%B1&quot;&gt;Καλό μήνα&lt;/a&gt;! A while back I wrote about how to
&lt;a href=&quot;/2012/04/16/overwriting-console-output-in-ruby&quot;&gt;overwrite console output in Ruby&lt;/a&gt;. Originally the project I used this
technique for only required overwriting a single line of output. That project
has now grown and I need to be able to maintain a mini-dashboard on the console.&lt;/p&gt;

&lt;p&gt;Fortunately, Ruby rocks and has a &lt;a href=&quot;http://www.ruby-doc.org/stdlib-2.0/libdoc/curses/rdoc/Curses.html&quot;&gt;standard library wrapper for Curses&lt;/a&gt;.
I would encourage you to read through the documentation. I’ve written a simple
script to show-off the most basic use-case. In this example I initialize ten
workers. Each worker is responsible for keeping track of the work she has
completed, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@percent&lt;/code&gt;, and then reporting that progress on her own line,
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@index&lt;/code&gt;, of the console.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;#!/usr/bin/env ruby&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'curses'&lt;/span&gt;

&lt;span class=&quot;no&quot;&gt;Curses&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;noecho&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;Curses&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;init_screen&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Worker&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initialize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@index&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@percent&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;run&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;work&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;report&lt;/span&gt;
      &lt;span class=&quot;nb&quot;&gt;sleep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;rand&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;Worker #&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'%2d'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@index&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; is &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'%3d'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@percent&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;% complete&quot;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;kp&quot;&gt;private&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;work&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@percent&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;report&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;Curses&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;setpos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;Curses&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;addstr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;to_s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;Curses&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;refresh&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;workers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Worker&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;at_exit&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;workers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;worker&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;worker&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;workers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;worker&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Thread&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;worker&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;run&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;no&quot;&gt;Curses&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;close_screen&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Because Curses clears the screen once it is complete, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;at_exit&lt;/code&gt; block
ensures that the last known state of the workers is echoed to the screen one
last time.&lt;/p&gt;

&lt;p&gt;Another command I found useful was the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Curses.clear&lt;/code&gt; command. This function
clears the entire screen before rewriting output. This is particularly helpful
when you want to overwrite a long line of text with a shorter one.&lt;/p&gt;

&lt;p&gt;I hope this was helpful! Have fun making some cool console applications. If you
build something worth sharing, please leave a comment that links to your code.&lt;/p&gt;</content><author><name>Pan Thomakos</name></author><category term="Tutorial" /><category term="ruby" /><summary type="html">Καλό μήνα! A while back I wrote about how to overwrite console output in Ruby. Originally the project I used this technique for only required overwriting a single line of output. That project has now grown and I need to be able to maintain a mini-dashboard on the console.</summary></entry><entry><title type="html">Context Driven Refactoring</title><link href="http://ablogaboutcode.com//2012/12/16/context-driven-refactoring" rel="alternate" type="text/html" title="Context Driven Refactoring" /><published>2012-12-16T00:00:00+00:00</published><updated>2012-12-16T00:00:00+00:00</updated><id>http://ablogaboutcode.com//2012/12/16/context-driven-refactoring</id><content type="html" xml:base="http://ablogaboutcode.com//2012/12/16/context-driven-refactoring">&lt;p&gt;I got excited about this refactoring website called &lt;a href=&quot;http://www.refactr.it&quot;&gt;refactr.it&lt;/a&gt;. Users
post refactoring questions and vote on the best answers. The website is kind of
a simplified version of the &lt;a href=&quot;http://programmers.stackexchange.com&quot;&gt;Programmers Stack Exchange&lt;/a&gt;. But as I explored
the ruby section, which is definitely still in it’s infancy, I was a little
disappointed.&lt;/p&gt;

&lt;p&gt;Here is an example of a question and solution that was titled
“&lt;a href=&quot;http://www.refactr.it/problems/50bab8def2f2231000000001&quot;&gt;Simplifying Nested If Statements&lt;/a&gt;”.&lt;/p&gt;

&lt;h2 id=&quot;question-code&quot;&gt;Question Code&lt;/h2&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;vi&quot;&gt;@problems&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@tags&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;blank?&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@language&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;nil?&lt;/span&gt;
            &lt;span class=&quot;no&quot;&gt;Problem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;where&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;language: &lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@language&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;desc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@sort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;page&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@page&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
            &lt;span class=&quot;no&quot;&gt;Problem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;desc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@sort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;page&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@page&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@language&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;nil?&lt;/span&gt;
            &lt;span class=&quot;no&quot;&gt;Problem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;tags: &lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@tags&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;where&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;language: &lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@language&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;desc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@sort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;page&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@page&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
            &lt;span class=&quot;no&quot;&gt;Problem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;tags: &lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@tags&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;desc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@sort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;page&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@page&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;solution-code&quot;&gt;Solution Code&lt;/h2&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;vi&quot;&gt;@problems&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Problem&lt;/span&gt;
&lt;span class=&quot;vi&quot;&gt;@problems&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@problems&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;tags: &lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@tags&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@tags&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;blank?&lt;/span&gt;
&lt;span class=&quot;vi&quot;&gt;@problems&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@problems&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;where&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;language: &lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@language&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@language&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;nil?&lt;/span&gt;
&lt;span class=&quot;vi&quot;&gt;@problems&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@problems&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;desc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@sort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;page&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@page&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The solution is definitely a start. In fact it “simplifies the nested if
statement” perfectly. And I would be a much happier programmer if I happened
upon the solution code than I would be if I came across the question code. My
disappointment is that the refactoring lacks context. It’s just an example of a
refactoring formula:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# Nested&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;A&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;B&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;Z&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;Z&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;B&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;Z&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;Z&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Not Nested&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;chain&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Z&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;chain&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;chain&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;A&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;chain&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;chain&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;B&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The solution is “correct”, and it’s a valuable technique, but it misses the
mark. Refactoring often falls short &lt;strong&gt;because&lt;/strong&gt; people blindly apply a selection
of these transformations and then call it a day. &lt;strong&gt;Refactoring isn’t just about
rewriting code.&lt;/strong&gt; Let’s take a look at a couple of questions that might help us
devise a better strategy for approaching this problem.&lt;/p&gt;

&lt;h2 id=&quot;question-one-why-should-i-refactor-this-code&quot;&gt;Question One: Why should I refactor this code?&lt;/h2&gt;

&lt;p&gt;Refactoring is fun, but if the code is a mess, and you don’t need to touch it,
&lt;a href=&quot;http://confreaks.com/videos/1115-gogaruco2012-go-ahead-make-a-mess&quot;&gt;leave it alone&lt;/a&gt;. As Sandi Metz explains, if you can’t see the mess, it
doesn’t exist. &lt;strong&gt;Refactoring should always happen for a reason.&lt;/strong&gt; In this case
there are multiple potential reasons we might need to refactor. But leaving that
reasoning out of the discussion can lead to a misguided solution.&lt;/p&gt;

&lt;p&gt;Do I need to add a new search parameter? Then I’m probably in need of a solution
that reduces complexity.&lt;/p&gt;

&lt;p&gt;Am I replicating this code somewhere else? Then I’m probably in need of a
solution that DRYs up my existing implementation.&lt;/p&gt;

&lt;h2 id=&quot;step-one-establish-a-context-for-the-refactoring&quot;&gt;Step One: Establish a context for the refactoring.&lt;/h2&gt;

&lt;p&gt;Let’s start with, “I need to add a new search parameter.” This helps us
establish that the code is too complex, and that we need to address this issue
because we need to change the code.&lt;/p&gt;

&lt;h2 id=&quot;question-two-how-am-i-going-to-test-this-code&quot;&gt;Question Two: How am I going to test this code?&lt;/h2&gt;

&lt;p&gt;Imagine, first without using a database, how you would go about testing the
question code, or even the solution code for that matter. You would definitely
have to provide stubs for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#in&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#where&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#sort&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#page&lt;/code&gt;. You would have
to test conditionals for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@language&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@tags&lt;/code&gt;, and your new search parameter.
And all those tests have to combined with the rest of the controller tests for
the search action.&lt;/p&gt;

&lt;p&gt;Even if you allowed yourself use of the database, you would still have to
construct objects for each of the test scenarios and verify that the
conditionals were working properly.&lt;/p&gt;

&lt;p&gt;That’s a lot of stuff (otherwise know as responsibilities). The “always write
tests” mantra isn’t just meant to increase code confidence, it helps illuminate
design flaws and unwanted complexity.&lt;/p&gt;

&lt;h2 id=&quot;step-two-readwrite-tests&quot;&gt;Step Two: Read/Write Tests.&lt;/h2&gt;

&lt;p&gt;Assuming the tests don’t already exist, write them. Even though they are brutal
to write after the fact, you need to have test coverage before you start moving
code around.&lt;/p&gt;

&lt;h2 id=&quot;question-three-what-did-the-tests-teach-us&quot;&gt;Question Three: What did the tests teach us?&lt;/h2&gt;

&lt;p&gt;Probably that we have a “Fat Controller”. You’ve probably heard of “Fat Models,
Skinny Controllers”, but this heuristic does not really mean Fat
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ActiveRecord::Base&lt;/code&gt; classes and Skinny &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ApplicationController&lt;/code&gt; classes. It
means that objects responsible for connecting business logic and views, should
do only that. It’s the “Single Responsibility Principle” in Rails terms.&lt;/p&gt;

&lt;p&gt;The reason we should strive for single responsibility objects is that they are
easier to extend and test. In this case we’ve seen how difficult it is to test
the code (in both the question and the solution) which indicates that the
proposed solution should probably not be our first refactoring step.&lt;/p&gt;

&lt;h2 id=&quot;step-three-refactor-your-code&quot;&gt;Step Three: Refactor Your Code&lt;/h2&gt;

&lt;p&gt;Because the tests indicated an unnecessary complexity, we know that we should
probably introduce a new object this is responsible for handling some of the
logic, without involving the controller.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;vi&quot;&gt;@problems&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ProblemSearch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@language&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@tags&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@sort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@page&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;find&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;So what goes into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ProblemSearch#find&lt;/code&gt;? Probably the original solution, but
at this point it really doesn’t matter because it’s completely isolated. The
original non-nested code is definitely simpler and easier to extend than the
nested code, but that’s the transformation part of refactoring, not the reason
we are refactoring in the first place.&lt;/p&gt;

&lt;p&gt;You should always simplify your programming constructs so that they are more
intention revealing, but the meat of this refactoring is really in the domain
modelling and the tests. The original code had too many responsibilities, it
was hard to test, and it was hard to extend.&lt;/p&gt;

&lt;p&gt;When we needed to add a new search parameter and tried writing tests, we
realized how complex that was going to be and identified the need for a
refactoring. Allowing that context to guide us, resulted in an intention
revealing, testable and extensible solution.&lt;/p&gt;</content><author><name>Pan Thomakos</name></author><category term="Refactoring" /><category term="ruby" /><category term="refactoring" /><summary type="html">I got excited about this refactoring website called refactr.it. Users post refactoring questions and vote on the best answers. The website is kind of a simplified version of the Programmers Stack Exchange. But as I explored the ruby section, which is definitely still in it’s infancy, I was a little disappointed.</summary></entry><entry><title type="html">Actually Always Refactoring</title><link href="http://ablogaboutcode.com//2012/09/26/actually-always-refactoring" rel="alternate" type="text/html" title="Actually Always Refactoring" /><published>2012-09-26T00:00:00+00:00</published><updated>2012-09-26T00:00:00+00:00</updated><id>http://ablogaboutcode.com//2012/09/26/actually-always-refactoring</id><content type="html" xml:base="http://ablogaboutcode.com//2012/09/26/actually-always-refactoring">&lt;p&gt;I apologize, it’s been a while since my last blog post. After being sick, doing
a lot of climbing, and some traveling, I attended &lt;a href=&quot;http://gogaruco.com/&quot;&gt;GoGaRuCo 2012&lt;/a&gt;. It
was my first Ruby conference and it really opened my eyes to the active and
friendly community of Ruby. It gave me the boost I needed to sit down and write
another blog post.&lt;/p&gt;

&lt;p&gt;While on my hiatus, some comments trickled in on old blog posts. I do want to go
back and write updated versions of a few of my older articles. But today I want
to talk about Refactoring. I watched
&lt;a href=&quot;http://www.confreaks.com/videos/1071-cascadiaruby2012-therapeutic-refactoring&quot;&gt;Therapeutic Refactoring by Katrina Owen&lt;/a&gt; the other day and it got me
thinking. While I was at GoGaRuCo I made a point of talking to people, and I
noticed the sly smile on their faces when I told them that, “I love
refactoring.” They loved it too. So why don’t we do more of it? If it’s
therapeutic, if it’s exciting and makes our code better, why aren’t we always
refactoring?&lt;/p&gt;

&lt;p&gt;The reason, I think, is that along with that feeling of making our code awesome,
and coding purely to write code - no feature requests, there is a very real
feeling of &lt;a href=&quot;http://i.imgur.com/wGUTG.gif&quot;&gt;impending doom&lt;/a&gt;. What if I pull on a thread that
unravels the system? What if I find out that refactoring the mailer actually
means I need to refactor the entire user object?&lt;/p&gt;

&lt;p&gt;We’ve all experienced that elated feeling after watching a great presentation
about refactoring. We head back to our keyboards, determined to make our code
better.  But in reality the systems we encounter are never as simple as the
examples we’ve just seen. The same tricks don’t apply. Our objects aren’t easy
to isolate, they aren’t easy to test and are often so complex that it hurts to
even think about them.&lt;/p&gt;

&lt;p&gt;So what are we to do? Here are my thoughts.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Change your mindset. The goal is not to make the system &lt;strong&gt;perfect&lt;/strong&gt; and
&lt;strong&gt;easy&lt;/strong&gt; to understand. The goal is to make the system &lt;strong&gt;better&lt;/strong&gt; and
&lt;strong&gt;easier&lt;/strong&gt; to understand.&lt;/li&gt;
  &lt;li&gt;It’s okay to stop. Start small - even if it’s not the final solution. Pick
one function, a few lines or even one line of code, and work on that first.
Think about creating a pull request with the changes you’ve just made. Would
your peers be able to reason about your changes?&lt;/li&gt;
  &lt;li&gt;Don’t be afraid to replace two messes with one mess (of equal and approximate
size). It’s an evolving process and each piece of code does not need to be
final or pretty, it just needs to make your program better in one way. Take
another stab at refactoring duplication or complexity once the first step is
done. Too many times have I been sucked down the rat hole of trying to fix
all the messy parts at once.&lt;/li&gt;
  &lt;li&gt;Find someone to share the experience with. Pair refactoring is a great way to
tackle the larger messes.&lt;/li&gt;
  &lt;li&gt;Refactor all the time. When a new feature request comes along, see if you can
refactor first, in a separate commit. Then implement the feature. The goal
is to make the feature commit simpler.&lt;/li&gt;
  &lt;li&gt;Demand refactoring. If you don’t have the support to refactor then get that
support or find a company/client that values it. Refactoring makes code
better. Better code makes better products and better jobs.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I hope that helps. And keep your spirits up. Refactoring isn’t easy to do the
first time. Soon enough though, you’ll begin to view it as “your feature
request.” And it will be a regular part of your awesome day.&lt;/p&gt;</content><author><name>Pan Thomakos</name></author><category term="Refactoring" /><category term="ruby" /><category term="refactoring" /><summary type="html">I apologize, it’s been a while since my last blog post. After being sick, doing a lot of climbing, and some traveling, I attended GoGaRuCo 2012. It was my first Ruby conference and it really opened my eyes to the active and friendly community of Ruby. It gave me the boost I needed to sit down and write another blog post.</summary></entry><entry><title type="html">Fixtures and Factories</title><link href="http://ablogaboutcode.com//2012/06/21/fixtures-and-factories" rel="alternate" type="text/html" title="Fixtures and Factories" /><published>2012-06-21T00:00:00+00:00</published><updated>2012-06-21T00:00:00+00:00</updated><id>http://ablogaboutcode.com//2012/06/21/fixtures-and-factories</id><content type="html" xml:base="http://ablogaboutcode.com//2012/06/21/fixtures-and-factories">&lt;p&gt;I recently converted a test suite that only used factories to a hybrid that uses
a combination of factories and fixtures. While I really like the simplicity and
cleanliness of factories, fixtures are simply unbeatable in some cases. I had
never really used both together in the same project, so I wanted to outline the
pros and cons of each, as well as how they work together.&lt;/p&gt;

&lt;h3 id=&quot;loading-and-creating-data-performance&quot;&gt;Loading and Creating Data (Performance)&lt;/h3&gt;

&lt;p&gt;If you’re loading all of your fixtures at the beginning of every test you’re
missing out on one of their major benefits - loading a lot of data only once.
Instead, switch to loading all of your fixtures at the beginning of the entire
test suite, and then using transactions around each test for cleanup. That way
the base fixture data hangs around and each test takes care of cleaning up its
own changes. Since generating data can be more expensive than saving it to the
database, this simple change can result in dramatic performance gains.&lt;/p&gt;

&lt;p&gt;When using factories you have the benefit of creating only the data you want.
You may face some degraded performance caused by create operations, since you’ll
have to process all those pesky callbacks, but you will benefit from having more
isolated tests and data.&lt;/p&gt;

&lt;h3 id=&quot;sharing-and-customizing-data-maintainability&quot;&gt;Sharing and Customizing Data (Maintainability)&lt;/h3&gt;

&lt;p&gt;Fixtures often make customizations to data more complex. It’s certainly a lot
harder to change fixtures because other tests depend on that very same data.
Certainly a slew of update statements is going to offset some of that
performance gain of having data pre-loaded as well.&lt;/p&gt;

&lt;p&gt;I often find that fixture based tests end up doing a lot of pre-assertions to
ensure that data is in the correct state. If that’s the case in your tests it’s
probably worth asking yourself if you could be using factories instead.&lt;/p&gt;

&lt;p&gt;One way to combat the fixture modification data is to combine fixtures and
factories. For instance, if you need to parse a large XML file and then create
a model from that data, do the parsing ahead of time, store it as a fixture, and
then use that model as a base for your factories.&lt;/p&gt;

&lt;p&gt;Factories should generally be an MVO, or minimally-viable-object. Data sharing
becomes a non-issue because each object adds only what it needs without worrying
about conflicting with other objects or tests.&lt;/p&gt;

&lt;h3 id=&quot;proximity-of-data-and-assertions-ease-of-use&quot;&gt;Proximity of Data and Assertions (Ease of Use)&lt;/h3&gt;

&lt;p&gt;In the fixture approach it’s often harder to find the data related to a test
because it’s usually contained in another file. Sometimes this is unavoidable,
even with factories, but it’s more often the case that fixture data lives in
some other file. If you are making an assertion about data, it’s best to have
that data near the assertion.&lt;/p&gt;

&lt;p&gt;In the factory approach the relevant data declarations and modifications are
all contained in the same test file which makes the test cases easier to read
and follow.&lt;/p&gt;

&lt;h3 id=&quot;rule-of-thumb&quot;&gt;Rule of Thumb&lt;/h3&gt;

&lt;p&gt;No approach is ever 100% better. In fact you’ll probably see the greatest
performance gains and have the most fun by using both factories and fixtures.
It feels great to use the right tool for the job. If you use transactions to
clean your tests then the two approaches work very well together. Fixtures will
load data before the entire suite, and then each test will automatically
rollback any changes to fixture data, and remove any factories it created.&lt;/p&gt;

&lt;p&gt;As a rule of thumb, if data is expensive to create, it’s probably better to use
fixtures. If data requires many small customizations, it’s probably better to
use factories.&lt;/p&gt;</content><author><name>Pan Thomakos</name></author><category term="Best Practices" /><category term="ruby" /><category term="rails" /><category term="tdd" /><summary type="html">I recently converted a test suite that only used factories to a hybrid that uses a combination of factories and fixtures. While I really like the simplicity and cleanliness of factories, fixtures are simply unbeatable in some cases. I had never really used both together in the same project, so I wanted to outline the pros and cons of each, as well as how they work together.</summary></entry><entry><title type="html">Benchmark Your Bundle</title><link href="http://ablogaboutcode.com//2012/05/03/benchmark-your-bundle" rel="alternate" type="text/html" title="Benchmark Your Bundle" /><published>2012-05-03T00:00:00+00:00</published><updated>2012-05-03T00:00:00+00:00</updated><id>http://ablogaboutcode.com//2012/05/03/benchmark-your-bundle</id><content type="html" xml:base="http://ablogaboutcode.com//2012/05/03/benchmark-your-bundle">&lt;p&gt;Your Rails app takes anywhere from 20 seconds to a minute to boot.
&lt;a href=&quot;/2012/01/12/a-simple-rails-boot-time-improvement/&quot;&gt;Maybe you’ve even tried to optimize your gem loading&lt;/a&gt;. But which
gems are actually causing you all that trouble? How can you pinpoint the gems to
delay, replace or optimize?&lt;/p&gt;

&lt;p&gt;Here’s a simple script I wrote to benchmark the loading of each of the gems in
your Gemfile. A gist can be found &lt;a href=&quot;https://gist.github.com/2588879&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;#!/usr/bin/env ruby&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'benchmark'&lt;/span&gt;

&lt;span class=&quot;no&quot;&gt;REGEXPS&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;sr&quot;&gt;/^no such file to load -- (.+)$/i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;sr&quot;&gt;/^Missing \w+ (?:file\s*)?([^\s]+.rb)$/i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;sr&quot;&gt;/^Missing API definition file in (.+)$/i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;sr&quot;&gt;/^cannot load such file -- (.+)$/i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;pull&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;required_file&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;begin&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;autorequire&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;required_file&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;
      &lt;span class=&quot;no&quot;&gt;Kernel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;rescue&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;LoadError&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;autorequire&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;nil?&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;include?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'-'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;begin&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;namespaced_file&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;gsub&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'-'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;no&quot;&gt;Kernel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;namespaced_file&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;rescue&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;LoadError&lt;/span&gt;
        &lt;span class=&quot;no&quot;&gt;REGEXPS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;find&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=~&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;raise&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;autorequire&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;vg&quot;&gt;$1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;gsub&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'-'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;namespaced_file&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
      &lt;span class=&quot;no&quot;&gt;REGEXPS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;find&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=~&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;raise&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;autorequire&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;vg&quot;&gt;$1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;required_file&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'rails/all'&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# If you would prefer gems to incur the cost of autoloading&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# Rails frameworks, then comment out this next line.&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;ActiveSupport&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Autoload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;eager_autoload!&lt;/span&gt;

&lt;span class=&quot;vg&quot;&gt;$VERBOSE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;

&lt;span class=&quot;no&quot;&gt;Benchmark&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;bm&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;no&quot;&gt;Bundler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;setup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dependency&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;report&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dependency&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ljust&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;21&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;pull&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dependency&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;All of the code in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#pull&lt;/code&gt; has been plucked right out of the
&lt;a href=&quot;https://github.com/carlhuda/bundler/blob/d351e68fa0a5df6de7aff587effce0801297848a/lib/bundler/runtime.rb#L51&quot;&gt;Bundler require function&lt;/a&gt;. It’s responsible for loading
a gem depending on its Gemfile configuration. It considers custom require paths,
and generally converts dashes into slashes if it can’t load the file.&lt;/p&gt;

&lt;p&gt;The script then loads rails (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;require 'rails/all'&lt;/code&gt;) - something you won’t be
able to avoid either way. It also turns warnings off (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$VERBOSE = nil&lt;/code&gt;) so that
the benchmarking output looks a little nicer.&lt;/p&gt;

&lt;p&gt;Once that setup is complete, it loops through each of the gem dependencies and
requires them. Your output will probably look something like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;rails&lt;/span&gt;                  &lt;span class=&quot;mf&quot;&gt;0.000000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.000000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.000000&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;  &lt;span class=&quot;mf&quot;&gt;0.000215&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;aws&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s3&lt;/span&gt;                 &lt;span class=&quot;mf&quot;&gt;0.160000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.030000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.190000&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;  &lt;span class=&quot;mf&quot;&gt;0.182991&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;declarative_authoriza&lt;/span&gt;  &lt;span class=&quot;mf&quot;&gt;0.850000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.120000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.970000&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;  &lt;span class=&quot;mf&quot;&gt;0.970152&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;fog&lt;/span&gt;                    &lt;span class=&quot;mf&quot;&gt;0.530000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.060000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.590000&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;  &lt;span class=&quot;mf&quot;&gt;0.589278&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;mysql2&lt;/span&gt;                 &lt;span class=&quot;mf&quot;&gt;0.010000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.000000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.010000&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;  &lt;span class=&quot;mf&quot;&gt;0.012908&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;nokogiri&lt;/span&gt;               &lt;span class=&quot;mf&quot;&gt;0.000000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.000000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.000000&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;  &lt;span class=&quot;mf&quot;&gt;0.000285&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;oauth2&lt;/span&gt;                 &lt;span class=&quot;mf&quot;&gt;0.140000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.010000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.150000&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;  &lt;span class=&quot;mf&quot;&gt;0.156330&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;rack&lt;/span&gt;                   &lt;span class=&quot;mf&quot;&gt;0.000000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.000000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.000000&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;  &lt;span class=&quot;mf&quot;&gt;0.000232&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;rails_autolink&lt;/span&gt;         &lt;span class=&quot;mf&quot;&gt;0.000000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.000000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.000000&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;  &lt;span class=&quot;mf&quot;&gt;0.000854&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;rpm_contrib&lt;/span&gt;            &lt;span class=&quot;mf&quot;&gt;0.450000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.030000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.480000&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;  &lt;span class=&quot;mf&quot;&gt;0.482697&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;timezone&lt;/span&gt;               &lt;span class=&quot;mf&quot;&gt;0.010000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.000000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.010000&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;  &lt;span class=&quot;mf&quot;&gt;0.007698&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;jquery&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rails&lt;/span&gt;           &lt;span class=&quot;mf&quot;&gt;0.010000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.000000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.010000&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;  &lt;span class=&quot;mf&quot;&gt;0.008963&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;hike&lt;/span&gt;                   &lt;span class=&quot;mf&quot;&gt;0.000000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.000000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.000000&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;  &lt;span class=&quot;mf&quot;&gt;0.001602&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;sass&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rails&lt;/span&gt;             &lt;span class=&quot;mf&quot;&gt;0.370000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.020000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.390000&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;  &lt;span class=&quot;mf&quot;&gt;0.400510&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;coffee&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rails&lt;/span&gt;           &lt;span class=&quot;mf&quot;&gt;0.120000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.020000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.140000&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;  &lt;span class=&quot;mf&quot;&gt;0.136651&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;uglifier&lt;/span&gt;               &lt;span class=&quot;mf&quot;&gt;0.000000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.000000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.000000&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;  &lt;span class=&quot;mf&quot;&gt;0.002760&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;capybara&lt;/span&gt;               &lt;span class=&quot;mf&quot;&gt;0.010000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.010000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.020000&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;  &lt;span class=&quot;mf&quot;&gt;0.006783&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;capybara&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;webkit&lt;/span&gt;        &lt;span class=&quot;mf&quot;&gt;0.050000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.000000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.050000&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;  &lt;span class=&quot;mf&quot;&gt;0.053145&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;database_cleaner&lt;/span&gt;       &lt;span class=&quot;mf&quot;&gt;0.000000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.000000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.000000&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;  &lt;span class=&quot;mf&quot;&gt;0.007077&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;gherkin&lt;/span&gt;                &lt;span class=&quot;mf&quot;&gt;0.070000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.010000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.080000&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;  &lt;span class=&quot;mf&quot;&gt;0.068361&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;jasmine&lt;/span&gt;                &lt;span class=&quot;mf&quot;&gt;0.020000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.000000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.020000&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;  &lt;span class=&quot;mf&quot;&gt;0.025752&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;jasmine&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;headless&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;webk&lt;/span&gt;  &lt;span class=&quot;mf&quot;&gt;0.000000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.000000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.000000&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;  &lt;span class=&quot;mf&quot;&gt;0.010595&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;launchy&lt;/span&gt;                &lt;span class=&quot;mf&quot;&gt;0.060000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.010000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.070000&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;  &lt;span class=&quot;mf&quot;&gt;0.060992&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;rspec&lt;/span&gt;                  &lt;span class=&quot;mf&quot;&gt;0.350000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.030000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.380000&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;  &lt;span class=&quot;mf&quot;&gt;0.385097&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;rspec&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rails&lt;/span&gt;            &lt;span class=&quot;mf&quot;&gt;0.000000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.000000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.000000&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;  &lt;span class=&quot;mf&quot;&gt;0.000903&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;sham&lt;/span&gt;                   &lt;span class=&quot;mf&quot;&gt;0.030000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.000000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.030000&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;  &lt;span class=&quot;mf&quot;&gt;0.025905&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;spork&lt;/span&gt;                  &lt;span class=&quot;mf&quot;&gt;0.000000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.000000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.000000&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;  &lt;span class=&quot;mf&quot;&gt;0.003553&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;timecop&lt;/span&gt;                &lt;span class=&quot;mf&quot;&gt;0.040000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.000000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.040000&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;  &lt;span class=&quot;mf&quot;&gt;0.041003&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;guard&lt;/span&gt;                  &lt;span class=&quot;mf&quot;&gt;0.000000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.000000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.000000&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;  &lt;span class=&quot;mf&quot;&gt;0.003354&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;rb&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fsevent&lt;/span&gt;             &lt;span class=&quot;mf&quot;&gt;0.010000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.000000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.010000&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;  &lt;span class=&quot;mf&quot;&gt;0.004126&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;guard&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;spork&lt;/span&gt;            &lt;span class=&quot;mf&quot;&gt;0.000000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.000000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.000000&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;  &lt;span class=&quot;mf&quot;&gt;0.008679&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unit&lt;/span&gt;              &lt;span class=&quot;mf&quot;&gt;0.130000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.010000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.140000&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;  &lt;span class=&quot;mf&quot;&gt;0.132788&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;webmock&lt;/span&gt;                &lt;span class=&quot;mf&quot;&gt;0.150000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.020000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.170000&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;  &lt;span class=&quot;mf&quot;&gt;0.167813&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;vcr&lt;/span&gt;                    &lt;span class=&quot;mf&quot;&gt;0.060000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.000000&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.060000&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;  &lt;span class=&quot;mf&quot;&gt;0.068362&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;I’ve condensed the output, but the total load time was 5 seconds. You can verify
that by benchmarking &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Bundler.require&lt;/code&gt; in your own application. You’ll also
notice that the declarative authorization gem took up approximately 1 second
(20% of the total time) to load.  Maybe it’s a good candidate for an upgrade,
replacement or optimization.&lt;/p&gt;</content><author><name>Pan Thomakos</name></author><category term="Under the Hood" /><category term="ruby" /><category term="rails" /><summary type="html">Your Rails app takes anywhere from 20 seconds to a minute to boot. Maybe you’ve even tried to optimize your gem loading. But which gems are actually causing you all that trouble? How can you pinpoint the gems to delay, replace or optimize?</summary></entry><entry><title type="html">Overwriting Console Output in Ruby</title><link href="http://ablogaboutcode.com//2012/04/16/overwriting-console-output-in-ruby" rel="alternate" type="text/html" title="Overwriting Console Output in Ruby" /><published>2012-04-16T00:00:00+00:00</published><updated>2012-04-16T00:00:00+00:00</updated><id>http://ablogaboutcode.com//2012/04/16/overwriting-console-output-in-ruby</id><content type="html" xml:base="http://ablogaboutcode.com//2012/04/16/overwriting-console-output-in-ruby">&lt;p&gt;I’ve always liked the way some long running console utilities display their
status without having to print a new line. For example the little spinner that
alternates displaying &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;|&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\&lt;/code&gt;. Or various internet utilities that
display the percentage of the file that has been downloaded.&lt;/p&gt;

&lt;p&gt;I recently wrote a utility to kick off parallel RSpec tasks on remote instances
and wanted to report the results back to the console after pinging the utility
every few seconds. I accomplished this with a cool little trick - the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\r&lt;/code&gt;.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;percent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\r&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;percent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;% complete&quot;&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;sleep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This little scripts begins by printing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;10% complete&lt;/code&gt; and works up to
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;100% complete&lt;/code&gt; in 10 percent increments. It’s a cool way to notify the user
of your Ruby utility that the script is still progressing and that it hasn’t
simply stopped dead in its tracks.&lt;/p&gt;

&lt;p&gt;One thing to keep in mind is that you are overwriting the previous line, so
if your previous line is of a longer length than the next one, you might need to
pad it with whitespace to cover up the last message.&lt;/p&gt;</content><author><name>Pan Thomakos</name></author><category term="Tutorial" /><category term="ruby" /><summary type="html">I’ve always liked the way some long running console utilities display their status without having to print a new line. For example the little spinner that alternates displaying |, /, and \. Or various internet utilities that display the percentage of the file that has been downloaded.</summary></entry><entry><title type="html">Respect the Active Record</title><link href="http://ablogaboutcode.com//2012/03/22/respect-the-active-record" rel="alternate" type="text/html" title="Respect the Active Record" /><published>2012-03-22T00:00:00+00:00</published><updated>2012-03-22T00:00:00+00:00</updated><id>http://ablogaboutcode.com//2012/03/22/respect-the-active-record</id><content type="html" xml:base="http://ablogaboutcode.com//2012/03/22/respect-the-active-record">&lt;p&gt;Here’s some bad Rails code I often come across:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;Author&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;where&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;public: &lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;where&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'score &amp;gt; ?'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;a href=&quot;/2012/02/27/understanding-the-law-of-demeter/&quot;&gt;The problem isn’t that we’re chaining&lt;/a&gt;. Because we’re only handling
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ActiveRecord::Relation&lt;/code&gt; objects, we aren’t increasing the complexity or
responsibility of our code by the mere act of chaining. Chaining is a useful
programming pattern. However, we are increasing the complexity of our code by
making assumptions about the internal workings of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Author&lt;/code&gt; - we’re breaking
encapsulation. Even if you feel that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ActiveRecord&lt;/code&gt; makes this easy to do, it
doesn’t mean you should do it.&lt;/p&gt;

&lt;p&gt;We shouldn’t know that authors have internal &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;score&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;public&lt;/code&gt; attributes.
Keep in mind that this is different from being able to call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Author#score&lt;/code&gt; and
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Author#public&lt;/code&gt;, because in the former case, we actually “know” a lot more about
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Author&lt;/code&gt; and we make some unhealthy assumptions.&lt;/p&gt;

&lt;p&gt;In particular we make the assumption that these two statements are logically
equivalent:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;Author&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;select&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;score&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;50&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;no&quot;&gt;Author&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;where&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;score: &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;all&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;In short, this code is asking &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Author&lt;/code&gt; to perform an operation based on an
assumed internal state. We are asking - not telling. That’s not good.&lt;/p&gt;

&lt;p&gt;Telling &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Author&lt;/code&gt; to give us this data looks very different:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;Author&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;with_public_account&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;with_score_above&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Having this kind of interface for our objects benefits us in a couple of
really awesome ways.&lt;/p&gt;

&lt;h3 id=&quot;readability&quot;&gt;Readability&lt;/h3&gt;

&lt;p&gt;Using intentionally crafted public interfaces for your objects makes them easier
to read and more descriptive. This is usually a by-product of the simple fact
that you are naming your methods instead of using what is already there. Keep in
mind that ORMs were created as a general infrastructure for many different kinds
of applications. There is no need to expose that infrastructure to your own
application. It makes more sense to write &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Author.with_public_account&lt;/code&gt; than it
does to write &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Author.where(public: true)&lt;/code&gt;. The intent is clearly communicated.&lt;/p&gt;

&lt;h3 id=&quot;searchability&quot;&gt;Searchability&lt;/h3&gt;

&lt;p&gt;Searching for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;where.*score&lt;/code&gt; in a code base can be tedious and might not result
in catching all the possible use cases. Code structured like this can easily be
missed:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;conditions&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;score: &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;Author&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;where&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;conditions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;By contrast, searching for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;with_score_above&lt;/code&gt; is much more likely to yield
usable and accurate results. Obviously having a full test suite helps alleviate
this kind of a refactoring, but that doesn’t mean you should make it difficult
for others to track down your handiwork.&lt;/p&gt;

&lt;h3 id=&quot;changeability&quot;&gt;Changeability&lt;/h3&gt;

&lt;p&gt;Have a more explicit interface makes it easier to change our ORM from
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ActiveRecord&lt;/code&gt; if we ever choose to. It makes it easier to make small attribute
level changes, like renaming score. That’s because we now only need to modify
the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Author&lt;/code&gt; object, not every piece of code that filters authors on score. You
could imagine a future implementation that looks something like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;AuthorRelation&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initialize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;authors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@authors&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;authors&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;with_public_account&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@authors&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@authors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;select&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;public?&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;paid?&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;with_score_above&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;score&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@authors&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@authors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;select&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;cached_score&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;score&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;If you’re thinking - why would I ever want to change something like that? Then
you’ve missed the point. This isn’t a pre-optimization, this is a philosophy for
creating persistence objects that behave like simple Ruby objects, without
exception. It’s a slippery slope to assume that some objects just aren’t going
to change and that kind of thinking causes headaches for the rest of your code
and for other developers working with code you’ve written.&lt;/p&gt;

&lt;p&gt;What if we didn’t change the entire object; what if we simply denormalized and
indexed a flag that combined &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;score&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;public&lt;/code&gt;? Our carefully crafted public
interface would allow us to make use of this new column, whereas being tied to
the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;where&lt;/code&gt; way of doing things would mean having to modify a lot more code.&lt;/p&gt;

&lt;h3 id=&quot;testability&quot;&gt;Testability&lt;/h3&gt;

&lt;p&gt;It’s easier to begin building an application without being tied to the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ActiveRecord&lt;/code&gt; way of doing things. This frees us up to write isolated tests and
hide &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ActiveRecord&lt;/code&gt; as a true implementation detail, rather than making it a
central part of our application. No object or collection of objects should
dominate your code. Some objects might be more or less connected, but that
doesn’t mean they should be required to test one another. Isolation is a great
thing.&lt;/p&gt;

&lt;h3 id=&quot;summary&quot;&gt;Summary&lt;/h3&gt;

&lt;p&gt;Respect the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ActiveRecord&lt;/code&gt;. Let it do what it does best, as a piece of
infrastructure and as a 3rd party library. Its way of doing things and its
method signatures should not infect the rest of your application. It does what
it does best when it’s limited to and hidden inside of your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ActiveRecord::Base&lt;/code&gt;
objects.&lt;/p&gt;</content><author><name>Pan Thomakos</name></author><category term="Best Practices" /><category term="rails" /><category term="active record" /><summary type="html">Here’s some bad Rails code I often come across:</summary></entry></feed>