<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Raquel</title>
    <description>The latest articles on DEV Community by Raquel (@raquelxmoss).</description>
    <link>https://dev.to/raquelxmoss</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F18637%2F0cbea25b-27bb-4434-b246-a22ae669efc1.jpeg</url>
      <title>DEV Community: Raquel</title>
      <link>https://dev.to/raquelxmoss</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/raquelxmoss"/>
    <language>en</language>
    <item>
      <title>Using `Hash#fetch` in Ruby for better nil handling</title>
      <dc:creator>Raquel</dc:creator>
      <pubDate>Thu, 21 Mar 2019 02:01:54 +0000</pubDate>
      <link>https://dev.to/raquelxmoss/using-hashfetch-in-ruby-for-better-nil-handling-2l8h</link>
      <guid>https://dev.to/raquelxmoss/using-hashfetch-in-ruby-for-better-nil-handling-2l8h</guid>
      <description>&lt;h1&gt;
  
  
  Using &lt;code&gt;Hash#fetch&lt;/code&gt; in Ruby for better nil handling
&lt;/h1&gt;

&lt;p&gt;Pulling values out of a Hash in Ruby is simple with the &lt;code&gt;[]&lt;/code&gt; method, but problems can occur when the value you’re looking up isn’t there. This can result in cumbersome nil checks, or our absolute favourite error  &lt;code&gt;Undefined method for nil:NilClass&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Let’s look at an example of a classifieds site that sorts its listings when displaying them for the user, and some of the ways we can use &lt;code&gt;Hash#fetch&lt;/code&gt; to proactively handle those nils before they happen.&lt;/p&gt;

&lt;p&gt;Just a quick note on the code—these examples are moderately contrived and not necessarily how you’d solve these problems in production, but hey, at least they illustrate my points!&lt;/p&gt;

&lt;h2&gt;
  
  
  Using Hash#fetch to set a default
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;index&lt;/span&gt;
  &lt;span class="n"&gt;valid_sort_orders&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="ss"&gt;lowest_price: :asc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;highest_price: :desc&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;sort_order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;valid_sort_orders&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;listings_params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:sort&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;

  &lt;span class="vi"&gt;@listings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Listing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;price: &lt;/span&gt;&lt;span class="n"&gt;sort_order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We have a problem here—what if the &lt;code&gt;sort&lt;/code&gt; parameter is not provided by the user, or they provide something that’s invalid? There’s many ways to handle this problem, for example, we could set a default with the &lt;code&gt;||&lt;/code&gt; operator. This is a pretty common pattern, and a perfectly fine way to handle this case.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;index&lt;/span&gt;
  &lt;span class="n"&gt;valid_sort_orders&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="ss"&gt;lowest_price: :asc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;highest_price: :desc&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;sort_order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;valid_sort_orders&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;listings_params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:sort&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="ss"&gt;:asc&lt;/span&gt;

  &lt;span class="vi"&gt;@listings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Listing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;price: &lt;/span&gt;&lt;span class="n"&gt;sort_order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Personally, I prefer to use the &lt;code&gt;Hash#fetch&lt;/code&gt; method for a slightly more elegant solution. With &lt;code&gt;Hash#fetch&lt;/code&gt;, if a key is not found in a hash, we can provide a default key to look for, which is quite a nice way to handle our nil situation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;index&lt;/span&gt;
  &lt;span class="n"&gt;valid_sort_orders&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="ss"&gt;lowest_price: :asc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;highest_price: :desc&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;sort_order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;valid_sort_orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;listings_params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:sort&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="ss"&gt;:asc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="vi"&gt;@listings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Listing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;price: &lt;/span&gt;&lt;span class="n"&gt;sort_order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Semantics alone aren’t a great reason to use this pattern though, so lets look at some more interesting examples where &lt;code&gt;Hash#fetch&lt;/code&gt; can be used to proactively handle nils.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using &lt;code&gt;Hash#fetch&lt;/code&gt; to set a falsey value
&lt;/h2&gt;

&lt;p&gt;This pattern is useful when you want to accept falsey values from a caller, but default to a truthy value. Let’s look at an example. &lt;/p&gt;

