<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://maximomussini.com</id>
    <title>Máximo Mussini</title>
    <updated>2025-01-03T20:01:13.485Z</updated>
    <generator>https://github.com/jpmonette/feed</generator>
    <link rel="alternate" href="https://maximomussini.com"/>
    <subtitle>Thoughts about development and product design.</subtitle>
    <logo>https://maximomussini.comdata:image/svg+xml,%3csvg%20viewBox='0%200%20260%20260'%20fill='none'%20xmlns='http://www.w3.org/2000/svg'%3e%3ccircle%20cx='130'%20cy='130'%20r='130'%20fill='%230284C7'/%3e%3cpath%20d='M56%20193h20.053c8.34%200%2011.357-3.887%2012.067-13.217l4.081-61.42c.71-9.135.178-21.574.178-21.574h.355s3.726%2013.8%206.92%2021.574l20.941%2050.924h18.81l20.94-50.924c3.195-7.774%206.921-21.38%206.921-21.38h.355s-.532%2012.245.178%2021.38l4.259%2061.42c.709%209.33%203.549%2013.217%2011.889%2013.217H204v-21.575h-5.501c-2.485%200-3.727-1.555-3.904-4.276L186.432%2055h-24.135l-25.909%2065.696c-3.016%207.969-6.211%2018.465-6.211%2018.465h-.354s-3.195-10.496-6.211-18.465L97.702%2055H73.569l-8.163%20112.149c-.177%202.721-1.42%204.276-3.904%204.276H56V193z'%20fill='%23fff'/%3e%3c/svg%3e</logo>
    <icon>https://maximomussini.com/favicon.ico</icon>
    <rights>Copyright © 2025 Máximo Mussini</rights>
    <entry>
        <title type="html"><![CDATA[A Rubyist's Guide to Vite.js]]></title>
        <id>https://maximomussini.com/posts/a-rubyist-guide-to-vite-js</id>
        <link href="https://maximomussini.com/posts/a-rubyist-guide-to-vite-js"/>
        <updated>2021-08-19T19:48:00.000Z</updated>
        <summary type="html"><![CDATA[Vite.js brings the joy back to frontend tooling! Learn how to use it in Ruby projects.]]></summary>
        <content type="html"><![CDATA[
<p>One of the reasons <a href="https://www.ruby-lang.org/" target="_blank" rel="nofollow noopener noreferrer">Ruby</a> is so enjoyable is that we can fire up a console and quickly try things out and iterate on ideas—the development experience is interactive.</p>
<p><a href="https://vitejs.dev/" target="_blank" rel="nofollow noopener noreferrer">Vite.js</a> is a build tool that can provide a similar feedback loop when doing web development, but this time the changes we make in our app are reflected <em>instantly</em> in our browser.</p>
<p>An instant connection with our creations is <em>incredibly</em> valuable—whether we are using one of the latest frontend frameworks, or just standard JS and CSS <span role="img" aria-label="grinning face with big eyes">😃</span></p>
<blockquote>
<p>If you would like to play first and read later, jump to <a href="#getting-started">Getting Started</a>.</p>
</blockquote>
<h2 id="why-is-vite-js-so-fast" class="heading"><a href="#why-is-vite-js-so-fast" class="heading-anchor" aria-label="Permalink for Why is Vite.js so fast? ⚡️" tabindex="-1"></a>Why is Vite.js so fast? <span role="img" aria-label="high voltage">⚡</span>️</h2>
<p>During development, instead of <a href="https://vitejs.dev/guide/why.html#slow-server-start" target="_blank" rel="nofollow noopener noreferrer">bundling the entire application</a> it leverages native <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import" target="_blank" rel="nofollow noopener noreferrer">ESM imports</a>, which are <a href="https://caniuse.com/es6-module" target="_blank" rel="nofollow noopener noreferrer">supported</a> by all modern browsers.</p>
<p>Browsers will request files imported in ESM scripts as needed, which can then be transformed and served on demand by the Vite.js web server. Any code that is not imported in the current page will not be processed nor served.</p>
<p>Because it doesn't need to bundle everything, the server starts really fast even on large applications, and changes are reflected instantly thanks to <a href="https://vitejs.dev/guide/api-hmr.html" target="_blank" rel="nofollow noopener noreferrer">hot module replacement</a> which will push updates to the browser using websockets.</p>
<blockquote>
<p>As an optimization, Vite.js will pre-bundle large dependencies to reduce the amount of requests that the browser must make to the web server.</p>
</blockquote>
<h2 id="what-about-production" class="heading"><a href="#what-about-production" class="heading-anchor" aria-label="Permalink for What about production?" tabindex="-1"></a>What about production?</h2>
<p>To ensure optimal loading performance in production, Vite.js provides a build command to <a href="https://rollupjs.org/guide/en/" target="_blank" rel="nofollow noopener noreferrer">bundle our code</a>, which provides many performance optimizations out of the box, with features such as asset-fingerprinting and tree-shaking.</p>
<p>As a result, Vite.js provides a great balance. Smooth and enjoyable experience during development. Best performance practices in production.</p>
<h2 id="covering-the-basics" class="heading"><a href="#covering-the-basics" class="heading-anchor" aria-label="Permalink for Covering the basics 📖" tabindex="-1"></a>Covering the basics <span role="img" aria-label="open book">📖</span></h2>
<p>Vite.js enhances ESM imports to support various features that are typically seen in bundler-based setups, such as importing images or JSON files, or injecting styles.</p>
<div class="language-js" data-lang="js"><pre class="language-js"><code><span class="token keyword">import</span> logoUrl <span class="token keyword">from</span> <span class="token string">'./logo.svg'</span> <span class="token comment">// a URL to reference the icon</span>

<span class="token keyword">import</span> packageInfo <span class="token keyword">from</span> <span class="token string">'./package.json'</span> <span class="token comment">// a parsed JSON object</span>

<span class="token keyword">import</span> <span class="token punctuation">{</span> debounce <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'lodash-es'</span> <span class="token comment">// npm dependency</span></code></pre></div>
<h3 id="configuration-and-plugins" class="heading"><a href="#configuration-and-plugins" class="heading-anchor" aria-label="Permalink for Configuration and Plugins 🛠" tabindex="-1"></a>Configuration and Plugins 🛠</h3>
<p>Configuration in Vite.js revolves around a <code>vite.config.ts</code> file, usually placed at the root of the project, with autocompletion support thanks to TypeScript.</p>
<p>Vite.js is designed for extensibility, and <a href="https://vite-rollup-plugins.patak.dev/" target="_blank" rel="nofollow noopener noreferrer">compatible</a> with many <a href="https://rollupjs.org/guide/en/" target="_blank" rel="nofollow noopener noreferrer">rollup.js</a> plugins. Because of the conventions in place, plugins are easy to install and easy to use.</p>
<p>The <a href="https://vitejs.dev/guide/api-plugin.html" target="_blank" rel="nofollow noopener noreferrer">Plugin API</a> is well documented, and enables the creation of <a href="https://github.com/ElMassimo/vite-plugin-stimulus-hmr" target="_blank" rel="nofollow noopener noreferrer">new plugins</a>.</p>
<div class="language-ts" data-lang="ts"><pre class="line-highlight"><br><br><br><br><br><div class="highlighted">&nbsp;</div><br><br></pre><pre class="language-ts"><code><span class="token keyword">import</span> <span class="token punctuation">{</span> defineConfig <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'vite'</span>
<span class="token keyword">import</span> EnvironmentPlugin <span class="token keyword">from</span> <span class="token string">'vite-plugin-environment'</span>

<span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token function">defineConfig</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  plugins<span class="token operator">:</span> <span class="token punctuation">[</span>
    <span class="token function">EnvironmentPlugin</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'API_KEY'</span><span class="token punctuation">,</span> <span class="token string">'RACK_ENV'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div>
<p class="code caption"><small><code>vite.config.ts</code></small></p>
<h3 id="styles" class="heading"><a href="#styles" class="heading-anchor" aria-label="Permalink for Styles 🎨" tabindex="-1"></a>Styles <span role="img" aria-label="artist palette">🎨</span></h3>
<p>Importing CSS files will inject their content via a <code>&#x3C;style></code> tag with HMR support. Changes are reflected <em>instantly</em> in the browser <em>without</em> a full page reload, making it more enjoyable to iterate on a design.</p>
<div class="language-js" data-lang="js"><pre class="language-js"><code><span class="token keyword">import</span> <span class="token string">'./styles.scss'</span> <span class="token comment">// inject styles in the page</span>
<span class="token keyword">import</span> classes <span class="token keyword">from</span> <span class="token string">'./theme.module.css'</span> <span class="token comment">// CSS Modules</span></code></pre></div>
<p>PostCSS is supported out of the box. If we prefer a CSS preprocessor like <a href="https://sass-lang.com/" target="_blank" rel="nofollow noopener noreferrer">Sass</a> all we need to do is add the relevant package and use the appropriate file extensions.</p>
<div class="language-sh" data-lang="sh"><pre class="language-sh"><code><span class="token function">npm</span> <span class="token function">install</span> <span class="token parameter variable">-D</span> sass</code></pre></div>
<hr>
<p>Now that we have a sense of the role of imports and plugins in Vite.js, let's take a look and see how we can leverage all this goodness in a Ruby web app.</p>
<blockquote>
<p>By using Vite.js we can leverage tools in the Node.js ecosystem—such as Sass, PostCSS and Autoprefixer—without the need for Ruby integrations.</p>
</blockquote>
<h2 id="using-it-in-ruby" class="heading"><a href="#using-it-in-ruby" class="heading-anchor" aria-label="Permalink for Using it in Ruby" tabindex="-1"></a>Using it in Ruby</h2>
<p><a href="https://github.com/ElMassimo/vite_ruby" target="_blank" rel="nofollow noopener noreferrer">Vite Ruby</a> is a library that provides Vite.js integration for Ruby applications, with first-party support for frameworks such as <a href="https://vite-ruby.netlify.app/guide/rails.html" target="_blank" rel="nofollow noopener noreferrer">Rails</a> and <a href="https://jekyll-vite.netlify.app/" target="_blank" rel="nofollow noopener noreferrer">Jekyll</a>.</p>
<p>It uses conventions similar to those in <a href="https://github.com/rails/webpacker" target="_blank" rel="nofollow noopener noreferrer">webpacker</a> to <a href="https://vite-ruby.netlify.app/guide/development.html#entrypoints-%E2%A4%B5%EF%B8%8F" target="_blank" rel="nofollow noopener noreferrer">infer the entrypoints</a> of our application, and provides <a href="https://vite-ruby.netlify.app/guide/development.html#tag-helpers-%F0%9F%8F%B7" target="_blank" rel="nofollow noopener noreferrer">tag helpers</a> to render script and style tags that reference these entrypoints which will be processed by Vite.js.</p>
<p><picture><source media="(-webkit-min-device-pixel-ratio: 1.5)" type="image/avif" srcset="/assets/a-rubyist-guide-to-vite-js.785fde5d.avif 420w, /assets/a-rubyist-guide-to-vite-js.90411345.avif 720w"><source media="(-webkit-min-device-pixel-ratio: 1.5)" type="image/webp" srcset="/assets/a-rubyist-guide-to-vite-js.90c17612.webp 420w, /assets/a-rubyist-guide-to-vite-js.ae2d7fae.webp 720w"><source media="(-webkit-min-device-pixel-ratio: 1.5)" srcset="/assets/a-rubyist-guide-to-vite-js.d109e3c6.jpeg 420w, /assets/a-rubyist-guide-to-vite-js.bfde3191.jpeg 720w"><source type="image/avif" srcset="/assets/a-rubyist-guide-to-vite-js.bb6a8cdd.avif 720w"><source type="image/webp" srcset="/assets/a-rubyist-guide-to-vite-js.261a31b0.webp 720w"><img srcset="/assets/a-rubyist-guide-to-vite-js.1320b44c.jpeg 720w" loading="lazy" src="/assets/a-rubyist-guide-to-vite-js.1320b44c.jpeg" class="img" alt="Vite Ruby"></picture></p>
<blockquote>
<p>The following sections use Rails, but aside from different tag helper names, the concepts are the same for other frameworks such as <a href="https://vite-ruby.netlify.app/guide/hanami.html" target="_blank" rel="nofollow noopener noreferrer">Hanami</a> and <a href="https://vite-ruby.netlify.app/guide/padrino.html" target="_blank" rel="nofollow noopener noreferrer">Padrino</a>.</p>
<p>See the <a href="https://vite-ruby.netlify.app/guide/" target="_blank" rel="nofollow noopener noreferrer">installation guide</a> for more information.</p>
</blockquote>
<h3 id="getting-started" class="heading"><a href="#getting-started" class="heading-anchor" aria-label="Permalink for Getting started" tabindex="-1"></a>Getting started</h3>
<p>To get started let's add Vite Ruby to our <code>Gemfile</code> and run <code>bundle install</code>.</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code>gem <span class="token string-literal"><span class="token string">'vite_rails'</span></span></code></pre></div>
<p>Once the gem is installed we can run <code>bundle exec vite install</code> to <a href="https://vite-ruby.netlify.app/guide/#setup-%F0%9F%93%A6" target="_blank" rel="nofollow noopener noreferrer">get a basic setup</a>,
including configuration files and installing npm packages.</p>
<p>The <a href="https://github.com/ElMassimo/vite_ruby/tree/main/vite-plugin-ruby" target="_blank" rel="nofollow noopener noreferrer"><code>vite-plugin-ruby</code></a> package will take care of detecting
<a href="https://vite-ruby.netlify.app/guide/development.html#entrypoints-%E2%A4%B5%EF%B8%8F" target="_blank" rel="nofollow noopener noreferrer">entrypoints</a> in our app, and configure Vite.js based on the Ruby app structure.</p>
<div class="language-ts" data-lang="ts"><pre class="line-highlight"><br><div class="highlighted">&nbsp;</div><br><br><br><div class="highlighted">&nbsp;</div><br><br></pre><pre class="language-ts"><code><span class="token keyword">import</span> <span class="token punctuation">{</span> defineConfig <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'vite'</span>
<span class="token keyword">import</span> RubyPlugin <span class="token keyword">from</span> <span class="token string">'vite-plugin-ruby'</span>

<span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token function">defineConfig</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  plugins<span class="token operator">:</span> <span class="token punctuation">[</span>
    <span class="token function">RubyPlugin</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div>
<p class="code caption"><small><code>vite.config.ts</code></small></p>
<p>The <code>install</code> command will also add the following tag helpers to the app layout:</p>
<div class="language-erb" data-lang="erb"><pre class="language-erb"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>html</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>head</span><span class="token punctuation">></span></span>
    ...
    <span class="token erb language-erb"><span class="token delimiter punctuation">&lt;%=</span><span class="token ruby language-ruby"> vite_client_tag </span><span class="token delimiter punctuation">%></span></span>
    <span class="token erb language-erb"><span class="token delimiter punctuation">&lt;%=</span><span class="token ruby language-ruby"> vite_javascript_tag <span class="token string-literal"><span class="token string">'application'</span></span> </span><span class="token delimiter punctuation">%></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>head</span><span class="token punctuation">></span></span></code></pre></div>
<p class="code caption"><small><code>app/views/layouts/application.html.erb</code></small></p>
<p><code>vite_client_tag</code> renders a script referencing the Vite.js client, which
connects over websockets to the Vite.js development server to receive updates
as we make changes to the imported files.</p>
<p><code>vite_javascript_tag</code> renders a script referencing a file in the entrypoints directory, which is served by Vite.js during development. The sample file:</p>
<div class="language-js" data-lang="js"><pre class="language-js"><code>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Vite ⚡️ Rails'</span><span class="token punctuation">)</span></code></pre></div>
<p class="code caption"><small><code>app/frontend/entrypoints/application.js</code></small></p>
<h3 id="playing-with-vite-js" class="heading"><a href="#playing-with-vite-js" class="heading-anchor" aria-label="Permalink for Playing with Vite.js" tabindex="-1"></a>Playing with Vite.js</h3>
<p>Now we can restart our Ruby web server to load Vite Ruby, start the Vite.js
development server by running <code>bin/vite dev</code>, and visit any page.</p>
<p>If we inspect the browser console, we should see the following output:</p>
<div class="language-text" data-lang=""><pre class="language-text"><code>[vite] connecting...
Vite ⚡️ Rails
[vite] connected.</code></pre></div>
<p>Let's experiment with styles by creating a new stylesheet:</p>
<div class="language-css" data-lang="css"><pre class="language-css"><code><span class="token selector">html, body</span> <span class="token punctuation">{</span>
  <span class="token property">background-color</span><span class="token punctuation">:</span> #CC0000<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre></div>
<p class="code caption"><small><code>app/frontend/styles/background.css</code></small></p>
<p>We can import it directly from our JS entrypoint to see a colored background:</p>
<div class="language-js" data-lang="js"><pre class="language-js"><code><span class="token keyword">import</span> <span class="token string">'~/styles/background.css'</span>

console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Vite ⚡️ Rails'</span><span class="token punctuation">)</span></code></pre></div>
<p class="code caption"><small><code>app/frontend/entrypoints/application.js</code></small></p>
<p>Now, let's see how Vite.js performs updates by modifiying our styles and saving:</p>
<div class="language-css" data-lang="css"><pre class="language-css"><code><span class="token selector">html, body</span> <span class="token punctuation">{</span>
  <span class="token property">background-color</span><span class="token punctuation">:</span> #FFE02E<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre></div>
<p>Damn, that's fast! <span role="img" aria-label="high voltage">⚡</span>️</p>
<p>If we check the console logs, we can see more output from the Vite.js client:</p>
<div class="language-text" data-lang=""><pre class="language-text"><code>[vite] hot updated: /styles/background.css</code></pre></div>
<p>The <a href="https://vitejs.dev/guide/api-hmr.html" target="_blank" rel="nofollow noopener noreferrer">HMR</a> mechanism is at the heart of the development experience in Vite.js <span role="img" aria-label="red heart">❤️</span></p>
<h3 id="an-example-with-stimulus" class="heading"><a href="#an-example-with-stimulus" class="heading-anchor" aria-label="Permalink for An example with Stimulus" tabindex="-1"></a>An example with Stimulus</h3>
<p>To register all of our Stimulus controllers, we can leverage <a href="https://vitejs.dev/guide/features.html#glob-import" target="_blank" rel="nofollow noopener noreferrer">glob imports</a>:</p>
<div class="language-ts" data-lang="ts"><pre class="language-ts"><code><span class="token keyword">const</span> controllers <span class="token operator">=</span> <span class="token keyword">import</span><span class="token punctuation">.</span>meta<span class="token punctuation">.</span><span class="token function">glob</span><span class="token punctuation">(</span><span class="token string">'./**/*_controller.js'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> eager<span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div>
<p>Vite.js will statically replace the <a href="https://vitejs.dev/guide/features.html#glob-import" target="_blank" rel="nofollow noopener noreferrer"><code>glob</code></a> call with an object containing matching files:</p>
<div class="language-js" data-lang="js"><pre class="language-js"><code><span class="token punctuation">{</span>
  <span class="token string-property property">'./image/reveal_controller.js'</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token keyword">default</span><span class="token operator">:</span> RevealController <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span></code></pre></div>
<p>We can use <a href="https://github.com/ElMassimo/stimulus-vite-helpers" target="_blank" rel="nofollow noopener noreferrer">a helper</a> to register the controllers in our
Stimulus application, which will infer the controller names from the file names
by following the usual conventions.</p>
<div class="language-ts" data-lang="ts"><pre class="language-ts"><code><span class="token keyword">import</span> <span class="token punctuation">{</span> Application <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'stimulus'</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> registerControllers <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'stimulus-vite-helpers'</span>

<span class="token keyword">const</span> app <span class="token operator">=</span> Application<span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span>

<span class="token keyword">const</span> controllers <span class="token operator">=</span> <span class="token keyword">import</span><span class="token punctuation">.</span>meta<span class="token punctuation">.</span><span class="token function">glob</span><span class="token punctuation">(</span><span class="token string">'./**/*_controller.js'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> eager<span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token function">registerControllers</span><span class="token punctuation">(</span>app<span class="token punctuation">,</span> controllers<span class="token punctuation">)</span></code></pre></div>
<p class="code caption"><small><code>app/frontend/controllers/index.js</code></small></p>
<div class="language-diff" data-lang="diff"><pre class="language-diff"><code><span class="token unchanged"><span class="token prefix unchanged"> </span><span class="token line"> import '~/styles/background.css'
</span></span><span class="token inserted-sign inserted"><span class="token prefix inserted">+</span><span class="token line"> import '~/controllers'
</span></span>
<span class="token unchanged"><span class="token prefix unchanged"> </span><span class="token line"> console.log('Vite ⚡️ Rails')</span></span></code></pre></div>
<p class="code caption"><small><code>app/frontend/entrypoints/application.js</code></small></p>
<p>We can get the benefit of HMR by adding the <a href="https://github.com/ElMassimo/vite-plugin-stimulus-hmr" target="_blank" rel="nofollow noopener noreferrer"><code>vite-plugin-stimulus-hmr</code></a> plugin to our <code>vite.config.ts</code> file.</p>
<div class="language-diff" data-lang="diff"><pre class="language-diff"><code><span class="token unchanged"><span class="token prefix unchanged"> </span><span class="token line"> import { defineConfig } from 'vite'
</span><span class="token prefix unchanged"> </span><span class="token line"> import RubyPlugin from 'vite-plugin-ruby'
</span></span><span class="token inserted-sign inserted"><span class="token prefix inserted">+</span><span class="token line"> import StimulusHMR from 'vite-plugin-stimulus-hmr'
</span></span>
<span class="token unchanged"><span class="token prefix unchanged"> </span><span class="token line"> export default defineConfig({
</span><span class="token prefix unchanged"> </span><span class="token line">   plugins: [
</span><span class="token prefix unchanged"> </span><span class="token line">     RubyPlugin(),
</span></span><span class="token inserted-sign inserted"><span class="token prefix inserted">+</span><span class="token line">     StimulusHMR(),
</span></span><span class="token unchanged"><span class="token prefix unchanged"> </span><span class="token line">   ],
</span><span class="token prefix unchanged"> </span><span class="token line"> })</span></span></code></pre></div>
<p>Now changes to our Stimulus controllers will be <a href="https://github.com/ElMassimo/vite-plugin-stimulus-hmr#demo-" target="_blank" rel="nofollow noopener noreferrer">pushed instantly to the browser</a>, allowing us to iterate as needed without reloading the page.</p>
<h3 id="sidecar-assets" class="heading"><a href="#sidecar-assets" class="heading-anchor" aria-label="Permalink for Sidecar assets" tabindex="-1"></a>Sidecar assets</h3>
<p>When using a library such as <a href="https://viewcomponent.org/" target="_blank" rel="nofollow noopener noreferrer"><code>ViewComponent</code></a>, it can be
convenient to group JS and CSS files within each component folder—sometimes called <em><a href="https://viewcomponent.org/guide/javascript_and_css.html" target="_blank" rel="nofollow noopener noreferrer">sidecar assets</a></em>.</p>
<p>Although there are a <a href="https://vite-ruby.netlify.app/guide/advanced.html#bundling-files-outside-sourcecodedir" target="_blank" rel="nofollow noopener noreferrer">few options</a> to achieve this, the simplest
option is to import all JS files as we saw earlier with Stimulus controllers.</p>
<div class="language-js" data-lang="js"><pre class="language-js"><code><span class="token keyword">import</span><span class="token punctuation">.</span>meta<span class="token punctuation">.</span><span class="token function">glob</span><span class="token punctuation">(</span><span class="token string">'../components/**/*_component.js'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">eager</span><span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div>
<p class="code caption"><small><code>app/frontend/components.js</code></small></p>
<div class="language-diff" data-lang="diff"><pre class="language-diff"><code><span class="token unchanged"><span class="token prefix unchanged"> </span><span class="token line"> import '~/styles/background.css'
</span></span><span class="token inserted-sign inserted"><span class="token prefix inserted">+</span><span class="token line"> import '~/components'
</span></span>
<span class="token unchanged"><span class="token prefix unchanged"> </span><span class="token line"> console.log('Vite ⚡️ Rails')</span></span></code></pre></div>
<p class="code caption"><small><code>app/frontend/entrypoints/application.js</code></small></p>
<p>Files matching the glob will be imported, as well as any of their dependencies, such as CSS files. For example, if we wanted to encapsulate a component using the Shadow DOM:</p>
<div class="language-css" data-lang="css"><pre class="language-css"><code><span class="token selector">:host</span> <span class="token punctuation">{</span>
  <span class="token property">display</span><span class="token punctuation">:</span> flex<span class="token punctuation">;</span>
  <span class="token property">flex-direction</span><span class="token punctuation">:</span> column<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.commenter</span> <span class="token punctuation">{</span>
  <span class="token property">display</span><span class="token punctuation">:</span> flex<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre></div>
<p class="code caption"><small><code>app/components/comment_component.css</code></small></p>
<div class="language-js" data-lang="js"><pre class="language-js"><code><span class="token keyword">import</span> styles <span class="token keyword">from</span> <span class="token string">'./comment_component.css?inline'</span>

<span class="token keyword">class</span> <span class="token class-name">Comment</span> <span class="token keyword">extends</span> <span class="token class-name">HTMLElement</span> <span class="token punctuation">{</span>
  <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">super</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token keyword">const</span> shadow <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">attachShadow</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">mode</span><span class="token operator">:</span> <span class="token string">'open'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
    shadow<span class="token punctuation">.</span>innerHTML <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">
      &lt;style>
        </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>styles<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">
      &lt;/style>
      &lt;div class="commenter">
        &lt;slot name="author">&lt;/slot>
      &lt;/div>
      &lt;div class="body">
        &lt;slot name="body">&lt;/slot>
      &lt;/div>
    </span><span class="token template-punctuation string">`</span></span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
customElements<span class="token punctuation">.</span><span class="token function">define</span><span class="token punctuation">(</span><span class="token string">'my-comment'</span><span class="token punctuation">,</span> Comment<span class="token punctuation">)</span></code></pre></div>
<p class="code caption"><small><code>app/components/comment_component.js</code></small></p>
<h3 id="using-a-framework" class="heading"><a href="#using-a-framework" class="heading-anchor" aria-label="Permalink for Using a framework" tabindex="-1"></a>Using a framework</h3>
<p>Unlike other bundlers, adding a framework in Vite.js requires very little config. There are official plugins for <a href="https://v3.vuejs.org/" target="_blank" rel="nofollow noopener noreferrer">Vue</a>, <a href="https://reactjs.org/" target="_blank" rel="nofollow noopener noreferrer">React</a>, and <a href="https://svelte.dev/" target="_blank" rel="nofollow noopener noreferrer">Svelte</a>,
which can be used to import <code>.vue</code>, <code>.jsx</code>, and <code>.svelte</code> files. For example, adding Vue support:</p>
<div class="language-diff" data-lang="diff"><pre class="language-diff"><code><span class="token unchanged"><span class="token prefix unchanged"> </span><span class="token line"> import { defineConfig } from 'vite'
</span><span class="token prefix unchanged"> </span><span class="token line"> import RubyPlugin from 'vite-plugin-ruby'
</span></span><span class="token inserted-sign inserted"><span class="token prefix inserted">+</span><span class="token line"> import VuePlugin from '@vitejs/plugin-vue'
</span></span>
<span class="token unchanged"><span class="token prefix unchanged"> </span><span class="token line"> export default defineConfig({
</span><span class="token prefix unchanged"> </span><span class="token line">   plugins: [
</span><span class="token prefix unchanged"> </span><span class="token line">     RubyPlugin(),
</span></span><span class="token inserted-sign inserted"><span class="token prefix inserted">+</span><span class="token line">     VuePlugin(),
</span></span><span class="token unchanged"><span class="token prefix unchanged"> </span><span class="token line">   ],
</span><span class="token prefix unchanged"> </span><span class="token line"> })</span></span></code></pre></div>
<p>We can now import <code>.vue</code> files and mount them as usual:</p>
<div class="language-diff" data-lang="diff"><pre class="language-diff"><code><span class="token unchanged"><span class="token prefix unchanged"> </span><span class="token line"> import '~/styles/background.css'
</span></span><span class="token inserted-sign inserted"><span class="token prefix inserted">+</span><span class="token line"> import { createApp } from 'vue'  
</span><span class="token prefix inserted">+</span><span class="token line"> import App from '~/components/App.vue' 
</span><span class="token prefix inserted">+</span><span class="token line">  
</span><span class="token prefix inserted">+</span><span class="token line"> createApp(App).mount('#app')
</span></span>
<span class="token unchanged"><span class="token prefix unchanged"> </span><span class="token line"> console.log('Vite ⚡️ Rails')</span></span></code></pre></div>
<p>As we saw earlier, Vite.js will detect changes we make in our components and
push updates to the browser, causing Vue to re-render the updated components. To
our delight this whole process happens within milliseconds <span role="img" aria-label="grinning face with big eyes">😃</span></p>
<h3 id="code-splitting" class="heading"><a href="#code-splitting" class="heading-anchor" aria-label="Permalink for Code-splitting" tabindex="-1"></a>Code-splitting</h3>
<p>We can leverage <code>glob</code> and dynamic imports to split our bundle into separate files,
which is useful to defer the load of components until they are needed.</p>
<p>Let's see <a href="https://github.com/ElMassimo/pingcrm-vite" target="_blank" rel="nofollow noopener noreferrer">an example</a> using <a href="https://inertiajs.com/" target="_blank" rel="nofollow noopener noreferrer">Inertia.js</a>:</p>
<div class="language-js" data-lang="js"><pre class="language-js"><code><span class="token keyword">import</span> <span class="token punctuation">{</span> createInertiaApp <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@inertiajs/inertia-vue'</span>

<span class="token keyword">const</span> pages <span class="token operator">=</span> <span class="token keyword">import</span><span class="token punctuation">.</span>meta<span class="token punctuation">.</span><span class="token function">glob</span><span class="token punctuation">(</span><span class="token string">'../Pages/**/*.vue'</span><span class="token punctuation">)</span>

<span class="token function">createInertiaApp</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token keyword">async</span> <span class="token function">resolve</span> <span class="token punctuation">(</span><span class="token parameter">name</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token keyword">await</span> pages<span class="token punctuation">[</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">../Pages/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">.vue</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">]</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token operator">...</span></code></pre></div>
<p>When using <a href="https://vitejs.dev/guide/features.html#glob-import" target="_blank" rel="nofollow noopener noreferrer"><code>glob</code></a> without <code>eager: true</code>, each value in the
object is a function that returns a dynamic import for the corresponding module.</p>
<div class="language-js" data-lang="js"><pre class="language-js"><code><span class="token punctuation">{</span>
  <span class="token string-property property">'../Pages/Auth/Login.vue'</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token keyword">import</span><span class="token punctuation">(</span><span class="token string">'/vite-dev/Pages/Auth/Login.vue'</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span></code></pre></div>
<p>When building for production, each of the dynamic imports is bundled separately:</p>
<div class="language-js" data-lang="js"><pre class="language-js"><code><span class="token punctuation">{</span>
  <span class="token string-property property">'../Pages/Auth/Login.vue'</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token keyword">import</span><span class="token punctuation">(</span><span class="token string">'./Login.3ee8f1b8.js'</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span></code></pre></div>
<hr>
<h3 id="additional-resources" class="heading"><a href="#additional-resources" class="heading-anchor" aria-label="Permalink for Additional Resources 📖" tabindex="-1"></a>Additional Resources <span role="img" aria-label="open book">📖</span></h3>
<p>In this post we have barely scratched the surface of what's possible with Vite.js,
but hopefully we saw enough to understand the basics and start using it.</p>
<p>The following links should be helpful if you would like to learn more, are looking for a starter template, or need a working example to use as a configuration reference.</p>
<h4 id="docs" class="heading"><a href="#docs" class="heading-anchor" aria-label="Permalink for Docs" tabindex="-1"></a>Docs</h4>
<ul>
<li><a href="https://vite-ruby.netlify.app/overview.html" target="_blank" rel="nofollow noopener noreferrer">Vite.js and Vite Ruby Overview</a></li>
<li><a href="https://vitejs.dev/" target="_blank" rel="nofollow noopener noreferrer">Vite.js</a></li>
<li><a href="https://vite-ruby.netlify.app" target="_blank" rel="nofollow noopener noreferrer">Vite Ruby</a></li>
</ul>
<h4 id="plugins" class="heading"><a href="#plugins" class="heading-anchor" aria-label="Permalink for Plugins" tabindex="-1"></a>Plugins</h4>
<ul>
<li><a href="https://vite-ruby.netlify.app/guide/plugins.html" target="_blank" rel="nofollow noopener noreferrer">Recommended Plugins for Ruby apps</a></li>
<li><a href="https://vite-rollup-plugins.patak.dev/" target="_blank" rel="nofollow noopener noreferrer">Rollup Plugins</a></li>
<li><a href="https://github.com/vitejs/awesome-vite" target="_blank" rel="nofollow noopener noreferrer">Awesome Vite</a></li>
</ul>
<h4 id="example-apps" class="heading"><a href="#example-apps" class="heading-anchor" aria-label="Permalink for Example Apps" tabindex="-1"></a>Example Apps</h4>
<ul>
<li><a href="https://github.com/ElMassimo/vite_ruby/tree/main/examples/rails" target="_blank" rel="nofollow noopener noreferrer">Rails + Vite + React + Windi CSS</a></li>
<li><a href="https://github.com/ElMassimo/pingcrm-vite" target="_blank" rel="nofollow noopener noreferrer">Rails + Vite + Inertia.js + Vue2</a></li>
<li><a href="https://github.com/ElMassimo/vite-plugin-stimulus-hmr/tree/main/example" target="_blank" rel="nofollow noopener noreferrer">Stimulus + Vite</a></li>
</ul>
<h4 id="starter-templates" class="heading"><a href="#starter-templates" class="heading-anchor" aria-label="Permalink for Starter Templates" tabindex="-1"></a>Starter Templates</h4>
<ul>
<li><a href="https://railsbytes.com/public/templates/XE5sO3" target="_blank" rel="nofollow noopener noreferrer">One-line Vite Ruby installer for Rails</a></li>
<li><a href="https://github.com/justalever/kickoff_vite_rails" target="_blank" rel="nofollow noopener noreferrer">Rails + Vite Ruby + Windi CSS + Stimulus</a></li>
<li><a href="https://github.com/ElMassimo/jumpstart-vite" target="_blank" rel="nofollow noopener noreferrer">Jumpstart Rails + Vite + Stimulus</a></li>
</ul>
<br>
<p>Until next time <span role="img" aria-label="waving hand (skin tone 3)">👋🏼</span></p>]]></content>
        <author>
            <name>Máximo Mussini</name>
            <uri>https://maximomussini.com</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Vue Components as Custom Elements]]></title>
        <id>https://maximomussini.com/posts/vue-custom-elements</id>
        <link href="https://maximomussini.com/posts/vue-custom-elements"/>
        <updated>2021-08-10T19:32:00.000Z</updated>
        <summary type="html"><![CDATA[Now it's easier than ever to create native custom elements with Vue.]]></summary>
        <content type="html"><![CDATA[<p>Now that <a href="https://blog.vuejs.org/posts/vue-3.2.html" target="_blank" rel="nofollow noopener noreferrer">Vue 3.2 has been released</a>, creating native <a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements" target="_blank" rel="nofollow noopener noreferrer">custom elements</a>
from Vue components is easier than ever thanks to <a href="https://v3.vuejs.org/guide/web-components.html#definecustomelement" target="_blank" rel="nofollow noopener noreferrer"><code>defineCustomElement</code></a>.</p>
<p>In this post we will learn how to use this new API to turn a Vue component into a web component, how to package it as a library, and how to use it in plain
HTML.</p>
<p>The complete source code for this example is <a href="https://github.com/ElMassimo/vue-custom-element-example" target="_blank" rel="nofollow noopener noreferrer">available on GitHub</a>.</p>
<figure class="example-wrapper"><iframe src="https://vue-custom-element-example.netlify.app/embed.html" height="224" frameborder="0" class="example" scrolling="no" loading="lazy"></iframe></figure>
<h2 id="creating-a-custom-element" class="heading"><a href="#creating-a-custom-element" class="heading-anchor" aria-label="Permalink for Creating a Custom Element" tabindex="-1"></a>Creating a Custom Element</h2>
<p>The first step is to create a Vue component that we would like to use as a
custom element. In this example, we will build a button that can toggle a dark
theme on a website.</p>
<div class="language-vue" data-lang="vue"><pre class="language-vue"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span> <span class="token attr-name">setup</span> <span class="token attr-name">lang</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>ts<span class="token punctuation">'</span></span><span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript">
<span class="token keyword">import</span> <span class="token punctuation">{</span> useDark<span class="token punctuation">,</span> useToggle <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@vueuse/core'</span>

<span class="token keyword">const</span> isDark <span class="token operator">=</span> <span class="token function">useDark</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token keyword">const</span> toggleDark <span class="token operator">=</span> <span class="token function">useToggle</span><span class="token punctuation">(</span>isDark<span class="token punctuation">)</span>
</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>template</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">@click</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>toggleDark()<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">v-if</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>isDark<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>🌚<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">v-else</span><span class="token punctuation">></span></span>🌞<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>template</span><span class="token punctuation">></span></span></code></pre></div>
<p class="code caption"><small><code>DarkModeSwitch.vue</code></small></p>
<h3 id="vue-component-to-custom-element" class="heading"><a href="#vue-component-to-custom-element" class="heading-anchor" aria-label="Permalink for Vue Component to Custom Element" tabindex="-1"></a>Vue Component to Custom Element</h3>
<p>Once we have our Vue component we can use the <code>defineCustomElement</code> API to
create a custom element class that we can register.</p>
<div class="language-typescript" data-lang="typescript"><pre class="language-typescript"><code><span class="token keyword">import</span> <span class="token punctuation">{</span> defineCustomElement <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'vue'</span>
<span class="token keyword">import</span> VueDarkModeSwitch <span class="token keyword">from</span> <span class="token string">'./DarkModeSwitch.vue'</span>

<span class="token comment">// Vue generates a new HTML element class from the component definition.</span>
<span class="token keyword">const</span> DarkModeSwitch <span class="token operator">=</span> <span class="token function">defineCustomElement</span><span class="token punctuation">(</span>VueDarkModeSwitch<span class="token punctuation">)</span>

<span class="token comment">// Register the custom element so that it can be used as &lt;dark-mode-switch>.</span>
customElements<span class="token punctuation">.</span><span class="token function">define</span><span class="token punctuation">(</span><span class="token string">'dark-mode-switch'</span><span class="token punctuation">,</span> DarkModeSwitch<span class="token punctuation">)</span></code></pre></div>
<p class="code caption"><small><code>dark.ts</code></small></p>
<h2 id="styling-the-shadow-dom" class="heading"><a href="#styling-the-shadow-dom" class="heading-anchor" aria-label="Permalink for Styling the Shadow DOM 🎨" tabindex="-1"></a>Styling the Shadow DOM <span role="img" aria-label="artist palette">🎨</span></h2>
<p>Custom elements defined using the Vue API always use a <a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM" target="_blank" rel="nofollow noopener noreferrer">shadow DOM</a>, so
they are isolated from the parent document and any global styles in the app.</p>
<p>Styles for a custom element must be injected in its <a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM" target="_blank" rel="nofollow noopener noreferrer">shadow root</a>,
which is why <code>defineCustomElement</code> can receive a <code>styles</code> option with CSS rules to inject.</p>
<div class="language-typescript" data-lang="typescript"><pre class="language-typescript"><code><span class="token keyword">const</span> styles <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">'button { font-size: 24px; ... }'</span><span class="token punctuation">]</span>
<span class="token function">defineCustomElement</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token operator">...</span>VueDarkModeSwitch<span class="token punctuation">,</span> styles <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div>
<h3 id="importing-components-in-custom-element-mode" class="heading"><a href="#importing-components-in-custom-element-mode" class="heading-anchor" aria-label="Permalink for Importing Components in Custom Element Mode" tabindex="-1"></a>Importing Components in Custom Element Mode</h3>
<p>When importing a single-file component in <em><a href="https://v3.vuejs.org/guide/web-components.html#sfc-as-custo-element" target="_blank" rel="nofollow noopener noreferrer">custom element mode</a></em>, any <code>&#x3C;style></code>
tags in the component will be inlined during compilation as an array of CSS strings, allowing <code>defineCustomElement</code> to inject the styles in the shadow root.</p>
<blockquote>
<p>Files ending in <a href="https://github.com/ElMassimo/vue-custom-element-example/blob/main/package/index.ts#L2" target="_blank" rel="nofollow noopener noreferrer"><code>.ce.vue</code></a> will be imported in <em>custom element mode</em> by default.</p>
</blockquote>
<p>The <code>customElement</code> option can be used to specify which files should be imported in <em>custom element mode</em> (also available in <code>vue-loader</code>).</p>
<div class="language-typescript" data-lang="typescript"><pre class="language-typescript"><code>  plugins<span class="token operator">:</span> <span class="token punctuation">[</span>
    <span class="token comment">// Example: Import all Vue files in custom element mode.</span>
    <span class="token function">vue</span><span class="token punctuation">(</span><span class="token punctuation">{</span> customElement<span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token comment">// default: /\.ce\.vue$/</span>
  <span class="token punctuation">]</span><span class="token punctuation">,</span></code></pre></div>
<p class="code caption"><small><code>vite.config.ts</code></small></p>
<h3 id="caveats-of-custom-element-mode" class="heading"><a href="#caveats-of-custom-element-mode" class="heading-anchor" aria-label="Permalink for Caveats of Custom Element Mode 🚨" tabindex="-1"></a>Caveats of Custom Element Mode <span role="img" aria-label="police car light">🚨</span></h3>
<blockquote>
<p><em><strong>Warning</strong></em>: Only <code>&#x3C;style></code> tags <em>in</em> the single-file component will be inlined. Styles defined in nested Vue components won't be injected!</p>
</blockquote>
<p>A possible workaround is to define and use all nested components as custom elements, but that prevents using Vue-only features such as scoped slots.</p>
<p>Please let me know if this changes in the future, and I'll update this note.</p>
<h3 id="adding-styles-to-the-single-file-component" class="heading"><a href="#adding-styles-to-the-single-file-component" class="heading-anchor" aria-label="Permalink for Adding styles to the single-file component" tabindex="-1"></a>Adding styles to the single-file component</h3>
<p>Now that styles in the component will be injected in the custom element, it's time to define how our toggle button should look.</p>
<div class="language-vue" data-lang="vue"><pre class="language-vue"><code><span class="token comment">&lt;!-- Doesn't need to be scoped because it will be inside the Shadow DOM --></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>style</span><span class="token punctuation">></span></span><span class="token style"><span class="token language-css">
<span class="token comment">/* Shadow Root: Properties can be overriden externally for customization */</span>
<span class="token selector">:host</span> <span class="token punctuation">{</span>
  <span class="token property">--color</span><span class="token punctuation">:</span> #fbbf24<span class="token punctuation">;</span>
  <span class="token property">--bg-normal</span><span class="token punctuation">:</span> #fAfAf9<span class="token punctuation">;</span>
  <span class="token property">--bg-active</span><span class="token punctuation">:</span> #f5f5f4<span class="token punctuation">;</span>
  <span class="token property">--font-size</span><span class="token punctuation">:</span> 24px<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">button</span> <span class="token punctuation">{</span>
  <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--bg-normal<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">border</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span>
  <span class="token property">border-radius</span><span class="token punctuation">:</span> .5rem<span class="token punctuation">;</span>
  <span class="token property">color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">cursor</span><span class="token punctuation">:</span> pointer<span class="token punctuation">;</span>
  <span class="token property">display</span><span class="token punctuation">:</span> flex<span class="token punctuation">;</span>
  <span class="token property">font-size</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--font-size<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">overflow</span><span class="token punctuation">:</span> hidden<span class="token punctuation">;</span>
  <span class="token property">padding</span><span class="token punctuation">:</span> 0.4em<span class="token punctuation">;</span>
  <span class="token property">transition</span><span class="token punctuation">:</span> background-color 0.3s ease<span class="token punctuation">,</span>
    color 0.3s <span class="token function">cubic-bezier</span><span class="token punctuation">(</span>0.64<span class="token punctuation">,</span> 0<span class="token punctuation">,</span> 0.78<span class="token punctuation">,</span> 0<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">button:hover,
button:focus</span> <span class="token punctuation">{</span>
  <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--bg-active<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">outline</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">span</span> <span class="token punctuation">{</span>
  <span class="token property">width</span><span class="token punctuation">:</span> 1.3em<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>style</span><span class="token punctuation">></span></span></code></pre></div>
<p class="code caption"><small><code>DarkModeSwitch.vue</code></small></p>
<h2 id="using-a-custom-element" class="heading"><a href="#using-a-custom-element" class="heading-anchor" aria-label="Permalink for Using a Custom Element" tabindex="-1"></a>Using a Custom Element</h2>
<p>Once our custom element is <a href="#vue-component-to-custom-element">registered</a>, we can use it <a href="https://github.com/ElMassimo/vue-custom-element-example/blob/main/playground/index.html#L18" target="_blank" rel="nofollow noopener noreferrer">directly in HTML</a> as we would with any of the built-in tags.</p>
<div class="language-html" data-lang="html"><pre class="language-html"><code><span class="token doctype"><span class="token punctuation">&lt;!</span><span class="token doctype-tag">DOCTYPE</span> <span class="token name">html</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>html</span> <span class="token attr-name">lang</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>en<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>head</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>module<span class="token punctuation">"</span></span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>./dark.ts<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>head</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>body</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dark-mode-switch</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dark-mode-switch</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>body</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>html</span><span class="token punctuation">></span></span></code></pre></div>
<h3 id="using-web-components-in-vue" class="heading"><a href="#using-web-components-in-vue" class="heading-anchor" aria-label="Permalink for Using Web Components in Vue" tabindex="-1"></a>Using Web Components in Vue</h3>
<p>If we want to use these web components <a href="https://github.com/ElMassimo/vue-custom-element-example/blob/main/playground/App.vue#L3" target="_blank" rel="nofollow noopener noreferrer">within Vue components</a>,
the only difference is that we need to hint the compiler to skip component resolution and treat them as <a href="https://v3.vuejs.org/guide/web-components.html#skipping-component-resolution" target="_blank" rel="nofollow noopener noreferrer">native custom elements</a>.</p>
<div class="language-typescript" data-lang="typescript"><pre class="language-typescript"><code>  plugins<span class="token operator">:</span> <span class="token punctuation">[</span>
    <span class="token function">vue</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
      template<span class="token operator">:</span> <span class="token punctuation">{</span>
        compilerOptions<span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token comment">// Example: Treat all tags with a dash as custom elements.</span>
          <span class="token comment">// i.e. dark-mode-switch</span>
          <span class="token function-variable function">isCustomElement</span><span class="token operator">:</span> tag <span class="token operator">=></span> tag<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token string">'-'</span><span class="token punctuation">)</span></code></pre></div>
<p class="code caption"><small><code>vite.config.ts</code></small></p>
<h2 id="packaging-as-a-library" class="heading"><a href="#packaging-as-a-library" class="heading-anchor" aria-label="Permalink for Packaging as a Library 📦" tabindex="-1"></a>Packaging as a Library <span role="img" aria-label="package">📦</span></h2>
<p>Vite.js provides a <a href="https://vitejs.dev/guide/build.html#library-mode" target="_blank" rel="nofollow noopener noreferrer">library mode</a> which is a great way to bundle custom elements.</p>
<div class="language-typescript" data-lang="typescript"><pre class="language-typescript"><code>  build<span class="token operator">:</span> <span class="token punctuation">{</span>
    lib<span class="token operator">:</span> <span class="token punctuation">{</span>
      entry<span class="token operator">:</span> <span class="token function">resolvePath</span><span class="token punctuation">(</span><span class="token string">'index.ts'</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
      name<span class="token operator">:</span> <span class="token string">'DarkModeSwitch'</span><span class="token punctuation">,</span>
      <span class="token function-variable function">fileName</span><span class="token operator">:</span> format <span class="token operator">=></span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">index.</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>format<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">.js</span><span class="token template-punctuation string">`</span></span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span></code></pre></div>
<p class="code caption"><small><code>package/vite.config.ts</code></small></p>
<p>But, before we package our custom elements we need to make a few decisions:</p>
<ul>
<li>Should custom elements be eagerly registered?</li>
<li>Should <code>vue</code> and other dependencies be bundled with the package?</li>
</ul>
<h3 id="lazy-registration-of-custom-elements" class="heading"><a href="#lazy-registration-of-custom-elements" class="heading-anchor" aria-label="Permalink for Lazy Registration of Custom Elements" tabindex="-1"></a>Lazy Registration of Custom Elements</h3>
<p>Usually, it's more flexible to export the custom element class, and provide a <a href="https://github.com/ElMassimo/vue-custom-element-example/blob/main/playground/main.ts#L5" target="_blank" rel="nofollow noopener noreferrer">convenience method</a> to register custom elements with default tag names.</p>
<div class="language-typescript" data-lang="typescript"><pre class="language-typescript"><code><span class="token keyword">import</span> <span class="token punctuation">{</span> defineCustomElement <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'vue'</span>
<span class="token keyword">import</span> VueDarkModeSwitch <span class="token keyword">from</span> <span class="token string">'./DarkModeSwitch.vue'</span>

<span class="token comment">// Vue generates a new HTML element class from the component definition.</span>
<span class="token keyword">export</span> <span class="token keyword">const</span> DarkModeSwitch <span class="token operator">=</span> <span class="token function">defineCustomElement</span><span class="token punctuation">(</span>VueDarkModeSwitch<span class="token punctuation">)</span>

<span class="token comment">// Optional: Provide an easy way to register the custom element.</span>
<span class="token keyword">export</span> <span class="token keyword">function</span> <span class="token function">register</span> <span class="token punctuation">(</span>tagName <span class="token operator">=</span> <span class="token string">'dark-mode-switch'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  customElements<span class="token punctuation">.</span><span class="token function">define</span><span class="token punctuation">(</span>tagName<span class="token punctuation">,</span> DarkModeSwitch<span class="token punctuation">)</span>
<span class="token punctuation">}</span></code></pre></div>
<p class="code caption"><small><code>package/index.ts</code></small></p>
<p>That way we enable users to <a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements#high-level_view" target="_blank" rel="nofollow noopener noreferrer">define the custom element</a> using a different name.</p>
<div class="language-typescript" data-lang="typescript"><pre class="language-typescript"><code><span class="token keyword">import</span> <span class="token punctuation">{</span> DarkModeSwitch <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@mussi/vue-custom-element-example'</span>

customElements<span class="token punctuation">.</span><span class="token function">define</span><span class="token punctuation">(</span><span class="token string">'toggle-dark-mode'</span><span class="token punctuation">,</span> DarkModeSwitch<span class="token punctuation">)</span></code></pre></div>
<p class="code caption"><small><code>example registration</code></small></p>
<h3 id="externalizing-dependencies" class="heading"><a href="#externalizing-dependencies" class="heading-anchor" aria-label="Permalink for Externalizing dependencies" tabindex="-1"></a>Externalizing dependencies</h3>
<p>If we plan to use our component in applications that are already using Vue, then
it's better to externalize it to prevent duplicates and ensure they use the same version.</p>
<p>In Vite.js this can be configured with <a href="https://rollupjs.org/guide/en/#external" target="_blank" rel="nofollow noopener noreferrer"><code>build.rollupOptions.external</code></a>.</p>
<div class="language-typescript" data-lang="typescript"><pre class="language-typescript"><code>  build<span class="token operator">:</span> <span class="token punctuation">{</span>
    rollupOptions<span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token comment">// Externalize deps that shouldn't be bundled into the library.</span>
      external<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'vue'</span><span class="token punctuation">,</span> <span class="token string">'@vueuse/core'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span></code></pre></div>
<p class="code caption"><small><code>package/vite.config.ts</code></small></p>
<p>If custom elements will be used in non-Vue apps it might be suitable to bundle the dependencies instead, so that users don't have to provide them.</p>
<h2 id="farewell" class="heading"><a href="#farewell" class="heading-anchor" aria-label="Permalink for Farewell 👋🏼" tabindex="-1"></a>Farewell <span role="img" aria-label="waving hand (skin tone 3)">👋🏼</span></h2>
<p>Vue loves the open web, and the addition of <code>defineCustomElement</code> has made it easier than ever to create web components while enjoying an excellent DX.</p>
<p>It will be interesting to see future developments in this area, like being
able to replace Vue with something lighter such as <a href="https://github.com/vuejs/petite-vue" target="_blank" rel="nofollow noopener noreferrer"><code>petite-vue</code></a> for cases where the full runtime is not required.</p>
<figure class="example-wrapper"><iframe src="https://vue-custom-element-example.netlify.app/embed.html" height="224" frameborder="0" class="example" scrolling="no" loading="lazy"></iframe></figure>
<p>The complete source code for this example is <a href="https://github.com/ElMassimo/vue-custom-element-example" target="_blank" rel="nofollow noopener noreferrer">available on GitHub</a>.</p>]]></content>
        <author>
            <name>Máximo Mussini</name>
            <uri>https://maximomussini.com</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Debugging Ruby Libraries]]></title>
        <id>https://maximomussini.com/posts/debugging-ruby-libraries</id>
        <link href="https://maximomussini.com/posts/debugging-ruby-libraries"/>
        <updated>2021-03-27T16:32:00.000Z</updated>
        <summary type="html"><![CDATA[Opening gems is one of the best ways to understand how they work.]]></summary>
        <content type="html"><![CDATA[<small><em>This guide was extracted from the <a href="https://vite-ruby.netlify.app/guide/debugging.html" target="_blank" rel="nofollow noopener noreferrer">Debugging section</a> I wrote for <a href="https://github.com/ElMassimo/vite_ruby" target="_blank" rel="nofollow noopener noreferrer">Vite Ruby</a>.</em></small>
<p>In this post I will cover a few ways to debug code inside Ruby gems in your application.</p>
<p>I'll use <a href="https://github.com/rails/rails/tree/main/actionview" target="_blank" rel="nofollow noopener noreferrer"><code>actionview</code></a> in <a href="https://github.com/rails/rails" target="_blank" rel="nofollow noopener noreferrer">Rails</a> as an example, but you can apply these techniques to debug <strong>any gem</strong>.</p>
<h2 id="debugging-in-ruby" class="heading"><a href="#debugging-in-ruby" class="heading-anchor" aria-label="Permalink for Debugging in Ruby 🐞" tabindex="-1"></a>Debugging in Ruby <span role="img" aria-label="lady beetle">🐞</span></h2>
<p>There are two main debugging styles in Ruby:</p>
<ul>
<li>
<p><strong><a href="https://tenderlovemaking.com/2016/02/05/i-am-a-puts-debuggerer.html" target="_blank" rel="nofollow noopener noreferrer">Puts Debugging</a></strong> consists in adding <code>puts</code> statements in the target code,
execute the script or application, and use the output to understand what's
going on.</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code><span class="token keyword">def</span> <span class="token method-definition"><span class="token function">javascript_include_tag</span></span><span class="token punctuation">(</span><span class="token operator">*</span>sources<span class="token punctuation">)</span>
  puts <span class="token string-literal"><span class="token string">"javascript_include_tag(</span><span class="token interpolation"><span class="token delimiter punctuation">#{</span><span class="token content">sources<span class="token punctuation">.</span>inspect</span><span class="token delimiter punctuation">}</span></span><span class="token string">)"</span></span></code></pre></div>
</li>
<li>
<p><strong><a href="https://github.com/deivid-rodriguez/pry-byebug" target="_blank" rel="nofollow noopener noreferrer">Interactive Debugging</a></strong> enables pausing the program at a
specific instruction, examining the current state in a REPL, and doing step-by-step execution.</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code><span class="token keyword">def</span> <span class="token method-definition"><span class="token function">javascript_include_tag</span></span><span class="token punctuation">(</span><span class="token operator">*</span>sources<span class="token punctuation">)</span>
  binding<span class="token punctuation">.</span>pry <span class="token comment"># or binding.irb or byebug</span></code></pre></div>
</li>
</ul>
<p>One of many advantages of <em>interactive debugging</em> is that it becomes possible to
easily navigate into a library's internals by using <a href="https://github.com/deivid-rodriguez/pry-byebug#step-by-step-debugging" target="_blank" rel="nofollow noopener noreferrer"><code>step</code></a> or <a href="https://github.com/deivid-rodriguez/pry-byebug#breakpoints" target="_blank" rel="nofollow noopener noreferrer"><code>break</code></a>.</p>
<p>To debug a library using <em>puts debugging</em>, you'll need to do things differently.</p>
<h2 id="opening-gems-⛏" class="heading"><a href="#opening-gems-⛏" class="heading-anchor" aria-label="Permalink for Opening Gems 💎⛏" tabindex="-1"></a>Opening Gems <span role="img" aria-label="gem stone">💎</span>⛏</h2>
<p>You can run <a href="https://bundler.io/bundle_open.html" target="_blank" rel="nofollow noopener noreferrer"><code>bundle open</code></a> to open a gem in your favorite text editor.</p>
<blockquote>
<p>The <a href="https://bundler.io/bundle_open.html" target="_blank" rel="nofollow noopener noreferrer"><code>EDITOR</code></a> environment variable will be used to infer the preferred text editor. I like using Sublime Text or Visual Studio Code to navigate the file tree.</p>
</blockquote>
<p>For example, running <code>bundle open actionview</code> will open the version of the <a href="https://github.com/rails/rails/tree/main/actionview" target="_blank" rel="nofollow noopener noreferrer"><code>actionview</code></a> gem specified in the nearest <code>Gemfile.lock</code>.</p>
<h3 id="editing-in-place" class="heading"><a href="#editing-in-place" class="heading-anchor" aria-label="Permalink for Editing In-Place ✍️" tabindex="-1"></a>Editing In-Place <span role="img" aria-label="writing hand">✍️</span></h3>
<p>In contrast with compiled languages—where libraries are distributed as binaries—in Ruby most libraries are distributed as plain <code>.rb</code> files which are <em>human-readable</em>.</p>
<p>And <em>human-writable</em>! You can modify the code in a library, <strong>restart your app</strong>, and your changes will be picked up! <span role="img" aria-label="star-struck">🤩</span></p>
<p>This is extremely useful when tracking down bugs—you can add <code>puts</code> or breakpoints as needed, or even modify the behavior of the library.</p>
<picture><img srcset="/assets/binding-pry-tg-EORv9.svg" src="/assets/binding-pry-tg-EORv9.svg" class="img wide captioned" loading="lazy" alt="Debugging with Pry"></picture><p class="code caption"><small><code><em><a href="https://github.com/deivid-rodriguez/pry-byebug" target="_blank" rel="nofollow noopener noreferrer">Interactive Debugging</a> by hardcoding breakpoints inside <a href="https://github.com/rails/rails/tree/main/actionview" target="_blank" rel="nofollow noopener noreferrer"><code>actionview</code></a></em></code></small></p>
<blockquote>
<p>Run <code>gem pristine :library:</code> once you are done to <strong>undo any changes</strong>.
Otherwise, you risk relying on behavior that is <strong>local and unversioned</strong> <span role="img" aria-label="weary cat">🙀</span></p>
</blockquote>
<h2 id="using-a-local-library" class="heading"><a href="#using-a-local-library" class="heading-anchor" aria-label="Permalink for Using a Local Library 🔗" tabindex="-1"></a>Using a Local Library <span role="img" aria-label="link">🔗</span></h2>
<p>When you need to make extensive changes a nicer flow is to <strong>clone</strong> the library, and then <em>point to your local copy</em>.</p>
<p>For example, to <a href="https://github.com/rails/rails/pull/41697" target="_blank" rel="nofollow noopener noreferrer">fix a bug in <code>actionview</code></a> you would clone the
<a href="https://github.com/rails/rails" target="_blank" rel="nofollow noopener noreferrer">Rails</a> repo, open it in your editor to make changes, and then update the
<code>Gemfile</code> in your project to specify the dependency using <a href="https://bundler.io/man/gemfile.5.html#PATH" target="_blank" rel="nofollow noopener noreferrer"><code>path</code></a>.</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code><span class="token comment"># Assuming rails was cloned in the same parent directory</span>
gem <span class="token string-literal"><span class="token string">'actionview'</span></span><span class="token punctuation">,</span> <span class="token symbol">path</span><span class="token operator">:</span> <span class="token string-literal"><span class="token string">'../rails/actionview'</span></span></code></pre></div>
<blockquote>
<p>If a dependency is specified using a Git repository, prefer <a href="https://ryanbigg.com/2013/08/bundler-local-paths" target="_blank" rel="nofollow noopener noreferrer">local paths in Bundler</a>.</p>
</blockquote>
<p>Just as in the previous section, it's important to <strong>restart the program</strong> you intend to debug after making changes.</p>
<h3 id="why-is-it-necessary-to-restart-the-application" class="heading"><a href="#why-is-it-necessary-to-restart-the-application" class="heading-anchor" aria-label="Permalink for Why is it necessary to restart the application? 🤔" tabindex="-1"></a>Why is it necessary to restart the application? <span role="img" aria-label="thinking face">🤔</span></h3>
<p>Most Ruby programs use <code>require</code> to load a library into memory, and will use that cached version during their entire running time.</p>
<p>Restarting the program, such as a script or a web development server, ensures that any changes you have made to the library are loaded!</p>
<h2 id="additional-resources" class="heading"><a href="#additional-resources" class="heading-anchor" aria-label="Permalink for Additional Resources 📖" tabindex="-1"></a>Additional Resources <span role="img" aria-label="open book">📖</span></h2>
<p>I hope this summary has been useful! A similar <a href="/posts/debugging-javascript-libraries">guide for JavaScript is available</a> <span role="img" aria-label="grinning face with big eyes">😃</span></p>
<p>Please refer to the following documentation for more information:</p>
<ul>
<li><a href="https://github.com/deivid-rodriguez/pry-byebug" target="_blank" rel="nofollow noopener noreferrer"><code>pry-byebug</code></a>: Step-by-step debugging in Pry</li>
<li><a href="https://github.com/gsamokovarov/break" target="_blank" rel="nofollow noopener noreferrer"><code>break</code></a>: A debugger written in Ruby that integrates with IRB and Pry</li>
<li><a href="https://www.schneems.com/2016/01/25/ruby-debugging-magic-cheat-sheet.html" target="_blank" rel="nofollow noopener noreferrer"><em>Debugging Cheat Sheet</em></a>: Nice resource if you prefer <a href="https://tenderlovemaking.com/2016/02/05/i-am-a-puts-debuggerer.html" target="_blank" rel="nofollow noopener noreferrer">puts debugging</a></li>
</ul>]]></content>
        <author>
            <name>Máximo Mussini</name>
            <uri>https://maximomussini.com</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Debugging Node.js Libraries]]></title>
        <id>https://maximomussini.com/posts/debugging-javascript-libraries</id>
        <link href="https://maximomussini.com/posts/debugging-javascript-libraries"/>
        <updated>2021-03-23T21:20:00.000Z</updated>
        <summary type="html"><![CDATA[Tips and techniques to debug library-related issues in Node.js applications.]]></summary>
        <content type="html"><![CDATA[


<small><em>This guide was extracted from the <a href="https://vite-ruby.netlify.app/guide/debugging.html" target="_blank" rel="nofollow noopener noreferrer">Debugging section</a> I wrote for <a href="https://github.com/ElMassimo/vite_ruby" target="_blank" rel="nofollow noopener noreferrer">Vite Ruby</a>.</em></small>
<p>In this post I'm going to cover a few techniques that you can use when debugging library-related issues in your Node.js applications.</p>
<p>I'll be using <a href="https://github.com/vitejs/vite" target="_blank" rel="nofollow noopener noreferrer">Vite.js</a> as an example, as it provides an opportunity to cover some specifics related to debugging TypeScript packages and mono repos, but you can apply these techniques to debug <strong>any library</strong>.</p>
<h2 id="debug-output" class="heading"><a href="#debug-output" class="heading-anchor" aria-label="Permalink for Debug Output 📜" tabindex="-1"></a>Debug Output <span role="img" aria-label="scroll">📜</span></h2>
<p>It's common for <a href="https://nodejs.org/" target="_blank" rel="nofollow noopener noreferrer">node.js</a> packages to use the <a href="https://github.com/visionmedia/debug" target="_blank" rel="nofollow noopener noreferrer"><code>debug</code></a> library to log information about their configuration, or operations they perform.</p>
<p>To enable logging for these libraries, set the <code>DEBUG</code> environment variable:</p>
<ul>
<li><code>DEBUG=*</code>  Enable all debug output</li>
<li><code>DEBUG=vite:*</code>  Enable output for Vite.js core plugins</li>
<li><code>DEBUG=vite-plugin-ruby:*</code>  Enable output for a specific plugin</li>
</ul>
<p><picture><img srcset="/assets/debug-output-OvYdZXGD.svg" src="/assets/debug-output-OvYdZXGD.svg" class="img" loading="lazy" alt="Debug Output"></picture></p>
<h2 id="using-a-debugger" class="heading"><a href="#using-a-debugger" class="heading-anchor" aria-label="Permalink for Using a Debugger 🎯" tabindex="-1"></a>Using a Debugger <span role="img" aria-label="direct hit">🎯</span></h2>
<p>Sometimes debug output is not enough to figure out what's the problem. Fortunately, there are <a href="https://nodejs.org/en/docs/guides/debugging-getting-started/#inspector-clients" target="_blank" rel="nofollow noopener noreferrer">many ways</a> to start a <a href="https://nodejs.org/en/docs/guides/debugging-getting-started/#command-line-options" target="_blank" rel="nofollow noopener noreferrer">debugging session</a>.</p>
<p>Using <a href="https://nodejs.org/en/docs/guides/debugging-getting-started/#command-line-options" target="_blank" rel="nofollow noopener noreferrer"><code>node --inspect-brk</code></a> will break execution until a debugger client is attached. You must provide a JS executable as an argument, for example:</p>
<ul>
<li><code>node --inspect-brk "$(npm bin)/vite"</code></li>
<li><code>node --inspect-brk $(yarn bin vite)</code></li>
</ul>
<blockquote>
<p>Add an <code>inspect</code> shortcut in your <a href="https://docs.npmjs.com/misc/scripts/" target="_blank" rel="nofollow noopener noreferrer"><code>scripts</code></a> if you need to debug often.</p>
</blockquote>
<p>I like to use the <a href="https://chrome.google.com/webstore/detail/nodejs-v8-inspector-manag/gnhhdgbaldcilmgcpfddgdbkhjohddkj" target="_blank" rel="nofollow noopener noreferrer">Node Inspector Manager</a> extension, which will automatically attach the browser's DevTools to the node process.</p>
<picture><source media="(-webkit-min-device-pixel-ratio: 1.5)" type="image/avif" srcset="/assets/devtools.ca3241d2.avif 420w, /assets/devtools.36d55f46.avif 720w"><source media="(-webkit-min-device-pixel-ratio: 1.5)" type="image/webp" srcset="/assets/devtools.9ad7410f.webp 420w, /assets/devtools.3d9529a6.webp 720w"><source media="(-webkit-min-device-pixel-ratio: 1.5)" srcset="/assets/devtools.9f4ad34a.png 420w, /assets/devtools.800e9033.png 720w"><source type="image/avif" srcset="/assets/devtools.cc47546a.avif 720w"><source type="image/webp" srcset="/assets/devtools.e2ef353d.webp 720w"><img srcset="/assets/devtools.6050afff.png 720w" loading="lazy" src="/assets/devtools.6050afff.png" class="img narrow" alt="Debugging with Chrome DevTools"></picture>
<p>DevTools provide a great debugging environment, with visual breakpoints, watchers, file navigation, and more. <a href="https://nodejs.org/en/docs/guides/debugging-getting-started/#visual-studio-code-1-10" target="_blank" rel="nofollow noopener noreferrer">Visual Studio Code</a> is another great option.</p>
<blockquote>
<p>It's useful to <a href="https://code.visualstudio.com/docs/nodejs/nodejs-debugging#_additional-configuration" target="_blank" rel="nofollow noopener noreferrer">ignore Node.js internals</a> to avoid stepping into the framework.</p>
</blockquote>
<p><picture><img srcset="/assets/nim-DKTHp8GS.svg" src="/assets/nim-DKTHp8GS.svg" class="img" loading="lazy" alt="Attaching a Client to a Debugger Session"></picture></p>
<h2 id="opening-packages" class="heading"><a href="#opening-packages" class="heading-anchor" aria-label="Permalink for Opening Packages 📖" tabindex="-1"></a>Opening Packages <span role="img" aria-label="open book">📖</span></h2>
<p>In order to learn more and understand which files you should be debugging, you can run
<code>npm edit</code> to open a package in your favorite text editor.</p>
<blockquote>
<p>The <code>EDITOR</code> environment variable will be used to infer the preferred text editor. I like using Sublime Text or Visual Studio Code to navigate the file tree.</p>
</blockquote>
<p>For example, running <code>npm edit vite</code> will open the copy of the <code>vite</code> package that is installed in the <code>node_modules</code> for the current directory.</p>
<p>Unlike the previous sections, this is something you can leverage for client-side packages as well.</p>
<h3 id="editing-in-place" class="heading"><a href="#editing-in-place" class="heading-anchor" aria-label="Permalink for Editing In-Place ✍️" tabindex="-1"></a>Editing In-Place <span role="img" aria-label="writing hand">✍️</span></h3>
<p>Because JavaScript is a dynamic language, you can tweak the code <strong>in-place</strong>, <strong>restart the process</strong>, and your changes will be picked up.</p>
<blockquote>
<p><strong>Disclaimer:</strong> This has many caveats: bugs that only happen in your local, or the opposite, code that only seems to work in your local.</p>
<p><em><a href="#using-a-local-library-">Skip to the next section for a better approach</a></em>.</p>
<p><em>(I use it all the time though, so convenient <span role="img" aria-label="grinning face with sweat">😅</span>)</em></p>
</blockquote>
<p>You can add <code>console.log</code> as needed, or even modify the behavior of the library, which can be useful to track down bugs.</p>
<p>In TypeScript packages (and some JS packages), make sure to edit the transpiled file instead of the sources. This is often <code>dist/index.js</code> but that depends on the library and target environment.</p>
<p>For example, in Vite.js the entrypoint is <code>dist/node/index.js</code>.</p>
<h2 id="using-a-local-library" class="heading"><a href="#using-a-local-library" class="heading-anchor" aria-label="Permalink for Using a Local Library 🔗" tabindex="-1"></a>Using a Local Library <span role="img" aria-label="link">🔗</span></h2>
<p>When fixing a bug or implementing features, a better flow is to <strong>clone</strong> the library, and then <em>point to your local copy</em> by using the <a href="https://docs.npmjs.com/cli/v7/commands/npm-link" target="_blank" rel="nofollow noopener noreferrer"><code>npm link</code></a> or <a href="https://classic.yarnpkg.com/en/docs/cli/link" target="_blank" rel="nofollow noopener noreferrer"><code>yarn link</code></a> commands.</p>
<p>Let's see a step by step example with <code>vite</code>:</p>
<div class="language-bash" data-lang="bash"><pre class="language-bash"><code><span class="token comment"># 1. Clone the repo</span>
<span class="token function">git</span> clone git@github.com:vitejs/vite.git 
<span class="token builtin class-name">cd</span> vite/packages/vite <span class="token comment"># Location of package.json</span>
<span class="token function">pnpm</span> <span class="token function">install</span>

<span class="token comment"># 2. Make the local package available for linking</span>
<span class="token function">npm</span> <span class="token function">link</span> <span class="token comment"># skip if using pnpm</span>

<span class="token comment"># 3. Start compilation in "watch" mode</span>
<span class="token function">pnpm</span> dev</code></pre></div>
<p>In TypeScript or compiled JS libraries, it's important to build the library in order for changes to the source to be reflected in the linked project.</p>
<blockquote>
<p>By convention, libraries define a <code>build</code> script to perform compilation, and a <code>dev</code> script that starts compilation in <code>watch</code> mode—file changes will start a new build.</p>
</blockquote>
<p>Finally, link the library in the project you would like to test the changes:</p>
<div class="language-bash" data-lang="bash"><pre class="language-bash"><code><span class="token comment"># 4a. Link the library by name to use the local copy</span>
<span class="token function">npm</span> <span class="token function">link</span> vite

<span class="token comment"># 4b. If using pnpm, link it by path instead</span>
<span class="token function">pnpm</span> <span class="token function">link</span> <span class="token punctuation">..</span>/vite/packages/vite</code></pre></div>
<p>Just as in the previous section, it's important to <strong>restart the process</strong> you intend to debug after making changes.</p>
<h3 id="why-is-it-necessary-to-restart" class="heading"><a href="#why-is-it-necessary-to-restart" class="heading-anchor" aria-label="Permalink for Why is it necessary to restart? 🤔" tabindex="-1"></a>Why is it necessary to restart? <span role="img" aria-label="thinking face">🤔</span></h3>
<p>Most processes will load the required libraries into memory, and then use these cached versions during their entire running time.</p>
<p>Restarting the relevant process, such as the Vite.js development server, ensures the updated version of the library is loaded.</p>
<h2 id="additional-resources" class="heading"><a href="#additional-resources" class="heading-anchor" aria-label="Permalink for Additional Resources 📖" tabindex="-1"></a>Additional Resources <span role="img" aria-label="open book">📖</span></h2>
<p>I hope this summary has been useful! A similar <a href="/posts/debugging-ruby-libraries">guide for Ruby is available</a> <span role="img" aria-label="grinning face with big eyes">😃</span></p>
<p>Please refer to the following documentation for more information:</p>
<ul>
<li><a href="https://github.com/visionmedia/debug" target="_blank" rel="nofollow noopener noreferrer"><code>debug</code></a>: Conventions and available filters</li>
<li><a href="https://nodejs.org/en/docs/guides/debugging-getting-started/" target="_blank" rel="nofollow noopener noreferrer">Debugging Guide</a> for <a href="https://nodejs.org/" target="_blank" rel="nofollow noopener noreferrer">node.js</a>: CLI flags and inspector clients</li>
</ul>]]></content>
        <author>
            <name>Máximo Mussini</name>
            <uri>https://maximomussini.com</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Practical Applications of the Singleton Class in Ruby]]></title>
        <id>https://maximomussini.com/posts/practical-applications-of-the-singleton-class</id>
        <link href="https://maximomussini.com/posts/practical-applications-of-the-singleton-class"/>
        <updated>2020-12-06T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[A few practical applications of the singleton class that might prove useful in your code.]]></summary>
        <content type="html"><![CDATA[<p>In the <a href="/posts/understanding-the-singleton-class">previous post</a>, we discussed how the <em>singleton class</em> powers class methods in Ruby, and how every object instance has <a href="/posts/understanding-the-singleton-class"><em>its own</em> singleton class</a>.</p>
<p>In this post, we will cover a few practical usages of the <em>singleton class</em> as a way to modify the behavior of a particular object.</p>
<h2 id="adding-methods-and-mixins" class="heading"><a href="#adding-methods-and-mixins" class="heading-anchor" aria-label="Permalink for Adding Methods and Mixins" tabindex="-1"></a>Adding Methods and Mixins</h2>
<p>Since the <em>singleton class</em> of an object is specific to it, we can add methods to it, remove methods, or include modules, all without affecting other instances.</p>
<blockquote>
<p>When calling a method on an object, Ruby will first look into its singleton class to find it, before traversing the rest of the <a href="/posts/understanding-the-singleton-class/#the-metaclass-hierarchy">method chain</a>.</p>
</blockquote>
<h3 id="defining-singleton-methods" class="heading"><a href="#defining-singleton-methods" class="heading-anchor" aria-label="Permalink for Defining Singleton Methods" tabindex="-1"></a>Defining Singleton Methods</h3>
<p>Let's cover a few of the syntaxes we can use to define methods for a specific object.</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code>person <span class="token operator">=</span> <span class="token class-name">Object</span><span class="token punctuation">.</span><span class="token keyword">new</span>

person<span class="token punctuation">.</span>define_singleton_method<span class="token punctuation">(</span><span class="token symbol">:name</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token string-literal"><span class="token string">'Alice'</span></span>
<span class="token punctuation">}</span>

person<span class="token punctuation">.</span>singleton_class<span class="token punctuation">.</span><span class="token keyword">define_method</span><span class="token punctuation">(</span><span class="token symbol">:to_s</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token string-literal"><span class="token string">"</span><span class="token interpolation"><span class="token delimiter punctuation">#{</span><span class="token content"> name </span><span class="token delimiter punctuation">}</span></span><span class="token string"> in </span><span class="token interpolation"><span class="token delimiter punctuation">#{</span><span class="token content"> location </span><span class="token delimiter punctuation">}</span></span><span class="token string">"</span></span>
<span class="token punctuation">}</span>

<span class="token keyword">def</span> <span class="token method-definition"><span class="token class-name">person</span><span class="token punctuation">.</span><span class="token function">location</span></span>
  <span class="token string-literal"><span class="token string">'Wonderland'</span></span>
<span class="token keyword">end</span>

<span class="token keyword">class</span> <span class="token operator">&lt;&lt;</span> person
  <span class="token keyword">def</span> <span class="token method-definition"><span class="token function">inspect</span></span>
    <span class="token string-literal"><span class="token string">"</span><span class="token interpolation"><span class="token delimiter punctuation">#{</span><span class="token content"> to_s </span><span class="token delimiter punctuation">}</span></span><span class="token string">: </span><span class="token interpolation"><span class="token delimiter punctuation">#{</span><span class="token content"> <span class="token keyword">super</span> </span><span class="token delimiter punctuation">}</span></span><span class="token string">"</span></span>
  <span class="token keyword">end</span>
<span class="token keyword">end</span>

person<span class="token punctuation">.</span>inspect <span class="token comment"># => "Alice in Wonderland: #&lt;Object:0x00007fe7b5071238>"</span></code></pre></div>
<p>The last two syntaxes should be familiar, we usually use them inside a class definition with <code>self</code> as the receiver (inside the class definition <code>self</code> is the class object).</p>
<p>These four different ways of defining a method are equivalent, each one is defining a <em><strong>singleton method</strong></em>.</p>
<blockquote>
<p>A <em><strong>singleton method</strong></em> is a method defined in the <em>singleton class</em> of an object.</p>
</blockquote>
<p>As we saw in the <a href="/posts/understanding-the-singleton-class">previous post</a>, class methods are simply <em>singleton methods</em> of a class object, which explains why the same syntaxes can be used with a different receiver: they do <em>the same thing</em>.</p>
<h3 id="adding-mixins-to-the-singleton-class" class="heading"><a href="#adding-mixins-to-the-singleton-class" class="heading-anchor" aria-label="Permalink for Adding Mixins to the Singleton Class" tabindex="-1"></a>Adding Mixins to the Singleton Class</h3>
<p>We are not limited to adding or overriding methods, we can also work with modules.</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code><span class="token keyword">module</span> <span class="token class-name">Greeting</span>
  <span class="token keyword">def</span> <span class="token method-definition"><span class="token function">introduce</span></span>
    <span class="token string-literal"><span class="token string">"Hey, I'm </span><span class="token interpolation"><span class="token delimiter punctuation">#{</span><span class="token content"> name </span><span class="token delimiter punctuation">}</span></span><span class="token string">"</span></span>
  <span class="token keyword">end</span>
<span class="token keyword">end</span>

<span class="token keyword">module</span> <span class="token class-name">NiceGreeting</span>
  <span class="token keyword">def</span> <span class="token method-definition"><span class="token function">introduce</span></span>
    <span class="token string-literal"><span class="token string">"</span><span class="token interpolation"><span class="token delimiter punctuation">#{</span><span class="token content"> <span class="token keyword">super</span> </span><span class="token delimiter punctuation">}</span></span><span class="token string">, nice to meet you!"</span></span>
  <span class="token keyword">end</span>
<span class="token keyword">end</span>

person<span class="token punctuation">.</span><span class="token keyword">extend</span><span class="token punctuation">(</span>Greeting<span class="token punctuation">)</span>
person<span class="token punctuation">.</span>singleton_class<span class="token punctuation">.</span><span class="token keyword">include</span><span class="token punctuation">(</span>NiceGreeting<span class="token punctuation">)</span>

person<span class="token punctuation">.</span>introduce
<span class="token comment"># => "Hey, I'm Alice, nice to meet you!"</span>

person<span class="token punctuation">.</span>singleton_class<span class="token punctuation">.</span>ancestors
<span class="token comment"># => [#&lt;Class:#&lt;Object:...>>, NiceGreeting, Greeting, ...</span></code></pre></div>
<p>The example above illustrates how <a href="/posts/understanding-the-singleton-class/#the-metaclass-hierarchy">module inheritance</a> works when dealing with the <em>singleton class</em>. Using <code>extend</code> is like <em>including</em> a module in the <em>singleton class</em>.</p>
<blockquote>
<p>Calling <code>extend</code> on an object will make the module methods available on <em>that</em> object. In a class definition the object is implicit: <em>the <a href="/posts/understanding-the-singleton-class/#the-metaclass-of-a-class">class object</a>.</em></p>
</blockquote>
<h2 id="practical-applications" class="heading"><a href="#practical-applications" class="heading-anchor" aria-label="Permalink for Practical Applications" tabindex="-1"></a>Practical Applications</h2>
<p>Let's now dive into a few scenarios where all of this flexibility becomes useful.</p>
<h3 id="test-doubles-and-method-stubbing" class="heading"><a href="#test-doubles-and-method-stubbing" class="heading-anchor" aria-label="Permalink for Test Doubles and Method Stubbing" tabindex="-1"></a>Test Doubles and Method Stubbing</h3>
<p>A <em>test double</em> is any object that stands in for a real object during a test. <a href="https://github.com/rspec/rspec-mocks" target="_blank" rel="nofollow noopener noreferrer">Some libraries</a> allow to easily create doubles, and stub some of their methods:</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code>book <span class="token operator">=</span> instance_double<span class="token punctuation">(</span><span class="token string-literal"><span class="token string">'Book'</span></span><span class="token punctuation">,</span> <span class="token symbol">pages</span><span class="token operator">:</span> <span class="token number">236</span><span class="token punctuation">)</span>
book<span class="token punctuation">.</span>pages <span class="token comment"># => 236</span></code></pre></div>
<p>A <em>method stub</em> is an instruction to an object to return a known value in response to a message:</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code>allow<span class="token punctuation">(</span>book<span class="token punctuation">)</span><span class="token punctuation">.</span>to receive<span class="token punctuation">(</span><span class="token symbol">:title</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token string-literal"><span class="token string">'Free Play'</span></span> <span class="token punctuation">}</span>
book<span class="token punctuation">.</span>title <span class="token comment"># => "Free Play"</span></code></pre></div>
<blockquote>
<p>Most libraries implement both of these features by leveraging the <em>singleton class</em>.</p>
</blockquote>
<p>Let's see how we might be able to implement a very simplistic version of <code>double</code>, which returns an object that can respond to the specified methods:</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code><span class="token keyword">def</span> <span class="token method-definition"><span class="token function">double</span></span><span class="token punctuation">(</span>name<span class="token punctuation">,</span> <span class="token operator">**</span>method_stubs<span class="token punctuation">)</span>
  <span class="token class-name">Object</span><span class="token punctuation">.</span><span class="token keyword">new</span><span class="token punctuation">.</span>tap <span class="token keyword">do</span> <span class="token operator">|</span>object<span class="token operator">|</span>
    object<span class="token punctuation">.</span>instance_variable_set<span class="token punctuation">(</span><span class="token string-literal"><span class="token string">'@name'</span></span><span class="token punctuation">,</span> name<span class="token punctuation">)</span>
    method_stubs<span class="token punctuation">.</span><span class="token keyword">each</span> <span class="token keyword">do</span> <span class="token operator">|</span>name<span class="token punctuation">,</span> value<span class="token operator">|</span>
      object<span class="token punctuation">.</span>define_singleton_method<span class="token punctuation">(</span>name<span class="token punctuation">)</span> <span class="token punctuation">{</span> value <span class="token punctuation">}</span>
    <span class="token keyword">end</span>
  <span class="token keyword">end</span>
<span class="token keyword">end</span>

book <span class="token operator">=</span> double<span class="token punctuation">(</span><span class="token string-literal"><span class="token string">'Book'</span></span><span class="token punctuation">,</span> <span class="token symbol">pages</span><span class="token operator">:</span> <span class="token number">236</span><span class="token punctuation">,</span> <span class="token symbol">title</span><span class="token operator">:</span> <span class="token string-literal"><span class="token string">'Free Play'</span></span><span class="token punctuation">)</span>
book<span class="token punctuation">.</span>pages <span class="token comment"># => 236</span>
book<span class="token punctuation">.</span>title <span class="token comment"># => "Free Play"</span></code></pre></div>
<p>By using <a href="https://ruby-doc.org/core-2.7.2/Object.html#method-i-define_singleton_method" target="_blank" rel="nofollow noopener noreferrer"><code>define_singleton_method</code></a> we can create a test double that conforms to the provided options, without having to use temporary classes or structs, nor affecting other object instances.</p>
<h3 id="rspec-example-group-methods" class="heading"><a href="#rspec-example-group-methods" class="heading-anchor" aria-label="Permalink for RSpec Example Group Methods" tabindex="-1"></a>RSpec Example Group Methods</h3>
<p>When writing tests with RSpec, it's a good practice to keep helpers and state as local as possible. A typical way to do that is to include helpers only for certain types of tests.</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code>RSpec<span class="token punctuation">.</span>configure <span class="token keyword">do</span> <span class="token operator">|</span>config<span class="token operator">|</span>
  config<span class="token punctuation">.</span><span class="token keyword">include</span><span class="token punctuation">(</span>EmailSpec<span class="token double-colon punctuation">::</span>Helpers<span class="token punctuation">,</span> <span class="token symbol">type</span><span class="token operator">:</span> <span class="token symbol">:controller</span><span class="token punctuation">)</span>
<span class="token keyword">end</span></code></pre></div>
<p>Behind the scenes, RSpec will leverage the <em>singleton class</em> of a specific example group to include the module, without affecting other test scenarios.</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code>RSpec<span class="token punctuation">.</span>configure <span class="token keyword">do</span> <span class="token operator">|</span>config<span class="token operator">|</span>
  config<span class="token punctuation">.</span>before<span class="token punctuation">(</span><span class="token symbol">:each</span><span class="token punctuation">,</span> <span class="token symbol">type</span><span class="token operator">:</span> <span class="token symbol">:controller</span><span class="token punctuation">)</span> <span class="token keyword">do</span> <span class="token operator">|</span>example<span class="token operator">|</span>
    example<span class="token punctuation">.</span>example_group_instance<span class="token punctuation">.</span>singleton_class<span class="token punctuation">.</span><span class="token keyword">include</span><span class="token punctuation">(</span>EmailSpec<span class="token double-colon punctuation">::</span>Helpers<span class="token punctuation">)</span>
  <span class="token keyword">end</span>
<span class="token keyword">end</span></code></pre></div>
<p>We can use this to our advantage as a way to define scenario-specific methods as well:</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code>RSpec<span class="token punctuation">.</span>configure <span class="token keyword">do</span> <span class="token operator">|</span>config<span class="token operator">|</span>
  config<span class="token punctuation">.</span>before<span class="token punctuation">(</span><span class="token symbol">:each</span><span class="token punctuation">,</span> <span class="token symbol">:as</span><span class="token punctuation">)</span> <span class="token keyword">do</span> <span class="token operator">|</span>example<span class="token operator">|</span>
    example<span class="token punctuation">.</span>example_group_instance<span class="token punctuation">.</span>define_singleton_method<span class="token punctuation">(</span><span class="token symbol">:current_user</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      instance_exec<span class="token punctuation">(</span><span class="token operator">&amp;</span>example<span class="token punctuation">.</span>metadata<span class="token punctuation">[</span><span class="token symbol">:as</span><span class="token punctuation">]</span><span class="token punctuation">)</span>
    <span class="token punctuation">}</span>
  <span class="token keyword">end</span>
<span class="token keyword">end</span>

RSpec<span class="token punctuation">.</span>feature <span class="token string-literal"><span class="token string">'Visiting a page'</span></span> <span class="token keyword">do</span>
  before <span class="token punctuation">{</span> sign_in_as current_user <span class="token punctuation">}</span>

  it <span class="token string-literal"><span class="token string">'can visit the page as a user'</span></span><span class="token punctuation">,</span> <span class="token symbol">as</span><span class="token operator">:</span> <span class="token operator">-</span><span class="token operator">></span> <span class="token punctuation">{</span> User<span class="token punctuation">.</span>first <span class="token punctuation">}</span> <span class="token keyword">do</span>
    <span class="token operator">...</span>
  <span class="token keyword">end</span>

  it <span class="token string-literal"><span class="token string">'can visit the page as an admin'</span></span><span class="token punctuation">,</span> <span class="token symbol">as</span><span class="token operator">:</span> <span class="token operator">-</span><span class="token operator">></span> <span class="token punctuation">{</span> Admin<span class="token punctuation">.</span>first <span class="token punctuation">}</span> <span class="token keyword">do</span>
    <span class="token operator">...</span>
  <span class="token keyword">end</span>
<span class="token keyword">end</span></code></pre></div>
<p>Check <a href="https://github.com/ElMassimo/capybara_test_helpers/blob/367fdb898f9c02059dc54f2351a3a46f72cffac8/lib/capybara_test_helpers/rspec.rb#L24" target="_blank" rel="nofollow noopener noreferrer">this example</a> in the <a href="https://github.com/ElMassimo/capybara_test_helpers" target="_blank" rel="nofollow noopener noreferrer"><em>Capybara Test Helpers</em></a> library, which uses it to <a href="https://capybara-test-helpers.netlify.app/guide/essentials/injection.html#test-helpers-in-rspec" target="_blank" rel="nofollow noopener noreferrer">inject test helpers</a> using a <code>:test_helpers</code> option.</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code>RSpec<span class="token punctuation">.</span>feature <span class="token string-literal"><span class="token string">'Cities'</span></span> <span class="token keyword">do</span>
  scenario <span class="token string-literal"><span class="token string">'adding a city'</span></span><span class="token punctuation">,</span> <span class="token symbol">test_helpers</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token symbol">:cities</span><span class="token punctuation">]</span> <span class="token keyword">do</span>
    visit_page<span class="token punctuation">(</span><span class="token symbol">:cities</span><span class="token punctuation">)</span>
    cities<span class="token punctuation">.</span>add<span class="token punctuation">(</span><span class="token symbol">name</span><span class="token operator">:</span> <span class="token string-literal"><span class="token string">'Minneapolis'</span></span><span class="token punctuation">)</span>
    cities<span class="token punctuation">.</span>should<span class="token punctuation">.</span>have_city<span class="token punctuation">(</span><span class="token string-literal"><span class="token string">'Minneapolis'</span></span><span class="token punctuation">)</span>
  <span class="token keyword">end</span>
<span class="token keyword">end</span></code></pre></div>
<h3 id="custom-cache-keys" class="heading"><a href="#custom-cache-keys" class="heading-anchor" aria-label="Permalink for Custom Cache Keys" tabindex="-1"></a>Custom Cache Keys</h3>
<p>When using Rails' cache, <a href="https://github.com/rails/rails/blob/fe76a95b0d252a2d7c25e69498b720c96b243ea2/activesupport/lib/active_support/cache.rb#L435-L445" target="_blank" rel="nofollow noopener noreferrer"><code>fetch_multi</code></a> supports passing a list of keys, which will be yielded to the block in order to calculate the value to cache.</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code>keys <span class="token operator">=</span> items<span class="token punctuation">.</span>map <span class="token punctuation">{</span> <span class="token operator">|</span>item<span class="token operator">|</span> cache_key_for<span class="token punctuation">(</span>item<span class="token punctuation">)</span> <span class="token punctuation">}</span>
Rails<span class="token punctuation">.</span>cache<span class="token punctuation">.</span>fetch_multi<span class="token punctuation">(</span><span class="token operator">*</span>keys<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token operator">|</span>key<span class="token operator">|</span> value_for<span class="token punctuation">(</span>key<span class="token punctuation">)</span> <span class="token punctuation">}</span></code></pre></div>
<p>What if we need the item instead of the key in order to calculate the value to cache?</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code>items_by_cache_key <span class="token operator">=</span> items<span class="token punctuation">.</span>index_by <span class="token punctuation">{</span> <span class="token operator">|</span>item<span class="token operator">|</span> cache_key_for<span class="token punctuation">(</span>item<span class="token punctuation">)</span> <span class="token punctuation">}</span>
cache_keys <span class="token operator">=</span> items_by_cache_key<span class="token punctuation">.</span>keys
Rails<span class="token punctuation">.</span>cache<span class="token punctuation">.</span>fetch_multi<span class="token punctuation">(</span><span class="token operator">*</span>cache_keys<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token operator">|</span>key<span class="token operator">|</span> value_for<span class="token punctuation">(</span>items_by_cache_key<span class="token punctuation">[</span>key<span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">}</span></code></pre></div>
<p>Quite awkward. However, <a href="https://github.com/rails/rails/blob/fe76a95b0d252a2d7c25e69498b720c96b243ea2/activesupport/lib/active_support/cache.rb#L435-L445" target="_blank" rel="nofollow noopener noreferrer"><code>fetch_multi</code></a> also supports passing a list of objects, in which case it will call <a href="https://github.com/rails/rails/blob/fe76a95b0d252a2d7c25e69498b720c96b243ea2/activesupport/lib/active_support/cache.rb#L649-L653" target="_blank" rel="nofollow noopener noreferrer"><code>cache_key</code></a> on the objects to <a href="https://github.com/rails/rails/blob/fe76a95b0d252a2d7c25e69498b720c96b243ea2/activesupport/lib/active_support/cache.rb#L649-L653" target="_blank" rel="nofollow noopener noreferrer">obtain the cache keys</a>.</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code>Rails<span class="token punctuation">.</span>cache<span class="token punctuation">.</span>fetch_multi<span class="token punctuation">(</span><span class="token operator">*</span>items<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token operator">|</span>item<span class="token operator">|</span> value_for<span class="token punctuation">(</span>item<span class="token punctuation">)</span> <span class="token punctuation">}</span></code></pre></div>
<p>But what if the items don't respond to <code>cache_key</code>?</p>
<p>We can leverage <a href="https://ruby-doc.org/core-2.7.2/Object.html#method-i-define_singleton_method" target="_blank" rel="nofollow noopener noreferrer"><code>define_singleton_method</code></a> to define it differently for each item:</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code>items<span class="token punctuation">.</span><span class="token keyword">each</span> <span class="token keyword">do</span> <span class="token operator">|</span>item<span class="token operator">|</span>
  item<span class="token punctuation">.</span>define_singleton_method<span class="token punctuation">(</span><span class="token symbol">:cache_key</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> cache_key_for<span class="token punctuation">(</span>item<span class="token punctuation">)</span> <span class="token punctuation">}</span>
<span class="token keyword">end</span>
Rails<span class="token punctuation">.</span>cache<span class="token punctuation">.</span>fetch_multi<span class="token punctuation">(</span><span class="token operator">*</span>items<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token operator">|</span>item<span class="token operator">|</span> value_for<span class="token punctuation">(</span>item<span class="token punctuation">)</span> <span class="token punctuation">}</span></code></pre></div>
<p>Check <a href="https://github.com/ElMassimo/oj_serializers/blob/385aea5d97c477be9ff121edd622974a861877af/lib/oj_serializers/serializer.rb#L269" target="_blank" rel="nofollow noopener noreferrer">this example</a> in the <a href="https://github.com/ElMassimo/oj_serializers" target="_blank" rel="nofollow noopener noreferrer"><code>oj_serializers</code></a> library, which <a href="https://github.com/ElMassimo/oj_serializers/blob/385aea5d97c477be9ff121edd622974a861877af/lib/oj_serializers/serializer.rb#L262" target="_blank" rel="nofollow noopener noreferrer">defines</a> a <code>cache_key</code> <em>singleton method</em> for each object, so that they can be passed to <a href="https://github.com/rails/rails/blob/fe76a95b0d252a2d7c25e69498b720c96b243ea2/activesupport/lib/active_support/cache.rb#L649-L653" target="_blank" rel="nofollow noopener noreferrer"><code>fetch_multi</code></a>.</p>
<h2 id="ad-hoc-validations-in-rails" class="heading"><a href="#ad-hoc-validations-in-rails" class="heading-anchor" aria-label="Permalink for Ad Hoc Validations in Rails" tabindex="-1"></a>Ad Hoc Validations in Rails</h2>
<p>Let's imagine that we have a file upload API, and we are running an integrity check on save.</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code><span class="token keyword">module</span> <span class="token class-name">FileIntegrityValidation</span>
  <span class="token keyword">extend</span> ActiveSupport<span class="token double-colon punctuation">::</span>Concern

  included <span class="token keyword">do</span>
    validate <span class="token punctuation">{</span> errors<span class="token punctuation">.</span>add<span class="token punctuation">(</span><span class="token symbol">:file</span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">'is corrupt'</span></span><span class="token punctuation">)</span> <span class="token keyword">if</span> corrupt<span class="token operator">?</span> <span class="token punctuation">}</span>
  <span class="token keyword">end</span>

  <span class="token keyword">def</span> <span class="token method-definition"><span class="token function">corrupt</span></span><span class="token operator">?</span>
    <span class="token operator">...</span>
  <span class="token keyword">end</span>
<span class="token keyword">end</span></code></pre></div>
<p>What if we need to run the validation conditionally based on a setting that is not accesible from the model?</p>
<p>We can leverage the <em>singleton class</em> to define the validation conditionally:</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code><span class="token keyword">class</span> <span class="token class-name">Api</span><span class="token double-colon punctuation">::</span>FilesController <span class="token operator">&lt;</span> Api<span class="token double-colon punctuation">::</span>BaseController
  resource<span class="token punctuation">(</span><span class="token symbol">:file_upload</span><span class="token punctuation">)</span>

  <span class="token keyword">def</span> <span class="token method-definition"><span class="token function">create</span></span>
    <span class="token keyword">if</span> check_file_integrity<span class="token operator">?</span>
      file_upload<span class="token punctuation">.</span>singleton_class<span class="token punctuation">.</span><span class="token keyword">include</span><span class="token punctuation">(</span>FileIntegrityValidation<span class="token punctuation">)</span>
    <span class="token keyword">end</span>

    <span class="token keyword">if</span> file_upload<span class="token punctuation">.</span>save
      <span class="token operator">...</span></code></pre></div>
<blockquote>
<p>The <a href="https://github.com/ElMassimo/resourcerer" target="_blank" rel="nofollow noopener noreferrer"><code>resource</code></a> syntax is coming from <a href="https://github.com/ElMassimo/resourcerer" target="_blank" rel="nofollow noopener noreferrer"><em>resourcerer</em></a>.</p>
</blockquote>
<p>In this case we can't use <a href="#adding-mixins-to-the-singleton-class"><code>extend</code></a> because <code>ActiveSupport::Concern</code> internally uses the <a href="https://ruby-doc.org/core-2.7.2/Module.html#method-i-included" target="_blank" rel="nofollow noopener noreferrer"><code>included</code></a> hook, which is only triggered when using <code>include</code>.</p>
<p>When using this pattern, it's better to encapsulate it so that it's easier to understand:</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code>  <span class="token keyword">def</span> <span class="token method-definition"><span class="token function">create</span></span>
    <span class="token keyword">if</span> check_file_integrity<span class="token operator">?</span>
      FileIntegrityValidation<span class="token punctuation">.</span>apply_on<span class="token punctuation">(</span>file_upload<span class="token punctuation">)</span>
    <span class="token keyword">end</span></code></pre></div>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code><span class="token keyword">module</span> <span class="token class-name">FileIntegrityValidation</span>
  <span class="token comment"># Public: Define this validation only for the provided object.</span>
  <span class="token keyword">def</span> <span class="token method-definition"><span class="token keyword">self</span><span class="token punctuation">.</span><span class="token function">apply_on</span></span><span class="token punctuation">(</span>object<span class="token punctuation">)</span>
    object<span class="token punctuation">.</span>singleton_class<span class="token punctuation">.</span><span class="token keyword">include</span><span class="token punctuation">(</span><span class="token keyword">self</span><span class="token punctuation">)</span>
  <span class="token keyword">end</span>
<span class="token keyword">end</span></code></pre></div>
<h2 id="summary" class="heading"><a href="#summary" class="heading-anchor" aria-label="Permalink for Summary" tabindex="-1"></a>Summary</h2>
<p>We can use an object's <em>singleton class</em> to define methods or include modules without affecting other instances, which enables very powerful techniques such as method stubbing and dynamically modifying behavior.</p>
<p>In practice, the use cases where this is necessary don't come around very often. It's usually possible to achieve what we need using simpler or more explicit strategies, that are easier to reason about.</p>
<p>As with most advanced techniques, you will know when you need it <span role="img" aria-label="grinning face with big eyes">😃</span></p>]]></content>
        <author>
            <name>Máximo Mussini</name>
            <uri>https://maximomussini.com</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[What is the Singleton Class in Ruby?]]></title>
        <id>https://maximomussini.com/posts/understanding-the-singleton-class</id>
        <link href="https://maximomussini.com/posts/understanding-the-singleton-class"/>
        <updated>2020-12-04T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Demistifying the singleton class, also referred to as the metaclass or the eigenclass.]]></summary>
        <content type="html"><![CDATA[
<p>The <em>singleton class</em>, also referred to as the <em>metaclass</em> or the <em>eigenclass</em>. What is it exactly?</p>
<p>Let's begin by discussing the <strong>main purpose</strong> of metaclasses in Ruby.</p>
<h2 id="classes-and-method-dispatching" class="heading"><a href="#classes-and-method-dispatching" class="heading-anchor" aria-label="Permalink for Classes and Method Dispatching" tabindex="-1"></a>Classes and Method Dispatching</h2>
<p>In Ruby, everything is an <em>object</em>, and every object has a <em>class</em>, which defines the <em>methods</em> the object can respond to.</p>
<p>These two statements also apply to classes, which is what makes it possible for classes in Ruby to have their own instance variables and to receive methods.</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code><span class="token keyword">class</span> <span class="token class-name">Animal</span>
  <span class="token variable">@description</span> <span class="token operator">=</span> <span class="token string-literal"><span class="token string">'A multicellular eukaryotic organism.'</span></span>

  <span class="token keyword">def</span> <span class="token method-definition"><span class="token keyword">self</span><span class="token punctuation">.</span><span class="token function">description</span></span>
    <span class="token variable">@description</span>
  <span class="token keyword">end</span>
<span class="token keyword">end</span>

Animal<span class="token punctuation">.</span>description <span class="token comment"># => "A multicellular eukaryotic organism."</span></code></pre></div>
<p>In contrast with other languages, in Ruby what we usually refer to as <em>class methods</em> are simply <em>instance methods</em> of a class object.</p>
<p>Now, if a class in Ruby is an object, and every object has a class which defines its methods, then a class in Ruby <em>has a class which defines its methods</em>.</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code>Animal<span class="token punctuation">.</span><span class="token keyword">class</span> <span class="token comment"># => Class</span></code></pre></div>
<p>If <code>Class</code> defined those methods, then they would be available for any class object.</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code><span class="token builtin">Integer</span><span class="token punctuation">.</span>description
<span class="token comment"># NoMethodError (undefined method `description' for Integer:Class)</span></code></pre></div>
<p>How does Ruby pull it off then?</p>
<h2 id="the-metaclass-of-a-class" class="heading"><a href="#the-metaclass-of-a-class" class="heading-anchor" aria-label="Permalink for The Metaclass of a Class" tabindex="-1"></a>The Metaclass of a Class</h2>
<p>Ruby deals with it by giving every <em>object</em> its own unique class, which defines the methods available for that object. Its very own <em><strong>metaclass</strong></em>.</p>
<blockquote>
<p>The metaclass is called the <a href="https://en.wikipedia.org/wiki/Singleton_pattern" target="_blank" rel="nofollow noopener noreferrer"><em>singleton class</em></a> because there is <em>a single instance</em> of it.</p>
</blockquote>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code>Animal<span class="token punctuation">.</span>singleton_class <span class="token comment"># => #&lt;Class:Animal></span></code></pre></div>
<p>This class is hidden in the inheritance chain (it doesn't show up when calling <code>ancestors</code>, and <code>class</code> returns <code>Class</code>), but we can think of it as <em><strong>the first ancestor</strong></em> when it comes to dispatching methods.</p>
<p>When calling a method on an object, Ruby will perform the method lookup by first checking on the object's <em>metaclass</em>, before traversing the rest of the method chain.</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code>Animal<span class="token punctuation">.</span>singleton_methods <span class="token comment"># => [:description]</span></code></pre></div>
<p>Just like instance methods are defined in a class, class methods are defined in the <em>metaclass</em> of a class object.</p>
<blockquote>
<p>This design enables Ruby to share the same dispatch mechanism for class methods: <em><strong>internally all methods are instance methods</strong></em>.</p>
</blockquote>
<h2 id="the-metaclass-hierarchy" class="heading"><a href="#the-metaclass-hierarchy" class="heading-anchor" aria-label="Permalink for The Metaclass Hierarchy" tabindex="-1"></a>The Metaclass Hierarchy</h2>
<p>In the diagram below we can see that each class has a corresponding <em>metaclass</em>, which is where their respective <em>class methods</em> are defined.</p>
<p><picture><source media="(-webkit-min-device-pixel-ratio: 1.5)" type="image/avif" srcset="/assets/the-metaclass-hierarchy.81061b9e.avif 420w, /assets/the-metaclass-hierarchy.9cb9a659.avif 720w"><source media="(-webkit-min-device-pixel-ratio: 1.5)" type="image/webp" srcset="/assets/the-metaclass-hierarchy.d2fd3f90.webp 420w, /assets/the-metaclass-hierarchy.a8af51a8.webp 720w"><source media="(-webkit-min-device-pixel-ratio: 1.5)" srcset="/assets/the-metaclass-hierarchy.a71c0cab.jpeg 420w, /assets/the-metaclass-hierarchy.3872463c.jpeg 720w"><source type="image/avif" srcset="/assets/the-metaclass-hierarchy.e86b6b82.avif 720w"><source type="image/webp" srcset="/assets/the-metaclass-hierarchy.e2833547.webp 720w"><img srcset="/assets/the-metaclass-hierarchy.21e6b910.jpeg 720w" loading="lazy" src="/assets/the-metaclass-hierarchy.21e6b910.jpeg" class="img" alt="Diagram of the Metaclass Hierarchy"></picture></p>
<blockquote>
<p>The inheritance chain of metaclasses is what allows to inherit and override class methods and call <code>super</code>.</p>
</blockquote>
<p>And that is the main purpose of metaclasses in Ruby.</p>
<h2 id="the-metaclass-of-an-object" class="heading"><a href="#the-metaclass-of-an-object" class="heading-anchor" aria-label="Permalink for The Metaclass of an Object" tabindex="-1"></a>The Metaclass of an Object</h2>
<p>Notice how the instance also has its own metaclass: <em>classes are just a particular kind of object</em>. When we call a method on an instance, Ruby will also look in its metaclass first.</p>
<p>Let's see a few examples of how we can use the metaclass to define methods that are specific to a particular instance.</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code>animal <span class="token operator">=</span> <span class="token class-name">Animal</span><span class="token punctuation">.</span><span class="token keyword">new</span>
other_animal <span class="token operator">=</span> <span class="token class-name">Animal</span><span class="token punctuation">.</span><span class="token keyword">new</span>

<span class="token keyword">class</span> <span class="token operator">&lt;&lt;</span> animal
  <span class="token keyword">def</span> <span class="token method-definition"><span class="token function">bark</span></span>
    <span class="token string-literal"><span class="token string">'Woof'</span></span>
  <span class="token keyword">end</span>
<span class="token keyword">end</span>

<span class="token keyword">def</span> <span class="token method-definition"><span class="token class-name">animal</span><span class="token punctuation">.</span><span class="token function">greet</span></span>
  <span class="token string-literal"><span class="token string">'hi'</span></span>
<span class="token keyword">end</span>

animal<span class="token punctuation">.</span>define_singleton_method<span class="token punctuation">(</span><span class="token symbol">:roar</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token string-literal"><span class="token string">'Rawr!'</span></span> <span class="token punctuation">}</span>

animal<span class="token punctuation">.</span>bark  <span class="token comment"># => "Woof"</span>
animal<span class="token punctuation">.</span>greet <span class="token comment"># => "Hi"</span>
animal<span class="token punctuation">.</span>roar  <span class="token comment"># => "Rawr!"</span>

animal<span class="token punctuation">.</span>singleton_methods <span class="token comment"># => [:bark, :roar, :greet]</span>
animal<span class="token punctuation">.</span>singleton_class<span class="token punctuation">.</span>instance_methods<span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span> <span class="token comment"># => [:bark, :roar, :greet]</span>

other_animal<span class="token punctuation">.</span>bark <span class="token comment"># NoMethodError (undefined method `bark' for #&lt;Animal>)</span>
other_animal<span class="token punctuation">.</span>singleton_methods <span class="token comment"># => []</span></code></pre></div>
<p>You will certainly recognize the first two patterns, they use the same syntax that is typically used with <code>self</code> to define <em>class methods</em>!</p>
<p>Once again, <em>classes are just a particular kind of object</em>. And yet, unlike classes, modifying the behavior of a particular object is rarely used in practice.</p>
<p>In the <em><a href="/posts/practical-applications-of-the-singleton-class">next post</a></em> I share a few useful applications of this feature, <a href="/posts/practical-applications-of-the-singleton-class">read on</a>!</p>]]></content>
        <author>
            <name>Máximo Mussini</name>
            <uri>https://maximomussini.com</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Generating a JS API from Rails Routes]]></title>
        <id>https://maximomussini.com/posts/js-from-routes</id>
        <link href="https://maximomussini.com/posts/js-from-routes"/>
        <updated>2020-06-22T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Enjoy all the benefits of Rails path helpers in your JavaScript code.]]></summary>
        <content type="html"><![CDATA[<p>One idea I've always appreciated about the routing approach in Rails is <strong>path helpers</strong>, which are automatically generated from route definitions.</p>
<p>Some advantages of using path helpers are:</p>
<ul>
<li>There's no need to take care of manually interpolating ids and parameters to
build a <code>String</code> URL.</li>
<li>Any change to the route definition affects the helper, so if a route is
removed or modified, the path helper is no longer available.</li>
<li>Code that uses an outdated path helper causes a runtime error, which can be
detected by integration or unit tests, instead of rendering a path that would
end up in a 404, like it would happen when using manual string interpolation.</li>
</ul>
<h2 id="path-helpers-in-js" class="heading"><a href="#path-helpers-in-js" class="heading-anchor" aria-label="Permalink for Path Helpers in JS" tabindex="-1"></a>Path Helpers in JS</h2>
<p>Traditionally, frontend code in Rails replicates the path structure as defined in the backend, hardcoding the paths for every endpoint that needs to be accessed, and specifying HTTP verbs as needed (<code>GET</code>, <code>POST</code>, <code>PATCH</code>).</p>
<div class="language-js" data-lang="js"><pre class="language-js"><code>$<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'/search'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> query <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div>
<p>This approach is very cumbersome, and it is possible to introduce typos, or
make mistakes like choosing the wrong HTTP verb (<code>PUT</code> instead of <code>PATCH</code>, and so on).</p>
<blockquote>
<p>We could avoid these problems if we had path helpers in JS.</p>
</blockquote>
<p>While some tools that allowed to expose path helpers to JS already existed, they were created when <a href="https://github.com/rails/sprockets" target="_blank" rel="nofollow noopener noreferrer">sprockets</a> was <em>the</em> way to compile frontend assets in Rails, long before the <a href="https://github.com/rails/webpacker" target="_blank" rel="nofollow noopener noreferrer">Webpack</a> era.</p>
<p>I wanted a solution that provided an enjoyable front-end development experience. One that could leverage Webpack loaders and aliases, and was based on ES6 modules to allow tree-shaking, was easy to inspect, and where changes could be tracked under version control.</p>
<p>And that's why I created <a href="https://github.com/ElMassimo/js_from_routes" target="_blank" rel="nofollow noopener noreferrer"><code>JsFromRoutes</code></a>.</p>
<h3 id="shaping-the-vision" class="heading"><a href="#shaping-the-vision" class="heading-anchor" aria-label="Permalink for Shaping the Vision ✨" tabindex="-1"></a>Shaping the Vision <span role="img" aria-label="sparkles">✨</span></h3>
<p>From a developer's UX perspective, the goal was to simplify how to make <a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API" target="_blank" rel="nofollow noopener noreferrer">requests</a> to a Rails API.</p>
<p>This meant not thinking about paths, parameter interpolation, nor HTTP verbs. Just plain function calls and promises.</p>
<div class="language-js" data-lang="js"><pre class="language-js"><code><span class="token keyword">import</span> UsersRequests <span class="token keyword">from</span> <span class="token string">'@requests/UsersRequests'</span>

<span class="token keyword">const</span> user <span class="token operator">=</span> <span class="token keyword">await</span> UsersRequests<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token punctuation">{</span> name<span class="token punctuation">,</span> email <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div>
<p>These functions would be automatically generated from the Rails route definitions. The generation process should be transparent, and happen automatically as routes are added and the application is reloaded.</p>
<p>For maintainability, as well as for tree-shaking purposes, it was desirable to do a simple mapping: <em>one request object per controller</em>.</p>
<div class="language-js" data-lang="js"><pre class="language-js"><code><span class="token keyword">import</span> <span class="token punctuation">{</span> request <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@services/ApiService'</span>

<span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token punctuation">{</span>
  <span class="token function-variable function">search</span><span class="token operator">:</span> <span class="token parameter">options</span> <span class="token operator">=></span>
    <span class="token function">request</span><span class="token punctuation">(</span><span class="token string">'get'</span><span class="token punctuation">,</span> <span class="token string">'/users/search'</span><span class="token punctuation">,</span> options<span class="token punctuation">)</span><span class="token punctuation">,</span>

  <span class="token function-variable function">create</span><span class="token operator">:</span> <span class="token parameter">options</span> <span class="token operator">=></span>
    <span class="token function">request</span><span class="token punctuation">(</span><span class="token string">'post'</span><span class="token punctuation">,</span> <span class="token string">'/users'</span><span class="token punctuation">,</span> options<span class="token punctuation">)</span><span class="token punctuation">,</span>

  <span class="token function-variable function">destroy</span><span class="token operator">:</span> <span class="token parameter">options</span> <span class="token operator">=></span>
    <span class="token function">request</span><span class="token punctuation">(</span><span class="token string">'delete'</span><span class="token punctuation">,</span> <span class="token string">'/users/:id'</span><span class="token punctuation">,</span> options<span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span></code></pre></div>
<p>Delegating the actual request to an existing service would allow to keep the generated code lean. Any changes or improvements could then be made on the service itself, without having to regenerate the code. For example, switching from <a href="https://github.com/axios/axios" target="_blank" rel="nofollow noopener noreferrer">axios</a> to <a href="https://github.com/developit/redaxios" target="_blank" rel="nofollow noopener noreferrer">redaxios</a>, or to the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API" target="_blank" rel="nofollow noopener noreferrer">fetch API</a>.</p>
<h3 id="generating-js-from-rails-routes-⚙️" class="heading"><a href="#generating-js-from-rails-routes-⚙️" class="heading-anchor" aria-label="Permalink for Generating JS from Rails Routes ⚙️" tabindex="-1"></a>Generating JS from Rails Routes <span role="img" aria-label="gear">⚙️</span></h3>
<p>Although the routes DSL in Rails wasn't designed for inspection purposes, it does provide
the necessary metadata: the name of the endpoints, the HTTP verbs, and the paths including named parameters.</p>
<p>By doing some slight processing to the information in <code>Rails.application.routes</code>, and combining that with an ERB template, we are able to generate the JS functions we need.</p>
<div class="language-erb" data-lang="erb"><pre class="language-erb"><code>import { request } from '@services/ApiService'

export default {
<span class="token erb language-erb"><span class="token delimiter punctuation">&lt;%</span><span class="token ruby language-ruby"> routes<span class="token punctuation">.</span>each_with_index <span class="token keyword">do</span> <span class="token operator">|</span>route<span class="token punctuation">,</span> index<span class="token operator">|</span> </span><span class="token delimiter punctuation">%></span></span>
  <span class="token erb language-erb"><span class="token delimiter punctuation">&lt;%=</span><span class="token ruby language-ruby"> route<span class="token punctuation">.</span>helper </span><span class="token delimiter punctuation">%></span></span>: options =>
    request('<span class="token erb language-erb"><span class="token delimiter punctuation">&lt;%=</span><span class="token ruby language-ruby"> route<span class="token punctuation">.</span>verb </span><span class="token delimiter punctuation">%></span></span>', '<span class="token erb language-erb"><span class="token delimiter punctuation">&lt;%=</span><span class="token ruby language-ruby"> route<span class="token punctuation">.</span>path </span><span class="token delimiter punctuation">%></span></span>', options),
<span class="token erb language-erb"><span class="token delimiter punctuation">&lt;%</span><span class="token ruby language-ruby"> <span class="token keyword">end</span> </span><span class="token delimiter punctuation">%></span></span>
}</code></pre></div>
<h3 id="automating-the-flow" class="heading"><a href="#automating-the-flow" class="heading-anchor" aria-label="Permalink for Automating the Flow 🤖" tabindex="-1"></a>Automating the Flow <span role="img" aria-label="robot">🤖</span></h3>
<p>Why trigger the generation manually? Let the machines do it <span role="img" aria-label="grinning face with big eyes">😃</span></p>
<p>By adding a hook to Rails' reload process in development, we can automatically
generate files from routes when a route is added, modified, or removed.</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code>ActiveSupport<span class="token double-colon punctuation">::</span>Reloader<span class="token punctuation">.</span>to_prepare <span class="token punctuation">{</span> JsFromRoutes<span class="token punctuation">.</span>generate<span class="token operator">!</span> <span class="token punctuation">}</span></code></pre></div>
<p>In order to optimize file generation, we split the generated JS files by
controller, and add a cache key based on the routes to avoid rewriting the file
if the route definition hasn't changed.</p>
<p>When the Webpack development server is running, this automatically triggers a
new build, and our request method or path helper is ready to be used!</p>
<h3 id="the-gem" class="heading"><a href="#the-gem" class="heading-anchor" aria-label="Permalink for The Gem 💎" tabindex="-1"></a>The Gem <span role="img" aria-label="gem stone">💎</span></h3>
<p>The flow described above is now available through the <a href="https://github.com/ElMassimo/js_from_routes" target="_blank" rel="nofollow noopener noreferrer"><code>js_from_routes</code></a> gem. The library provides additional configuration options, <a href="https://github.com/ElMassimo/js_from_routes" target="_blank" rel="nofollow noopener noreferrer">visit the readme</a> for more information.</p>
<p>This approach has similar benefits to path helpers in Rails:</p>
<ul>
<li>No need to manually specify the URL, preventing mistakes and saving development time.</li>
<li>If an action is renamed or removed, the helper ceases to exist, which causes an error that is easier to detect than a 404.</li>
<li>The HTTP verb is embedded in the helper, so it's transparent for the client code. Changing the verb in the route causes the JS code to be regenerated, no need to update the consumers!</li>
</ul>
<h2 id="summary" class="heading"><a href="#summary" class="heading-anchor" aria-label="Permalink for Summary" tabindex="-1"></a>Summary</h2>
<p><a href="https://github.com/ElMassimo/js_from_routes" target="_blank" rel="nofollow noopener noreferrer"><code>js_from_routes</code></a> allows to automatically generate path and API helpers from Rails route definitions, allowing you to save development effort and focus on the things that matter.</p>
<p>Since introducing this tool, we have saved a lot of time that we would have
spent writing boilerplate code, avoided a lot of mistakes like typos and
interpolation errors, and made the front-end development experience more
enjoyable <span role="img" aria-label="grinning face with big eyes">😃</span></p>]]></content>
        <author>
            <name>Máximo Mussini</name>
            <uri>https://maximomussini.com</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Store Objects for Vuex]]></title>
        <id>https://maximomussini.com/posts/vuex-stores</id>
        <link href="https://maximomussini.com/posts/vuex-stores"/>
        <updated>2020-05-12T03:20:00.000Z</updated>
        <summary type="html"><![CDATA[It's easier to manage and understand state in Vuex when it is split between different modules.]]></summary>
        <content type="html"><![CDATA[<p><a href="https://vuex.vuejs.org/" target="_blank" rel="nofollow noopener noreferrer">Vuex</a> is a state-management solution that integrates nicely with
<a href="https://vuejs.org/" target="_blank" rel="nofollow noopener noreferrer">Vue</a> components.</p>
<p>When starting to use Vuex, one quickly realizes that it's easier to manage and
understand the state of a large application when the state is split between
different <a href="https://vuex.vuejs.org/guide/modules.html" target="_blank" rel="nofollow noopener noreferrer">modules in the Vuex store</a>.</p>
<p>Unfortunately, working with modules involves using a <em>namespace string</em> to
access state and getters, which makes typos hard to detect, and can
quickly become cumbersome if using <a href="https://vuex.vuejs.org/guide/mutations.html#using-constants-for-mutation-types" target="_blank" rel="nofollow noopener noreferrer">constants</a> or a similar
approach to avoid duplication.</p>
<p>Another weak spot is that dispatching actions feels very unnatural, and also
requires specifying the <em>namespace string</em> as a prefix for the action name.</p>
<h2 id="a-smoother-experience" class="heading"><a href="#a-smoother-experience" class="heading-anchor" aria-label="Permalink for A smoother experience 🥃" tabindex="-1"></a>A smoother experience <span role="img" aria-label="tumbler glass">🥃</span></h2>
<p>The <a href="https://github.com/ElMassimo/vuex-stores" target="_blank" rel="nofollow noopener noreferrer"><code>vuex-stores</code></a> library helps you avoid these shortcomings
by providing light wrappers around individual <a href="https://vuex.vuejs.org/guide/modules.html" target="_blank" rel="nofollow noopener noreferrer">Vuex store modules</a>,
which I've dubbed <em>"store-objects"</em>.</p>
<p><em>Store objects</em> address these issues by allowing access to state and getters as
properties, and dispatching actions easily by using plain method calls.</p>
<p>As a result, it's possible to leverage all the goodness in Vuex, using an
<a href="https://github.com/ElMassimo/vuex-stores#api-%EF%B8%8F" target="_blank" rel="nofollow noopener noreferrer">elegant and convenient API</a>.</p>
<h2 id="conventions" class="heading"><a href="#conventions" class="heading-anchor" aria-label="Permalink for Conventions 🔤" tabindex="-1"></a>Conventions <span role="img" aria-label="input latin letters">🔤</span></h2>
<p>In order to organize these store objects, an approach that works nicely is to:</p>
<ul>
<li>Create one file per store module under a <code>stores</code> directory.</li>
<li>Always use <code>Store</code> as a suffix for the file name (<code>ModalsStore</code>).</li>
<li>Add a <code>@stores</code> webpack alias to make them convenient to import.</li>
</ul>
<p>Let's take a look at an example usage:</p>
<div class="language-vue" data-lang="vue"><pre class="language-vue"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span><span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript">
<span class="token keyword">import</span> ModalsStore <span class="token keyword">from</span> <span class="token string">'@stores/ModalsStore'</span>

<span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token punctuation">{</span>
  <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'ModalManager'</span><span class="token punctuation">,</span>
  <span class="token literal-property property">computed</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token comment">// `mapState` and friends are available to inject state or getters into the</span>
    <span class="token comment">// template, without the need to specify the namespace string.</span>
    <span class="token operator">...</span>ModalsStore<span class="token punctuation">.</span><span class="token function">mapState</span><span class="token punctuation">(</span><span class="token string">'modals'</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token function">beforeMount</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">// closeAllModals is an action, and it will be dispatched every time the</span>
    <span class="token comment">// route changes, to hide any open modals.</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>$router<span class="token punctuation">.</span><span class="token function">afterEach</span><span class="token punctuation">(</span>ModalsStore<span class="token punctuation">.</span>closeAllModals<span class="token punctuation">)</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token literal-property property">methods</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token comment">// Actions are available as methods, notice the lack of boilerplate to</span>
    <span class="token comment">// inject it in the component using `mapActions`.</span>
    <span class="token function">onModalClose</span> <span class="token punctuation">(</span><span class="token parameter">modal</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      ModalsStore<span class="token punctuation">.</span><span class="token function">removeModal</span><span class="token punctuation">(</span>modal<span class="token punctuation">)</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token comment">// NOTE: A shorter version would be `onModalClose: ModalsStore.removeModal`</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>template</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>modal-manager<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>component</span>
      <span class="token attr-name">:is</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>modal.component<span class="token punctuation">"</span></span>
      <span class="token attr-name">v-for</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>modal in modals<span class="token punctuation">"</span></span>
      <span class="token attr-name">:key</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>modal.id<span class="token punctuation">"</span></span>
      <span class="token attr-name">v-bind</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>modal.attrs<span class="token punctuation">"</span></span>
      <span class="token attr-name"><span class="token namespace">@modal:</span>close</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>onModalClose(modal)<span class="token punctuation">"</span></span>
    <span class="token punctuation">/></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>template</span><span class="token punctuation">></span></span></code></pre></div>
<p>As seen in this short example, state, getters, and actions can be easily injected
in a component using <code>map</code> helpers to make them available in the template.</p>
<p>Actions can be dispatched by simply calling a method, which is closer to how
they are defined, and feels very natural. Typos in action names are prevented,
since a method call would fail if the name is not correct (instead of being ignored)</p>
<p>The <em>namespace string</em> becomes an implementation detail which is transparent to
the user, without having to use cumbersome manual techniques (such as <a href="https://vuex.vuejs.org/guide/mutations.html#using-constants-for-mutation-types" target="_blank" rel="nofollow noopener noreferrer">constants</a>)
to avoid duplicating the module name all over the codebase.</p>
<p>Because incorrect ES6 imports provide clear errors, typos in the store name can
be detected at compile time, and refactoring becomes a lot easier (usually as
simple as <em>search and replace</em>).</p>
<p>There are more code samples available in the <a href="https://github.com/ElMassimo/vuex-stores#api-%EF%B8%8F" target="_blank" rel="nofollow noopener noreferrer">documentation</a> <span role="img" aria-label="open book">📖</span></p>
<h2 id="code-splitting" class="heading"><a href="#code-splitting" class="heading-anchor" aria-label="Permalink for Code Splitting ✂️" tabindex="-1"></a>Code Splitting <span role="img" aria-label="scissors">✂️</span></h2>
<p>Store modules in Vuex can be <a href="https://vuex.vuejs.org/guide/modules.html#dynamic-module-registration" target="_blank" rel="nofollow noopener noreferrer">registered dynamically</a>,
so internally <a href="https://github.com/ElMassimo/vuex-stores" target="_blank" rel="nofollow noopener noreferrer"><code>vuex-stores</code></a> leverages <code>registerModule</code> to
add a new module when the store object is imported.</p>
<p>This means that store objects don't need to be imported up-front when initially
defining the Vuex store, playing nicely with apps that do code splitting, since
the code associated to a store object will only be loaded if needed.</p>
<p>As a result, the initial setup of the Vuex store will be lighter, and by
using the conventions described above, code loading and execution will be
optimized.</p>
<h2 id="summary" class="heading"><a href="#summary" class="heading-anchor" aria-label="Permalink for Summary" tabindex="-1"></a>Summary</h2>
<p><a href="https://github.com/ElMassimo/vuex-stores" target="_blank" rel="nofollow noopener noreferrer"><code>vuex-stores</code></a> provides a simple way to work with <a href="https://vuex.vuejs.org/guide/modules.html" target="_blank" rel="nofollow noopener noreferrer">Vuex modules</a>
by allowing you to define <em>store objects</em> to focus on one module at a time,
making it more enjoyable to leverage Vuex.</p>
<p>The API is convenient and easy to learn, prevents mistakes such as typos, and
works nicely when used in conjunction with ES6 modules, making the code easier
to reason about and refactor.</p>
<p>Also, it's a lot of fun, give it a try! <span role="img" aria-label="grinning face with big eyes">😃</span></p>]]></content>
        <author>
            <name>Máximo Mussini</name>
            <uri>https://maximomussini.com</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Documentation is a Great Investment]]></title>
        <id>https://maximomussini.com/posts/documentation-is-a-great-investment</id>
        <link href="https://maximomussini.com/posts/documentation-is-a-great-investment"/>
        <updated>2020-02-17T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Make changes faster and refactor with confidence while preventing problems and regressions.]]></summary>
        <content type="html"><![CDATA[<p>In this post I'd like to share a practice that has completely changed the way we
work: documentation as a first-class citizen in our software development process.</p>
<p>Documentation facilitates understanding, which is <em>vital</em> to enable
change and continuous improvement.</p>
<h2 id="how-is-it-helpful" class="heading"><a href="#how-is-it-helpful" class="heading-anchor" aria-label="Permalink for How is it helpful? 🤔" tabindex="-1"></a>How is it helpful? <span role="img" aria-label="thinking face">🤔</span></h2>
<p>Traditionally, we aim to produce clean and maintainable code to make it more
reliable, and write tests to protect it. We use good variable names, split
functions that perform too much into simpler ones, and design them so that
parameter names convey enough information.</p>
<p>However, seeing <em>what</em> the code does is not the same as figuring out <em>why</em> it does it.</p>
<p>Most of the design process happens informally in chat rooms, conversations, and
online documents. As a result, understanding a decision that was made a long time
ago can be very time consuming, as it requires scanning through chat messages,
and reaching out to the people that were involved.</p>
<p>When we are not able to obtain enough information about these decisions, it
becomes harder to effectively reason about the software, slowing down fixes and
improvements.</p>
<p>This is why learning about past decisions should be as efficient and
straightforward as possible: it will save us a lot of time and frustration down
the line. Knowing the context will allow us to make informed decisions,
which are <em>better</em> decisions.</p>
<h2 id="if-you-havent-started-the-best-time-is-now-⌛" class="heading"><a href="#if-you-havent-started-the-best-time-is-now-⌛" class="heading-anchor" aria-label="Permalink for If you haven&#x27;t started, the best time is now ⌛" tabindex="-1"></a>If you haven't started, the best time is now <span role="img" aria-label="hourglass done">⌛</span></h2>
<p>If we are to make our software easier to understand, and thus easier to change,
we should <strong><em>document our intent</em></strong> in every possible way. Think about it as a
byproduct of the thought process we carry out as developers when designing a
solution and writing code.</p>
<p>Capture any breadcrumbs that might be useful in the future to find out how
things are supposed to work, helping other developers unravel the conditions
and mindset that influenced the code, even when we no longer remember why.</p>
<p><strong><em>Document as you go</em></strong>. No other time will be better to document than when the
ideas are fresh in our mind. Memories fade over time, and what we fail to
record then might be hopeless or painfully time-consuming to remember later.</p>
<p>The overhead of documenting on the spot is negligible, but the overall benefits
are certainly not!</p>
<h2 id="documenting-is-intrinsically-a-valuable-activity" class="heading"><a href="#documenting-is-intrinsically-a-valuable-activity" class="heading-anchor" aria-label="Permalink for Documenting is intrinsically a valuable activity 💰" tabindex="-1"></a>Documenting is intrinsically a valuable activity <span role="img" aria-label="money bag">💰</span></h2>
<p>To get the best out of it, we should imagine we are someone else trying to
understand our work. Which things will not be so obvious a few months from now?
Thinking about it can help to reveal our underlying assumptions and knowledge.</p>
<blockquote>
<p>Is it clear how this component interacts with other parts of the system?</p>
</blockquote>
<p>By doing this mental exercise, we will be able to find simpler and more readable
ways to solve a problem, allowing us to refine our designs and solutions.
It has a direct positive impact in maintainability, regardless of whether
someone actually reads the resulting documentation.</p>
<p>Our focus should be on recording intent, <em>why</em> and <em>how</em> things <em>should</em> happen.
It's also useful to cross-reference classes and objects that interact with each
other. Aim for the bigger picture, and work your way down as needed.</p>
<h2 id="a-lightweight-approach-is-good-enough-⚡" class="heading"><a href="#a-lightweight-approach-is-good-enough-⚡" class="heading-anchor" aria-label="Permalink for A lightweight approach is good enough ⚡" tabindex="-1"></a>A lightweight approach is good enough <span role="img" aria-label="high voltage">⚡</span></h2>
<p>In practice, we've found that using a conventional but minimal
<a href="https://gist.github.com/ElMassimo/a118d08482d9db8e71d622e136f10155#which-format-to-use" target="_blank" rel="nofollow noopener noreferrer">syntax</a> for comments works well, and that it's better to
<a href="https://gist.github.com/ElMassimo/a118d08482d9db8e71d622e136f10155" target="_blank" rel="nofollow noopener noreferrer"><em><strong>inline documentation</strong></em></a> in the code itself.</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code><span class="token comment"># Public: Abbreviation of a few words that sums up what the question is about.</span>
<span class="token comment"># Example: 'Side Effects'</span>
field <span class="token symbol">:title</span><span class="token punctuation">,</span> <span class="token symbol">type</span><span class="token operator">:</span> <span class="token builtin">String</span></code></pre></div>
<p>Inline docs are always at hand, require very low effort to add and update, and
are very helpful for developers to gain insight (both during reviews and in the long run).</p>
<p>They should be clear and concise. Don't overstate the obvious and remove any
words that feel unnecessary. <em><strong>Creating good documentation takes practice</strong></em>,
it's more about writing skills and less about programming.</p>
<p>While it's possible to generate documentation pages from a <a href="https://gist.github.com/ElMassimo/a118d08482d9db8e71d622e136f10155#which-format-to-use" target="_blank" rel="nofollow noopener noreferrer">minimal syntax</a>,
usually navigating through the source code and reading the inline docs is more
convenient. Using <em>Goto Symbol</em> or <em>Goto Definition</em> on any <a href="https://www.sublimetext.com/" target="_blank" rel="nofollow noopener noreferrer">editor</a> does the trick.</p>
<blockquote>
<p>Won't the comments become outdated really quickly? <span role="img" aria-label="weary cat">🙀</span></p>
</blockquote>
<h2 id="version-control-to-the-rescue" class="heading"><a href="#version-control-to-the-rescue" class="heading-anchor" aria-label="Permalink for Version control to the rescue! 🦸" tabindex="-1"></a>Version control to the rescue! <span role="img" aria-label="superhero">🦸</span></h2>
<p>More often than not, the core concepts in the software we write rarely change,
so the documentation tends to be useful even when not entirely accurate.</p>
<p>Combined with <a href="https://git-scm.com/" target="_blank" rel="nofollow noopener noreferrer">source control</a>, even when the comments are
outdated, the original intention is never lost. We can navigate back through
history and get the full context in which the documentation was written.</p>
<p>In the same way we should document our intent in methods, properties, and classes,
it's also important to capture the broader purpose of changes in commits. This
will enable us to <a href="https://git-scm.com/docs/git-blame" target="_blank" rel="nofollow noopener noreferrer">look back to learn more</a>, saving us an
invaluable amount of time when trying to understand past decisions.</p>
<p>As a result, we can move forward with deeper undestanding and confidence,
refactoring or removing code without fear of accidentally breaking the app, or
going against an otherwise long-forgotten decision.</p>
<h2 id="pull-requests-as-the-unit-of-change" class="heading"><a href="#pull-requests-as-the-unit-of-change" class="heading-anchor" aria-label="Permalink for Pull Requests as the unit of change 🧩" tabindex="-1"></a>Pull Requests as the unit of change <span role="img" aria-label="puzzle piece">🧩</span></h2>
<p>Usually in a team environment, the <em>pull request</em> replaces the <em>commit</em> as the <em>unit
of change</em>. Besides providing a platform for code review, pull requests are
great for adding rich non-text information, such as images and video, and
hyperlinks to external resources.</p>
<p>As a result, they also have an immense potential for communication and
documentation. We should leverage the description to explain substantial changes
(<em>why</em> and <em>what for</em>), provide screenshots, and any content that makes it
easier to follow the work.</p>
<p>Doing so will leave a solid trail that can help anyone grasp the full picture
later on, in addition to improving the communication and quality of the reviews.
Two for one!</p>
<h2 id="tldr-document-all-the-things" class="heading"><a href="#tldr-document-all-the-things" class="heading-anchor" aria-label="Permalink for TL&#x27;DR: Document all the things! ✏️ 📖" tabindex="-1"></a>TL'DR: Document all the things! <span role="img" aria-label="pencil">✏️</span> <span role="img" aria-label="open book">📖</span></h2>
<p>Code is read a lot more often than it's written, which is why inline docs
provide a great return for their tiny cost. Same can be said about writing
a nice pull request description, describing specific decisions in comments,
and providing screenshots.</p>
<p>We've saved a lot of time when figuring out how things work, enabled our team to
refactor with confidence, prevented problems and regressions, and made entire
areas of the app more approachable for other developers.</p>
<p>The simple practice of documenting helps junior and senior developers alike, and
after you start using it, you'll be wondering why you didn't start sooner <span role="img" aria-label="grinning face with big eyes">😃</span></p>]]></content>
        <author>
            <name>Máximo Mussini</name>
            <uri>https://maximomussini.com</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Ruby Keywords and the Double Splat Operator]]></title>
        <id>https://maximomussini.com/posts/ruby-double-splat-keywords</id>
        <link href="https://maximomussini.com/posts/ruby-double-splat-keywords"/>
        <updated>2020-01-30T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[One of the nicest bits of syntax sugar in Ruby are keywords. Learn how to get the best out of them.]]></summary>
        <content type="html"><![CDATA[<p>One of the nicest bits of syntax sugar in Ruby are <em>keywords</em> (<code>**</code> or <em>double-splat</em>).</p>
<h2 id="keywords-in-method-parameters" class="heading"><a href="#keywords-in-method-parameters" class="heading-anchor" aria-label="Permalink for Keywords in Method Parameters" tabindex="-1"></a>Keywords in Method Parameters</h2>
<p>Just like the splat operator (<code>*args</code>) captures any parameters as an <code>Array</code> of
arguments, the double-splat operator (<code>**attrs</code>) captures any option parameters
as a <code>Hash</code>.</p>
<p>The nice thing is that it allows to destructure a <code>Hash</code> argument into any of
its individual keys, and mark it as required, or make it optional and provide a
default value for it.</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code><span class="token keyword">def</span> <span class="token method-definition"><span class="token function">greet</span></span><span class="token punctuation">(</span><span class="token symbol">first_name</span><span class="token operator">:</span><span class="token punctuation">,</span> <span class="token symbol">last_name</span><span class="token operator">:</span> <span class="token keyword">nil</span><span class="token punctuation">,</span> <span class="token operator">**</span>attrs<span class="token punctuation">)</span>
  name <span class="token operator">=</span> <span class="token punctuation">[</span>first_name<span class="token punctuation">,</span> attrs<span class="token punctuation">[</span><span class="token symbol">:middle_name</span><span class="token punctuation">]</span><span class="token punctuation">,</span> last_name<span class="token punctuation">]</span><span class="token punctuation">.</span>compact<span class="token punctuation">.</span>join<span class="token punctuation">(</span><span class="token string-literal"><span class="token string">' '</span></span><span class="token punctuation">)</span>
  puts <span class="token string-literal"><span class="token string">"Hi </span><span class="token interpolation"><span class="token delimiter punctuation">#{</span><span class="token content"> name </span><span class="token delimiter punctuation">}</span></span><span class="token string">!"</span></span>
<span class="token keyword">end</span>

greet<span class="token punctuation">(</span><span class="token symbol">first_name</span><span class="token operator">:</span> <span class="token string-literal"><span class="token string">'Gale'</span></span><span class="token punctuation">)</span>
<span class="token comment"># Hi Gale!</span>

greet<span class="token punctuation">(</span><span class="token symbol">last_name</span><span class="token operator">:</span> <span class="token string-literal"><span class="token string">'John'</span></span><span class="token punctuation">)</span>
<span class="token comment"># ArgumentError (missing keyword: first_name)</span>

greet<span class="token punctuation">(</span><span class="token symbol">first_name</span><span class="token operator">:</span> <span class="token string-literal"><span class="token string">'Bruce'</span></span><span class="token punctuation">,</span> <span class="token symbol">middle_name</span><span class="token operator">:</span> <span class="token string-literal"><span class="token string">'Wayne'</span></span><span class="token punctuation">,</span> <span class="token symbol">last_name</span><span class="token operator">:</span> <span class="token string-literal"><span class="token string">'Keaton'</span></span><span class="token punctuation">)</span>
<span class="token comment"># Hi Bruce Wayne Keaton!</span></code></pre></div>
<p>There's one <strong><em>big gotcha</em></strong> which comes up a lot when first learning Ruby:</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code><span class="token keyword">def</span> <span class="token method-definition"><span class="token function">greet</span></span><span class="token punctuation">(</span><span class="token operator">**</span>attrs<span class="token punctuation">)</span>
  puts <span class="token string-literal"><span class="token string">"Hi </span><span class="token interpolation"><span class="token delimiter punctuation">#{</span><span class="token content"> attrs<span class="token punctuation">[</span><span class="token symbol">:name</span><span class="token punctuation">]</span> </span><span class="token delimiter punctuation">}</span></span><span class="token string">!"</span></span>
<span class="token keyword">end</span>

greet
<span class="token comment"># Hi !</span>

greet<span class="token punctuation">(</span><span class="token string-literal"><span class="token string">'name'</span></span> <span class="token operator">=></span> <span class="token string-literal"><span class="token string">'Jane'</span></span><span class="token punctuation">)</span>
<span class="token comment"># ArgumentError (wrong number of arguments (given 1, expected 0))</span></code></pre></div>
<p>Many developers have scratched their heads wondering what's going on, until
they learn the cause of this unintuitive message.</p>
<blockquote>
<p>Only <code>Symbol</code> keys are allowed in keyword arguments <span role="img" aria-label="astonished face">😲</span></p>
</blockquote>
<p>Ruby handles keyword arguments differently in its internals, which unfortunately
leaks into this error message.</p>
<h2 id="merging-hashes-with-the-double-splat-operator" class="heading"><a href="#merging-hashes-with-the-double-splat-operator" class="heading-anchor" aria-label="Permalink for Merging Hashes with the Double-Splat operator" tabindex="-1"></a>Merging Hashes with the Double-Splat operator</h2>
<p>The double-splat operator can also be used to combine hashes. The order matters,
when resolving duplicate keys, the rightmost ones will take priority.</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code>jane <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token symbol">:first_name</span> <span class="token operator">=></span> <span class="token string-literal"><span class="token string">"Jane"</span></span><span class="token punctuation">,</span> <span class="token symbol">:last_name</span> <span class="token operator">=></span> <span class="token string-literal"><span class="token string">"Doe"</span></span> <span class="token punctuation">}</span>

<span class="token punctuation">{</span> <span class="token operator">**</span>jane<span class="token punctuation">,</span> <span class="token symbol">:last_name</span> <span class="token operator">=></span> <span class="token string-literal"><span class="token string">"Johnson"</span></span> <span class="token punctuation">}</span>
<span class="token comment"># { :first_name => "Jane", :last_name => "Johnson" }</span>

<span class="token punctuation">{</span> <span class="token symbol">:last_name</span> <span class="token operator">=></span> <span class="token string-literal"><span class="token string">"Johnson"</span></span><span class="token punctuation">,</span> <span class="token operator">**</span>jane <span class="token punctuation">}</span>
<span class="token comment"># { :last_name => "Doe, :first_name => "Jane" }</span></code></pre></div>
<p>There are a few caveats when combining hashes:</p>
<ul>
<li>It does not combine keys of different types, such as <code>String</code> and <code>Symbol</code>.</li>
<li>It can <strong>only</strong> be used with Hashes where all keys are <code>Symbol</code>s.</li>
</ul>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code>jane <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token symbol">:first_name</span> <span class="token operator">=></span> <span class="token string-literal"><span class="token string">"Jane"</span></span><span class="token punctuation">,</span> <span class="token symbol">:last_name</span> <span class="token operator">=></span> <span class="token string-literal"><span class="token string">"Doe"</span></span> <span class="token punctuation">}</span>
<span class="token punctuation">{</span> <span class="token operator">**</span>jane<span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"first_name"</span></span> <span class="token operator">=></span> <span class="token string-literal"><span class="token string">"John"</span></span> <span class="token punctuation">}</span>
<span class="token comment"># { :first_name => "Jane", :last_name=>"Doe", "first_name"=>"John" }</span>

jane <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token string-literal"><span class="token string">"first_name"</span></span> <span class="token operator">=></span> <span class="token string-literal"><span class="token string">"Jane"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"last_name"</span></span> <span class="token operator">=></span> <span class="token string-literal"><span class="token string">"Doe"</span></span> <span class="token punctuation">}</span>
doe <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token operator">**</span>jane<span class="token punctuation">,</span> <span class="token symbol">first_name</span><span class="token operator">:</span> <span class="token string-literal"><span class="token string">"John"</span></span> <span class="token punctuation">}</span>
<span class="token comment"># TypeError (hash key "first_name" is not a Symbol)</span></code></pre></div>
<p>This message used to be very cryptic like the one for keyword arguments, but it
has improved a lot since the feature was first added <span role="img" aria-label="party popper">🎉</span></p>
<h2 id="a-quick-note-about-rails" class="heading"><a href="#a-quick-note-about-rails" class="heading-anchor" aria-label="Permalink for A quick note about Rails" tabindex="-1"></a>A quick note about Rails</h2>
<p>When using Rails a developer might think:</p>
<blockquote>
<p>I can obtain values from <code>params</code> using <code>Symbol</code> keys, but I can't pass them
as keyword arguments! Thought they were all <em>Symbol</em> keys?</p>
</blockquote>
<p>The short answer is <em>no</em>. In Rails controllers, <code>params</code> is an instance of <em>HashWithIndiferentAccess</em>.
You may index it with <em>Symbol</em> keys but internally it uses <em>String</em> keys.</p>
<p>Fortunately, <code>symbolize_keys</code> is our friend here, allowing us to transform any
Hash, such as HTTP parameters, to something we can pass as keyword arguments.</p>
<h2 id="summary" class="heading"><a href="#summary" class="heading-anchor" aria-label="Permalink for Summary" tabindex="-1"></a>Summary</h2>
<p>So there you have it, <code>**</code> is to <code>Hash</code> what <code>*</code> is to <code>Array</code>, and is a very
convenient tool to write shorter, expressive code.</p>
<p>Just watch out for errors when using non-<code>Symbol</code> keys in keyword arguments,
at least until Ruby improves that error message <span role="img" aria-label="winking face">😉</span></p>]]></content>
        <author>
            <name>Máximo Mussini</name>
            <uri>https://maximomussini.com</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Automatic Trailing Commas for Version Control]]></title>
        <id>https://maximomussini.com/posts/trailing-commas</id>
        <link href="https://maximomussini.com/posts/trailing-commas"/>
        <updated>2019-04-04T02:50:00.000Z</updated>
        <summary type="html"><![CDATA[A useful practice to prevent Git conflicts and keep cleaner diffs.]]></summary>
        <content type="html"><![CDATA[
<p>Today I'd like to share a simple but very useful practice for managing Ruby and
JS code under version control.</p>
<p>In our team, we always use trailing commas when defining multi-line literals for
arrays and hash (object in JS) literals.</p>
<p>It's great that both Ruby and JS allow this in their syntax, because as a result
we are able to get cleaner diffs:</p>
<p><picture><img srcset="/assets/standard-vs-trailing-Kpi0YqbB.svg" src="/assets/standard-vs-trailing-Kpi0YqbB.svg" class="img" loading="lazy" alt="Standard vs Trailing"></picture></p>
<p>Notice how the same code change results in a drastically simpler diff: <em>adding
or removing an item changes a single line, nothing more</em>.</p>
<h2 id="other-benefits" class="heading"><a href="#other-benefits" class="heading-anchor" aria-label="Permalink for Other Benefits 👩‍💻👨‍💻" tabindex="-1"></a>Other Benefits <span role="img" aria-label="woman technologist">👩‍💻</span><span role="img" aria-label="man technologist">👨‍💻</span></h2>
<p>Reordering lines, or sorting them alphabetically with the help of an editor
(like <a href="https://www.sublimetext.com/" target="_blank" rel="nofollow noopener noreferrer"><em>Sublime Text</em></a>), will always result in valid code,
without the need to manually add the missing comma to avoid a syntax error.</p>
<p>Also, conflicts in <a href="https://git-scm.com/" target="_blank" rel="nofollow noopener noreferrer">source control</a> are less likely to happen,
since each line change becomes independent, unlike the usual approach where we
are actually removing the last line without a comma to add two lines.</p>
<p>Finally, tools like <a href="https://git-scm.com/docs/git-blame" target="_blank" rel="nofollow noopener noreferrer"><code>git blame</code></a> are more likely to display relevant commit
information, rather than the commit that added the comma.</p>
<h2 id="automation" class="heading"><a href="#automation" class="heading-anchor" aria-label="Permalink for Automation 🤖" tabindex="-1"></a>Automation <span role="img" aria-label="robot">🤖</span></h2>
<p>To make this practice effortless, we have modified the configuration of the
static analysis tools (<em><a href="https://github.com/rubocop-hq/rubocop" target="_blank" rel="nofollow noopener noreferrer">Rubocop</a></em> and <em><a href="https://eslint.org/" target="_blank" rel="nofollow noopener noreferrer">ESLint</a></em>),
to require trailing commas in multi-line literals.</p>
<p>We have also set up <a href="https://github.com/guard/guard" target="_blank" rel="nofollow noopener noreferrer"><code>Guard</code></a> to listen for file changes and automatically run
the tools with <code>--autofix</code>, so that commas are automatically added when we
forget; we don't really need to think about it.</p>
<p>In <em>ESLint</em> for JS:</p>
<div class="language-js" data-lang="js"><pre class="language-js"><code>  <span class="token string-property property">"comma-dangle"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"error"</span><span class="token punctuation">,</span> <span class="token string">"always-multiline"</span><span class="token punctuation">]</span><span class="token punctuation">,</span></code></pre></div>
<p>In <em>Rubocop</em> for Ruby:</p>
<div class="language-yaml" data-lang="yaml"><pre class="language-yaml"><code><span class="token key atrule">Style/TrailingCommaInArrayLiteral</span><span class="token punctuation">:</span>
  <span class="token key atrule">EnforcedStyleForMultiline</span><span class="token punctuation">:</span> comma

<span class="token key atrule">Style/TrailingCommaInHashLiteral</span><span class="token punctuation">:</span>
  <span class="token key atrule">EnforcedStyleForMultiline</span><span class="token punctuation">:</span> comma

<span class="token key atrule">Style/TrailingCommaInArguments</span><span class="token punctuation">:</span>
  <span class="token key atrule">EnforcedStyleForMultiline</span><span class="token punctuation">:</span> comma</code></pre></div>
<p>An example <code>Guardfile</code> configuration:</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code><span class="token comment"># Run Rubocop every time we change a file, and autofix it if possible.</span>
guard <span class="token symbol">:rubocop</span><span class="token punctuation">,</span> <span class="token symbol">all_on_start</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token symbol">cli</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string-literal"><span class="token string">'-a'</span></span><span class="token punctuation">]</span> <span class="token keyword">do</span>
  <span class="token operator">...</span></code></pre></div>
<h2 id="summary" class="heading"><a href="#summary" class="heading-anchor" aria-label="Permalink for Summary" tabindex="-1"></a>Summary</h2>
<p>Using trailing commas in multi-line literals results in code that is
syntactically more stable to changes, and keeps a cleaner history in source control.</p>
<p>Developers make less syntax errors, since they can add and remove items, sort or
reorder them, without having to manage missing (or extra) trailing commas.</p>
<p>We've been using this approach for years now, and haven't run into any issues in
practice. It's been great so far <span role="img" aria-label="grinning face with big eyes">😃</span></p>]]></content>
        <author>
            <name>Máximo Mussini</name>
            <uri>https://maximomussini.com</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Better Settings in Ruby apps]]></title>
        <id>https://maximomussini.com/posts/better-settings</id>
        <link href="https://maximomussini.com/posts/better-settings"/>
        <updated>2019-03-02T16:32:00.000Z</updated>
        <summary type="html"><![CDATA[A safe and robust settings library for Ruby apps. Immutable, predictable, and error-friendly.]]></summary>
        <content type="html"><![CDATA[<p><a href="https://github.com/ElMassimo/better_settings" target="_blank" rel="nofollow noopener noreferrer"><em>BetterSettings</em></a> is a settings-management library for Ruby apps, which was
designed in response to certain issues we faced when using <a href="https://github.com/settingslogic/settingslogic" target="_blank" rel="nofollow noopener noreferrer"><em>settingslogic</em></a>
(one of the most popular libraries to manage settings in Rails applications).</p>
<p>In this post we'll talk about <em>settingslogic</em> and its design decisions, how they
affect reliability, and how we can overcome them.</p>
<p>Even if you are not familiar with these libraries, reading this article might
help you to learn about potentially harmful practices, and how to avoid them in
your own code.</p>
<h2 id="settingslogic" class="heading"><a href="#settingslogic" class="heading-anchor" aria-label="Permalink for Settingslogic" tabindex="-1"></a>Settingslogic</h2>
<p><em>Settingslogic</em> can read a <em>.yml</em> file and turn it into a Ruby object, which
provides access to settings by indexing it as a Hash, or by using method calls.</p>
<h3 id="settings-can-be-modified" class="heading"><a href="#settings-can-be-modified" class="heading-anchor" aria-label="Permalink for Settings can be modified" tabindex="-1"></a>Settings can be modified</h3>
<p>The library aims to be flexible, by allowing to create a setting that is not
present in the file or modify an existing one, by using:</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code>Settings<span class="token punctuation">[</span><span class="token string-literal"><span class="token string">'property'</span></span><span class="token punctuation">]</span> <span class="token operator">||=</span> <span class="token string-literal"><span class="token string">'value'</span></span></code></pre></div>
<p>Although it might seem like a good idea, this behavior introduces uncertainty
about whether a setting will be available or not when accessing it, and the
value it might have, since that depends on the execution order of the program.</p>
<p>Because the library is not thread-safe, modifying settings makes them suceptible
to race conditions in multi-threaded apps or multi-threaded app containers.</p>
<h3 id="values-are-mutable" class="heading"><a href="#values-are-mutable" class="heading-anchor" aria-label="Permalink for Values are mutable" tabindex="-1"></a>Values are mutable</h3>
<p>Even when not creating or modifying a setting at runtime, the values read from
the <em>.yml</em> file can be accidentally modified since the settings are not frozen
(specially <code>String</code>, <code>Hash</code>, and <code>Array</code> values).</p>
<p>For example, when working with a <code>Hash</code> or <code>Array</code> setting, calling <code>merge!</code> or
<code>push</code> causes the setting to be changed on every subsequent access, which can
have unpredictable consequences in the application.</p>
<p>These accidental mutations are usually very hard to detect, and can cause bugs
that are difficult to replicate and track down.</p>
<p>Writing code carefully to avoid mutating the data structures is not enough,
since we have no guarantee that third-party libraries will be as careful. To
solve this we would need to always clone settings before handing them over,
which is cumbersome and error-prone.</p>
<h3 id="limited-to-a-single-file" class="heading"><a href="#limited-to-a-single-file" class="heading-anchor" aria-label="Permalink for Limited to a single file" tabindex="-1"></a>Limited to a single file</h3>
<p>Only one <em>.yml</em> file can be specified, so there's no way to read configuration
from multiple files. Because settings are necessary to run the application, it's
important that the file is versioned under source control.</p>
<p>In our case, this meant that when developers changed a setting based on their
local setup, or to perform a manual test, they had to manually skip it when
making a commit.</p>
<p>As a result, many times a developer would accidentally push these changes that
should not be merged upstream, and we had to be on the lookout during code
reviews to prevent unwanted changes.</p>
<h3 id="error-prone-design" class="heading"><a href="#error-prone-design" class="heading-anchor" aria-label="Permalink for Error-prone design" tabindex="-1"></a>Error-prone design</h3>
<p>These problems we experienced with <em>settingslogic</em>, related with reliability and
collaboration, are a consequence of the design decisions in the library.</p>
<p>The library defaults are troublesome, such as deferring the load of the <em>.yml</em>
file until the settings are accessed, making it possible for an app to start
successfully and fail later at runtime.</p>
<p>In the end, it has the same disadvantages of simpler approaches, like using a
plain <code>OpenStruct</code> to manage settings.</p>
<h2 id="a-better-way" class="heading"><a href="#a-better-way" class="heading-anchor" aria-label="Permalink for A Better Way" tabindex="-1"></a>A <em>Better</em> Way</h2>
<p>With that in mind, we decided to design a new solution from scratch, that could
handle these shortcomings, and actively prevent bugs and misusage.</p>
<p>The result is <a href="https://github.com/ElMassimo/better_settings" target="_blank" rel="nofollow noopener noreferrer"><em><code>BetterSettings</code></em></a>, designed after the following concerns:</p>
<ul>
<li><strong>Predictability</strong>: Once created, settings can not be added or modified, which
prevents race conditions and makes usage safe and predictable.</li>
<li><strong>Immutability</strong>: All setting values are frozen, preventing an entire category
of bugs related to accidental mutation.</li>
<li><strong>Multiple sources</strong>: Settings can be read from different files. This allows
to split settings as needed, or create additional files for development purposes.</li>
<li><strong>Better errors</strong>: Accessing a missing setting is treated as an error, helping
developers to easily detect typos and other mistakes with a clear error message.</li>
<li><strong>Fail-fast</strong>: Source files should be eager loaded by default, so that
problems in the environment are detected during deployment.</li>
</ul>
<p>The setup for the <em>.yml</em> file is very similar to <em>settingslogic</em>, you can find
more information and examples in the <a href="https://github.com/ElMassimo/better_settings" target="_blank" rel="nofollow noopener noreferrer">README</a>.</p>
<h3 id="how-does-it-work" class="heading"><a href="#how-does-it-work" class="heading-anchor" aria-label="Permalink for How does it work?" tabindex="-1"></a>How does it work?</h3>
<p>Internally, settings are stored in a frozen <code>Hash</code>, which is an instance
variable in the <code>BetterSettings</code> object. We delegate <code>to_h</code> to this internal
hash for easy access, but other than that, we don't expose any <code>Hash</code> methods.</p>
<p>We go through every hash <em>entry</em>, processing any nested <code>Array</code> and <code>Hash</code> objects,
freezing every wrapped <em>value</em>, setting it in an instance variable, and making it
accessible by defining a getter for that <em>key</em>.</p>
<p>It's worth noting that we wrap nested <code>Hash</code> values in instances of your
<code>BetterSettings</code> class, which will recursively repeat the process.</p>
<p>As a result, the entire settings graph is readable but immutable, and each
nested object exposes getters for the available keys.</p>
<p>To make errors a bit friendlier, we implement <code>method_missing</code> to provide
context on where a setting is missing, instead of an unhelpful <code>NoMethodError</code>.</p>
<p>Finally, we sprinkle some syntax sugar by making every top-level key available
as a method in the <code>Settings</code> class, by delegating it to a <code>root_settings</code>
instance that is populated when calling <code>source</code> in the class.</p>
<h3 id="reading-from-multiple-files-⚙" class="heading"><a href="#reading-from-multiple-files-⚙" class="heading-anchor" aria-label="Permalink for Reading from multiple files ⚙" tabindex="-1"></a>Reading from multiple files ⚙</h3>
<p>Not being limited to a single source file opens up the possiblities.</p>
<p>We usually read two optional files: <code>development.yml</code> and <code>test.yml</code> that are
loaded in the <em>development</em> and <em>test</em> environments respectively, allowing each
developer to easily override settings in their local setup.</p>
<p>In a Rails app with the typical setup, the configuration looks like this:</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code><span class="token keyword">class</span> <span class="token class-name">Settings</span> <span class="token operator">&lt;</span> BetterSettings
  source Rails<span class="token punctuation">.</span>root<span class="token punctuation">.</span>join<span class="token punctuation">(</span><span class="token string-literal"><span class="token string">'config/application.yml'</span></span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token symbol">namespace</span><span class="token operator">:</span> Rails<span class="token punctuation">.</span>env

  <span class="token keyword">if</span> Rails<span class="token punctuation">.</span>env<span class="token punctuation">.</span>development<span class="token operator">?</span>
    source Rails<span class="token punctuation">.</span>root<span class="token punctuation">.</span>join<span class="token punctuation">(</span><span class="token string-literal"><span class="token string">'config/development.yml'</span></span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token symbol">namespace</span><span class="token operator">:</span> Rails<span class="token punctuation">.</span>env<span class="token punctuation">,</span> <span class="token symbol">optional</span><span class="token operator">:</span> <span class="token boolean">true</span>
  <span class="token keyword">end</span>

  <span class="token keyword">if</span> Rails<span class="token punctuation">.</span>env<span class="token punctuation">.</span>test<span class="token operator">?</span>
    source Rails<span class="token punctuation">.</span>root<span class="token punctuation">.</span>join<span class="token punctuation">(</span><span class="token string-literal"><span class="token string">'config/test.yml'</span></span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token symbol">namespace</span><span class="token operator">:</span> Rails<span class="token punctuation">.</span>env<span class="token punctuation">,</span> <span class="token symbol">optional</span><span class="token operator">:</span> <span class="token boolean">true</span>
  <span class="token keyword">end</span>
<span class="token keyword">end</span></code></pre></div>
<p>Having a <code>development.yml</code> file comes in handy when making changes that should
not be shared, such as a temporary change to test a different configuration, or
a permanent one that is only relevant in a specific local setup (such as
different host names or port numbers).</p>
<p>This could also be achieved by reading environment variables (<a href="#environment-variables">see the next
section</a>), but for development using an optional file is
more convenient, as it's located in the same folder than the main one, and
settings can be copied and tweaked.</p>
<p>On the other hand, <code>test.yml</code> makes it possible to configure tests to run with a
different formatter for the results, or configure optional behavior, like
automatically opening the screenshots that are captured when integration tests
fail.</p>
<p>This flexibility enables us to provide awesome defaults, while still allowing
everyone to modify the configuration according to their personal preference or
local setup, without having to worry about pushing those changes by accident.</p>
<h3 id="environment-variables" class="heading"><a href="#environment-variables" class="heading-anchor" aria-label="Permalink for Environment Variables" tabindex="-1"></a>Environment Variables</h3>
<p>In server environments, such as <em>staging</em> and <em>production</em>, we use environment
variables for any sensitive information, such as passwords.</p>
<p>In order to ensure that missing environment variables are quickly detected, we
use this simple helper:</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code><span class="token keyword">module</span> <span class="token class-name">Env</span>
  <span class="token comment"># Public: Read an environment variable by name.</span>
  <span class="token comment"># NOTE: Defaults are only used in the development and test environments.</span>
  <span class="token keyword">def</span> <span class="token method-definition"><span class="token keyword">self</span><span class="token punctuation">.</span><span class="token function">require</span></span><span class="token punctuation">(</span><span class="token operator">*</span>args<span class="token punctuation">,</span> <span class="token operator">&amp;</span>block<span class="token punctuation">)</span>
    <span class="token keyword">if</span> Rails<span class="token punctuation">.</span>env<span class="token punctuation">.</span>development<span class="token operator">?</span> <span class="token operator">||</span> Rails<span class="token punctuation">.</span>env<span class="token punctuation">.</span>test<span class="token operator">?</span>
      <span class="token constant">ENV</span><span class="token punctuation">.</span>fetch<span class="token punctuation">(</span><span class="token operator">*</span>args<span class="token punctuation">,</span> <span class="token operator">&amp;</span>block<span class="token punctuation">)</span>
    <span class="token keyword">else</span>
      <span class="token constant">ENV</span><span class="token punctuation">.</span>fetch<span class="token punctuation">(</span>args<span class="token punctuation">.</span>first<span class="token punctuation">)</span>
    <span class="token keyword">end</span>
  <span class="token keyword">end</span>
<span class="token keyword">end</span></code></pre></div>
<p>and then in <code>application.yml</code>:</p>
<div class="language-yaml" data-lang="yaml"><pre class="language-yaml"><code><span class="token key atrule">mailer</span><span class="token punctuation">:</span> &lt;%= Env.require('MAILER_PORT'<span class="token punctuation">,</span> 587) %<span class="token punctuation">></span></code></pre></div>
<p>By using this helper, we can be very <em>strict on servers</em>－where we need
everything to be configured (such as hosts, ports, and third-party integrations)－and
<em>lenient in development</em>－where we can just provide a default value and then
override it by using <code>development.yml</code> if necessary.</p>
<p>We prefer this pattern over using <code>ENV.fetch</code> with a default value as a
fallback, since that would cover up a missing environment variable in the servers.</p>
<h2 id="summary" class="heading"><a href="#summary" class="heading-anchor" aria-label="Permalink for Summary" tabindex="-1"></a>Summary</h2>
<p>So there you have it, <a href="https://github.com/ElMassimo/better_settings" target="_blank" rel="nofollow noopener noreferrer"><em>BetterSettings</em></a> is a settings solution
for Ruby apps that encourages good practices, is friendlier for team
collaboration and source-control, and prevents bugs.</p>
<p><a href="https://github.com/ElMassimo/better_settings" target="_blank" rel="nofollow noopener noreferrer"><em><code>BetterSettings</code></em></a>: simple, immutable, better.</p>]]></content>
        <author>
            <name>Máximo Mussini</name>
            <uri>https://maximomussini.com</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[i18n Multitenancy: Customer-Specific Translations]]></title>
        <id>https://maximomussini.com/posts/i18n-multitenant</id>
        <link href="https://maximomussini.com/posts/i18n-multitenant"/>
        <updated>2017-01-26T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[A hack to manage customer-specific jargon using i18n.]]></summary>
        <content type="html"><![CDATA[<p>When providing services to different companies or customers with the same
software, such as enterprise or white-label applications, it's not unusual that
each customer uses different terminology for certain concepts within the application.</p>
<p>While they might be similar in terms of operations and transactions, different
domains will often use different jargon, and as a result, prefer different names
for a given feature or aspect of an application.</p>
<p>For example, a concept that in our application is <em>"person"</em>, might be referred to
as <em>"user"</em>, <em>"customer"</em>, or <em>"employee"</em>, based on the language of their specific
domain, or when using their <em>in-house</em> terminology.</p>
<p>Using the same terms than our users in their every day routine can help to make
the software feel more natural and easier to grasp, lowering the adoption
barrier and reducing the resistance to change in large organizations.</p>
<blockquote>
<p>...fits right in with our usual flow.</p>
</blockquote>
<h2 id="using-i18n-fallbacks" class="heading"><a href="#using-i18n-fallbacks" class="heading-anchor" aria-label="Permalink for Using i18n fallbacks 🌎" tabindex="-1"></a>Using i18n fallbacks <span role="img" aria-label="globe showing Americas">🌎</span></h2>
<p>Fortunately, we can easily accomplish this by leveraging the existing i18n tools
that are available in most platforms.</p>
<p>Just like we might allow a customer to switch between American or British
variants of the English language (<code>en-US</code> and <code>en-UK</code>), we can create additional
language-variants or locales for each customer or domain (<code>en-LAW</code>):</p>
<div class="language-yaml" data-lang="yaml"><pre class="language-yaml"><code>en<span class="token punctuation">-</span>LAW
  <span class="token key atrule">customer</span><span class="token punctuation">:</span> client</code></pre></div>
<p>We can then use i18n fallbacks, so that any keys that are not defined in our
domain-specific locale <em>fall back</em> to the usual definition in the language.</p>
<p>In the example above, any users that have the <code>LAW</code> translation preset assigned
would see <em>"client"</em>, but other users might see <em>"customer"</em>.</p>
<p>This allows us to achieve a nice balance between configurability and productivity.</p>
<p>By managing these text overrides within the translation engine, it becomes
almost effortless to dynamically customize the language used in the app.</p>
<p>Dictionaries for different domains or specific customers can be added with ease,
and it becomes easier to test all the different combinations in the application.</p>
<h2 id="a-solution-for-ruby-apps" class="heading"><a href="#a-solution-for-ruby-apps" class="heading-anchor" aria-label="Permalink for A solution for Ruby apps 💎" tabindex="-1"></a>A solution for Ruby apps <span role="img" aria-label="gem stone">💎</span></h2>
<p>I have wrapped a Ruby solution as the <a href="https://github.com/ElMassimo/i18n_multitenant" target="_blank" rel="nofollow noopener noreferrer"><code>i18n_multitenant</code></a> gem.
Please <a href="https://github.com/ElMassimo/i18n_multitenant" target="_blank" rel="nofollow noopener noreferrer">check the readme</a> for a more thorough explanation of
how language variants are used, and a few examples on how to organize
translations in order to effectively implement the approach.</p>
<h3 id="what-about-translations-in-the-browser" class="heading"><a href="#what-about-translations-in-the-browser" class="heading-anchor" aria-label="Permalink for What about translations in the browser?" tabindex="-1"></a>What about translations in the browser?</h3>
<p>For single-page applications or other apps where it's desirable to perform the
translations in the browser, we can use a library such as <a href="https://github.com/fnando/i18n-js" target="_blank" rel="nofollow noopener noreferrer"><code>i18n-js</code></a>.</p>
<p>It's possible to <a href="https://github.com/ElMassimo/i18n_multitenant#front-end_translations" target="_blank" rel="nofollow noopener noreferrer">configure it to use fallbacks</a>,
allowing us to reuse the same translation files in the JS world.</p>
<h2 id="summary" class="heading"><a href="#summary" class="heading-anchor" aria-label="Permalink for Summary" tabindex="-1"></a>Summary</h2>
<p><code>i18n</code> fallbacks provide a simple way to adapt the terminology used in our
software based on different domains and users needs, making it <em>feel more familiar</em>
and easier to use <em>without restricting the software's flexibility</em>.</p>]]></content>
        <author>
            <name>Máximo Mussini</name>
            <uri>https://maximomussini.com</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Aggregation DSL in Mongoid]]></title>
        <id>https://maximomussini.com/posts/mongoid-aggregation-dsl</id>
        <link href="https://maximomussini.com/posts/mongoid-aggregation-dsl"/>
        <updated>2016-06-30T19:19:00.000Z</updated>
        <summary type="html"><![CDATA[Unlock the powerful aggregation DSL that is hiding within Mongoid by adding a few extensions.]]></summary>
        <content type="html"><![CDATA[<p><em>Mongoid</em> provides support for <a href="https://docs.mongodb.com/manual/core/aggregation-pipeline/" target="_blank" rel="nofollow noopener noreferrer"><em>MongoDB's Aggregation Framework</em></a>, but writing raw queries can be confusing and is extremely verbose:</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code>Product<span class="token punctuation">.</span>collection<span class="token punctuation">.</span>aggregate <span class="token punctuation">[</span>
  <span class="token punctuation">{</span> <span class="token string-literal"><span class="token string">'$match'</span></span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token string-literal"><span class="token string">'country'</span></span> <span class="token operator">=></span> <span class="token string-literal"><span class="token string">'US'</span></span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">{</span> <span class="token string-literal"><span class="token string">'$project'</span></span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token string-literal"><span class="token string">'categories'</span></span> <span class="token operator">=></span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">'price'</span></span> <span class="token operator">=></span> <span class="token number">1</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">{</span> <span class="token string-literal"><span class="token string">'$unwind'</span></span> <span class="token operator">=></span> <span class="token string-literal"><span class="token string">'$category_ids'</span></span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">{</span>
    <span class="token string-literal"><span class="token string">'$group'</span></span> <span class="token operator">=></span> <span class="token punctuation">{</span>
      <span class="token string-literal"><span class="token string">'_id'</span></span> <span class="token operator">=></span> <span class="token string-literal"><span class="token string">'$category_ids'</span></span><span class="token punctuation">,</span>
      <span class="token string-literal"><span class="token string">'avg_price'</span></span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token string-literal"><span class="token string">'$avg'</span></span> <span class="token operator">=></span> <span class="token string-literal"><span class="token string">'$price'</span></span> <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">{</span> <span class="token string-literal"><span class="token string">'$sort'</span></span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token string-literal"><span class="token string">'avg_price'</span></span> <span class="token operator">=></span> <span class="token operator">-</span><span class="token number">1</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">{</span> <span class="token string-literal"><span class="token string">'$limit'</span></span> <span class="token operator">=></span> <span class="token number">30</span> <span class="token punctuation">}</span>
<span class="token punctuation">]</span></code></pre></div>
<p>Turns out <a href="https://github.com/mongoid/origin" target="_blank" rel="nofollow noopener noreferrer"><em>Origin</em></a>—the gem that powers <em>Mongoid's</em> query DSL—already provides methods for each aggregation operation. The only problem is that it doesn't provide a way to execute the aggregation, and there's no documentation about it <span role="img" aria-label="grimacing face">😬</span></p>
<p>Every aggregation method call adds an operation to an internal pipeline, which we can manually retrieve by calling the <code>pipeline</code> method:</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code>products <span class="token operator">=</span> Product<span class="token punctuation">.</span>where<span class="token punctuation">(</span><span class="token symbol">country</span><span class="token operator">:</span> <span class="token symbol">:US</span><span class="token punctuation">)</span><span class="token punctuation">.</span>
  project<span class="token punctuation">(</span><span class="token symbol">categories</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token symbol">price</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">.</span>
  unwind<span class="token punctuation">(</span><span class="token string-literal"><span class="token string">'$category_ids'</span></span><span class="token punctuation">)</span><span class="token punctuation">.</span>
  group<span class="token punctuation">(</span><span class="token symbol">_id</span><span class="token operator">:</span> <span class="token string-literal"><span class="token string">'$category_ids'</span></span><span class="token punctuation">,</span> <span class="token symbol">:avg_price</span><span class="token punctuation">.</span>avg <span class="token operator">=></span> <span class="token string-literal"><span class="token string">'$price'</span></span><span class="token punctuation">)</span><span class="token punctuation">.</span>
  desc<span class="token punctuation">(</span><span class="token symbol">:avg_price</span><span class="token punctuation">)</span><span class="token punctuation">.</span>
  limit<span class="token punctuation">(</span><span class="token number">30</span><span class="token punctuation">)</span>

products<span class="token punctuation">.</span>pipeline
<span class="token comment"># {"$match"=>{"country"=>:US}}</span>
<span class="token comment"># {"$project"=>{"categories"=>1, "price"=>1}}</span>
<span class="token comment"># {"$unwind"=>"$category_ids"}</span>
<span class="token comment"># {"$group"=>{"_id"=>"$category_ids", "avg_price"=>{"$avg"=>"$price"}}}</span>
<span class="token comment"># {"$sort"=>{"avg_price"=>-1}}</span>
<span class="token comment"># {"$limit"=>30}</span></code></pre></div>
<p>Notice how using the DSL we obtain the same aggregation pipeline that we have in the first example, except it's way more concise, and we are able to use <code>Symbol</code> extensions like <code>avg</code>, <code>max</code>, or <code>add_to_set</code>, which add a great deal of expressiveness and make our queries more concise.</p>
<p>Now all we have to do is pass the pipeline to the <code>aggregate</code> method:</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code>Product<span class="token punctuation">.</span>collection<span class="token punctuation">.</span>aggregate products<span class="token punctuation">.</span>pipeline</code></pre></div>
<p>We can add a little syntax sugar using refinements and make it even more convenient:</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code><span class="token keyword">module</span> <span class="token class-name">AggregationRefinements</span>
  refine Mongoid<span class="token double-colon punctuation">::</span>Criteria <span class="token keyword">do</span>
    <span class="token keyword">def</span> <span class="token method-definition"><span class="token function">aggregate</span></span>
      collection<span class="token punctuation">.</span>aggregate pipeline
    <span class="token keyword">end</span>
  <span class="token keyword">end</span>
<span class="token keyword">end</span>

using AggregationRefinements

Product<span class="token punctuation">.</span>project<span class="token punctuation">(</span><span class="token symbol">categories</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token symbol">price</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">.</span>
  unwind<span class="token punctuation">(</span><span class="token string-literal"><span class="token string">'$category_ids'</span></span><span class="token punctuation">)</span><span class="token punctuation">.</span>
  group<span class="token punctuation">(</span><span class="token symbol">_id</span><span class="token operator">:</span> <span class="token string-literal"><span class="token string">'$category_ids'</span></span><span class="token punctuation">,</span> <span class="token symbol">:avg_price</span><span class="token punctuation">.</span>avg <span class="token operator">=></span> <span class="token string-literal"><span class="token string">'$price'</span></span><span class="token punctuation">)</span><span class="token punctuation">.</span>
  aggregate</code></pre></div>
<p>Or if you are using <a href="https://github.com/ElMassimo/queryable" target="_blank" rel="nofollow noopener noreferrer"><strong>query objects</strong></a>, it's as simple as adding a method to the objects where you need to perform aggregations:</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code><span class="token keyword">def</span> <span class="token method-definition"><span class="token function">aggregate</span></span>
  queryable<span class="token punctuation">.</span>collection<span class="token punctuation">.</span>aggregate<span class="token punctuation">(</span>queryable<span class="token punctuation">.</span>pipeline<span class="token punctuation">)</span>
<span class="token keyword">end</span></code></pre></div>
<p>Now we can enjoy <em>Mongoid's</em> fluent DSL for aggregations <span role="img" aria-label="grinning face with big eyes">😃</span></p>]]></content>
        <author>
            <name>Máximo Mussini</name>
            <uri>https://maximomussini.com</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Class Instance Variables in Ruby]]></title>
        <id>https://maximomussini.com/posts/ruby-class-variables</id>
        <link href="https://maximomussini.com/posts/ruby-class-variables"/>
        <updated>2016-05-31T00:10:00.000Z</updated>
        <summary type="html"><![CDATA[Learn the difference between class variables and class instance variables.]]></summary>
        <content type="html"><![CDATA[<p>Like most object-oriented languages, Ruby has both instance and class variables. The syntax is <code>@name</code> for <em>instance variables</em>, and <code>@@name</code> for <em>class variables</em>.</p>
<p>Let's look at a simple example to understand how we might use <em>class variables</em>:</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code><span class="token keyword">class</span> <span class="token class-name">Animal</span>
  <span class="token variable">@@animals</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>

  <span class="token keyword">def</span> <span class="token method-definition"><span class="token keyword">self</span><span class="token punctuation">.</span><span class="token function">all</span></span>
    <span class="token variable">@@animals</span>
  <span class="token keyword">end</span>

  <span class="token keyword">def</span> <span class="token method-definition"><span class="token function">other_species</span></span>
    <span class="token variable">@@animals</span> <span class="token operator">-</span> <span class="token punctuation">[</span><span class="token keyword">self</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">]</span>
  <span class="token keyword">end</span>
<span class="token keyword">end</span>

<span class="token keyword">class</span> <span class="token class-name">Dog</span> <span class="token operator">&lt;</span> Animal
  <span class="token variable">@@animals</span> <span class="token operator">&lt;&lt;</span> <span class="token keyword">self</span>
<span class="token keyword">end</span>

<span class="token keyword">class</span> <span class="token class-name">Cat</span> <span class="token operator">&lt;</span> Animal
  <span class="token variable">@@animals</span> <span class="token operator">&lt;&lt;</span> <span class="token keyword">self</span>
<span class="token keyword">end</span>

Animal<span class="token punctuation">.</span>all
<span class="token comment"># [Dog, Cat]</span>

<span class="token class-name">Cat</span><span class="token punctuation">.</span><span class="token keyword">new</span><span class="token punctuation">.</span>other_species
<span class="token comment"># [Dog]</span>

<span class="token class-name">Dog</span><span class="token punctuation">.</span><span class="token keyword">new</span><span class="token punctuation">.</span>other_species
<span class="token comment"># [Cat]</span></code></pre></div>
<p>The <code>@@animals</code> <em>class variable</em> is <strong>shared</strong> among subclasses, and we can refer to it by using the same syntax from both class and instance methods.</p>
<h2 id="limitations-of-class-variables" class="heading"><a href="#limitations-of-class-variables" class="heading-anchor" aria-label="Permalink for Limitations of Class Variables" tabindex="-1"></a>Limitations of Class Variables</h2>
<p>Now, what happens if we wanted to do something different, like storing metadata or configuration in each subclass?</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code><span class="token keyword">class</span> <span class="token class-name">Animal</span>
  <span class="token variable">@@sound</span> <span class="token operator">=</span> <span class="token string-literal"><span class="token string">'?'</span></span>

  <span class="token keyword">def</span> <span class="token method-definition"><span class="token function">talk</span></span>
    <span class="token variable">@@sound</span>
  <span class="token keyword">end</span>
<span class="token keyword">end</span>

<span class="token keyword">class</span> <span class="token class-name">Dog</span> <span class="token operator">&lt;</span> Animal
  <span class="token variable">@@sound</span> <span class="token operator">=</span> <span class="token string-literal"><span class="token string">'woof!'</span></span>
<span class="token keyword">end</span>

<span class="token keyword">class</span> <span class="token class-name">Cat</span> <span class="token operator">&lt;</span> Animal
  <span class="token variable">@@sound</span> <span class="token operator">=</span> <span class="token string-literal"><span class="token string">'meow!'</span></span>
<span class="token keyword">end</span>

<span class="token class-name">Dog</span><span class="token punctuation">.</span><span class="token keyword">new</span><span class="token punctuation">.</span>talk
<span class="token comment"># "meow!"</span>

<span class="token class-name">Cat</span><span class="token punctuation">.</span><span class="token keyword">new</span><span class="token punctuation">.</span>talk
<span class="token comment"># "meow!"</span></code></pre></div>
<p>Because <em>class variables</em> are shared between the parent class and its subclasses, the value of <code>@@sound</code> gets stepped over by the last subclass, rather than it taking a different value for each subclass as intended.</p>
<h2 id="class-instance-variables" class="heading"><a href="#class-instance-variables" class="heading-anchor" aria-label="Permalink for Class Instance Variables" tabindex="-1"></a>Class Instance Variables</h2>
<p>Fortunately, there's a simple way to achieve this in Ruby:</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code><span class="token keyword">class</span> <span class="token class-name">Animal</span>
  <span class="token keyword">def</span> <span class="token method-definition"><span class="token keyword">self</span><span class="token punctuation">.</span><span class="token function">sound</span></span>
    <span class="token variable">@sound</span>
  <span class="token keyword">end</span>

  <span class="token keyword">def</span> <span class="token method-definition"><span class="token function">talk</span></span>
    <span class="token keyword">self</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">.</span>sound
  <span class="token keyword">end</span>
<span class="token keyword">end</span>

<span class="token keyword">class</span> <span class="token class-name">Dog</span> <span class="token operator">&lt;</span> Animal
  <span class="token variable">@sound</span> <span class="token operator">=</span> <span class="token string-literal"><span class="token string">'woof!'</span></span>
<span class="token keyword">end</span>

<span class="token keyword">class</span> <span class="token class-name">Cat</span> <span class="token operator">&lt;</span> Animal
  <span class="token variable">@sound</span> <span class="token operator">=</span> <span class="token string-literal"><span class="token string">'meow!'</span></span>
<span class="token keyword">end</span>

<span class="token class-name">Dog</span><span class="token punctuation">.</span><span class="token keyword">new</span><span class="token punctuation">.</span>talk
<span class="token comment"># 'woof!'</span>

<span class="token class-name">Cat</span><span class="token punctuation">.</span><span class="token keyword">new</span><span class="token punctuation">.</span>talk
<span class="token comment"># 'meow!'</span></code></pre></div>
<p>By using instance variables, each subclass gets its own variable so <code>@sound</code> does not get stepped over, and each subclass can configure the variable as needed. So, <em>how does it work</em>?</p>
<blockquote>
<p>Classes in Ruby are plain objects, instances of the <code>Class</code> class.</p>
</blockquote>
<p>Let that sink in for a bit <span role="img" aria-label="grinning face with smiling eyes">😄</span></p>
<blockquote>
<p>Because each class is an object, it can have instance variables just like any other Ruby object.</p>
</blockquote>
<p>Although they are often called <em>class instance variables</em> to differentiate them from actual <em>class variables</em>, there's nothing special about them—they are just plain ole' instance variables.</p>
<p>The key practical difference is that <em>class variables</em> (<code>@@</code>) are shared among a class and all of its descendants, whereas <em>class instance variables</em> (<code>@</code>) are not shared and each class has separate instance variables just like you would expect from different objects.</p>
<h3 id="limitations-of-class-instance-variables" class="heading"><a href="#limitations-of-class-instance-variables" class="heading-anchor" aria-label="Permalink for Limitations of Class Instance Variables" tabindex="-1"></a>Limitations of Class Instance Variables</h3>
<p>It's worth noting that in the last example we lost the convenience of referencing the <code>@sound</code> variable directly on the <code>talk</code> method like we did in the <a href="#limitations-of-class-variables">second example</a>, and instead need to define a getter method at the class level in order to access it.</p>
<p>This is because the same syntax is used for regular <em>instance variables</em>, so we can only refer to class instance variables directly when we are in the class scope—like in <strong>class methods</strong> and in the <strong>top-level context</strong> of a class definition.</p>
<p>Also, since we can't use <em>class instance variables</em> to share values between a class and its descendants, in cases where we would like to access the variable of a parent class we will need to refer to it using a fully qualified getter (such as <code>Animal.sound</code>) or use <a href="https://github.com/ElMassimo/queryable/blob/7c5eb3448456e6e84a907cbf4a567c576433428a/lib/queryable/default_scope.rb#L38-L50" target="_blank" rel="nofollow noopener noreferrer">metaprogramming</a> in order to achieve that.</p>
<h2 id="driving-it-home" class="heading"><a href="#driving-it-home" class="heading-anchor" aria-label="Permalink for Driving it home 🏠 🚗" tabindex="-1"></a>Driving it home <span role="img" aria-label="house">🏠</span> <span role="img" aria-label="automobile">🚗</span></h2>
<p>In general, <em>class instance variables</em> are the way to go because they are not shared, which is very useful when building libraries or DSLs, and we don't run the risk of the value getting stepped over by accident in a subclass.</p>
<p>On the other hand, when the variable must be shared by a class and its descendants we should always use <em>class variables</em>.</p>
<p>When inheritance is not in play we can use either, but it's better to be consistent and pick a "default". I always use <em>class instance variables</em> unless I actually need the variable to be shared.</p>
<p>We should now be less fuzzy on what <code>@</code> means when used in class methods or in a class definition, and when to use <em>class instance variables</em> instead of <em>class variables</em> <span role="img" aria-label="grinning face with big eyes">😃</span></p>]]></content>
        <author>
            <name>Máximo Mussini</name>
            <uri>https://maximomussini.com</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Optimizing AngularJS performance with events]]></title>
        <id>https://maximomussini.com/posts/angular-less-watchers</id>
        <link href="https://maximomussini.com/posts/angular-less-watchers"/>
        <updated>2016-04-15T23:38:00.000Z</updated>
        <summary type="html"><![CDATA[Effective ways to reduce the amount of watchers in AngularJS applications and improve performance.]]></summary>
        <content type="html"><![CDATA[<p>Like we saw in the <a href="/posts/angular-intro">previous post</a>, <em>AngularJS</em> uses watchers to detect changes, allowing it to update views as needed. <em>Angular</em> will create a watcher for every expression that we add to our templates using data-bindings, <code>ng-repeat</code>, or similar directives.</p>
<p>As we learned, each time a watcher is created <em>Angular</em> will add the expression to a <em><a href="/posts/angular-intro#the-watch-list-and-dirty-checking">watch list</a></em>, which is then iterated during each digest cycle to evaluate every expression and detect changes. That means, the more watchers are registered, the more <em>Angular</em> has to process during <a href="/posts/angular-intro#repeat-the-digest-cycle">the digest cycle</a>.</p>
<p>In pages that have many components—such as long lists and grids—the amount of watchers can be very high, which can negatively affect the performance of our app and make it feel unresponsive.</p>
<p>In this post we will take a look at two techniques that can help us mitigate this problem and speed up our applications.</p>
<h2 id="one-time-bindings" class="heading"><a href="#one-time-bindings" class="heading-anchor" aria-label="Permalink for One-Time Bindings" tabindex="-1"></a>One-Time Bindings</h2>
<p>One of the most convenient techniques that we have to reduce the amount of watchers is the use of <em>one-time bindings</em>. Any expression that starts with <code>::</code> is considered a <em>one-time expression</em>.</p>
<div class="language-html" data-lang="html"><pre class="language-html"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">ng-repeat</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>user in ::users<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span><span class="token punctuation">></span></span>{{{ ::user.name }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span></code></pre></div>
<p><em>Angular</em> will remove a <em>one-time expression</em> from the watch list once it has been <a href="https://docs.angularjs.org/guide/expression#value-stabilization-algorithm" target="_blank" rel="nofollow noopener noreferrer">resolved</a>, unlike normal expressions which are evaluated on every digest cycle.</p>
<blockquote>
<p>If the expression will not change once set, it is a candidate for one-time binding. For example, internationalization <span role="img" aria-label="flag: United Kingdom">🇬🇧</span> <span role="img" aria-label="flag: Spain">🇪🇸</span></p>
</blockquote>
<p>As a result, we have less expressions being watched, which makes the digest loop faster, increases the responsiveness of the app, and allows more information to be displayed at the same time.</p>
<p>Using one-time bindings is an easy and effective way to reduce the amount of watchers, but there's a catch. <em>Angular</em> won't detect changes on each digest cycle and update the view, which makes them only suitable for values that won't change.</p>
<h2 id="recompiling-with-events" class="heading"><a href="#recompiling-with-events" class="heading-anchor" aria-label="Permalink for Recompiling with Events" tabindex="-1"></a>Recompiling with Events</h2>
<p>What about expressions with a value that might change, yet remain the same most of the time? It's a waste to evaluate them on every digest cycle, but we can't just use one-time expressions since the value might eventually change.</p>
<p>A technique that I have been using in pages where performance is critical is <em>event-driven recompilation</em>.</p>
<div class="language-html" data-lang="html"><pre class="language-html"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span> <span class="token attr-name">recompile-on</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>user:changed<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>{{ ::user.name }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">></span></span></code></pre></div>
<p>This technique has three key aspects: one-time expressions, compilation, and event propagation. Let's see how the <code>recompileOn</code> directive could be written:</p>
<div class="language-coffeescript" data-lang="coffeescript"><pre class="language-coffeescript"><code><span class="token comment"># Public: Recompiles an element if an event occurs.</span>
#
<span class="token comment"># NOTE: Do not use in combination with ng-if or ng-repeat, unless a one-time</span>
<span class="token comment"># binding is used in the expression.</span>
app<span class="token punctuation">.</span>directive <span class="token string">'recompileOn'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span>$compile<span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span>
  directive <span class="token operator">=</span>
    <span class="token property">scope</span><span class="token operator">:</span> <span class="token keyword">true</span>
    <span class="token property">priority</span><span class="token operator">:</span> <span class="token number">5</span>
    <span class="token property">restrict</span><span class="token operator">:</span> <span class="token string">'A'</span>
    <span class="token property">compile</span><span class="token operator">:</span> <span class="token punctuation">(</span>element<span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span>
      html <span class="token operator">=</span> element<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">outerHTML</span>

      <span class="token punctuation">(</span>scope<span class="token punctuation">,</span> element<span class="token punctuation">,</span> attrs<span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span>
        <span class="token comment"># Internal: Will trigger a recompilation if the event is triggered.</span>
        recompileOnEvent <span class="token operator">=</span> <span class="token punctuation">(</span>eventName<span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span>
          scope<span class="token punctuation">.</span>$<span class="token keyword">on</span> eventName<span class="token punctuation">,</span> <span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span>
            <span class="token comment"># Remove the previously added listener, if any.</span>
            removeListener<span class="token operator">?</span><span class="token punctuation">(</span><span class="token punctuation">)</span>

            <span class="token comment"># Replace the element after the digest loop that triggered the event has ended.</span>
            scope<span class="token punctuation">.</span>$evalAsync <span class="token operator">-</span><span class="token operator">></span>
              newEl <span class="token operator">=</span> <span class="token function">$compile</span><span class="token punctuation">(</span>html<span class="token punctuation">)</span><span class="token punctuation">(</span>scope<span class="token punctuation">.</span>$parent<span class="token punctuation">)</span>
              element<span class="token punctuation">.</span><span class="token function">replaceWith</span><span class="token punctuation">(</span>newEl<span class="token punctuation">)</span>

              <span class="token comment"># Destroy the old scope, since a new one was created by using compile.</span>
              scope<span class="token punctuation">.</span><span class="token function">$destroy</span><span class="token punctuation">(</span><span class="token punctuation">)</span>

        removeListener <span class="token operator">=</span> <span class="token function">recompileOnEvent</span><span class="token punctuation">(</span>attrs<span class="token punctuation">.</span>recompileOn<span class="token punctuation">)</span></code></pre></div>
<p>The directive will listen for a particular event on the current <em>scope</em>, and force a recompilation of the element when the event is triggered. This means that every directive inside the element will be processed from scratch, including our <em>one-time expressions</em>.</p>
<p>Events can be triggered as usual:</p>
<div class="language-coffeescript" data-lang="coffeescript"><pre class="language-coffeescript"><code>$scope<span class="token punctuation">.</span><span class="token function">$broadcast</span><span class="token punctuation">(</span><span class="token string">'user:changed'</span><span class="token punctuation">)</span></code></pre></div>
<h2 id="conclusion" class="heading"><a href="#conclusion" class="heading-anchor" aria-label="Permalink for Conclusion" tabindex="-1"></a>Conclusion</h2>
<p>One-time bindings provide a very efficient way to render dynamic values once without taking up watchers, while <code>$on</code> and <code>$compile</code> provide a helpful way to render from scratch when we need to. This combination works very well for complex pages where the amount of watchers is taking a toll on performance.</p>
<p>There are many variations that we can introduce to the implementation of <code>recompileOn</code>, such as allowing to pass several event names, or checking the event arguments for a specific value, such as an id. We can take this idea as far as we want to <span role="img" aria-label="rocket">🚀</span></p>
<p>As with any optimization, it's important to consider whether the performance improvement justifies the additional complexity. Use it wisely!</p>]]></content>
        <author>
            <name>Máximo Mussini</name>
            <uri>https://maximomussini.com</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[AngularJS: Watchers and the Digest Cycle]]></title>
        <id>https://maximomussini.com/posts/angular-intro</id>
        <link href="https://maximomussini.com/posts/angular-intro"/>
        <updated>2016-03-30T01:29:00.000Z</updated>
        <summary type="html"><![CDATA[A brief tour through Angular's internals: watchers and the digest cycle.]]></summary>
        <content type="html"><![CDATA[<p><em>AngularJS</em> might not be hip anymore, but it's still a useful framework to create interactive web apps. In this post we will take a brief tour through <em>Angular</em>'s internals: watchers and the digest cycle.</p>
<h2 id="bindings-and-watchers" class="heading"><a href="#bindings-and-watchers" class="heading-anchor" aria-label="Permalink for Bindings and Watchers" tabindex="-1"></a>Bindings and Watchers</h2>
<p>One of the most useful features in <em>AngularJS</em> are data-bindings, which allow us to bind a model or property to a view; whenever the model changes, the view is updated automatically.</p>
<div class="language-html" data-lang="html"><pre class="language-html"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">ng-model</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>user.name<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>text<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span><span class="token punctuation">></span></span>{{ user.name }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">></span></span></code></pre></div>
<p>How does that work? When you write an expression like <code>{{ user.name }}</code>, <em>Angular</em> creates a <em>watcher</em> that observes the <code>user.name</code> property, which will be triggered whenever the model changes, allowing <em>Angular</em> to update the view content.</p>
<p>We can also create watchers manually and execute arbitrary code when the model changes:</p>
<div class="language-js" data-lang="js"><pre class="language-js"><code>$scope<span class="token punctuation">.</span><span class="token function">$watch</span><span class="token punctuation">(</span><span class="token string">'user.name'</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">newName<span class="token punctuation">,</span> oldName</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'user.name changed from'</span><span class="token punctuation">,</span> oldName<span class="token punctuation">,</span> <span class="token string">'to'</span><span class="token punctuation">,</span> newName<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div>
<p>The first argument passed to <code>$watch</code> is known as the <em>model</em>, and the second argument is the <em>listener</em> function, which is called whenever the model (or more precisely, value of the watched expression) changes.</p>
<p>Now that we know what watchers can do for us, let's dig a bit deeper and learn how they work. How does <em>Angular</em> figure out when <code>user.name</code> changed in order to call the <em>listener</em>?</p>
<h2 id="the-watch-list-and-dirty-checking" class="heading"><a href="#the-watch-list-and-dirty-checking" class="heading-anchor" aria-label="Permalink for The Watch List and Dirty Checking" tabindex="-1"></a>The Watch List and Dirty Checking</h2>
<p>Each time a watcher is created, <em>Angular</em> adds the expression to a <em>watch list</em> to track changes. <em>Angular</em> will walk down the watch list from time to time and resolve each watcher through a process called <em>dirty checking</em>:</p>
<ul>
<li>Keep the last value for each watched expression.</li>
<li>Evaluate the expression: if the value is the same than the last one continue down the watch list.</li>
<li>If the value is different the expression is <strong>dirty</strong>, so propagate the change by calling each <em>listener</em> with the old and the new value.</li>
<li>Once the change has been synchronized across the app, replace the last value with the new value.</li>
<li>Continue to the next expression in the watch list.</li>
</ul>
<blockquote>
<p>For every UI element that is bound to a $scope object, a watch is created and added to the <em>watch list</em>, which is checked on every digest loop.</p>
</blockquote>
<h2 id="the-digest-cycle" class="heading"><a href="#the-digest-cycle" class="heading-anchor" aria-label="Permalink for 🔁 The Digest Cycle" tabindex="-1"></a><span role="img" aria-label="repeat button">🔁</span> The Digest Cycle</h2>
<p>And it's in the <a href="https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$digest" target="_blank" rel="nofollow noopener noreferrer"><code>$digest</code></a> cycle where every watcher in the watch list is evaluated, and the changes propagated to the <em>listeners</em>.</p>
<p>This cycle starts as a result of a call to <code>$scope.$digest()</code>, which often happens as a result of an action performed by the user. For example, clicking an element with the <code>ng-click</code> directive will explicitly call <code>$scope.$digest()</code> and start the loop.</p>
<p>Once the cycle starts, it will go through the <em>watch list</em>, propagating changes to <em>listeners</em> as needed.</p>
<blockquote>
<p>There are many <em>Angular</em> directives and services that will automatically trigger a digest cycle, such as <code>ng-model</code> and <code>$timeout</code>.</p>
</blockquote>
<h2 id="keep-calm-and-digest" class="heading"><a href="#keep-calm-and-digest" class="heading-anchor" aria-label="Permalink for 👑 Keep Calm and Digest" tabindex="-1"></a><span role="img" aria-label="crown">👑</span> Keep Calm and Digest</h2>
<p>Once <em>Angular</em> has run through the entire watch list, if any value changed, it will start a new digest cycle until no model is changed and no watchers are triggered.</p>
<p>Why does it run the loop all over again? Because any <code>$watch</code> listener could change the value of an expression that was evaluated earlier in the digest loop, so <em>Angular</em> wouldn't be able to detect and propagate that change.</p>
<p>Remember that <em>Angular</em> uses dirty-checking as a way to determine if the watched expression changed, so the only way to guarantee all changes are propagated is to go through the <em>watch list</em> again and check that no values were changed during the previous digest cycle.</p>
<p>This means that the digest loop will run a minimum of two times, even when <em>listeners</em> don’t change any models.</p>
<blockquote>
<p>Minimize changes to watched models when inside listener functions, each change could trigger an extra digest loop.</p>
</blockquote>
<p>If the loop runs ten times or more, <em>Angular</em> will throw an exception to prevent a possible infinite loop, which would make the app unusable.</p>
<h2 id="conclusion" class="heading"><a href="#conclusion" class="heading-anchor" aria-label="Permalink for Conclusion" tabindex="-1"></a>Conclusion</h2>
<p>Because of the nature of <em>Angular</em>'s internals, it's very important to minimize the amount of watchers in order to keep the digest cycle fast.</p>
<p>At the same time, it's important to ensure that our application doesn't trigger more digest cycles than necessary, since each loop requires evaluating every watcher in the list.</p>
<p>While watchers are a very useful feature, the digest cycle implementation takes a brute force approach, which makes it almost magical at times, but is inefficient and can cause performance problems in complex applications.</p>
<p>In the <a href="/posts/angular-less-watchers">next post</a>, we will take a look at some techniques that help to reduce the amount of watchers and improve the performance of our app. Stay tuned! <span role="img" aria-label="grinning face with big eyes">😃</span></p>]]></content>
        <author>
            <name>Máximo Mussini</name>
            <uri>https://maximomussini.com</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Positive-Negative Assertions in Cucumber]]></title>
        <id>https://maximomussini.com/posts/cucumber-to_or_not_to</id>
        <link href="https://maximomussini.com/posts/cucumber-to_or_not_to"/>
        <updated>2016-02-03T18:34:00.000Z</updated>
        <summary type="html"><![CDATA[A simple trick to make assertions in Cucumber more powerful—while not repeating yourself.]]></summary>
        <content type="html"><![CDATA[<p><a href="https://github.com/cucumber/cucumber-ruby" target="_blank" rel="nofollow noopener noreferrer"><em>Cucumber</em></a> steps often involve asserting a condition or the opposite of it. For example:</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code>Then<span class="token punctuation">(</span><span class="token regex-literal"><span class="token regex">/^I should see a "(.*?)" comment$/</span></span><span class="token punctuation">)</span> <span class="token keyword">do</span> <span class="token operator">|</span>message<span class="token operator">|</span>
  expect<span class="token punctuation">(</span>page<span class="token punctuation">)</span><span class="token punctuation">.</span>to have_css<span class="token punctuation">(</span><span class="token string-literal"><span class="token string">'li.comment'</span></span><span class="token punctuation">,</span> <span class="token symbol">text</span><span class="token operator">:</span> message<span class="token punctuation">)</span>
<span class="token keyword">end</span>

Then<span class="token punctuation">(</span><span class="token regex-literal"><span class="token regex">/^I should not see a "(.*?)" comment$/</span></span><span class="token punctuation">)</span> <span class="token keyword">do</span> <span class="token operator">|</span>message<span class="token operator">|</span>
  expect<span class="token punctuation">(</span>page<span class="token punctuation">)</span><span class="token punctuation">.</span>not_to have_css<span class="token punctuation">(</span><span class="token string-literal"><span class="token string">'li.comment'</span></span><span class="token punctuation">,</span> <span class="token symbol">text</span><span class="token operator">:</span> message<span class="token punctuation">)</span>
<span class="token keyword">end</span></code></pre></div>
<p>Not only is it boring to write steps like this: it also has the downside of introducing duplication into our test steps. If the DOM changes, we are forced to update both steps.</p>
<p>Even worse, if the DOM changes and we forget to update the negative assertion, it will always pass since the element doesn't even exist!</p>
<p>Let's give it another shot, but this time we will encapsulate the DOM references:</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code><span class="token keyword">def</span> <span class="token method-definition"><span class="token function">have_comment</span></span><span class="token punctuation">(</span>message<span class="token punctuation">)</span>
  have_css<span class="token punctuation">(</span><span class="token string-literal"><span class="token string">'li.comment'</span></span><span class="token punctuation">,</span> <span class="token symbol">text</span><span class="token operator">:</span> message<span class="token punctuation">)</span>
<span class="token keyword">end</span>

Then<span class="token punctuation">(</span><span class="token regex-literal"><span class="token regex">/^I should see a "(.*?)" comment$/</span></span><span class="token punctuation">)</span> <span class="token keyword">do</span> <span class="token operator">|</span>message<span class="token operator">|</span>
  expect<span class="token punctuation">(</span>page<span class="token punctuation">)</span><span class="token punctuation">.</span>to have_comment<span class="token punctuation">(</span>message<span class="token punctuation">)</span>
<span class="token keyword">end</span>

Then<span class="token punctuation">(</span><span class="token regex-literal"><span class="token regex">/^I should not see a "(.*?)" comment$/</span></span><span class="token punctuation">)</span> <span class="token keyword">do</span> <span class="token operator">|</span>message<span class="token operator">|</span>
  expect<span class="token punctuation">(</span>page<span class="token punctuation">)</span><span class="token punctuation">.</span>not_to have_comment<span class="token punctuation">(</span>message<span class="token punctuation">)</span>
<span class="token keyword">end</span></code></pre></div>
<p>The code is easier to read, and we solved a potential maintainability issue, nice! It's possible to add a little touch of regular expressions to combine both steps into one:</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code>Then<span class="token punctuation">(</span><span class="token regex-literal"><span class="token regex">/^I should( not)? see a "(.*?)" comment$/</span></span><span class="token punctuation">)</span> <span class="token keyword">do</span> <span class="token operator">|</span>should_not<span class="token punctuation">,</span> message<span class="token operator">|</span>
  <span class="token keyword">if</span> should_not
    expect<span class="token punctuation">(</span>page<span class="token punctuation">)</span><span class="token punctuation">.</span>not_to have_comment<span class="token punctuation">(</span>message<span class="token punctuation">)</span>
  <span class="token keyword">else</span>
    expect<span class="token punctuation">(</span>page<span class="token punctuation">)</span><span class="token punctuation">.</span>to have_comment<span class="token punctuation">(</span>message<span class="token punctuation">)</span>
  <span class="token keyword">end</span>
<span class="token keyword">end</span></code></pre></div>
<p>If we write <em>"should not see"</em> then the group will match and the <code>should_not</code> variable will contain <code>" not"</code>. If we write <em>"should see"</em> then the group won't capture anything and <code>should_not</code> will be <code>nil</code>. This allows us to make a simple conditional check.</p>
<p>We can leverage Ruby's expressiveness and take it a bit further:</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code>Then<span class="token punctuation">(</span><span class="token regex-literal"><span class="token regex">/^I should( not)? see a "(.*?)" comment$/</span></span><span class="token punctuation">)</span> <span class="token keyword">do</span> <span class="token operator">|</span>should_not<span class="token punctuation">,</span> message<span class="token operator">|</span>
  expect<span class="token punctuation">(</span>page<span class="token punctuation">)</span><span class="token punctuation">.</span>send <span class="token punctuation">(</span>should_not <span class="token operator">?</span> <span class="token symbol">:not_to</span> <span class="token operator">:</span> <span class="token symbol">:to</span><span class="token punctuation">)</span><span class="token punctuation">,</span> have_comment<span class="token punctuation">(</span>message<span class="token punctuation">)</span>
<span class="token keyword">end</span></code></pre></div>
<p>Shorter, but not necessarily easier to understand. Fortunately, we can create our own custom RSpec matcher to encapsulate this pattern and make it easier to reuse and understand:</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code><span class="token comment"># features/support/to_or.rb</span>
<span class="token keyword">module</span> <span class="token class-name">PositiveNegativeExpectationHandler</span>
  <span class="token keyword">def</span> <span class="token method-definition"><span class="token function">to_or</span></span><span class="token punctuation">(</span>not_to<span class="token punctuation">,</span> matcher<span class="token punctuation">,</span> message<span class="token operator">=</span><span class="token keyword">nil</span><span class="token punctuation">,</span> <span class="token operator">&amp;</span>block<span class="token punctuation">)</span>
    <span class="token keyword">if</span> not_to
      not_to<span class="token punctuation">(</span>matcher<span class="token punctuation">,</span> message<span class="token punctuation">,</span> <span class="token operator">&amp;</span>block<span class="token punctuation">)</span>
    <span class="token keyword">else</span>
      to<span class="token punctuation">(</span>matcher<span class="token punctuation">,</span> message<span class="token punctuation">,</span> <span class="token operator">&amp;</span>block<span class="token punctuation">)</span>
    <span class="token keyword">end</span>
  <span class="token keyword">end</span>
<span class="token keyword">end</span>

RSpec<span class="token double-colon punctuation">::</span>Expectations<span class="token double-colon punctuation">::</span>ExpectationTarget<span class="token punctuation">.</span>send<span class="token punctuation">(</span><span class="token symbol">:include</span><span class="token punctuation">,</span> PositiveNegativeExpectationHandler<span class="token punctuation">)</span></code></pre></div>
<p>Finally, we are able to express the step in a very concise and readable way:</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code>Then<span class="token punctuation">(</span><span class="token regex-literal"><span class="token regex">/^I should( not)? see a "(.*?)" comment$/</span></span><span class="token punctuation">)</span> <span class="token keyword">do</span> <span class="token operator">|</span>not_to<span class="token punctuation">,</span> message<span class="token operator">|</span>
  expect<span class="token punctuation">(</span>page<span class="token punctuation">)</span><span class="token punctuation">.</span>to_or not_to<span class="token punctuation">,</span> have_comment<span class="token punctuation">(</span>message<span class="token punctuation">)</span>
<span class="token keyword">end</span></code></pre></div>
<blockquote>
<p>No magic here <span role="img" aria-label="top hat">🎩</span>, just clever naming <span role="img" aria-label="rabbit face">🐰</span></p>
</blockquote>
<p><code>to_or</code> has been a very helpful addition to our projects, allowing us to write simple steps that read like English.</p>
<p>You can copy the <code>PositiveNegativeExpectationHandler</code> to a support file in your project, like <code>features/support/to_or.rb</code>, and start using it right away <span role="img" aria-label="grinning face with big eyes">😃</span></p>]]></content>
        <author>
            <name>Máximo Mussini</name>
            <uri>https://maximomussini.com</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Redirecting AJAX requests in Rails]]></title>
        <id>https://maximomussini.com/posts/rails-ajax_redirect</id>
        <link href="https://maximomussini.com/posts/rails-ajax_redirect"/>
        <updated>2016-01-11T20:00:00.000Z</updated>
        <summary type="html"><![CDATA[Learn a new trick that extends what's possible with remote links in Rails.]]></summary>
        <content type="html"><![CDATA[<p><a href="https://github.com/rails/jquery-rails" target="_blank" rel="nofollow noopener noreferrer"><code>jquery-rails</code></a> powers links and forms in Rails: it's what makes <code>remote: true</code> work, allowing any link to make an AJAX request unobtrusively.</p>
<p><a href="https://github.com/ElMassimo/rails-ajax_redirect" target="_blank" rel="nofollow noopener noreferrer"><code>rails-ajax_redirect</code></a> is an extension to this unobtrusive behaviour that adds AJAX support to <code>redirect_to</code>. It allows us to redirect an AJAX request as usual, instead of having to perform the redirect by handling the response manually in JS every time.</p>
<p>This is helpful in many different scenarios, and just like <code>remote: true</code>, it allows us to skip some of the boilerplate in cases where we need to redirect the user to a different page.</p>
<p><a href="https://github.com/ElMassimo/rails-ajax_redirect" target="_blank" rel="nofollow noopener noreferrer"><code>Rails::AjaxRedirect</code></a> extends <code>redirect_to</code> to use a custom status code for ajax
requests, while still setting the <code>Location</code> header. On the front-end, it adds a handler for the <code>ajax:success</code> event, that navigates to the location in the header for responses that have the custom status code.</p>
<p>This makes it possible to write a simple redirect as usual, but without having to handle it manually every time <span role="img" aria-label="grinning face with big eyes">😃</span></p>
<h2 id="turbolinks" class="heading"><a href="#turbolinks" class="heading-anchor" aria-label="Permalink for Turbolinks" tabindex="-1"></a>Turbolinks</h2>
<p>If your application uses <a href="https://github.com/rails/turbolinks" target="_blank" rel="nofollow noopener noreferrer"><em>Turbolinks</em></a> check out <a href="https://github.com/remind101/turbolinks-redirect" target="_blank" rel="nofollow noopener noreferrer"><code>turbolinks-redirect</code></a>, on which <a href="https://github.com/ElMassimo/rails-ajax_redirect" target="_blank" rel="nofollow noopener noreferrer"><code>rails-ajax_redirect</code></a> is based on. The advantage is that it will perform faster navigation by leveraging <em>Turbolinks</em> to visit the new location.</p>
<h2 id="axios" class="heading"><a href="#axios" class="heading-anchor" aria-label="Permalink for Axios" tabindex="-1"></a>Axios</h2>
<p>If your application makes the AJAX request using <code>axios</code> instead of <code>jQuery</code>, it will be necessary to add an interceptor similar to this:</p>
<div class="language-javascript" data-lang="javascript"><pre class="language-javascript"><code>axios<span class="token punctuation">.</span>interceptors<span class="token punctuation">.</span>response<span class="token punctuation">.</span><span class="token function">use</span><span class="token punctuation">(</span>
  <span class="token parameter">response</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>response<span class="token punctuation">.</span>status <span class="token operator">===</span> <span class="token constant">AJAX_REDIRECT_STATUS_CODE</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      window<span class="token punctuation">.</span>location <span class="token operator">=</span> response<span class="token punctuation">.</span>headers<span class="token punctuation">.</span>location
    <span class="token punctuation">}</span>
    <span class="token keyword">return</span> response
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token parameter">error</span> <span class="token operator">=></span> Promise<span class="token punctuation">.</span><span class="token function">reject</span><span class="token punctuation">(</span>error<span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">)</span></code></pre></div>]]></content>
        <author>
            <name>Máximo Mussini</name>
            <uri>https://maximomussini.com</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Anko DSL vs Android XML-First]]></title>
        <id>https://maximomussini.com/posts/anko-vs-android-xml</id>
        <link href="https://maximomussini.com/posts/anko-vs-android-xml"/>
        <updated>2016-01-04T20:06:00.000Z</updated>
        <summary type="html"><![CDATA[An outdated look at Anko as a UI builder in Kotlin Android apps.]]></summary>
        <content type="html"><![CDATA[

<p><a href="https://github.com/kotlin/anko" target="_blank" rel="nofollow noopener noreferrer"><em>Anko</em></a> is a library for <em>Android</em> development in <a href="https://kotlinlang.org" target="_blank" rel="nofollow noopener noreferrer"><em>Kotlin</em></a>. The library provides helper methods that take advantage of <em>Kotlin</em>'s extension functions as a way to reduce the amount of boilerplate the <em>Android SDK</em> requires. Those extension functions make it possible to accomplish common tasks like starting an activity or displaying a toast in a very succinct way.</p>
<p>A big part of the library though, focuses on creating a <a href="https://kotlinlang.org/docs/reference/type-safe-builders.html" target="_blank" rel="nofollow noopener noreferrer">type-safe builder</a> for creating view hierarchies, as an alternative to the XML-inflated view approach. Some of the benefits of defining a layout with <em>Anko</em> are type-safety, and efficiency, since it's not necessary to parse the XML.</p>
<p>I decided to take the DSL for a test drive by rewriting the "Navigation Drawer Activity" template from <em>AndroidStudio</em>, replacing some of the XML layouts with the <em>Anko DSL</em>.</p>
<p><picture><source media="(-webkit-min-device-pixel-ratio: 1.5)" type="image/avif" srcset="/assets/navigation-drawer-activity-template.6a90849b.avif 420w, /assets/navigation-drawer-activity-template.1daca4fe.avif 720w"><source media="(-webkit-min-device-pixel-ratio: 1.5)" type="image/webp" srcset="/assets/navigation-drawer-activity-template.0f0567e9.webp 420w, /assets/navigation-drawer-activity-template.423cf499.webp 720w"><source media="(-webkit-min-device-pixel-ratio: 1.5)" srcset="/assets/navigation-drawer-activity-template.6c56e335.png 420w, /assets/navigation-drawer-activity-template.0e0f56ed.png 720w"><source type="image/avif" srcset="/assets/navigation-drawer-activity-template.71cf670e.avif 720w"><source type="image/webp" srcset="/assets/navigation-drawer-activity-template.7593826d.webp 720w"><img srcset="/assets/navigation-drawer-activity-template.aa1a8f8d.png 720w" loading="lazy" src="/assets/navigation-drawer-activity-template.aa1a8f8d.png" class="img" alt="Android Studio Activity Wizard"></picture></p>
<p>We can define an <code>AnkoComponent</code> to create the UI:</p>
<div class="language-kotlin" data-lang="kotlin"><pre class="language-kotlin"><code><span class="token keyword">package</span> com<span class="token punctuation">.</span>maximomussini<span class="token punctuation">.</span>anko

<span class="token keyword">import</span> android<span class="token punctuation">.</span>support<span class="token punctuation">.</span>design<span class="token punctuation">.</span>widget<span class="token punctuation">.</span>AppBarLayout
<span class="token keyword">import</span> android<span class="token punctuation">.</span>support<span class="token punctuation">.</span>design<span class="token punctuation">.</span>widget<span class="token punctuation">.</span>Snackbar
<span class="token keyword">import</span> android<span class="token punctuation">.</span>support<span class="token punctuation">.</span>v4<span class="token punctuation">.</span>content<span class="token punctuation">.</span>ContextCompat
<span class="token keyword">import</span> android<span class="token punctuation">.</span>support<span class="token punctuation">.</span>v4<span class="token punctuation">.</span>view<span class="token punctuation">.</span>GravityCompat
<span class="token keyword">import</span> android<span class="token punctuation">.</span>util<span class="token punctuation">.</span>TypedValue
<span class="token keyword">import</span> android<span class="token punctuation">.</span>view<span class="token punctuation">.</span>Gravity
<span class="token keyword">import</span> android<span class="token punctuation">.</span>view<span class="token punctuation">.</span>View
<span class="token keyword">import</span> com<span class="token punctuation">.</span>maximomussini<span class="token punctuation">.</span>anko<span class="token punctuation">.</span>util<span class="token punctuation">.</span>snackbar
<span class="token keyword">import</span> org<span class="token punctuation">.</span>jetbrains<span class="token punctuation">.</span>anko<span class="token punctuation">.</span><span class="token operator">*</span>
<span class="token keyword">import</span> org<span class="token punctuation">.</span>jetbrains<span class="token punctuation">.</span>anko<span class="token punctuation">.</span>appcompat<span class="token punctuation">.</span>v7<span class="token punctuation">.</span>toolbar
<span class="token keyword">import</span> org<span class="token punctuation">.</span>jetbrains<span class="token punctuation">.</span>anko<span class="token punctuation">.</span>design<span class="token punctuation">.</span>appBarLayout
<span class="token keyword">import</span> org<span class="token punctuation">.</span>jetbrains<span class="token punctuation">.</span>anko<span class="token punctuation">.</span>design<span class="token punctuation">.</span>coordinatorLayout
<span class="token keyword">import</span> org<span class="token punctuation">.</span>jetbrains<span class="token punctuation">.</span>anko<span class="token punctuation">.</span>design<span class="token punctuation">.</span>floatingActionButton
<span class="token keyword">import</span> org<span class="token punctuation">.</span>jetbrains<span class="token punctuation">.</span>anko<span class="token punctuation">.</span>design<span class="token punctuation">.</span>navigationView
<span class="token keyword">import</span> org<span class="token punctuation">.</span>jetbrains<span class="token punctuation">.</span>anko<span class="token punctuation">.</span>support<span class="token punctuation">.</span>v4<span class="token punctuation">.</span>_DrawerLayout
<span class="token keyword">import</span> org<span class="token punctuation">.</span>jetbrains<span class="token punctuation">.</span>anko<span class="token punctuation">.</span>support<span class="token punctuation">.</span>v4<span class="token punctuation">.</span>drawerLayout

<span class="token keyword">class</span> MainUI <span class="token operator">:</span> AnkoComponent<span class="token operator">&lt;</span>MainActivity<span class="token operator">></span> <span class="token punctuation">{</span>

    <span class="token keyword">override</span> <span class="token keyword">fun</span> <span class="token function">createView</span><span class="token punctuation">(</span>ui<span class="token operator">:</span> AnkoContext<span class="token operator">&lt;</span>MainActivity<span class="token operator">></span><span class="token punctuation">)</span><span class="token operator">:</span> View <span class="token operator">=</span> <span class="token function">with</span><span class="token punctuation">(</span>ui<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        drawerLayout <span class="token punctuation">{</span>
            id <span class="token operator">=</span> R<span class="token punctuation">.</span>id<span class="token punctuation">.</span>drawer
            fitsSystemWindows <span class="token operator">=</span> <span class="token boolean">true</span>
            <span class="token function">createAppBar</span><span class="token punctuation">(</span>ui<span class="token punctuation">)</span>
            <span class="token function">createNavigationView</span><span class="token punctuation">(</span>ui<span class="token punctuation">)</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">fun</span> _DrawerLayout<span class="token punctuation">.</span><span class="token function">createAppBar</span><span class="token punctuation">(</span>ui<span class="token operator">:</span> AnkoContext<span class="token operator">&lt;</span>MainActivity<span class="token operator">></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        coordinatorLayout <span class="token punctuation">{</span>
            fitsSystemWindows <span class="token operator">=</span> <span class="token boolean">true</span>

            appBarLayout <span class="token punctuation">{</span>
                toolbar <span class="token punctuation">{</span>
                    id <span class="token operator">=</span> R<span class="token punctuation">.</span>id<span class="token punctuation">.</span>toolbar
                    popupTheme <span class="token operator">=</span> R<span class="token punctuation">.</span>style<span class="token punctuation">.</span>AppTheme_PopupOverlay
                    backgroundResource <span class="token operator">=</span> R<span class="token punctuation">.</span>color<span class="token punctuation">.</span>colorPrimary
                <span class="token punctuation">}</span><span class="token punctuation">.</span><span class="token function">lparams</span><span class="token punctuation">(</span>width <span class="token operator">=</span> matchParent<span class="token punctuation">)</span> <span class="token punctuation">{</span>
                    <span class="token keyword">val</span> tv <span class="token operator">=</span> <span class="token function">TypedValue</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
                    <span class="token keyword">if</span> <span class="token punctuation">(</span>ui<span class="token punctuation">.</span>owner<span class="token punctuation">.</span>theme<span class="token punctuation">.</span><span class="token function">resolveAttribute</span><span class="token punctuation">(</span>R<span class="token punctuation">.</span>attr<span class="token punctuation">.</span>actionBarSize<span class="token punctuation">,</span> tv<span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                        height <span class="token operator">=</span> TypedValue<span class="token punctuation">.</span><span class="token function">complexToDimensionPixelSize</span><span class="token punctuation">(</span>tv<span class="token punctuation">.</span>data<span class="token punctuation">,</span> resources<span class="token punctuation">.</span>displayMetrics<span class="token punctuation">)</span><span class="token punctuation">;</span>
                    <span class="token punctuation">}</span>
                <span class="token punctuation">}</span>
            <span class="token punctuation">}</span><span class="token punctuation">.</span><span class="token function">lparams</span><span class="token punctuation">(</span>width <span class="token operator">=</span> matchParent<span class="token punctuation">)</span>

            relativeLayout <span class="token punctuation">{</span>
                horizontalPadding <span class="token operator">=</span> resources<span class="token punctuation">.</span><span class="token function">getDimensionPixelSize</span><span class="token punctuation">(</span>R<span class="token punctuation">.</span>dimen<span class="token punctuation">.</span>activity_horizontal_margin<span class="token punctuation">)</span>
                verticalPadding <span class="token operator">=</span> resources<span class="token punctuation">.</span><span class="token function">getDimensionPixelSize</span><span class="token punctuation">(</span>R<span class="token punctuation">.</span>dimen<span class="token punctuation">.</span>activity_vertical_margin<span class="token punctuation">)</span>
                <span class="token function">textView</span><span class="token punctuation">(</span><span class="token string-literal singleline"><span class="token string">"Hello World!"</span></span><span class="token punctuation">)</span>
            <span class="token punctuation">}</span><span class="token punctuation">.</span><span class="token function">lparams</span><span class="token punctuation">(</span>width <span class="token operator">=</span> matchParent<span class="token punctuation">,</span> height <span class="token operator">=</span> matchParent<span class="token punctuation">)</span> <span class="token punctuation">{</span>
                behavior <span class="token operator">=</span> AppBarLayout<span class="token punctuation">.</span><span class="token function">ScrollingViewBehavior</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
            <span class="token punctuation">}</span>

            floatingActionButton <span class="token punctuation">{</span>
                imageResource <span class="token operator">=</span> android<span class="token punctuation">.</span>R<span class="token punctuation">.</span>drawable<span class="token punctuation">.</span>ic_dialog_email
                backgroundColor <span class="token operator">=</span> ContextCompat<span class="token punctuation">.</span><span class="token function">getColor</span><span class="token punctuation">(</span>ui<span class="token punctuation">.</span>owner<span class="token punctuation">,</span> R<span class="token punctuation">.</span>color<span class="token punctuation">.</span>colorAccent<span class="token punctuation">)</span>
                onClick <span class="token punctuation">{</span>
                    <span class="token function">snackbar</span><span class="token punctuation">(</span><span class="token string-literal singleline"><span class="token string">"Replace with your own action"</span></span><span class="token punctuation">,</span> Snackbar<span class="token punctuation">.</span>LENGTH_LONG<span class="token punctuation">)</span> <span class="token punctuation">{</span>
                        <span class="token function">setAction</span><span class="token punctuation">(</span><span class="token string-literal singleline"><span class="token string">"Action"</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span> ui<span class="token punctuation">.</span><span class="token function">toast</span><span class="token punctuation">(</span><span class="token string-literal singleline"><span class="token string">"Clicked Snack"</span></span><span class="token punctuation">)</span> <span class="token punctuation">}</span>
                    <span class="token punctuation">}</span>
                <span class="token punctuation">}</span>
            <span class="token punctuation">}</span><span class="token punctuation">.</span><span class="token function">lparams</span> <span class="token punctuation">{</span>
                margin <span class="token operator">=</span> resources<span class="token punctuation">.</span><span class="token function">getDimensionPixelSize</span><span class="token punctuation">(</span>R<span class="token punctuation">.</span>dimen<span class="token punctuation">.</span>fab_margin<span class="token punctuation">)</span>
                gravity <span class="token operator">=</span> Gravity<span class="token punctuation">.</span>BOTTOM <span class="token operator">or</span> GravityCompat<span class="token punctuation">.</span>END
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span><span class="token punctuation">.</span><span class="token function">lparams</span><span class="token punctuation">(</span>width <span class="token operator">=</span> matchParent<span class="token punctuation">,</span> height <span class="token operator">=</span> matchParent<span class="token punctuation">)</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">fun</span> _DrawerLayout<span class="token punctuation">.</span><span class="token function">createNavigationView</span><span class="token punctuation">(</span>ui<span class="token operator">:</span> AnkoContext<span class="token operator">&lt;</span>MainActivity<span class="token operator">></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        navigationView <span class="token punctuation">{</span>
            fitsSystemWindows <span class="token operator">=</span> <span class="token boolean">true</span>
            <span class="token function">setNavigationItemSelectedListener</span><span class="token punctuation">(</span>ui<span class="token punctuation">.</span>owner<span class="token punctuation">)</span>
            <span class="token function">inflateHeaderView</span><span class="token punctuation">(</span>R<span class="token punctuation">.</span>layout<span class="token punctuation">.</span>nav_header_main<span class="token punctuation">)</span>
            <span class="token function">inflateMenu</span><span class="token punctuation">(</span>R<span class="token punctuation">.</span>menu<span class="token punctuation">.</span>activity_main_drawer<span class="token punctuation">)</span>
        <span class="token punctuation">}</span><span class="token punctuation">.</span><span class="token function">lparams</span><span class="token punctuation">(</span>height <span class="token operator">=</span> matchParent<span class="token punctuation">,</span> gravity <span class="token operator">=</span> GravityCompat<span class="token punctuation">.</span>START<span class="token punctuation">)</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre></div>
<p>And then, use the component to set the content view for the activity instead of using an XML layout:</p>
<div class="language-kotlin" data-lang="kotlin"><pre class="language-kotlin"><code><span class="token keyword">package</span> com<span class="token punctuation">.</span>maximomussini<span class="token punctuation">.</span>anko

<span class="token keyword">import</span> android<span class="token punctuation">.</span>os<span class="token punctuation">.</span>Bundle
<span class="token keyword">import</span> android<span class="token punctuation">.</span>support<span class="token punctuation">.</span>design<span class="token punctuation">.</span>widget<span class="token punctuation">.</span>NavigationView
<span class="token keyword">import</span> android<span class="token punctuation">.</span>support<span class="token punctuation">.</span>v4<span class="token punctuation">.</span>view<span class="token punctuation">.</span>GravityCompat
<span class="token keyword">import</span> android<span class="token punctuation">.</span>support<span class="token punctuation">.</span>v4<span class="token punctuation">.</span>widget<span class="token punctuation">.</span>DrawerLayout
<span class="token keyword">import</span> android<span class="token punctuation">.</span>support<span class="token punctuation">.</span>v7<span class="token punctuation">.</span>app<span class="token punctuation">.</span>ActionBarDrawerToggle
<span class="token keyword">import</span> android<span class="token punctuation">.</span>support<span class="token punctuation">.</span>v7<span class="token punctuation">.</span>app<span class="token punctuation">.</span>AppCompatActivity
<span class="token keyword">import</span> android<span class="token punctuation">.</span>support<span class="token punctuation">.</span>v7<span class="token punctuation">.</span>widget<span class="token punctuation">.</span>Toolbar
<span class="token keyword">import</span> android<span class="token punctuation">.</span>view<span class="token punctuation">.</span>Menu
<span class="token keyword">import</span> android<span class="token punctuation">.</span>view<span class="token punctuation">.</span>MenuItem
<span class="token keyword">import</span> org<span class="token punctuation">.</span>jetbrains<span class="token punctuation">.</span>anko<span class="token punctuation">.</span>find
<span class="token keyword">import</span> org<span class="token punctuation">.</span>jetbrains<span class="token punctuation">.</span>anko<span class="token punctuation">.</span>setContentView
<span class="token keyword">import</span> org<span class="token punctuation">.</span>jetbrains<span class="token punctuation">.</span>anko<span class="token punctuation">.</span>toast

<span class="token keyword">class</span> MainActivity <span class="token operator">:</span> <span class="token function">AppCompatActivity</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> NavigationView<span class="token punctuation">.</span><span class="token function">OnNavigationItemSelectedListener</span> <span class="token punctuation">{</span>

    <span class="token keyword">lateinit</span> <span class="token keyword">var</span> drawer<span class="token operator">:</span> DrawerLayout

    <span class="token keyword">override</span> <span class="token keyword">fun</span> <span class="token function">onCreate</span><span class="token punctuation">(</span>savedInstanceState<span class="token operator">:</span> Bundle<span class="token operator">?</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">super</span><span class="token punctuation">.</span><span class="token function">onCreate</span><span class="token punctuation">(</span>savedInstanceState<span class="token punctuation">)</span>
        <span class="token function">MainUI</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">setContentView</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span>
        drawer <span class="token operator">=</span> find<span class="token operator">&lt;</span>DrawerLayout<span class="token operator">></span><span class="token punctuation">(</span>R<span class="token punctuation">.</span>id<span class="token punctuation">.</span>drawer<span class="token punctuation">)</span>

        <span class="token keyword">val</span> toolbar <span class="token operator">=</span> find<span class="token operator">&lt;</span>Toolbar<span class="token operator">></span><span class="token punctuation">(</span>R<span class="token punctuation">.</span>id<span class="token punctuation">.</span>toolbar<span class="token punctuation">)</span>
        <span class="token function">setSupportActionBar</span><span class="token punctuation">(</span>toolbar<span class="token punctuation">)</span>

        <span class="token keyword">val</span> toggle <span class="token operator">=</span> <span class="token function">ActionBarDrawerToggle</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> drawer<span class="token punctuation">,</span> toolbar<span class="token punctuation">,</span>
                R<span class="token punctuation">.</span>string<span class="token punctuation">.</span>navigation_drawer_open<span class="token punctuation">,</span> R<span class="token punctuation">.</span>string<span class="token punctuation">.</span>navigation_drawer_close<span class="token punctuation">)</span>
        drawer<span class="token punctuation">.</span><span class="token function">setDrawerListener</span><span class="token punctuation">(</span>toggle<span class="token punctuation">)</span>
        toggle<span class="token punctuation">.</span><span class="token function">syncState</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">override</span> <span class="token keyword">fun</span> <span class="token function">onBackPressed</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>drawer<span class="token punctuation">.</span><span class="token function">isDrawerOpen</span><span class="token punctuation">(</span>GravityCompat<span class="token punctuation">.</span>START<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            drawer<span class="token punctuation">.</span><span class="token function">closeDrawer</span><span class="token punctuation">(</span>GravityCompat<span class="token punctuation">.</span>START<span class="token punctuation">)</span>
        <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
            <span class="token keyword">super</span><span class="token punctuation">.</span><span class="token function">onBackPressed</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">override</span> <span class="token keyword">fun</span> <span class="token function">onCreateOptionsMenu</span><span class="token punctuation">(</span>menu<span class="token operator">:</span> Menu<span class="token punctuation">)</span><span class="token operator">:</span> Boolean <span class="token punctuation">{</span>
        menuInflater<span class="token punctuation">.</span><span class="token function">inflate</span><span class="token punctuation">(</span>R<span class="token punctuation">.</span>menu<span class="token punctuation">.</span>main<span class="token punctuation">,</span> menu<span class="token punctuation">)</span>
        <span class="token keyword">return</span> <span class="token boolean">true</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">override</span> <span class="token keyword">fun</span> <span class="token function">onOptionsItemSelected</span><span class="token punctuation">(</span>item<span class="token operator">:</span> MenuItem<span class="token punctuation">)</span><span class="token operator">:</span> Boolean <span class="token punctuation">{</span>
        <span class="token keyword">when</span> <span class="token punctuation">(</span>item<span class="token punctuation">.</span>itemId<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            R<span class="token punctuation">.</span>id<span class="token punctuation">.</span>action_settings <span class="token operator">-></span> <span class="token punctuation">{</span>
                <span class="token function">toast</span><span class="token punctuation">(</span><span class="token string-literal singleline"><span class="token string">"Settings"</span></span><span class="token punctuation">)</span>
                <span class="token keyword">return</span> <span class="token boolean">true</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
        <span class="token keyword">return</span> <span class="token keyword">super</span><span class="token punctuation">.</span><span class="token function">onOptionsItemSelected</span><span class="token punctuation">(</span>item<span class="token punctuation">)</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">override</span> <span class="token keyword">fun</span> <span class="token function">onNavigationItemSelected</span><span class="token punctuation">(</span>item<span class="token operator">:</span> MenuItem<span class="token punctuation">)</span><span class="token operator">:</span> Boolean <span class="token punctuation">{</span>
        <span class="token keyword">when</span> <span class="token punctuation">(</span>item<span class="token punctuation">.</span>itemId<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            R<span class="token punctuation">.</span>id<span class="token punctuation">.</span>nav_camera <span class="token operator">-></span> <span class="token function">toast</span><span class="token punctuation">(</span><span class="token string-literal singleline"><span class="token string">"Camera"</span></span><span class="token punctuation">)</span>
            R<span class="token punctuation">.</span>id<span class="token punctuation">.</span>nav_gallery <span class="token operator">-></span> <span class="token function">toast</span><span class="token punctuation">(</span><span class="token string-literal singleline"><span class="token string">"Gallery"</span></span><span class="token punctuation">)</span>
            R<span class="token punctuation">.</span>id<span class="token punctuation">.</span>nav_slideshow <span class="token operator">-></span> <span class="token function">toast</span><span class="token punctuation">(</span><span class="token string-literal singleline"><span class="token string">"Slideshow"</span></span><span class="token punctuation">)</span>
            R<span class="token punctuation">.</span>id<span class="token punctuation">.</span>nav_manage <span class="token operator">-></span> <span class="token function">toast</span><span class="token punctuation">(</span><span class="token string-literal singleline"><span class="token string">"Manage"</span></span><span class="token punctuation">)</span>
            R<span class="token punctuation">.</span>id<span class="token punctuation">.</span>nav_share <span class="token operator">-></span> <span class="token function">toast</span><span class="token punctuation">(</span><span class="token string-literal singleline"><span class="token string">"Share"</span></span><span class="token punctuation">)</span>
            R<span class="token punctuation">.</span>id<span class="token punctuation">.</span>nav_send <span class="token operator">-></span> <span class="token function">toast</span><span class="token punctuation">(</span><span class="token string-literal singleline"><span class="token string">"Send"</span></span><span class="token punctuation">)</span>
        <span class="token punctuation">}</span>
        drawer<span class="token punctuation">.</span><span class="token function">closeDrawer</span><span class="token punctuation">(</span>GravityCompat<span class="token punctuation">.</span>START<span class="token punctuation">)</span>
        <span class="token keyword">return</span> <span class="token boolean">true</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre></div>
<p>In contrast with the <a href="https://gist.github.com/ElMassimo/839df056c44b7c8e53b7" target="_blank" rel="nofollow noopener noreferrer">generated version</a>, the <em>Anko</em> version does require some boilerplate to set dimensions and colors from resources, but has a lot of expressiveness when it comes to bindings. Notice how it's not necessary to create references to most of the components, since the listeners are added to each view when they are instantiated:</p>
<div class="language-kotlin" data-lang="kotlin"><pre class="language-kotlin"><code>floatingActionButton <span class="token punctuation">{</span>
    onClick <span class="token punctuation">{</span> <span class="token function">snackbar</span><span class="token punctuation">(</span><span class="token string-literal singleline"><span class="token string">"FAB"</span></span><span class="token punctuation">,</span> Snackbar<span class="token punctuation">.</span>LENGTH_LONG<span class="token punctuation">)</span> <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre></div>
<p>Compare this to the usual code, which incurs in the cost of finding the view (even if it's a very low cost) and referencing the view id:</p>
<div class="language-kotlin" data-lang="kotlin"><pre class="language-kotlin"><code><span class="token keyword">val</span> fab<span class="token operator">:</span>FloatingActionButton <span class="token operator">=</span> <span class="token function">findViewById</span><span class="token punctuation">(</span>R<span class="token punctuation">.</span>id<span class="token punctuation">.</span>fab<span class="token punctuation">)</span> <span class="token keyword">as</span> FloatingActionButton
fab<span class="token punctuation">.</span><span class="token function">setOnClickListener</span> <span class="token punctuation">{</span>
  Snackbar<span class="token punctuation">.</span><span class="token function">make</span><span class="token punctuation">(</span>it<span class="token punctuation">,</span> <span class="token string-literal singleline"><span class="token string">"FAB"</span></span><span class="token punctuation">,</span> Snackbar<span class="token punctuation">.</span>LENGTH_LONG<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">show</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span></code></pre></div>
<p>The <em>Anko DSL</em> exposes the native API of each View, so it's only possible to do what <em>Android</em> components can do, with the exception of a few synthetic properties to set text or an image from a resource.</p>
<p>Unfortunately, that means things get pretty rough once we dive into styling and theming. The <em>Android SDK</em> and support libraries contain a lot of <em>hacks</em> that rely on the view being created by a <code>LayoutInflater</code> from the XML, initializing the view with a <code>Context</code> and an <code>AttributeSet</code>. There's no first-class support for setting the <a href="https://github.com/Kotlin/anko/issues/16" target="_blank" rel="nofollow noopener noreferrer">style</a> or theme programmatically, which means it's not possible to set them when using <em>Anko</em> either.</p>
<p><em>Anko</em> does provide a way to <a href="https://github.com/Kotlin/anko#styles" target="_blank" rel="nofollow noopener noreferrer">style a view</a>, but it leaves much to be desired since it requires targeting the different view classes manually, unlike styling in XML where valid attributes are applied automatically.</p>
<p>When it comes to theming, <em>Android</em> uses <a href="https://chris.banes.dev/theme-vs-style/#underlying-functionality" target="_blank" rel="nofollow noopener noreferrer"><code>ContextThemeWrapper</code></a> internally to override <code>getTheme</code> for a view or its children. Since the <a href="https://github.com/Kotlin/anko/releases/tag/v0.8.1" target="_blank" rel="nofollow noopener noreferrer">current <em>Anko</em> version</a> does not allow to override the context used to create a view inside the DSL, using a theme-wrapped context manually is extremely contrived.</p>
<p>No theming support is a serious limitation, since most components in the design library need a theme to be styled properly.</p>
<picture><source media="(-webkit-min-device-pixel-ratio: 1.5)" type="image/avif" srcset="/assets/anko-vs-xml.878de5b7.avif 420w, /assets/anko-vs-xml.dc7f8f88.avif 720w"><source media="(-webkit-min-device-pixel-ratio: 1.5)" type="image/webp" srcset="/assets/anko-vs-xml.9c3431a9.webp 420w, /assets/anko-vs-xml.895f8756.webp 720w"><source media="(-webkit-min-device-pixel-ratio: 1.5)" srcset="/assets/anko-vs-xml.4c9b5985.png 420w, /assets/anko-vs-xml.fed7427d.png 720w"><source type="image/avif" srcset="/assets/anko-vs-xml.a01cd55f.avif 720w"><source type="image/webp" srcset="/assets/anko-vs-xml.4ee4dae2.webp 720w"><img srcset="/assets/anko-vs-xml.64aaee96.png 720w" loading="lazy" src="/assets/anko-vs-xml.64aaee96.png" class="img square" alt="Anko does not have theming support"></picture>
<p>It should be possible to add support for theming in <em>Anko</em>, but unfortunately theming is just one of many XML-based hacks and workarounds in the SDK.</p>
<p>Adding views with Java code is very cumbersome, so most Java developers will stick to XML, and the SDK and support library will continue to do hacks around XML inflation.</p>
<p>The idea behind the <em>Anko DSL</em> is a very interesting one, but it seems like the <em>Android SDK</em> is not polished enough for <em>Anko</em> to reach its full potential.</p>]]></content>
        <author>
            <name>Máximo Mussini</name>
            <uri>https://maximomussini.com</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[CoffeeScript and JS Libraries]]></title>
        <id>https://maximomussini.com/posts/coffeescript-js-libraries</id>
        <link href="https://maximomussini.com/posts/coffeescript-js-libraries"/>
        <updated>2015-12-31T21:58:00.000Z</updated>
        <summary type="html"><![CDATA[Be careful when using a library that was designed for a different language.]]></summary>
        <content type="html"><![CDATA[<p>A language helps to shape the libraries that are written on it. This can have unexpected side-effects when using these libraries from a different language.</p>
<p>In the frontend this has become increasingly more common because of all the available languages that compile to JavaScript. <a href="https://coffeescript.org/" target="_blank" rel="nofollow noopener noreferrer"><em>CoffeeScript</em></a> was one of the first ones to gain adoption, but nowadays we have a myriad of available languages like <a href="https://elm-lang.org/" target="_blank" rel="nofollow noopener noreferrer"><em>Elm</em></a>, <a href="https://github.com/clojure/clojurescript" target="_blank" rel="nofollow noopener noreferrer"><em>ClojureScript</em></a>, <a href="https://opalrb.com/" target="_blank" rel="nofollow noopener noreferrer"><em>Opal</em></a>, and <a href="https://github.com/jashkenas/coffeescript/wiki/List-of-languages-that-compile-to-JS" target="_blank" rel="nofollow noopener noreferrer">many more</a>.</p>
<p>Recently, we were trying to debug a strange issue with <a href="http://www.nick-cherry.com" target="_blank" rel="nofollow noopener noreferrer">one of my coworkers</a>, where we had a list of selectable items with a checkbox to select/unselect all the items. Selecting all the items was working properly, but only the first item got unselected.</p>
<figure class="example-wrapper"><iframe src="/examples/select_all_broken.html" height="254" frameborder="0" class="example" scrolling="no" loading="lazy"></iframe></figure>
<p>After debugging it for a while we reached the conclusion that the iteration was being interrupted. Could <a href="http://lodash.com" target="_blank" rel="nofollow noopener noreferrer"><code>lodash</code></a> have such a serious bug?</p>
<div class="language-coffeescript" data-lang="coffeescript"><pre class="language-coffeescript"><code>selectAll <span class="token operator">=</span> <span class="token punctuation">(</span>isSelected<span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span>
  _<span class="token punctuation">.</span><span class="token keyword">each</span> tasks<span class="token punctuation">,</span> <span class="token punctuation">(</span>task<span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span> task<span class="token punctuation">.</span>selected <span class="token operator">=</span> isSelected</code></pre></div>
<p>Fortunately, we decided to skip that theory, and instead reached for the <a href="https://lodash.com/docs#forEach" target="_blank" rel="nofollow noopener noreferrer">documentation</a>, which stated:</p>
<blockquote>
<p>Iteratee functions may exit iteration early by explicitly returning false.</p>
</blockquote>
<p>Which sounds like a reasonable feature that can help to create more efficient algorithms—though we weren't returning <code>false</code>!</p>
<p>But CoffeeScript was. The language draws inspiration from Ruby, and it borrows features like expressions and implicit returns. For functions, this means that the last executed expression becomes the return value of the function. This allows us to write very concise functions:</p>
<div class="language-coffeescript" data-lang="coffeescript"><pre class="language-coffeescript"><code>isEven <span class="token operator">=</span> <span class="token punctuation">(</span>n<span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span> n <span class="token operator">%</span> <span class="token number">2</span> <span class="token operator">==</span> <span class="token number">0</span></code></pre></div>
<p>If we reinterpret our snippet above taking implicit returns into account, it is equivalent to:</p>
<div class="language-javascript" data-lang="javascript"><pre class="language-javascript"><code><span class="token keyword">function</span> <span class="token function">selectAll</span><span class="token punctuation">(</span><span class="token parameter">isSelected</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> _<span class="token punctuation">.</span><span class="token function">each</span><span class="token punctuation">(</span>tasks<span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">task</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> task<span class="token punctuation">.</span>selected <span class="token operator">=</span> isSelected <span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span></code></pre></div>
<p>When we unselect all the items and <code>selectAll(false)</code> is called, the first iteration returns the value of <code>task.selected</code> which is <code>false</code>, causing <em>lodash</em> to exit the iteration. Mistery solved <span role="img" aria-label="magnifying glass tilted left">🔍</span></p>
<figure class="example-wrapper"><iframe src="/examples/select_all.html" height="254" frameborder="0" class="example" scrolling="no" loading="lazy"></iframe></figure>
<p>We can fix the bug by explicitly returning <code>null</code> or <code>true</code> on each loop, which will avoid stopping the iteration, and all the items will be unselected correctly.</p>
<div class="language-coffeescript" data-lang="coffeescript"><pre class="language-coffeescript"><code>selectAll <span class="token operator">=</span> <span class="token punctuation">(</span>isSelected<span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span>
  _<span class="token punctuation">.</span><span class="token keyword">each</span> tasks<span class="token punctuation">,</span> <span class="token punctuation">(</span>task<span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span>
    task<span class="token punctuation">.</span>selected <span class="token operator">=</span> isSelected
    <span class="token keyword">true</span></code></pre></div>
<p>These are two useful features on their own, yet extremely inconvenient when combined. The reason is that the library was written for a language with a different mindset. The design of the language and the design of the library are not fully compatible.</p>
<h2 id="tldr" class="heading"><a href="#tldr" class="heading-anchor" aria-label="Permalink for TL;DR" tabindex="-1"></a>TL;DR</h2>
<p>Watch out for language differences when using libraries written for another language, they will bite sooner or later.</p>]]></content>
        <author>
            <name>Máximo Mussini</name>
            <uri>https://maximomussini.com</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Improving your Git Experience in Bash]]></title>
        <id>https://maximomussini.com/posts/bash-git-prompt</id>
        <link href="https://maximomussini.com/posts/bash-git-prompt"/>
        <updated>2015-12-14T20:46:00.000Z</updated>
        <summary type="html"><![CDATA[Learn how to improve your Git usage in bash by adding a few plugins.]]></summary>
        <content type="html"><![CDATA[


<p><em>Bash</em> is the default terminal for most Unix distributions, so it's very appealing to get the best out of it. If you enjoy customizing your setup, you might want to try something like <a href="http://ohmyz.sh/" target="_blank" rel="nofollow noopener noreferrer">zsh</a> instead, which comes with similar functionality out of the box.</p>
<p>Let's take a look at how we can improve our <em>Git</em> usage in <em>bash</em> by adding a
few plugins <span role="img" aria-label="laptop">💻</span></p>
<h2 id="bash-git-autocompletion" class="heading"><a href="#bash-git-autocompletion" class="heading-anchor" aria-label="Permalink for Bash Git Autocompletion" tabindex="-1"></a>Bash Git Autocompletion</h2>
<p>A great way to get <em>Git</em> autocompletion is to install the <code>bash-completion</code> package. This plugin will improve our experience when switching or pulling different branches, and is a real time-saver when using <a href="https://git-scm.com/book/en/v2/Git-Branching-Branching-Workflows#Topic-Branches" target="_blank" rel="nofollow noopener noreferrer">topic branches</a>.</p>
<p><picture><source media="(-webkit-min-device-pixel-ratio: 1.5)" type="image/avif" srcset="/assets/git-autocompletion.84ac22ea.avif 420w, /assets/git-autocompletion.b0b92a29.avif 720w"><source media="(-webkit-min-device-pixel-ratio: 1.5)" type="image/webp" srcset="/assets/git-autocompletion.fcdd8f5c.webp 420w, /assets/git-autocompletion.fe6818cc.webp 720w"><source media="(-webkit-min-device-pixel-ratio: 1.5)" srcset="/assets/git-autocompletion.f657ffb4.png 420w, /assets/git-autocompletion.6b4afda2.png 720w"><source type="image/avif" srcset="/assets/git-autocompletion.13f1914a.avif 720w"><source type="image/webp" srcset="/assets/git-autocompletion.52f732bd.webp 720w"><img srcset="/assets/git-autocompletion.2c1fae54.png 720w" loading="lazy" src="/assets/git-autocompletion.2c1fae54.png" class="img" alt="Checking out Branches"></picture></p>
<h3 id="installation-on-os-x" class="heading"><a href="#installation-on-os-x" class="heading-anchor" aria-label="Permalink for Installation on OS X" tabindex="-1"></a>Installation on OS X</h3>
<p>First, install <code>bash-completion</code> using <a href="http://brew.sh/" target="_blank" rel="nofollow noopener noreferrer">Homebrew</a>:</p>
<div class="language-bash" data-lang="bash"><pre class="language-bash"><code>brew <span class="token function">install</span> bash-completion</code></pre></div>
<p>and then add this line to <code>~/.bash_profile</code> to load the plugin:</p>
<div class="language-bash" data-lang="bash"><pre class="language-bash"><code><span class="token punctuation">[</span><span class="token punctuation">[</span> <span class="token parameter variable">-f</span> <span class="token string">"<span class="token variable"><span class="token variable">$(</span>brew <span class="token parameter variable">--prefix</span><span class="token variable">)</span></span>/etc/bash_completion"</span> <span class="token punctuation">]</span><span class="token punctuation">]</span> <span class="token operator">&amp;&amp;</span> <span class="token builtin class-name">source</span> <span class="token string">"<span class="token variable"><span class="token variable">$(</span>brew <span class="token parameter variable">--prefix</span><span class="token variable">)</span></span>/etc/bash_completion"</span></code></pre></div>
<h3 id="installation-on-ubuntu" class="heading"><a href="#installation-on-ubuntu" class="heading-anchor" aria-label="Permalink for Installation on Ubuntu" tabindex="-1"></a>Installation on Ubuntu</h3>
<div class="language-bash" data-lang="bash"><pre class="language-bash"><code><span class="token function">sudo</span> <span class="token function">apt-get</span> <span class="token function">install</span> bash-completion</code></pre></div>
<h2 id="bash-git-prompt" class="heading"><a href="#bash-git-prompt" class="heading-anchor" aria-label="Permalink for Bash Git Prompt" tabindex="-1"></a>Bash Git Prompt</h2>
<p>Running a <em>Git</em> command without knowing the current branch is like running <code>rm</code> or <code>mkdir</code> in the terminal without knowning the current directory: it's dangerous and error-prone.</p>
<p>Sure, we could type <code>pwd</code> every time before running those commands, but it wouldn't be practical. Why not take the same approach for <em>Git</em>, and display the current branch in the terminal prompt?</p>
<p><a href="https://github.com/magicmonty/bash-git-prompt" target="_blank" rel="nofollow noopener noreferrer"><code>bash-git-prompt</code></a> is a project that takes care of that, displaying the current branch and other helpful stats. It has many different themes available, which can be customized by specifying a theme through the <code>GIT_PROMPT_THEME</code> environment variable.</p>
<p><picture><source media="(-webkit-min-device-pixel-ratio: 1.5)" type="image/avif" srcset="/assets/git-prompt-default.32ad3fe3.avif 420w, /assets/git-prompt-default.fd5a86b0.avif 720w"><source media="(-webkit-min-device-pixel-ratio: 1.5)" type="image/webp" srcset="/assets/git-prompt-default.c150f7f8.webp 420w, /assets/git-prompt-default.16dfc6aa.webp 720w"><source media="(-webkit-min-device-pixel-ratio: 1.5)" srcset="/assets/git-prompt-default.4d27a6e1.png 420w, /assets/git-prompt-default.4dad8018.png 720w"><source type="image/avif" srcset="/assets/git-prompt-default.d2d487b9.avif 720w"><source type="image/webp" srcset="/assets/git-prompt-default.91380bc5.webp 720w"><img srcset="/assets/git-prompt-default.c3a57a22.png 720w" loading="lazy" src="/assets/git-prompt-default.c3a57a22.png" class="img" alt="Default Theme"></picture></p>
<h3 id="installation-on-os-x-2" class="heading"><a href="#installation-on-os-x-2" class="heading-anchor" aria-label="Permalink for Installation on OS X" tabindex="-1"></a>Installation on OS X</h3>
<p>First, install <code>bash-git-prompt</code> using <a href="http://brew.sh/" target="_blank" rel="nofollow noopener noreferrer">Homebrew</a>:</p>
<div class="language-bash" data-lang="bash"><pre class="language-bash"><code>brew <span class="token function">install</span> bash-git-prompt</code></pre></div>
<p>And then source the file in your ~/.bash_profile as follows:</p>
<div class="language-bash" data-lang="bash"><pre class="language-bash"><code><span class="token punctuation">[</span><span class="token punctuation">[</span> <span class="token parameter variable">-f</span> <span class="token string">"<span class="token variable"><span class="token variable">$(</span>brew <span class="token parameter variable">--prefix</span><span class="token variable">)</span></span>/opt/bash-git-prompt/share/gitprompt.sh"</span> <span class="token punctuation">]</span><span class="token punctuation">]</span> <span class="token operator">&amp;&amp;</span> <span class="token builtin class-name">source</span> <span class="token string">"<span class="token variable"><span class="token variable">$(</span>brew <span class="token parameter variable">--prefix</span><span class="token variable">)</span></span>/opt/bash-git-prompt/share/gitprompt.sh"</span></code></pre></div>
<h4 id="installation-on-ubuntu-2" class="heading"><a href="#installation-on-ubuntu-2" class="heading-anchor" aria-label="Permalink for Installation on Ubuntu" tabindex="-1"></a>Installation on Ubuntu</h4>
<p>It might be necessary to <a href="https://github.com/magicmonty/bash-git-prompt#via-git-clone" target="_blank" rel="nofollow noopener noreferrer">clone the project's git repo</a>, and source <code>gitprompt.sh</code> into the <code>~/.bashrc</code> file.</p>
<h4 id="basic-customization" class="heading"><a href="#basic-customization" class="heading-anchor" aria-label="Permalink for Basic Customization" tabindex="-1"></a>Basic Customization</h4>
<p>The following are some settings I modified in my <code>~/.bash_profile</code>:</p>
<div class="language-bash" data-lang="bash"><pre class="language-bash"><code><span class="token assign-left variable">GIT_PROMPT_ONLY_IN_REPO</span><span class="token operator">=</span><span class="token number">1</span> <span class="token comment"># Use the default prompt when not in a git repo.</span>
<span class="token assign-left variable">GIT_PROMPT_FETCH_REMOTE_STATUS</span><span class="token operator">=</span><span class="token number">0</span> <span class="token comment"># Avoid fetching remote status</span>
<span class="token assign-left variable">GIT_PROMPT_SHOW_UPSTREAM</span><span class="token operator">=</span><span class="token number">0</span> <span class="token comment"># Don't display upstream tracking branch</span>
<span class="token assign-left variable">GIT_SHOW_UNTRACKED_FILES</span><span class="token operator">=</span>no <span class="token comment"># Don't count untracked files (no, normal, all)</span></code></pre></div>
<p>These constants must be defined before sourcing <code>bash-git-prompt</code> in the <code>~/.bash_profile</code> or <code>~/.bashrc</code> file.</p>
<h2 id="customizing-the-git-prompt" class="heading"><a href="#customizing-the-git-prompt" class="heading-anchor" aria-label="Permalink for Customizing the Git Prompt" tabindex="-1"></a>Customizing the Git Prompt</h2>
<p>The themes that come bundled with <a href="https://github.com/magicmonty/bash-git-prompt" target="_blank" rel="nofollow noopener noreferrer"><code>bash-git-prompt</code></a> displayed too much information for my taste, and the symbols in the default theme are not particularly meaningful.</p>
<p>After trying different themes, I decided to bake my own. I wanted something that emphasized the important bits and pieces, looked clean, and was easy to understand. Fortunately, the plugin provides a command to generate a custom theme file:</p>
<div class="language-bash" data-lang="bash"><pre class="language-bash"><code>git_prompt_make_custom_theme Default</code></pre></div>
<p>The command creates a <code>~/.git-prompt-colors.sh</code> based on the default theme and will get loaded by the plugin automatically, so you can start playing with the variables right away. However, you may need to dive into the source code to figure out how each variable is used, and find the ones you want to customize.</p>
<p>After tweaking the variables for a while, I was able to create a custom theme. The expresiveness of emojis made it easier for me to understand the current git status <span role="img" aria-label="grinning face with sweat">😅</span></p>
<p><picture><source media="(-webkit-min-device-pixel-ratio: 1.5)" type="image/avif" srcset="/assets/git-prompt-emoji.7c8250df.avif 420w, /assets/git-prompt-emoji.1a3589be.avif 720w"><source media="(-webkit-min-device-pixel-ratio: 1.5)" type="image/webp" srcset="/assets/git-prompt-emoji.029c1916.webp 420w, /assets/git-prompt-emoji.d21035d9.webp 720w"><source media="(-webkit-min-device-pixel-ratio: 1.5)" srcset="/assets/git-prompt-emoji.24493767.png 420w, /assets/git-prompt-emoji.e47ec5a1.png 720w"><source type="image/avif" srcset="/assets/git-prompt-emoji.b674d7d6.avif 720w"><source type="image/webp" srcset="/assets/git-prompt-emoji.c230a4b0.webp 720w"><img srcset="/assets/git-prompt-emoji.8fb69bc5.png 720w" loading="lazy" src="/assets/git-prompt-emoji.8fb69bc5.png" class="img" alt="Emoji Theme"></picture></p>
<div class="language-bash" data-lang="bash"><pre class="language-bash"><code><span class="token comment"># .git-prompt-colors.sh</span>

<span class="token function-name function">override_git_prompt_colors</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token assign-left variable">GIT_PROMPT_THEME_NAME</span><span class="token operator">=</span><span class="token string">"Custom"</span>

  <span class="token assign-left variable">PathShort</span><span class="token operator">=</span><span class="token string">"\W"</span> <span class="token comment"># Display only the current folder</span>

  <span class="token comment"># Display the current folder first</span>
  <span class="token assign-left variable">GIT_PROMPT_START_USER</span><span class="token operator">=</span><span class="token string">"<span class="token variable">${Green}</span><span class="token variable">${PathShort}</span>"</span>
  <span class="token assign-left variable">GIT_PROMPT_START_ROOT</span><span class="token operator">=</span><span class="token string">"<span class="token variable">${Green}</span><span class="token variable">${PathShort}</span>"</span>

  <span class="token comment"># Skip the default prefix</span>
  <span class="token assign-left variable">GIT_PROMPT_PREFIX</span><span class="token operator">=</span><span class="token string">"<span class="token variable">${ResetColor}</span>"</span>

  <span class="token comment"># Use whitespace as separator</span>
  <span class="token assign-left variable">GIT_PROMPT_SEPARATOR</span><span class="token operator">=</span><span class="token string">" "</span>

  <span class="token comment"># Skip remote branch</span>
  <span class="token assign-left variable">GIT_PROMPT_REMOTE</span><span class="token operator">=</span><span class="token string">"<span class="token variable">${ResetColor}</span>"</span>
  <span class="token assign-left variable">GIT_PROMPT_UPSTREAM</span><span class="token operator">=</span><span class="token string">"<span class="token variable">${ResetColor}</span>"</span>

  <span class="token comment"># Use yellow for the current branch</span>
  <span class="token assign-left variable">GIT_PROMPT_BRANCH</span><span class="token operator">=</span><span class="token string">"<span class="token variable">${Yellow}</span>"</span>

  <span class="token comment"># Use red and green for behind and ahead origin</span>
  <span class="token assign-left variable">GIT_PROMPT_SYMBOLS_BEHIND</span><span class="token operator">=</span><span class="token string">"<span class="token variable">${Red}</span> ↓"</span>
  <span class="token assign-left variable">GIT_PROMPT_SYMBOLS_AHEAD</span><span class="token operator">=</span><span class="token string">"<span class="token variable">${Green}</span> ↑"</span>

  <span class="token comment"># Add a few emojis to make it fun!</span>
  <span class="token assign-left variable">GIT_PROMPT_STAGED</span><span class="token operator">=</span><span class="token string">"<span class="token variable">${Yellow}</span>👍 "</span>
  <span class="token assign-left variable">GIT_PROMPT_CONFLICTS</span><span class="token operator">=</span><span class="token string">"<span class="token variable">${Red}</span>❌ "</span>
  <span class="token assign-left variable">GIT_PROMPT_CHANGED</span><span class="token operator">=</span><span class="token string">"<span class="token variable">${Yellow}</span>✏️ "</span>
  <span class="token assign-left variable">GIT_PROMPT_UNTRACKED</span><span class="token operator">=</span><span class="token string">"❔ "</span>
  <span class="token assign-left variable">GIT_PROMPT_STASHED</span><span class="token operator">=</span><span class="token string">"<span class="token variable">${Yellow}</span>📦 "</span> <span class="token comment"># A lot nicer than the default flag</span>
  <span class="token assign-left variable">GIT_PROMPT_CLEAN</span><span class="token operator">=</span><span class="token string">"<span class="token variable">${ResetColor}</span>✅ "</span>  
  <span class="token assign-left variable">GIT_PROMPT_SYMBOLS_NO_REMOTE_TRACKING</span><span class="token operator">=</span><span class="token string">" 🔒 "</span> <span class="token comment"># when a branch is untracked</span>

  <span class="token comment"># Skip the default suffix</span>
  <span class="token assign-left variable">GIT_PROMPT_SUFFIX</span><span class="token operator">=</span><span class="token string">" "</span>

  <span class="token comment"># Skip the default ending</span>
  <span class="token assign-left variable">GIT_PROMPT_END_USER</span><span class="token operator">=</span><span class="token string">"<span class="token variable">${ResetColor}</span>"</span>
  <span class="token assign-left variable">GIT_PROMPT_END_ROOT</span><span class="token operator">=</span><span class="token string">"<span class="token variable">${ResetColor}</span>"</span>
<span class="token punctuation">}</span>

reload_git_prompt_colors <span class="token string">"Custom"</span></code></pre></div>
<p>Emojis are a great way to make ye olde terminal a bit more fun! <span role="img" aria-label="party popper">🎉</span></p>
<hr>
<p>It would be awesome if <a href="https://github.com/magicmonty/bash-git-prompt" target="_blank" rel="nofollow noopener noreferrer"><code>bash-git-prompt</code></a> provided a way to customize the full prompt order and displayed elements, with a template string like:</p>
<div class="language-bash" data-lang="bash"><pre class="language-bash"><code><span class="token assign-left variable">GIT_PROMPT</span><span class="token operator">=</span><span class="token string">"{PathShort}{Branch}{Remote}{Modified}{Staged}{Clean}"</span></code></pre></div>
<p>That would make it possible to create very different themes, as well as opting out of certain information—like git stashes.</p>
<p>For now, I'm pleased with the result; it's practical, looks nice, and I don't need to type <code>git branch</code> to check the current branch <span role="img" aria-label="smiling face with sunglasses">😎</span></p>]]></content>
        <author>
            <name>Máximo Mussini</name>
            <uri>https://maximomussini.com</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Ruby & to_proc]]></title>
        <id>https://maximomussini.com/posts/ruby-to_proc</id>
        <link href="https://maximomussini.com/posts/ruby-to_proc"/>
        <updated>2015-12-07T22:22:00.000Z</updated>
        <summary type="html"><![CDATA[An extremely common idiom in Ruby uses symbols to specify the method that should be called, but.. how does it work?]]></summary>
        <content type="html"><![CDATA[<p>Blocks are a very unique part of Ruby's syntax. Let's look at a simple example:</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code><span class="token string-literal"><span class="token string">'Jane Jim Jenny'</span></span><span class="token punctuation">.</span>split<span class="token punctuation">.</span>map <span class="token punctuation">{</span> <span class="token operator">|</span>s<span class="token operator">|</span> s<span class="token punctuation">.</span>length <span class="token punctuation">}</span><span class="token punctuation">.</span>reduce <span class="token punctuation">{</span> <span class="token operator">|</span>sum<span class="token punctuation">,</span> n<span class="token operator">|</span> sum <span class="token operator">+</span> n <span class="token punctuation">}</span>
<span class="token comment"># => 12</span></code></pre></div>
<p>When performing this kind of functional transformation, it's tedious to write a block to perform a simple method call. An extremely common idiom in Ruby uses symbols to specify the method that should be called:</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code>names<span class="token punctuation">.</span>map<span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token symbol">:length</span><span class="token punctuation">)</span><span class="token punctuation">.</span>reduce<span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token operator">:</span><span class="token operator">+</span><span class="token punctuation">)</span></code></pre></div>
<blockquote>
<p>Sweet! <span role="img" aria-label="shortcake">🍰</span></p>
</blockquote>
<p>In Ruby, the ampersand operator <code>&#x26;</code> can coerce an object into a <code>Proc</code> by calling the <code>to_proc</code> method if it's defined. More generally, <code>&#x26;object</code> will be evaluated in the following way:</p>
<ul>
<li>object is a <code>Proc</code>: <code>&#x26;</code> converts it to a block.</li>
<li>object is not a <code>Proc</code>: <code>&#x26;</code> tries to call <code>to_proc</code> on the object, and then converts it to a block.</li>
</ul>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code>names<span class="token punctuation">.</span>map <span class="token operator">&amp;</span><span class="token symbol">:to_s</span>
<span class="token comment"># is the same than</span>
names<span class="token punctuation">.</span>map <span class="token operator">&amp;</span><span class="token symbol">:to_s</span><span class="token punctuation">.</span>to_proc</code></pre></div>
<blockquote>
<p>Huh? <span role="img" aria-label="confused face">😕</span></p>
</blockquote>
<p>It turns out the <em>magic</em> is in how Ruby defines <code>to_proc</code> for symbols. In recent versions of Ruby, the method is <a href="https://ruby-doc.org/core/Symbol.html#method-i-to_proc" target="_blank" rel="nofollow noopener noreferrer">defined in C</a>, but it would look like this in Ruby:</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code><span class="token keyword">class</span> <span class="token class-name">Symbol</span>
  <span class="token keyword">def</span> <span class="token method-definition"><span class="token function">to_proc</span></span>
    <span class="token operator">-</span><span class="token operator">></span><span class="token punctuation">(</span>obj<span class="token punctuation">,</span> args <span class="token operator">=</span> <span class="token keyword">nil</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> obj<span class="token punctuation">.</span>send<span class="token punctuation">(</span><span class="token keyword">self</span><span class="token punctuation">,</span> <span class="token operator">*</span>args<span class="token punctuation">)</span> <span class="token punctuation">}</span>
  <span class="token keyword">end</span>
<span class="token keyword">end</span></code></pre></div>
<p>Back to our snippet, let's expand the <code>to_proc</code> call incrementally until we arrive at the same block we would write by hand:</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code>names<span class="token punctuation">.</span>map <span class="token operator">&amp;</span><span class="token symbol">:to_s</span>

<span class="token comment"># We can expand it to</span>
names<span class="token punctuation">.</span>map <span class="token operator">&amp;</span><span class="token symbol">:to_s</span><span class="token punctuation">.</span>to_proc

<span class="token comment"># Replacing "to_proc" with the result of calling the method</span>
names<span class="token punctuation">.</span>map <span class="token operator">&amp;</span><span class="token operator">-</span><span class="token operator">></span><span class="token punctuation">(</span>name<span class="token punctuation">,</span> args <span class="token operator">=</span> <span class="token keyword">nil</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> name<span class="token punctuation">.</span>send<span class="token punctuation">(</span><span class="token symbol">:to_s</span><span class="token punctuation">,</span> <span class="token operator">*</span>args<span class="token punctuation">)</span> <span class="token punctuation">}</span>

<span class="token comment"># "map" passes a single argument to the block, so we can simplify</span>
names<span class="token punctuation">.</span>map <span class="token operator">&amp;</span><span class="token operator">-</span><span class="token operator">></span><span class="token punctuation">(</span>name<span class="token punctuation">)</span> <span class="token punctuation">{</span> name<span class="token punctuation">.</span>send<span class="token punctuation">(</span><span class="token symbol">:to_s</span><span class="token punctuation">)</span> <span class="token punctuation">}</span>

<span class="token comment"># Calling the method directly we get</span>
names<span class="token punctuation">.</span>map <span class="token operator">&amp;</span><span class="token operator">-</span><span class="token operator">></span><span class="token punctuation">(</span>name<span class="token punctuation">)</span> <span class="token punctuation">{</span> name<span class="token punctuation">.</span>to_s <span class="token punctuation">}</span>

<span class="token comment"># Since "&amp;" transforms Procs and Lambdas to blocks, it's equivalent to</span>
names<span class="token punctuation">.</span>map <span class="token punctuation">{</span> <span class="token operator">|</span>name<span class="token operator">|</span> name<span class="token punctuation">.</span>to_s <span class="token punctuation">}</span></code></pre></div>
<p>So there you have it, <code>&#x26;</code> will coerce the <code>:to_s</code> symbol by calling <code>to_proc</code>, and then transform the resulting proc or lambda to a block.</p>
<blockquote>
<p>There's nothing special about the shorthand <code>&#x26;:method</code> syntax. Ruby arbitrarily defines <code>Symbol#to_proc</code> in a way that allows programmers to avoid some boilerplate.</p>
</blockquote>
<h2 id="a-world-of-proc" class="heading"><a href="#a-world-of-proc" class="heading-anchor" aria-label="Permalink for A world of proc 🌎" tabindex="-1"></a>A world of proc <span role="img" aria-label="globe showing Americas">🌎</span></h2>
<p>Now that we understand what is really going on, we could use <code>to_proc</code> for our own benefit by defining it in our objects and classes.</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code><span class="token keyword">require</span> <span class="token string-literal"><span class="token string">'ostruct'</span></span>

<span class="token keyword">class</span> <span class="token class-name">Formula</span>
  <span class="token keyword">def</span> <span class="token method-definition"><span class="token function">initialize</span></span><span class="token punctuation">(</span>formula<span class="token punctuation">)</span>
    <span class="token variable">@formula</span> <span class="token operator">=</span> formula<span class="token punctuation">.</span>gsub<span class="token punctuation">(</span><span class="token string-literal"><span class="token string">'^'</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">'**'</span></span><span class="token punctuation">)</span>
  <span class="token keyword">end</span>

  <span class="token keyword">def</span> <span class="token method-definition"><span class="token function">apply</span></span><span class="token punctuation">(</span>variables<span class="token punctuation">)</span>
    <span class="token class-name">OpenStruct</span><span class="token punctuation">.</span><span class="token keyword">new</span><span class="token punctuation">(</span>variables<span class="token punctuation">)</span><span class="token punctuation">.</span>instance_eval<span class="token punctuation">(</span><span class="token variable">@formula</span><span class="token punctuation">)</span>
  <span class="token keyword">end</span>

  <span class="token keyword">def</span> <span class="token method-definition"><span class="token function">to_proc</span></span>
    <span class="token operator">-</span><span class="token operator">></span><span class="token punctuation">(</span><span class="token operator">*</span>args<span class="token punctuation">)</span><span class="token punctuation">{</span> apply<span class="token punctuation">(</span><span class="token operator">*</span>args<span class="token punctuation">)</span> <span class="token punctuation">}</span>
  <span class="token keyword">end</span>
<span class="token keyword">end</span>

x2 <span class="token operator">=</span> <span class="token class-name">Formula</span><span class="token punctuation">.</span><span class="token keyword">new</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">'x^2 + y^2'</span></span><span class="token punctuation">)</span>
<span class="token punctuation">[</span><span class="token punctuation">{</span> <span class="token symbol">x</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token symbol">y</span><span class="token operator">:</span> <span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token symbol">x</span><span class="token operator">:</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token symbol">y</span><span class="token operator">:</span> <span class="token number">4</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token symbol">x</span><span class="token operator">:</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token symbol">y</span><span class="token operator">:</span> <span class="token number">7</span> <span class="token punctuation">}</span><span class="token punctuation">]</span><span class="token punctuation">.</span>map<span class="token punctuation">(</span><span class="token operator">&amp;</span>x2<span class="token punctuation">)</span>
<span class="token comment"># => [2, 25, 74]</span></code></pre></div>
<p>We may also define <code>to_proc</code> at the class level, allowing us to pass a class as a block:</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code><span class="token keyword">class</span> <span class="token class-name">Formula</span>

  <span class="token keyword">def</span> <span class="token method-definition"><span class="token keyword">self</span><span class="token punctuation">.</span><span class="token function">to_proc</span></span>
    <span class="token operator">-</span><span class="token operator">></span><span class="token punctuation">(</span><span class="token operator">*</span>args<span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token keyword">new</span><span class="token punctuation">(</span><span class="token operator">*</span>args<span class="token punctuation">)</span> <span class="token punctuation">}</span>
  <span class="token keyword">end</span>
<span class="token keyword">end</span>

<span class="token punctuation">[</span><span class="token string-literal"><span class="token string">'x^2 + y^2'</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">'x + y^3'</span></span><span class="token punctuation">]</span><span class="token punctuation">.</span>map<span class="token punctuation">(</span><span class="token operator">&amp;</span>Formula<span class="token punctuation">)</span>
<span class="token comment"># => [#&lt;Formula @formula="x**2 + y**2">, #&lt;Formula: @formula="x + y**3">]</span></code></pre></div>
<h2 id="a-note-on-performance" class="heading"><a href="#a-note-on-performance" class="heading-anchor" aria-label="Permalink for A note on performance 📊" tabindex="-1"></a>A note on performance <span role="img" aria-label="bar chart">📊</span></h2>
<p>Running some benchmarks in Ruby 2.2.3, it seems that there is not an important performance penalty from using <code>to_proc</code>. I wrote a small <a href="https://gist.github.com/ElMassimo/2183ffc0401d1157c78e" target="_blank" rel="nofollow noopener noreferrer">benchmark</a> that you can <a href="https://gist.github.com/ElMassimo/2183ffc0401d1157c78e" target="_blank" rel="nofollow noopener noreferrer">run</a> if you are curious <span role="img" aria-label="grinning face with big eyes">😃</span></p>
<h2 id="summary" class="heading"><a href="#summary" class="heading-anchor" aria-label="Permalink for Summary" tabindex="-1"></a>Summary</h2>
<p>There's nothing special about the shorthand <code>&#x26;:method</code> syntax. Ruby defines <code>Symbol#to_proc</code> in a particular way that allows programmers to avoid some boilerplate, and the <code>&#x26;</code> operator can coerce any object into a block by calling <code>to_proc</code>.</p>
<p><code>Symbol#to_proc</code> is so ubiquitous that there's no harm in using it; most of the times it can help to keep the code terse without any downsides.</p>
<p>However, it's better to stay away from <code>to_proc</code> in everyday usage, since it is as obscure as it is powerful. Defining <code>to_proc</code> for custom objects can make it very difficult to reason about the code, which defeats the purpose of using it in the first place.</p>]]></content>
        <author>
            <name>Máximo Mussini</name>
            <uri>https://maximomussini.com</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[One Does Not Simply Extend Mongoid]]></title>
        <id>https://maximomussini.com/posts/mongoid_includes</id>
        <link href="https://maximomussini.com/posts/mongoid_includes"/>
        <updated>2015-12-01T01:46:00.000Z</updated>
        <summary type="html"><![CDATA[A follow-up on how to solve the N+1 problem using mongoid includes.]]></summary>
        <content type="html"><![CDATA[<p><em>Mongoid</em> is not designed for extensibility; if you need to modify its behaviour in a slight way, you will probably have no choice but to <em>monkey-patch</em> it.</p>
<p>A while ago I was working on a feature that required displaying information from several <em>mongodb</em> collections. The performance was pretty bad, since for each item being displayed it was necessary to traverse nested and polymorphic associations to get the rest of the data.</p>
<p>Although <em>Mongoid</em> provides eager loading support <a href="/posts/mongoid-n+1">out of the box</a>, it has a few limitations:</p>
<ul>
<li><strong>No Nested</strong>: Only direct relations can be eager loaded.</li>
<li><strong>No Polymorphic</strong>: Polymorphic relations can't be included.</li>
<li><strong>Criteria-only</strong>: It's only possible to use eager loading with a <code>Mongoid::Criteria</code> object. We can't leverage the functionality if we have a list of objects.</li>
</ul>
<p>Unfortunately, one of those traversed associations was both <strong>nested &#x26; polymorphic</strong>, so in the beginning the only available solution was to eager load the relations manually.</p>
<p>After thinking about it for a while, I decided to give it a shot and come up with an extension to eager load polymorphic and nested associations, and do away with all the boilerplate that is necessary to perform eager loading.</p>
<h2 id="mongoidincludes" class="heading"><a href="#mongoidincludes" class="heading-anchor" aria-label="Permalink for Mongoid::Includes 💎" tabindex="-1"></a>Mongoid::Includes <span role="img" aria-label="gem stone">💎</span></h2>
<p>When writing the library, I picked a few constraints in order to give the project a clear direction:</p>
<ul>
<li>Reuse <em>Mongoid's</em> eager loading functionality as building blocks.</li>
<li>Fail-fast, or as early as possible.</li>
<li>Cover only the most common use cases.</li>
<li>Allow to override eager loading for the not so common ones.</li>
</ul>
<p>Choosing these constraints allowed me to keep the library fairly small, without compromising its usefulness in more complex scenarios.</p>
<p>The result is <a href="https://github.com/ElMassimo/mongoid_includes" target="_blank" rel="nofollow noopener noreferrer"><code>mongoid_includes</code></a>, a gem that enhances support for eager loading in <em>Mongoid</em>, allowing to include polymorphic and nested associations, and modify eager loading queries on the fly.</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code>Album<span class="token punctuation">.</span>includes<span class="token punctuation">(</span><span class="token symbol">:songs</span><span class="token punctuation">)</span><span class="token punctuation">.</span>includes<span class="token punctuation">(</span><span class="token symbol">:musicians</span><span class="token punctuation">,</span> <span class="token symbol">from</span><span class="token operator">:</span> <span class="token symbol">:band</span><span class="token punctuation">)</span>

Band<span class="token punctuation">.</span>includes<span class="token punctuation">(</span><span class="token symbol">:albums</span><span class="token punctuation">,</span> <span class="token symbol">with</span><span class="token operator">:</span> <span class="token operator">-</span><span class="token operator">></span><span class="token punctuation">(</span>albums<span class="token punctuation">)</span> <span class="token punctuation">{</span> albums<span class="token punctuation">.</span>gt<span class="token punctuation">(</span><span class="token symbol">release</span><span class="token operator">:</span> <span class="token number">1970</span><span class="token punctuation">)</span><span class="token punctuation">.</span>limit<span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div>
<p><code>Mongoid::Includes</code> extends the <code>includes</code> method to support polymorphic associations without any syntax change. For nested includes, it expects a <code>:from</code> option, indicating from which relation the include is going to be performed, eager loading it as well.</p>
<p>While those are the most typical cases, it also supports a <code>:with</code> option which conveniently allows to modify the default query, and a <code>:loader</code> option which receives the foreign keys of the documents to include.</p>
<blockquote>
<p>Polymorphic or nested includes might be a sign of a poorly designed schema. <a href="https://github.com/ElMassimo/mongoid_includes" target="_blank" rel="nofollow noopener noreferrer"><code>mongoid_includes</code></a> is very easy to use, but it should only be used if it's truly necessary.</p>
</blockquote>
<h2 id="extending-mongoid" class="heading"><a href="#extending-mongoid" class="heading-anchor" aria-label="Permalink for Extending Mongoid" tabindex="-1"></a>Extending Mongoid</h2>
<p>Although it was possible to reuse the eager loading logic in <em>Mongoid</em>, doing so required a lot of fiddling and monkey-patching (using <code>prepend</code>), since the library does not provide any point of extension.</p>
<p><em>Mongoid's</em> eager loading was written to work with queries, and assumes that the included documents will match an association on the model, so it relies on the association metadata to perform the includes. There is no simple way to reuse the logic without using relation metadata.</p>
<p>The biggest downside though, is that there is no way to perform eager loading for a set of documents, since the code relies on the contract of <code>Mongoid::Criteria</code>. We can't use eager loading if we triggered the query by using any <code>Enumerable</code> method, or got the models by aggregation or any in-memory operation <span role="img" aria-label="sad but relieved face">😥</span></p>
<p>It would be a lot easier to extend <em>Mongoid's</em> functionality if it had a more modular design. Adding support for plugins that can be attached to the query lifecycle would be a huge step in that direction—less patching means more and better extensions.</p>
<h2 id="a-better-way" class="heading"><a href="#a-better-way" class="heading-anchor" aria-label="Permalink for A Better Way" tabindex="-1"></a>A Better Way</h2>
<p>Some ORMs take a very different approach when it comes to eager loading. <a href="https://github.com/elixir-lang/ecto" target="_blank" rel="nofollow noopener noreferrer">Ecto</a>, a popular database wrapper for the <a href="http://elixir-lang.org/" target="_blank" rel="nofollow noopener noreferrer">Elixir</a> language, has a different <a href="http://hexdocs.pm/ecto/Ecto.html" target="_blank" rel="nofollow noopener noreferrer">philosophy</a>:</p>
<blockquote>
<p>NOTE: Ecto does not lazy load associations. While lazily loading associations may sound convenient at first, in the long run it becomes a source of confusion and performance issues.</p>
</blockquote>
<p>As a long time <em>Mongoid</em> user, I can painfully relate to this statement. <a href="/posts/mongoid-n+1">N+1 queries</a> are one of the fastest ways to degrade performance, and lazy loading associations makes it a lot easier to introduce them by accident. By not implementing lazy loading, the library becomes a lot simpler, and it encourages good practices and efficient data access patterns <span role="img" aria-label="tropical drink">🍹</span></p>
<p>Ecto also allows you to modify which models will be included for an association—like the <code>:with</code> option in <a href="https://github.com/ElMassimo/mongoid_includes" target="_blank" rel="nofollow noopener noreferrer"><code>mongoid_includes</code></a>—and you can also preload associations on a given model or models after they have been fetched from the database using the <a href="http://hexdocs.pm/ecto/Ecto.Repo.html#c:preload/2" target="_blank" rel="nofollow noopener noreferrer"><code>Repo.preload/2</code></a> method. So much win!</p>
<p>Playing with Ecto inspired me to keep looking for a better solution for eager loading in <em>Mongoid</em>. <code>Mongoid::Includes</code> solves the first two limitations, but wouldn't it be great if we could preload documents without a query? <span role="img" aria-label="winking face">😉</span></p>]]></content>
        <author>
            <name>Máximo Mussini</name>
            <uri>https://maximomussini.com</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Avoiding the N+1 problem in Mongoid]]></title>
        <id>https://maximomussini.com/posts/mongoid-n+1</id>
        <link href="https://maximomussini.com/posts/mongoid-n+1"/>
        <updated>2015-10-30T22:30:00.000Z</updated>
        <summary type="html"><![CDATA[An overview of the N+1 problem, and tactics to prevent it in MongoDB.]]></summary>
        <content type="html"><![CDATA[<p>One of the downsides of using an ORM is that it abstracts the queries in a way that it's difficult to understand which queries are being performed; it's harder to notice inefficient queries, since we didn't actually write them!</p>
<p>A performance issue that is very common when using ORMs is the <em>N+1 query</em> problem. This anti-pattern usually occurs when trying to load related information for each item in a list of results.</p>
<p>Since most ORMs don't perform eager loading by default (to avoid fetching more data than necessary), it's necessary to make extra queries <em>per item</em> to fetch the related data. Imagine that we have a simple music store app:</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code><span class="token keyword">class</span> <span class="token class-name">Band</span>
  <span class="token keyword">include</span> Mongoid<span class="token double-colon punctuation">::</span>Document
  has_many <span class="token symbol">:albums</span>
<span class="token keyword">end</span>

<span class="token keyword">class</span> <span class="token class-name">Album</span>
  <span class="token keyword">include</span> Mongoid<span class="token double-colon punctuation">::</span>Document
  belongs_to <span class="token symbol">:band</span>
  has_many <span class="token symbol">:songs</span>
<span class="token keyword">end</span>

<span class="token keyword">class</span> <span class="token class-name">Song</span>
  <span class="token keyword">include</span> Mongoid<span class="token double-colon punctuation">::</span>Document
  belongs_to <span class="token symbol">:album</span>
<span class="token keyword">end</span></code></pre></div>
<p>A classic appearance of the <em>N+1 problem</em> would be:</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code>albums <span class="token operator">=</span> Album<span class="token punctuation">.</span>where<span class="token punctuation">(</span><span class="token symbol">year</span><span class="token operator">:</span> <span class="token number">1970</span><span class="token punctuation">)</span>

albums<span class="token punctuation">.</span><span class="token keyword">each</span> <span class="token keyword">do</span> <span class="token operator">|</span>album<span class="token operator">|</span>
  puts <span class="token string-literal"><span class="token string">"Album: </span><span class="token interpolation"><span class="token delimiter punctuation">#{</span><span class="token content">album<span class="token punctuation">.</span>name</span><span class="token delimiter punctuation">}</span></span><span class="token string">, Band: </span><span class="token interpolation"><span class="token delimiter punctuation">#{</span><span class="token content">album<span class="token punctuation">.</span>band<span class="token punctuation">.</span>name</span><span class="token delimiter punctuation">}</span></span><span class="token string">"</span></span>
<span class="token keyword">end</span></code></pre></div>
<p>In this example, we are loading a list of albums (the first query) and then loading the related band for each album, making one query <em>per album</em>. With a list of <em>N albums</em>, we make 1 query to get the albums and N queries to get the bands: a total of <em>N+1 queries</em>.</p>
<blockquote>
<p>The problem can also appear in other scenarios, such as more complex object graph traversals. In those cases, it can be much harder to spot the cause.</p>
</blockquote>
<p>To understand why this is inefficient, we need to consider the impact of latency in the response time. Even if each of the <em>N queries</em> is executed quickly, each query requires one database round trip. This latency will add up linearly as <em>N</em> increases, which can have a devastating effect in the response time.</p>
<h2 id="avoiding-the-n1-problem" class="heading"><a href="#avoiding-the-n1-problem" class="heading-anchor" aria-label="Permalink for Avoiding the N+1 problem" tabindex="-1"></a>Avoiding the N+1 problem</h2>
<p>A solution to the <em>N+1 problem</em> is to eagerly load the documents that we need, so that when we access a relation it's already preloaded and doesn't trigger a query.</p>
<p>In <em>Mongoid</em>, we can do this by running an <code>$in</code> query using the relation foreign keys to fetch all the related records, and then assign the relations in memory using <code>set_relation</code>. This way, we only perform a single query to fetch a relation, regardless of the amount of documents returned by the first query.</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code>band_ids <span class="token operator">=</span> albums<span class="token punctuation">.</span>map<span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token symbol">:band_id</span><span class="token punctuation">)</span>

bands <span class="token operator">=</span> Band<span class="token punctuation">.</span><span class="token keyword">in</span><span class="token punctuation">(</span><span class="token symbol">id</span><span class="token operator">:</span> band_ids<span class="token punctuation">)</span>

bands <span class="token operator">=</span> bands<span class="token punctuation">.</span>index_by<span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token symbol">:id</span><span class="token punctuation">)</span>
albums<span class="token punctuation">.</span><span class="token keyword">each</span> <span class="token keyword">do</span> <span class="token operator">|</span>album<span class="token operator">|</span>
  album<span class="token punctuation">.</span>set_relation<span class="token punctuation">(</span><span class="token symbol">:band</span><span class="token punctuation">,</span> bands<span class="token punctuation">[</span>album<span class="token punctuation">.</span>band_id<span class="token punctuation">]</span><span class="token punctuation">)</span>
<span class="token keyword">end</span></code></pre></div>
<p>The algorithm changes slightly depending on the type of relation we want to <em>include</em>, and how the foreign keys are stored, but the idea is the same: get a list of foreign keys, use them to make a query to fetch the related documents, and assign the relations in memory using the foreign keys to match the objects.</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code>album_ids <span class="token operator">=</span> albums<span class="token punctuation">.</span>map<span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token symbol">:id</span><span class="token punctuation">)</span>

songs <span class="token operator">=</span> Song<span class="token punctuation">.</span><span class="token keyword">in</span><span class="token punctuation">(</span><span class="token symbol">album_id</span><span class="token operator">:</span> album_ids<span class="token punctuation">)</span>

album_songs <span class="token operator">=</span> songs<span class="token punctuation">.</span>group_by<span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token symbol">:album_id</span><span class="token punctuation">)</span>
albums<span class="token punctuation">.</span><span class="token keyword">each</span> <span class="token keyword">do</span> <span class="token operator">|</span>album<span class="token operator">|</span>
  album<span class="token punctuation">.</span>set_relation<span class="token punctuation">(</span><span class="token symbol">:songs</span><span class="token punctuation">,</span> album_songs<span class="token punctuation">[</span>album<span class="token punctuation">.</span>id<span class="token punctuation">]</span><span class="token punctuation">)</span>
<span class="token keyword">end</span></code></pre></div>
<p>Although eager loading the documents manually is not very complex, writing this logic every time is cumbersome, error-prone, and hard to maintain.</p>
<p>Fortunately, <em>Mongoid</em> has baked-in support to eager load relations using the <code>includes</code> method, which allows to specify all the relations that we want to eager load once the query is made. The following is equivalent to the two snippets above:</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code>albums<span class="token punctuation">.</span>includes<span class="token punctuation">(</span><span class="token symbol">:band</span><span class="token punctuation">,</span> <span class="token symbol">:songs</span><span class="token punctuation">)</span></code></pre></div>
<p>Easy, right? This becomes extremely useful when trying to avoid those sneaky <em>N+1 queries</em> we were talking about <span role="img" aria-label="winking face">😉</span></p>
<h2 id="performance-considerations" class="heading"><a href="#performance-considerations" class="heading-anchor" aria-label="Permalink for Performance Considerations" tabindex="-1"></a>Performance Considerations</h2>
<p>Although eager loading can be helpful, it's important to be aware that:</p>
<ul>
<li>It takes a lot of processing to obtain the foreign keys, fetch the documents from the database, traverse them, and assign them to the objects in memory.</li>
<li><code>$in</code> queries are usually slower, and get slower as the amount of values increases.</li>
</ul>
<p>Most of the times, the overhead of processing in memory and making a more complex query is lower than the latency of issuing a lot of queries separately. Rewriting the code to eager load the relations that we need will usually improve the performance.</p>
<p>As with any performance optimization, there might be some corner cases where eager loading is slower. It's important to run benchmarks and measure the response time to verify that it's worth it to use eager loading <span role="img" aria-label="bar chart">📊</span></p>
<p>Always keep an eye out for this anti-pattern; accessing the database in a naive way will hurt the performance. Using a tool like <a href="https://github.com/flyerhzm/bullet" target="_blank" rel="nofollow noopener noreferrer"><code>bullet</code></a> can help to detect N+1 queries or unused includes, but it's better to use it as a safety net for the cases that slipped past our manual control.</p>
<blockquote>
<p>Have in mind that in <em>mongodb</em> it's possible to embed the related documents instead of storing them in separate collections. Depending on the domain requirements, it can be a very good way to get the best out of the database, and avoid the problem entirely.</p>
</blockquote>
<p>Thinking about data access from the beginning yields the best results, because it allow us to spot potential inefficiencies, and find alternative queries that perform better.</p>
<h2 id="limitations-in-mongoid" class="heading"><a href="#limitations-in-mongoid" class="heading-anchor" aria-label="Permalink for Limitations in Mongoid" tabindex="-1"></a>Limitations in Mongoid</h2>
<p>Eager loading in <em>Mongoid</em> has some limitations:</p>
<ul>
<li><strong>Criteria-only</strong>: It's only possible to use eager loading with a <code>Mongoid::Criteria</code> object. We can't leverage the functionality if we have a list of objects.</li>
<li><strong>No Nested</strong>: Only direct relations can be included, nested relations can't be eagerly loaded (like <code>band.albums.songs</code>).</li>
<li><strong>No Polymorphic</strong>: Polymorphic relations can't be included.</li>
</ul>
<p>The first limitation exists because <em>Mongoid</em> relies on the metadata to pick the appropriate eager loading algorithm. The relation metadata allows to infer things like foreign key names, the name of the database collection, and the name of the setter method for the relation.</p>
<p>I have solved the other limitations in <a href="https://github.com/ElMassimo/mongoid_includes" target="_blank" rel="nofollow noopener noreferrer"><code>mongoid_includes</code></a> <span role="img" aria-label="gem stone">💎</span>, which extends the <code>includes</code> method to support eager loading polymorphic and nested associations.</p>
<p>You can check <a href="/posts/mongoid_includes">the next post</a> where I talk about this gem and explain the motivation behind it, as well as the difficulties of extending <em>Mongoid</em> <span role="img" aria-label="grinning face with big eyes">😃</span></p>]]></content>
        <author>
            <name>Máximo Mussini</name>
            <uri>https://maximomussini.com</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Breaking Mongoid Inheritance]]></title>
        <id>https://maximomussini.com/posts/mongoid-inheritance</id>
        <link href="https://maximomussini.com/posts/mongoid-inheritance"/>
        <updated>2015-10-13T02:29:00.000Z</updated>
        <summary type="html"><![CDATA[A way to use model inheritance without sharing the same collection.]]></summary>
        <content type="html"><![CDATA[<p>By default, <a href="http://mongoid.github.io/" target="_blank" rel="nofollow noopener noreferrer"><em>Mongoid</em></a> will use <a href="http://martinfowler.com/eaaCatalog/singleTableInheritance.html" target="_blank" rel="nofollow noopener noreferrer">single-collection inheritance</a> when extending a Ruby class, by storing a <code>_type</code> attribute in every document in the collection that contains the concrete class name, and using it to instantiate the object properly when fetching a document from the database.</p>
<p>In addition, it will handle the hierarchy in queries, by allowing to query the parent class to return documents from any subclass, or query a specific subclass to fetch only documents of that specific type. In order to do this efficiently, <em>Mongoid</em> will check for existing indexes that contain <code>_type</code> as a prefix, or add a <code>{ _type: 1 }</code> index.</p>
<p>As a consequence of the approach:</p>
<ul>
<li>Storage size increases since we need to store an additional attribute on every document. The smaller the document, the bigger the impact of this extra field.</li>
<li>For large collections, adding a <code>_type</code> index or prefix it to existing ones to create compound indexes could be a concern, since large indexes might not fit in memory, which would quickly degrade the performance.</li>
</ul>
<blockquote>
<p>Bah, trade-offs. It's still awesome <span role="img" aria-label="smirking face">😏</span></p>
</blockquote>
<p>While this behaviour is usually desirable, there are some scenarios where it's suitable to use inheritance in Ruby but it doesn't make sense to store different classes of the hierarchy in the same collection.</p>
<p>In particular, if subclasses will always be queried independently, we can <strong>store each type in a different collection</strong>, which will improve the performance because it:</p>
<ul>
<li>Doesn't require additional indexes.</li>
<li>Doesn't require extra information in each document.</li>
<li>Provides a natural way to partition the data.</li>
</ul>
<blockquote>
<p>Easy. Just use mixins to share code between the subclasses, <em>Mongoid</em> will store them in separate collections <span role="img" aria-label="relieved face">😌</span></p>
</blockquote>
<hr>
<h2 id="an-example-more-like-a-very-contrived-example" class="heading"><a href="#an-example-more-like-a-very-contrived-example" class="heading-anchor" aria-label="Permalink for An example (more like &#x22;A Very Contrived Example&#x22; 😄)" tabindex="-1"></a>An example <small>(more like "A Very Contrived Example" <span role="img" aria-label="grinning face with smiling eyes">😄</span>)</small></h2>
<p>Let's imagine that we have a drawing app, where you can draw many triangles on a canvas, and need to choose between three different drawing modes: regular, equilateral, or isosceles.</p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code><span class="token keyword">class</span> <span class="token class-name">Triangle</span>
  <span class="token keyword">include</span> Mongoid<span class="token double-colon punctuation">::</span>Document
  <span class="token operator">...</span>
<span class="token keyword">end</span>

<span class="token keyword">class</span> <span class="token class-name">IsoscelesTriangle</span> <span class="token operator">&lt;</span> Triangle
  validate_two_sides_are_equal
<span class="token keyword">end</span>

<span class="token keyword">class</span> <span class="token class-name">EquilateralTriangle</span> <span class="token operator">&lt;</span> Triangle
  validate_all_sides_are_equal
<span class="token keyword">end</span></code></pre></div>
<p>We can take advantage of this restriction and store each type of triangle in a separate collection, which will prevent the database from scanning more documents than necessary to execute our queries.</p>
<p>This will be more efficient than adding an extra <code>_type</code> attribute and index, which is the default behaviour provided by <em>Mongoid</em> when inheriting a model. If we want to make this work, we will need to avoid <em>Mongoid</em>'s single-collection inheritance.</p>
<h3 id="mixins" class="heading"><a href="#mixins" class="heading-anchor" aria-label="Permalink for Mixins" tabindex="-1"></a>Mixins</h3>
<p>Using mixins to share the code is a nice way to get the job done, but in this case it falls short because <code>Triangle</code> (the base class) is not abstract—turning it into a module wouldn't allow us to instantiate it. We can deal with this by creating a module that contains the code that we want to reuse.</p>
<p>We shall name it <code>Trianglable</code>. Hmm, sounds weird, let's go with <code>Trilateral</code>. Maybe <code>BaseTriangle</code>? <code>Triangleness</code>? Damn, names are tough <span role="img" aria-label="tired face">😫</span></p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code><span class="token keyword">module</span> <span class="token class-name">AbstractTriangle</span>
  <span class="token keyword">include</span> Mongoid<span class="token double-colon punctuation">::</span>Document
  <span class="token operator">...</span>
<span class="token keyword">end</span>

<span class="token keyword">class</span> <span class="token class-name">Triangle</span>
  <span class="token keyword">include</span> AbstractTriangle
<span class="token keyword">end</span>

<span class="token keyword">class</span> <span class="token class-name">IsoscelesTriangle</span>
  <span class="token keyword">include</span> AbstractTriangle
  validate_two_sides_are_equal
<span class="token keyword">end</span>

<span class="token keyword">class</span> <span class="token class-name">EquilateralTriangle</span>
  <span class="token keyword">include</span> AbstractTriangle
  validate_all_sides_are_equal
<span class="token keyword">end</span></code></pre></div>
<p>Much better <span role="img" aria-label="neutral face">😐</span></p>
<hr>
<h3 id="using-inheritance" class="heading"><a href="#using-inheritance" class="heading-anchor" aria-label="Permalink for Using Inheritance" tabindex="-1"></a>Using Inheritance</h3>
<p>In cases like this I would like to start with inheritance, which can make the code easier to follow, and move to the mixin approach or composition as the requirements change and some of the behaviour or logic in the base class should no longer be shared with the subclasses.</p>
<p>When facing a similar situation recently, I decided to take a look at <em>Mongoid</em> internals and find out if it was viable to prevent the unwanted STI behaviour. Ideally, we would get standard Ruby inheritance, without the subclass being handled differently by <em>Mongoid</em>.</p>
<p>The first thing to do, was to look for an <a href="https://ruby-doc.com/core/Class.html#method-i-inherited" target="_blank" rel="nofollow noopener noreferrer"><code>inherited</code></a> hook in one of the many modules inside the library, which happened to be in <a href="https://github.com/mongodb/mongoid/blob/d787ec40e5554d7e09a1c4d4cc95c5251ec279eb/lib/mongoid/traversable.rb#L193" target="_blank" rel="nofollow noopener noreferrer"><code>Mongoid::Traversable</code></a>. Unfortunately, there's a lot going on in that method; <em>Mongoid</em> doesn't make it easy to extend or modify its functionality in a clean way.</p>
<p>Feeling determined, I chose to hack my way into a solution. The result is the module below—hacky at best, more likely a problem waiting for the next <em>Mongoid</em> update to blow up <span role="img" aria-label="hear-no-evil monkey">🙉</span></p>
<div class="language-ruby" data-lang="ruby"><pre class="language-ruby"><code><span class="token keyword">module</span> <span class="token class-name">Mongoid</span>

  <span class="token comment"># Public: Allows to use inheritance to reuse logic, without using Single-</span>
  <span class="token comment"># Collection Inheritance, storing the model and superclass in different</span>
  <span class="token comment"># collections.</span>
  <span class="token keyword">module</span> <span class="token class-name">NoHeritage</span>
    <span class="token keyword">extend</span> ActiveSupport<span class="token double-colon punctuation">::</span>Concern

    included <span class="token keyword">do</span>
      <span class="token comment"># Internal: Preserve the default storage options instead of storing in</span>
      <span class="token comment"># the same collection than the superclass.</span>
      delegate <span class="token symbol">:storage_options</span><span class="token punctuation">,</span> <span class="token symbol">to</span><span class="token operator">:</span> <span class="token symbol">:class</span>
    <span class="token class-name">end</span>

    <span class="token keyword">module</span> <span class="token class-name">ClassMethods</span>
      <span class="token comment"># Internal: Prevent adding _type in query selectors, and adding an index</span>
      <span class="token comment"># for _type.</span>
      <span class="token keyword">def</span> <span class="token method-definition"><span class="token function">hereditary</span></span><span class="token operator">?</span>
        <span class="token boolean">false</span>
      <span class="token keyword">end</span>

      <span class="token comment"># Internal: Prevent Mongoid from defining a _type getter and setter.</span>
      <span class="token keyword">def</span> <span class="token method-definition"><span class="token function">field</span></span><span class="token punctuation">(</span>name<span class="token punctuation">,</span> options <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span>
        <span class="token keyword">super</span> <span class="token keyword">unless</span> name<span class="token punctuation">.</span>to_sym <span class="token operator">==</span> <span class="token symbol">:_type</span>
      <span class="token keyword">end</span>

      <span class="token comment"># Internal: Preserve the default storage options instead of storing in</span>
      <span class="token comment"># the same collection than the superclass.</span>
      <span class="token keyword">def</span> <span class="token method-definition"><span class="token function">inherited</span></span><span class="token punctuation">(</span>subclass<span class="token punctuation">)</span>
        <span class="token keyword">super</span>

        <span class="token keyword">def</span> <span class="token method-definition"><span class="token class-name">subclass</span><span class="token punctuation">.</span><span class="token function">storage_options</span></span>
          <span class="token variable">@storage_options</span> <span class="token operator">||=</span> storage_options_defaults
        <span class="token keyword">end</span>
      <span class="token keyword">end</span>
    <span class="token keyword">end</span>
  <span class="token keyword">end</span>
<span class="token keyword">end</span></code></pre></div>
<p>All things considered, it provided a nice balance between sharing code, keeping the storage and index size down, and maintaining a straightforward structure in the code.</p>
<p><strong>¯\<em>(ツ)</em>/¯</strong></p>]]></content>
        <author>
            <name>Máximo Mussini</name>
            <uri>https://maximomussini.com</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Less]]></title>
        <id>https://maximomussini.com/posts/less</id>
        <link href="https://maximomussini.com/posts/less"/>
        <updated>2015-10-01T03:09:00.000Z</updated>
        <summary type="html"><![CDATA[Blabbering about simplicity.]]></summary>
        <content type="html"><![CDATA[<p>Recently I've been digging into the <em>#lesscode</em> movement, which proposes that software tools exist to solve real problems—a piece of code that doesn't solve a problem is just waste. It also implies that frugality is a trademark of great designs; we should use it as an inspiration to create elegant software that focuses on solving the problem at hand.</p>
<p>This is related with other ideas like <em><a href="http://www.amazon.com/Machine-That-Changed-World-Revolutionizing/dp/0743299795" target="_blank" rel="nofollow noopener noreferrer">lean manufacturing</a></em>: focus all effort in the things that add value, and reduce everything else. This management philosophy was started by Toyota in the ’50s and later evolved to a business methodology called <em><a href="http://www.amazon.com/Lean-Thinking-Banish-Create-Corporation-ebook/dp/B0048WQDIO" target="_blank" rel="nofollow noopener noreferrer">lean thinking</a></em>, a way to apply the idea—of delivering more value while eliminating waste—to business in general.</p>
<p>While both <em>lesscode</em> and the lean methodologies share the idea of creating something valuable and cutting down the waste, <em>lesscode</em> has a deeper emotional perspective. As a developer, you are responsible for any complexity in the solution.</p>
<p>It's by embracing the constraints—both natural and self-imposed, such as aiming for a great design—and gaining a sense of minimalism, that one is able to discover elegant and simple solutions, and find freedom.</p>
<p>Freedom from bloated frameworks, cargo-cult programming, and the fear of not understanding. Freedom to rid your code out of <em>excess and complexity</em>, and <strong>focus on what matters</strong>.</p>]]></content>
        <author>
            <name>Máximo Mussini</name>
            <uri>https://maximomussini.com</uri>
        </author>
    </entry>
</feed>