<?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>Forem: Denis Defreyne</title>
    <description>The latest articles on Forem by Denis Defreyne (@denisdenisdenis).</description>
    <link>https://forem.com/denisdenisdenis</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%2F287901%2F9abc07df-1973-434f-a330-8cf049955fac.jpg</url>
      <title>Forem: Denis Defreyne</title>
      <link>https://forem.com/denisdenisdenis</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/denisdenisdenis"/>
    <language>en</language>
    <item>
      <title>The intricacies of implementing memoization in Ruby</title>
      <dc:creator>Denis Defreyne</dc:creator>
      <pubDate>Tue, 19 Nov 2024 10:19:04 +0000</pubDate>
      <link>https://forem.com/denisdenisdenis/the-intricacies-of-implementing-memoization-in-ruby-2m3f</link>
      <guid>https://forem.com/denisdenisdenis/the-intricacies-of-implementing-memoization-in-ruby-2m3f</guid>
      <description>&lt;p&gt;&lt;em&gt;This post originally appeared &lt;a href="https://denisdefreyne.com/articles/2024-memoization/" rel="noopener noreferrer"&gt;on denisdefreyne.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In the never-ending quest to write code that is performant, we have many techniques at our disposal. One of those techniques is &lt;em&gt;memoization&lt;/em&gt;,&lt;sup id="fnref1"&gt;1&lt;/sup&gt; which boils down to storing the results of expensive function calls, so that these expensive functions do not need to be called more than absolutely necessary.&lt;/p&gt;

&lt;p&gt;Many years ago, I wrote a Ruby gem for memoization, &lt;em&gt;ddmemoize&lt;/em&gt;. It has since been superseded by better solutions, but for a long time, it was one of the best memoization libraries for Ruby out there.&lt;/p&gt;

&lt;p&gt;Creating this library taught me a great deal. Memoization is surprisingly complex, and a proper implementation, it turns out, goes far beyond Ruby’s &lt;code&gt;||=&lt;/code&gt; memoization operator. Memory management and thread safety, for example, are important considerations, though often overlooked.&lt;/p&gt;

&lt;p&gt;In this article, I’ll walk you through all the learnings I gained in the process of implementing this memoization gem.&lt;/p&gt;

&lt;h1&gt;
  
  
  Local variables
&lt;/h1&gt;

&lt;p&gt;The simplest tool at our disposal for remembering values is the concept of &lt;em&gt;local variables&lt;/em&gt;. Trivial, perhaps — but still worth mentioning.&lt;/p&gt;

&lt;p&gt;In the following example, the &lt;code&gt;#calc_base_price&lt;/code&gt; function is called twice:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def total_price
  vat = calc_base_price * VAT_RATE
  calc_base_price + vat
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;If the &lt;code&gt;#calc_base_price&lt;/code&gt; function were expensive, for example because of a database query, it would make sense to store the result in a local variable. In the following snippet, the base price is stored in a local variable called &lt;code&gt;base_price&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def total_price
  base_price = calc_base_price
  vat = base_price * VAT_RATE
  base_price + vat
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;But there is certainly more to memoization than just this trivial example!&lt;/p&gt;

&lt;h1&gt;
  
  
  The memoization operator
&lt;/h1&gt;

&lt;p&gt;Ruby comes with an operator, &lt;code&gt;||=&lt;/code&gt;, which is sometimes called the &lt;em&gt;memoization operator&lt;/em&gt;. Here is an example of it in use:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def base_price
  @base_price ||= calc_base_price
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;When executing this method, Ruby will check whether the &lt;code&gt;@base_price&lt;/code&gt; instance variable is already defined and has a value that is &lt;em&gt;truthy&lt;/em&gt;, meaning not &lt;code&gt;nil&lt;/code&gt; and not &lt;code&gt;false&lt;/code&gt;. If so, it will return the value of &lt;code&gt;@base_price&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If, on the other hand, &lt;code&gt;@base_price&lt;/code&gt; is either undefined or set to &lt;code&gt;nil&lt;/code&gt; or &lt;code&gt;false&lt;/code&gt;, it will call the &lt;code&gt;#calc_base_price&lt;/code&gt; method, store its return value in the &lt;code&gt;@base_price&lt;/code&gt; instance variable, and use that value as the value for the entire expression (and thus as the return value of &lt;code&gt;#base_price&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;#base_price&lt;/code&gt; method could be rewritten without the use of the &lt;code&gt;||=&lt;/code&gt; operator like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def base_price
  if defined?(@base_price) &amp;amp;&amp;amp; @base_price
    @base_price
  else
    @base_price = calc_base_price
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;However, one of the cases in which Ruby’s &lt;code&gt;||=&lt;/code&gt; operator does not work well is when the memoized method has parameters. That’s next on the list to fix.&lt;/p&gt;
&lt;h2&gt;
  
  
  Be careful with false and nil
&lt;/h2&gt;

&lt;p&gt;The values &lt;code&gt;false&lt;/code&gt; and &lt;code&gt;nil&lt;/code&gt; can make memoization using the &lt;code&gt;||=&lt;/code&gt; operator not work as intended. This is because the &lt;code&gt;||=&lt;/code&gt; operator evaluates the right-hand side when the memoization variable is undefined, or when the memoized value is falsy.&lt;/p&gt;

&lt;p&gt;Consider the following memoized method:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;memoize def open?
  @is_open ||= calc_is_open
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;If &lt;code&gt;#calc_is_open&lt;/code&gt; returns false, the &lt;code&gt;@is_open&lt;/code&gt; memoized instance variable will be set to false. But the next time &lt;code&gt;#open?&lt;/code&gt; is called, the &lt;code&gt;#calc_is_open&lt;/code&gt; method will be called again — because &lt;code&gt;@is_open&lt;/code&gt; is &lt;em&gt;falsy&lt;/em&gt;, meaning &lt;code&gt;nil&lt;/code&gt; or &lt;code&gt;false&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is a general problem with using the &lt;code&gt;||=&lt;/code&gt; operator to memoize methods that return boolean values. It is a problem with methods that are expected to return &lt;code&gt;nil&lt;/code&gt;, too.&lt;/p&gt;

&lt;p&gt;A good way around this problem is to avoid &lt;code&gt;||=&lt;/code&gt; in this situation, and instead use &lt;code&gt;#defined?&lt;/code&gt; to check whether or not to use the memoized value:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def open?
  if defined?(@is_open)
    @is_open
  else
    @is_open = calc_is_open
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Less compact, but at least it works.&lt;/p&gt;

&lt;h1&gt;
  
  
  Argument-aware memoization
&lt;/h1&gt;

&lt;p&gt;Any piece of literature on the topic of memoization will inevitably bring up the Fibonacci sequence as an example where memoization is particularly useful. Here is a Ruby implementation of a function that returns a given entry in the Fibonacci sequence:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def fib(n)
  case n
  when 0
    0
  when 1
    1
  else
    fib(n - 1) + fib(n - 2)
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This works as intended: &lt;code&gt;fib(6)&lt;/code&gt; evaluates to 8 and &lt;code&gt;fib(7)&lt;/code&gt; evaluates to 13.&lt;/p&gt;

&lt;p&gt;However, for larger numbers, the execution time quickly increases. I wrote some code to calculate the first 50 Fibonacci numbers, and print out the duration&lt;sup id="fnref2"&gt;2&lt;/sup&gt; to calculate them:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def now
  Process.clock_gettime(
    Process::CLOCK_MONOTONIC
  )
end