&lt;p&gt;Here we want to be able to control with parameters whether to include a seller’s details in the response, with a default value of &lt;code&gt;true&lt;/code&gt;.  It’s easy to accidentally do something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;index&lt;/span&gt;
  &lt;span class="vi"&gt;@include_seller_details&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;listings_params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:include_metadata&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;

  &lt;span class="n"&gt;valid_sort_orders&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="ss"&gt;lowest_price: :asc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;highest_price: :desc&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;sort_order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;valid_sort_orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;listings_params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:sort&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="ss"&gt;:asc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="vi"&gt;@listings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Listing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;price: &lt;/span&gt;&lt;span class="n"&gt;sort_order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Which is not going to work correctly! Because if &lt;code&gt;listing_params[:include_metadata]&lt;/code&gt; is a falsey value, this will evaluate to &lt;code&gt;true&lt;/code&gt; anyway. It’s probably not disasterous, but it means that we’re going to be sending more information in the response than we want to, which is impolite at best and could be a security concern at worst.&lt;/p&gt;

&lt;p&gt;One way to fix this would be to use &lt;code&gt;Hash#fetch&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;index&lt;/span&gt;
  &lt;span class="vi"&gt;@include_seller_details&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;listing_params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:include_metadata&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="n"&gt;valid_sort_orders&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="ss"&gt;lowest_price: :asc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;highest_price: :desc&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;sort_order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;valid_sort_orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;listings_params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:sort&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="ss"&gt;:asc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="vi"&gt;@listings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Listing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;price: &lt;/span&gt;&lt;span class="n"&gt;sort_order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In this example, if there is any value at &lt;code&gt;:include_metadata&lt;/code&gt;, including a falsey value, it will be set, which is exactly what we want.&lt;/p&gt;

&lt;h2&gt;
  
  
  Run a block of code if you don’t find what you’re looking for
&lt;/h2&gt;

&lt;p&gt;In the case where you don’t find what you’re looking for in a hash, returning a default value is nice, as we’ve seen. Sometimes, though, a simple value won’t do, and you might want to run a block of code as a fallback instead. &lt;code&gt;Hash#fetch&lt;/code&gt; accepts a block to help you achieve this, which is pretty nifty!&lt;/p&gt;

&lt;p&gt;In this example, if a user sends an invalid sort order to the API, we will record that in an analytics service. That will help us decide if we want to build that feature for our users next. If a lot of users are requesting to order Listings by &lt;code&gt;popular&lt;/code&gt; or &lt;code&gt;new&lt;/code&gt;, it’s handy for us to know that. So, we’ll report the value, then return the default.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;index&lt;/span&gt;
  &lt;span class="vi"&gt;@include_seller_details&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;listing_params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:include_metadata&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="n"&gt;valid_sort_orders&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="ss"&gt;lowest_price: :asc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;highest_price: :desc&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;sort_order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;valid_sort_orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;listings_params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:sort&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="no"&gt;Analytics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;report&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"user requested to sort listings by &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="ss"&gt;:asc&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="vi"&gt;@listings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Listing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;price: &lt;/span&gt;&lt;span class="n"&gt;sort_order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Safer handling of environment variables with &lt;code&gt;Hash#fetch&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Poor handling of environment variables can make for some pretty disasterous outcomes (…ask me how I know). After being bitten more than once, I like to use &lt;code&gt;Hash#fetch&lt;/code&gt; when retrieving environment variables.&lt;/p&gt;

&lt;p&gt;This is especially important if you are using environment variables to feature flag releases, or if adding/removing environment variables is something that is handled separately to your normal code deploy process. &lt;/p&gt;

&lt;p&gt;code expecting an environment variable + a silent failure if it’s not there + failing to correctly set an environment variable = potentially very costly mistake&lt;/p&gt;

&lt;p&gt;🙃&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;index&lt;/span&gt;
  &lt;span class="n"&gt;seasonal_discount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"SEASONAL_DISCOUNT"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

  &lt;span class="n"&gt;valid_sort_orders&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="ss"&gt;lowest_price: :asc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;highest_price: :desc&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;sort_order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;valid_sort_orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;listings_params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:sort&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="ss"&gt;:asc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="vi"&gt;@listings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Listing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;price: &lt;/span&gt;&lt;span class="n"&gt;sort_order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;seasonal_discount&lt;/span&gt;
    &lt;span class="vi"&gt;@listings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@listings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="ss"&gt;:apply_seasonal_discount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In this case, if someone fails to set the &lt;code&gt;SEASONAL_DISCOUNT&lt;/code&gt; environment variable, we might fail to notice because nothing here is going to throw an error. Our customers will miss out on a good deal!&lt;/p&gt;

