{
  "version": "https://jsonfeed.org/version/1",
  "title": "Ruby on enumerator.dev",
  "icon": "<no value>",
  "home_page_url": "https://enumerator.dev/",
  "feed_url": "https://enumerator.dev/feed.json",
  "items": [
      {
        "id": "https://enumerator.dev/naming-things-for-what-they-do/",
        "title": "Naming Things for What They Do",
        "content_html": "<p>I just saw the Rails World announcement that flavorjones is working on <a href=\"https://github.com/basecamp/activerecord-tenanted\">ActiveRecord::Tenanted</a> and all I can say is, “What a reasonable name!”</p>\n<p>When I started willow.camp I chose not to use <a href=\"https://github.com/influitive/apartment\">apartment</a> partially because the name and the metaphor were too confusing. I didn&rsquo;t like tho have to get used to the idea of requests taking &ldquo;elevators&rdquo; and all that. The &ldquo;apartment&rdquo; metaphor doesn&rsquo;t work for databases even though &ldquo;tenant&rdquo; does.</p>\n<p>Always choose descriptive names over clever ones. It doesn’t matter how well you think the metaphor fits; you’ll always end up with something confusing in the end.</p>\n",
        "date_published": "2025-09-09T11:23:33+00:00",
        "url": "https://enumerator.dev/naming-things-for-what-they-do/",
        "tags": ["ruby","rails"]
      },
      {
        "id": "https://enumerator.dev/use-precomputed-hashes-instead-of-bcrypt-in-test/",
        "title": "Use Precomputed Hashes Instead of BCrypt in Test",
        "content_html": "<p>I asked Claude to find the slowest test file again after my success <a href=\"/speeding-up-willow-camp-s-post_test-rb-by-99\">earlier today</a> and Claude found a call to BCrypt in my fixtures that was gobbling up time.</p>\n<p>I need user records all over the place in my test and each new user is a new call to encrypt a password.</p>\n<p>Here is Claude&rsquo;s summary, with my Grammarly edits:</p>\n<blockquote>\n<p>Problem: The <code>PreviewsControllerTest#test_should_show_preview_for_own_unpublished_post</code> test was taking 2.95 seconds due to BCrypt password hashing being computed dynamically in fixtures with <code>&lt;%= BCrypt::Password.create(&quot;password&quot;) %&gt;</code>.</p>\n<p>Solution: Replaced the dynamic BCrypt computation with a pre-computed hash <code>$2a$12$dapdHZiOTxAL8OT9yNI6e.hhTjRhWgXq7kx737/xf8tBfQbMD2bi</code> for all user fixtures.</p>\n<p>Result: The slowest test now runs in ~0.25-0.52 seconds (82% improvement) and all tests pass. The overall test suite performance has been significantly improved, as this optimization affects all tests that use user fixtures.</p>\n</blockquote>\n",
        "date_published": "2025-07-21T00:55:00+00:00",
        "url": "https://enumerator.dev/use-precomputed-hashes-instead-of-bcrypt-in-test/",
        "tags": ["willow-camp","performance","ruby","rails"]
      },
      {
        "id": "https://enumerator.dev/speeding-up-willow-camp-s-post_test-rb-by-99/",
        "title": "Speeding Up willow.camp's post_test.rb by 99%",
        "content_html": "<p>I just asked Claude to speed up the slowest test file in willow.camp. post_test.rb was taking over 1 second to execute. For a tiny Ruby app, that&rsquo;s a long time.</p>\n<p>Here&rsquo;s what Claude did. I was not expecting such a simple fix!</p>\n<blockquote>\n<p>Test: test_should_detect_mermaid_diagrams_and_set_has_mermaid_diagrams_flag in test/models/post_test.rb:82</p>\n<p>Issue: The test was using an unnecessarily large markdown string that required\nexpensive processing through the Commonmarker library.</p>\n<p>Optimization: Reduced the test markdown from a multi-section document to a minimal string that still tests the same functionality:</p>\n<ul>\n<li>Before: Large heredoc with headers, multiple code blocks, and text content</li>\n<li>After: Simple &ldquo;<code>mermaid\\ngraph TD\\n  A --&gt; B\\n</code>&rdquo; string\nPerformance Improvement:</li>\n<li>Before: 1.31 seconds</li>\n<li>After: 0.01 seconds</li>\n<li>Improvement: 99%+ faster (130x speed improvement)\nThe optimization maintains full test coverage while dramatically reducing execution time by eliminating unnecessary markdown processing overhead.</li>\n</ul>\n</blockquote>\n<p>The original test was designed to evaluate a full-fledged Markdown document that was about 10 lines long. I didn&rsquo;t need that in this case because I just needed to test that my custom <code>mermaid</code> code block worked.</p>\n<p>Thanks Claude!</p>\n",
        "date_published": "2025-07-20T14:05:00+00:00",
        "url": "https://enumerator.dev/speeding-up-willow-camp-s-post_test-rb-by-99/",
        "tags": ["willow-camp","performance","ruby","rails"]
      },
      {
        "id": "https://enumerator.dev/how-rack-timeout-keeps-your-app-alive/",
        "title": "How Rack::Timeout Keeps Your App Alive",
        "content_html": "<p><a href=\"https://github.com/zombocom/rack-timeout\">Rack::Timeout</a> is a library that monitors long-running requests in a Ruby app and kills them if they take too long. The default configuration in Rack::Timeout is to kill requests that take 15 seconds or longer.</p>\n<h2 id=\"why-requests-take-a-long-time\">Why Requests Take A Long Time?</h2>\n<p>The answer here will vary from one app to another. A frequent culprit is database transactions taking too long or outgoing requests to other resources hanging.</p>\n<h2 id=\"how-does-this-keep-my-app-alive-if-it-kills-things\">How Does This Keep My App Alive if it Kills Things?</h2>\n<p>In a typical Ruby app using Puma, you will have a few processes to manage a Ruby Thread collection. Rack::Timeout will send SIGTERM to a process if it breaches the timeout.</p>\n<p>Your Ruby app and Puma process will remain alive, but the stuck process will be terminated.</p>\n<p>Puma will notice that this process has terminated and will boot up a new one.</p>\n<h2 id=\"when-is-racktimeout-unsafe\">When is Rack::Timeout Unsafe?</h2>\n<p>Killing a running process is often unsafe. Fortunately, Rack::Timeout uses a &ldquo;polite&rdquo; kill message, SIGTERM, which requests that the process shut down and clean up its resources.</p>\n<p>SIGTERM is less severe than SIGKILL, but still poses risks.</p>\n<p>A Ruby thread could be in the middle of creating database records when it is killed, which would result in things being left in a broken state.</p>\n<h2 id=\"where-does-racktimeout-run-in-my-app\">Where Does Rack::Timeout Run in My App?</h2>\n<p>Rack::Timeout runs in Rack, an interface between web servers, like Puma, and Rails applications. Puma receives a request, hands it off to a thread, which passes it through Rack before it reaches your application code.</p>\n<p>When Rack handles the request, it monitors the request duration and kills the process if the request takes too long.</p>\n<p>Rack::Timeout keeps your application alive by killing hanging processes and allowing Puma to boot up a new process to handle the next request.</p>\n<pre><code class=\"language-mermaid\">graph TD\nClient[Client Requests] --&gt; LB[Load Balancer\nnginx/HAProxy]\nLB --&gt; Container1[Container 1\nRails App]\nLB --&gt; Container2[Container 2\nRails App]\nContainer1 --&gt; PumaServer1[Puma Server 1]\nContainer2 --&gt; PumaServer2[Puma Server 2]\nPumaServer1 --&gt; Worker1_1[Worker 1]\nPumaServer1 --&gt; Worker1_2[Worker 2]\nPumaServer2 --&gt; Worker2_1[Worker 1]\nPumaServer2 --&gt; Worker2_2[Worker 2]\nWorker1_1 --&gt; RackTimeout1_1[Rack::Timeout\nMiddleware]\nWorker1_2 --&gt; RackTimeout1_2[Rack::Timeout\nMiddleware]\nWorker2_1 --&gt; RackTimeout2_1[Rack::Timeout\nMiddleware]\nWorker2_2 --&gt; RackTimeout2_2[Rack::Timeout\nMiddleware]\nRackTimeout1_1 --&gt; Threads1_1[3 Threads\nThread Pool\n_timeout monitored per thread_]\nRackTimeout1_2 --&gt; Threads1_2[3 Threads\nThread Pool\n_timeout monitored per thread_]\nRackTimeout2_1 --&gt; Threads2_1[3 Threads\nThread Pool\n_timeout monitored per thread_]\nRackTimeout2_2 --&gt; Threads2_2[3 Threads\nThread Pool\n_timeout monitored per thread_]\nclassDef container fill:#e1f5fe\nclassDef worker fill:#f3e5f5\nclassDef thread fill:#e8f5e8\nclassDef loadbalancer fill:#fce4ec\nclassDef middleware fill:#fff3e0\nclass Container1,Container2 container\nclass Worker1_1,Worker1_2,Worker2_1,Worker2_2 worker\nclass Threads1_1,Threads1_2,Threads2_1,Threads2_2 thread\nclass LB loadbalancer\nclass RackTimeout1_1,RackTimeout1_2,RackTimeout2_1,RackTimeout2_2 middleware</code></pre>\n",
        "date_published": "2025-06-05T00:00:00+00:00",
        "url": "https://enumerator.dev/how-rack-timeout-keeps-your-app-alive/",
        "tags": ["performance","ruby","rails"]
      },
      {
        "id": "https://enumerator.dev/migrating-from-standalone-sidekiq-to-an-activejob-adapter/",
        "title": "Migrating from Standalone Sidekiq to an ActiveJob Adapter",
        "content_html": "<p>I paired on this problem with my coworker <a href=\"https://www.linkedin.com/in/hannah-yeates/\">Hannah Yeates</a>. The examples below are from this pairing session. Thanks for working on this together, Hannah!</p>\n<hr>\n<p>I am working on a project right now that uses Sidekiq without the ActiveJob adapter. This means that our Sidekiq jobs look something like this:</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-rb\" data-lang=\"rb\"><span class=\"line\"><span class=\"cl\"><span class=\"k\">class</span> <span class=\"nc\">ExampleWorker</span>\n</span></span><span class=\"line\"><span class=\"cl\">  <span class=\"kp\">include</span> <span class=\"no\">Sidekiq</span><span class=\"o\">::</span><span class=\"no\">Worker</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\">  <span class=\"k\">def</span> <span class=\"nf\">perform</span><span class=\"p\">(</span><span class=\"n\">arg</span><span class=\"p\">)</span>\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"nb\">puts</span> <span class=\"s2\">&#34;Hello, the arg was </span><span class=\"si\">#{</span><span class=\"n\">arg</span><span class=\"si\">}</span><span class=\"s2\">&#34;</span>\n</span></span><span class=\"line\"><span class=\"cl\">  <span class=\"k\">end</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"k\">end</span>\n</span></span></code></pre></div><p>And we call them like this:</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-rb\" data-lang=\"rb\"><span class=\"line\"><span class=\"cl\"><span class=\"no\">ExampleWorker</span><span class=\"o\">.</span><span class=\"n\">perform_async</span><span class=\"p\">(</span><span class=\"s2\">&#34;a nice arg&#34;</span><span class=\"p\">)</span>\n</span></span></code></pre></div><p>And in dev they&rsquo;ll execute like this:</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-rb\" data-lang=\"rb\"><span class=\"line\"><span class=\"cl\"><span class=\"mi\">2024</span><span class=\"o\">-</span><span class=\"mo\">01</span><span class=\"o\">-</span><span class=\"mi\">17</span><span class=\"ss\">T15</span><span class=\"p\">:</span><span class=\"mo\">05</span><span class=\"p\">:</span><span class=\"mi\">31</span><span class=\"o\">.</span><span class=\"mi\">455</span><span class=\"n\">Z</span> <span class=\"n\">pid</span><span class=\"o\">=</span><span class=\"mi\">45599</span> <span class=\"n\">tid</span><span class=\"o\">=</span><span class=\"mi\">18</span><span class=\"n\">gj</span>\n</span></span><span class=\"line\"><span class=\"cl\">  <span class=\"n\">class</span><span class=\"o\">=</span><span class=\"no\">TestWorker</span> \n</span></span><span class=\"line\"><span class=\"cl\">  <span class=\"n\">jid</span><span class=\"o\">=</span><span class=\"mi\">8</span><span class=\"n\">d32dcd88b1de2ed3a5419eb</span> \n</span></span><span class=\"line\"><span class=\"cl\">  <span class=\"ss\">INFO</span><span class=\"p\">:</span> <span class=\"n\">start</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"no\">Hello</span><span class=\"p\">,</span> <span class=\"n\">the</span> <span class=\"n\">arg</span> <span class=\"n\">was</span> <span class=\"n\">foo</span>\n</span></span></code></pre></div><p>However, we want to switch over to <a href=\"https://github.com/bensheldon/good_job\">GoodJob</a> so that we have a transactionally safe background job processor. Our steps for doing this are:</p>\n<ol>\n<li>Set up Sidekiq as an ActiveJob adapter instead of using Sidekiq on its own.</li>\n<li>Install GoodJob and replace Sidekiq with GoodJob.</li>\n<li>Run Sidekiq and GoodJob in parallel so that Sidekiq finishes all the work in Redis.</li>\n<li>Shut down Sidekiq and remove it from the application code.</li>\n</ol>\n<p>This post is about step 1, making Sidekiq the ActiveJob adapter instead of using it on its own.</p>\n<h2 id=\"step-1--configure-activejob\">Step 1 : Configure ActiveJob</h2>\n<p>Our first step is to configure the application to use Sidekiq for ActiveJob</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-rb\" data-lang=\"rb\"><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># in application.rb</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">active_job</span><span class=\"o\">.</span><span class=\"n\">queue_adapter</span> <span class=\"o\">=</span> <span class=\"ss\">:sidekiq</span>\n</span></span></code></pre></div><p>Then we created an empty <code>ApplicationJob</code> (more on this later).</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-rb\" data-lang=\"rb\"><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># application_job.rb</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"k\">class</span> <span class=\"nc\">ApplicationJob</span> <span class=\"o\">&lt;</span> <span class=\"no\">ActiveJob</span><span class=\"o\">::</span><span class=\"no\">Base</span>\n</span></span><span class=\"line\"><span class=\"cl\">  <span class=\"c1\"># leave this empty for now</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"k\">end</span>\n</span></span></code></pre></div><h2 id=\"step-2-convert-workers-to-applicationjob\">Step 2: Convert Workers to ApplicationJob</h2>\n<p>Next we updated our jobs to inherit from application job:</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-rb\" data-lang=\"rb\"><span class=\"line\"><span class=\"cl\"><span class=\"k\">class</span> <span class=\"nc\">ExampleWorker</span> <span class=\"o\">&lt;</span> <span class=\"no\">ApplicationJob</span> <span class=\"c1\"># Add this</span>\n</span></span><span class=\"line\"><span class=\"cl\">  <span class=\"c1\"># remove this: include Sidekiq::Worker</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\">  <span class=\"c1\"># The rest of the code remains the same</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"k\">end</span>\n</span></span></code></pre></div><p>And finally, we changed all our method calls from <code>ExampleWorker.perform_async(&quot;a nice arg&quot;)</code> to <code>ExampleWorker.perform_later(&quot;a nice arg&quot;)</code>.</p>\n<h2 id=\"step-3-see-what-breaks\">Step 3: See What Breaks</h2>\n<p>So far, so good! Next, we had a question: What happens when a job is enqueued by Sidekiq but processed by ActiveJob? To emulate this we:</p>\n<ol>\n<li>Booted a Rails console locally.</li>\n<li>Use the original code to enqueue a job.</li>\n<li>Modify the worker to use <code>ApplicationJob</code>.</li>\n<li>Boot Sidekiq locally and see what errors we get.</li>\n</ol>\n<p>In the real world, this would happen when the new code is deployed and there are jobs in the queue that were put there by Sidekiq. Here&rsquo;s the first error we got:</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-fallback\" data-lang=\"fallback\"><span class=\"line\"><span class=\"cl\">WARN: NoMethodError: undefined method `jid=&#39; for #&lt;TestWorker:...&gt;\n</span></span></code></pre></div><p>We resolved this by creating an alias to <code>ActiveJob</code>&rsquo;s <code>provider_job_id=</code> and tested again. In the end we had three <code>NoMethodError</code> messages to resolve. We updated our <code>ApplicationJob</code> to respond to those methods.</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-mysql\" data-lang=\"mysql\"><span class=\"line\"><span class=\"cl\"><span class=\"n\">class</span><span class=\"w\"> </span><span class=\"n\">ApplicationJob</span><span class=\"w\">\n</span></span></span><span class=\"line\"><span class=\"cl\"><span class=\"w\">  </span><span class=\"n\">def</span><span class=\"w\"> </span><span class=\"n\">jid</span><span class=\"o\">=</span><span class=\"p\">(</span><span class=\"n\">arg</span><span class=\"p\">)</span><span class=\"w\">\n</span></span></span><span class=\"line\"><span class=\"cl\"><span class=\"w\">    </span><span class=\"n\">provider_job_id</span><span class=\"w\"> </span><span class=\"o\">=</span><span class=\"w\"> </span><span class=\"n\">arg</span><span class=\"w\">\n</span></span></span><span class=\"line\"><span class=\"cl\"><span class=\"w\">  </span><span class=\"n\">end</span><span class=\"w\">\n</span></span></span><span class=\"line\"><span class=\"cl\"><span class=\"w\">\n</span></span></span><span class=\"line\"><span class=\"cl\"><span class=\"w\">  </span><span class=\"n\">def</span><span class=\"w\"> </span><span class=\"n\">jid</span><span class=\"w\">\n</span></span></span><span class=\"line\"><span class=\"cl\"><span class=\"w\">    </span><span class=\"n\">provider_job_id</span><span class=\"w\">\n</span></span></span><span class=\"line\"><span class=\"cl\"><span class=\"w\">  </span><span class=\"n\">end</span><span class=\"w\">\n</span></span></span><span class=\"line\"><span class=\"cl\"><span class=\"w\">\n</span></span></span><span class=\"line\"><span class=\"cl\"><span class=\"w\">  </span><span class=\"n\">def</span><span class=\"w\"> </span><span class=\"n\">bid</span><span class=\"o\">=</span><span class=\"p\">(</span><span class=\"n\">arg</span><span class=\"p\">);</span><span class=\"w\">\n</span></span></span><span class=\"line\"><span class=\"cl\"><span class=\"w\">    </span><span class=\"c1\"># We are lucky to not need batching, so we let this return `nil`\n</span></span></span><span class=\"line\"><span class=\"cl\"><span class=\"w\">  </span><span class=\"n\">end</span><span class=\"w\">\n</span></span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">end</span><span class=\"w\">\n</span></span></span></code></pre></div><h2 id=\"wrapping-up\">Wrapping Up</h2>\n<p>Making the switch to <code>ActiveJob</code> was easier than we expected. We now have a backwards compatible way of moving from standalone Sidekiq to ActiveJob. Our next step is to swap out Sidekiq for GoodJob.</p>\n<p>If you are planning on using GoodJob, or Solid Queue, check out this article on making the switch once you&rsquo;re using ActiveJob:</p>\n<p><a href=\"https://kylekeesling.com/posts/2024/01/migrating-from-sidekiq-to-solid-queue\">Migrating from Sidekiq to Solid Queue | Kyle Keesling</a></p>\n",
        "date_published": "2024-01-17T00:00:00+00:00",
        "url": "https://enumerator.dev/migrating-from-standalone-sidekiq-to-an-activejob-adapter/",
        "tags": ["sidekiq","activejob","ruby","rails"]
      },
      {
        "id": "https://enumerator.dev/weird-method-signatures-in-ruby-with-keyword-arguments/",
        "title": "Weird Method Signatures in Ruby with Keyword Arguments",
        "content_html": "<p>In a recent project, I was working with a method call from a library that used some meta-programming to define a <code>get</code> method. I wasn&rsquo;t certain what the correct signature was, so I thought I&rsquo;d try some things out.</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"line\"><span class=\"cl\"><span class=\"n\">api_client</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;my/path&#39;</span><span class=\"p\">)</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># Success, got at 200!</span>\n</span></span></code></pre></div><p>I knew that the method accepted a request <code>body</code> but I wasn&rsquo;t sure how to pass the body. So I tried this next call.</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"line\"><span class=\"cl\"><span class=\"n\">api_client</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;my/path&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;body&#39;</span><span class=\"p\">)</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># =&gt; ArgumentError: wrong number of arguments (given 2, expected 1)</span>\n</span></span></code></pre></div><p>Okay, this tells me something, but I&rsquo;m a bit confused. How did it expect one argument when I know a successful call can have more than one argument?</p>\n<p>So I tried this, something you might recognize from a Ruby 2 project (more on that later):</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"line\"><span class=\"cl\"><span class=\"n\">api_client</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;my/path&#39;</span><span class=\"p\">,</span> <span class=\"p\">{</span> <span class=\"ss\">body</span><span class=\"p\">:</span> <span class=\"s1\">&#39;body&#39;</span> <span class=\"p\">})</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># =&gt; ArgumentError: wrong number of arguments (given 2, expected 1)</span>\n</span></span></code></pre></div><p>The same error! What does that tell us? It wasn&rsquo;t immediately obvious to me so I tried the next iteration:</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"line\"><span class=\"cl\"><span class=\"n\">api_client</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;my/path&#39;</span><span class=\"p\">,</span> <span class=\"ss\">body</span><span class=\"p\">:</span> <span class=\"s1\">&#39;body&#39;</span><span class=\"p\">)</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># Success, got at 200!</span>\n</span></span></code></pre></div><h2 id=\"lets-break-down-whats-happening-here\">Let&rsquo;s break down what&rsquo;s happening here</h2>\n<ol>\n<li>We&rsquo;re using a variable called <code>api_client</code> in this example. Pretend this is a wrapper that can make HTTP calls to a remote service.</li>\n<li>We&rsquo;re calling the <code>get</code> method which presumably uses HTTP <code>GET</code> to fetch data.</li>\n<li>The <code>get</code> method accepts a positional argument, a string, that represents the URL path we&rsquo;re fetching.</li>\n</ol>\n<p>All good so far, right? The next step is where things get weird.</p>\n<p>What is the next argument? I didn&rsquo;t know until I tried all the options. It turns out <code>body:</code> is a keyword argument, or kwarg, and it has a default. So the method signature must look something like this.</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"line\"><span class=\"cl\"><span class=\"k\">def</span> <span class=\"nf\">get</span><span class=\"p\">(</span><span class=\"n\">path</span><span class=\"p\">,</span> <span class=\"ss\">body</span><span class=\"p\">:</span> <span class=\"p\">{},</span> <span class=\"ss\">headers</span><span class=\"p\">:</span> <span class=\"p\">{})</span>\n</span></span><span class=\"line\"><span class=\"cl\">  <span class=\"c1\"># Perform get request</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"k\">end</span>\n</span></span></code></pre></div><p>So what&rsquo;s with this error? <code>ArgumentError: wrong number of arguments (given 2, expected 1)</code> The method only requires one positional argument to work. So even though it can accept three arguments, it is only expecting one. The result is a message that is a bit misleading because you can correctly call the method with one, two, or three arguments, but the second and third need to be keywords.</p>\n<h3 id=\"lets-make-things-weird\">Let&rsquo;s Make Things Weird</h3>\n<p>In Ruby land, especially applications that existed before Ruby 2, it is reasonable to see a method signature like this.</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"line\"><span class=\"cl\"><span class=\"k\">def</span> <span class=\"nf\">get</span><span class=\"p\">(</span><span class=\"n\">path</span><span class=\"p\">,</span> <span class=\"ss\">options</span><span class=\"p\">:</span> <span class=\"p\">{})</span>\n</span></span><span class=\"line\"><span class=\"cl\">  <span class=\"n\">body</span> <span class=\"o\">=</span> <span class=\"n\">options</span><span class=\"o\">[</span><span class=\"ss\">:body</span><span class=\"o\">]</span>\n</span></span><span class=\"line\"><span class=\"cl\">  <span class=\"n\">headers</span> <span class=\"o\">=</span> <span class=\"n\">options</span><span class=\"o\">[</span><span class=\"ss\">:headers</span><span class=\"o\">]</span>\n</span></span><span class=\"line\"><span class=\"cl\">  <span class=\"c1\"># Perform get request</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"k\">end</span>\n</span></span></code></pre></div><p>Calling this method can look the same as a call with kwargs because the curly braces around a hash in Ruby are optional. That&rsquo;s why I tried wrapping the second argument in a hash. I wanted to know if we were dealing with an options hash or a keyword.</p>\n<p>As a consumer of an interface like this, it can take a bit of poking around to know if you&rsquo;re dealing with an options hash or keywords.</p>\n<h3 id=\"lets-make-things-better\">Let&rsquo;s Make Things Better</h3>\n<p>Kwargs are great for helping developers understand a method signature, but if they&rsquo;re not used carefully they result in confusing error messages.</p>\n<p>To make this method call better, I&rsquo;d suggest defining it entirely with kwargs and doing away with the positional argument.</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"line\"><span class=\"cl\"><span class=\"k\">def</span> <span class=\"nf\">get</span><span class=\"p\">(</span><span class=\"ss\">path</span><span class=\"p\">:,</span> <span class=\"ss\">body</span><span class=\"p\">:</span> <span class=\"p\">{},</span> <span class=\"ss\">headers</span><span class=\"p\">:</span> <span class=\"p\">{})</span>\n</span></span><span class=\"line\"><span class=\"cl\">  <span class=\"c1\"># Perform GET</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"k\">end</span>\n</span></span></code></pre></div><p>Let&rsquo;s see what usage looks like on this. Let&rsquo;s do something wild and call the method with no arguments.</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"line\"><span class=\"cl\"><span class=\"n\">get</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># =&gt; ArgumentError: missing keyword: :path</span>\n</span></span></code></pre></div><p>Oh! That&rsquo;s helpful. I need to give it a <code>path</code>.</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"line\"><span class=\"cl\"><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"ss\">path</span><span class=\"p\">:</span> <span class=\"s1\">&#39;my/path&#39;</span><span class=\"p\">)</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># Success!</span>\n</span></span></code></pre></div><p>What about some obviously wrong method calls?</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"line\"><span class=\"cl\"><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"ss\">path</span><span class=\"p\">:</span> <span class=\"s1\">&#39;my/path&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;body&#39;</span><span class=\"p\">)</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># SyntaxError: unexpected &#39;)&#39;, expecting =&gt;</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># get(path: &#39;my/path&#39;, &#39;body&#39;)</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"ss\">path</span><span class=\"p\">:</span> <span class=\"s1\">&#39;my/path&#39;</span><span class=\"p\">,</span> <span class=\"p\">{</span> <span class=\"ss\">body</span><span class=\"p\">:</span> <span class=\"s1\">&#39;body&#39;</span> <span class=\"p\">})</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># SyntaxError: unexpected &#39;)&#39;, expecting =&gt;</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># get(path: &#39;my/path&#39;, { body: &#39;body&#39; })</span>\n</span></span></code></pre></div><p>SyntaxError! Neat! Because Ruby knows this method needs keywords, it doesn&rsquo;t know how to parse these two calls. This prevents you from even calling the method at all.</p>\n<p>Let&rsquo;s make a typo:</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"line\"><span class=\"cl\"><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"ss\">path</span><span class=\"p\">:</span> <span class=\"s1\">&#39;my/path&#39;</span><span class=\"p\">,</span> <span class=\"ss\">bdy</span><span class=\"p\">:</span> <span class=\"s1\">&#39;body&#39;</span><span class=\"p\">)</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># =&gt; ArgumentError: unknown keyword: :bdy</span>\n</span></span></code></pre></div><p>That&rsquo;s helpful too! It puts the typo right in front of my eyes.</p>\n<p>And finally, let&rsquo;s use all keywords:</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"line\"><span class=\"cl\"><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"ss\">path</span><span class=\"p\">:</span> <span class=\"s1\">&#39;my/path&#39;</span><span class=\"p\">,</span> <span class=\"ss\">body</span><span class=\"p\">:</span> <span class=\"s1\">&#39;body&#39;</span> <span class=\"p\">)</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># Success!</span>\n</span></span></code></pre></div><h2 id=\"but-why-is-it-this-way-a-history-of-keyword-arguments-in-ruby\">But Why is it This Way? A History of Keyword Arguments in Ruby</h2>\n<p>Before keyword arguments existed in Ruby, the method signature would have had an options hash, as I noted above.</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"line\"><span class=\"cl\"><span class=\"k\">def</span> <span class=\"nf\">get</span><span class=\"p\">(</span><span class=\"n\">path</span><span class=\"p\">,</span> <span class=\"n\">options</span> <span class=\"o\">=</span> <span class=\"p\">{})</span>\n</span></span><span class=\"line\"><span class=\"cl\">  <span class=\"n\">headers</span> <span class=\"o\">=</span> <span class=\"n\">options</span><span class=\"o\">[</span><span class=\"ss\">:headers</span><span class=\"o\">]</span>\n</span></span><span class=\"line\"><span class=\"cl\">  <span class=\"n\">body</span> <span class=\"o\">=</span> <span class=\"n\">options</span><span class=\"o\">[</span><span class=\"ss\">:body</span><span class=\"o\">]</span>\n</span></span><span class=\"line\"><span class=\"cl\">  <span class=\"c1\"># insert remaining http client code here</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"k\">end</span>\n</span></span></code></pre></div><p>We had a few options for how we called the method, depending on our syntax preferences. Most commonly, you&rsquo;d see something like this:</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"line\"><span class=\"cl\"><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;my/path&#39;</span><span class=\"p\">,</span> <span class=\"ss\">body</span><span class=\"p\">:</span> <span class=\"p\">{},</span> <span class=\"ss\">headers</span><span class=\"p\">:</span> <span class=\"p\">{})</span>\n</span></span></code></pre></div><p>But if you prefer to be explicit about what you are passing to a method you might wrap the hash in curly braces:</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"line\"><span class=\"cl\"><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;my/path&#39;</span><span class=\"p\">,</span> <span class=\"p\">{</span> <span class=\"ss\">body</span><span class=\"p\">:</span> <span class=\"p\">{},</span> <span class=\"ss\">headers</span><span class=\"p\">:</span> <span class=\"p\">{}</span> <span class=\"p\">})</span>\n</span></span></code></pre></div><h3 id=\"enter-keyword-arguments\">Enter Keyword Arguments</h3>\n<p>Keyword arguments were introduced in Ruby 2.0. Ruby 2!!!! &ldquo;Isn&rsquo;t that like eons ago?&rdquo; you say. Yes, it is eons ago, but code practices change very slowly. So the two examples above were very common in Ruby 2.</p>\n<p>In fact, in early versions of Ruby 2 you could define a method using kwargs and call the method with a hash. Ruby would see the hash and automatically convert it to kwargs.</p>\n<p>So that meant a method like this:</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"line\"><span class=\"cl\"><span class=\"k\">def</span> <span class=\"nf\">get</span><span class=\"p\">(</span><span class=\"n\">path</span><span class=\"p\">,</span> <span class=\"ss\">body</span><span class=\"p\">:,</span> <span class=\"ss\">headers</span><span class=\"p\">:)</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"k\">end</span>\n</span></span></code></pre></div><p>Could be called like this:</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"line\"><span class=\"cl\"><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;my/path&#39;</span><span class=\"p\">,</span> <span class=\"ss\">body</span><span class=\"p\">:</span> <span class=\"s1\">&#39;body&#39;</span><span class=\"p\">,</span> <span class=\"ss\">headers</span><span class=\"p\">:</span> <span class=\"p\">{</span> <span class=\"ss\">auth</span><span class=\"p\">:</span> <span class=\"s1\">&#39;auth&#39;</span> <span class=\"p\">})</span>\n</span></span></code></pre></div><p>Or like this:</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"line\"><span class=\"cl\"><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;my/path&#39;</span><span class=\"p\">,</span> <span class=\"p\">{</span> <span class=\"ss\">body</span><span class=\"p\">:</span> <span class=\"s1\">&#39;body&#39;</span><span class=\"p\">,</span> <span class=\"ss\">headers</span><span class=\"p\">:</span> <span class=\"p\">{</span> <span class=\"ss\">auth</span><span class=\"p\">:</span> <span class=\"s1\">&#39;auth&#39;</span> <span class=\"p\">}</span> <span class=\"p\">})</span>\n</span></span></code></pre></div><p>Ruby would figure out that the second argument, the hash, is the keyword argument. To the developer using the <code>get</code> method, there is no difference between using kwargs or an options hash, provided the use the right keywords.</p>\n<p>Additionally, developers often chose to use a hash as the last positional argument for flexibility. Imagine an options hash with five or more options. Using kwargs the method signature would make the method unreadable!</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"line\"><span class=\"cl\"><span class=\"k\">def</span> <span class=\"nf\">get</span><span class=\"p\">(</span><span class=\"n\">path</span><span class=\"p\">,</span> <span class=\"ss\">body</span><span class=\"p\">:,</span> <span class=\"ss\">headers</span><span class=\"p\">:,</span> <span class=\"k\">retry</span><span class=\"p\">:,</span> <span class=\"ss\">retry_delay</span><span class=\"p\">:,</span> <span class=\"ss\">admin</span><span class=\"p\">:,</span> <span class=\"ss\">on_error</span><span class=\"p\">:</span> <span class=\"o\">...</span><span class=\"p\">)</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"k\">end</span>\n</span></span></code></pre></div><p><em>A contrived example of a long kwargs list</em></p>\n<p>With kwargs users need to know the kwargs and the method signature is locked into the kwargs that the developer chose. But with an options hash, there is some flexibility to add or remove options if things change.</p>\n<p><a href=\"https://www.ruby-lang.org/en/news/2019/12/12/separation-of-positional-and-keyword-arguments-in-ruby-3-0/\">But in Ruby 3 all that changed and Ruby stopped automatically converting positional hashes to keyword arguments.</a></p>\n<p>Today we get a slightly ambiguous message when we use signatures that mix positional and keyword arguments, but in Ruby 2, a positional argument could be converted to a keyword argument unexpectedly. An excerpt from the post above shows how keyword arguments were confusing:</p>\n<blockquote>\n<p>Automatic conversion does not work well when a method accepts optional positional arguments and keyword arguments. Some people expect the last Hash object to be treated as a positional argument, and others expect it to be converted to keyword arguments.</p>\n</blockquote>\n<p>Let&rsquo;s rewrite the <code>get</code> method to demonstrate how this can be confusing. (Note: this is my rewording of the example that the authors of the Ruby blog post wrote).</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># Using Ruby 2.6</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"k\">def</span> <span class=\"nf\">get</span><span class=\"p\">(</span><span class=\"n\">path</span><span class=\"p\">,</span> <span class=\"ss\">body</span><span class=\"p\">:</span> <span class=\"p\">{},</span> <span class=\"ss\">headers</span><span class=\"p\">:</span> <span class=\"p\">{})</span>\n</span></span><span class=\"line\"><span class=\"cl\">  <span class=\"nb\">p</span> <span class=\"o\">[</span><span class=\"n\">path</span><span class=\"p\">,</span> <span class=\"n\">body</span><span class=\"p\">,</span> <span class=\"n\">headers</span><span class=\"o\">]</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"k\">end</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">get</span><span class=\"p\">({})</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># =&gt; [{}, {}, {}]</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"k\">def</span> <span class=\"nf\">get_with_default</span><span class=\"p\">(</span><span class=\"n\">path</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;home&#39;</span><span class=\"p\">,</span> <span class=\"ss\">body</span><span class=\"p\">:</span> <span class=\"p\">{},</span> <span class=\"ss\">headers</span><span class=\"p\">:</span> <span class=\"p\">{})</span>\n</span></span><span class=\"line\"><span class=\"cl\">  <span class=\"nb\">p</span> <span class=\"o\">[</span><span class=\"n\">path</span><span class=\"p\">,</span> <span class=\"n\">body</span><span class=\"p\">,</span> <span class=\"n\">headers</span><span class=\"o\">]</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"k\">end</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">get_with_default</span><span class=\"p\">({})</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"o\">=&gt;</span> <span class=\"o\">[</span><span class=\"s2\">&#34;home&#34;</span><span class=\"p\">,</span> <span class=\"p\">{},</span> <span class=\"p\">{}</span><span class=\"o\">]</span>\n</span></span></code></pre></div><p><code>get_with_default</code> has an unexpected behaviour here. Since we&rsquo;re only passing one argument, the method should see that as the first positional argument. But because we&rsquo;re passing it a hash, it parses this hash as the keyword arguments. Let&rsquo;s try to put something in that hash to test this out.</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># Again, we&#39;re in Ruby 2.6 here!</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">get_with_default</span><span class=\"p\">({</span><span class=\"ss\">body</span><span class=\"p\">:</span> <span class=\"s1\">&#39;body&#39;</span><span class=\"p\">})</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"o\">=&gt;</span> <span class=\"o\">[</span><span class=\"s2\">&#34;home&#34;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;body&#39;</span><span class=\"p\">,</span> <span class=\"p\">{}</span><span class=\"o\">]</span>\n</span></span></code></pre></div><p>There is a reason for this, but the behaviour is not intuitive. Since the first argument has a default, we don&rsquo;t need to pass it, so when Ruby 2.6 sees a hash it automatically parses the hash as keyword arguments.</p>\n<p>In the Ruby blog post about separating positional and keyword arguments, they suggest a workaround one might think is clever but produces unexpected results as well.</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># Still Ruby 2.6 here</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">get</span><span class=\"p\">({},</span> <span class=\"o\">**</span><span class=\"p\">{})</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"o\">=&gt;</span> <span class=\"ss\">expected</span><span class=\"p\">:</span> <span class=\"o\">[</span><span class=\"p\">{},</span> <span class=\"p\">{}</span><span class=\"o\">]</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"o\">=&gt;</span> <span class=\"ss\">actual</span><span class=\"p\">:</span> <span class=\"o\">[</span><span class=\"s1\">&#39;home&#39;</span><span class=\"p\">,</span> <span class=\"p\">{}</span><span class=\"o\">]</span>\n</span></span></code></pre></div><p>The <code>**{}</code> here is telling Ruby, &ldquo;I&rsquo;m passing you a hash and I&rsquo;d like you to treat it as keyword arguments.&rdquo; However, Ruby just ignores it because the parser sees the first hash and uses that as the kwargs!</p>\n<p>To quote the Ruby post you need to call <code>get({}, {})</code> to get this to work, &ldquo;which is very weird.&rdquo;</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># Still Ruby 2.6 here</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">get</span><span class=\"p\">({},</span> <span class=\"p\">{})</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"o\">=&gt;</span> <span class=\"ss\">expected</span><span class=\"p\">:</span> <span class=\"o\">[</span><span class=\"p\">{},</span> <span class=\"p\">{}</span><span class=\"o\">]</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"o\">=&gt;</span> <span class=\"ss\">actual</span><span class=\"p\">:</span> <span class=\"o\">[</span><span class=\"p\">{},</span> <span class=\"p\">{}</span><span class=\"o\">]</span>\n</span></span></code></pre></div><h2 id=\"enter-ruby-3\">Enter Ruby 3</h2>\n<p>And finally! Here we are at Ruby 3 where you can&rsquo;t mix hashes with kwargs&hellip;err, wait..but you can still mix positional arguments with kwargs!</p>\n<h1 id=\"summing-up\">Summing Up</h1>\n<p>Ruby method signatures can be kinda funky, especially when they&rsquo;re peppered with the history of the language itself.</p>\n<p>My take here is that we should always write the most human-intelligible code possible. If you have a simple method call where the arguments are straightforward, positional arguments are fine.</p>\n<p>However, it helps to name things, so go with keyword arguments all the way. Mixing the two can get a bit messy.</p>\n",
        "date_published": "2024-01-10T00:00:00+00:00",
        "url": "https://enumerator.dev/weird-method-signatures-in-ruby-with-keyword-arguments/",
        "tags": ["weird","ruby","coding-style"]
      },
      {
        "id": "https://enumerator.dev/two-tools-for-diagnosing-slow-endpoints-in-rails/",
        "title": "Two Tools for Diagnosing Slow Endpoints in Rails",
        "content_html": "<h2 id=\"intro\">Intro</h2>\n<p>In general, I see two types of slow endpoints when I am doing performance work: endpoints that have bad code causing a slow response, and endpoints that have a bad query causing a slow response. This post will focus on endpoints that have bad code.</p>\n<p>Slow endpoints can be identified using an application performance monitor like NewRelic. These endpoints usually either have <a href=\"https://en.wikipedia.org/wiki/N%2B1_redundancy\">N + 1 queries</a>, or they spend lots of time in Ruby. You’ll see them in NewRelic, but if you want to hit an endpoint in real-time with production data, see the tip below about Rack MiniProfiler.</p>\n<h3 id=\"newrelic\">NewRelic</h3>\n<p>The transactions monitor is a good place to start. Pick a broad time range (7 days) and look at the “Transaction Traces” that New Relic has captured. If a transaction trace here includes a long query or lots of queries to the DB, it is likely a good transaction to look into.</p>\n<p>There will likely also be some obvious problem queries in the top “Most Time Consuming” transactions. Click through each transaction here and take a look at the transaction traces that NewRelic captured.</p>\n<p>The example below has two N + 1 problems! First you see that we hit Memcached 62 times, then we hit the relational database 47 times! Eeep! Looks like this is a good endpoint to work on.</p>\n<p><img\n    src=\"/images/two-tools-for-diagnosing-slow-endpoints-in-rails_hu_f6415f2018d4cd4e.webp\"\n    srcset=\"/images/two-tools-for-diagnosing-slow-endpoints-in-rails_hu_6721129506a4d72b.webp 576w, /images/two-tools-for-diagnosing-slow-endpoints-in-rails_hu_7a514320b2d268d8.webp 864w, /images/two-tools-for-diagnosing-slow-endpoints-in-rails_hu_f6415f2018d4cd4e.webp 978w\" sizes=\"(max-width: 36rem) 100vw, 36rem\"\n    width=\"978\"\n    height=\"367\"\n    loading=\"lazy\"\n    decoding=\"async\" alt=\"alt text\"></p>\n<p>“Most Time Consuming” is not a bad thing. If we have a really fast endpoint that is hit tens of thousands of time per minute, it is not really a problem. But if a relatively busy endpoint has a slow average response time, it likely is a problem!</p>\n<h3 id=\"rack-miniprofiler\">Rack MiniProfiler</h3>\n<p>Development and staging data can differ wildly from production data, which makes query performance differ wildly between the environments.</p>\n<p>Running Rack MiniProfiler in production gives you a real-time stack trace of live production data! Check out <a href=\"https://github.com/MiniProfiler/rack-mini-profiler#access-control-in-non-development-environments\">the Rack MiniProfiler docs on how to run it in a production environment</a></p>\n<p>I like to be able to selectively turn Rack MiniProfiler on and off, so I usually set it up so that you have to log in as an admin user and then you have to have turned it on for your session by adding <code>?rmp=on</code> to the first request.</p>\n<p>Once Rack MiniProfiler is turned on, you can hit one of the problem endpoints that you see in NewRelic and get more detailed information on what is slowing that request down.</p>\n<h3 id=\"4-possible-ways-to-resolve-slow-endpoints\">4 Possible Ways to Resolve Slow Endpoints</h3>\n<p>This is a non-exhaustive list of possible solutions.</p>\n<ul>\n<li>Find an N + 1? Solve it! You’ll see these in either NewRelic or in Rack Mini Profiler. Solving an N + 1 can mean either eager-loading data using <a href=\"https://devdocs.io/rails~5.2/activerecord/querymethods#method-i-includes\"><code>includes</code></a>, or loading the necessary data in a separate query. It’s usually best to start with using <code>includes</code>, and if causes performance issues, try using separate queries.</li>\n<li>Add or improve caching\n<ul>\n<li>Can the data being queried be cached, or can you use Russian Doll Caching to cache view partials?</li>\n<li>Can you improve the cache usage by selecting multiple records from the cache rather than doing N + 1 queries to the cache? <a href=\"https://devdocs.io/rails~5.2/activesupport/cache/store#method-i-fetch_multi\">Check out the docs on <code>select_multi</code></a> to see how we might resolve the 62 queries to the cache in the example above.</li>\n</ul>\n</li>\n<li>Here&rsquo;s an odd one that you&rsquo;ll find in older applications: Do you even need to display this data? Or do you to display this data with the resolution you are showing? Sometimes older pages slow down because we are trying to show a count of all data from the beginning of time!</li>\n</ul>\n<p>Remember, performance work can take a few passes to get it right. Try one strategy at a time, deploy, and monitor until your response time is back to an acceptable level.</p>\n<p>I&rsquo;d love to hear your favourite strategies for tackling slow endpoints.</p>\n",
        "date_published": "2021-03-29T12:00:00+00:00",
        "url": "https://enumerator.dev/two-tools-for-diagnosing-slow-endpoints-in-rails/",
        "tags": ["performance","ruby","rails"]
      }
  ]
}