50.times do |i|
  print "#{i}: "

  before = now
  val = fib(i)
  after = now
  duration = after - before

  puts "#{val} (#{format '%.1f', duration}s)"
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Here is what it printed out:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0: 0 (0.0s)
1: 1 (0.0s)
2: 1 (0.0s)
3: 2 (0.0s)
4: 3 (0.0s)
5: 5 (0.0s)
6: 8 (0.0s)
7: 13 (0.0s)
8: 21 (0.0s)
9: 34 (0.0s)
10: 55 (0.0s)
11: 89 (0.0s)
12: 144 (0.0s)
13: 233 (0.0s)
14: 377 (0.0s)
15: 610 (0.0s)
16: 987 (0.0s)
17: 1597 (0.0s)
18: 2584 (0.0s)
19: 4181 (0.0s)
20: 6765 (0.0s)
21: 10946 (0.0s)
22: 17711 (0.0s)
23: 28657 (0.0s)
24: 46368 (0.0s)
25: 75025 (0.0s)
26: 121393 (0.0s)
27: 196418 (0.0s)
28: 317811 (0.0s)
29: 514229 (0.0s)
30: 832040 (0.1s)
31: 1346269 (0.1s)
32: 2178309 (0.2s)
33: 3524578 (0.3s)
34: 5702887 (0.5s)
35: 9227465 (0.8s)
36: 14930352 (1.2s)
37: 24157817 (2.0s)
38: 39088169 (3.2s)
39: 63245986 (5.2s)
40: 102334155 (8.3s)
41: 165580141 (13.5s)
42: 267914296 (21.8s)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Calculating number 42 in the Fibonacci sequence took &lt;em&gt;21 seconds&lt;/em&gt;,&lt;sup id="fnref3"&gt;3&lt;/sup&gt; after which I gave up and aborted the script. Extrapolating from the durations above, I estimate that calculating number 50 in the Fibonacci sequence would take 17 minutes.&lt;sup id="fnref4"&gt;4&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;The reason why calculating Fibonacci numbers gets so slow is because there is a &lt;em&gt;lot&lt;/em&gt; of redundant work happening. For example, calculating &lt;code&gt;fib(40)&lt;/code&gt; calculates &lt;code&gt;fib(39)&lt;/code&gt; and &lt;code&gt;fib(38)&lt;/code&gt;. Calculating &lt;code&gt;fib(39)&lt;/code&gt; &lt;em&gt;also&lt;/em&gt; calculates &lt;code&gt;fib(38)&lt;/code&gt;. This redundant work gets progressively worse for lower numbers. For example, &lt;code&gt;fib(40)&lt;/code&gt; calculates the third number (n=2) in the Fibonacci sequence &lt;em&gt;63 245 986 times&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;It only really needs to do that once. No wonder this implementation is slow.&lt;/p&gt;

&lt;p&gt;One way to avoid this problem with execution speed would be to rewrite the method to avoid recursion and use looping instead:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def fib(n)
  arr = [0, 1]
  while init.size &amp;lt;= n
    arr &amp;lt;&amp;lt; arr.last(2).sum
  end
  arr[n]
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The reason why this solution is so much faster is because it avoids recalculating anything. For example, &lt;code&gt;fib(40)&lt;/code&gt; calculates the third number in the Fibonacci sequence only once — not 63 million times.&lt;/p&gt;

&lt;p&gt;The version that uses a loop instead of recursion is &lt;em&gt;much&lt;/em&gt; faster, but it has the problem of not being nearly as easy to read as the initial version. In this faster, recursive version, the mathematical definition of the Fibonacci sequence is not readily visible.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;#fib&lt;/code&gt; function cannot be memoized by applying the &lt;code&gt;||=&lt;/code&gt; operator as before. Something a little more sophisticated is needed, creating a cache for each value of the argument &lt;code&gt;n&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def fib(n)
  @fib ||= {}
  @fib[n] ||=
    case n
    when 0
      0
    when 1
      1
    else
      fib(n - 1) + fib(n - 2)
    end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;With this change, calculating &lt;code&gt;fib(40)&lt;/code&gt; is instantaneous. In fact, so is &lt;code&gt;fib(4000)&lt;/code&gt;.&lt;sup id="fnref5"&gt;5&lt;/sup&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Memoization DSL
&lt;/h1&gt;

&lt;p&gt;One of Ruby’s great strengths is its capacity for metaprogramming. A good use case for this is automating memoization by tagging a call to &lt;code&gt;memoize&lt;/code&gt; after a method definition, like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def fib(n)
  # [snip]
end
memoize :fib
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The technique that I’ll introduce here only works for &lt;em&gt;methods&lt;/em&gt;, not for functions. So, let’s stick &lt;code&gt;#fib&lt;/code&gt; in a class:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Fib
  def fib(n)
    case n
    when 0
      0
    when 1
      1
    else
      fib(n - 1) + fib(n - 2)
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The invocation is a little different, but it works as before (with the same slowness):&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;p Fib.new.fib(10)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We’ll create a module named &lt;code&gt;Memoize&lt;/code&gt; and stick the &lt;code&gt;memoize&lt;/code&gt; method in there:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module Memoize
  def memoize(method_name)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Its goal will be to replace the method with the given name (&lt;code&gt;:fib&lt;/code&gt; in our example) with a new one that performs automatic memoization. This new method needs to be able to call the original method, so it first creates a copy of the original method, using &lt;code&gt;#alias_method&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    orig_method_name =
      '__orig_' + method_name.to_s
    alias_method(orig_method_name, method_name)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In our example with &lt;code&gt;#fib&lt;/code&gt; example, this will create a method named &lt;code&gt;#__orig_fib&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The original method (&lt;code&gt;#fib&lt;/code&gt; in our example) has not been touched yet. The next step is to redefine that original method, for which &lt;code&gt;#define_method&lt;/code&gt; is useful. For now, it’ll use &lt;code&gt;#send&lt;/code&gt; to call the original method; an implementation with memoization will follow later:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    define_method(method_name) do |*args|
      send(orig_method_name, *args)
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;To use this new functionality in our existing &lt;code&gt;Fib&lt;/code&gt; class, first add &lt;code&gt;extend Memoization&lt;/code&gt; near the top, and then add &lt;code&gt;memoize :fib&lt;/code&gt; after the &lt;code&gt;#fib&lt;/code&gt; method definition:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Fib
  extend Memoization

  def fib(n)
    case n
    when 0
      0
    when 1
      1
    else
      fib(n - 1) + fib(n - 2)
    end
  end
  memoize :fib
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This will still work, still without memoization (yet):&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;p Fib.new.fib(10)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;It is now time to implement memoization in the newly defined method. The first thing it needs is a cache:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;define_method(method_name) do |*args|
  @__cache ||= {}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This &lt;code&gt;@__cache&lt;/code&gt; instance variable will contain the results of all invocations for all methods on this particular instance. The keys of the &lt;code&gt;@__cache&lt;/code&gt; hash will be the method name.&lt;/p&gt;

&lt;p&gt;Next, the implementation needs to get the cache for this particular method, given by the &lt;code&gt;method_name&lt;/code&gt; variable:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  method_cache = (@__cache[method_name] ||= {})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;With the cache for this particular method now available, it can check whether there is already a value for the given arguments. If there is, that is the value that can be returned — the entire point of memoization:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  if method_cache.key?(args)
    method_cache[args]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;If there is no value available yet, call the original method and store the return value in the cache for this method:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  else
    method_cache[args] =
      send(orig_method_name, *args)
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In Ruby, an assignment evaluates to the value that was assigned, so there is no need for an explicit &lt;code&gt;method_cache[args]&lt;/code&gt; after the assignment.&lt;/p&gt;