&lt;p&gt;We can use &lt;code&gt;Hash#fetch&lt;/code&gt; so that this fails noisily when no env var is found.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;index&lt;/span&gt;
  &lt;span class="n"&gt;seasonal_discount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"SEASONAL_DISCOUNT"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="n"&gt;valid_sort_orders&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="ss"&gt;lowest_price: :asc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;highest_price: :desc&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;sort_order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;valid_sort_orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;listings_params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:sort&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="ss"&gt;:asc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="vi"&gt;@listings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Listing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;price: &lt;/span&gt;&lt;span class="n"&gt;sort_order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;seasonal_discount&lt;/span&gt;
    &lt;span class="vi"&gt;@listings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@listings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="ss"&gt;:apply_seasonal_discount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If no environment variable is found, this will fail noisily and your code probably won’t even deploy correctly. You could also choose to set a default if it makes more sense to do so, but there are often cases when a noisy failure is preferable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Those are some of my favourite uses for &lt;code&gt;Hash#fetch&lt;/code&gt;. It's a really useful tool for any Rubyist, and I think it’s good to remember that &lt;code&gt;[]&lt;/code&gt; is not the only way to retrieve values from a Hash.
&lt;/h3&gt;

</description>
      <category>programming</category>
      <category>ruby</category>
    </item>
    <item>
      <title>How To Review Code You Don't Understand</title>
      <dc:creator>Raquel</dc:creator>
      <pubDate>Wed, 20 Jun 2018 16:02:20 +0000</pubDate>
      <link>https://dev.to/raquelxmoss/how-to-review-code-you-dont-understand-pc7</link>
      <guid>https://dev.to/raquelxmoss/how-to-review-code-you-dont-understand-pc7</guid>
      <description>

&lt;p&gt;I recently read an article by Max Bittker called &lt;a href="https://maxbittker.com/code-review/"&gt;“How to Review Code You Don’t Understand”&lt;/a&gt;, and it got me to thinking about times when I’ve been tasked with doing just that.&lt;/p&gt;

&lt;p&gt;One of the troubles I have with code review is understanding the context around a change. Given a diff, I can work through it line-by-line and understand most of what’s going on there, probably. At least, I can understand the &lt;em&gt;mechanics&lt;/em&gt; of it. But is that the same as understanding what the code is trying to achieve? In my opinion, no.&lt;/p&gt;

&lt;p&gt;Since becoming a developer, one of the struggles I’ve had with reading code is that whatever I’m looking at, I’m seeing the &lt;em&gt;solution&lt;/em&gt;, not the problem. And in fact, I’m only seeing one particular solution, the one I’m tasked with reviewing.&lt;/p&gt;

