<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Reactoring on CodeGoalie</title><link>https://codegoalie.com/categories/reactoring/</link><description>Recent content in Reactoring on CodeGoalie</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><lastBuildDate>Fri, 12 Jan 2018 08:20:15 -0500</lastBuildDate><atom:link href="https://codegoalie.com/categories/reactoring/index.xml" rel="self" type="application/rss+xml"/><item><title>Ruby refactoring: Open/Closed Principle</title><link>https://codegoalie.com/posts/ruby-open-closed/</link><pubDate>Fri, 12 Jan 2018 08:20:15 -0500</pubDate><guid>https://codegoalie.com/posts/ruby-open-closed/</guid><description>&lt;p>Let&amp;rsquo;s examine a refactoring to move code to follow the
&lt;a href="https://en.wikipedia.org/wiki/Open/closed_principle">open/closed principle&lt;/a>.
We&amp;rsquo;ll see how the resulting calling code becomes much easier to read locally,
without having to open other files or classes to understand what&amp;rsquo;s going on.&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;h2 id="openclosed-principle">Open/closed principle&lt;/h2>
&lt;p>First, let&amp;rsquo;s do a quick recap of the open/closed principle. Classes should be
open to extension, but closed to modification. What does that mean? Let&amp;rsquo;s take
it a half at a time.&lt;/p>
&lt;p>&amp;ldquo;Classes should be open to extension.&amp;rdquo; This means building
your classes in a way that they are simple and single-use enough to be reusable
or combine-able. This is the difference between building a Lego brick and a
fully built spaceship. The spaceship is more complete, but when you&amp;rsquo;re tired of
playing spaceships, you can&amp;rsquo;t easily reconfigure it into something else.&lt;/p>
&lt;p>Second, &amp;ldquo;classes should be closed to modification.&amp;rdquo; Violating this
principle will require you to modify far off code to implement your current
feature. You should structure your code to avoid this because you may forget
to change that far off code, other developers on the team may not know to change
that code, and it&amp;rsquo;s often a mystery why this far off code is even related.
More practically, this often manifests in a list of classes, types, &amp;ldquo;allowed&amp;rdquo;
things, &amp;ldquo;blacklisted&amp;rdquo; stuff, etc. If you add a new class and then have to add
that class to a list somewhere, you&amp;rsquo;re probably not following open/closed.&lt;/p>
&lt;h2 id="sending-update-notifications">Sending update notifications&lt;/h2>
&lt;p>I recently had a project where we wanted to send some update notifications to
users when entities they were interested in were updated by other users. This
Rails application exposes a JSON API and has a bulk update mechanism. The
controller action which handles these bulk requests is generic such that many
types of models can be updated simultaneously. After successful updates, we
schedule a background job to send the update notifications:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-ruby" data-lang="ruby">&lt;span style="color:#66d9ef">if&lt;/span> entity&lt;span style="color:#f92672">.&lt;/span>save
&lt;span style="color:#66d9ef">SendUpdateNotificationJob&lt;/span>&lt;span style="color:#f92672">.&lt;/span>perform_later(entity)
&lt;span style="color:#f92672">...&lt;/span>
&lt;span style="color:#66d9ef">end&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Initially we only sent updates for new or updated Posts:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-ruby" data-lang="ruby">&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">SendUpdateNotificationJob&lt;/span> &lt;span style="color:#f92672">&amp;lt;&lt;/span> &lt;span style="color:#66d9ef">ApplicationJob&lt;/span>
&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">perform&lt;/span>(entity)
&lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#66d9ef">unless&lt;/span> entity&lt;span style="color:#f92672">.&lt;/span>class &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#66d9ef">Post&lt;/span>
&lt;span style="color:#75715e"># send push notifications here&lt;/span>
&lt;span style="color:#66d9ef">end&lt;/span>
&lt;span style="color:#66d9ef">end&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="adding-more-notification-types">Adding more notification types&lt;/h2>
&lt;p>Seems reasonable enough. However, new and updated post notifications were such
a hit that when we added responses to the application, people asked to get
updates for them as well. Super easy to do that:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-diff" data-lang="diff">&lt;span style="color:#f92672">- return unless entity.class == Post
&lt;/span>&lt;span style="color:#f92672">&lt;/span>&lt;span style="color:#a6e22e">+ return unless entity.class == Post || entitty.class == Response
&lt;/span>&lt;span style="color:#a6e22e">&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;p>And then bulletins&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-diff" data-lang="diff">&lt;span style="color:#f92672">- return unless entity.class == Post || entitty.class == Response
&lt;/span>&lt;span style="color:#f92672">&lt;/span>&lt;span style="color:#a6e22e">+ return if entity.class == Post || entitty.class == Response || entitty.class == Bulletin
&lt;/span>&lt;span style="color:#a6e22e">&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Your level of pain tolerance may vary, but to me, this is already &lt;strong>way&lt;/strong> out
of control. Even though we aren&amp;rsquo;t expressing it as an array or list explicitly,
we are building up a list of classes which we decided earler was a sign of
violating open/closed.&lt;/p>
&lt;h2 id="naming-conditionals">Naming conditionals&lt;/h2>
&lt;p>So, how do we fix this? A really nice refactoring technique I like to use is
what I call &amp;ldquo;naming conditionals&amp;rdquo; (super trademarked;
&lt;a href="https://www.youtube.com/watch?v=Md1MDHroXGU">not to be used without express written consent of Ricky Bobby, inc.&lt;/a>).
This is pretty easy to do. I take a conditional, extact it to a method and
give it a name. Let&amp;rsquo;s do that here:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-ruby" data-lang="ruby">&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">______?&lt;/span>(entity)
entity&lt;span style="color:#f92672">.&lt;/span>class &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#66d9ef">Post&lt;/span> &lt;span style="color:#f92672">||&lt;/span> entitty&lt;span style="color:#f92672">.&lt;/span>class &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#66d9ef">Response&lt;/span> &lt;span style="color:#f92672">||&lt;/span> entitty&lt;span style="color:#f92672">.&lt;/span>class &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#66d9ef">Bulletin&lt;/span>
&lt;span style="color:#66d9ef">end&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Now the hardest part of programming: naming this method. I like to keep it
simple, so how about &lt;code>send_updates?&lt;/code>? Now our calling code reads like this:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-ruby" data-lang="ruby">&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">SendUpdateNotificationJob&lt;/span> &lt;span style="color:#f92672">&amp;lt;&lt;/span> &lt;span style="color:#66d9ef">ApplicationJob&lt;/span>
&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">perform&lt;/span>(entity)
&lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#66d9ef">unless&lt;/span> send_updates?(entity)
&lt;span style="color:#75715e"># send push notifications here&lt;/span>
&lt;span style="color:#66d9ef">end&lt;/span>
&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">send_updates?&lt;/span>(entity)
entity&lt;span style="color:#f92672">.&lt;/span>class &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#66d9ef">Post&lt;/span> &lt;span style="color:#f92672">||&lt;/span> entitty&lt;span style="color:#f92672">.&lt;/span>class &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#66d9ef">Response&lt;/span> &lt;span style="color:#f92672">||&lt;/span> entitty&lt;span style="color:#f92672">.&lt;/span>class &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#66d9ef">Bulletin&lt;/span>
&lt;span style="color:#66d9ef">end&lt;/span>
&lt;span style="color:#66d9ef">end&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;p>The calling code is much easier to read: Don&amp;rsquo;t send updates unless you should.&lt;/p>
&lt;p>&lt;em>But&lt;/em>, we haven&amp;rsquo;t solved the open/closed problem yet.&lt;/p>
&lt;h2 id="reverse-dependency-injection">Reverse dependency injection&lt;/h2>
&lt;p>One of my favorite discussions in programming is about who doesn&amp;rsquo;t care about
things. In this case, I would say that this job does not care about which
classes the entities are that it gets. It only cares about if it can send
notifications for them, and then doing so. In this case, it would not check
the classes of the entity.&lt;/p>
&lt;p>If tho doesn&amp;rsquo;t know about the classes, then who does? Well, the entities know
their classes. What if the job asked them if updates should be sent for
themselves?&lt;/p>
&lt;p>Then we&amp;rsquo;d have code like:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-ruby" data-lang="ruby">&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">SendUpdateNotificationJob&lt;/span> &lt;span style="color:#f92672">&amp;lt;&lt;/span> &lt;span style="color:#66d9ef">ApplicationJob&lt;/span>
&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">perform&lt;/span>(entity)
&lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#66d9ef">unless&lt;/span> entity&lt;span style="color:#f92672">.&lt;/span>send_updates?
&lt;span style="color:#75715e"># send push notifications here&lt;/span>
&lt;span style="color:#66d9ef">end&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;p>That seems pretty straightforward to me.&lt;/p>
&lt;blockquote>
&lt;p>Quick aside: It might also be worth removing that conditional from the job
and preforming the check before even scheduling the background job. This would
allow you to send notifications for &amp;ldquo;unallowed&amp;rdquo; types if really necessary but
put the gate keeping burden upon the scheduler of the job. Trade-offs&amp;hellip;&lt;/p>
&lt;/blockquote>
&lt;h2 id="set-a-default-override-when-necessary">Set a default, override when necessary&lt;/h2>
&lt;p>With Rails 5+, the concept of an &lt;code>ApplicationRecord&lt;/code> was introduced to give a
single parent class for your models within your application. This is a great
place to add code or configuration to be shared by all models.&lt;/p>
&lt;p>For most models, we don&amp;rsquo;t want to send updates:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-ruby" data-lang="ruby">&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">ApplicationRecord&lt;/span> &lt;span style="color:#f92672">&amp;lt;&lt;/span> &lt;span style="color:#66d9ef">ActiveRecord&lt;/span>&lt;span style="color:#f92672">::&lt;/span>&lt;span style="color:#66d9ef">Base&lt;/span>
&lt;span style="color:#f92672">...&lt;/span>
&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">send_updates?&lt;/span>
&lt;span style="color:#66d9ef">false&lt;/span>
&lt;span style="color:#66d9ef">end&lt;/span>
&lt;span style="color:#66d9ef">end&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Any class we want to send updates for can say so:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-ruby" data-lang="ruby">&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">Post&lt;/span>
&lt;span style="color:#f92672">...&lt;/span>
&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">send_updates?&lt;/span>
&lt;span style="color:#66d9ef">true&lt;/span>
&lt;span style="color:#66d9ef">end&lt;/span>
&lt;span style="color:#66d9ef">end&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Now, we don&amp;rsquo;t ever have to &lt;em>open&lt;/em> the send updates job and add more classes to
the list. When we add &lt;code>NewsArtlcles&lt;/code> next month, it&amp;rsquo;ll be super straightforward
to allow or disallow notifications for them. Further, we can add more logic in
the &lt;code>send_updates?&lt;/code> method; like only sending updates bulletin created after
2pm on a Sunday.&lt;/p>
&lt;p>If you find yourself adding and removing from lists of classes in your
application, take a moment to think about the open/closed principle and
whether or not it can help you make more readable, modifiable, and exemplary
code.&lt;/p>
&lt;p>Happy open/closing!&lt;/p>
&lt;p>&amp;ndash; Chris&lt;/p></description></item></channel></rss>