&lt;p&gt;With this change, running &lt;code&gt;fib(40)&lt;/code&gt; is now very fast indeed — practically instantaneous:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;p Fib.new.fib(40)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;There is one more neat change that is possible. In Ruby, method definitions return the mehod name as a symbol, so &lt;code&gt;memoize&lt;/code&gt; can be stuck in front of the &lt;code&gt;def&lt;/code&gt; keyword and the &lt;code&gt;memoize :fib&lt;/code&gt; line removed:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;memoize def fib(n)
  # [snip]
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now it looks like a keyword, which I find rather neat.&lt;/p&gt;

&lt;h2&gt;
  
  
  Memoization requirements
&lt;/h2&gt;

&lt;p&gt;Before continuing, I want address the following question: under which circumstances can memoization be safely applied? Memoization is not a technique that can be spray-painted onto code to make it faster. There are restrictions to consider for memoized code to work correctly.&lt;/p&gt;

&lt;p&gt;A memoized method must only use variables that never change value. This includes instance variables, arguments, global variables, constants, and more.&lt;/p&gt;

&lt;p&gt;To illustrate this, take a look at the following example &lt;code&gt;LineItem&lt;/code&gt; class, with a memoized &lt;code&gt;#total_price&lt;/code&gt; method:&lt;sup id="fnref6"&gt;6&lt;/sup&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class LineItem
  extend Memoization

  attr_accessor :unit_price
  attr_accessor :count

  def initialize(unit_price:, count:)
    @unit_price = unit_price
    @count = count
  end

  memoize def total_price
    count * unit_price
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The total price is calculated correctly:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;line_item = LineItem.new(unit_price: 49, count: 2)
p line_item.total_price
# =&amp;gt; 98
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;However, after changing the count, the total price is not updated, because it is memoized:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;line_item.count = 3
p line_item.total_price
# =&amp;gt; 98
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;A solution to this problem is to make &lt;code&gt;LineItem&lt;/code&gt; immutable, either by freezing it or replacing &lt;code&gt;attr_accessor&lt;/code&gt; with &lt;code&gt;attr_reader&lt;/code&gt;. This would prevent the count of a &lt;code&gt;LineItem&lt;/code&gt; from being changed; instead, a new instance of &lt;code&gt;LineItem&lt;/code&gt; can be created with the correct count:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;line_item = LineItem.new(
  unit_price: 49,
  count: 2)
p line_item.total_price
# =&amp;gt; 98

line_item = LineItem.new(
  unit_price: line_item.unit_price,
  count: 3)
p line_item.total_price
# =&amp;gt; 147
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;A good general guideline is to use memoization only on objects that are immutable, and likewise pass in only arguments that are immutable as well.&lt;/p&gt;

&lt;h1&gt;
  
  
  Memoizing on frozen objects
&lt;/h1&gt;