&lt;p&gt;When reviewing code, I want to give thoughtful suggestions, learn something new, and pick up bugs that I am able to see. (In Ruby, 90% of the time I’m asking (“Hey, do you want to do a nil check here?”).&lt;/p&gt;

&lt;p&gt;So, how can I do that when I am only seeing the output of (usually) one developer’s understanding, problem-solving process, and personal style? It’s hard — arguably one of the harder parts of my job. Lacking copious code comments, or some sort narration available to me while I read the code (imagine that — like director’s commentary for code), all of that important context gets lost.&lt;/p&gt;

&lt;p&gt;Assuming that we’re not going to overhaul our team’s processes entirely, or build better code-reviewing tools from the ground up, what are some things we could go ahead and do tomorrow at work to improve our code review experience?&lt;/p&gt;

&lt;h3&gt;
  
  
  Ask the submitter to review the code
&lt;/h3&gt;

&lt;p&gt;If your colleague hasn’t already self-reviewed their diff and left in-line comments, ask them to do so. This will provide some valuable insight — why they made a particular choice, what they struggled with, why something might seem overly complex. They might point out particular areas they’d like reviewers to focus on, or point to areas where they might be unsure about their decision-making. This will go a small part of the way towards capturing the developer’s thought process as they wrote the code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Seek to understand what the developer was trying to achieve
&lt;/h3&gt;

&lt;p&gt;If your workplace is like mine, you might start a code review with a pull request, a user story, some mock-ups, and a general idea of the larger context surrounding the piece of work.&lt;/p&gt;

&lt;p&gt;We don’t live in a perfect world, though. Perhaps the user story will be vague (I’m yet to find a team that writes impeccable stories). Maybe there’s no mock-ups, and maybe you’re not too familiar around the context.&lt;/p&gt;

&lt;p&gt;So before proceeding, seek to understand.&lt;/p&gt;

&lt;p&gt;The gotcha here getting to the point where you have the right amount of understanding. Sometimes, a story or PR’s description might be too broad.&lt;/p&gt;

&lt;p&gt;For example, you might know that the overarching goal is &lt;strong&gt;Display a user’s address on their invoice PDF&lt;/strong&gt;. Great, that’s what this code is going to do, right?&lt;/p&gt;

&lt;p&gt;What you might not know, is that a user’s address is owned by another service, and the app that you’re looking at has to request that information. So, the developer has had to think about distributed transactions, data integrity, and gracefully handling HTTP request failures. Perhaps they’ve thought about where this code should sit, and chosen one option of several.&lt;/p&gt;

&lt;p&gt;You need to ask some questions to get enough context.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What sort of approach did you take?&lt;/strong&gt; is a good question to ask your colleague. &lt;strong&gt;Did you explore any other approaches and decide against them?&lt;/strong&gt; is another good one.&lt;/p&gt;

&lt;p&gt;Follow-on questions might explore the trade-offs that they made. If you’re newer to being a developer, that might sound intimidating, but it doesn’t have to be. &lt;strong&gt;Why?&lt;/strong&gt; is good follow-up question. It might even be a good idea to do a &lt;a href="https://en.wikipedia.org/wiki/5_Whys"&gt;5 Whys&lt;/a&gt; exercise.&lt;/p&gt;

&lt;p&gt;Whatever you do, get into the habit of asking questions before reviewing the pull request.&lt;/p&gt;

&lt;h3&gt;
  
  
  Go through the code on your own*
&lt;/h3&gt;

&lt;p&gt;Armed with the submitter’s self-review, and your understanding of the approach they took, read through the code, and leave in-line comments. They could be questions, or notes to yourself, or feedback for the submitter.&lt;/p&gt;

&lt;p&gt;I particularly like Github’s feature where you’re able to ‘stage’ all of your review notes and then submit them all at once. This leaves me free to write notes to myself, delete any questions that are answered further down the diff (&lt;a href="https://coppermind.net/wiki/RAFO"&gt;RAFO&lt;/a&gt;!), and edit my notes without flooding the submitter with a deluge of emails.&lt;/p&gt;

&lt;h3&gt;
  
  
  Go through the code with them, if possible
&lt;/h3&gt;

&lt;p&gt;In person, ideally. Get answers to your questions and discuss any changes to the work.&lt;/p&gt;

&lt;p&gt;This is also an opportunity to talk about alternate approaches, which actually leads me back to my previous conundrum with code reviews.&lt;/p&gt;

&lt;p&gt;When you’re reading code that’s been submitted for review, you’re seeing one solution to the problem at hand. &lt;strong&gt;One&lt;/strong&gt; solution. When you’re looking at the solution, it’s hard to consider other possible solutions.&lt;/p&gt;

&lt;p&gt;I’ve found that it’s easier with more experience, but for newer developers, or for developers reviewing code that’s very different from their usual wheelhouse, it can be very tricky to think outside what has already been presented to you. It’s like the &lt;a href="https://en.wikipedia.org/wiki/Einstellung_effect"&gt;Einstellung Effect&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you’re reviewing a pull request, and you’re finding it hard to consider other approaches, talk to the submitter. Ask them: &lt;strong&gt;Did you consider other ways to do this? What were they?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If it turns out they hadn’t considered any other ways to approach the problem, and you haven’t thought of any either, that’s okay. It’s good to get into the habit of asking those questions anyway.&lt;/p&gt;

&lt;h3&gt;
  
  
  Follow up on any discussed changes, then give it the tick!
&lt;/h3&gt;

&lt;p&gt;Hopefully by taking this approach, you’ve both learned something. Perhaps you’ve gained more understanding of your domain, and the code-base. You and the submitter might have talked about different approaches to solving the problem, or at least spent two minutes trying to think of a different approach. Ka pai 😄.&lt;/p&gt;

&lt;p&gt;This isn’t the approach that I would take with every pull request. Some, blessedly, are more straightforward than others! But if you find yourself tasked with reviewing something that’s quite chunky, consider taking some of these ideas and giving them a try.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;If it’s a large changeset, ask the submitter if they can break it down for you any more — not necessarily into separate PRs (though that might be desirable if it’s doable), but perhaps they could take you through a slice of the work, in whatever way makes sense. What we really need is a better tool for reasoning about code diffs, but that’s a blog post for another day.&lt;/em&gt;&lt;/p&gt;


</description>
      <category>codereview</category>
    </item>
  </channel>
</rss>