&lt;p&gt;There is one particular issue with this implementation. Attempting to use memoization on a frozen object fails. Take the following code as an example:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;f = Fib.new
f.freeze
p f.fib(40)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This fails with a &lt;code&gt;FrozenError&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;example3.rb:20:in `block in memoize': can't modify frozen Fib: #&amp;lt;Fib:0x000000011ffeb008&amp;gt; (FrozenError)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This happens because the &lt;code&gt;@__cache&lt;/code&gt; instance variable is frozen along with the rest of the object.&lt;/p&gt;

&lt;p&gt;The solution&lt;sup id="fnref7"&gt;7&lt;/sup&gt; I used was to turn the idea of a cache on its head. Rather than have one cache per instance (the &lt;code&gt;@__cache&lt;/code&gt; instance variable) with keys for each method name, I opted for having one cache per &lt;em&gt;method&lt;/em&gt;,  with keys for each instance. In practice, this solution looks like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module Memoize
  def memoize(method_name)
    # [snip]

    method_cache = {}
    define_method(method_name) do |*args|
      instance_cache = (method_cache[self] ||= {})
      if instance_cache.key?(args)
        instance_cache[args]
      else
        instance_cache[args] =
          send(orig_method_name, *args)
      end
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;method_cache&lt;/code&gt; local variable is the cache for the particular method given by the &lt;code&gt;method_name&lt;/code&gt; argument. The instance cache simply is &lt;code&gt;method_cache[self]&lt;/code&gt;, with self being the instance on which the memoized method is called.&lt;sup id="fnref8"&gt;8&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;Unfortunately, in the excitement of finding an approach to support memoization for frozen objects, a bigger problem has appeared: memory usage.&lt;/p&gt;

&lt;h1&gt;
  
  
  Memory-efficient memoization
&lt;/h1&gt;

&lt;p&gt;The memoization implementation never frees up memory. This means that memory usage can keep on growing. I can get this to happen if I’m not careful:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;low swap: killing largest compressed process with pid 95941 (ruby) and size 76343 MB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This particular Ruby process ballooned to north of 75 GB of memory usage, before the macOS kernel killed it.&lt;/p&gt;

&lt;p&gt;This is especially an issue with long-running processes.&lt;sup id="fnref9"&gt;9&lt;/sup&gt; Availability becomes a problem when a process can’t adhere to its memory limits!&lt;/p&gt;

&lt;p&gt;This issue was not as much of problem before. After all, memoized values were stored on the instance, and when the instance is deallocated, the memoized values are deallocated with it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Weak references
&lt;/h2&gt;

&lt;p&gt;There is a potential solution that Ruby provides by default: &lt;em&gt;weak references&lt;/em&gt;. Explaining what weak references are is best done by comparing them to regular references, also known as &lt;em&gt;strong references&lt;/em&gt;. Take a look at this piece of code:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;arr = [1, 2, 3]
arr.reverse
# =&amp;gt; [3, 2, 1]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This example creates an array, and returns a reversed version of it. Straightforward, so far. The garbage collector will not deallocate &lt;code&gt;arr&lt;/code&gt;, because it is still referenced. This code snippet still works:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GC.start

arr.reverse
# =&amp;gt; [3, 2, 1]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This happens because there is a reference (a strong reference) to the &lt;code&gt;arr&lt;/code&gt; object. Any object that is referenced, directly or indirectly, by a variable in scope (like an instance variable, a global variable, a local variable, or a constant) is immune from being garbage-collected, i.e. having its memory reclaimed. This makes so much sense that we as programmers rarely think about this.&lt;/p&gt;

&lt;p&gt;Weak references, however, change things up a little. Consider this code snippet:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;require 'weakref'

arr = WeakRef.new([1, 2, 3])
arr.reverse
# =&amp;gt; [3, 2, 1]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;That still works as before. However, after invoking the garbage collector, the array is no longer accessible; trying to do anything with it will yield an exception:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GC.start
arr.reverse
# WeakRef::RefError (Invalid Reference - probably recycled)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The array, i.e. the object that the arr variable pointed to, has had its memory reclaimed; it is gone.&lt;/p&gt;

&lt;p&gt;On first sight, weak references seem like they could provide an excellent solution to the problem of memory bloat caused by memoization. Wrap the memoized values in a &lt;code&gt;WeakRef&lt;/code&gt;, and done — right?&lt;/p&gt;

&lt;p&gt;But there is a problem: when using weak references for memoization, &lt;em&gt;all&lt;/em&gt; memoized values wiped out when garbage collection occurs. This is unfortunate, and in my experience wrecks the usefulness of memoization. An alternative is needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Soft references
&lt;/h2&gt;

&lt;p&gt;There exists a kind of reference that is weaker than a strong reference, but stronger than a weak reference. These are called &lt;em&gt;soft references&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Soft references are much less eager to be garbage-collected than weak references. The value pointed to by a soft reference will only be garbage collected after it has not been accessed for a number of garbage collections.&lt;/p&gt;

&lt;p&gt;Ruby does not come with an implementation of soft references by default. There is a now-deprecated gem, &lt;code&gt;ref&lt;/code&gt;, that implements them:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;require 'ref'

ref = Ref::SoftReference.new("hello")

ref.object.upcase
# =&amp;gt; HI
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The API is similar to that of Ruby’s built-in &lt;code&gt;WeakRef&lt;/code&gt;, though &lt;code&gt;Ref::SoftReference&lt;/code&gt; does not automatically delegate to the object. Accessing the pointed-to object is done through the &lt;code&gt;#object&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;Initially, the pointed-to object is accessible as usual.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;p ref.object
# "hello"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;However, after a couple of garbage-collection cycles, the object is finally garbage collected, and the pointer becomes &lt;code&gt;nil&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;p ref.object
# nil
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;It is not much work to replace the uses of &lt;code&gt;WeakRef&lt;/code&gt; with &lt;code&gt;Ref::SoftReference&lt;/code&gt; ones. But is it worth it? I don’t think it is, for two reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;ref&lt;/code&gt; gem is no longer maintained, and there is no other soft reference implementation for Ruby that I know of.&lt;sup id="fnref10"&gt;10&lt;/sup&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Soft references have a performance overhead, especially when implemented in Ruby itself. This can diminish the gains from memoization.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There is also still the problem that the function/method arguments are not garbage-collected either. This was already a problem with &lt;code&gt;WeakRef&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Neither &lt;code&gt;WeakRef&lt;/code&gt; nor &lt;code&gt;Ref::SoftReference&lt;/code&gt; works well enough for the purposes of memoization. The original implementation, which used an instance variable, overall is a better choice when it comes to memory management.&lt;/p&gt;

&lt;p&gt;And there is a better way of dealing with frozen objects, too!&lt;/p&gt;

&lt;h2&gt;
  
  
  Freezing, revisited
&lt;/h2&gt;

&lt;p&gt;There is a better way to deal with frozen objects. It is a slight variation on the original implementation of the memoization DSL. Gone are the weak references and the soft references.&lt;/p&gt;

&lt;p&gt;The first change (a trivial one) is to move the &lt;code&gt;memoize&lt;/code&gt; method into a &lt;code&gt;Memoization::ClassMethods&lt;/code&gt; module:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module Memoization::ClassMethods
  def memoize(method_name)
    # [snip]

    define_method(method_name) do |*args|
      @__cache ||= {}
      method_cache =
        (@__cache[method_name] ||= {})

      # [snip]
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This new module can already be used as-is by passing this module to &lt;code&gt;extend&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Fib
  extend Memoization::ClassMethods

  memoize def fib(n)
    # [snip]
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;So far, nothing has changed: the behavior is identical to what we had in the initial implementation of &lt;code&gt;memoize&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Next comes the solution to the frozenness problem. The idea is the following: when &lt;code&gt;#freeze&lt;/code&gt; is called on an instance of a class that uses memoization, the cache is created &lt;em&gt;before&lt;/em&gt; the object becomes frozen. That is what the &lt;code&gt;Memoization::InstanceMethods&lt;/code&gt; is for:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module Memoization::InstanceMethods
  def freeze
    @__cache ||= {}
    super
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This new module can be put to use in the example &lt;code&gt;Fib&lt;/code&gt; class using &lt;code&gt;prepend&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Fib
  extend Memoization::ClassMethods
  prepend Memoization::InstanceMethods

  memoize def fib(n)
    # [snip]
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;It is important to use &lt;code&gt;prepend&lt;/code&gt; rather than &lt;code&gt;include&lt;/code&gt; here. With &lt;code&gt;prepend&lt;/code&gt; (unlike &lt;code&gt;include&lt;/code&gt;) the &lt;code&gt;#freeze&lt;/code&gt; method of the prepended module would be executed before the &lt;code&gt;#freeze&lt;/code&gt; method defined on the instance (if there is any). This is necessary, because the &lt;code&gt;@__cache&lt;/code&gt; instance variable needs to be created before any freezing takes place.&lt;/p&gt;

&lt;p&gt;So now there is a better solution for dealing with frozen objects: call &lt;code&gt;extend&lt;/code&gt; with the &lt;code&gt;ClassMethods&lt;/code&gt; module, and &lt;code&gt;prepend&lt;/code&gt; the &lt;code&gt;InstanceMethods&lt;/code&gt; module. With this change, frozen objects are no longer an obstacle to memoization. Memory usage is not an issue anymore.&lt;/p&gt;

&lt;p&gt;There is one more useful change to make. Calling both &lt;code&gt;extend&lt;/code&gt; and &lt;code&gt;prepend&lt;/code&gt; is slightly awkward. Ideally, there would be only a single call to &lt;code&gt;extend Memoization&lt;/code&gt;, like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Fib
  extend Memoization

  memoize def fib(n)
    # [snip]
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;To make this work, implement the &lt;code&gt;extended&lt;/code&gt; method on the Memoization module, which will be called as a callback whenever any class calls &lt;code&gt;extend Memoization&lt;/code&gt;. The &lt;code&gt;extended&lt;/code&gt; method, which takes the class or module as an argument, can then delegate to the proper &lt;code&gt;extend&lt;/code&gt; and &lt;code&gt;prepend&lt;/code&gt; methods, like above:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module Memoization
  def self.extended(thing)
    thing.extend(ClassMethods)
    thing.prepend(InstanceMethods)
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;And with that, the &lt;code&gt;Memoization&lt;/code&gt; module provides a nice way of memoizing that works with frozen objects and is memory-efficient.&lt;/p&gt;

&lt;p&gt;But are still a few more problems left to solve.&lt;/p&gt;

&lt;h1&gt;
  
  
  Supporting keyword arguments
&lt;/h1&gt;

&lt;p&gt;Since version 3.0, Ruby supports &lt;em&gt;keyword arguments&lt;/em&gt;. There are distinct from regular arguments, also known as &lt;em&gt;positional arguments&lt;/em&gt;. Here is an example of &lt;code&gt;#fib&lt;/code&gt; which takes &lt;code&gt;n&lt;/code&gt; as a keyword argument:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def fib(n:)
  case n
  when 0
    0
  when 1
    1
  else
    fib(n: n - 1) + fib(n: n - 2)
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;At the moment, memoize this method and calling it will fail with an &lt;code&gt;ArgumentError&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;example.rb:5:in `fib': wrong number of arguments (given 1, expected 0; required keyword: n) (ArgumentError)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The method created by &lt;code&gt;#define_method&lt;/code&gt; inside the &lt;code&gt;memoize&lt;/code&gt; method does not take keyword arguments; &lt;code&gt;*args&lt;/code&gt; captures only positional arguments and not keyword arguments. The &lt;code&gt;#define_method&lt;/code&gt; call needs to be updated to also grab keyword arguments by adding &lt;code&gt;**kwargs&lt;/code&gt; to the list of parameters:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;define_method(method_name) do |*args, **kwargs|
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Getting the method cache remains the same:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  @__cache ||= {}
  method_cache = (@__cache[method_name] ||= {})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The memoization key needs to change. Instead of only including positional arguments, it also needs to include the keyword arguments. The easiest approach is to construct a key that consists of positional arguments and keyword arguments:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  key = [args, kwargs]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This key is then used, instead of just args, when fetching the memoized value (if any):&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  if method_cache.key?(key)
    method_cache[key]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;If there is no memoized value, the original method needs to be called with not just the positional arguments, but also the keyword arguments:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  else
    method_cache[key] =
      send(orig_method_name, *args, **kwargs)
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;With this change, memoization works as expected on methods with keyword arguments.&lt;/p&gt;

&lt;h1&gt;
  
  
  Supporting blocks
&lt;/h1&gt;

&lt;p&gt;In Ruby, methods can take three types of things. We have tackled positional arguments and keyword arguments, but there is one more type of thing a Ruby method can take: a &lt;em&gt;block&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;However, there is a snag: every invocation of a block will result in a new block object (a &lt;code&gt;Proc&lt;/code&gt; instance), which renders it impossible to meaningfully memoize a method that takes a block. To illustrate this, consider the following trivial class:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Test
  def run(&amp;amp;blk)
    p blk.__id__
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This code simply prints the ID of the block. Calling Test#run twice prints two different &lt;code&gt;Proc&lt;/code&gt; IDs:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;test = Test.new

test.run { }
# stdout: 860

test.run { }
# stdout: 880
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;It is not only because there are two distinct blocks in the source code (line 3 and 5 in the example above) that the &lt;code&gt;Proc&lt;/code&gt; IDs are different. This even happens when there is only a single block in the source code:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2.times do
  test.run { }
end
# stdout: 860
# stdout: 880
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;That this happens in general makes sense, because each invocation of a block captures a (potentially) different environment.&lt;/p&gt;

&lt;p&gt;This, however, means that memoizing a method that takes a block is not possible. Memoization will be entirely ineffective: no invocation of the memoized method will ever use a memoized value.&lt;/p&gt;

&lt;p&gt;For this reason, I believe the best way forward is to explicitly disallow memoizing a method that takes a block. Memoization needs to raise an error in this case:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;define_method(method_name) do |*args, **kwargs, &amp;amp;blk|
  if blk
    raise ArgumentError,
      "cannot memoize methods that take a block"
  end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Raising an exception when a block is given to a memoized method is the most reasonable thing to do. With this change, we’ve made it less likely that unexpected behavior arises.&lt;/p&gt;

&lt;h1&gt;
  
  
  Thread-safe memoization
&lt;/h1&gt;

&lt;p&gt;In a multi-threaded environment, the current implementation of memoization potentially has some issues.&lt;/p&gt;

&lt;p&gt;Two threads could be calling the same method (with the same arguments, if any) at the same time. This is wasteful, and could lock up valuable resources that could better be used for something else. When two threads are calling the same method with the same arguments, then it would be better if the second thread were to wait for the first thread to finish, and then reuse the just-obtained return value.&lt;/p&gt;

&lt;p&gt;This is not a problem with correctness, but with resource usage. You might not consider this to be a problem that is worth solving.&lt;/p&gt;

&lt;p&gt;But if you were to try to fix it, know that adding thread safety&lt;sup id="fnref11"&gt;11&lt;/sup&gt; is not trivial. Take a look at this example for a class with a single memoized method that takes no arguments:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Order
  def initialize
    @mutex = Thread::Mutex.new
  end

  def discount
    @_discount ||= begin
      @mutex.synchronize do
        unmemoized_discount
      end
    end
  end

  private

  def unmemoized_discount
    # [snip]
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Multiple threads might attempt to run &lt;code&gt;Order#discount&lt;/code&gt;, but only a single &lt;code&gt;#unmemoized_discount&lt;/code&gt; call will be coming from &lt;code&gt;#discount&lt;/code&gt; at any given time. That is what a mutex is for, and it does its job admirably.&lt;/p&gt;

&lt;p&gt;Admirably… and uselessly! This implementation is not quite correct. It is possible for two concurrent calls to &lt;code&gt;#discount&lt;/code&gt; to happen, and those two calls will compete for the mutex. The first invocation will call &lt;code&gt;#unmemoized_discount&lt;/code&gt;. The second invocation will wait to obtain a mutex lock, eventually calling &lt;code&gt;#unmemoized_discount&lt;/code&gt;. The second call does not use the memoized value at all.&lt;/p&gt;

&lt;p&gt;Here is a better implementation:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def discount
  @_discount ||= begin
    @mutex.synchronize do
      if defined?(@_discount) &amp;amp;&amp;amp; @_discount
        @_discount
      else
        unmemoized_discount
      end
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;At the very beginning of the mutex, the method checks the presence of &lt;code&gt;@_discount&lt;/code&gt; &lt;em&gt;again&lt;/em&gt;. It could’ve changed since the method call began awaiting the mutex, after all.&lt;/p&gt;

&lt;p&gt;This version works better, but there is another issue: the mutex block could have finished, an another thread could have started executing the mutex-protected block &lt;em&gt;before&lt;/em&gt; the memoized &lt;code&gt;@_discount&lt;/code&gt; instance variable got assigned.&lt;/p&gt;

&lt;p&gt;The solution is to move the assignment to &lt;code&gt;@_discount&lt;/code&gt; into the mutex block:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def discount
  if defined?(@_discount) &amp;amp;&amp;amp; @_discount
    return @_discount
  end

  @mutex.synchronize do
    if defined?(@_discount) &amp;amp;&amp;amp; @_discount
      @_discount
    else
      @_discount = unmemoized_discount
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This implementation will properly prevent multiple concurrent and unnecessary calls to &lt;code&gt;#unmemoized_discount&lt;/code&gt;.&lt;sup id="fnref12"&gt;12&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;There is something missing, however. At the moment, there is only one memoized method, so a single mutex, &lt;code&gt;@mutex&lt;/code&gt;, is sufficient. Ideally, though, there would need to be a single mutex per memoized method; after all, parallel calls to different memoized methods should probably not block each other.&lt;/p&gt;

&lt;p&gt;Additionally, this approach also only realistically works for memoized methods that have no parameters. If there are parameters, it might make sense to have a mutex for each possible combination of arguments. But then it might happen that two threads create a mutex for the same combination of arguments at the same time, so there might need to be a mutex to prevent that from happening. Also, mutexes that are no longer needed should ideally not take up memory, so a way of automatically cleaning them up would be useful, too.&lt;/p&gt;

&lt;p&gt;Multithreading-aware memoization gets complicated very fast. And none of this is likely necessary, and perhaps not even very useful at all. Memoized methods are meant to be idempotent (or pure) anyway.&lt;/p&gt;

&lt;p&gt;My preferred approach to this problem is to explicitly not think about thread safety, and delegate this concern to the caller. Document the thread-safety guarantees and move on. An easy way out, perhaps, but also the most reasonable in my opinion.&lt;/p&gt;

&lt;p&gt;That leaves us with just one thing left to improve.&lt;/p&gt;

&lt;h1&gt;
  
  
  Metrics
&lt;/h1&gt;

&lt;p&gt;A memoized function must have exactly the same behavior as its non-memoized counterpart, save for differences in execution speed. That is the contract for using memoization. But if the behavior of a memoized method is exactly the same as its non-memoized counterpart, then how does one check whether memoization is useful at all?&lt;/p&gt;

&lt;p&gt;One of the neat features of my old &lt;em&gt;ddmemoize&lt;/em&gt; library is that you could configure it to track and print metrics. Here is an example of what &lt;code&gt;DDMemoize.print_metrics&lt;/code&gt; could spit out:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   memoization │ hit  miss  %
───────────────┼─────────────────
Order#discount │ 258   110  70.1%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;A &lt;em&gt;hit&lt;/em&gt; indicates an invocation where the memoized value was used, and a &lt;em&gt;miss&lt;/em&gt; means that a no memoized value was available and the original method thus had to be called. In this example, the hit ratio of &lt;code&gt;Order#discount&lt;/code&gt; is 70.1%, which means that of all calls (hits plus misses), 70.1% were hits. &lt;/p&gt;

&lt;p&gt;Is 70.1% a good rate? It depends. Is &lt;code&gt;#discount&lt;/code&gt; slow? Then perhaps having it memoized makes sense. But if &lt;code&gt;#discount&lt;/code&gt; is already fast, then memoization might not help, and perhaps even be harmful to performance, as memoization itself brings a tiny overhead in execution speed and memory usage.&lt;/p&gt;

&lt;p&gt;If the number of misses is significantly higher than the number of hits, then memoization is most likely not effective.&lt;/p&gt;

&lt;p&gt;A high hit rate is not inherently better than a low hit rate. The hit rate merely gives an idea of whether or not memoization is effective. When a code change makes the hit rate drop dramatically, then the correct response would to be reconsider the usage of memoization, rather than attempt to bring the hit rate back up.&lt;/p&gt;

&lt;p&gt;There is a more interesting question to ask when the hit rate is high: why was the memoized method called so often (on the same object, and with the same arguments) in the first place? Perhaps rather than introducing memoization, it is worth figuring out where duplicate calls are coming from, and then eliminating them.&lt;/p&gt;

&lt;p&gt;In my experience, memoization can be a crutch. That does not mean memoization is not useful, but it can be indication of sub-optimal design or architecture. These issues are often hard to spot or hard to fix, so memoization still has a place in a software developer’s tool kit. Knowing the hit rate, too, is great for using memoization effectively.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;The preceding few thousand words have made it hopefully clear that memoization is tricky to implement.&lt;/p&gt;

&lt;p&gt;Use a battle-tested library instead of writing a memoization implementation yourself. I recommend the &lt;em&gt;&lt;a href="https://github.com/panorama-ed/memo_wise" rel="noopener noreferrer"&gt;memo_wise&lt;/a&gt;&lt;/em&gt; Ruby gem. It is the best memoization library for Ruby that I am aware of. Jemma Issroff and Jacob Evelyn have written about &lt;a href="https://ja.cob.land/optimizing-memowise-performance" rel="noopener noreferrer"&gt;optimising memo_wise performance&lt;/a&gt; and &lt;a href="https://jemma.dev/blog/esoteric-ruby-in-memowise" rel="noopener noreferrer"&gt;esoteric Ruby in memo_wise&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;At the moment of writing, my &lt;em&gt;ddmemoize&lt;/em&gt; gem is about seven years old, and deprecated. Don’t use it! Better solutions exist.&lt;sup id="fnref13"&gt;13&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;And now, with quite a bit of a delay, I have shared my own learnings in building this library in the hope and conviction that the learnings I gained along my journey will be useful to others.&lt;/p&gt;

&lt;p&gt;If you found this article useful, consider &lt;a href="https://ko-fi.com/denisdefreyne" rel="noopener noreferrer"&gt;buying me a coffee&lt;/a&gt;.&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;That’s memoization, not memorization — there’s no “r”! ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;This code snippet uses a monotonic clock to calculate elapsed time. This is a more accurate way than using &lt;code&gt;Time.now&lt;/code&gt;, because the monotonic clock is not affected by small shifts that occur e.g. when synchronising with a network time server. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn3"&gt;
&lt;p&gt;Did you spot how the durations form something quite close to the Fibonacci sequence, too? How neat is that?! ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn4"&gt;
&lt;p&gt;This is assuming that the thermal throttling on my M2 MacBook Air does not engage. If it does, I imagine it would take much longer than that. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn5"&gt;
&lt;p&gt;Any number much larger than 8000 or so will yield a different problem: &lt;code&gt;stack level too deep (SystemStackError)&lt;/code&gt;. This is difficult, but not impossible, to avoid with a recursive solution. The version that uses a loop won’t have this issue. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn6"&gt;
&lt;p&gt;The use of memoization here is not particularly useful: multiplying two numbers, &lt;code&gt;count&lt;/code&gt; and &lt;code&gt;unit_price&lt;/code&gt;, is very fast — but it is appropriate as an example. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn7"&gt;
&lt;p&gt;The &lt;em&gt;initial&lt;/em&gt; solution, that is. Yes, I am foreshadowing an alternative implementation! ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn8"&gt;
&lt;p&gt;A benefit to this approach of using a local variable rather than an instance variable is that the instance variable no longer needs to be hidden with an obscure name. The reason why &lt;code&gt;@__cache&lt;/code&gt; starts with a double underscore is so that it’s not accidentally accessed by code outside the gem. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn9"&gt;
&lt;p&gt;Is it really still a problem with “long-running” processes if they’re no longer “long-running” because they get quickly killed by the kernel? (Don’t answer that — it is a rhetorical question.) ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn10"&gt;
&lt;p&gt;I was considering contributing my own implementation of soft references to Ruby, but I worry that I have neither the time nor the skill to see such a project through. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn11"&gt;
&lt;p&gt;The term “thread safety” is possibly not quite correct in this context. After all, the code will execute correctly without changes, and the issue is really about efficiency. But I can’t think of a term that fits this problem better than “thread safety”, so that is what I am using. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn12"&gt;
&lt;p&gt;To the best of my knowledge, that is. I wouldn’t want to swear on this implementation being correct, because multithreading is &lt;em&gt;hard&lt;/em&gt;. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn13"&gt;
&lt;p&gt;I am happy to have abandoned &lt;em&gt;ddmemoize&lt;/em&gt; in favor of better solutions. It is, after all, not about what we create, but about what we do to help us &lt;em&gt;get stuff done&lt;/em&gt; and grow and learn as software developers and as people.The &lt;em&gt;ddmemoize&lt;/em&gt; project definitely helped with that. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>ruby</category>
      <category>memoization</category>
    </item>
    <item>
      <title>Avoiding bugs in Ruby code using the state pattern</title>
      <dc:creator>Denis Defreyne</dc:creator>
      <pubDate>Thu, 19 Jan 2023 12:39:52 +0000</pubDate>
      <link>https://forem.com/denisdenisdenis/avoiding-bugs-in-ruby-code-using-the-state-pattern-ibd</link>
      <guid>https://forem.com/denisdenisdenis/avoiding-bugs-in-ruby-code-using-the-state-pattern-ibd</guid>
      <description>&lt;p&gt;“Be more careful” is often not useful advice. Software bugs are inevitable, but as I become proficient in software development, my code tends to have fewer initial bugs.&lt;/p&gt;

&lt;p&gt;In some part, this is because experience has taught me to spot bugs more quickly. But more importantly, I’ve learned techniques to structure code in ways that make bugs much less likely to arise in the first place.&lt;/p&gt;

&lt;p&gt;One such technique is the &lt;em&gt;state pattern&lt;/em&gt;. In this article, I’ll take you through an example, at first with a brittle implementation, and then reworked using the state pattern into something more stable.&lt;/p&gt;

&lt;h2&gt;
  
  
  The example: A messaging platform
&lt;/h2&gt;

&lt;p&gt;The example I’ll use throughout this article is a simplified messaging platform. On this platform, any person can register:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;account&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;account_details&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The account details, passed to the &lt;code&gt;.register&lt;/code&gt; method, would include at least an email address, but also properties such as first name and last name.&lt;/p&gt;

&lt;p&gt;Before the registered account is usable, the person needs to confirm the account, using a code they received via email:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;confirm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"ABC123"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, an administrator is expected to approve the account before it can be used:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;approve&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the account confirmed (by the person registering) and approved (by an administrator), the person is now free to use their account to send messages to other people:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;tim&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="s2"&gt;"I’m selling these fine leather jackets."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is important that people &lt;em&gt;cannot&lt;/em&gt; send messages unless their account is both confirmed and approved.&lt;/p&gt;

&lt;p&gt;Let’s take a look at two different ways of implementing this: a naïve implementation, and a safer implementation that uses the state pattern.&lt;/p&gt;

&lt;h2&gt;
  
  
  A naïve implementation
&lt;/h2&gt;

&lt;p&gt;The simplest implementation (that I can think of) starts with an initializer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Account&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;
    &lt;span class="vi"&gt;@code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"ABC123"&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The initializer sets the confirmation code. In a real-world scenario, the confirmation code would be randomly generated. Here, it is hardcoded for the sake of simplicity.&lt;/p&gt;

&lt;p&gt;We’ll also need an implementation for the &lt;code&gt;Account.register&lt;/code&gt; method, which we used earlier:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;account_details&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;new&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For this demo implementation, all it does is create a new instance of &lt;code&gt;Account&lt;/code&gt;. In a real-world scenario, this might be the place to create a new database record and send out an email with the confirmation code. For simplicity, all of that is left out.&lt;/p&gt;

&lt;p&gt;We’ll need &lt;code&gt;#confirm&lt;/code&gt;, which checks whether the given code is correct, and advances the state to &lt;code&gt;:confirmed&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-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;confirm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;code&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;code&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="vi"&gt;@code&lt;/span&gt;
      &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="no"&gt;InvalidConfirmationCode&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="vi"&gt;@state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:confirmed&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next up is &lt;code&gt;#approve&lt;/code&gt;, which advances the state to &lt;code&gt;:confirmed_and_approved&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-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;approve&lt;/span&gt;
    &lt;span class="vi"&gt;@state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:confirmed_and_approved&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, we have &lt;code&gt;#message&lt;/code&gt;, which is the method used for sending messages to other accounts. It requires that the account is in the &lt;code&gt;:confirmed_and_approved&lt;/code&gt; state:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-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;message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;who&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="vi"&gt;@state&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="ss"&gt;:confirmed_and_approved&lt;/span&gt;
      &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="no"&gt;AccountNotApproved&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Sending message to &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;who&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&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 example implementation of &lt;code&gt;#message&lt;/code&gt;, we just log the message.&lt;/p&gt;

&lt;p&gt;We’ll also need these two exception classes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;AccountNotApproved&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;StandardError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="no"&gt;InvalidConfirmationCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;StandardError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is an example that ties it all together:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;tims_account_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;12358&lt;/span&gt;

&lt;span class="n"&gt;account&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;confirm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"ABC123"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;approve&lt;/span&gt;
&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tims_account_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"What’s up, Tim?"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we confirm the account, then an administrator approves the account, and lastly we use the account to send a message to Tim, whose account ID is 12358. The terminal output now shows this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Sending message to 12358.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So far, so good.&lt;/p&gt;

&lt;p&gt;But what if we confirm the account again, after it has already been approved?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;tims_account_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;12358&lt;/span&gt;

&lt;span class="n"&gt;account&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;confirm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"ABC123"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;approve&lt;/span&gt;
&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;confirm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"ABC123"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tims_account_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"What’s up, Tim?"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running this example results in an error during the call to the &lt;code&gt;#message&lt;/code&gt; method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;account.rb:9:in `message':
  AccountNotApproved (AccountNotApproved)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;AccountNotApproved&lt;/code&gt;?! The account definitely &lt;em&gt;was&lt;/em&gt; approved. The issue is that our implementation of &lt;code&gt;#confirm&lt;/code&gt; set the state to &lt;code&gt;:confirmed&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-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;confirm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;code&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;code&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="vi"&gt;@code&lt;/span&gt;
      &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="no"&gt;InvalidConfirmationCode&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="vi"&gt;@state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:confirmed&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we have a bug: the state shouldn’t be set to &lt;code&gt;:confirmed&lt;/code&gt; if the account is already approved. One quick fix for this would be to zero out the &lt;code&gt;@code&lt;/code&gt; variable, so that attempting to confirm again would fail:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-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;confirm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;code&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;code&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="vi"&gt;@code&lt;/span&gt;
      &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="no"&gt;InvalidConfirmationCode&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="vi"&gt;@state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:confirmed&lt;/span&gt;
    &lt;span class="vi"&gt;@code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&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;That is a bit of a hack, though. A slightly better way to solve this is to only allow confirmation when the &lt;code&gt;@state&lt;/code&gt; is the initial state:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-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;confirm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vi"&gt;@state&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="ss"&gt;:initial&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="vi"&gt;@code&lt;/span&gt;
      &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="no"&gt;InvalidConfirmationCode&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="vi"&gt;@state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:confirmed&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’d also need to set the initial &lt;code&gt;@state&lt;/code&gt; in the initializer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-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;initialize&lt;/span&gt;
    &lt;span class="vi"&gt;@code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"ABC123"&lt;/span&gt;
    &lt;span class="vi"&gt;@state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:initial&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With that bug solved, let us take a look at another issue: it is possible for an account to be approved without having gone through confirmation at all:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;tims_account_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;12358&lt;/span&gt;

&lt;span class="n"&gt;account&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;approve&lt;/span&gt;
&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tims_account_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"What’s up, Tim?"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The terminal output now shows this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Sending message to 12358.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This might be a bug, or it might not be. Perhaps it is intentional that administrators can approve accounts, skipping confirmation. Or perhaps this is an oversight in our implementation.&lt;/p&gt;

&lt;p&gt;If we assume it is an oversight, and thus a bug, one way of fixing it is to verify that the state is what we expect it to be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-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;approve&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="no"&gt;AccountNotConfirmed&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vi"&gt;@state&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="ss"&gt;:confirmed&lt;/span&gt;

    &lt;span class="vi"&gt;@state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:confirmed_and_approved&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’ll also need to define a new exception:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;AccountNotConfirmed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;StandardError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="no"&gt;AccountNotApproved&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;StandardError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="no"&gt;InvalidConfirmationCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;StandardError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code is now — as far as I can tell — bug-free, though I’m not comfortable with the end result. This code feels brittle to me: any change in the future has a high chance of inadvertently modifying the expected behavior.&lt;/p&gt;

&lt;p&gt;This could would need an extensive test suite. Such a test suite would verify that going through all the different paths, in all different orders, yield correct results. The presence of a test suite would make me feel more comfortable, but there is more that we can do.&lt;/p&gt;

&lt;p&gt;Let’s now take a look at a new implementation, which uses &lt;code&gt;@state&lt;/code&gt; rather differently.&lt;/p&gt;

&lt;h2&gt;
  
  
  A safer implementation
&lt;/h2&gt;

&lt;p&gt;In this implementation, the &lt;code&gt;Account&lt;/code&gt; class no longer contains the functionality for confirming, approving, and messaging. Rather, all of that is delegated to &lt;code&gt;@state&lt;/code&gt;, which is now its own object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Account&lt;/span&gt;
  &lt;span class="nb"&gt;attr_accessor&lt;/span&gt; &lt;span class="ss"&gt;:state&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;
    &lt;span class="vi"&gt;@state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;InitialAccountState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&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;def&lt;/span&gt; &lt;span class="nf"&gt;confirm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;confirm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;code&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;def&lt;/span&gt; &lt;span class="nf"&gt;approve&lt;/span&gt;
    &lt;span class="vi"&gt;@state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;approve&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;who&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;who&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&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;You could go fancy and use Ruby’s built-in &lt;code&gt;Forwardable&lt;/code&gt; module for that if you want. With that module, the implementation of &lt;code&gt;Account&lt;/code&gt; could look like this — doing exactly the same:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Account&lt;/span&gt;
  &lt;span class="kp"&gt;extend&lt;/span&gt; &lt;span class="no"&gt;Forwardable&lt;/span&gt;
  &lt;span class="n"&gt;def_delegators&lt;/span&gt; &lt;span class="ss"&gt;:@state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:confirm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:approve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:message&lt;/span&gt;

  &lt;span class="nb"&gt;attr_accessor&lt;/span&gt; &lt;span class="ss"&gt;:state&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;
    &lt;span class="vi"&gt;@state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;InitialAccountState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&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;Here is what &lt;code&gt;InitialAccountState&lt;/code&gt; looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;InitialAccountState&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"ABC123"&lt;/span&gt;
    &lt;span class="vi"&gt;@account&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;account&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;confirm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;code&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;code&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="vi"&gt;@code&lt;/span&gt;
      &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="no"&gt;InvalidConfirmationCode&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="vi"&gt;@account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ConfirmedAccountState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@account&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;The &lt;code&gt;InitialAccountState#confirm&lt;/code&gt; method is quite similar to the original &lt;code&gt;#confirm&lt;/code&gt;: it checks the confirmation codes, and raises an exception if they don’t match.&lt;/p&gt;

&lt;p&gt;While the original &lt;code&gt;#confirm&lt;/code&gt; changed the state using &lt;code&gt;@state = :confirmed&lt;/code&gt;, this new &lt;code&gt;#confirm&lt;/code&gt; method changes the account state to a new state object. (We’ll get to the implementation of &lt;code&gt;ConfirmedAccountState&lt;/code&gt; in a bit.)&lt;/p&gt;

&lt;p&gt;Also worth noting is that the confirmation code lives in the &lt;code&gt;InitialAccountState&lt;/code&gt; instance. That is the only place where it is useful. It could also live in &lt;code&gt;Account&lt;/code&gt;, but it wouldn’t have a purpose there.&lt;/p&gt;

&lt;p&gt;Without having the other state objects implemented, we can already see that one of the buggy behaviors from earlier no longer silently succeeds:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;tims_account_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;12358&lt;/span&gt;

&lt;span class="n"&gt;account&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;approve&lt;/span&gt;
&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tims_account_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"What’s up, Tim?"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This piece of code raises a &lt;code&gt;NoMethodError&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;account_with_state.rb:13:
  in `approve': undefined method `approve' for
  #&amp;lt;InitialAccountState:0x0000000100907fa8 …&amp;gt;
  (NoMethodError)

  @state.approve(code)
        ^^^^^^^^
      from account_with_state.rb:66:in `&amp;lt;main&amp;gt;'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This &lt;code&gt;NoMethodError&lt;/code&gt; is intentional! It signals that there hasn’t been any thought put into the situation where someone would try to approve an account that hasn’t been confirmed yet.&lt;/p&gt;

&lt;p&gt;This &lt;code&gt;NoMethodError&lt;/code&gt; is a replacement for undefined behavior. I believe that it is preferable to get a &lt;code&gt;NoMethodError&lt;/code&gt; than to execute incorrect behavior.&lt;/p&gt;

&lt;p&gt;We are still able to implement &lt;code&gt;#approve&lt;/code&gt; here, if we wish. Perhaps it &lt;em&gt;is&lt;/em&gt; desirable to approve accounts from their initial state, bypassing confirmation. If so, we could implement &lt;code&gt;#approve&lt;/code&gt; as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;InitialAccountState&lt;/span&gt;
  &lt;span class="err"&gt;…&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;approve&lt;/span&gt;
    &lt;span class="vi"&gt;@account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ConfirmedAndApprovedAccountState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@account&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;Let’s move on to &lt;code&gt;ConfirmedAccountState&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ConfirmedAccountState&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@account&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;account&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;approve&lt;/span&gt;
    &lt;span class="vi"&gt;@account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ConfirmedAndApprovedAccountState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@account&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;The &lt;code&gt;#approve&lt;/code&gt; method exists here, and moves the state forward to the “account approved” state.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;ConfirmedAccountState&lt;/code&gt; state has no &lt;code&gt;#confirm&lt;/code&gt; method here. If we were to try to confirm an already approved account, we’d get a &lt;code&gt;NoMethodError&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;account_with_state.rb:28:
  in `confirm': undefined method `confirm' for
  #&amp;lt;ConfirmedAccountState:0x0000000100907fa8 …&amp;gt;
  (NoMethodError)

  @state.confirm(code)
        ^^^^^^^^
      from account_with_state.rb:66:in `&amp;lt;main&amp;gt;'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, the &lt;code&gt;NoMethodError&lt;/code&gt; is less desirable. I would probably implement &lt;code&gt;#confirm&lt;/code&gt; anyway, and have it do nothing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ConfirmedAccountState&lt;/span&gt;
  &lt;span class="err"&gt;…&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;confirm&lt;/span&gt;
    &lt;span class="c1"&gt;# Already confirmed; do nothing&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This makes the behavior explicit: confirming an account that is already confirmed does nothing. The &lt;code&gt;#confirm&lt;/code&gt; method in our naïve implementation also did nothing in this case, but it wasn’t nearly as explicit.&lt;/p&gt;

&lt;p&gt;Lastly, we have &lt;code&gt;ConfirmedAndApprovedAccountState&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ConfirmedAndApprovedAccountState&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@account&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;account&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;who&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Sending message to &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;who&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&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;This state is the least interesting: it just has the &lt;code&gt;#message&lt;/code&gt; for sending messages.&lt;/p&gt;

&lt;p&gt;For this state, it makes sense to implement the &lt;code&gt;#confirm&lt;/code&gt; and &lt;code&gt;#approve&lt;/code&gt; methods, and have them do nothing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ConfirmedAndApprovedAccountState&lt;/span&gt;
  &lt;span class="err"&gt;…&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;confirm&lt;/span&gt;
    &lt;span class="c1"&gt;# Already confirmed; do nothing&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;approve&lt;/span&gt;
    &lt;span class="c1"&gt;# Already approved; do nothing&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With all that, we have an implementation where the state transitions are explicit, and it is also more clear what actions can be taken in which states.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing thoughts
&lt;/h2&gt;

&lt;p&gt;The implementation which uses the state pattern makes me the most comfortable. It avoids undefined behavior, and even though &lt;code&gt;NoMethodError&lt;/code&gt;s are a little nasty, they’re better to have than undefined behavior.&lt;/p&gt;

&lt;p&gt;There is nothing preventing us from implementing &lt;em&gt;all&lt;/em&gt; methods, and avoiding &lt;code&gt;NoMethodError&lt;/code&gt; altogether. For each combination of state and method, we’d have to think about what the behavior should be. Perhaps it is doing nothing, perhaps it is raising a specific exception, or perhaps it is doing something else entirely.&lt;/p&gt;

&lt;p&gt;Defining the behavior for each combination of state and method is not always easy. This can make the state pattern look cumbersome and difficult. However, if we want high-quality software, we can’t get away from defining behavior anyway. It seemed to be optional in the original, naïve implementation, but that led to bugs as a result.&lt;/p&gt;

&lt;p&gt;I prefer explicit, readable code over compact code every time. Explicit code makes it easier to find and prevent bugs. Explicit, readable code is less likely to break over time, even in a codebase with a large amount of churn.&lt;/p&gt;

&lt;p&gt;Back in university, a professor said to me that &lt;code&gt;if&lt;/code&gt; statements are a code smell. While I think that is an over-generalisation, you’ll find that the original, naïve implementation has quite some &lt;code&gt;if&lt;/code&gt;s — especially in the bug fixes — while the state pattern implementation has few.&lt;/p&gt;

&lt;p&gt;If in the future I find myself in a situation where behavior depends on state, you can be sure I’ll whip out the state pattern.&lt;/p&gt;

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