<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Ruby | AkitaOnRails.com</title><link>https://akitaonrails.github.io/en/tags/ruby/</link><description>Fabio Akita's blog — tech, career, and assorted geek topics. English edition.</description><generator>Hugo -- gohugo.io</generator><language>en</language><lastBuildDate>Mon, 19 Oct 2026 23:20:52 +0000</lastBuildDate><atom:link href="https://akitaonrails.github.io/en/tags/ruby/index.xml" rel="self" type="application/rss+xml"/><item><title>Ruby on Rails implementation of a (proper) Ranking/Popularity system</title><link>https://akitaonrails.github.io/en/2016/10/31/ruby-on-rails-implementation-of-a-proper-ranking-popularity-system/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2016/10/31/ruby-on-rails-implementation-of-a-proper-ranking-popularity-system/</guid><pubDate>Mon, 31 Oct 2016 16:51:00 -0200</pubDate><description>&lt;p&gt;I was reading a blog post published recently titled &lt;a href="http://naturaily.com/blog/post/ruby-on-rails-implementation-of-a-ranking-system-using-postgresql-window-functions"target="_blank" rel="noopener"&gt;&amp;ldquo;Ruby on Rails implementation of a ranking system using PostgreSQL window functions&amp;rdquo;&lt;/a&gt; and to be fair the purpose of the post was to introduce &lt;a href="https://www.postgresql.org/docs/8.4/static/functions-window.html"target="_blank" rel="noopener"&gt;PostgreSQL&amp;rsquo;s &amp;ldquo;ntile&amp;rdquo; window function&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But in the process, the author made the same mistake I&amp;rsquo;ve seen time and time again.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s assume you have a project with resources that you want to list by &amp;ldquo;popularity&amp;rdquo;. It can be a Reddit-like site where people like or dislike posts or comments. It can be an e-commerce where people like or dislike products.&lt;/p&gt;</description><content:encoded><![CDATA[<p>I was reading a blog post published recently titled <a href="http://naturaily.com/blog/post/ruby-on-rails-implementation-of-a-ranking-system-using-postgresql-window-functions"target="_blank" rel="noopener">&ldquo;Ruby on Rails implementation of a ranking system using PostgreSQL window functions&rdquo;</a> and to be fair the purpose of the post was to introduce <a href="https://www.postgresql.org/docs/8.4/static/functions-window.html"target="_blank" rel="noopener">PostgreSQL&rsquo;s &ldquo;ntile&rdquo; window function</a>.</p>
<p>But in the process, the author made the same mistake I&rsquo;ve seen time and time again.</p>
<p>Let&rsquo;s assume you have a project with resources that you want to list by &ldquo;popularity&rdquo;. It can be a Reddit-like site where people like or dislike posts or comments. It can be an e-commerce where people like or dislike products.</p>
<p>It can be anything where people like or dislike something.</p>
<p>The biggest error people make is to consider a simple score like this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="n">popularity</span> <span class="o">=</span> <span class="n">positive_votes</span> <span class="o">-</span> <span class="n">negative_votes</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>There is an old article titled <a href="http://www.evanmiller.org/how-not-to-sort-by-average-rating.html"target="_blank" rel="noopener">&ldquo;How Not To Sort By Average Rating&rdquo;</a> and I quote:</p>
<blockquote>
  <p>&ldquo;<em>Why it is wrong:</em> Suppose one item has 600 positive ratings and 400 negative ratings: 60% positive. Suppose item two has 5,500 positive ratings and 4,500 negative ratings: 55% positive. This algorithm puts item two (score = 1000, but only 55% positive) above item one (score = 200, and 60% positive). WRONG.&rdquo;</p>

</blockquote>
<p>Then you may think, I know how to fix it:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="no">Score</span> <span class="o">=</span> <span class="n">average_rating</span> <span class="o">=</span> <span class="n">positive_votes</span> <span class="o">/</span> <span class="n">total_votes</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Again, this is wrong, and again I quote:</p>
<blockquote>
  <p>&ldquo;<em>Why it is wrong:</em> Average rating works fine if you always have a ton of ratings, but suppose item 1 has 2 positive ratings and 0 negative ratings. Suppose item 2 has 100 positive ratings and 1 negative rating. This algorithm puts item two (tons of positive ratings) below item one (very few positive ratings). WRONG.&rdquo;</p>

</blockquote>
<h3>Correct Solution: Lower Bound of Wilson Score Confidence Interval for a Bernoulli<span class="hx:absolute hx:-mt-20" id="correct-solution-lower-bound-of-wilson-score-confidence-interval-for-a-bernoulli"></span>
    <a href="#correct-solution-lower-bound-of-wilson-score-confidence-interval-for-a-bernoulli" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>And I quote again:</p>
<blockquote>
  <p>&ldquo;<em>Say what:</em> We need to balance the proportion of positive ratings with the uncertainty of a small number of observations. Fortunately, the math for this was worked out in 1927 by Edwin B. Wilson. What we want to ask is: Given the ratings I have, there is a 95% chance that the &ldquo;real&rdquo; fraction of positive ratings is at least what? Wilson gives the answer. Considering only positive and negative ratings (i.e. not a 5-star scale), the lower bound on the proportion of positive ratings is given by:&rdquo;</p>

</blockquote>
<p><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/565/rating-equation.png" alt="Lower Bound Bernoulli equation"  loading="lazy" /></p>
<p>I recommend you read the <a href="http://www.evanmiller.org/how-not-to-sort-by-average-rating.html"target="_blank" rel="noopener">original article</a> but let&rsquo;s cut to the chase. If we follow the original post I linked in the beginning, I have a simple blog post Rails app, but instead of a <code>visits_count</code> field I need to add a <code>positive:integer</code> and <code>negative:integer</code> fields and user interface to post votes.</p>
<p>And I will replace the <code>PostWithPopularityQuery</code> class with the following:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">PostWithPopularityQuery</span>
</span></span><span class="line"><span class="cl">  <span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">call</span>
</span></span><span class="line"><span class="cl">    <span class="no">Post</span><span class="o">.</span><span class="n">find_by_sql</span> <span class="o">[</span><span class="s1">&#39;SELECT id, title, body, positive, negative,
</span></span></span><span class="line"><span class="cl"><span class="s1">        ((positive + 1.9208) / (positive + negative) -
</span></span></span><span class="line"><span class="cl"><span class="s1">        1.96 * SQRT((positive * negative) / (positive + negative) + 0.9604) /
</span></span></span><span class="line"><span class="cl"><span class="s1">        (positive + negative)) / (1 + 3.8416 / (positive + negative))
</span></span></span><span class="line"><span class="cl"><span class="s1">        AS ci_lower_bound
</span></span></span><span class="line"><span class="cl"><span class="s1">      FROM posts 
</span></span></span><span class="line"><span class="cl"><span class="s1">      WHERE positive + negative &gt; 0
</span></span></span><span class="line"><span class="cl"><span class="s1">      ORDER BY ci_lower_bound DESC&#39;</span><span class="o">]</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>And this is what I expect to see in a simple scaffold <code>index.html.erb</code>:</p>
<p><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/564/Screen_Shot_2016-10-31_at_16.43.50.png" alt="Post index page"  loading="lazy" /></p>
<p>I would even go as far as recommending the <code>ci_lower_bound</code> to be a float field in the table and to have an asynchronous ActiveJob to update it in some larger interval of time (every 5 minutes, for example) and then the <code>PostsController#index</code> action would perform a straightforward <code>SELECT</code> query ordering directly against a real indexed field <code>ci_lower_bound DESC</code> without performing the calculations on <strong>every</strong> query.</p>
<p>Now <strong>THIS</strong> is the correct way to implement a simple, naive popularity ranking system that actually works correctly.</p>
<p>And this is not the only way to do it. There are dozens of good discussions of algorithms online. Every service that depends on content popularity has been refining algorithms like this for years. Facebook used to have an algorithm called &ldquo;EdgeRank&rdquo; which relied on variables such as Affinity, Weight, Time Decay, and it seems to have evolved so much that it now calculates popularity against more than <a href="http://marketingland.com/edgerank-is-dead-facebooks-news-feed-algorithm-now-has-close-to-100k-weight-factors-55908"target="_blank" rel="noopener">100 thousand variables</a>!!</p>
<p>But regardless of the online service, I can assure you that <strong>none</strong> sorts by simple visits count or simple average votes count. That would be downright wrong.</p>
]]></content:encoded><category>algorithms-and-data-structures</category><category>rails</category><category>ruby</category></item><item><title>Natural Language Generation in Ruby (with JRuby + SimpleNLG)</title><link>https://akitaonrails.github.io/en/2016/10/28/natural-language-generation-in-ruby-with-jruby-simplenlg/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2016/10/28/natural-language-generation-in-ruby-with-jruby-simplenlg/</guid><pubDate>Fri, 28 Oct 2016 17:53:00 -0200</pubDate><description>&lt;p&gt;I am building a project which needs to generate proper English sentences. The first version I built used the super naive way of just creating a string template and doing simple sub-string replacements or concatenations.&lt;/p&gt;
&lt;p&gt;But you can imagine that it quickly becomes cumbersome when you have to deal with pluralization, inflection, and it starts to become something like this:&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-ruby" data-lang="ruby"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;&amp;#34;There &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="vi"&gt;@users&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;is&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;are&amp;#39;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="vi"&gt;@users&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; user&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;s&amp;#39;&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="vi"&gt;@users&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="Copy code"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Or use Rails I18n support like this:&lt;/p&gt;</description><content:encoded><![CDATA[<p>I am building a project which needs to generate proper English sentences. The first version I built used the super naive way of just creating a string template and doing simple sub-string replacements or concatenations.</p>
<p>But you can imagine that it quickly becomes cumbersome when you have to deal with pluralization, inflection, and it starts to become something like this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="s2">&#34;There </span><span class="si">#{</span><span class="vi">@users</span><span class="o">.</span><span class="n">size</span> <span class="o">==</span> <span class="mi">1</span> <span class="o">?</span> <span class="s1">&#39;is&#39;</span> <span class="p">:</span> <span class="s1">&#39;are&#39;</span><span class="si">}</span><span class="s2"> </span><span class="si">#{</span><span class="vi">@users</span><span class="o">.</span><span class="n">size</span><span class="si">}</span><span class="s2"> user</span><span class="si">#{</span><span class="s1">&#39;s&#39;</span> <span class="k">unless</span> <span class="vi">@users</span><span class="o">.</span><span class="n">size</span> <span class="o">==</span> <span class="mi">1</span><span class="si">}</span><span class="s2">.&#34;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Or use Rails I18n support like this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="no">I18n</span><span class="o">.</span><span class="n">backend</span><span class="o">.</span><span class="n">store_translations</span> <span class="ss">:en</span><span class="p">,</span> <span class="ss">:user_msg</span> <span class="o">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="ss">:one</span> <span class="o">=&gt;</span> <span class="s1">&#39;There is 1 user&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="ss">:other</span> <span class="o">=&gt;</span> <span class="s1">&#39;There are %{count} users&#39;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="no">I18n</span><span class="o">.</span><span class="n">translate</span> <span class="ss">:user_msg</span><span class="p">,</span> <span class="ss">:count</span> <span class="o">=&gt;</span> <span class="mi">2</span>
</span></span><span class="line"><span class="cl"><span class="c1"># =&gt; &#39;There are 2 users&#39;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>For simple transactional phrases (such as flash messages), this is more than enough.</p>
<p>But if you want to generate an entire article in plain English from data structures, then the logic becomes very convoluted very fast.</p>
<p>I looked around and found a few Ruby projects that could help, for example:</p>
<ul>
<li><a href="https://github.com/chorn/nameable"target="_blank" rel="noopener">&ldquo;nameable&rdquo;</a> which can do useful stuff like this:</li>
</ul>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="no">Nameable</span><span class="o">::</span><span class="no">Latin</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="s1">&#39;Chris&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">gender</span>
</span></span><span class="line"><span class="cl"><span class="c1">#=&gt; :male</span>
</span></span><span class="line"><span class="cl"><span class="no">Nameable</span><span class="o">::</span><span class="no">Latin</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="s1">&#39;Janine&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">female?</span>
</span></span><span class="line"><span class="cl"><span class="c1">#=&gt; true</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<ul>
<li><a href="https://github.com/maetl/calyx"target="_blank" rel="noopener">&ldquo;calyx&rdquo;</a> which can be used to generate simple phrases like this:</li>
</ul>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">GreenBottle</span> <span class="o">&lt;</span> <span class="no">Calyx</span><span class="o">::</span><span class="no">Grammar</span>
</span></span><span class="line"><span class="cl">  <span class="n">mapping</span> <span class="ss">:pluralize</span><span class="p">,</span> <span class="sr">/(.+)/</span> <span class="o">=&gt;</span> <span class="s1">&#39;\\1s&#39;</span>
</span></span><span class="line"><span class="cl">  <span class="n">start</span> <span class="s1">&#39;One green {bottle}.&#39;</span><span class="p">,</span> <span class="s1">&#39;Two green {bottle.pluralize}.&#39;</span>
</span></span><span class="line"><span class="cl">  <span class="n">bottle</span> <span class="s1">&#39;bottle&#39;</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># =&gt; &#34;One green bottle.&#34;</span>
</span></span><span class="line"><span class="cl"><span class="c1"># =&gt; &#34;Two green bottles.&#34;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Nice and dandy, but still useless for the more complex needs I have in mind.</p>
<p>So I decided to dig a bit deeper, into the dark world of NLG, or <strong>Natural Language Generation</strong> (not to be confused with NLP, which stands for Natural Language Processing, which is the opposite of what I want. NLP gets plain English text and returns a parsed data structure).</p>
<p>For <strong>NLP</strong> (parsing, tokenization, etc) I&rsquo;d highly recommend <a href="http://stanfordnlp.github.io/CoreNLP/"target="_blank" rel="noopener">&ldquo;Stanford CoreNLP&rdquo;</a>. It seems to be one of the most robust and comprehensive out there (come on, it&rsquo;s from Stanford). Again a Java project, and a big download (more than 300MB!). Those linguistics projects are super heavy because they have to download entire dictionaries and lexicon databases.</p>
<p>But focusing on my problem at hand, <strong>NLG</strong>, there are <a href="https://aclweb.org/aclwiki/index.php?title=Downloadable_NLG_systems"target="_blank" rel="noopener">several options</a> out there. In all honesty, I did not do very extensive research, so if you are aware of which is the most robust and also well maintained and with an easy to use interface, let me know in the comments section below.</p>
<p>My choice was <a href="https://github.com/simplenlg/simplenlg"target="_blank" rel="noopener">SimpleNLG</a>. From its GitHub page we can see that it seems to be quite well maintained to this day, it&rsquo;s a simple Java library and it is one of the &ldquo;simpler&rdquo; alternatives. <a href="http://www.fb10.uni-bremen.de/anglistik/langpro/kpml/README.html"target="_blank" rel="noopener">KPML</a> is on the opposite spectrum: it seems to be one of the oldest (since the 80&rsquo;s!) and most robust ones. But seriously, it feels like you need a Ph.D to even get started.</p>
<p>Reading the SimpleNLG Java source code was boring but easy enough. Give yourself one full day of study to get used to the code and you&rsquo;re in business.</p>
<p>The main problem is that it&rsquo;s written in Java and I don&rsquo;t intend to write anything in Java (or any derivative) for now. For a short while I considered the endeavor of rewriting the damn thing in something more portable such as Rust, which I could load anywhere through FFI.</p>
<p>But even though SimpleNLG has &ldquo;Simple&rdquo; in its name it has a few hairy dependencies to load the lexicon database. And the database itself is an HSQLDB dump, which is a Java-written database. And then, there would be the issue of maintaining a fork.</p>
<p>I quickly gave up on that idea and instead I worked around this by wrapping the library under a simple <a href="https://github.com/rails-api/rails-api"target="_blank" rel="noopener">Rails-API</a> endpoint. I had a few issues because I had Git LFS tracking jar files in my system and Heroku doesn&rsquo;t support it and I ended up with a corrupted deployment (beware of those quirks, by the way!)</p>
<p>Finally, I was able to deploy a working JRuby + Rails-API project embedding SimpleNLG at Heroku. You can deploy your own copy by cloning my <a href="https://github.com/Codeminer42/nlg_service"target="_blank" rel="noopener">nlg_service</a>. It works fine with the latest JRuby 9.1.5.0. You should pay for at least a Hobby tier over Heroku. Java takes a ridiculous amount of time to start up and more time to warm up. Heroku&rsquo;s free tier shuts down your dyno if it sits idle and a subsequent web request will definitely time out or take an absurd amount of time to return.</p>
<p>Once deployed it starts up Rails, then loads <a href="https://github.com/Codeminer42/nlg_service/blob/master/config/initializers/simple_nlg.rb"target="_blank" rel="noopener">this initializer</a>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="nb">require</span> <span class="s1">&#39;java&#39;</span>
</span></span><span class="line"><span class="cl"><span class="no">Java</span><span class="o">::</span><span class="no">JavaLang</span><span class="o">::</span><span class="no">System</span><span class="o">.</span><span class="n">set_property</span> <span class="s2">&#34;file.encoding&#34;</span><span class="p">,</span><span class="s2">&#34;UTF-8&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="no">SIMPLE_NLG_DEFAULT_LEXICON_PATH</span> <span class="o">=</span> <span class="no">Rails</span><span class="o">.</span><span class="n">root</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="s2">&#34;lib/SimpleNLG/resources/default-lexicon.xml&#34;</span><span class="p">)</span><span class="o">.</span><span class="n">to_s</span><span class="o">.</span><span class="n">freeze</span>
</span></span><span class="line"><span class="cl"><span class="no">SIMPLE_NLG_PATH</span>                 <span class="o">=</span> <span class="no">Rails</span><span class="o">.</span><span class="n">root</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="s2">&#34;lib/SimpleNLG&#34;</span><span class="p">)</span><span class="o">.</span><span class="n">to_s</span><span class="o">.</span><span class="n">freeze</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="no">Dir</span><span class="o">[</span><span class="s2">&#34;</span><span class="si">#{</span><span class="no">SIMPLE_NLG_PATH</span><span class="si">}</span><span class="s2">/*.jar&#34;</span><span class="o">].</span><span class="n">each</span> <span class="p">{</span> <span class="o">|</span><span class="n">jar</span><span class="o">|</span> <span class="nb">require</span> <span class="n">jar</span> <span class="p">}</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>And then I map the classes <a href="https://github.com/Codeminer42/nlg_service/blob/master/app/models/simple_nlg.rb"target="_blank" rel="noopener">like this</a>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="k">module</span> <span class="nn">SimpleNLG</span>
</span></span><span class="line"><span class="cl">  <span class="sx">%w(
</span></span></span><span class="line"><span class="cl"><span class="sx">    simplenlg.aggregation
</span></span></span><span class="line"><span class="cl"><span class="sx">    simplenlg.features
</span></span></span><span class="line"><span class="cl"><span class="sx">    simplenlg.format.english
</span></span></span><span class="line"><span class="cl"><span class="sx">    simplenlg.framework
</span></span></span><span class="line"><span class="cl"><span class="sx">    simplenlg.lexicon
</span></span></span><span class="line"><span class="cl"><span class="sx">    simplenlg.morphology.english
</span></span></span><span class="line"><span class="cl"><span class="sx">    simplenlg.orthography.english
</span></span></span><span class="line"><span class="cl"><span class="sx">    simplenlg.phrasespec
</span></span></span><span class="line"><span class="cl"><span class="sx">    simplenlg.realiser.english
</span></span></span><span class="line"><span class="cl"><span class="sx">    simplenlg.syntax.english
</span></span></span><span class="line"><span class="cl"><span class="sx">    simplenlg.xmlrealiser
</span></span></span><span class="line"><span class="cl"><span class="sx">    simplenlg.xmlrealiser.wrapper
</span></span></span><span class="line"><span class="cl"><span class="sx">  )</span><span class="o">.</span><span class="n">each</span> <span class="p">{</span> <span class="o">|</span><span class="n">package</span><span class="o">|</span> <span class="n">include_package</span> <span class="n">package</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Finally, I have a simple endpoint mapped to a <a href="https://github.com/Codeminer42/nlg_service/blob/master/app/controllers/api/realisers_controller.rb"target="_blank" rel="noopener">controller</a> action:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Api</span><span class="o">::</span><span class="no">RealisersController</span> <span class="o">&lt;</span> <span class="no">ApplicationController</span>
</span></span><span class="line"><span class="cl">  <span class="k">def</span> <span class="nf">create</span>
</span></span><span class="line"><span class="cl">    <span class="n">reader</span> <span class="o">=</span> <span class="n">java</span><span class="o">::</span><span class="n">io</span><span class="o">::</span><span class="no">StringReader</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="n">params</span><span class="o">[</span><span class="ss">:xml</span><span class="o">]</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">begin</span>
</span></span><span class="line"><span class="cl">      <span class="n">records</span> <span class="o">=</span> <span class="no">SimpleNLG</span><span class="o">::</span><span class="no">XMLRealiser</span><span class="o">.</span><span class="n">getRecording</span><span class="p">(</span><span class="n">reader</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="n">output</span> <span class="o">=</span> <span class="n">records</span><span class="o">.</span><span class="n">getRecord</span><span class="o">.</span><span class="n">map</span> <span class="k">do</span> <span class="o">|</span><span class="n">record</span><span class="o">|</span>
</span></span><span class="line"><span class="cl">        <span class="no">SimpleNLG</span><span class="o">::</span><span class="no">XMLRealiser</span><span class="o">.</span><span class="n">realise</span><span class="p">(</span><span class="n">record</span><span class="o">&amp;.</span><span class="n">getDocument</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="k">end</span>
</span></span><span class="line"><span class="cl">      <span class="vi">@realisation</span> <span class="o">=</span> <span class="n">output</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="s2">&#34;</span><span class="se">\n</span><span class="s2">&#34;</span><span class="p">)</span><span class="o">.</span><span class="n">strip</span>
</span></span><span class="line"><span class="cl">      <span class="n">render</span> <span class="ss">plain</span><span class="p">:</span> <span class="vi">@realisation</span>
</span></span><span class="line"><span class="cl">    <span class="k">ensure</span>
</span></span><span class="line"><span class="cl">      <span class="n">reader</span><span class="o">.</span><span class="n">close</span>
</span></span><span class="line"><span class="cl">    <span class="k">end</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>The process of generating the final English text is called <strong>&ldquo;realisation&rdquo;</strong>. SimpleNLG has a comprehensive Java API but it also exposes it as a simpler XML format. The full <a href="https://github.com/simplenlg/simplenlg/blob/master/src/main/resources/xml/RealizerSchema.xsd"target="_blank" rel="noopener">XML Realiser Schema</a> is available as an XSD.</p>
<p>If I want to write this sentence:</p>
<blockquote>
  <p>&ldquo;There are some finished and delivered stories that may not have been tested.&rdquo;</p>

</blockquote>
<p>This is the XML that I need to assemble:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-xml" data-lang="xml"><span class="line"><span class="cl"><span class="cp">&lt;?xml version=&#34;1.0&#34;?&gt;</span>
</span></span><span class="line"><span class="cl"><span class="nt">&lt;NLGSpec</span> <span class="na">xmlns=</span><span class="s">&#34;http://simplenlg.googlecode.com/svn/trunk/res/xml&#34;</span> <span class="na">xmlns:xsd=</span><span class="s">&#34;http://www.w3.org/2001/XMLSchema&#34;</span> <span class="na">xmlns:xsi=</span><span class="s">&#34;http://www.w3.org/2001/XMLSchema-instance&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&lt;Recording&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;Record&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&lt;Document</span> <span class="na">cat=</span><span class="s">&#34;PARAGRAPH&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&lt;child</span> <span class="na">xsi:type=</span><span class="s">&#34;SPhraseSpec&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&lt;subj</span> <span class="na">xsi:type=</span><span class="s">&#34;NPPhraseSpec&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&lt;head</span> <span class="na">cat=</span><span class="s">&#34;ADVERB&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&lt;base&gt;</span>there<span class="nt">&lt;/base&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&lt;/head&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&lt;/subj&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&lt;vp</span> <span class="na">xsi:type=</span><span class="s">&#34;VPPhraseSpec&#34;</span> <span class="na">PERSON=</span><span class="s">&#34;THIRD&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&lt;head</span> <span class="na">cat=</span><span class="s">&#34;VERB&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&lt;base&gt;</span>be<span class="nt">&lt;/base&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&lt;/head&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&lt;compl</span> <span class="na">xsi:type=</span><span class="s">&#34;NPPhraseSpec&#34;</span> <span class="na">NUMBER=</span><span class="s">&#34;PLURAL&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&lt;head</span> <span class="na">cat=</span><span class="s">&#34;NOUN&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&lt;base&gt;</span>story<span class="nt">&lt;/base&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&lt;/head&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&lt;spec</span> <span class="na">xsi:type=</span><span class="s">&#34;WordElement&#34;</span> <span class="na">cat=</span><span class="s">&#34;DETERMINER&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&lt;base&gt;</span>a<span class="nt">&lt;/base&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&lt;/spec&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&lt;preMod</span> <span class="na">xsi:type=</span><span class="s">&#34;CoordinatedPhraseElement&#34;</span> <span class="na">conj=</span><span class="s">&#34;and&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&lt;coord</span> <span class="na">xsi:type=</span><span class="s">&#34;VPPhraseSpec&#34;</span> <span class="na">TENSE=</span><span class="s">&#34;PAST&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">                  <span class="nt">&lt;head</span> <span class="na">cat=</span><span class="s">&#34;VERB&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">                    <span class="nt">&lt;base&gt;</span>finish<span class="nt">&lt;/base&gt;</span>
</span></span><span class="line"><span class="cl">                  <span class="nt">&lt;/head&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&lt;/coord&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&lt;coord</span> <span class="na">xsi:type=</span><span class="s">&#34;VPPhraseSpec&#34;</span> <span class="na">TENSE=</span><span class="s">&#34;PAST&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">                  <span class="nt">&lt;head</span> <span class="na">cat=</span><span class="s">&#34;VERB&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">                    <span class="nt">&lt;base&gt;</span>deliver<span class="nt">&lt;/base&gt;</span>
</span></span><span class="line"><span class="cl">                  <span class="nt">&lt;/head&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&lt;/coord&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&lt;/preMod&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&lt;compl</span> <span class="na">xsi:type=</span><span class="s">&#34;SPhraseSpec&#34;</span> <span class="na">MODAL=</span><span class="s">&#34;may&#34;</span> <span class="na">PASSIVE=</span><span class="s">&#34;true&#34;</span> <span class="na">TENSE=</span><span class="s">&#34;PAST&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&lt;vp</span> <span class="na">xsi:type=</span><span class="s">&#34;VPPhraseSpec&#34;</span> <span class="na">TENSE=</span><span class="s">&#34;PAST&#34;</span> <span class="na">NEGATED=</span><span class="s">&#34;true&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">                  <span class="nt">&lt;head</span> <span class="na">cat=</span><span class="s">&#34;VERB&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">                    <span class="nt">&lt;base&gt;</span>test<span class="nt">&lt;/base&gt;</span>
</span></span><span class="line"><span class="cl">                  <span class="nt">&lt;/head&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&lt;/vp&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&lt;/compl&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&lt;/compl&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&lt;/vp&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&lt;/child&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&lt;/Document&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;/Record&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&lt;/Recording&gt;</span>
</span></span><span class="line"><span class="cl"><span class="nt">&lt;/NLGSpec&gt;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Ok, this is preposterous, I know.</p>
<p>Which is why I decided to go ahead and use one of Ruby&rsquo;s most recognized strengths: creating <strong>DSLs</strong> or <strong>Domain Specific Languages</strong>.</p>
<p>The result of my initial endeavor to simplify this process is the <a href="https://github.com/Codeminer42/nlg_xml_realiser_builder"target="_blank" rel="noopener">nlg_xml_realiser_builder</a> ruby gem. Simply add the following to your <code>Gemfile</code>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>gem &#39;nlg_xml_realiser_builder&#39;</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>And the humongous XML above becomes something more manageable like this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="n">dsl</span> <span class="o">=</span> <span class="no">NlgXmlRealiserBuilder</span><span class="o">::</span><span class="no">DSL</span><span class="o">.</span><span class="n">new</span>
</span></span><span class="line"><span class="cl"><span class="n">dsl</span><span class="o">.</span><span class="n">builder</span><span class="p">(</span><span class="kp">true</span><span class="p">)</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">  <span class="n">sp</span> <span class="ss">:child</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">    <span class="n">subj</span> <span class="ss">:np</span><span class="p">,</span> <span class="s1">&#39;there&#39;</span><span class="p">,</span> <span class="ss">cat</span><span class="p">:</span> <span class="s1">&#39;ADVERB&#39;</span>
</span></span><span class="line"><span class="cl">    <span class="n">verb</span> <span class="s1">&#39;be&#39;</span><span class="p">,</span> <span class="ss">PERSON</span><span class="p">:</span> <span class="s1">&#39;THIRD&#39;</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">      <span class="n">compl</span> <span class="ss">:np</span><span class="p">,</span> <span class="o">[</span><span class="s1">&#39;a&#39;</span><span class="p">,</span> <span class="s1">&#39;story&#39;</span><span class="o">]</span><span class="p">,</span> <span class="ss">NUMBER</span><span class="p">:</span> <span class="s1">&#39;PLURAL&#39;</span>  <span class="k">do</span>
</span></span><span class="line"><span class="cl">        <span class="n">preMod</span> <span class="ss">:cp</span><span class="p">,</span> <span class="ss">conj</span><span class="p">:</span> <span class="s1">&#39;and&#39;</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">          <span class="n">coord</span> <span class="ss">:vp</span><span class="p">,</span> <span class="s1">&#39;finish&#39;</span><span class="p">,</span> <span class="ss">TENSE</span><span class="p">:</span> <span class="s1">&#39;PAST&#39;</span>
</span></span><span class="line"><span class="cl">          <span class="n">coord</span> <span class="ss">:vp</span><span class="p">,</span> <span class="s1">&#39;deliver&#39;</span><span class="p">,</span> <span class="ss">TENSE</span><span class="p">:</span> <span class="s1">&#39;PAST&#39;</span>
</span></span><span class="line"><span class="cl">        <span class="k">end</span>
</span></span><span class="line"><span class="cl">        <span class="n">compl</span> <span class="ss">:sp</span><span class="p">,</span> <span class="ss">MODAL</span><span class="p">:</span> <span class="s1">&#39;may&#39;</span><span class="p">,</span> <span class="ss">PASSIVE</span><span class="p">:</span> <span class="kp">true</span><span class="p">,</span> <span class="ss">TENSE</span><span class="p">:</span> <span class="s1">&#39;PAST&#39;</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">          <span class="n">verb</span> <span class="s1">&#39;test&#39;</span><span class="p">,</span> <span class="ss">TENSE</span><span class="p">:</span> <span class="s1">&#39;PAST&#39;</span><span class="p">,</span> <span class="ss">NEGATED</span><span class="p">:</span> <span class="kp">true</span>
</span></span><span class="line"><span class="cl">        <span class="k">end</span>
</span></span><span class="line"><span class="cl">      <span class="k">end</span>
</span></span><span class="line"><span class="cl">    <span class="k">end</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span><span class="o">.</span><span class="n">to_xml</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Understanding the intricacies of an <code>NPPhraseSpec</code> vs a <code>VPPhraseSpec</code> or the difference between a <code>WordElement</code> or <code>StringElement</code> are beyond this blog post. But most of the original XSD has been mapped through <a href="https://github.com/Codeminer42/nlg_xml_realiser_builder/blob/master/lib/nlg_xml_realiser_builder/consts.rb"target="_blank" rel="noopener">this constants file</a>.</p>
<p>I have a <a href="https://github.com/Codeminer42/nlg_xml_realiser_builder/blob/master/spec/nlg_xml_realiser_builder_spec.rb"target="_blank" rel="noopener">few acceptance specs</a> that are generating XMLs like the above, posting to my live online NLG Web Service and fetching the resulting English sentences. I will change this process in the future but you can test it out yourself.</p>
<p>The advantages start here. Now let&rsquo;s check out the previous example more closely. Again, it renders this phrase:</p>
<blockquote>
  <p>&ldquo;There are some finished and delivered stories that may not have been tested.&rdquo;</p>

</blockquote>
<p>Now, it&rsquo;s in plural form because I am talking about &lsquo;stories&rsquo;, but what if I want a singular version?</p>
<p>Below is the new version where I just wrap it around a method and make the attribute &lsquo;NUMBER&rsquo; accept both &lsquo;PLURAL&rsquo; or &lsquo;SINGULAR&rsquo;:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">example</span><span class="p">(</span><span class="n">plural</span> <span class="o">=</span> <span class="s1">&#39;PLURAL&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">dsl</span> <span class="o">=</span> <span class="no">NlgXmlRealiserBuilder</span><span class="o">::</span><span class="no">DSL</span><span class="o">.</span><span class="n">new</span>
</span></span><span class="line"><span class="cl">  <span class="n">dsl</span><span class="o">.</span><span class="n">builder</span><span class="p">(</span><span class="kp">true</span><span class="p">)</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">    <span class="n">sp</span> <span class="ss">:child</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">      <span class="n">subj</span> <span class="ss">:np</span><span class="p">,</span> <span class="s1">&#39;there&#39;</span><span class="p">,</span> <span class="ss">cat</span><span class="p">:</span> <span class="s1">&#39;ADVERB&#39;</span>
</span></span><span class="line"><span class="cl">      <span class="n">verb</span> <span class="s1">&#39;be&#39;</span><span class="p">,</span> <span class="ss">PERSON</span><span class="p">:</span> <span class="s1">&#39;THIRD&#39;</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">        <span class="n">compl</span> <span class="ss">:np</span><span class="p">,</span> <span class="o">[</span><span class="s1">&#39;a&#39;</span><span class="p">,</span> <span class="s1">&#39;story&#39;</span><span class="o">]</span><span class="p">,</span> <span class="ss">NUMBER</span><span class="p">:</span> <span class="n">plural</span>  <span class="k">do</span>
</span></span><span class="line"><span class="cl">          <span class="n">preMod</span> <span class="ss">:cp</span><span class="p">,</span> <span class="ss">conj</span><span class="p">:</span> <span class="s1">&#39;and&#39;</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">            <span class="n">coord</span> <span class="ss">:vp</span><span class="p">,</span> <span class="s1">&#39;finish&#39;</span><span class="p">,</span> <span class="ss">TENSE</span><span class="p">:</span> <span class="s1">&#39;PAST&#39;</span>
</span></span><span class="line"><span class="cl">            <span class="n">coord</span> <span class="ss">:vp</span><span class="p">,</span> <span class="s1">&#39;deliver&#39;</span><span class="p">,</span> <span class="ss">TENSE</span><span class="p">:</span> <span class="s1">&#39;PAST&#39;</span>
</span></span><span class="line"><span class="cl">          <span class="k">end</span>
</span></span><span class="line"><span class="cl">          <span class="n">compl</span> <span class="ss">:sp</span><span class="p">,</span> <span class="ss">MODAL</span><span class="p">:</span> <span class="s1">&#39;may&#39;</span><span class="p">,</span> <span class="ss">PASSIVE</span><span class="p">:</span> <span class="kp">true</span><span class="p">,</span> <span class="ss">TENSE</span><span class="p">:</span> <span class="s1">&#39;PAST&#39;</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">            <span class="n">verb</span> <span class="s1">&#39;test&#39;</span><span class="p">,</span> <span class="ss">TENSE</span><span class="p">:</span> <span class="s1">&#39;PAST&#39;</span><span class="p">,</span> <span class="ss">NEGATED</span><span class="p">:</span> <span class="kp">true</span>
</span></span><span class="line"><span class="cl">          <span class="k">end</span>
</span></span><span class="line"><span class="cl">        <span class="k">end</span>
</span></span><span class="line"><span class="cl">      <span class="k">end</span>
</span></span><span class="line"><span class="cl">    <span class="k">end</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span><span class="o">.</span><span class="n">to_xml</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>And I can run the singular version like this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>puts example(&#39;SINGULAR&#39;)</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>This is the resulting phrase:</p>
<blockquote>
  <p>&ldquo;There is a finished and delivered story that may not have been tested.&rdquo;</p>

</blockquote>
<p>Check out how it changed the verb from &ldquo;are&rdquo; to &ldquo;is&rdquo; and the noun determiner from &ldquo;some&rdquo; to &ldquo;a&rdquo; on its own! And of course, this is a contrived example. Now imagine an entire customizable article, full of paragraphs and sentences that I can customize depending on several variables I have.</p>
<p>While I was studying and writing this DSL I got a good enough grasp of the SimpleNLG structure, but if you have more examples for more complex phrase structures, please let me know in the comments section down below.</p>
<p>Most of the specs were copied from the XML Realiser tests from the original Java project to make sure I am covering most cases.</p>
<p>It will be interesting to see if this DSL makes it easier for more people to experiment with NLG. As usual, send your Pull Requests, ideas and suggestions on my GitHub public repositories:</p>
<ul>
<li><a href="https://github.com/Codeminer42/nlg_service"target="_blank" rel="noopener">nlg_service</a></li>
<li><a href="https://github.com/Codeminer42/nlg_xml_realiser_builder"target="_blank" rel="noopener">nlg_xml_realiser_builder</a></li>
</ul>
<p>And if you&rsquo;re interested in the subject of NLP and NLG I found <a href="https://github.com/diasks2/ruby-nlp"target="_blank" rel="noopener">this list</a> of Ruby related open source projects as well.</p>
]]></content:encoded><category>ruby</category><category>java</category><category>rails</category></item><item><title>The Ruby Community and Reputation</title><link>https://akitaonrails.github.io/en/2016/08/19/the-ruby-community-and-reputation/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2016/08/19/the-ruby-community-and-reputation/</guid><pubDate>Fri, 19 Aug 2016 11:02:00 -0300</pubDate><description>&lt;p&gt;I&amp;rsquo;ve just read the posts from &lt;a href="http://hawkins.io/2015/05/the-ruby-community-the-next-version/"target="_blank" rel="noopener"&gt;Adam Hawkins&lt;/a&gt; and the support from &lt;a href="http://www.alanbradburne.com/Rubys-reputation"target="_blank" rel="noopener"&gt;Alan Bradburne&lt;/a&gt; over Ruby Weekly.&lt;/p&gt;
&lt;p&gt;As a disclaimer, I don&amp;rsquo;t know them, and I respect their points of view. This is not supposed to start a flame war, just to paint an alternative point of view.&lt;/p&gt;
&lt;p&gt;Both articles represent the point of view of many veteran Ruby developers in this community. Some of whom already left for other technologies or stopped public appearances.&lt;/p&gt;</description><content:encoded><![CDATA[<p>I&rsquo;ve just read the posts from <a href="http://hawkins.io/2015/05/the-ruby-community-the-next-version/"target="_blank" rel="noopener">Adam Hawkins</a> and the support from <a href="http://www.alanbradburne.com/Rubys-reputation"target="_blank" rel="noopener">Alan Bradburne</a> over Ruby Weekly.</p>
<p>As a disclaimer, I don&rsquo;t know them, and I respect their points of view. This is not supposed to start a flame war, just to paint an alternative point of view.</p>
<p>Both articles represent the point of view of many veteran Ruby developers in this community. Some of whom already left for other technologies or stopped public appearances.</p>
<p>I already made my stand very clear in <a href="http://www.akitaonrails.com/en/2016/05/23/rails-venceu-o-elefante-na-sala"target="_blank" rel="noopener">&ldquo;Rails has Won: The Elephant in the Room&rdquo;</a>. But let me simplify here.</p>
<p>There is clearly a faction being formed. Apart from great developers like Solnic (dry-rb), Nick (Trailblazer), and Luca (Hanami), most people are complaining that Rails and some of the closest pieces of the ecosystem around it don&rsquo;t conform to their newly found vision of what &ldquo;good&rdquo; should be.</p>
<p>In their view of the world, a &ldquo;better&rdquo; Rails should be way simpler, way more explicit, composed of super small libraries, super explicit external APIs, and super composability to take it apart back and forth.</p>
<p>And here lies my problem: if DHH complied and took that direction, that would be &ldquo;Ruby OFF the Rails.&rdquo; The whole point of &ldquo;Ruby <strong>ON</strong> Rails&rdquo; is precisely because it is defined by being a coherent, opinionated full stack with coarse-grained libraries that are meant to work together in tandem.</p>
<p>Let me present the true Elephant in the Room:</p>
<ul>
<li>
<p>Discussions like this are just inflammatory link baits. They serve no point but create a cloud of animosity against something without actually presenting an objective good alternative. Writing bullet points is easy, but writing complete solutions and maintaining them is not.</p>
</li>
<li>
<p>There are indeed good alternatives popping up already, such as the aforementioned Trailblazer, Hanami, and the dry-rb collection of libraries, just to name a few. The complaint is that they don&rsquo;t have as much traction right now. What&rsquo;s the solution? Bad-mouthing Rails? Writing ranting articles of how life is unjust? Or, actually, are you writing more tutorials on how to use Trailblazer? Recording screencasts on how to use Hanami? Going to a conference and presenting more talks on importing dry-rb into your projects?</p>
</li>
<li>
<p>Ruby on Rails was meant for programmers tired of super composability, super configuration, super explicit, super fine-grained libraries. It was meant for Java programmers coming out straight from the nightmare that was J2EE 1.x in 2004, remember that? Now, the &ldquo;proposal&rdquo; is to go back to that? Waste enormous amounts of time fine-tuning your tailor-made mini-stack? We have that already. It&rsquo;s called Javascript. And let me tell you: configuring the current breed of <code>package.json</code> brings me back really bad memories from <code>pom.xml</code>, <code>hibernate.cfg.xml</code> to <code>struts-config.xml</code>.</p>
</li>
<li>
<p>Beginners are not interested in fine-grained solutions. Most people forget how it was to be a beginner. Actually, I&rsquo;d argue that 80% of the world&rsquo;s developers benefit greatly from a Rails-like approach. It&rsquo;s no coincidence that many platforms conformed to an opinionated, convention-over-configuration approach after it proved its point.</p>
</li>
</ul>
<p>The fact that people are complaining against Rails makes it feel like it is Rails&rsquo; fault somehow. Actually not, it&rsquo;s just a reflection of the frustration of the very people that <strong>failed</strong> (and are failing) to pitch the alternatives. Everybody wants a free lunch.</p>
<p>Let me tell you a short story.</p>
<p>Back in 2005 I was the only Rails developer I knew in my country (Brazil). I googled around and found perhaps half a dozen other hobbyists doing Ruby for fun, and a couple were doing it professionally already.</p>
<p>People would make fun of us everywhere I looked because they thought we were just crazy. <em>&ldquo;Of course, J2EE is the way to go.&rdquo; &ldquo;Of course, every project should conform to Eric Evan&rsquo;s DDD approach.&rdquo; &ldquo;Of course, every project should conform to all of the Gang of Four&rsquo;s Design Patterns, the more, the merrier.&rdquo; &ldquo;Of course, we should have very isolated deployment packages with very explicit API boundaries between them, no matter how it makes productivity decrease.&rdquo;</em></p>
<p>We&rsquo;ve been there before. In 2004, I already had more than ten years of experience in professional programming.</p>
<p>It took me another ten years of pilgrimage. 9 years organizing my own conference. More than 1,000 blog posts. Almost 200 talks, several of which I paid from my own pocket to buy bus and airplane tickets. I put my money where my mouth was.</p>
<p>The promise was to replace all the complexity and bureaucracy with an opinionated stack where most of the basic decisions were already made. It would be out of our way so we could focus on the most important part: the business.</p>
<div class="video-container">
    <video controls>
        <source src="https://s3.us-east-2.amazonaws.com/blip.tv/Java_is_not_evil.mp4" type="video/mp4">
        Your browser does not support the video tag. [Direct Link](https://s3.us-east-2.amazonaws.com/blip.tv/Java_is_not_evil.mp4)
    </video>
</div>
<p>Every talk I pitched to Rails since 2006 had the above section. And with every single person who ever watched any of my talks as my witness, I always said:</p>
<blockquote>
  <p>&ldquo;Many of you have heard that Java is bad because it&rsquo;s so complex and so bureaucratic. And many will try to pitch their alternatives at the expense of Java. Not us. We embrace what Java has to offer. Solr, Elasticsearch, and Hadoop are all made with Java. What will we do? Rewrite everything in Ruby? Of course not. For Rails to Win, Java doesn&rsquo;t have to Lose.&rdquo; (I put the &ldquo;evil edition&rdquo; image on fire, on stage).</p>

</blockquote>
<p>I wrote an article (in pt-BR, sorry) in October of 2007 titled <a href="http://www.akitaonrails.com/2007/10/23/para-eu-ganhar-o-outro-precisa-perder"target="_blank" rel="noopener">&ldquo;For me to win, the other has to lose &hellip;&rdquo;</a> where I explained why this way of thinking is so lame. I also took inspiration from the famous 1998 Macworld talk by Steve Jobs, where he called Bill Gates on stage, on the big screen, to announce their collaboration. The Apple fans went nuts, they were horrified by that sight, it was like sleeping with Satan.</p>
<p>Almost 20 years later, Apple is one of the most valuable companies in the world. Because it didn&rsquo;t matter. Jobs left pure ideology behind and became pragmatic. They needed Microsoft&rsquo;s endorsement, got it, and proved their points by results: they spent the 90s masturbating over why classic OS 7 to 9 were better than Windows 3.1 up to NT 4. But it took them ten years to prove the worth of OS X over the first decade of the 21st century. One step at a time, one release after the other, frequently delivering instead of spending years closed in the labs until the &ldquo;perfect&rdquo; solution arose. Baby steps. It culminated when they squeezed OS X into iOS in 2007.</p>
<p>That&rsquo;s how you prove a point: through sheer pain and sweat, by putting it out there in the streets, pitching it, selling it, and creating true value one small release at a time.</p>
<p>And then this happened:</p>
<p><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/559/big_mac-school.jpg" alt="Macbooks everywhere"  loading="lazy" /></p>
<p>Remember when Apple took over the world? One entire decade to come back from <a href="http://money.cnn.com/1998/10/14/technology/apple/"target="_blank" rel="noopener">bleeding 1 billion a year</a> up until becoming the <a href="http://fortune.com/2016/02/03/apple-facebook-amazon-google/"target="_blank" rel="noopener">most valuable company in the world</a>, whose effects are still going on 5 years after Jobs&rsquo; passing.</p>
<p>Some of us understand that engineers want to masturbate over irrelevant things.</p>
<blockquote>
  <p>&ldquo;- My algorithm runs 0.1 milliseconds faster than yours&rdquo;.</p>

</blockquote>
<blockquote>
  <p>&ldquo;- Ha, but my design has fewer dependency points than yours!&rdquo;</p>

</blockquote>
<p>Rails did to Ruby what Apple did to Unix and Canonical did to Linux-based distros. People complaining about Rails remind me of people trying to argue why Archlinux is way superior to OS X or Ubuntu, but it&rsquo;s just that people in general are too stupid to perceive that value.</p>
<p>And for some, it&rsquo;s not exactly flattering to be in the same league as Apple or Canonical, but the results are undeniable.</p>
<p>Remember the legendary &ldquo;15-minute blog&rdquo;? Why did it surprise us so much in 2005? It was not what Rails could do; it was all the work we didn&rsquo;t need to do. And Rails has stayed true to that until now.</p>
<p>If you&rsquo;re a beginner programmer, Rails still has plenty to teach, and you can learn the details later.</p>
<p>If you&rsquo;re the average programmer, Rails&rsquo; ecosystem will take you from point A to point B much faster, with better productivity and maintainability.</p>
<p>Why are you complaining if you&rsquo;re the tech star programmer funded by a unicorn?</p>
<p>Programmers ranting are not following one of our own old favorite quotes: &ldquo;Premature Optimization is the Root of All Evil.&rdquo; And as the &ldquo;UNIX way&rdquo; already had:</p>
<blockquote>
  <p>The strategy is definitely:</p>

</blockquote>
<blockquote>
  <p>Make it work,</p>

</blockquote>
<blockquote>
  <p>Then make it right,</p>

</blockquote>
<blockquote>
  <p>and, finally, make it fast.</p>

</blockquote>
<p>There is nothing wrong with having alternatives to Rails, but the Rails bashing is getting very old very fast. It&rsquo;s difficult to pitch alternatives, I know. I&rsquo;ve spent many shoe soles in the last 10 years advocating Ruby, so I really know it.</p>
<p>I never believed in free lunch. I believe in targeted, hard work, and that&rsquo;s been my philosophy for the last 25 years in programming.</p>
]]></content:encoded><category>rails</category><category>ruby</category></item><item><title>[Manga-Downloadr] Porting from Crystal to Ruby (and a bit of JRuby)</title><link>https://akitaonrails.github.io/en/2016/06/06/manga-downloadr-porting-from-crystal-to-ruby-and-a-bit-of-jruby/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2016/06/06/manga-downloadr-porting-from-crystal-to-ruby-and-a-bit-of-jruby/</guid><pubDate>Mon, 06 Jun 2016 18:06:00 -0300</pubDate><description>&lt;p&gt;I have this old pet project of mine called &lt;a href="http://www.akitaonrails.com/2014/12/17/small-bites-downloader-para-mangareader-kindle-edition"target="_blank" rel="noopener"&gt;Manga Downloadr&lt;/a&gt; that I published in 2014. It was a very rough version. I was experimenting with Typhoeus asynchronous requests and in the end the code ended up becoming super messed up.&lt;/p&gt;
&lt;p&gt;The nature of the original Manga Downloader is no different from a web crawler: it fetches HTML pages, parses them in order to find collections of links and keeps fetching until a set of images is downloaded. Then I organize them in volumes, optimize them to fit the Kindle screen resolution, and compile them down into PDF files. This makes this project an interesting exercise in trying to make concurrent HTTP requests and process the results.&lt;/p&gt;</description><content:encoded><![CDATA[<p>I have this old pet project of mine called <a href="http://www.akitaonrails.com/2014/12/17/small-bites-downloader-para-mangareader-kindle-edition"target="_blank" rel="noopener">Manga Downloadr</a> that I published in 2014. It was a very rough version. I was experimenting with Typhoeus asynchronous requests and in the end the code ended up becoming super messed up.</p>
<p>The nature of the original Manga Downloader is no different from a web crawler: it fetches HTML pages, parses them in order to find collections of links and keeps fetching until a set of images is downloaded. Then I organize them in volumes, optimize them to fit the Kindle screen resolution, and compile them down into PDF files. This makes this project an interesting exercise in trying to make concurrent HTTP requests and process the results.</p>
<p>A year later I was learning Elixir. The Manga Downloadr was a nice candidate for me to figure out how to implement the same thing in a different language. You can follow my learning process in <a href="http://www.akitaonrails.com/exmangadownloadr"target="_blank" rel="noopener">this series of posts</a>.</p>
<p>Finally, I&rsquo;ve been learning more about Crystal, a Ruby-inspired platform that can compile Ruby-like source code into LLVM-optimized native binaries. And as a bonus it features Go-like CSP channels and fibers to allow for concurrent code.</p>
<p>So I adapted my Elixir version to Crystal and the result is this code you can find over Github as <a href="https://github.com/akitaonrails/cr_manga_downloadr"target="_blank" rel="noopener">akitaonrails/cr_manga_downloadr</a>.</p>
<p>It works very well and performs really fast, limited mainly by how many requests MangaReader can respond to concurrently and the speed/reliability of the Internet connection. So, as my original Ruby version was terrible code, it was a good time to rewrite it. And as Crystal is surprisingly close to Ruby I decided to port it over.</p>
<blockquote>
  <p>The port was almost too trivial</p>

</blockquote>
<p>It was mostly copying and pasting the Crystal code without the Type annotations. And I had to replace the lightweight Fibers and Channel implementation for concurrency with traditional Ruby Threads.</p>
<p>The new version 2.0 for the Ruby version of the tool can be found in this Github repository: <a href="https://github.com/akitaonrails/manga-downloadr"target="_blank" rel="noopener">akitaonrails/manga-downloadr</a>.</p>
<h3>Ruby, Ruby everywhere!<span class="hx:absolute hx:-mt-20" id="ruby-ruby-everywhere"></span>
    <a href="#ruby-ruby-everywhere" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Moving between Ruby and Crystal is not so difficult. The Crystal team did a fantastic job implementing a very solid Standard Library (stdlib) that very closely resembles MRI Ruby&rsquo;s.</p>
<p>For example, let&rsquo;s compare a snippet from my Crystal version first:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">fetch</span><span class="p">(</span><span class="n">page_link</span> <span class="p">:</span> <span class="nb">String</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">get</span> <span class="n">page_link</span> <span class="k">do</span> <span class="o">|</span><span class="n">html</span><span class="o">|</span>
</span></span><span class="line"><span class="cl">    <span class="n">images</span> <span class="o">=</span> <span class="n">html</span><span class="o">.</span><span class="n">xpath</span><span class="p">(</span><span class="s2">&#34;//img[contains(@id, &#39;img&#39;)]&#34;</span><span class="p">)</span><span class="o">.</span><span class="n">as</span><span class="p">(</span><span class="no">XML</span><span class="o">::</span><span class="no">NodeSet</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">image_alt</span> <span class="o">=</span> <span class="n">images</span><span class="o">[</span><span class="mi">0</span><span class="o">][</span><span class="s2">&#34;alt&#34;</span><span class="o">]</span>
</span></span><span class="line"><span class="cl">    <span class="n">image_src</span> <span class="o">=</span> <span class="n">images</span><span class="o">[</span><span class="mi">0</span><span class="o">][</span><span class="s2">&#34;src&#34;</span><span class="o">]</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">image_alt</span> <span class="o">&amp;&amp;</span> <span class="n">image_src</span>
</span></span><span class="line"><span class="cl">      <span class="n">extension</span>      <span class="o">=</span> <span class="n">image_src</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&#34;.&#34;</span><span class="p">)</span><span class="o">.</span><span class="n">last</span>
</span></span><span class="line"><span class="cl">      <span class="n">list</span>           <span class="o">=</span> <span class="n">image_alt</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&#34; &#34;</span><span class="p">)</span><span class="o">.</span><span class="n">reverse</span>
</span></span><span class="line"><span class="cl">      <span class="n">title_name</span>     <span class="o">=</span> <span class="n">list</span><span class="o">[</span><span class="mi">4</span><span class="o">..-</span><span class="mi">1</span><span class="o">].</span><span class="n">join</span><span class="p">(</span><span class="s2">&#34; &#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="n">chapter_number</span> <span class="o">=</span> <span class="n">list</span><span class="o">[</span><span class="mi">3</span><span class="o">].</span><span class="n">rjust</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="s1">&#39;0&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="n">page_number</span>    <span class="o">=</span> <span class="n">list</span><span class="o">[</span><span class="mi">0</span><span class="o">].</span><span class="n">rjust</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="s1">&#39;0&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="n">uri</span> <span class="o">=</span> <span class="no">URI</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">image_src</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="no">CrMangaDownloadr</span><span class="o">::</span><span class="no">Image</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="n">uri</span><span class="o">.</span><span class="n">host</span> <span class="n">as</span> <span class="nb">String</span><span class="p">,</span> <span class="n">uri</span><span class="o">.</span><span class="n">path</span> <span class="n">as</span> <span class="nb">String</span><span class="p">,</span> <span class="s2">&#34;</span><span class="si">#{</span><span class="n">title_name</span><span class="si">}</span><span class="s2">-Chap-</span><span class="si">#{</span><span class="n">chapter_number</span><span class="si">}</span><span class="s2">-Pg-</span><span class="si">#{</span><span class="n">page_number</span><span class="si">}</span><span class="s2">.</span><span class="si">#{</span><span class="n">extension</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">else</span>
</span></span><span class="line"><span class="cl">      <span class="k">raise</span> <span class="no">Exception</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="s2">&#34;Couldn&#39;t find proper metadata alt in the image tag&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">end</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Now let&rsquo;s check the ported Ruby version:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">fetch</span><span class="p">(</span><span class="n">page_link</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">get</span> <span class="n">page_link</span> <span class="k">do</span> <span class="o">|</span><span class="n">html</span><span class="o">|</span>
</span></span><span class="line"><span class="cl">    <span class="n">images</span> <span class="o">=</span> <span class="n">html</span><span class="o">.</span><span class="n">css</span><span class="p">(</span><span class="s1">&#39;#img&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">image_alt</span> <span class="o">=</span> <span class="n">images</span><span class="o">[</span><span class="mi">0</span><span class="o">][</span><span class="s2">&#34;alt&#34;</span><span class="o">]</span>
</span></span><span class="line"><span class="cl">    <span class="n">image_src</span> <span class="o">=</span> <span class="n">images</span><span class="o">[</span><span class="mi">0</span><span class="o">][</span><span class="s2">&#34;src&#34;</span><span class="o">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">image_alt</span> <span class="o">&amp;&amp;</span> <span class="n">image_src</span>
</span></span><span class="line"><span class="cl">      <span class="n">extension</span>      <span class="o">=</span> <span class="n">image_src</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&#34;.&#34;</span><span class="p">)</span><span class="o">.</span><span class="n">last</span>
</span></span><span class="line"><span class="cl">      <span class="n">list</span>           <span class="o">=</span> <span class="n">image_alt</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&#34; &#34;</span><span class="p">)</span><span class="o">.</span><span class="n">reverse</span>
</span></span><span class="line"><span class="cl">      <span class="n">title_name</span>     <span class="o">=</span> <span class="n">list</span><span class="o">[</span><span class="mi">4</span><span class="o">..-</span><span class="mi">1</span><span class="o">].</span><span class="n">join</span><span class="p">(</span><span class="s2">&#34; &#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="n">chapter_number</span> <span class="o">=</span> <span class="n">list</span><span class="o">[</span><span class="mi">3</span><span class="o">].</span><span class="n">rjust</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="s1">&#39;0&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="n">page_number</span>    <span class="o">=</span> <span class="n">list</span><span class="o">[</span><span class="mi">0</span><span class="o">].</span><span class="n">rjust</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="s1">&#39;0&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      <span class="n">uri</span> <span class="o">=</span> <span class="no">URI</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">image_src</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="no">Image</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="n">uri</span><span class="o">.</span><span class="n">host</span><span class="p">,</span> <span class="n">uri</span><span class="o">.</span><span class="n">path</span><span class="p">,</span> <span class="s2">&#34;</span><span class="si">#{</span><span class="n">title_name</span><span class="si">}</span><span class="s2">-Chap-</span><span class="si">#{</span><span class="n">chapter_number</span><span class="si">}</span><span class="s2">-Pg-</span><span class="si">#{</span><span class="n">page_number</span><span class="si">}</span><span class="s2">.</span><span class="si">#{</span><span class="n">extension</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">else</span>
</span></span><span class="line"><span class="cl">      <span class="k">raise</span> <span class="no">Exception</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="s2">&#34;Couldn&#39;t find proper metadata alt in the image tag&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">end</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>It&rsquo;s uncanny how similar they are, down to stdlib calls such as <code>URI.parse</code> or Array methods such as <code>split</code>.</p>
<blockquote>
  <p>Once you remove the Type annotations from the Crystal version, it&rsquo;s 99% Ruby.</p>

</blockquote>
<p>Ruby doesn&rsquo;t care if you&rsquo;re trying to call a method on a Nil object - at source code compiling time. Crystal does compile-time checks and if it feels like the method call will be over Nil, it won&rsquo;t even compile. So this is one big win to avoid subtle bugs.</p>
<p>In Rails we are used to the <code>#try</code> method. Ruby 2.3 introduced the <a href="http://mitrev.net/ruby/2015/11/13/the-operator-in-ruby/"target="_blank" rel="noopener">safe navigation operator</a>.</p>
<p>So, in Ruby 2.3 with Rails, both of the following lines are valid:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="n">obj</span><span class="o">.</span><span class="n">try</span><span class="p">(</span><span class="ss">:something</span><span class="p">)</span><span class="o">.</span><span class="n">try</span><span class="p">(</span><span class="ss">:something2</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">obj</span><span class="o">&amp;.</span><span class="n">something</span><span class="o">&amp;.</span><span class="n">something2</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>In Crystal we can do the following:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="n">obj</span><span class="o">.</span><span class="n">try</span><span class="p">(</span><span class="o">&amp;.</span><span class="n">something</span><span class="p">)</span><span class="o">.</span><span class="n">try</span><span class="p">(</span><span class="o">&amp;.</span><span class="n">something2</span><span class="p">)</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>So, it&rsquo;s close. Use with care.</p>
<p>As I mentioned before, Crystal is close to Ruby but it&rsquo;s not meant to be compatible, so we can&rsquo;t just load Rubygems without porting. In this example I don&rsquo;t have Nokogiri to parse the HTML. But this is where the stdlib shines: Crystal comes with good enough XML/HTML and JSON parsers. So we can parse HTML as XML and use plain XPath instead.</p>
<p>Instead of Ruby&rsquo;s <code>Net::HTTP</code> we have <code>HTTP::Client</code> (but their methods and semantics are surprisingly similar).</p>
<p>There are other differences, for example, this is the main file that requires all the others in Ruby:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="o">...</span>
</span></span><span class="line"><span class="cl"><span class="vg">$LOAD_PATH</span><span class="o">.</span><span class="n">unshift</span> <span class="no">File</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="no">File</span><span class="o">.</span><span class="n">dirname</span><span class="p">(</span><span class="bp">__FILE__</span><span class="p">),</span> <span class="s2">&#34;lib&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">require</span> <span class="s2">&#34;manga-downloadr/records.rb&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">require</span> <span class="s2">&#34;manga-downloadr/downloadr_client.rb&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">require</span> <span class="s2">&#34;manga-downloadr/concurrency.rb&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">require</span> <span class="s2">&#34;manga-downloadr/chapters.rb&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">require</span> <span class="s2">&#34;manga-downloadr/pages.rb&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">require</span> <span class="s2">&#34;manga-downloadr/page_image.rb&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">require</span> <span class="s2">&#34;manga-downloadr/image_downloader.rb&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">require</span> <span class="s2">&#34;manga-downloadr/workflow.rb&#34;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>And this is the Crystal version of the same manifest:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="nb">require</span> <span class="s2">&#34;./cr_manga_downloadr/*&#34;</span>
</span></span><span class="line"><span class="cl"><span class="o">...</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>On the other hand, we need to be a bit more explicit in each Crystal source code file, and declare the specific dependencies where needed. For example, in the <code>pages.cr</code> file it starts like this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="nb">require</span> <span class="s2">&#34;./downloadr_client&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">require</span> <span class="s2">&#34;xml&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">module</span> <span class="nn">CrMangaDownloadr</span>
</span></span><span class="line"><span class="cl">  <span class="k">class</span> <span class="nc">Pages</span> <span class="o">&lt;</span> <span class="no">DownloadrClient</span><span class="p">(</span><span class="nb">Array</span><span class="p">(</span><span class="nb">String</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">  <span class="o">...</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Crystal has less room for &ldquo;magic&rdquo; but it&rsquo;s able to maintain a high level of abstraction anyway.</p>
<h3>A Word about Types<span class="hx:absolute hx:-mt-20" id="a-word-about-types"></span>
    <a href="#a-word-about-types" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><blockquote>
  <p>We can spend the next decade masturbating over all there is about Types, and it will be extremely boring.</p>

</blockquote>
<p>The only thing you must understand: the compiler must know the method signature of classes before you can use them. There is no Runtime component that can introspect objects on the fly, like in Ruby and other dynamic languages (even Objective-C/Swift can do more dynamic stuff than Crystal).</p>
<p>Most of the time the Crystal compiler will be smart enough to infer the types for you, so you don&rsquo;t need to be absolutely explicit. You should follow the compiler&rsquo;s lead to know when to use Type Annotations.</p>
<p>What may really scare you at first is the need for Type Annotations, to understand Generics and so forth. The compiler will print out every scary error dump that you will need to get used to. Most scary errors will usually be a Type Annotation missing or you trying to call a method on a possibly Nil object.</p>
<p>For example, if I change the following line in the <code>page_image_spec.cr</code> test file:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="c1"># line 8:</span>
</span></span><span class="line"><span class="cl"><span class="n">image</span> <span class="o">=</span> <span class="no">CrMangaDownloadr</span><span class="o">::</span><span class="no">PageImage</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="s2">&#34;www.mangareader.net&#34;</span><span class="p">)</span><span class="o">.</span><span class="n">fetch</span><span class="p">(</span><span class="s2">&#34;/naruto/662/2&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># line 10:</span>
</span></span><span class="line"><span class="cl"><span class="c1"># image.try(&amp;.host).should eq(&#34;i8.mangareader.net&#34;)</span>
</span></span><span class="line"><span class="cl"><span class="n">image</span><span class="o">.</span><span class="n">host</span><span class="o">.</span><span class="n">should</span> <span class="n">eq</span><span class="p">(</span><span class="s2">&#34;i8.mangareader.net&#34;</span><span class="p">)</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>The commented out line recognizes that the <code>image</code> instance might come as Nil, so we add an explicit <code>#try</code> call in the spec.</p>
<p>If we try to compile without this recognition, this is the error the compiler will dump on you:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>$ crystal spec                                                        [
Error in ./spec/cr_manga_downloadr/page_image_spec.cr:10: undefined method &#39;host&#39; for Nil (compile-time type is CrMangaDownloadr::Image?)

    image.host.should eq(&#34;i8.mangareader.net&#34;)
          ^~~~

=============================================================================

Nil trace:

  ./spec/cr_manga_downloadr/page_image_spec.cr:8

        image = CrMangaDownloadr::PageImage.new(&#34;www.mangareader.net&#34;).fetch(&#34;/naruto/662/2&#34;)
...</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>There is a large stack trace dump after that snippet above, but you only need to pay attention to the first few lines that already say what&rsquo;s wrong: &ldquo;undefined method &lsquo;host&rsquo; for Nil (compile-time type is CrMangaDownloadr::Image?)&rdquo;. If you know how to read, you shouldn&rsquo;t have any problems most of the time.</p>
<p>Now, the <code>Chapters</code>, <code>Pages</code>, <code>PageImage</code> (all subclasses of <code>DownloadrClient</code>) are basically the same thing: they do <code>HTTP::Client</code> requests.</p>
<p>This is how the <code>Pages</code> class is implemented:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="o">...</span>
</span></span><span class="line"><span class="cl"><span class="k">module</span> <span class="nn">CrMangaDownloadr</span>
</span></span><span class="line"><span class="cl">  <span class="k">class</span> <span class="nc">Pages</span> <span class="o">&lt;</span> <span class="no">DownloadrClient</span><span class="p">(</span><span class="nb">Array</span><span class="p">(</span><span class="nb">String</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="nf">fetch</span><span class="p">(</span><span class="n">chapter_link</span> <span class="p">:</span> <span class="nb">String</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="n">get</span> <span class="n">chapter_link</span> <span class="k">do</span> <span class="o">|</span><span class="n">html</span><span class="o">|</span>
</span></span><span class="line"><span class="cl">        <span class="n">nodes</span> <span class="o">=</span> <span class="n">html</span><span class="o">.</span><span class="n">xpath_nodes</span><span class="p">(</span><span class="s2">&#34;//div[@id=&#39;selectpage&#39;]//select[@id=&#39;pageMenu&#39;]//option&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">nodes</span><span class="o">.</span><span class="n">map</span> <span class="p">{</span> <span class="o">|</span><span class="n">node</span><span class="o">|</span> <span class="o">[</span><span class="n">chapter_link</span><span class="p">,</span> <span class="n">node</span><span class="o">.</span><span class="n">text</span> <span class="n">as</span> <span class="nb">String</span><span class="o">].</span><span class="n">join</span><span class="p">(</span><span class="s2">&#34;/&#34;</span><span class="p">)</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">      <span class="k">end</span>
</span></span><span class="line"><span class="cl">    <span class="k">end</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p><code>#get</code> is a method from the <code>DownloadrClient</code> superclass that receives a String <code>chapter_link</code> and a block. The block receives a parsed <code>html</code> collection of nodes and we can play with it, returning an Array of Strings.</p>
<p>That&rsquo;s why we have the <code>(Array(String))</code> when inheriting from <code>DownloadrClient</code>. Let&rsquo;s see how the <code>DownloadrClient</code> superclass is implemented.</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="k">module</span> <span class="nn">CrMangaDownloadr</span>
</span></span><span class="line"><span class="cl">  <span class="k">class</span> <span class="nc">DownloadrClient</span><span class="p">(</span><span class="n">T</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="o">...</span>
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="nf">get</span><span class="p">(</span><span class="n">uri</span> <span class="p">:</span> <span class="nb">String</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">block</span> <span class="p">:</span> <span class="no">XML</span><span class="o">::</span><span class="no">Node</span> <span class="o">-&gt;</span> <span class="n">T</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="n">response</span> <span class="o">=</span> <span class="vi">@http_client</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">uri</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="k">case</span> <span class="n">response</span><span class="o">.</span><span class="n">status_code</span>
</span></span><span class="line"><span class="cl">      <span class="k">when</span> <span class="mi">301</span>
</span></span><span class="line"><span class="cl">        <span class="n">get</span> <span class="n">response</span><span class="o">.</span><span class="n">headers</span><span class="o">[</span><span class="s2">&#34;Location&#34;</span><span class="o">]</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">block</span>
</span></span><span class="line"><span class="cl">      <span class="k">when</span> <span class="mi">200</span>
</span></span><span class="line"><span class="cl">        <span class="n">parsed</span> <span class="o">=</span> <span class="no">XML</span><span class="o">.</span><span class="n">parse_html</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">body</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">block</span><span class="o">.</span><span class="n">call</span><span class="p">(</span><span class="n">parsed</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="k">end</span>
</span></span><span class="line"><span class="cl">      <span class="o">...</span>
</span></span><span class="line"><span class="cl">    <span class="k">end</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>You can see that this class receives a Generic Type and it uses it as the return type for the yielded block in the <code>#get</code> method. The <code>XML::Node -&gt; T</code> is the declaration of the signature for the block, sending <code>XML::Node</code> and receiving whatever the type <code>T</code> is. At compile time, imagine this <code>T</code> being replaced by <code>Array(String)</code>. That&rsquo;s how you can create classes that can deal with any number of different Types without having to overload for polymorphism.</p>
<p>If you come from Java, C#, Go or any other modern statically typed language, you probably already know what a Generic is.</p>
<p>You can go very far with Generics, check out how our <code>Concurrency.cr</code> begins:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Concurrency</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">,</span> <span class="n">C</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="o">...</span>
</span></span><span class="line"><span class="cl">  <span class="k">def</span> <span class="nf">fetch</span><span class="p">(</span><span class="n">collection</span> <span class="p">:</span> <span class="nb">Array</span><span class="p">(</span><span class="n">A</span><span class="p">)</span><span class="sc">?,</span> <span class="o">&amp;</span><span class="n">block</span> <span class="p">:</span> <span class="n">A</span><span class="p">,</span> <span class="n">C?</span> <span class="o">-&gt;</span> <span class="nb">Array</span><span class="p">(</span><span class="n">B</span><span class="p">)</span><span class="sc">?)</span> <span class="p">:</span> <span class="nb">Array</span><span class="p">(</span><span class="n">B</span><span class="p">)?</span>
</span></span><span class="line"><span class="cl">    <span class="n">results</span> <span class="o">=</span> <span class="o">[]</span> <span class="n">of</span> <span class="n">B</span>
</span></span><span class="line"><span class="cl">    <span class="n">collection</span><span class="o">.</span><span class="n">try</span> <span class="o">&amp;.</span><span class="n">each_slice</span><span class="p">(</span><span class="vi">@config</span><span class="o">.</span><span class="n">download_batch_size</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">batch</span><span class="o">|</span>
</span></span><span class="line"><span class="cl">      <span class="n">engine</span>  <span class="o">=</span> <span class="k">if</span> <span class="vi">@turn_on_engine</span>
</span></span><span class="line"><span class="cl">                  <span class="n">C</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="vi">@config</span><span class="o">.</span><span class="n">domain</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                <span class="k">end</span>
</span></span><span class="line"><span class="cl">      <span class="n">channel</span> <span class="o">=</span> <span class="no">Channel</span><span class="p">(</span><span class="nb">Array</span><span class="p">(</span><span class="n">B</span><span class="p">)</span><span class="sc">?)</span><span class="o">.</span><span class="n">new</span>
</span></span><span class="line"><span class="cl">      <span class="n">batch</span><span class="o">.</span><span class="n">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">item</span><span class="o">|</span>
</span></span><span class="line"><span class="cl">      <span class="o">...</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>And this is how we use it in the <code>workflow.cr</code>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="kp">private</span> <span class="k">def</span> <span class="nf">fetch_pages</span><span class="p">(</span><span class="n">chapters</span> <span class="p">:</span> <span class="nb">Array</span><span class="p">(</span><span class="nb">String</span><span class="p">)</span><span class="sc">?)</span>
</span></span><span class="line"><span class="cl">  <span class="nb">puts</span> <span class="s2">&#34;Fetching pages from all chapters ...&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="n">reactor</span> <span class="o">=</span> <span class="no">Concurrency</span><span class="p">(</span><span class="nb">String</span><span class="p">,</span> <span class="nb">String</span><span class="p">,</span> <span class="no">Pages</span><span class="p">)</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="vi">@config</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">reactor</span><span class="o">.</span><span class="n">fetch</span><span class="p">(</span><span class="n">chapters</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">link</span><span class="p">,</span> <span class="n">engine</span><span class="o">|</span>
</span></span><span class="line"><span class="cl">    <span class="n">engine</span><span class="o">.</span><span class="n">try</span><span class="p">(</span> <span class="o">&amp;.</span><span class="n">fetch</span><span class="p">(</span><span class="n">link</span><span class="p">)</span> <span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>In this example, imagine <code>A</code> being replaced by <code>String</code>, <code>B</code> also being replaced by <code>String</code> and C being replaced by <code>Pages</code> in the <code>Concurrency</code> class.</p>
<p>This is the &ldquo;first-version-that-worked&rdquo; so it&rsquo;s probably not very idiomatic. Either this could be solved with less Generics exercising or maybe I could simplify it with the use of Macros. But it&rsquo;s working quite ok as it is.</p>
<p>The pure Ruby version ends up just like this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Concurrency</span>
</span></span><span class="line"><span class="cl">  <span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">engine_klass</span> <span class="o">=</span> <span class="kp">nil</span><span class="p">,</span> <span class="n">config</span> <span class="o">=</span> <span class="no">Config</span><span class="o">.</span><span class="n">new</span><span class="p">,</span> <span class="n">turn_on_engine</span> <span class="o">=</span> <span class="kp">true</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="o">...</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl">  <span class="k">def</span> <span class="nf">fetch</span><span class="p">(</span><span class="n">collection</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">block</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">results</span> <span class="o">=</span> <span class="o">[]</span>
</span></span><span class="line"><span class="cl">    <span class="n">collection</span><span class="o">&amp;.</span><span class="n">each_slice</span><span class="p">(</span><span class="vi">@config</span><span class="o">.</span><span class="n">download_batch_size</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">batch</span><span class="o">|</span>
</span></span><span class="line"><span class="cl">      <span class="n">mutex</span>   <span class="o">=</span> <span class="no">Mutex</span><span class="o">.</span><span class="n">new</span>
</span></span><span class="line"><span class="cl">      <span class="n">threads</span> <span class="o">=</span> <span class="n">batch</span><span class="o">.</span><span class="n">map</span> <span class="k">do</span> <span class="o">|</span><span class="n">item</span><span class="o">|</span>
</span></span><span class="line"><span class="cl">      <span class="o">...</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>This version is much &ldquo;simpler&rdquo; in terms of source code density. But on the other hand we would have to test this Ruby version a lot more because it has many different permutations (we even inject classes through <code>engine_klass</code>) that we must make sure respond correctly. In practice we should add tests for all combinations of the initializer&rsquo;s arguments.</p>
<p>In the Crystal version, because all types have been checked at compile-time, it was more demanding in terms of annotations; but we can be pretty sure that if it compiles, it will run as expected.</p>
<blockquote>
  <p>I&rsquo;m not saying that Crystal doesn&rsquo;t need any specs.</p>

</blockquote>
<p>Compilers can only go so far. But how much is &ldquo;so far&rdquo;? Whenever you&rsquo;re &ldquo;forced&rdquo; to add Type Annotations, I will state that those parts are either trying to be too smart or they are intrinsically complex. Those are parts that would require extra levels of tests in Ruby and, if we can add the annotations properly, we can have fewer tests (we don&rsquo;t need to cover most permutations) in the Crystal version (exponential complexity of permutations could go down to a linear complexity, I think).</p>
<h3>A Word about Ruby Threads<span class="hx:absolute hx:-mt-20" id="a-word-about-ruby-threads"></span>
    <a href="#a-word-about-ruby-threads" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>The main concepts you must understand about concurrency in Ruby are these:</p>
<ul>
<li>MRI Ruby has a GIL, a Global Interpreter Lock, that forbids code from running concurrently.</li>
<li>MRI Ruby does have access and exposes native Threads since version 1.9. But even if you fire up multiple Threads, they will run sequentially because only one thread can hold the Lock at a time.</li>
<li>I/O operations are the exception: they do release the Lock for other threads to run while the operation is waiting to complete. The OS will signal the program through OS-level poll.</li>
</ul>
<p>This means that if your app is <strong>I/O intensive</strong> (HTTP requests, File reads or writes, socket operations, etc), you will have <em>some</em> concurrency. A web server, such as Puma for example, can take some advantage of Threads because a big part of the operations involves receiving HTTP requests and sending HTTP responses over the wire, which would make the Ruby process idle while waiting.</p>
<p>If your app is CPU intensive (heavy algorithms, data crunching, stuff that really makes the CPU hot) then you can&rsquo;t take advantage of native Threads, only one will run at a time. If you have multiple cores in your CPU, you can Fork your process to the number of cores available.</p>
<p>You should check out <a href="https://github.com/grosser/parallel"target="_blank" rel="noopener">grosser/parallel</a> to make it easy.</p>
<p>This is why Puma also has a &ldquo;worker&rdquo; mode. &ldquo;Worker&rdquo; is the name we usually give to forked children of processes.</p>
<p>In the case of this downloader process, it will perform thousands of HTTP requests to scrape the needed metadata from the MangaReader pages. So it&rsquo;s definitely much more I/O intensive than CPU intensive (the CPU intensive parts are the HTML parsing and later the image resizing and PDF compiling).</p>
<p>A sequential version of what has to be done, in Ruby, looks like this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">fetch_sequential</span><span class="p">(</span><span class="n">collection</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">block</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">results</span> <span class="o">=</span> <span class="o">[]</span>
</span></span><span class="line"><span class="cl">  <span class="n">engine</span>  <span class="o">=</span> <span class="vi">@turn_on_engine</span> <span class="p">?</span> <span class="vi">@engine_klass</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="vi">@config</span><span class="o">.</span><span class="n">domain</span><span class="p">)</span> <span class="p">:</span> <span class="kp">nil</span>
</span></span><span class="line"><span class="cl">  <span class="n">collection</span><span class="o">&amp;.</span><span class="n">each_slice</span><span class="p">(</span><span class="vi">@config</span><span class="o">.</span><span class="n">download_batch_size</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">batch</span><span class="o">|</span>
</span></span><span class="line"><span class="cl">    <span class="n">batch</span><span class="o">.</span><span class="n">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">item</span><span class="o">|</span>
</span></span><span class="line"><span class="cl">      <span class="n">batch_results</span> <span class="o">=</span> <span class="n">block</span><span class="o">.</span><span class="n">call</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="n">engine</span><span class="p">)</span><span class="o">&amp;.</span><span class="n">flatten</span>
</span></span><span class="line"><span class="cl">      <span class="n">results</span> <span class="o">+=</span> <span class="p">(</span> <span class="n">batch_results</span> <span class="o">||</span> <span class="o">[]</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">end</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl">  <span class="n">results</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>If we have 10,000 links in the <code>collection</code>, we first slice it to what <code>@config.download_batch_size</code> defines and we iterate over those smaller slices, calling some block and accumulating the results. This is a naive algorithm, as you will find out in the next section, but bear with me.</p>
<p>In Elixir you can fire up micro-processes to make the HTTP requests in parallel. In Crystal you can fire up Fibers and wait for the HTTP requests to complete and signal the results through Channels.</p>
<p>Both are lightweight ways and you can have hundreds or even thousands running in parallel. Manga Reader will probably complain if you try that many at once, so the limit is not in the code, but in the external service.</p>
<p>To transform the sequential version into a concurrent one, this is what we can do in Crystal:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">fetch</span><span class="p">(</span><span class="n">collection</span> <span class="p">:</span> <span class="nb">Array</span><span class="p">(</span><span class="n">A</span><span class="p">)</span><span class="sc">?,</span> <span class="o">&amp;</span><span class="n">block</span> <span class="p">:</span> <span class="n">A</span><span class="p">,</span> <span class="n">C?</span> <span class="o">-&gt;</span> <span class="nb">Array</span><span class="p">(</span><span class="n">B</span><span class="p">)</span><span class="sc">?)</span> <span class="p">:</span> <span class="nb">Array</span><span class="p">(</span><span class="n">B</span><span class="p">)?</span>
</span></span><span class="line"><span class="cl">  <span class="n">results</span> <span class="o">=</span> <span class="o">[]</span> <span class="n">of</span> <span class="n">B</span>
</span></span><span class="line"><span class="cl">  <span class="n">collection</span><span class="o">.</span><span class="n">try</span> <span class="o">&amp;.</span><span class="n">each_slice</span><span class="p">(</span><span class="vi">@config</span><span class="o">.</span><span class="n">download_batch_size</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">batch</span><span class="o">|</span>
</span></span><span class="line"><span class="cl">    <span class="n">channel</span> <span class="o">=</span> <span class="no">Channel</span><span class="p">(</span><span class="nb">Array</span><span class="p">(</span><span class="n">B</span><span class="p">)</span><span class="sc">?)</span><span class="o">.</span><span class="n">new</span>
</span></span><span class="line"><span class="cl">    <span class="n">batch</span><span class="o">.</span><span class="n">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">item</span><span class="o">|</span>
</span></span><span class="line"><span class="cl">      <span class="n">spawn</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">engine</span>  <span class="o">=</span> <span class="k">if</span> <span class="vi">@turn_on_engine</span>
</span></span><span class="line"><span class="cl">                    <span class="n">C</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="vi">@config</span><span class="o">.</span><span class="n">domain</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                  <span class="k">end</span>
</span></span><span class="line"><span class="cl">        <span class="n">reply</span> <span class="o">=</span> <span class="n">block</span><span class="o">.</span><span class="n">call</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="n">engine</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">channel</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">reply</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">engine</span><span class="o">.</span><span class="n">try</span> <span class="o">&amp;.</span><span class="n">close</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">end</span>
</span></span><span class="line"><span class="cl">    <span class="n">batch</span><span class="o">.</span><span class="n">size</span><span class="o">.</span><span class="n">times</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">      <span class="n">reply</span> <span class="o">=</span> <span class="n">channel</span><span class="o">.</span><span class="n">receive</span>
</span></span><span class="line"><span class="cl">      <span class="k">if</span> <span class="n">reply</span>
</span></span><span class="line"><span class="cl">        <span class="n">results</span><span class="o">.</span><span class="n">concat</span><span class="p">(</span><span class="n">reply</span><span class="o">.</span><span class="n">flatten</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="k">end</span>
</span></span><span class="line"><span class="cl">    <span class="k">end</span>
</span></span><span class="line"><span class="cl">    <span class="n">channel</span><span class="o">.</span><span class="n">close</span>
</span></span><span class="line"><span class="cl">    <span class="nb">puts</span> <span class="s2">&#34;Processed so far: </span><span class="si">#{</span><span class="n">results</span><span class="o">.</span><span class="n">try</span> <span class="o">&amp;.</span><span class="n">size</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl">  <span class="n">results</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Fetching a huge collection and slicing it in smaller &lsquo;batches&rsquo; is easy. Now we have a smaller <code>batch</code> collection. For each item (usually a URI) we <code>spawn</code> a Fiber and call a block that will request and process the results. Once it&rsquo;s finished processing it sends the results over a <code>channel</code>.</p>
<p>Once we finish iterating over the batch and spawning that many Fibers we can &ldquo;wait&rdquo; for them by doing <code>channel.receive</code>, which will start receiving results as soon as the Fibers finish requesting/processing each URI.</p>
<p>We accumulate the results and go over the next batch of the collection until finished. The amount of concurrency is determined by the size of the batch (it&rsquo;s like <a href="http://www.akitaonrails.com/en/en/2015/11/19/ex-manga-downloadr-parte-2-poolboy-ao-resgate/"target="_blank" rel="noopener">what I did with &lsquo;poolboy&rsquo; over Elixir</a> where we start a fixed number of processes to run in parallel and avoid doing a Denial of Service to Manga Reader).</p>
<p>By the way, this Crystal implementation is similar to what you would do if you were in Go, using Channels.</p>
<p>In the Ruby version you can fire up native Threads - which has a lot of overhead to spawn! - and assume the HTTP requests will run almost all in parallel. Because it&rsquo;s I/O intensive, you can have them all in parallel. This is what it looks like:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">fetch</span><span class="p">(</span><span class="n">collection</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">block</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">results</span> <span class="o">=</span> <span class="o">[]</span>
</span></span><span class="line"><span class="cl">  <span class="n">collection</span><span class="o">&amp;.</span><span class="n">each_slice</span><span class="p">(</span><span class="vi">@config</span><span class="o">.</span><span class="n">download_batch_size</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">batch</span><span class="o">|</span>
</span></span><span class="line"><span class="cl">    <span class="n">mutex</span>   <span class="o">=</span> <span class="no">Mutex</span><span class="o">.</span><span class="n">new</span>
</span></span><span class="line"><span class="cl">    <span class="n">threads</span> <span class="o">=</span> <span class="n">batch</span><span class="o">.</span><span class="n">map</span> <span class="k">do</span> <span class="o">|</span><span class="n">item</span><span class="o">|</span>
</span></span><span class="line"><span class="cl">      <span class="no">Thread</span><span class="o">.</span><span class="n">new</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">engine</span>  <span class="o">=</span> <span class="vi">@turn_on_engine</span> <span class="p">?</span> <span class="vi">@engine_klass</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="vi">@config</span><span class="o">.</span><span class="n">domain</span><span class="p">)</span> <span class="p">:</span> <span class="kp">nil</span>
</span></span><span class="line"><span class="cl">        <span class="no">Thread</span><span class="o">.</span><span class="n">current</span><span class="o">[</span><span class="s2">&#34;results&#34;</span><span class="o">]</span> <span class="o">=</span> <span class="n">block</span><span class="o">.</span><span class="n">call</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="n">engine</span><span class="p">)</span><span class="o">&amp;.</span><span class="n">flatten</span>
</span></span><span class="line"><span class="cl">        <span class="n">mutex</span><span class="o">.</span><span class="n">synchronize</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">          <span class="n">results</span> <span class="o">+=</span> <span class="p">(</span> <span class="no">Thread</span><span class="o">.</span><span class="n">current</span><span class="o">[</span><span class="s2">&#34;results&#34;</span><span class="o">]</span> <span class="o">||</span> <span class="o">[]</span> <span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">end</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">end</span>
</span></span><span class="line"><span class="cl">    <span class="n">threads</span><span class="o">.</span><span class="n">each</span><span class="p">(</span><span class="o">&amp;</span><span class="ss">:join</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="nb">puts</span> <span class="s2">&#34;Processed so far: </span><span class="si">#{</span><span class="n">results</span><span class="o">&amp;.</span><span class="n">size</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl">  <span class="n">results</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Threads are all initialized in a &ldquo;paused&rdquo; state. Once we instantiate those many Threads, we can <code>#join</code> on each of them and wait for them all to finish.</p>
<p>Once each Thread finishes the same URI request/process, the results must be accumulated in a global storage, in this case a simple array called <code>results</code>. But because we might have the chance of 2 or more threads trying to update the same array, we might as well synchronize the access (I&rsquo;m not sure if Ruby&rsquo;s Array access is already synchronized, but I guess not). To synchronize access we use a Mutex, which is a fine-grained lock, to make sure only 1 thread can modify the global array at once.</p>
<p>To prove that Ruby can support concurrent I/O operations, I have added 2 methods to the <code>Concurrent</code> class, the first is just <code>#fetch</code> and it&rsquo;s the Thread implementation above. The second is called <code>#fetch_sequential</code> and it is the sequential version also shown at the beginning of this section. And I added the following spec:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="n">it</span> <span class="s2">&#34;should check that the fetch implementation runs in less time than the sequential version&#34;</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">  <span class="n">reactor</span> <span class="o">=</span> <span class="no">MangaDownloadr</span><span class="o">::</span><span class="no">Concurrency</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="no">MangaDownloadr</span><span class="o">::</span><span class="no">Pages</span><span class="p">,</span> <span class="n">config</span><span class="p">,</span> <span class="kp">true</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">collection</span> <span class="o">=</span> <span class="o">[</span><span class="s2">&#34;/onepunch-man/96&#34;</span><span class="o">]</span> <span class="o">*</span> <span class="mi">10</span>
</span></span><span class="line"><span class="cl">  <span class="no">WebMock</span><span class="o">.</span><span class="n">allow_net_connect!</span>
</span></span><span class="line"><span class="cl">  <span class="k">begin</span>
</span></span><span class="line"><span class="cl">    <span class="n">concurrent_measurement</span> <span class="o">=</span> <span class="no">Benchmark</span><span class="o">.</span><span class="n">measure</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="n">results</span> <span class="o">=</span> <span class="n">reactor</span><span class="o">.</span><span class="n">fetch</span><span class="p">(</span><span class="n">collection</span><span class="p">)</span> <span class="p">{</span> <span class="o">|</span><span class="n">link</span><span class="p">,</span> <span class="n">engine</span><span class="o">|</span> <span class="n">engine</span><span class="o">&amp;.</span><span class="n">fetch</span><span class="p">(</span><span class="n">link</span><span class="p">)</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="n">sequential_measurement</span> <span class="o">=</span> <span class="no">Benchmark</span><span class="o">.</span><span class="n">measure</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="n">results</span> <span class="o">=</span> <span class="n">reactor</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="ss">:fetch_sequential</span><span class="p">,</span> <span class="n">collection</span><span class="p">)</span> <span class="p">{</span> <span class="o">|</span><span class="n">link</span><span class="p">,</span> <span class="n">engine</span><span class="o">|</span> <span class="n">engine</span><span class="o">&amp;.</span><span class="n">fetch</span><span class="p">(</span><span class="n">link</span><span class="p">)</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="sr">/\((.*?)\)$/</span><span class="o">.</span><span class="n">match</span><span class="p">(</span><span class="n">concurrent_measurement</span><span class="o">.</span><span class="n">to_s</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">cm</span><span class="o">|</span>
</span></span><span class="line"><span class="cl">      <span class="sr">/\((.*?)\)/</span><span class="o">.</span><span class="n">match</span><span class="p">(</span><span class="n">sequential_measurement</span><span class="o">.</span><span class="n">to_s</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">sm</span><span class="o">|</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># expected for the concurrent version to be close to 10 times faster than sequential</span>
</span></span><span class="line"><span class="cl">        <span class="n">expect</span><span class="p">(</span><span class="n">sm</span><span class="o">[</span><span class="mi">1</span><span class="o">].</span><span class="n">to_f</span><span class="p">)</span><span class="o">.</span><span class="n">to</span> <span class="n">be</span> <span class="o">&gt;</span> <span class="p">(</span> <span class="n">cm</span><span class="o">[</span><span class="mi">1</span><span class="o">].</span><span class="n">to_f</span> <span class="o">*</span> <span class="mi">9</span> <span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="k">end</span>
</span></span><span class="line"><span class="cl">    <span class="k">end</span>
</span></span><span class="line"><span class="cl">  <span class="k">ensure</span>
</span></span><span class="line"><span class="cl">    <span class="no">WebMock</span><span class="o">.</span><span class="n">disable_net_connect!</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Because it uses WebMock, I first disable it during this spec. I create a fake collection of 10 real links to MangaReader. And then I benchmark the Thread-based concurrent version and the plain sequential version. Because we have 10 links and they are all the same you can assume that the sequential version will be almost <strong>10 times slower</strong> than the Thread-based version. And this is exactly what this spec compares and proves (the spec fails if the concurrent version is not at least 9x faster).</p>
<p>To compare all versions of the Manga Downloadrs I let it download and compile an entire manga collection, in this case &ldquo;One-Punch Man&rdquo;, which has almost <strong>1,900 pages/images</strong>. I am just measuring the fetching and scraping processes and skipping the actual image downloading, image resizing and PDF generation as they take the majority of the time and the resizing and PDF part are all done by ImageMagick&rsquo;s mogrify and convert tools.</p>
<p>This is how long this new Ruby version takes to fetch and scrape almost 1,900 pages (using MRI Ruby 2.3.1):</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>12,42s user 1,33s system 23% cpu 57,675 total</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>This is how long the Crystal version takes:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>4,03s user 0,40s system 7% cpu 59,207 total</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Just for fun I tried to run the Ruby version under JRuby 9.1.1.0. To run with JRuby just add the following line in the <code>Gemfile</code>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="n">ruby</span> <span class="s2">&#34;2.3.0&#34;</span><span class="p">,</span> <span class="ss">:engine</span> <span class="o">=&gt;</span> <span class="s1">&#39;jruby&#39;</span><span class="p">,</span> <span class="ss">:engine_version</span> <span class="o">=&gt;</span> <span class="s1">&#39;9.1.1.0&#39;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Bundle install, run normally, and this is the result:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>47,80s user 1,99s system 108% cpu 45,967 total</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>And this is how long the Elixir version takes:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>11,38s user 1,04s system 85% cpu 14,590 total</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<h3>Reality Check!<span class="hx:absolute hx:-mt-20" id="reality-check"></span>
    <a href="#reality-check" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>If you just look at the times above you might come to the wrong conclusions.</p>
<p>First of all, it&rsquo;s an <strong>unfair comparison</strong>. The Elixir version uses a very different algorithm than the Ruby and Crystal versions.</p>
<p>In Elixir I boot up a pool of processes, around 50 of them. Then I start 50 HTTP requests at once. Once each process finishes, it releases itself back to the pool and I can fire up another HTTP request from the queue of links. So it&rsquo;s a <strong>constant stream</strong> of at most 50 HTTP requests, constantly.</p>
<p>The Crystal and Ruby/JRuby versions slice the 1,900 links into batches of 40 links and then I fire up 40 requests at once. This implementation waits for all 40 to finish and they fire up another 40. So it&rsquo;s never a constant stream, it&rsquo;s bursts of 40 requests. So each batch is slowed down by the slowest request in the batch, not giving a chance for other requests to go through.</p>
<p>It&rsquo;s a difference in architecture. Elixir makes it much easier to do streams and Crystal, with its CSP style, makes it easier to do bursts. A better approach would be to queue up the 1,900 links and use something like Sidekiq.cr to go over one link at a time (spawning 40 fibers to serve as a &ldquo;pool&rdquo;, for example).</p>
<p>The Elixir version has a more efficient architecture, which is why it takes no more than 15 seconds to fetch all the image links while the Crystal version takes almost a full minute to finish (the accumulation of the slowest requests in each batch).</p>
<p>Now, you will be surprised that the Crystal version is actually a bit slower than the Ruby version! And you won&rsquo;t be too surprised to see JRuby being faster at 45 seconds!</p>
<p>This is more evidence that you should not dismiss Ruby (and that you should try JRuby more often). As I explained before, it does support concurrency in I/O operations and the applications I tested are all I/O heavy.</p>
<p>The difference is probably in the maturity of Ruby&rsquo;s <code>Net::HTTP</code> library against Crystal&rsquo;s <code>HTTP::Client</code>. I tried many tweaks in the Crystal version but I couldn&rsquo;t get much faster. I tried to do larger batches, but for some reason the application just hangs, pauses, and never releases. I have to Ctrl-C out of it and retry until it finally goes through. If someone knows what I am doing wrong, please don&rsquo;t forget to write in the comments section below.</p>
<p>Some of this is probably due to MangaReader&rsquo;s unreliable servers, they probably have some kind of DoS protection, throttling connections or something like this.</p>
<p>Anyway, when they go through, because the Ruby and Crystal algorithms are essentially the same, they take roughly the same time to complete. So what&rsquo;s missing is for me to evolve this algorithm to either use something like Sidekiq or implement an internal queue/pool of workers scheme.</p>
<h3>Conclusion<span class="hx:absolute hx:-mt-20" id="conclusion"></span>
    <a href="#conclusion" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>The goal of this experiment was to learn more of Crystal&rsquo;s ability and how easy it would be to go back and forth with Ruby.</p>
<p>As you can see, there are many differences, but it&rsquo;s not so difficult. I may be missing something, but I stumbled upon some difficulties when pushing <code>HTTP::Client</code> + Fibers too hard, as I explained above. If you know what I am doing wrong, please let me know.</p>
<p>The difference between the Elixir vs Ruby/Crystal algorithms shows not just language performance differences, but also the importance of architecture and algorithms in the overall performance. This test was not conclusive, just a hint that my naive Fibers implementation needs some more work, and that Elixir&rsquo;s natural handling of parallel processes makes it easier to achieve higher levels of parallelism.</p>
<p>This serves as a taste of what Crystal can do, and also that Ruby is still in the game. But also that Elixir surely is something to look at closely.</p>
]]></content:encoded><category>anime-and-manga</category><category>programming-languages</category><category>ruby</category></item><item><title>Small Experiment with Rails over JRuby 9.x on Heroku</title><link>https://akitaonrails.github.io/en/2016/06/03/small-experiment-with-rails-over-jruby-9-x-on-heroku/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2016/06/03/small-experiment-with-rails-over-jruby-9-x-on-heroku/</guid><pubDate>Fri, 03 Jun 2016 18:12:00 -0300</pubDate><description>&lt;p&gt;After playing around with languages different than Ruby (such as &lt;a href="https://akitaonrails.github.io/elixir"&gt;Elixir&lt;/a&gt; or &lt;a href="https://akitaonrails.github.io/crystal"&gt;Crystal&lt;/a&gt;), it was time to go back to Ruby and see how JRuby is performing nowadays.&lt;/p&gt;
&lt;p&gt;JRuby always pursued the goal of being a competent MRI replacement. If you have not followed what&amp;rsquo;s going on, JRuby changed version schemes when they switched from the 1.7 series to the 9.x series. You should read this blog post that explains it.&lt;/p&gt;
&lt;p&gt;In summary, if you want MRI 2.2 compatibility you must use JRuby 9.0.x and if you want MRI 2.3 compatibility you must use the JRuby 9.1.x series. The most current release being 9.1.2.0. Anything prior to that you can refer to this &lt;a href="https://devcenter.heroku.com/articles/ruby-support#ruby-versions"target="_blank" rel="noopener"&gt;table of versions&lt;/a&gt; from Heroku&amp;rsquo;s documentation.&lt;/p&gt;</description><content:encoded><![CDATA[<p>After playing around with languages different than Ruby (such as <a href="/elixir">Elixir</a> or <a href="/crystal">Crystal</a>), it was time to go back to Ruby and see how JRuby is performing nowadays.</p>
<p>JRuby always pursued the goal of being a competent MRI replacement. If you have not followed what&rsquo;s going on, JRuby changed version schemes when they switched from the 1.7 series to the 9.x series. You should read this blog post that explains it.</p>
<p>In summary, if you want MRI 2.2 compatibility you must use JRuby 9.0.x and if you want MRI 2.3 compatibility you must use the JRuby 9.1.x series. The most current release being 9.1.2.0. Anything prior to that you can refer to this <a href="https://devcenter.heroku.com/articles/ruby-support#ruby-versions"target="_blank" rel="noopener">table of versions</a> from Heroku&rsquo;s documentation.</p>
<p>There are important recommendations as well:</p>
<ul>
<li>
<p>Ideally you should use Rails 4.2. Try to be at least above 4.0, and you can turn on <code>config.threadsafe!</code> by default in the &ldquo;config/environments/production.rb&rdquo; file. To understand this subject, refer to <a href="http://tenderlovemaking.com/2012/06/18/removing-config-threadsafe.html"target="_blank" rel="noopener">Tenderlove&rsquo;s excellent explanation</a>.</p>
</li>
<li>
<p>If you&rsquo;re deploying to Heroku, don&rsquo;t bother trying the free or 1X dyno, which only gives you 512Mb of RAM. While it is enough for most small Rails applications (even with 2 or 3 Puma concurrent workers), I found that even the smallest apps can easily go above that. So you must consider at least the 2X dyno. In any server configuration, always consider more than 1Gb of RAM.</p>
</li>
</ul>
<h3>Gems<span class="hx:absolute hx:-mt-20" id="gems"></span>
    <a href="#gems" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>There are several gems with C extensions that just won&rsquo;t work. Some of them have drop-in replacements, some don&rsquo;t. You should refer to <a href="https://github.com/jruby/jruby/wiki/C-Extension-Alternatives"target="_blank" rel="noopener">their Wiki</a> for a list of cases.</p>
<p>In my small sample application - which is nothing more than a content website backed by a Postgresql database, ActiveAdmin to manage content, RMagick + Paperclip (yes, it&rsquo;s an old app) to handle image upload and resizing, there was not a lot to change. The important bits of my &ldquo;Gemfile&rdquo; end up looking like this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="n">source</span> <span class="s1">&#39;https://rubygems.org&#39;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">ruby</span> <span class="s1">&#39;2.3.0&#39;</span><span class="p">,</span> <span class="ss">:engine</span> <span class="o">=&gt;</span> <span class="s1">&#39;jruby&#39;</span><span class="p">,</span> <span class="ss">:engine_version</span> <span class="o">=&gt;</span> <span class="s1">&#39;9.1.1.0&#39;</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ruby &#39;2.3.1&#39;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">gem</span> <span class="s1">&#39;rails&#39;</span><span class="p">,</span> <span class="s1">&#39;~&gt; 4.2.6&#39;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">gem</span> <span class="s1">&#39;devise&#39;</span>
</span></span><span class="line"><span class="cl"><span class="n">gem</span> <span class="s1">&#39;haml&#39;</span>
</span></span><span class="line"><span class="cl"><span class="n">gem</span> <span class="s1">&#39;puma&#39;</span>
</span></span><span class="line"><span class="cl"><span class="n">gem</span> <span class="s1">&#39;rack-attack&#39;</span>
</span></span><span class="line"><span class="cl"><span class="n">gem</span> <span class="s1">&#39;rack-timeout&#39;</span>
</span></span><span class="line"><span class="cl"><span class="n">gem</span> <span class="s1">&#39;rakismet&#39;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Database</span>
</span></span><span class="line"><span class="cl"><span class="n">gem</span> <span class="s1">&#39;pg&#39;</span><span class="p">,</span> <span class="ss">platforms</span><span class="p">:</span> <span class="ss">:ruby</span>
</span></span><span class="line"><span class="cl"><span class="n">gem</span> <span class="s1">&#39;activerecord-jdbcpostgresql-adapter&#39;</span><span class="p">,</span> <span class="ss">platforms</span><span class="p">:</span> <span class="ss">:jruby</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Cache</span>
</span></span><span class="line"><span class="cl"><span class="n">gem</span> <span class="s1">&#39;dalli&#39;</span>
</span></span><span class="line"><span class="cl"><span class="n">gem</span> <span class="s2">&#34;actionpack-action_caching&#34;</span><span class="p">,</span> <span class="ss">github</span><span class="p">:</span> <span class="s2">&#34;rails/actionpack-action_caching&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Admin</span>
</span></span><span class="line"><span class="cl"><span class="n">gem</span> <span class="s1">&#39;activeadmin&#39;</span><span class="p">,</span> <span class="ss">github</span><span class="p">:</span> <span class="s1">&#39;activeadmin&#39;</span>
</span></span><span class="line"><span class="cl"><span class="n">gem</span> <span class="s1">&#39;active_skin&#39;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Assets</span>
</span></span><span class="line"><span class="cl"><span class="n">gem</span> <span class="s1">&#39;therubyracer&#39;</span><span class="p">,</span> <span class="ss">platforms</span><span class="p">:</span> <span class="ss">:ruby</span>
</span></span><span class="line"><span class="cl"><span class="n">gem</span> <span class="s1">&#39;therubyrhino&#39;</span><span class="p">,</span> <span class="ss">platforms</span><span class="p">:</span> <span class="ss">:jruby</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">gem</span> <span class="s1">&#39;asset_sync&#39;</span>
</span></span><span class="line"><span class="cl"><span class="n">gem</span> <span class="s1">&#39;jquery-ui-rails&#39;</span>
</span></span><span class="line"><span class="cl"><span class="n">gem</span> <span class="s1">&#39;sass-rails&#39;</span>
</span></span><span class="line"><span class="cl"><span class="n">gem</span> <span class="s1">&#39;uglifier&#39;</span><span class="p">,</span>     <span class="s1">&#39;&gt;= 1.3.0&#39;</span>
</span></span><span class="line"><span class="cl"><span class="n">gem</span> <span class="s1">&#39;coffee-rails&#39;</span><span class="p">,</span> <span class="s1">&#39;~&gt; 4.0.0&#39;</span>
</span></span><span class="line"><span class="cl"><span class="n">gem</span> <span class="s1">&#39;compass-rails&#39;</span>
</span></span><span class="line"><span class="cl"><span class="n">gem</span> <span class="s1">&#39;sprockets&#39;</span><span class="p">,</span> <span class="s1">&#39;~&gt;2.11.0&#39;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Image Processing</span>
</span></span><span class="line"><span class="cl"><span class="n">gem</span> <span class="s1">&#39;paperclip&#39;</span>
</span></span><span class="line"><span class="cl"><span class="n">gem</span> <span class="s1">&#39;fog&#39;</span>
</span></span><span class="line"><span class="cl"><span class="n">gem</span> <span class="s1">&#39;rmagick&#39;</span><span class="p">,</span> <span class="ss">platforms</span><span class="p">:</span> <span class="ss">:ruby</span>
</span></span><span class="line"><span class="cl"><span class="n">gem</span> <span class="s1">&#39;rmagick4j&#39;</span><span class="p">,</span> <span class="ss">platforms</span><span class="p">:</span> <span class="ss">:jruby</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">group</span> <span class="ss">:test</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">  <span class="n">gem</span> <span class="s1">&#39;shoulda-matchers&#39;</span><span class="p">,</span> <span class="nb">require</span><span class="p">:</span> <span class="kp">false</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">group</span> <span class="ss">:test</span><span class="p">,</span> <span class="ss">:development</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">  <span class="n">gem</span> <span class="s2">&#34;sqlite3&#34;</span><span class="p">,</span> <span class="ss">platforms</span><span class="p">:</span> <span class="ss">:ruby</span>
</span></span><span class="line"><span class="cl">  <span class="n">gem</span> <span class="s2">&#34;activerecord-jdbcsqlite3-adapter&#34;</span><span class="p">,</span> <span class="ss">platforms</span><span class="p">:</span> <span class="ss">:jruby</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># Pretty printed test output</span>
</span></span><span class="line"><span class="cl">  <span class="n">gem</span> <span class="s1">&#39;turn&#39;</span><span class="p">,</span> <span class="nb">require</span><span class="p">:</span> <span class="kp">false</span>
</span></span><span class="line"><span class="cl">  <span class="n">gem</span> <span class="s1">&#39;jasmine&#39;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="n">gem</span> <span class="s1">&#39;pry-rails&#39;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="n">gem</span> <span class="s1">&#39;rspec&#39;</span>
</span></span><span class="line"><span class="cl">  <span class="n">gem</span> <span class="s1">&#39;rspec-rails&#39;</span>
</span></span><span class="line"><span class="cl">  <span class="n">gem</span> <span class="s1">&#39;capybara&#39;</span>
</span></span><span class="line"><span class="cl">  <span class="n">gem</span> <span class="s1">&#39;poltergeist&#39;</span>
</span></span><span class="line"><span class="cl">  <span class="n">gem</span> <span class="s1">&#39;database_cleaner&#39;</span><span class="p">,</span> <span class="s1">&#39;&lt; 1.1.0&#39;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="n">gem</span> <span class="s1">&#39;letter_opener&#39;</span>
</span></span><span class="line"><span class="cl">  <span class="n">gem</span> <span class="s1">&#39;dotenv-rails&#39;</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">group</span> <span class="ss">:production</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">  <span class="n">gem</span> <span class="s1">&#39;rails_12factor&#39;</span>
</span></span><span class="line"><span class="cl">  <span class="n">gem</span> <span class="s1">&#39;rack-cache&#39;</span><span class="p">,</span> <span class="nb">require</span><span class="p">:</span> <span class="s1">&#39;rack/cache&#39;</span>
</span></span><span class="line"><span class="cl">  <span class="n">gem</span> <span class="s1">&#39;memcachier&#39;</span>
</span></span><span class="line"><span class="cl">  <span class="n">gem</span> <span class="s1">&#39;newrelic_rpm&#39;</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Notice how I paired gems for the <code>:ruby</code> and <code>:jruby</code> platforms. After doing this change and <code>bundle install</code> everything, I ran my Rspec suite and - fortunately - they all passed on the first run without any further changes! Your mileage will vary depending on the complexity of your application, so have your tests ready.</p>
<h3>Puma<span class="hx:absolute hx:-mt-20" id="puma"></span>
    <a href="#puma" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>In the case of Puma, the configuration is a bit trickier, mine looks like this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="n">web_concurrency</span> <span class="o">=</span> <span class="nb">Integer</span><span class="p">(</span><span class="no">ENV</span><span class="o">[</span><span class="s1">&#39;WEB_CONCURRENCY&#39;</span><span class="o">]</span> <span class="o">||</span> <span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="n">web_concurrency</span> <span class="o">&gt;</span> <span class="mi">1</span>
</span></span><span class="line"><span class="cl">  <span class="n">workers</span> <span class="n">web_concurrency</span>
</span></span><span class="line"><span class="cl">  <span class="n">preload_app!</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">threads_count</span> <span class="o">=</span> <span class="nb">Integer</span><span class="p">(</span><span class="no">ENV</span><span class="o">[</span><span class="s1">&#39;RAILS_MAX_THREADS&#39;</span><span class="o">]</span> <span class="o">||</span> <span class="mi">5</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">threads</span> <span class="n">threads_count</span><span class="p">,</span> <span class="n">threads_count</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">rackup</span>      <span class="no">DefaultRackup</span>
</span></span><span class="line"><span class="cl"><span class="n">port</span>        <span class="no">ENV</span><span class="o">[</span><span class="s1">&#39;PORT&#39;</span><span class="o">]</span>     <span class="o">||</span> <span class="mi">3000</span>
</span></span><span class="line"><span class="cl"><span class="n">environment</span> <span class="no">ENV</span><span class="o">[</span><span class="s1">&#39;RACK_ENV&#39;</span><span class="o">]</span> <span class="o">||</span> <span class="s1">&#39;development&#39;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">on_worker_boot</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">  <span class="c1"># Worker specific setup for Rails 4.1+</span>
</span></span><span class="line"><span class="cl">  <span class="c1"># See: https://devcenter.heroku.com/articles/deploying-rails-applications-with-the-puma-web-server#on-worker-boot</span>
</span></span><span class="line"><span class="cl">  <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Base</span><span class="o">.</span><span class="n">establish_connection</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>It&rsquo;s a bit different from what you might find in other documentation. The important part is to turn off workers and preload_app when loading over JRuby. Otherwise it will complain and crash. On my original MRI deploy I am using a small 1X dyno and I can leave <code>WEB_CONCURRENCY=2</code> and <code>RAILS_MAX_THREADS=5</code> but on the JRuby deploy I set it to <code>WEB_CONCURRENCY=1</code> (to turn off workers) and <code>RAILS_MAX_THREADS=16</code> (because I am assuming JRuby can handle more multithreading than MRI).</p>
<p>Another important bit: most people still assume that MRI can&rsquo;t take advantage of native parallel threads at all because of the dreaded GIL (Global Interpreter Lock), but that&rsquo;s only half true. MRI Ruby can parallelize threads on I/O waits. So, if a part of your app is waiting for the database to process and return rows, for example, another thread can take over and do something else, in parallel. There is some concurrency available, even if limited, so setting a small amount of threads for Puma might help a bit.</p>
<p>Do not forget to set the Pool size to at least the same number of <code>RAILS_MAX_THREADS</code>. You can either use the <code>config/database.yml</code> for Rails 4.1+ or add an initializer. Follow <a href="https://devcenter.heroku.com/articles/concurrency-and-database-connections#threaded-servers"target="_blank" rel="noopener">Heroku&rsquo;s documentation</a> on how to do so.</p>
<h3>Initial Benchmarks<span class="hx:absolute hx:-mt-20" id="initial-benchmarks"></span>
    <a href="#initial-benchmarks" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>So, I was able to successfully deploy a secondary JRuby version of my original MRI-based Rails app.</p>
<p>The original app is still in a Hobby Dyno, sized at 512Mb of RAM. The secondary app needed a Standard 1X Dyno, sized at 1Gb of RAM.</p>
<p>The app itself is super simple and as I&rsquo;m using caching - <a href="http://www.akitaonrails.com/2015/05/20/dynamic-site-as-fast-as-a-static-generated-one-with-raptor"target="_blank" rel="noopener">as you always should!</a> -, the response time is very low, on the tens of milliseconds.</p>
<p>I tried to use the <a href="https://github.com/rakyll/boom"target="_blank" rel="noopener">Boom</a> tool to benchmark the requests. I did a lot of warming up on the JRuby version, running the benchmarks multiple times and even using Loader.io for added pressure.</p>
<p>I am running this test:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>$ boom -n 200 -c 50 http://foo-my-site/</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>The MRI version performs like this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>Summary:
  Total:    16.4254 secs
  Slowest:  9.0785 secs
  Fastest:  0.8362 secs
  Average:  2.6551 secs
  Requests/sec: 12.1763
  Total data:   28837306 bytes
  Size/request: 144186 bytes

Status code distribution:
  [200] 200 responses

Response time histogram:
  0.836 [1] |
  1.660 [57]    |∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎
  2.485 [57]    |∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎
  3.309 [33]    |∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎
  4.133 [22]    |∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎
  4.957 [16]    |∎∎∎∎∎∎∎∎∎∎∎
  5.782 [6] |∎∎∎∎
  6.606 [3] |∎∎
  7.430 [1] |
  8.254 [3] |∎∎
  9.079 [1] |

Latency distribution:
  10% in 1.2391 secs
  25% in 1.5910 secs
  50% in 2.1974 secs
  75% in 3.4327 secs
  90% in 4.5580 secs
  95% in 5.6727 secs
  99% in 8.1567 secs</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>And the JRuby version performs like this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>Summary:
  Total:    15.5784 secs
  Slowest:  7.4106 secs
  Fastest:  0.5770 secs
  Average:  2.3224 secs
  Requests/sec: 12.8383
  Total data:   28848475 bytes
  Size/request: 144242 bytes

Status code distribution:
  [200] 200 responses

Response time histogram:
  0.577 [1] |
  1.260 [23]    |∎∎∎∎∎∎∎∎∎∎∎∎∎∎
  1.944 [62]    |∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎
  2.627 [51]    |∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎
  3.310 [24]    |∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎
  3.994 [26]    |∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎
  4.677 [8] |∎∎∎∎∎
  5.361 [1] |
  6.044 [0] |
  6.727 [1] |
  7.411 [3] |∎

Latency distribution:
  10% in 1.1599 secs
  25% in 1.5154 secs
  50% in 2.0781 secs
  75% in 2.8909 secs
  90% in 3.7409 secs
  95% in 4.2556 secs
  99% in 6.7685 secs</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>In general, I&rsquo;d say that they are around the same. As this is not a particularly CPU-intensive processing, and most of the time is spent going through the Rails stack and hitting Memcachier to pull back the same content all the time, maybe it&rsquo;s only fair to expect similar results.</p>
<p>On the other hand, I&rsquo;m not sure I&rsquo;m using the tool in the best way possible. The log says something like this for every request:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>source=rack-timeout id=c8ad5f0c-b5c1-47ec-b88b-3fc597ab01dc wait=29ms timeout=20000ms state=ready
Started GET &#34;/&#34; for XXX.35.10.XXX at 2016-06-03 18:54:34 &#43;0000
Processing by HomeController#home as HTML
Read fragment views/radiant-XXXX-XXXXX.herokuapp.com/en (6.0ms)
Completed 200 OK in 8ms (ActiveRecord: 0.0ms)
source=rack-timeout id=c8ad5f0c-b5c1-47ec-b88b-3fc597ab01dc wait=29ms timeout=20000ms service=19ms state=completed
source=rack-timeout id=a5389dc4-9a1a-46b7-a1e5-53f334ca0941 wait=35ms timeout=20000ms state=ready

Started GET &#34;/&#34; for XXX.35.10.XXX at 2016-06-03 18:54:36 &#43;0000
Processing by HomeController#home as HTML
Read fragment views/radiant-XXXX-XXXXX.herokuapp.com/en (6.0ms)
Completed 200 OK in 9ms (ActiveRecord: 0.0ms)
source=rack-timeout id=a5389dc4-9a1a-46b7-a1e5-53f334ca0941 wait=35ms timeout=20000ms service=21ms state=completed
at=info method=GET path=&#34;/&#34; host=radiant-XXXX-XXXXX.herokuapp.com request_id=a5389dc4-9a1a-46b7-a1e5-53f334ca0941 fwd=&#34;XXX.35.10.XXX&#34; dyno=web.1 connect=1ms service=38ms status=200 bytes=144608</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>The times reported by the Boom tool are much larger (2 seconds?) than the processing times in the logs (10ms?). Even considering some overhead for the router and so on, it&rsquo;s still a big difference. I wonder if requests are being queued for too long because the app isn&rsquo;t able to respond to more of the concurrent requests.</p>
<p>The amount of requests divided by the number of concurrent connections will bring the overall performance and throughput down if you increase it too much, I wasn&rsquo;t able to go much above 14 rpm with this configuration, though.</p>
<p>If you have more experience with http benchmarking and you can spot something wrong I am doing here, please let me know in the comments section below.</p>
<h3>Conclusion<span class="hx:absolute hx:-mt-20" id="conclusion"></span>
    <a href="#conclusion" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>JRuby continues to evolve, and you might benefit if you already have a large set of Dynos or large servers around. I wouldn&rsquo;t recommend it for small to medium applications.</p>
<p>I&rsquo;ve seen many orders of magnitude improvements in specific use cases (I believe it was a very high traffic API endpoint). This particular case I tested is probably not its sweet spot and changing from MRI to JRuby didn&rsquo;t give me too much advantage, so in this case I would recommend sticking to MRI.</p>
<p>Startup time is still an issue. There is an entry in <a href="https://github.com/jruby/jruby/wiki/Improving-startup-time"target="_blank" rel="noopener">their Wiki</a> giving some recommendations, but even in the Heroku deploy I ended up having R10 errors (Boot Timeout) every once in a while for this small app.</p>
<p>I didn&rsquo;t try increasing the dynos to the <a href="https://blog.heroku.com/archives/2015/8/20/introducing-improved-performance-dynos"target="_blank" rel="noopener">Performance tier</a> introduced last year. I would bet that JRuby would be better at those and more able to leverage the extra power of having from 2.5GB up to 14GB if you have really big traffic (on the order of thousands or tens of thousands of requests per minute). With MRI the recommendation would be using small-ish dynos (2X or at most Performance-M dynos) and scale horizontally. With JRuby you could have fewer dynos with larger sizes (Performance-L, for example). Again, depends on your case.</p>
<p>Don&rsquo;t take the benchmarks above as &ldquo;facts&rdquo; to generalize everywhere, they are just there to give you a notion of a specific use case of mine. Your mileage will vary, so you must test it out yourself.</p>
<p>Another use case (that I did not test) is, instead of just &ldquo;porting&rdquo; an MRI app to JRuby, leveraging JRuby&rsquo;s unique strengths as <a href="https://blog.heroku.com/archives/2016/5/24/reactive_ruby_building_real_time_apps_with_jruby_and_ratpack"target="_blank" rel="noopener">this post</a> from Heroku explains, in the case of using JRuby with Ratpack, for example.</p>
<p>All in all, JRuby is still a great project to experiment with. MRI itself has come a long way as well and 2.3.1 is quite decent. Most of the time it&rsquo;s down to your overall architecture choices, and the language is just one piece of the puzzle. If you didn&rsquo;t try it yet, you definitely should. It &ldquo;just works&rdquo;.</p>
]]></content:encoded><category>rails</category><category>performance</category><category>ruby</category></item><item><title>Flirting with Crystal, a Rubyist Perspective</title><link>https://akitaonrails.github.io/en/2016/05/31/flirting-with-crystal-a-rubyist-perspective/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2016/05/31/flirting-with-crystal-a-rubyist-perspective/</guid><pubDate>Tue, 31 May 2016 18:21:00 -0300</pubDate><description>&lt;p&gt;If you&amp;rsquo;re following me you will see that I have been sidetracking to &lt;a href="https://akitaonrails.github.io/elixir"&gt;Elixir&lt;/a&gt; recently. I will write a big introduction before diving into Crystal, so bear with me.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ll say that Erlang OTP and its internals intrigue me more than just the novelty of the language syntax. I believe that if you want to build highly distributed and also highly reliable systems you will either use Erlang (through Elixir) or you will end up replicating most of what Erlang already has with OTP.&lt;/p&gt;</description><content:encoded><![CDATA[<p>If you&rsquo;re following me you will see that I have been sidetracking to <a href="/elixir">Elixir</a> recently. I will write a big introduction before diving into Crystal, so bear with me.</p>
<p>I&rsquo;ll say that Erlang OTP and its internals intrigue me more than just the novelty of the language syntax. I believe that if you want to build highly distributed and also highly reliable systems you will either use Erlang (through Elixir) or you will end up replicating most of what Erlang already has with OTP.</p>
<p>This is true if you see that there are many Java/Scala-based distributed systems such as Hadoop, Spark, Cassandra, and they all could have benefitted from Erlang&rsquo;s OTP architecture. On the other hand, if you follow Cassandra you will see that even Java still has a hard time competing with C++ if you compare the clone called <a href="http://www.scylladb.com/"target="_blank" rel="noopener">ScyllaDB</a>.</p>
<p>I believe Elixir (perhaps with HiPE) can compete in the same league as Java for distributed systems, avoiding people leaving the Erlang platform for C or Java as <a href="https://www.infoq.com/news/2012/01/Katz-CouchDB-Couchbase-Server"target="_blank" rel="noopener">happened with CouchDB</a> back in 2012 because of lack of interest and exotic syntax. And because Java already has a big ecosystem, Clojure is in the game primarily because it can interface directly with it.</p>
<p>I think Go is also a Java contender but for other use cases, particularly in the systems tools space where you have lots of C/C++ and also glue code in Perl and Python. An obvious example being Docker orchestration. Yes, you can do microservices, crawlers and other stuff but I am not so keen to build big &ldquo;applications&rdquo; in it, although there is nothing preventing it. Again, it&rsquo;s just a personal opinion.</p>
<p>Rust is a big contender to low-level systems development. I think it can replace C in many use cases and be used to implement libraries and components to be used by other languages, with the added benefits of a modern language that tries to avoid security hazards such as the recent <a href="https://tonyarcieri.com/would-rust-have-prevented-heartbleed-another-look"target="_blank" rel="noopener">Heartbleed debacle</a>. But because of its &ldquo;Borrow system&rdquo; I find it extremely bureaucratic, especially if you&rsquo;re coming from highly dynamic languages such as Ruby, Python or even Swift or Elixir. I&rsquo;m not saying it&rsquo;s a bad thing, just something that takes way more time to become comfortable with than I expected.</p>
<p>Crystal is something between Rust and Go. LLVM is something you must have on your radar, because of <a href="http://appleinsider.com/articles/08/06/20/apples_other_open_secret_the_llvm_complier"target="_blank" rel="noopener">Apple&rsquo;s support</a> towards Swift it&rsquo;s better than ever. Crystal is <em>similar</em> to RubyMotion in terms of both being similar to Ruby but not fully compatible and both being front-end parsers to LLVM. RubyMotion, on the other hand, is closer to Ruby and can even use some Ruby libraries almost without changes.</p>
<p>You do have to take your hats off to Ary Borenszweig and his contributors. It&rsquo;s very impressive how far they got in such a short period of time and without having deep pockets from Mozilla, Apple or Google.</p>
<h3>Limitations<span class="hx:absolute hx:-mt-20" id="limitations"></span>
    <a href="#limitations" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Crystal borrows heavily from Ruby but it&rsquo;s not a goal to reach any level of compatibility. It&rsquo;s a strong, statically typed language with Type Inference. It does not have any runtime component such as RubyMotion or Swift, so it has no notion of introspection or reflection over objects.</p>
<p>Mainly, you have neither &ldquo;#eval&rdquo; nor &ldquo;#send&rdquo;. The lack of runtime evaluation is not so bad as you do have compilation-time AST manipulation through a good enough system of Macros (more on that later).</p>
<p>But the lack of &ldquo;#send&rdquo; does hurt a bit. It&rsquo;s the one thing that makes Crystal further away from Ruby&rsquo;s dynamic object flexibility. But it&rsquo;s also understandable why it&rsquo;s not a priority to have it.</p>
<p>As of version 0.17.0, Crystal has one huge limitation: it&rsquo;s using a <a href="http://crystal-lang.org/2013/12/05/garbage-collector.html"target="_blank" rel="noopener">Boehm-Demers-Weiser conservative garbage collector</a>.</p>
<blockquote class="twitter-tweet" data-lang="en"><p lang="en" dir="ltr"><a href="https://twitter.com/asterite">@asterite</a> <a href="https://twitter.com/headius">@headius</a> I assumed as much... the Boehm GC, although handy for starting a new language, will only get you so far</p>&mdash; Jason Frey (@Fryguy9) <a href="https://twitter.com/Fryguy9/status/736990644082757632">May 29, 2016</a></blockquote>
<p>The language is currently implemented as a single-threaded process. This means that you <em>probably</em> can&rsquo;t max out all CPUs of your machine with just a single process. Although I may be wrong here, it&rsquo;s just my first impressions.</p>
<p>Charles Nutter (from JRuby fame) gives a warning about this:</p>
<blockquote class="twitter-tweet" data-lang="en"><p lang="en" dir="ltr"><a href="https://twitter.com/Fryguy9">@fryguy9</a> From their site: <a href="https://t.co/uOjIT0c8ji">https://t.co/uOjIT0c8ji</a> It does say something about "when" parallelism happens. Risky to start single-threaded.</p>&mdash; Charles Nutter (@headius) <a href="https://twitter.com/headius/status/736982955239870464">May 29, 2016</a></blockquote>
<p>It&rsquo;s a double-edged sword. Using a &ldquo;generic&rdquo; plug-and-play GC such as Boehm - which is not a bad thing in itself, but it&rsquo;s possibly not nearly as powerful as the JVM&rsquo;s own set of high performance GC such as the brand new G1GC.</p>
<p>Making the language single-threaded by default also means that the entire standard library and the whole ecosystem are built assuming there is no parallelism. So there are no race-conditions and hence, no usage of proper synchronization anywhere. If one day they decide to add multi-threading, all existing code will not be thread-safe. This is probably the meaning of Charles&rsquo; warning.</p>
<p>I don&rsquo;t think it&rsquo;s a pressing problem though. You probably won&rsquo;t have a highly parallel system built with Crystal but maybe it&rsquo;s not the use case. In that case you should be using Elixir + OTP, Scala + Akka, for example.</p>
<h3>Concurrency<span class="hx:absolute hx:-mt-20" id="concurrency"></span>
    <a href="#concurrency" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Not having access to native Threads doesn&rsquo;t mean that you can&rsquo;t have Concurrency. <a href="https://blog.golang.org/concurrency-is-not-parallelism"target="_blank" rel="noopener">Concurrency is not Parallelism</a>. Since <a href="http://crystal-lang.org/2015/04/30/crystal-0.7.0-released.html"target="_blank" rel="noopener">version 0.7.0</a> they have added support for non-blocking I/O and also Fibers and Channels.</p>
<p>In a nutshell, a Fiber is a special kind of coroutine. It&rsquo;s a &ldquo;piece of execution&rdquo; that can &ldquo;pause&rdquo; itself and yield control of the execution back to its caller. It can pause itself but it can&rsquo;t be paused from the outside like Erlang&rsquo;s Scheduler can pause its running processes, for example.</p>
<p>In this case we can have a &ldquo;Fiber Scheduler&rdquo; of sorts, that can &ldquo;resume&rdquo; other Fibers. It is currently single-threaded, of course. And it works as an Event Loop. Whenever you have a non-blocking I/O operation waiting for file reading, network packet sending and stuff like that, it can yield control back to other fibers to resume work.</p>
<p>This makes it work more or less like Node.js. Javascript is also a single-threaded language and Node.js is basically an implementation of an event loop. Functions declare other anonymous functions as callbacks and it works based on the I/O triggers to callback those functions on every tick of the reactor.</p>
<p>On top of that you can add <a href="https://github.com/crystal-lang/crystal/issues/1967"target="_blank" rel="noopener">&ldquo;Channels&rdquo;</a> as popularized by Google&rsquo;s Go language. You can start as many channels as you like. Then you can spawn Fibers in the Scheduler. Fibers can execute and keep sending messages through the Channels. Execution control is yielded to whoever is expecting to receive from the same Channels. Once one of them receives and executes, control is sent back to the Scheduler to allow other spawned Fibers to execute, and they can keep &ldquo;pinging&rdquo; and &ldquo;ponging&rdquo; like this.</p>
<p>Speaking of ping-pong, you have <a href="https://gobyexample.com/channel-directions"target="_blank" rel="noopener">this snippet in the &ldquo;Go by Example&rdquo;</a> site:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kn">package</span><span class="w"> </span><span class="nx">main</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kn">import</span><span class="w"> </span><span class="s">&#34;fmt&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kd">func</span><span class="w"> </span><span class="nf">ping</span><span class="p">(</span><span class="nx">pings</span><span class="w"> </span><span class="kd">chan</span><span class="o">&lt;-</span><span class="w"> </span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="nx">msg</span><span class="w"> </span><span class="kt">string</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nx">pings</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="nx">msg</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kd">func</span><span class="w"> </span><span class="nf">pong</span><span class="p">(</span><span class="nx">pings</span><span class="w"> </span><span class="o">&lt;-</span><span class="kd">chan</span><span class="w"> </span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="nx">pongs</span><span class="w"> </span><span class="kd">chan</span><span class="o">&lt;-</span><span class="w"> </span><span class="kt">string</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nx">msg</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="o">&lt;-</span><span class="nx">pings</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nx">pongs</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="nx">msg</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kd">func</span><span class="w"> </span><span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nx">pings</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nb">make</span><span class="p">(</span><span class="kd">chan</span><span class="w"> </span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nx">pongs</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nb">make</span><span class="p">(</span><span class="kd">chan</span><span class="w"> </span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nf">ping</span><span class="p">(</span><span class="nx">pings</span><span class="p">,</span><span class="w"> </span><span class="s">&#34;passed message&#34;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nf">pong</span><span class="p">(</span><span class="nx">pings</span><span class="p">,</span><span class="w"> </span><span class="nx">pongs</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="o">&lt;-</span><span class="nx">pongs</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>And this is mostly the same thing but implemented in Crystal:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">ping</span><span class="p">(</span><span class="n">pings</span><span class="p">,</span> <span class="n">message</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">pings</span><span class="o">.</span><span class="n">send</span> <span class="n">message</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">pong</span><span class="p">(</span><span class="n">pings</span><span class="p">,</span> <span class="n">pongs</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">message</span> <span class="o">=</span> <span class="n">pings</span><span class="o">.</span><span class="n">receive</span>
</span></span><span class="line"><span class="cl">  <span class="n">pongs</span><span class="o">.</span><span class="n">send</span> <span class="n">message</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">pings</span> <span class="o">=</span> <span class="no">Channel</span><span class="p">(</span><span class="nb">String</span><span class="p">)</span><span class="o">.</span><span class="n">new</span>
</span></span><span class="line"><span class="cl"><span class="n">pongs</span> <span class="o">=</span> <span class="no">Channel</span><span class="p">(</span><span class="nb">String</span><span class="p">)</span><span class="o">.</span><span class="n">new</span>
</span></span><span class="line"><span class="cl"><span class="n">spawn</span> <span class="n">ping</span> <span class="n">pings</span><span class="p">,</span> <span class="s2">&#34;passed message&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">spawn</span> <span class="n">pong</span> <span class="n">pings</span><span class="p">,</span> <span class="n">pongs</span>
</span></span><span class="line"><span class="cl"><span class="nb">puts</span> <span class="n">pongs</span><span class="o">.</span><span class="n">receive</span>
</span></span><span class="line"><span class="cl"><span class="c1"># =&gt; &#34;passed message&#34;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Same thing, but more pleasant to my eyes, again a personal opinion - which is expected if you&rsquo;re also a Rubyist.</p>
<p>So Crystal has Node.js/Javascript-like Event Loop in the form of a Fiber Scheduler and a Go-like Channel/CSP mechanism to coordinate concurrent processing. It&rsquo;s a &ldquo;cooperative multitasking&rdquo; mechanism. It&rsquo;s not good if you have CPU intensive processing, such as heavy number crunching, data processing. It works best for I/O intensive processing.</p>
<p>If you have a Fiber doing super heavy processing, it will block the Scheduler, as is also true for Node.js. The current implementation of the Scheduler is bound to a single native thread so it can&rsquo;t use other available native threads of the system for now.</p>
<p>Because the Channel implementation is quite new, it&rsquo;s not used throughout the standard library. But the standard implementation for <code>HTTP::Server</code> uses Fibers. And because it is compiled down to a native binary it&rsquo;s <strong>way faster</strong> than Javascript, as this <a href="https://github.com/sdogruyol/fast-http-server"target="_blank" rel="noopener">&ldquo;fast-http-server&rdquo;</a> shows:</p>
<ul>
<li>fast-http-server (Crystal)  18348.47rpm at 8.67ms avg. response time</li>
<li>http-server (Node.js)   2105.55rpm at 47.92ms avg. response time</li>
<li>SimpleHTTPServer (Python)   785.14rpm at 1.91ms avg. response time</li>
</ul>
<p>We&rsquo;re talking about an order of magnitude of 8 times faster than Node.js and more than 20 times faster than Python.</p>
<p>As usual, you shouldn&rsquo;t blindly trust <a href="https://github.com/kostya/benchmarks"target="_blank" rel="noopener">synthetic benchmarks</a> but depending on which kind of processing you decide to compare against, you will see Crystal being pretty on par with Rust, Go, Swift, D.</p>
<h3>Type Inference<span class="hx:absolute hx:-mt-20" id="type-inference"></span>
    <a href="#type-inference" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Crystal is a statically typed language. But it won&rsquo;t require you to declare every single type beforehand. It&rsquo;s quite smart in its Type Inference so if you just type:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="n">a</span> <span class="o">=</span> <span class="mi">1</span>
</span></span><span class="line"><span class="cl"><span class="n">b</span> <span class="o">=</span> <span class="s2">&#34;HELO&#34;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>It will know that &ldquo;a&rdquo; is an &ldquo;Int32&rdquo; and that &ldquo;b&rdquo; is a &ldquo;String&rdquo;. By the way, contrary to Ruby, all Strings must be double-quoted. But it becomes particularly more complicated when you&rsquo;re dealing with complicated data structures such as JSON.</p>
<p>In Ruby I can just parse a JSON String and immediately explore its structure like this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="n">parsed_json</span> <span class="o">=</span> <span class="no">JSON</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">body</span><span class="p">)</span><span class="o">[</span><span class="s2">&#34;files&#34;</span><span class="o">].</span><span class="n">first</span><span class="o">[</span><span class="s2">&#34;id&#34;</span><span class="o">]</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>I can&rsquo;t do this in Crystal, instead the <a href="http://crystal-lang.org/api/JSON.html#mapping%28properties%2Cstrict%3Dfalse%29-macro"target="_blank" rel="noopener">recommended approach</a> is to declare a schema-like structure like this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">FilesResponse</span>
</span></span><span class="line"><span class="cl">  <span class="no">JSON</span><span class="o">.</span><span class="n">mapping</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">    <span class="ss">ok</span><span class="p">:</span> <span class="p">{</span><span class="ss">type</span><span class="p">:</span> <span class="no">Bool</span><span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="ss">files</span><span class="p">:</span> <span class="p">{</span><span class="ss">type</span><span class="p">:</span> <span class="nb">Array</span><span class="p">(</span><span class="no">FilesItemResponse</span><span class="p">)}</span>
</span></span><span class="line"><span class="cl">  <span class="p">})</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span>
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">FilesItemResponse</span>
</span></span><span class="line"><span class="cl">  <span class="no">JSON</span><span class="o">.</span><span class="n">mapping</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">    <span class="nb">id</span><span class="p">:</span> <span class="p">{</span><span class="ss">type</span><span class="p">:</span> <span class="nb">String</span><span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nb">name</span><span class="p">:</span> <span class="p">{</span><span class="ss">type</span><span class="p">:</span> <span class="nb">String</span><span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="ss">filetype</span><span class="p">:</span> <span class="p">{</span><span class="ss">type</span><span class="p">:</span> <span class="nb">String</span><span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="ss">created</span><span class="p">:</span> <span class="p">{</span><span class="ss">type</span><span class="p">:</span> <span class="no">Time</span><span class="p">,</span> <span class="ss">converter</span><span class="p">:</span> <span class="no">Time</span><span class="o">::</span><span class="no">EpochConverter</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="ss">timestamp</span><span class="p">:</span> <span class="p">{</span><span class="ss">type</span><span class="p">:</span> <span class="no">Time</span><span class="p">,</span> <span class="ss">converter</span><span class="p">:</span> <span class="no">Time</span><span class="o">::</span><span class="no">EpochConverter</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="ss">permalink</span><span class="p">:</span> <span class="p">{</span><span class="ss">type</span><span class="p">:</span> <span class="nb">String</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">})</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span>
</span></span><span class="line"><span class="cl"><span class="o">...</span>
</span></span><span class="line"><span class="cl"><span class="c1"># parsed_json = JSON.parse(response.body)[&#34;files&#34;].first[&#34;id&#34;]</span>
</span></span><span class="line"><span class="cl"><span class="n">parsed_json</span> <span class="o">=</span> <span class="no">FilesResponse</span><span class="o">.</span><span class="n">from_json</span><span class="p">(</span><span class="vi">@body</span><span class="p">)</span><span class="o">.</span><span class="n">files</span><span class="o">.</span><span class="n">first</span><span class="o">.</span><span class="n">id</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>I am very used to Ruby&rsquo;s duck typing and the ability to query objects in runtime. It&rsquo;s just not the same in Crystal and it can be quite tedious to change your mindset to think about types beforehand. The compiler will scream a hell of a lot during your development cycle until you become acquainted with this concept.</p>
<p>I did an experiment with JSON parsing and the result is a project I called <a href="https://github.com/akitaonrails/cr_slack_cleanup"target="_blank" rel="noopener">&ldquo;cr_slack_cleanup&rdquo;</a> which showcases both this idea of JSON Schemas as well as Fibers and Channels as I explained in the previous section.</p>
<p>Update: after I posted this article @LuisLavena stepped in to correct me: you can do it like Ruby, without schemas:</p>
<blockquote class="twitter-tweet" data-partner="tweetdeck"><p lang="en" dir="ltr"><a href="https://twitter.com/AkitaOnRails">@AkitaOnRails</a> <a href="https://twitter.com/CrystalLanguage">@CrystalLanguage</a> re: JSON, you can parse it kinda-like Ruby, see JSON::Any: <a href="https://t.co/MD7PYy5AVH">https://t.co/MD7PYy5AVH</a></p>&mdash; Luis Lavena (@luislavena) <a href="https://twitter.com/luislavena/status/738005493189316608">June 1, 2016</a></blockquote>
<p>And it will be like this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="nb">require</span> <span class="s2">&#34;json&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">data</span> <span class="o">=</span> <span class="s">&lt;&lt;-JSON
</span></span></span><span class="line"><span class="cl">  <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;files&#34;</span><span class="p">:</span> <span class="o">[</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="s2">&#34;id&#34;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="s2">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;photo.jpg&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="s2">&#34;id&#34;</span><span class="p">:</span> <span class="mi">99</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="s2">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;another.jpg&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="o">]</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="no">JSON</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">obj</span> <span class="o">=</span> <span class="no">JSON</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">obj</span><span class="o">[</span><span class="s2">&#34;files&#34;</span><span class="o">].</span><span class="n">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">item</span><span class="o">|</span>
</span></span><span class="line"><span class="cl">  <span class="nb">puts</span> <span class="n">item</span><span class="o">[</span><span class="s2">&#34;id&#34;</span><span class="o">].</span><span class="n">as_i</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>So yeah, JSON parsing can be almost identical to what you would do with Ruby, although he also recommends Schemas as it&rsquo;s a bit faster anyway.</p>
<h3>Macros<span class="hx:absolute hx:-mt-20" id="macros"></span>
    <a href="#macros" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>The last important feature worth mentioning is the presence of Macros. As you don&rsquo;t have control over your code in runtime, you don&rsquo;t have &ldquo;eval&rdquo;, you don&rsquo;t have &ldquo;send&rdquo;, then you would not have any way to do proper metaprogramming.</p>
<p>Macros bring back some of Ruby&rsquo;s metaprogramming. For example, in Ruby, when you include a Module to a Class, there is the &ldquo;included?&rdquo; hook in the Module where you can add some metaprogramming such as &ldquo;class_eval&rdquo; stuff.</p>
<p>In Crystal, a Module does have an &ldquo;included&rdquo; hook but now it&rsquo;s a Macro. You can do something like this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="k">module</span> <span class="nn">Foo</span>
</span></span><span class="line"><span class="cl">  <span class="n">macro</span> <span class="n">included</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span><span class="o">%</span> <span class="k">if</span> <span class="vi">@type</span><span class="o">.</span><span class="n">name</span> <span class="o">==</span> <span class="s2">&#34;Bar&#34;</span> <span class="s">%}
</span></span></span><span class="line"><span class="cl"><span class="s">    def self.hello
</span></span></span><span class="line"><span class="cl"><span class="s">      puts &#34;Bar&#34;
</span></span></span><span class="line"><span class="cl"><span class="s">    end
</span></span></span><span class="line"><span class="cl"><span class="s">    {% else %}</span>
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">hello</span>
</span></span><span class="line"><span class="cl">      <span class="nb">puts</span> <span class="s2">&#34;HELLO&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">end</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span><span class="o">%</span> <span class="k">end</span> <span class="o">%</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">module</span> <span class="nn">Bar</span>
</span></span><span class="line"><span class="cl">  <span class="kp">include</span> <span class="no">Foo</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">module</span> <span class="nn">Something</span>
</span></span><span class="line"><span class="cl">  <span class="kp">include</span> <span class="no">Foo</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="no">Bar</span><span class="o">.</span><span class="n">hello</span> <span class="c1"># =&gt; &#34;Bar&#34;</span>
</span></span><span class="line"><span class="cl"><span class="no">Something</span><span class="o">.</span><span class="n">hello</span> <span class="c1"># =&gt; &#34;HELLO&#34;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>It feels like having &ldquo;ERB&rdquo; templates but for code. A macro is code building code in compile time. In the resulting AST it&rsquo;s as if you wrote the boring repetitive code yourself. The compiled native binary doesn&rsquo;t care. If you&rsquo;re from C it&rsquo;s like pre-processing but having control of an AST tree of Nodes instead of just manipulating the source code. You can even have something akin to the venerable &ldquo;#method_missing&rdquo;.</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Foo</span>
</span></span><span class="line"><span class="cl">  <span class="n">macro</span> <span class="nb">method_missing</span><span class="p">(</span><span class="nb">name</span><span class="p">,</span> <span class="n">args</span><span class="p">,</span> <span class="n">block</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{{</span><span class="n">pp</span> <span class="nb">name</span><span class="p">}}</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="no">Foo</span><span class="o">.</span><span class="n">new</span><span class="o">.</span><span class="n">hello_world</span>
</span></span><span class="line"><span class="cl"><span class="c1"># =&gt; name = &#34;hello_world&#34;</span>
</span></span><span class="line"><span class="cl"><span class="no">Foo</span><span class="o">.</span><span class="n">new</span><span class="o">.</span><span class="n">bla_bla</span><span class="p">(</span><span class="s2">&#34;bla&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># =&gt; name = &#34;bla_bla&#34;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Any macro function can receive an AST as the argument and you can manipulate this AST in any way as you see fit. For example:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>module Foo
  macro teste(ast)
    puts {{ast.stringify}}
  end
end

Foo.teste &#34;Hello World&#34;.split(&#34; &#34;).join(&#34; - &#34;)
# =&gt; (&#34;Hello World&#34;.split(&#34; &#34;)).join(&#34; - &#34;)</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>In this example you just get a normalized version of the code you passed as argument. And the code won&rsquo;t be &ldquo;executed&rdquo; at that location.</p>
<p>So, you can define new methods and call different versions of methods depending on the combination of elements that you get from the AST. One example of what is possible is this experiment from developer Oleksii that I bundled in this small project I called <a href="https://github.com/akitaonrails/cr_chainable_methods"target="_blank" rel="noopener">&ldquo;cr_chainable_methods&rdquo;</a> and we can build code that is very different from either Crystal or Ruby:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="n">result</span> <span class="o">=</span> <span class="n">pipe</span> <span class="s2">&#34;Hello World&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="o">.</span><span class="n">&gt;&gt;</span> <span class="no">Foo</span><span class="o">.</span><span class="n">split_words</span>
</span></span><span class="line"><span class="cl">  <span class="o">.</span><span class="n">&gt;&gt;</span> <span class="no">Foo</span><span class="o">.</span><span class="n">append_message</span><span class="p">(</span><span class="s2">&#34;Bar&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="o">.</span><span class="n">&gt;&gt;</span> <span class="no">Bar</span><span class="o">.</span><span class="n">add_something</span>
</span></span><span class="line"><span class="cl">  <span class="o">.</span><span class="n">&gt;&gt;</span> <span class="no">Foo</span><span class="o">.</span><span class="n">join</span>
</span></span><span class="line"><span class="cl">  <span class="o">.</span><span class="n">&gt;&gt;</span> <span class="n">unwrap</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>(Yes, a subset of what a real Elixir Pipe can do.)</p>
<h3>Crystal Shards<span class="hx:absolute hx:-mt-20" id="crystal-shards"></span>
    <a href="#crystal-shards" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Finally, one aspect I like about Crystal is that it has task management and dependency management already figured out. No pointless discussions on which implementation of packages and dependencies we &ldquo;should&rdquo; be using.</p>
<p>You can just write a simple script into a file such as &ldquo;test.cr&rdquo; and run this file like this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>crystal test.cr</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Or, you can build and compile to a native binary before executing like this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>crystal build test.cr --release
./test</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>And you can also start in a proper project structure and development lifecycle like this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>crystal init app test
cd test
crystal build src/test.cr --release
./test
git add .
git commit -m &#34;initial commit&#34;
git push -u origin master</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>It sets up a proper project directory structure, a Git repository is pre-initialized for you (why would you be programming without Git!?) with proper &ldquo;.gitignore&rdquo; file.</p>
<p>You will also find a &ldquo;shard.yml&rdquo; file where you can declare your application or library name, version, author, and also its dependencies like this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">kemal</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">version</span><span class="p">:</span><span class="w"> </span><span class="m">0.12.0</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">dependencies</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">radix</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">github</span><span class="p">:</span><span class="w"> </span><span class="l">luislavena/radix</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">version</span><span class="p">:</span><span class="w"> </span><span class="m">0.3.0</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">kilt</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">github</span><span class="p">:</span><span class="w"> </span><span class="l">jeromegn/kilt</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">version</span><span class="p">:</span><span class="w"> </span><span class="m">0.3.3</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">author</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span>- <span class="l">Serdar Dogruyol &lt;dogruyolserdar@gmail.com&gt;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>This example is from the <a href="https://github.com/sdogruyol/kemal"target="_blank" rel="noopener">Kemal web framework</a> by Serdar. It depends on the Radix and Kilt libraries. You must run <code>crystal deps</code> and it will fetch from Github before you can compile.</p>
<p>More than that: every project receives a proper &ldquo;spec&rdquo; directory where you can write Rspec-like tests and you can run them using <code>crystal spec</code>. And the spec runner results will look like this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>$ crystal spec
........................................................

Finished in 8.28 milliseconds
56 examples, 0 failures, 0 errors, 0 pending</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>All built-in, no external libraries needed.</p>
<p>And 8 milliseconds to run the entire test suite of a micro web framework? Not too shabby. If you add up start up time for the executable, it still is around 1 second of total running time. Pretty impressive.</p>
<h3>Conclusion<span class="hx:absolute hx:-mt-20" id="conclusion"></span>
    <a href="#conclusion" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Crystal is not meant to be a Ruby replacement like JRuby. So it will never run existing and complicated Ruby projects such as Ruby on Rails or even Sinatra for that matter.</p>
<p>To me Crystal fills a gap in some use cases where I would use Rust or Go. It has the raw performance of an LLVM-optimized native binary, a reasonably fast Go-like concurrency system (and much faster and less resource intensive than Node.js), and the added benefit of a much more enjoyable Ruby-like syntax set.</p>
<p>You can even start experimenting with Crystal to build Ruby native extensions without the need of FFI and without having to write C. There is an attempted <a href="https://github.com/startram/activesupport.cr"target="_blank" rel="noopener">port of ActiveSupport</a> as a native extension to MRI Ruby, written as a proof of concept in Crystal.</p>
<p>If you&rsquo;re a Rubyist you will find yourself pretty much at home with most of the standard library. You will miss a thing or two but most of the time it will feel like Ruby. The <a href="http://crystal-lang.org/docs"target="_blank" rel="noopener">official Guide</a> is good enough to get started and there is a comprehensive <a href="http://crystal-lang.org/api"target="_blank" rel="noopener">API documentation</a> just to check if that favorite Ruby API is there or not, and if not what the replacements are. Most of the time you will think <em>&ldquo;hmm, in Ruby I would use Enumerator#each &hellip; and yes, sure enough, there is Enumerator#each as expected.&rdquo;</em> The API documentation could use some more love, so if you want to contribute this is a good place to start.</p>
<p>If you want to check out a curated list of Crystal libraries and applications, go straight to <a href="http://awesome-crystal.com/"target="_blank" rel="noopener">&ldquo;Awesome Crystal&rdquo;</a>. You can also see the more dynamic <a href="https://github.com/trending/crystal"target="_blank" rel="noopener">&ldquo;Trending Projects in Github&rdquo;</a>.</p>
<p>For the most part, your proficiency in Ruby will pay off to build small systems where raw performance and concurrency are really necessary. This is exactly the use case for Mike Perham&rsquo;s port of <a href="https://github.com/mperham/sidekiq.cr"target="_blank" rel="noopener">Sidekiq.cr</a>. Say you have gigabytes of files to crunch. Or you have thousands of external websites to crawl, parse and organize. Or you have petabytes of data in your database waiting to be number crunched. Those are tasks that MRI Ruby won&rsquo;t help with but Crystal may well be the quick answer.</p>
<p>You can even get one of the many micro web frameworks such as Kemal and deploy your HTTP API providers <a href="http://crystal-lang.org/2016/05/26/heroku-buildpack.html"target="_blank" rel="noopener">directly to Heroku</a> now. This will give you Go-levels of performance, and this is <strong>very</strong> compelling for me as I really also dislike Go&rsquo;s archaic smelling syntax.</p>
<p>So, Rust, Go, Javascript, all very fast, but with very questionable syntaxes and not so enjoyable. They are way more mature, and their ecosystems are much larger. But unless I really need to, I&rsquo;d rather choose Crystal for the use cases I described above, and I think you will find some good use for it too.</p>
<p>Update: after I posted, the creator of Crystal, @Asterite had a few things to add as well:</p>
<blockquote class="twitter-tweet" data-partner="tweetdeck"><p lang="en" dir="ltr"><a href="https://twitter.com/AkitaOnRails">@AkitaOnRails</a> <a href="https://twitter.com/waj">@waj</a> so it&#39;s likely that we&#39;ll have something similar. We aren&#39;t there yet because we are not Google, Mozilla nor Apple</p>&mdash; Ary Borenszweig (@asterite) <a href="https://twitter.com/asterite/status/737778080085868545">May 31, 2016</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
]]></content:encoded><category>crystal</category><category>ruby</category><category>programming-languages</category></item><item><title>Rails has won: The Elephant in the Room</title><link>https://akitaonrails.github.io/en/2016/05/23/rails-has-won-the-elephant-in-the-room/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2016/05/23/rails-has-won-the-elephant-in-the-room/</guid><pubDate>Mon, 23 May 2016 17:21:00 -0300</pubDate><description>&lt;p&gt;I just read a very &lt;a href="http://web.archive.org/web/20160523160801/http://solnic.eu/2016/05/22/my-time-with-rails-is-up.html"target="_blank" rel="noopener"&gt;well written and important article&lt;/a&gt; from OSS contributor Solnic and I have to agree with him in almost every technical point.&lt;/p&gt;
&lt;p&gt;First of all, it&amp;rsquo;s inevitable but I still hate dramatic headlines, even though I write like this myself sometimes. &amp;ldquo;My time with Rails is up&amp;rdquo; like it&amp;rsquo;s saying &amp;ldquo;And you should leave Rails now too if you&amp;rsquo;re smart&amp;rdquo;. I dismissed the article entirely because of that. I was about to post a counter-rant to that without reading it properly, but now that I have, I wrote this new article from scratch.&lt;/p&gt;</description><content:encoded><![CDATA[<p>I just read a very <a href="http://web.archive.org/web/20160523160801/http://solnic.eu/2016/05/22/my-time-with-rails-is-up.html"target="_blank" rel="noopener">well written and important article</a> from OSS contributor Solnic and I have to agree with him in almost every technical point.</p>
<p>First of all, it&rsquo;s inevitable but I still hate dramatic headlines, even though I write like this myself sometimes. &ldquo;My time with Rails is up&rdquo; like it&rsquo;s saying &ldquo;And you should leave Rails now too if you&rsquo;re smart&rdquo;. I dismissed the article entirely because of that. I was about to post a counter-rant to that without reading it properly, but now that I have, I wrote this new article from scratch.</p>
<p>Solnic is right: Ruby, by itself, has little to no future alone. Rails is a real monopoly in this community and most OSS projects are targeting Rails. And yes, Rails does encourage some bad practices and anti-patterns. This can be very discouraging to many OSS contributors, especially because changing the direction of a huge Elephant takes humongous effort.</p>
<p>To make it clear, the dialectic technical arguments he makes are all true. But half the article - as he stated himself - is just rant, pure rhetoric. And I think it would be good to balance it out, which is what I will try to do in this post.</p>
<h3>Accepting Reality<span class="hx:absolute hx:-mt-20" id="accepting-reality"></span>
    <a href="#accepting-reality" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>The reality is this: Rails is tailor-made for Basecamp.</p>
<p>We all know that, or we should. Basecamp-like apps are not too difficult to make, at least in terms of architecture. You don&rsquo;t need fancy super performant languages with super duper highly concurrent and parallel primitives. Also a reality is that 80% of the web applications are Basecamp-like (disclosure: my feelings for years of experience in consulting). Which is why Rails has endured so far.</p>
<p>It&rsquo;s like content management systems, or CMS. Most of them are blog-like systems. And for that you should go ahead and install Wordpress. The very same arguments made against Rails can be made against Wordpress. And you should never, ever, tweak Wordpress to be anything but a blog-system. Try to make it into an e-commerce for high traffic, and you will suffer.</p>
<p>To make it clear: Wordpress has one of the most offensive source codes I&rsquo;ve ever seen. I would hate having to maintain that codebase. I&rsquo;m sorry if anyone from the Wordpress base of contributors is reading this, I say this without malevolence. And you know what? Possibly half of all CMSs in the world are Wordpress. Over a million websites.</p>
<p>Then you have the case for Magento2. Big rewrite over the original Magento, written using all the dreaded Zend stuff that everybody else dislikes. But it&rsquo;s huge. If you need a fast turn-key solution for e-commerce, look no further.</p>
<p>Do Wordpress plugins work with Magento? Nope. They are 2 fragmented, independent and isolated communities. But they both generate a lot of revenue, which is what covers the cost of redundancy between them. And this is not even counting Drupal, Joomla. PHP is one big ocean of disconnected islands. Countries with severe immigration laws.</p>
<p>Fragmentation is no stranger to the Javascript world. But it&rsquo;s a different kind of value generation. Facebook, Google, Microsoft, they all want to be the thought-leaders in the fast evolving Millenials generation. It&rsquo;s a long term strategy. And one of the elements of this game is the Browser. But not only in terms of Chrome vs Firefox vs IE, but also on how applications are implemented.</p>
<p>Facebook came up with React. Google came up with Polymer and Angular. The Node guys went through a power struggle with Joyent which almost resulted in further fragmentation but they settled for the <a href="http://readwrite.com/2015/02/10/joyent-node-js-foundation/"target="_blank" rel="noopener">Node Foundation</a>.</p>
<p>Apple went all on war against Adobe&rsquo;s Flash and then only now Google is <a href="http://web.archive.org/web/20160520233349/http://www.theinquirer.net/inquirer/news/2458329/googles-chrome-browser-will-switch-off-flash-content-by-default"target="_blank" rel="noopener">turning them off in Chrome</a>, but they are all looting on the consequences for all the attention it brings in the Web Development communities.</p>
<p>Apple wants native to succeed and Swift to be the one language to lead it all. Google has conflicting strategies because they want native <a href="http://techcrunch.com/2016/05/18/google-takes-a-new-approach-to-native-apps-with-instant-apps-for-android/"target="_blank" rel="noopener">Instant Apps</a> to succeed but if it fails, plan B continues to be for them to dominate HTML5/CSS3 based web apps with Angular. Facebook doesn&rsquo;t want to have its fate decided by the power struggle between Apple and Google.</p>
<p>It&rsquo;s a complex power struggle unfolding, and you can see it has little to do with technical prowess or value generation. It&rsquo;s about ego, influence and power. Very fitting for the YouTuber generation. And the web technologies are being held <em>hostage</em> in this siege, if you haven&rsquo;t noticed.</p>
<p>Then there is the issue that Ruby&rsquo;s future is now tightly coupled with Rails. This is a reality and if you&rsquo;re a Rubyist who doesn&rsquo;t like Rails, I feel bad for you. But not so much. For example, if Hanami is interesting I believe at least one company invested on it. If no one is using it, then it doesn&rsquo;t matter how technically superior it is. If Rom.rb is great someone should be using it, otherwise what&rsquo;s the point? Why create a technical marvel that no one wants? But if there is at least one company using it, it&rsquo;s <strong>enough reason</strong> to keep going, regardless of what happens to Rails or what DHH says or does.</p>
<blockquote>
  <p>People think that because something is &ldquo;technically superior&rdquo; everybody else should blindly adopt. But this is not how the market works.</p>

</blockquote>
<p>Of all the cosmic-size events going on out there, I really don&rsquo;t sweat it that much if Ruby stays tied to Rails. What would it do without it?</p>
<p>All communities face fragmentation at some point. It&rsquo;s very difficult and expensive to maintain cohesiveness for a long time. The only community that I think achieved that through sheer force of regulation is Microsoft&rsquo;s .NET stack. It doesn&rsquo;t mean that there was no pressure from the outside. Rails itself played a big role into influencing the move from old-ASP.NET to ASP.NET MVC. Now they finally <a href="http://blogs.microsoft.com/blog/2016/02/24/microsoft-to-acquire-xamarin-and-empower-more-developers-to-build-apps-on-any-device/"target="_blank" rel="noopener">acquired Xamarin</a> before .NET could steer out of their control in open source platforms they don&rsquo;t control.</p>
<p>Ruby on Rails is the only other &ldquo;cohesive&rdquo; community I&rsquo;ve seen. With the upside that Basecamp doesn&rsquo;t need hundreds of thousands of developers to exist. A niche market would suffice, enough for the framework to evolve gradually through OSS processes. Which is why I always question the history and origins of tools and technologies to make my decisions on where to use them, not just technical prowess.</p>
<p>Rails works because it doesn&rsquo;t have to play politics with Apple, Facebook, Microsoft, Google or any other committees (by the way, by default, I never trust committees). Those who depend on Rails will do the house-keeping, directly. Heroku, Github, New Relic, Shopify, and many talented developers.</p>
<h3>3 Laws of Market Reality<span class="hx:absolute hx:-mt-20" id="3-laws-of-market-reality"></span>
    <a href="#3-laws-of-market-reality" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><ol>
<li>
<p>It&rsquo;s easy to over-analyse something after the fact. 10 years down the road, I can easily trace back an optimal path, avoiding all booby traps and obstacles along the way. Doesn&rsquo;t make me any genius, just shows that I can connect the - now clearly visible - dots.</p>
</li>
<li>
<p>No solution implementation is perfect. If it actually solves a real problem it&rsquo;s bound to be imperfect. If it solves a real problem in a fast paced changing market, the more imperfect.</p>
</li>
<li>
<p>Either you build tools because your core business applications depend on it or you build tools to sell. The former will usually be better - in terms of market-fit - than the latter. So if you have to blindly choose, go with the former.</p>
</li>
</ol>
<p>So, first of all, I will always prefer tools that solve a real problem made by those that actually depend on them. Otherwise, the shoemaker&rsquo;s son will end up barefoot. Case in point: I will definitely use Angular, if I have to. But I would never, ever, begin a new business that depends solely on Angular to survive. Why? Because Google doesn&rsquo;t need it. It didn&rsquo;t blink to give up GWT, it didn&rsquo;t have to think twice to decide to rewrite Angular 2 in an incompatible way to Angular 1, and so on.</p>
<p>Second of all, I will always see what other external factors will influence the fate of the technology. Imagine that I spent a whole lot of time writing scripts, libraries, tools for Grunt. Then people decide it&rsquo;s bad. Now Gulp is the better choice - and you will find plenty of technical reasons. Now you invest a lot of time writing everything you had for Grunt to Gulp. Then, for plenty of other reasons people decide that Webpack is the best choice. And there you go again. NIH (Not-invented-here) syndrome galore.</p>
<p>This is clearly a small bubble. It&rsquo;s tulips all over again. There are too many big players (Facebook, Google, Apple, Microsoft, Mozilla, etc) with big pockets, plenty of time and resources. This is how an experimental lab works in public. Lots and lots of experimental alternatives and several businesses blindly choosing depending on the best sales pitch of the week.</p>
<p>Sometimes this kind of situation makes the monopoly of ASP.NET on the Microsoft camp and the Rails monopoly on the Ruby camp seem innocuous. And yes, I compared Rails to .NET here. They are the 2 most comparable stacks. Possibly comparable to Spring faction in the Java camp. If you remember the history, Spring was like Rails in the Java community, rising up against the humongous complexity of the official J2EE stack back in 2002. And then Spring itself became the new J2EE-like behemoth to beat.</p>
<p>This is a millennia-old dilemma:</p>
<blockquote>
  <p>&ldquo;You either die a hero, or live long enough to see yourself become the villain.&rdquo;</p>

</blockquote>
<h3>Why is Rails a problem now?<span class="hx:absolute hx:-mt-20" id="why-is-rails-a-problem-now"></span>
    <a href="#why-is-rails-a-problem-now" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>As I said before, I agree to almost every technical problem that Solnic outlined.</p>
<p>Rails is indeed the brainchild of David Hansson (DHH). DHH is a person, with a very big ego, and a business to run. You can&rsquo;t expect any person to be reasonable all the time, especially one who pushed something up from zero, both a business and a technology platform.</p>
<p>When it started, people defected from Java, .NET, PHP even Python, in droves and they all acknowledged how interesting Rails was compared to J2EE, ASP.NET, Plone. It offered not only productivity but technical enjoyment. We were discussing the wondrous world of dynamic languages, open classes, injecting behavior on the fly (aka <a href="https://m.signalvnoise.com/provide-sharp-knives-cc0a22bf7934"target="_blank" rel="noopener">monkey patching</a>), we all stood up and applauded dropping all unnecessary abstractions.</p>
<p>We could not have enough of our Ruby fix, spitting out all the Perl-like magic we would accomplish in a language that didn&rsquo;t feel ugly as PHP or bureaucratic like Java or C#. And they all laughed.</p>
<p>The Golden Age from 2004 to 2006 saw a never ending stream of celebratory masturbation of Perl-like coding prowess. We learned Ruby through <a href="http://poignant.guide/"target="_blank" rel="noopener">Why, the Lucky Stiff</a> most obscure black magic, remember that? It was everything but clean and modular architectures.</p>
<p>Then we entered the Silver Age, from 2007 to around 2011. Rails actually went too far, too fast. Suddenly we saw big companies popping up from everywhere! Twitter, Github, Engine Yard, Heroku, Zendesk, Airbnb, everybody drank the Rails Kool-Aid. The opportunity was there to offer something for the enterprise. Merb was ahead of its time and it was pitched the wrong way. I do think that confronting the almighty Rails upfront, at that point, was not smart. You should expect overreaction and it did come and it was a swift blow. I will be honest and say that I was very apprehensive in 2009 and 2010 to see if the Rails 3 pseudo-rewrite, pseudo-Merb-merge would actually come through.</p>
<p>2011 to 2016 was the Bronze Age, a bittersweet period. That&rsquo;s because many new languages have emerged and finally reached &ldquo;usable&rdquo; state. From JS&rsquo;s V8 and Node.js, to Rust, to Clojure, to Elixir, and even some gems from the past started to get attention, such as Scala and even Haskell. The most important change of all: 2010 saw the advent of the Walled Garden App Store, commercially available native applications for smartphone and tablets. Forget web development: mobile was getting it all.</p>
<p>And that&rsquo;s when all the big companies started to show their deep pockets. Apple releases Swift. Google released Dart, Angular, Go. Microsoft released Typescript, ASP.NET MVC then vNext and had its hands full working on Windows 10. Facebook entered the game late by releasing React and then React Native.</p>
<p>Rails can now be considered a &ldquo;problem&rdquo; for the very same reasons that made it popular in the first place. And this is bound to happen to any technology.</p>
<p>But you can&rsquo;t change the architecture of Rails too much, otherwise you risk breaking down very big chunks of the projects that are deployed in production now. And when someone has to rewrite big chunks of a project you might as well consider rewriting it in something else entirely.</p>
<p>Many people are doing exactly that, especially for APIs and web applications implemented as SPAs talking to APIs. The APIs can be written in Go, Elixir, Scala and avoid Ruby altogether. You lose the fast turn around of the Rails ecosystem, but if you can afford it (you&rsquo;re a Unicorn startup with deep pockets), why not?</p>
<p>But again, for the 90% of small to medium projects out there, you can still get the best punch for the buck using Rails and all the libraries available for Rails. It&rsquo;s like saying, if you want to build a blog, go for Wordpress and you will get the best benefit for the limited resources you have. Don&rsquo;t try to be fancy and write an SPA blog using Go APIs with React from scratch. Feasible, but not worth it.</p>
<p>If you&rsquo;re a medium company already using Rails for some time, first of all make sure you adhere to basic best practices. Add tests and specs if you haven&rsquo;t already. Steadily refactor code, remove duplication, upgrade gems. Then you should consider adding an abstraction layer such as <a href="http://trailblazer.to/"target="_blank" rel="noopener">Trailblazer</a> and possibly consider componentizing parts of your application as <a href="https://leanpub.com/cbra"target="_blank" rel="noopener">Rails Engines</a> or removing those parts into separated <a href="https://github.com/rails-api/rails-api"target="_blank" rel="noopener">Rails-API</a> applications to be consumed, if possible. But do one step at a time, as needed.</p>
<blockquote>
  <p>One rarely benefits from big bang rewrites from scratch.</p>

</blockquote>
<h3>Conclusion<span class="hx:absolute hx:-mt-20" id="conclusion"></span>
    <a href="#conclusion" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>So yes, for developers such as Solnic the Rails community is probably a frustrating place to be. But it&rsquo;s also an addiction that&rsquo;s hard to drop because Rails is so much larger than any other competitor in any other new and fancy platform, you always feel bad for being the underdog.</p>
<p>Rails went from underdog to mainstream in 5 years. Possibly the fastest growth any web framework ever achieved. The life of a web developer from 1995 to 2003 was not particularly interesting. Rails did a lot to improve it. And if anyone thinks they can do better, just do it. What&rsquo;s the point of writing about Rails? More than just code competing against code, results should compete against results.</p>
<p>Active Record&rsquo;s architecture will indeed hurt hard maybe 10% of the cases out there. Active Support does not have a better alternative so far, and just removing it won&rsquo;t bring anything of value for the end user. Replacing a big component such as Active Record with something &ldquo;better&rdquo; such as an improved version of DataMapper or Rom.rb as the default again won&rsquo;t bring so much value, especially for the hundreds of applications out there. You&rsquo;re telling everybody to just rewrite everything. And if I had to rewrite, I would definitely do a new application using Rails + Trailblazer or go straight to Hanami. But most people would decide in favor of ditching Ruby altogether.</p>
<p>Could Active Record be better? Sure! We have old Data Mapper, Sequel and ROM.rb to prove it. But the real question is: could it be done better back in 2004 when it was first created? I don&rsquo;t think so. Now even the creator of DataMapper advocates for No-ORM. In 2004 &ldquo;NoSQL&rdquo; wasn&rsquo;t even a thing. The best we had back then was Hibernate, way before JPA! And for all intents and purposes, Active Record still does much better than average. But if you&rsquo;re big, you should be careful. That&rsquo;s all.</p>
<p>The other communities will face the same predicaments we are now facing in the Rails community. It&rsquo;s inevitable. Everything is so much easier when you have a small community that even if you break things it won&rsquo;t be too bad. It&rsquo;s much harder to maintain something that actually became big beyond your most optimistic scenarios.</p>
<p>I do understand the conservative approach DHH is taking by not making big disruptions. If this is something he is doing because he believes in conservative moves or because he doesn&rsquo;t understand better architectural options is not up to me to judge, but it&rsquo;s a valid move that will alienate advanced developers like Solnic but still allow for beginners to jump right into it without worrying too much right now about too many abstractions.</p>
<p>Update: DHH commented on this section later:</p>
<blockquote class="twitter-tweet" data-partner="tweetdeck"><p lang="en" dir="ltr"><a href="https://twitter.com/AkitaOnRails">@akitaonrails</a> It's not out of conservatism. But a difference of opinion and values. I love Active Record. Love callbacks.</p>&mdash; DHH (@dhh) <a href="https://twitter.com/dhh/status/735051111141396480">May 24, 2016</a></blockquote>
<blockquote class="twitter-tweet" data-partner="tweetdeck"><p lang="en" dir="ltr"><a href="https://twitter.com/AkitaOnRails">@akitaonrails</a> Will everyone love the same techniques and methods as me? Of course not (see RSpec for just one popular example!). That's fine</p>&mdash; DHH (@dhh) <a href="https://twitter.com/dhh/status/735051237071171584">May 24, 2016</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
<p>People forget that abstractions are very nice for advanced developers who have suffered the lack of them. But beginners will always suffer if presented with too many architectural choices upfront. Understanding GoF Design Patterns, Data-Driven Design, SOLID, Enterprise Architectures, etc is very overwhelming. Experienced people often forget the learning curve when they were themselves beginners, and at that time Rails was so attractive, so sexy. Remember that feeling? Of accomplishment in the face of the knowledge that some nice witch left super useful black magic behind?</p>
<p><strong>Rails has won</strong> for its simplicity for beginners, having a &ldquo;rails&rdquo;-like guidance for experienced people as well, and <em>somewhat acceptable</em> flexibility for more advanced developers. Will it be able to last another 10 years in face of the many smaller alternatives out there trying to recreate everything from scratch? Time will tell.</p>
<p>I think it would be a good fit to finish with Bob Dylan:</p>
<blockquote>
  <p>Come gather &lsquo;round people</p>

</blockquote>
<blockquote>
  <p>Wherever you roam</p>

</blockquote>
<blockquote>
  <p>And admit that the waters</p>

</blockquote>
<blockquote>
  <p>Around you have grown</p>

</blockquote>
<blockquote>
  <p>And accept it that soon</p>

</blockquote>
<blockquote>
  <p>You&rsquo;ll be drenched to the bone.</p>

</blockquote>
<blockquote>
  <p>If your time to you</p>

</blockquote>
<blockquote>
  <p>Is worth savin&rsquo;</p>

</blockquote>
<blockquote>
  <p>Then you better start swimmin'</p>

</blockquote>
<blockquote>
  <p>Or you&rsquo;ll sink like a stone</p>

</blockquote>
<blockquote>
  <p>For the times they are a-changin'.</p>

</blockquote>
<blockquote>
  <p>&hellip;</p>

</blockquote>
]]></content:encoded><category>rails</category><category>ruby</category><category>off-topic</category></item><item><title>Elixir Pipe Operator for Ruby: Chainable Methods</title><link>https://akitaonrails.github.io/en/2016/02/18/elixir-pipe-operator-for-ruby-chainable-methods/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2016/02/18/elixir-pipe-operator-for-ruby-chainable-methods/</guid><pubDate>Thu, 18 Feb 2016 16:28:00 -0200</pubDate><description>&lt;p&gt;There have been &lt;a href="http://blog.molawson.com/elixir-pipes-in-ruby/"target="_blank" rel="noopener"&gt;recent&lt;/a&gt; &lt;a href="https://gist.github.com/pcreux/2f87847e5e4aad37db02"target="_blank" rel="noopener"&gt;discussions&lt;/a&gt; about how nice it would be to have something like the awesome Elixir Pipe Operator for Ruby.&lt;/p&gt;
&lt;p&gt;If you don&amp;rsquo;t know what the &amp;ldquo;Pipe Operator&amp;rdquo; is in Elixir, take the following code:&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-ruby" data-lang="ruby"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="no"&gt;Enum&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Enum&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Enum&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="mi"&gt;100_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt; &lt;span class="n"&gt;odd?&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="Copy code"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;It&amp;rsquo;s ugly, we all know that. In an Object Oriented language like Ruby we would do something like this:&lt;/p&gt;</description><content:encoded><![CDATA[<p>There have been <a href="http://blog.molawson.com/elixir-pipes-in-ruby/"target="_blank" rel="noopener">recent</a> <a href="https://gist.github.com/pcreux/2f87847e5e4aad37db02"target="_blank" rel="noopener">discussions</a> about how nice it would be to have something like the awesome Elixir Pipe Operator for Ruby.</p>
<p>If you don&rsquo;t know what the &ldquo;Pipe Operator&rdquo; is in Elixir, take the following code:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="no">Enum</span><span class="o">.</span><span class="n">sum</span><span class="p">(</span><span class="no">Enum</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="no">Enum</span><span class="o">.</span><span class="n">map</span><span class="p">(</span><span class="mi">1</span><span class="o">..</span><span class="mi">100_000</span><span class="p">,</span> <span class="o">&amp;</span><span class="p">(</span><span class="o">&amp;</span><span class="mi">1</span> <span class="o">*</span> <span class="mi">3</span><span class="p">)),</span> <span class="n">odd?</span><span class="p">))</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>It&rsquo;s ugly, we all know that. In an Object Oriented language like Ruby we would do something like this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="p">(</span><span class="mi">1</span><span class="o">..</span><span class="mi">100_000</span><span class="p">)</span><span class="o">.</span>
</span></span><span class="line"><span class="cl">  <span class="n">map</span> <span class="p">{</span> <span class="o">|</span><span class="n">i</span><span class="o">|</span> <span class="n">i</span> <span class="o">*</span> <span class="mi">3</span> <span class="p">}</span><span class="o">.</span>
</span></span><span class="line"><span class="cl">  <span class="nb">select</span><span class="p">(</span><span class="o">&amp;</span><span class="ss">:odd?</span><span class="p">)</span><span class="o">.</span>
</span></span><span class="line"><span class="cl">  <span class="n">reduce</span><span class="p">(</span><span class="o">&amp;</span><span class="ss">:+</span><span class="p">)</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>But Elixir does not have objects, only functions, so how can we code more elegantly? The solution came up in the form of the so called &ldquo;Pipe Operator&rdquo; which takes the last returning value and passes it through as the first argument of the next function call, like this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="mi">1</span><span class="o">..</span><span class="mi">100_000</span>
</span></span><span class="line"><span class="cl">  <span class="o">|&gt;</span> <span class="no">Stream</span><span class="o">.</span><span class="n">map</span><span class="p">(</span><span class="o">&amp;</span><span class="p">(</span><span class="o">&amp;</span><span class="mi">1</span> <span class="o">*</span> <span class="mi">3</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">  <span class="o">|&gt;</span> <span class="no">Stream</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">odd?</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="o">|&gt;</span> <span class="no">Enum</span><span class="o">.</span><span class="n">sum</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>So Ruby and Elixir &ldquo;feel&rdquo; the same when we are able to &ldquo;chain&rdquo; methods. In the Ruby world we don&rsquo;t have the &ldquo;need&rdquo; for an operator like that. But it would be nice to have a mechanism that we could use to make our code more expressive, or more testable, or more readable. For example, what if we could write something like this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="p">(</span><span class="mi">1</span><span class="o">..</span><span class="mi">100_000</span><span class="p">)</span><span class="o">.</span>
</span></span><span class="line"><span class="cl">  <span class="n">multiple_each_element_by_three</span><span class="o">.</span>
</span></span><span class="line"><span class="cl">  <span class="n">filter_out_odd_elements</span><span class="o">.</span>
</span></span><span class="line"><span class="cl">  <span class="n">give_the_sum_of_all_elements</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Of course, this is a very constrained example with really bad method naming. But if we look at Mo Lawson&rsquo;s article I linked above, it becomes more interesting:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="n">keywords</span>
</span></span><span class="line"><span class="cl">  <span class="o">.</span><span class="n">map</span> <span class="p">{</span> <span class="o">|</span><span class="n">kw</span><span class="o">|</span> <span class="n">kw</span><span class="o">.</span><span class="n">gsub</span><span class="p">(</span><span class="sr">/(^[^[:alpha:]]+|[^[:alpha:]]+$)/</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">)</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="o">.</span><span class="n">map</span> <span class="p">{</span> <span class="o">|</span><span class="n">kw</span><span class="o">|</span> <span class="no">LegacySpanishCorrector</span><span class="o">.</span><span class="n">new</span><span class="o">.</span><span class="n">correct</span><span class="p">(</span><span class="n">kw</span><span class="p">)</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="o">.</span><span class="n">map</span> <span class="p">{</span> <span class="o">|</span><span class="n">kw</span><span class="o">|</span> <span class="n">kw</span><span class="o">.</span><span class="n">gsub</span><span class="p">(</span><span class="sr">/[^[:alpha:]\d&#39;_\-\/]/</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">)</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="o">.</span><span class="n">reject</span> <span class="p">{</span> <span class="o">|</span><span class="n">kw</span><span class="o">|</span> <span class="no">STOP_WORDS</span><span class="o">.</span><span class="n">include?</span><span class="p">(</span><span class="n">kw</span><span class="p">)</span> <span class="p">}</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Ruby allows us to chain Enumerable methods one after the other, transforming the initial keywords list into &ldquo;something&rdquo; that is very difficult to infer just by looking at this code.</p>
<p>What about this other version?</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">KeywordNormalizer</span>
</span></span><span class="line"><span class="cl">  <span class="k">def</span> <span class="nf">call</span><span class="p">(</span><span class="n">keywords</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="no">Collection</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="n">keywords</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="o">.</span><span class="n">strip_outer_punctuation</span>
</span></span><span class="line"><span class="cl">      <span class="o">.</span><span class="n">fix_spanish</span>
</span></span><span class="line"><span class="cl">      <span class="o">.</span><span class="n">clean_inner_punctuation</span>
</span></span><span class="line"><span class="cl">      <span class="o">.</span><span class="n">remove_stop_words</span>
</span></span><span class="line"><span class="cl">      <span class="o">.</span><span class="n">to_a</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># ...</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>This is where he ends up by the end of his article: much more readable and each new isolated method is unit testable, resulting in more robust code.</p>
<p>The whole idea of this post is to introduce you to my new little gem <a href="https://rubygems.org/gems/chainable_methods"target="_blank" rel="noopener">&ldquo;Chainable Methods&rdquo;</a>. The <a href="https://github.com/akitaonrails/chainable_methods"target="_blank" rel="noopener">source code</a> is on Github, as usual, so please contribute.</p>
<p>My gem will allow you to write Lawson&rsquo;s last code like this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="no">KeywordNormalizer</span>
</span></span><span class="line"><span class="cl">  <span class="o">.</span><span class="n">chain_from</span><span class="p">(</span><span class="n">keywords</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="o">.</span><span class="n">strip_outer_punctuation</span>
</span></span><span class="line"><span class="cl">  <span class="o">.</span><span class="n">fix_spanish</span>
</span></span><span class="line"><span class="cl">  <span class="o">.</span><span class="n">clean_inner_punctuation</span>
</span></span><span class="line"><span class="cl">  <span class="o">.</span><span class="n">remove_stop_words</span>
</span></span><span class="line"><span class="cl">  <span class="o">.</span><span class="n">to_a</span>
</span></span><span class="line"><span class="cl">  <span class="o">.</span><span class="n">unwrap</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>You add the <tt>chainable_methods</tt> to your Gemfile as usual (you know the drill), then you can write Lawson&rsquo;s module like this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="k">module</span> <span class="nn">KeywordNormalizer</span>
</span></span><span class="line"><span class="cl">  <span class="kp">extend</span> <span class="no">ChainableMethods</span>
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">  <span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">strip_outer_punctuation</span><span class="p">(</span><span class="n">array</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">array</span><span class="o">.</span><span class="n">map</span> <span class="p">{</span> <span class="o">|</span><span class="n">el</span><span class="o">|</span> <span class="n">el</span><span class="o">.</span><span class="n">gsub</span><span class="p">(</span><span class="sr">/(^[^[:alpha:]]+|[^[:alpha:]]+$)/</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">)</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl">  <span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">fix_spanish</span><span class="p">(</span><span class="n">array</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">array</span><span class="o">.</span><span class="n">map</span> <span class="p">{</span> <span class="o">|</span><span class="n">el</span><span class="o">|</span> <span class="no">LegacySpanishCorrector</span><span class="o">.</span><span class="n">new</span><span class="o">.</span><span class="n">correct</span><span class="p">(</span><span class="n">el</span><span class="p">)</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl">  <span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">clean_inner_punctuation</span><span class="p">(</span><span class="n">array</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">array</span><span class="o">.</span><span class="n">map</span> <span class="p">{</span> <span class="o">|</span><span class="n">el</span><span class="o">|</span> <span class="n">el</span><span class="o">.</span><span class="n">gsub</span><span class="p">(</span><span class="sr">/[^[:alpha:]\d&#39;_\-\/]/</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">)</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl">  <span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">remove_stop_words</span><span class="p">(</span><span class="n">array</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">array</span><span class="o">.</span><span class="n">reject</span> <span class="p">{</span> <span class="o">|</span><span class="n">el</span><span class="o">|</span> <span class="no">STOP_WORDS</span><span class="o">.</span><span class="n">include?</span><span class="p">(</span><span class="n">el</span><span class="p">)</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>And that&rsquo;s it, now you can chain everything like I showed previously. The pattern is:</p>
<ol>
<li>Write a Module with class-level methods that receive at least one argument and extend the &lsquo;ChainableMethods&rsquo; module:</li>
</ol>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="k">module</span> <span class="nn">MyModule</span>
</span></span><span class="line"><span class="cl">  <span class="kp">extend</span> <span class="no">ChainableMethods</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">method_a</span><span class="p">(</span><span class="n">argument1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># ...</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">method_b</span><span class="p">(</span><span class="n">argument1</span><span class="p">,</span> <span class="n">argument2</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># ...</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">method_c</span><span class="p">(</span><span class="n">argument1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># yield a block passing the received argument</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<ol start="2">
<li>Wrap an initial state that will be passed to the first method as its first argument:</li>
</ol>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="n">some_initial_state</span> <span class="o">=</span> <span class="s2">&#34;Hello World&#34;</span>
</span></span><span class="line"><span class="cl"><span class="no">MyModule</span>
</span></span><span class="line"><span class="cl">  <span class="o">.</span><span class="n">chain_from</span><span class="p">(</span><span class="n">some_initial_state</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="c1"># ...</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<ol start="3">
<li>Chain as many methods from the module or methods that the returning state recognizes:</li>
</ol>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="no">MyModule</span>
</span></span><span class="line"><span class="cl">  <span class="o">.</span><span class="n">chain_from</span><span class="p">(</span><span class="n">some_initial_state</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="o">.</span><span class="n">upcase</span>
</span></span><span class="line"><span class="cl">  <span class="o">.</span><span class="n">method_a</span>
</span></span><span class="line"><span class="cl">  <span class="o">.</span><span class="n">method_b</span><span class="p">(</span><span class="n">argument2</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="o">.</span><span class="n">method_c</span> <span class="p">{</span> <span class="o">|</span><span class="n">foo</span><span class="o">|</span> <span class="n">foo</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&#34; &#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="s2">&#34;, &#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="o">.</span><span class="n">unwrap</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Notice that we do not need to pass the first argument to the methods within the &lsquo;MyModule&rsquo; module, it will get the result from the last call automatically.</p>
<ol start="4">
<li>Do not forget to call <tt>#unwrap</tt> as the last call to get the last result from the chain.</li>
</ol>
<h3>An Experiment<span class="hx:absolute hx:-mt-20" id="an-experiment"></span>
    <a href="#an-experiment" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>And that&rsquo;s it! I isolated this behavior only into modules that explicitly extend the &lsquo;ChainableMethods&rsquo; module instead of automagically enabling it at the BasicObject level as many would initially think, because we don&rsquo;t want a global &lsquo;method_missing&rsquo; dangling around unchecked.</p>
<p>This behavior makes use of &lsquo;method_missing&rsquo; so it&rsquo;s not going to be fast in a synthetic benchmark against a direct method call, for obvious reasons. The purpose is not to be fast, just expressive. So keep that in mind.</p>
<p>The use case is: whenever you have some kind of transformation, you will want a chain of unit testable, isolated functions, and this is how you can get it without too much hassle.</p>
<p>This is an experiment. Because I&rsquo;m using &lsquo;method_missing&rsquo; there may be side-effects I am not seeing right now, so please let me know in the <a href="https://github.com/akitaonrails/chainable_methods/issues"target="_blank" rel="noopener">Github Issues</a> and send feedback if it helped you out in some project.</p>
<p>Pull Requests are most welcome!</p>
]]></content:encoded><category>ruby</category><category>elixir-and-erlang</category><category>programming-languages</category></item><item><title>The New Kid on the Block for Ruby Servers: Raptor!</title><link>https://akitaonrails.github.io/en/2014/10/19/the-new-kid-on-the-block-for-ruby-servers-raptor/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2014/10/19/the-new-kid-on-the-block-for-ruby-servers-raptor/</guid><pubDate>Sun, 19 Oct 2014 15:00:00 -0200</pubDate><description>&lt;p&gt;&lt;em&gt;Update (25/11/2014):&lt;/em&gt; We can finally confirm that yes, the awesome Raptor project is the codename for the next release of Phusion Passenger itself! Read the &lt;a href="http://blog.phusion.nl/2014/11/25/introducing-phusion-passenger-5-beta-1-codename-raptor/"target="_blank" rel="noopener"&gt;announcement&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re a seasoned Ruby web developer you&amp;rsquo;re probably familiar and comfortable using the usual suspects to deploy your applications. You&amp;rsquo;re either deploying something simple through good old Thin, or you&amp;rsquo;re orchestrating several Ruby processes through Unicorn workers, or you&amp;rsquo;re trying out JRuby and want better concurrency and thread management, and therefore you&amp;rsquo;re using either Puma or Torquebox.&lt;/p&gt;</description><content:encoded><![CDATA[<p><em>Update (25/11/2014):</em> We can finally confirm that yes, the awesome Raptor project is the codename for the next release of Phusion Passenger itself! Read the <a href="http://blog.phusion.nl/2014/11/25/introducing-phusion-passenger-5-beta-1-codename-raptor/"target="_blank" rel="noopener">announcement</a></p>
<p>If you&rsquo;re a seasoned Ruby web developer you&rsquo;re probably familiar and comfortable using the usual suspects to deploy your applications. You&rsquo;re either deploying something simple through good old Thin, or you&rsquo;re orchestrating several Ruby processes through Unicorn workers, or you&rsquo;re trying out JRuby and want better concurrency and thread management, and therefore you&rsquo;re using either Puma or Torquebox.</p>
<p>And even though it feels like we are already at the peak of what&rsquo;s possible with Ruby, we do want more. Ruby 2.1.3 was just released, 3.0 is in development. But until then it should be possible to squeeze some more performance out of your boxes.</p>
<p>In fact, a new contender with some new approaches just showed up. I have few details so far, but it&rsquo;s a brand new product - not derived from the others - from an unknown team. This product is named <a href="http://www.rubyraptor.org"target="_blank" rel="noopener">&ldquo;Raptor&rdquo;</a> and they claim that it can squeeze the extra juice out of our boxes.</p>
<p>And this is their claim:</p>
<p><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/475/chart-1.png" alt="Raptor Chart"  loading="lazy" /></p>
<p>Fortunately, I had the chance to experiment with its beta release in a controlled Vagrant environment and check those claims! Bear in mind that those are synthetic benchmarks and real world throughput of real applications should give us different behavior. With that having been said, let&rsquo;s see how the main Ruby servers perform a very simple Rack app returning a simple HTTP 200 with &ldquo;Hello World&rdquo;:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code> ==&gt; Benchmark parameters:
     Application         : hello_app
     Operating system    : Ubuntu 14.04 LTS (x86_64)
     Virtual CPU cores   : 4
     MRI Ruby            : ruby 2.1.3p242 (2014-09-19 revision 45877) [x86_64-linux-gnu]
     JRuby               : jruby 1.7.13 (1.9.3p392) 2014-06-24 43f133c on OpenJDK 64-Bit Server VM 1.7.0_65-b32 [linux-amd64]

     Unicorn workers     : 8
     Puma workers (MRI)  : 8 (16 threads each)
     Puma workers (JRuby): 1 (32 threads each)
     Torquebox threads   : 32
     Raptor workers      : 8

     Concurrent clients  : 16

 ==&gt; Benchmark summary:
     Unicorn (MRI Ruby)         : 23015.36 req/sec
     Puma (MRI Ruby)            : 32538.62 req/sec
     Puma (JRuby)               : 399.14 req/sec
     Torquebox (JRuby)          : 29773.21 req/sec
     Raptor (MRI Ruby)          : 95309.35 req/sec
     Raptor (JRuby)             : 87523.65 req/sec</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Now, this sounds very impressive indeed! And what about a more complex example: a simple Rails 4.1.6 application rendering a default scaffold index page with a model fetching 20 rows from MySQL:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>==&gt; Benchmark summary:
    Unicorn (MRI Ruby)         : 326.49 req/sec
    Puma (MRI Ruby)            : 327.36 req/sec
    Puma (JRuby)               : 221.78 req/sec
    Torquebox (JRuby)          : 226.57 req/sec
    Raptor (MRI Ruby)          : 79617.78 req/sec
    Raptor (JRuby)             : 73948.59 req/sec</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Again, <strong>super</strong> impressive. My first impression when reading these numbers is that Raptor must have built-in response caching (which is great!). So I tweaked the example to make it much heavier than what&rsquo;s considered &ldquo;normal&rdquo; for a small cache, rendering a table of 100 rows from the database in the index page, and the results are still competitive:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>==&gt; Benchmark summary:
    Unicorn (MRI Ruby)         : 85.98 req/sec
    Puma (MRI Ruby)            : 89.93 req/sec
    Puma (JRuby)               : 79.42 req/sec
    Torquebox (JRuby)          : 77.98 req/sec
    Raptor (MRI Ruby)          : 82.63 req/sec
    Raptor (JRuby)             : 88.92 req/sec</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>This could mean that in the best case scenario, you could get almost <strong>4 times</strong> the throughput from your application, and in the worst case scenario, you&rsquo;re still getting similar throughputs. This means that Raptor is adaptable and reasonably &ldquo;smart&rdquo;. So overall it&rsquo;s a win-win situation!</p>
<p>The way they are able to achieve these superior numbers can be explained by the way they approached the implementation. This is the breakdown that they have released so far:</p>
<ul>
<li><strong>Protection against slow clients</strong>: Slow clients on the Internet can block your app, like people standing still in front of your door. Unicorn only has a single small door, so it <a href="http://unicorn.bogomips.org/PHILOSOPHY.html"target="_blank" rel="noopener">requires</a> you to attach a buffering reverse proxy in front of it, like Nginx. Puma has as many small doors as you configure threads, so you still need to attach Nginx in front to be safe. But Raptor has a door that&rsquo;s almost infinitely wide, and fully protects your app against slow clients without additional software.</li>
<li><strong>Optional integration with Nginx</strong>. Nginx is a great web server and provides useful features like compression, security, etc. But using Puma and Unicorn with Nginx requires you to configure Puma/Unicorn separately, to configure Nginx separately, to configure monitoring separately, and to manage each component separately. Doesn&rsquo;t it make sense to consolidate all these moving parts into a single package? Enter Raptor&rsquo;s optional Nginx integration mode: configuration, management and daemon monitoring all directly from Nginx.</li>
<li><strong>Multitenancy</strong>. If you run multiple apps on the same server, then managing all those Puma and Unicorn instances quickly becomes tedious. Raptor&rsquo;s Nginx integration mode allows you to manage all your apps from a single Nginx instance.</li>
<li><strong>Security</strong>. Improve your server&rsquo;s security by easily running multiple apps under multiple user accounts. This way, a vulnerability in one app won&rsquo;t affect all your other apps.</li>
<li><strong>JRuby support</strong>. Like Puma (and unlike Unicorn), Raptor has great JRuby support.</li>
</ul>
<p>So it&rsquo;s a different implementation and also brings features for the future, transparently handling slow clients without causing bottlenecks for your application and avoiding extra layers of protection. And everything in an easy-to-use package (according to their release: you will be able to replace your current server in the Gemfile and bundle install it!)</p>
<p>Raptor is about to be released, so stay tuned for more news and for when it&rsquo;s available for everybody to test their applications with. From what we have seen so far, this one looks like a winner!</p>
<p>Go to <a href="http://www.rubyraptor.org"target="_blank" rel="noopener">their website</a> to know more about it and if you&rsquo;re like me and feel like this is the real deal, <a href="https://www.thunderclap.it/projects/17748-raptor-fast-ruby-web-server"target="_blank" rel="noopener">Thunderclap it!</a></p>
<p><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/473/raptor_square.png" alt="Raptor"  loading="lazy" /></p>
]]></content:encoded><category>performance</category><category>rails</category><category>ruby</category></item><item><title>_Why, Ruby Dramas, and Dynamiting Courtlandt</title><link>https://akitaonrails.github.io/en/2012/09/07/_why-ruby-dramas-and-dynamiting-courtlandt/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2012/09/07/_why-ruby-dramas-and-dynamiting-courtlandt/</guid><pubDate>Fri, 07 Sep 2012 14:37:00 -0300</pubDate><description>&lt;p&gt;&lt;img src="http://s3.amazonaws.com/akitaonrails/assets/image_asset/image/22/why_fountainhead.jpg" alt="_Why is the Howard Roark of the Ruby world" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;I recently wrote an article named &lt;a href="http://www.akitaonrails.com/en/2012/09/03/documentario-do-why-na-rubyconf-2012-denver"target="_blank" rel="noopener"&gt;_Why Documentary at Rubyconf 2012, Denver&lt;/a&gt; reminding people about this person that called himself &amp;ldquo;_Why&amp;rdquo;, who decided to vanish in August of 2009, taking all his work with him, essentially committing virtual suicide.&lt;/p&gt;
&lt;p&gt;It has attracted lots of trolls and haters at the comments section, more discussion than I anticipated, questioning why we praise someone that was crazy enough to destroy all his work, that is obviously not a good role model, and that compared to other titans of programming has done little and with less quality?&lt;/p&gt;</description><content:encoded><![CDATA[<p><img src="http://s3.amazonaws.com/akitaonrails/assets/image_asset/image/22/why_fountainhead.jpg" alt="_Why is the Howard Roark of the Ruby world"  loading="lazy" /></p>
<p>I recently wrote an article named <a href="http://www.akitaonrails.com/en/2012/09/03/documentario-do-why-na-rubyconf-2012-denver"target="_blank" rel="noopener">_Why Documentary at Rubyconf 2012, Denver</a> reminding people about this person that called himself &ldquo;_Why&rdquo;, who decided to vanish in August of 2009, taking all his work with him, essentially committing virtual suicide.</p>
<p>It has attracted lots of trolls and haters at the comments section, more discussion than I anticipated, questioning why we praise someone that was crazy enough to destroy all his work, that is obviously not a good role model, and that compared to other titans of programming has done little and with less quality?</p>
<p>Then, today I heard about this website about Ruby Dramas - that I&rsquo;m not linking. I don&rsquo;t know the author and I even think this is just for fun, but the reactions from the trolls and haters aren&rsquo;t. Essentially it links a few of what we call &ldquo;Ruby Dramas&rdquo;, the discussions that trolls and haters call a waste of time, a demonstration of the immaturity and childish behavior of Ruby programmers.</p>
<p>In 2006, Kathy Sierra wrote an article called <a href="http://headrush.typepad.com/creating_passionate_users/2006/10/dilbert_and_the.html"target="_blank" rel="noopener">Dilbert and the zone of mediocrity</a> where she asserts that if you want to be successful, then you don&rsquo;t want to just please everybody in order to make all of them just like you. You do things in a way that people will love you, but knowing that the consequence is that many others will certainly hate you in the process. It&rsquo;s an all or nothing proposition, if you just make efforts for everybody to like you, you are just being mediocre.</p>
<p>There&rsquo;s a catch. It&rsquo;s not that you make things in order to make people love you. It&rsquo;s just that you should do things in a way that <strong>You Love It</strong>.</p>
<p>What are trolls and haters? In essence, they come back to you every time because they care about some of the same things that you do. But they are not producers, they are looters, plunderers. What they are actually saying is: <strong>&ldquo;You&rsquo;re so good, please me, I want the successful ones to please me, because I can&rsquo;t do what you do, as the weaker one, I deserve to be pleased.&rdquo;</strong></p>
<p>Such is the mentality of altruism and collectivism: people that have less, that can achieve less, deserve what successful people produced, and the successful people must feel guilt for being so much better. The horrible Robin Hood philosophy.</p>
<p>I will allow myself for some philosophical liberty and the use of metaphors to illustrate my point. I have never talked to other Rubyists that knew _Why personally, so I hope they don&rsquo;t get offended if my personal view differs, but again, this is just my personal opinion.</p>
<p>I learned recently that coincidentally the name <strong>&ldquo;Why, the Lucky Stiff&rdquo;</strong> is mentioned in Ayn Rand&rsquo;s famous masterpiece <a href="http://en.wikipedia.org/wiki/Talk:Why_the_lucky_stiff#Real_name"target="_blank" rel="noopener">The Fountainhead</a>. &ndash; by the way, as a non-native English speaker, I was just told that this was a very common expression back in the day. But I couldn&rsquo;t resist leaving this coincidence noted anyway :-)</p>
<p>This novel illustrates the ideal vision of Ayn Rand&rsquo;s Objectivism philosophy. It tells the story of the ideal man: Howard Roark, a talented architect that lives for the passion of his creative skills. He bows to no one, even if it means his own destruction. He lives by his moral principles of voluntary trade and individual achievement.</p>
<p><a href="http://bit.ly/P1H10f"target="_blank" rel="noopener">Objectivism</a> is the foundation of a more pure version of Capitalism (not the version we currently live in), where individual men make voluntary agreements only.</p>
<p>So, the trolls and haters, in The Fountainhead, are personified by the looters such as the Peter Keatings and Ellsworth Tooheys of the world.</p>
<h2>Spoiler Alert!! (do not go forward if you prefer to read the book)<span class="hx:absolute hx:-mt-20" id="spoiler-alert-do-not-go-forward-if-you-prefer-to-read-the-book"></span>
    <a href="#spoiler-alert-do-not-go-forward-if-you-prefer-to-read-the-book" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Summarizing, in the book Roark ends up in a project called Courtlandt, a huge complex for the poor and destitute, where no other architect was able to design a complex that would be within requirements and budget. Only Roark was able to solve the puzzle and he agrees to deliver if, and only if, his work is not modified by any means.</p>
<p>When he does deliver, the other architects think they have a say in his designs and they modify it according to a committee that thinks they know better for &ldquo;the greater good&rdquo;. When Roark knows about it, and sees his creation being built in a way that he did not want, he decides to dynamite and bring it down.</p>
<p>He goes to court and this is his defense:</p>
<div class="video-container">
    <video controls>
        <source src="https://s3.us-east-2.amazonaws.com/blip.tv/Akitaonrails-TheFountainheadDefesaDeHowardRoark654.m4v.mp4">
        Your browser does not support the video tag. [Direct Link](https://s3.us-east-2.amazonaws.com/blip.tv/Akitaonrails-TheFountainheadDefesaDeHowardRoark654.m4v.mp4)
    </video>
</div>
<p><a href="http://www.nasonart.com/personal/lifelessons/fountainhead.html"target="_blank" rel="noopener">Read the full novel version of this remarkable defense speech</a>.</p>
<p>Again, as a metaphor, I can&rsquo;t help picturing _Why in Howard&rsquo;s shoes, talking to his detractors, the trolls and haters, the ones naming the so called &ldquo;Ruby Dramas&rdquo;, the looters, the ones that think they know about &ldquo;the greater good&rdquo;.</p>
<p>Some people question why &ldquo;_Why&rdquo; evokes such &ldquo;irrational worship&rdquo; when at the end of the day he didn&rsquo;t even do so much coding, and his coding was not exactly good enough (according to their own views, of course).</p>
<p>My personal pet theory is exactly because _Why embodies Howard Roark&rsquo;s ideals. He is an artist, just like Roark. He did things in ways that surprised people. He created, he produced, he remained an independent mind. But some contract was breached. I don&rsquo;t know what it is, maybe the agreement was exactly that: &ldquo;leave me alone&rdquo;, &ldquo;do not come after my personal identity&rdquo;, &ldquo;do not tell me how I should do my work&rdquo;.</p>
<p>So when the Tooheys ran over him, he literally dynamited Courtlandt. It was his work, his terms, his choice. And his individual choice was to do what Roark defended:</p>
<blockquote>
  <p>&ldquo;I am an architect. I know what is to come by the principle on which it is built. <strong>We are approaching a world in which I cannot permit myself to live</strong>.</p>
<p>&ldquo;Now you know why I dynamited Cortlandt.</p>
<p>&ldquo;I designed Cortlandt. I gave it to you. I destroyed it.</p>
<p>&ldquo;I destroyed it because I did not choose to let it exist. It was a double monster. In form and in implication. I had to blast both. The form was mutilated by two second-handers who assumed the right to improve upon that which they had not made and could not equal. They were permitted to do it by the general implication that the altruistic purpose of the building superseded all rights and that I had no claim to stand against it.</p>
<p>&ldquo;I agreed to design Cortlandt for the purpose of seeing it erected as I designed it and for no other reason. That was the price I set for my work. I was not paid.</p>

</blockquote>
<p>So Kathy Sierra was right: if you do something remarkable, that you love, some will also love it, and others will denounce and hate it. Trolls are like leeches, they come crawling fast pursuing other people&rsquo;s success in order to feed from it. They do it not by producing, but by evoking the altruistic principles, all against the individual. And this is the evil in our society: we should be able to understand that individual achievement is not to be shared. An individual that achieved success by his own merits deserves every penny of it without the need to feel guilty.</p>
<p>Trolls and Haters name things such as &ldquo;Ruby Dramas&rdquo; because they want your attention. They want the people they quote to be available to please them. And they can&rsquo;t be pleased, so it&rsquo;s an impossible proposition. Trolls exist just for the sake of trolling. That&rsquo;s what Kathy may not have realized when she first wrote her essay: yes, success will attract the haters, but not because they care about what was achieved and want to protect it, but because - like leeches - they want to benefit without producing, on the principle that successful people must please those who cannot achieve.</p>
<p>Roark said: <strong>&ldquo;We are approaching a world in which I cannot permit myself to live&rdquo;</strong>, and so _Why deleted his work, even though many others contributed to it. Again, there was a breach of contract and again I quote Roark:</p>
<blockquote>
  <p>&ldquo;I did not receive the payment I asked. But the owners of Cortlandt got what they needed from me. They wanted a scheme devised to build a structure as cheaply as possible. They found no one else who could do it to their satisfaction. I could and did. They took the benefit of my work and made me contribute it as a gift. But I am not an altruist. I do not contribute gifts of this nature.</p>
<p>&ldquo;It is said that I have destroyed the home of the destitute. It is forgotten that but for me the destitute could not have had this particular home. Those who were concerned with the poor had to come to me, who have never been concerned, in order to help the poor. It is believed that the poverty of the future tenants gave them the right to my work. That their need constituted a claim on my life. That it was my duty to contribute anything demanded of me. This is the second-hander&rsquo;s credo now swallowing the world.</p>
<p>&ldquo;I came here to say that I do not recognize anyone&rsquo;s right to one minute of my life. Nor to any part of my energy. Nor to any achievement of mine. No matter who makes the claim, how large their number or how great their need.</p>
<p>&ldquo;I wished to come here and say that I am a man who does not exist for others.</p>
<p>&ldquo;It had to be said. <strong>The world is perishing from an orgy of self-sacrificing</strong>.</p>
<p>&ldquo;I wished to come here and say that the integrity of a man&rsquo;s creative work is of greater importance than any charitable endeavor. Those of you who do not understand this are the men who&rsquo;re destroying the world.</p>
<p>&ldquo;I wished to come here and state my terms. I do not care to exist on any others.</p>

</blockquote>
<p>And the point of this article is not to idealize _Why, just to state what it means to value individual achievement.</p>
<p>So, many people see value in _Why, enough to forgive him for destroying his Courtlandt and praise him as an inspiration. The trolls and haters are furious, of course, just like Ellsworth Toohey was. It doesn&rsquo;t matter the volume or even the quality of his work. It could&rsquo;ve been 6 lines of code, but if those 6 lines have meant plenty to a lot of people, he would still be remembered. Such is the nature of creation.</p>
<p>We can&rsquo;t get rid of the trolls and haters. I myself know that for everything I do that people love, I know some of the haters by name and address. They are there, sneaking, crawling. But it doesn&rsquo;t matter, because I don&rsquo;t do what I do for their sake, I do for my own. And if you&rsquo;re a person that produces, you should too.</p>
<p>And if anything, to me personally, that&rsquo;s what _Why symbolizes. I don&rsquo;t think we are praising just his person, but what he represented: being a creative individual producing for his own sake.</p>
]]></content:encoded><category>philosophy</category><category>ruby</category><category>biographies</category></item><item><title>_Why Documentary at Rubyconf 2012, Denver</title><link>https://akitaonrails.github.io/en/2012/09/03/why-documentary-at-rubyconf-2012-denver/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2012/09/03/why-documentary-at-rubyconf-2012-denver/</guid><pubDate>Mon, 03 Sep 2012 00:54:00 -0300</pubDate><description>&lt;p&gt;&lt;em&gt;Update:&lt;/em&gt; This article generated some heat. I&amp;rsquo;ve published &lt;a href="http://akitaonrails.com/en/2012/09/07/why-dramas-do-ruby-e-dinamitando-courtlandt"target="_blank" rel="noopener"&gt;another post&lt;/a&gt; with some of my thoughts about the subject later.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.akitaonrails.com/en/2012/09/01/rubyconf-brasil-2012-encerramento"target="_blank" rel="noopener"&gt;RubyConf Brazil 2012&lt;/a&gt; has just finished but the US Rubyconf 2012 will begin on November 1-3, 2012, at Denver, Colorado. While I was finishing my post about the event, I came across &lt;a href="http://www.youtube.com/watch?v=47LtM830ocE"target="_blank" rel="noopener"&gt;this trailer for Why&amp;rsquo;s Documentary&lt;/a&gt;, to be released during the US Rubyconf, if I understood correctly.&lt;/p&gt;
&lt;p&gt;Now, if you&amp;rsquo;re new to the Ruby ecosystem, you may have not heard about this character named &amp;ldquo;Why, The Lucky Stiff&amp;rdquo;. I think 2 of the best articles about him were written by a fellow Brazilian Rubyist, &lt;a href="http://twitter.com/dterror"target="_blank" rel="noopener"&gt;Diogo Terror&lt;/a&gt; to Smashing Magazine in 2010, titled &lt;a href="http://www.smashingmagazine.com/2010/05/15/why-a-tale-of-a-post-modern-genius/"target="_blank" rel="noopener"&gt;_Why: A Tale Of A Post-Modern Genius&lt;/a&gt; and Annie Lowrey for Slate &lt;a href="http://www.slate.com/articles/technology/technology/2012/03/ruby_ruby_on_rails_and__why_the_disappearance_of_one_of_the_world_s_most_beloved_computer_programmers_.single.html"target="_blank" rel="noopener"&gt;Where&amp;rsquo;s _why?&lt;/a&gt;.&lt;/p&gt;</description><content:encoded><![CDATA[<p><em>Update:</em> This article generated some heat. I&rsquo;ve published <a href="http://akitaonrails.com/en/2012/09/07/why-dramas-do-ruby-e-dinamitando-courtlandt"target="_blank" rel="noopener">another post</a> with some of my thoughts about the subject later.</p>
<p><a href="http://www.akitaonrails.com/en/2012/09/01/rubyconf-brasil-2012-encerramento"target="_blank" rel="noopener">RubyConf Brazil 2012</a> has just finished but the US Rubyconf 2012 will begin on November 1-3, 2012, at Denver, Colorado. While I was finishing my post about the event, I came across <a href="http://www.youtube.com/watch?v=47LtM830ocE"target="_blank" rel="noopener">this trailer for Why&rsquo;s Documentary</a>, to be released during the US Rubyconf, if I understood correctly.</p>
<p>Now, if you&rsquo;re new to the Ruby ecosystem, you may have not heard about this character named &ldquo;Why, The Lucky Stiff&rdquo;. I think 2 of the best articles about him were written by a fellow Brazilian Rubyist, <a href="http://twitter.com/dterror"target="_blank" rel="noopener">Diogo Terror</a> to Smashing Magazine in 2010, titled <a href="http://www.smashingmagazine.com/2010/05/15/why-a-tale-of-a-post-modern-genius/"target="_blank" rel="noopener">_Why: A Tale Of A Post-Modern Genius</a> and Annie Lowrey for Slate <a href="http://www.slate.com/articles/technology/technology/2012/03/ruby_ruby_on_rails_and__why_the_disappearance_of_one_of_the_world_s_most_beloved_computer_programmers_.single.html"target="_blank" rel="noopener">Where&rsquo;s _why?</a>.</p>
<p>He inspired an entire first generation of Rubyists around the turn of the century. He wasn&rsquo;t just a programmer, he was a craftsman, literally. The only one I accept calling himself an &ldquo;artist&rdquo; within our programming world. His most famous work is the book <a href="http://mislav.uniqpath.com/poignant-guide/book/"target="_blank" rel="noopener">Why&rsquo;s Poignant Guide to Ruby</a> used by many famous Rubyists you know when they first found out about Ruby.</p>
<p>Then on August 19, 2009 he vanished.</p>
<div class="embed-container">


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/47LtM830ocE"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

</div>
<p>Some say that great men are recognized only after their passing (&ldquo;You either die a hero, or live long enough to see yourself becoming the villain&rdquo;). Maybe his last stroke of genius was to commit &ldquo;virtual suicide&rdquo;, by erasing every digital trace of his existence - he actually deleted all his work, his projects, his source codes that were available online. Thanks to technologies such as Git (by the way, this was a great showcase of the recovering capabilities of distributed versioning systems) almost all of the deleted material was recovered and you can find them in places such as <a href="http://viewsourcecode.org/why/"target="_blank" rel="noopener">here</a>. But the fact that he disappeared and his whereabouts are still unknown kept the myth going and 3 years later he is still remembered.</p>
<p>In 2007 I was conducting a <a href="http://www.akitaonrails.com/English%20Interviews"target="_blank" rel="noopener">series of interviews with several famous Rubyists of our community</a>. And of course, I did send an email to Why himself. And he responded in a very unexpected way. I think it&rsquo;s time to disclose the unabridged content of the email so you understand his exotic personality.</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>Date: Thu, 19 Apr 2007 17:38:59 -0500
From: why the lucky stiff &lt;why@whytheluckystiff.net&gt;
To: fakita@bccl.com.br
Subject: SPAM: Re: Invitation for an Interview for Brazilian Blog

On Wed, Apr 18, 2007 at 10:28:25AM -0300, Fabio Akita wrote:
&gt; First of all let me introduce myself, my name is Fabio Akita, I&#39;ve written
&gt; the first brazilian Rails book called &#34;Repensando a Web com Rails&#34;. I have a
&gt; very well known blog in Brazil called &#34;Akita on Rails&#34;:

It is great to meet you, Fabio.  I love accomplished Brazilians and
try to fill my life with any kind of Brazilian I can find.  I also
try to drink milk from a bag as often as I can.

Do you like apricots?  I like mediterranean apricots only.  But I am
willing to entertain new forms of apricot, as they become available.

&gt; I adore your work! I love creative stuff and you&#39;re an artist.

I appreciate your remarks, but I have a hard time believing that
anyone would like my art.  I will definitely die without recognition
and few will ever see the work I do.  But I like it that way a lot!!

One of the worst things a person can get in life is recognition.
But a scalp rash is very, very bad as well.  I have had some serious
scalp rashes and I also have thrown up blood quite a few times along
the way.

&gt; So here goes the invitation: would you be available for an interview to my
&gt; blog? We could do the usual way via Skype or Gtalk where I can record the
&gt; chat.  Nothing formal or fancy, just a conversation between two tech geeks
&gt; that anyone could enjoy.

I&#39;m afraid I am currently in hiding, my friend Fabio.  As you may
know, I am operating as a freelance professor right now.  I am
unaccredited, unlicensed with an ill-advised curriculum.  There are
no international laws protecting freelance professors from
imprisonment and deportation, so am I forced into hiding.
Fortunately, I have found a rather remarkable hiding place which is
quite safe and has very colorful wallpaper and animal pelts.

I also cannot do interviews unless they are submitted in
handwriting.  I also cannot respond to interviews in anything but
handwriting.  There are several reasons for this rule, but the
foremost reason is that I like making people do unnecessary and
frivolous things.  And forcing interviews to be handwritten is way
too unnecessary and frivolous for me to pass up, oh Fabio can&#39;t you
see that!!

Anyway, it is a pleasure to know you.  I hope a free cart of food
and cheese and DVDs and satin robes and super-long sofas comes
crashing into your house today!!  It will all be free and courtesy
of a steep incline somewhere at a higher elevation.

_why</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Unfortunately I didn&rsquo;t pursue this enough, I was actually planning on sending the interview questions to him, handwritten. :-) In retrospect, I wish I had, it would&rsquo;ve been fun.</p>
<p>And that was Why, an icon for the Ruby community, an original character that can&rsquo;t be copied or replaced and we are very lucky for having had him here. Explore his material, learn his style, transmit his message of education, entertainment, friendliness, mastery and craftsmanship.</p>
]]></content:encoded><category>ruby</category><category>biographies</category></item><item><title>Ruby is Beautiful? What is Beauty?</title><link>https://akitaonrails.github.io/en/2012/09/02/ruby-is-beautiful-what-is-beauty/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2012/09/02/ruby-is-beautiful-what-is-beauty/</guid><pubDate>Sun, 02 Sep 2012 21:46:00 -0300</pubDate><description>&lt;p&gt;If you&amp;rsquo;re a Rubyist you know the meme that &lt;a href="http://web.archive.org/web/20120904122219/http://rubyrogues.com/what-makes-beautiful-code/"target="_blank" rel="noopener"&gt;&amp;ldquo;Ruby allows you to write beautiful code&amp;rdquo;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Several within the community have tried to define what &amp;ldquo;Beautiful Ruby Code&amp;rdquo; is. Most of them managed to show us really beautiful code, but I still haven&amp;rsquo;t seen anyone actually communicate the concept of &amp;ldquo;Beauty&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Enter &lt;a href="http://www.ted.com"target="_blank" rel="noopener"&gt;TED&lt;/a&gt;. If you know me, you know I&amp;rsquo;ve been completely addicted to it for years now, every theme inspires me. And tonight, while having dinner, I watched the great &lt;a href="https://www.ted.com/talks/richard_seymour_how_beauty_feels"target="_blank" rel="noopener"&gt;Richard Seymour&lt;/a&gt; (no, he is not a programmer) talking about this very subject and I was blown away.&lt;/p&gt;</description><content:encoded><![CDATA[<p>If you&rsquo;re a Rubyist you know the meme that <a href="http://web.archive.org/web/20120904122219/http://rubyrogues.com/what-makes-beautiful-code/"target="_blank" rel="noopener">&ldquo;Ruby allows you to write beautiful code&rdquo;</a>.</p>
<p>Several within the community have tried to define what &ldquo;Beautiful Ruby Code&rdquo; is. Most of them managed to show us really beautiful code, but I still haven&rsquo;t seen anyone actually communicate the concept of &ldquo;Beauty&rdquo;.</p>
<p>Enter <a href="http://www.ted.com"target="_blank" rel="noopener">TED</a>. If you know me, you know I&rsquo;ve been completely addicted to it for years now, every theme inspires me. And tonight, while having dinner, I watched the great <a href="https://www.ted.com/talks/richard_seymour_how_beauty_feels"target="_blank" rel="noopener">Richard Seymour</a> (no, he is not a programmer) talking about this very subject and I was blown away.</p>
<p>Find the video below, but let me add a few words of my own. In our small world of programmers and technologists, we have lots of discussions around &ldquo;Form&rdquo; vs &ldquo;Function&rdquo;, as if we should choose one over the other, or balance one against the other.</p>
<p>I&rsquo;m of the same opinion as Richard: it is not a matter of &ldquo;Form&rdquo; <strong>VS</strong> &ldquo;Function&rdquo;. The correct way of thinking is &ldquo;Form&rdquo; <strong>IS</strong> &ldquo;Function&rdquo;. And beauty is something you <strong>feel</strong>, before any analysis or rationalization.</p>
<p>Your reaction to beauty is directly tied to what you know and what you&rsquo;ve experienced. Without living and without learning, you won&rsquo;t find beauty. Back to programming, it&rsquo;s impossible for someone that just started to write software, or even someone that already did a few small projects, to grasp the concept of &ldquo;beauty&rdquo;.</p>
<p>It&rsquo;s only after some time, some experience, and some learning that they&rsquo;ll start to grasp what beauty possibly feels like.</p>
<p>With that comment, please watch Richard Seymour (if you want subtitles for your native language, go to the <a href="https://www.ted.com/talks/richard_seymour_how_beauty_feels"target="_blank" rel="noopener">original site</a> so you can choose subtitles):</p>
<!-- dead Flash embed removed (service offline): flash -->
<p>Knowledge and Experience are everything. Ignorance doesn&rsquo;t know beauty.</p>
]]></content:encoded><category>philosophy</category><category>ruby</category><category>off-topic</category></item><item><title>Chatting with Luis Lavena (Ruby on Windows)</title><link>https://akitaonrails.github.io/en/2008/07/02/chatting-with-luis-lavena-ruby-on-windows/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2008/07/02/chatting-with-luis-lavena-ruby-on-windows/</guid><pubDate>Wed, 02 Jul 2008 14:16:00 -0300</pubDate><description>&lt;p&gt;This time I interviewed &lt;a href="http://blog.mmediasys.com/"target="_blank" rel="noopener"&gt;&lt;strong&gt;Luis Lavena&lt;/strong&gt;&lt;/a&gt;. If you&amp;rsquo;re a Ruby developer working on Windows, you owe him a lot! After all he is the maintainer of &lt;a href="http://github.com/luislavena/rubyinstaller/tree"target="_blank" rel="noopener"&gt;One-Click Ruby Installer&lt;/a&gt;, the main Windows Ruby distribution. It is a lot of work to maintain such a distro and Luis explains all the hoops necessary to achieve this. The main message: we need more collaborators! Anyone can rant, but there are a few who actually step down from the pedestal and get their hands dirty.&lt;/p&gt;</description><content:encoded><![CDATA[<p>This time I interviewed <a href="http://blog.mmediasys.com/"target="_blank" rel="noopener"><strong>Luis Lavena</strong></a>. If you&rsquo;re a Ruby developer working on Windows, you owe him a lot! After all he is the maintainer of <a href="http://github.com/luislavena/rubyinstaller/tree"target="_blank" rel="noopener">One-Click Ruby Installer</a>, the main Windows Ruby distribution. It is a lot of work to maintain such a distro and Luis explains all the hoops necessary to achieve this. The main message: we need more collaborators! Anyone can rant, but there are a few who actually step down from the pedestal and get their hands dirty.</p>
<p><a href="http://www.flickr.com/photos/diegal/325572435/"target="_blank" rel="noopener"><img src="http://s3.amazonaws.com/akitaonrails/assets/2008/7/2/325572435_f1f1382372.jpg" alt=""  loading="lazy" /></a></p>
<p><strong>AkitaOnRails:</strong> Ok. So, let&rsquo;s start. First of all thank you for your time. This is very funny because we are like 5 hours apart. You&rsquo;re in Paris right now, but I understand you were in Argentina. Can you tell us what you are doing now?</p>
<p><strong>Luis Lavena:</strong> Yeah, funny indeed. Right now I&rsquo;m Technical director of an interactive and design agency with offices in NY and Paris. My job is to bridge the design field with the technology one, mostly on web based application development.</p>
<p>I&rsquo;m from Argentina, live there, family and friends. I moved a few months ago to boost some developments and get first steps of the new organization in place.</p>
<p>I&rsquo;m from a small province named Tucuman, northwest area of Argentina (1200 kms from Buenos Aires to be exact)</p>
<p><strong>AkitaOnRails:</strong> Awesome, have you ever been in Brazil? Do you have contact with other Latin America Railers?</p>
<p><strong>Luis Lavena:</strong> Even though Brazil is so close from Argentina I have never been there, which is a shame. I have several friends that lived there over the years.</p>
<p>I keep in touch with several Rubists and Railers of Latin America, but most with the ones in Argentina due to several meetings we had during the years <a href="http://lista.rubyargentina.com.ar"target="_blank" rel="noopener">RubyArg</a> mailing list has been working.</p>
<p><strong>AkitaOnRails:</strong> I am very interested in understanding how the Railers are organizing themselves in Argentina as we, in Brazil, are a growing community as well. Do you see new programmers going straight to Rails or is it the usual move from Java/others to Rails? Are companies adopting it, or Rails (and Ruby in general) still has a long way to go there as well?</p>
<p><strong>Luis Lavena:</strong> Well, there is a huge number of developers that came from Java and dotNET stuff (mostly Java) and they are playing with Rails, there is also lot of developers that do Ruby for administrative stuff or even creating games with it.<br>
Companies that develop software still need to adopt Ruby/Rails for their business, the biggest problem with that is the lack of support shaped as companies like Sun or some consulting services for Java. (or even Microsoft).</p>
<p><strong>AkitaOnRails:</strong> Going back to the past, how did you start in programming in general? Did you study computer science, or were you dragged in there in some other way? And, finally, how did you stumble upon Ruby and Rails?</p>
<p><strong>Luis Lavena:</strong> It&rsquo;s funny, I started programming back in 1989, playing with sprites and GOTO&rsquo;s with BASIC on a Z80 computer.</p>
<p>I officially didn&rsquo;t finish my degree on CS, since job and fun stuff distracted me away from it. I first met Ruby back in 2001, loved its syntax, enjoyed its verbosity but it was not mature enough for my needs, at least not in Windows.</p>
<p>Even though I was using Python for so many years, I internally used Ruby to manage several stuff, from simple scripts to later rake tasks that helped us build our tools.</p>
<p>With Rails it was kind of different, since we started to look for alternatives to Zope and we bet on Rails at that time (0.10 or 0.12 at that time, if memory plays nice with me).</p>
<p>I can say I don&rsquo;t regret the bet on Rails at that time.</p>
<p><strong>AkitaOnRails:</strong> It is very interesting to see professionals like you moving out from your zone of comfort toward something &lsquo;unknown&rsquo; as Ruby and Rails. Most programmers are very defensive and even aggressive on trying to find justifications for not using neither. Did you feel like that back then? What drove you towards Ruby?</p>
<p><strong>Luis Lavena:</strong> Well, I&rsquo;m used to change languages to fit my needs.<br>
Keep in consideration that our first choice was pre-J2EE era or dotNET stuff, we analyzed which would provide us better solutions in the long run and we decided to avoid them.</p>
<p>Java stuff sounded at that time, and until today, expensive for business. Argentina is not a country where you will find customers with huge budgets to invoice them the cost of using tools designed for other markets.</p>
<p>Banks and such can pay the luxury of have everything running with J2EE, but that doesn&rsquo;t work when you try to go smaller and agile. (mostly based on experiences with the market flow in Argentina).</p>
<p><strong>AkitaOnRails:</strong> It is even more daunting considering that you decided that you wanted Ruby on Windows, you probably didn&rsquo;t find anything reasonable and decided to tackle the problem yourself. Is that how it happened?</p>
<p><strong>Luis Lavena:</strong> I&rsquo;ve been forced to use Windows for many years, mostly related to hardware development in the video broadcast field. Moreover, I&rsquo;m a BSD user and Linux one, even played some years with Macs and lately with OSX.</p>
<p>So that restriction forced me to build most of my tools around that limitation.<br>
Ruby allowed me to enjoy that limitation by being expressive, which made me more productive in that field.</p>
<p>Ruby is not capable of handling my main requirements for video processing, but it still powers 70% of my environment, along with Open Source Software and Freeware.</p>
<p>I&rsquo;ve been using Ruby for so long, that I thought the community, now that it&rsquo;s growing, would maybe value the experience and the willingness to help in this particular scenario.</p>
<p>So instead of just scratching my itch in the shadow, I decided to contribute back and help others that search for the same stuff. So you can say I&rsquo;m trying to balance my karma.</p>
<p><strong>AkitaOnRails:</strong> Americans probably don&rsquo;t understand this but in emerging countries such as Brazil, people don&rsquo;t actually have much choice, most are not educated enough (<em>cof</em> english <em>cof</em>) and so they find lots of barriers. The last resort for everybody is Windows. I think it is the same thing in Argentina. Railers here don&rsquo;t simply migrate to Macs or Linux, I would say that at least 90% of all developers are locked in to Windows for one reason or another. Is it the same in Argentina, I presume?</p>
<p><strong>Luis Lavena:</strong> Even though I don&rsquo;t like it, I must agree. Thankfully the Universities started to change that some years ago, giving talks and been more open to Linux community, which grew a lot.</p>
<p>Still, there are plenty of users and developer that are locked in to some corporate / mid-size environments or they require to run Windows for some proprietary hardware or such.</p>
<p>So, we (as the community) can&rsquo;t get to those developers without being more open minded or provide tools that ease the path between their current environment and alternative tools.</p>
<p><strong>AkitaOnRails:</strong> But for some reason there seems to be near to zero interest from the community on supporting Ruby on Windows. I mean, there are people like you, some RubyGem developers who go through all the trouble of making available a binary for win32, but it is not enough it seems. How did the <a href="http://rubyforge.org/projects/rubyinstaller/"target="_blank" rel="noopener">One-Click Ruby Installer</a> begin, did you create it or you inherited it?</p>
<p><strong>Luis Lavena:</strong> Yeah, I agree with you, but I cannot blame them, after all, everybody just scratches their own itch ;-)</p>
<p>I&rsquo;ve inherited One-Click Installer from <a href="http://curthibbs.wordpress.com/"target="_blank" rel="noopener">Curt Hibbs</a>, who also inherited from <a href="http://en.wikipedia.org/wiki/Andy_Hunt_%28author%29"target="_blank" rel="noopener">Andy Hunt</a> and other contributors.</p>
<p>The truth is that for many years I&rsquo;ve been using my own version of Ruby, compiled in-house, so we had control over it. We didn&rsquo;t patch it in any way, we like to have the whole process documented and automated, so we can take a look to the specific components updated that introduced conflicts.</p>
<p>One-Click Installer, on the other hand, relies on some builds made by the current ruby-core developers and maintainers, which make the process of finding the proper dependencies a bit hard. That build also imposed other problems, but that will require more time to explain</p>
<p><strong>AkitaOnRails:</strong> Haha, I want to dive in to the more technical stuff so people can better understand the current situation on Windows. How different is Ruby on Windows compared to Ruby on Linux, for instance? The most obvious thing is that any Gem with C Extensions without proper binaries for Windows will fail. Trying to execute shell commands will fail and <a href="http://www.zenspider.com/ZSS/Products/RubyInline/"target="_blank" rel="noopener">RubyInline</a> as well. What else?</p>
<p><strong>Luis Lavena:</strong> Hehe, that&rsquo;s just the tip of the iceberg, let me show you one example. Let&rsquo;s say that you have a package ABC that was built for your current distribution of Linux. That specific version of Linux links to a common runtime that handles the basic commands like file handling, console, etc. That is often called CRT (C Runtime) and on Linux, glibc.</p>
<p>So, your distro of Linux is linked to this glibc version A.B.C. If your distribution upgrades glibc version (like from 2.2 to 2.5) then you&rsquo;re forced to:</p>
<ol>
<li>upgrade all your installed packages, or</li>
<li>build everything from scratch.</li>
</ol>
<p>I&rsquo;ve even heard of some of these upgrades go so bad that users are forced to start from scratch. Windows, on the other hand, cannot break 2 billion applications just because of a change of CRT, so they keep old versions and maintain compatibility in the MSVCRT.dll file (where the base version is 6.0).</p>
<p>A plus for Windows is that you can have several CRT co-existing in your OS, the bad thing is that you cannot safely link to one CRT and use components that link to another version without worrying about segfaults and such stuff.</p>
<p>I tried to condense this information in <a href="http://blog.mmediasys.com/2008/01/17/ruby-for-windows-part-1/"target="_blank" rel="noopener">a post</a> some time ago. So you can see, the lack of development tools is not the worst problem dealing with Windows development.</p>
<p><strong>AkitaOnRails:</strong> Interesting. And another thing is the Visual Studio compiler vs <a href="http://www.mingw.org/"target="_blank" rel="noopener">MinGW</a>. Can you give us a glimpse on why you chose MinGW? Is it just because VS is commercial and developers would have to pay?</p>
<p><strong>Luis Lavena:</strong> Visual Studio is great, but only when you can pay for it. The free versions lack some stuff that is very useful, like Profile-Guided Optimization (PGO) which is being used to build Windows binaries of Python, as an example.</p>
<p>The thing with VS, even the free versions, is that you&rsquo;re not allowed to distribute them, I think it is even illegal to link to the download URL/page of it. So even for our automated sandbox project, Visual Studio would be required to be manually downloaded, installed and configured.</p>
<p>Thankfully in the latest versions you don&rsquo;t need to install Platform SDK kit, which was 1GB. VS versions link only to the latest version of MSVCRT, which then force us to relink every library that ruby depends on with it (and Ruby source code depends on lots of externals).</p>
<p>Also, Ruby doesn&rsquo;t use the safe CRT version of string copy functions, so you need to use a compiler flags just to avoid them… So after weeks of hard work getting it built with VC8 and every dependency, you end with something that performs almost the same, since there is no performance gain (but now you have less hair).</p>
<p>MinGW, on the other hand, was closer to a Linux environment, so most of the tools worked out of the box. The good part was that we didn&rsquo;t need to build all the dependencies with it, since by default everything links with MSVCRT (the default CRT on Windows). MinGW also provides some cross-compilation tools that lets you build, using Linux environment, shared libraries (dll) and executables for Windows.<br>
I can consider that a plus, dunno what others think about it</p>
<p><strong>AkitaOnRails:</strong> Wow, this is really overwhelming and I recommend anyone interested in the details to take a look at your <a href="http://blog.mmediasys.com/"target="_blank" rel="noopener">blog</a>. But all that said, you now have everything in place, a proper process and such, I assume. If I am a Windows C developer and I want to contribute, where should I go first, I mean, so I can know what tools to use, how to build stuff and so on?</p>
<p><strong>Luis Lavena:</strong> That&rsquo;s the good part! <a href="http://blog.robustlunchbox.com/"target="_blank" rel="noopener">Gordon Thiesfeld</a> and I have been working on two packages for new One-Click Installer: Runtime and Developer Kit.</p>
<p>Runtime ships the minimum Ruby+RubyGems so you get started, and it can also be used as modules for other installations. The DevKit provides the MinGW environment so you create Ruby extensions or even install the ones that are not pre-built for Windows but they are easy to get it.</p>
<p>This DevKit will not only let you get easily working with Ruby on Windows (and have access to some great and cool Rubygems) but also lets you contribute back to Ruby project. How? Easily, the Ruby Installer project (on <a href="http://github.com/luislavena/rubyinstaller/tree/master"target="_blank" rel="noopener">Github</a>) is self-hosted. What does it mean? It is possible for you to replicate our development environment anywhere, hack your changes or even debug Ruby&rsquo;s own C code and contribute back to the community. We have been doing that for several months, and it&rsquo;s working, how cool is that?</p>
<p><strong>AkitaOnRails:</strong> That sounds awesome, I didn&rsquo;t know that, and I bet lots of developers didn&rsquo;t also. So I hope C developers reading this can get up to speed with this now. Another detail: RubyGems. How difficult is it to port a Gem with C Extensions to provide a Windows binary when you install it?</p>
<p><strong>Luis Lavena:</strong> Oh, that requires that some developers don&rsquo;t fall into platform specific tricks to make their tools work. One example, that is also a bad practice, is to use hardcoded paths…</p>
<p>Another one is to rely on the existence of some external tools, which sometimes are not available or developers/users didn&rsquo;t install it. And I&rsquo;m not talking about Linux-Windows platform issues, even between Linux distros that is a problem.</p>
<!-- dead Flash embed removed (service offline): flash -->  
<p><a href="http://www.vimeo.com/1266418?pg=embed&amp;sec=1266418"target="_blank" rel="noopener">Installing Gems on RubyInstaller</a> from <a href="http://www.vimeo.com/luislavena?pg=embed&amp;sec=1266418"target="_blank" rel="noopener">Luis Lavena</a> on <a href="http://vimeo.com?pg=embed&amp;sec=1266418"target="_blank" rel="noopener">Vimeo</a>.</p>
<p><strong>AkitaOnRails:</strong> So it is pretty much dependent on the quality of the original Gem, right? The cleaner the code the easier to port it, of course. But does your DevKit provide some shortcuts to achieve that? And what about RubyInline, does it simply break down?</p>
<p><strong>Luis Lavena:</strong> Yeah, I&rsquo;ve learned over the years that you shouldn&rsquo;t assume anything about the environment your application is supposed to run, in that way, you avoid those mistakes.</p>
<p>Thankfully RubyInline is playing nice with Ruby Installer (One-Click Installer that uses MinGW) for a few versions back (Thanks goes to Ryan Davis to include those patches).</p>
<p>The current, VC6 build of One-Click Installer is not safe, since you need VS6 to work, which is no longer available. I&rsquo;ve heard of users enjoying Sequel, Ambition and ImageScience on Windows thanks to those patches.</p>
<p><strong>AkitaOnRails:</strong> Correct me if I am wrong, but isn&rsquo;t it a way to embed C code snippets mixed in Ruby code? This means it will natively compile this snippet to run? How does it achieve this in a Windows environment that doesn&rsquo;t have compilers by default?</p>
<p><strong>Luis Lavena:</strong> We managed to sneak some patches to Hoe and RubyInline that &ldquo;bundles&rdquo; the pre-built extensions into the gems, so users don&rsquo;t need a compiler in those cases.</p>
<p>Anyway, right now using VC6 build of Ruby requires man power to maintain those gems and keep up with new releases, which takes time. Up until now I was the only man in the show (since we own some VC6 licenses). Building everything for everyone is a burden I&rsquo;m looking forward to drop into DevKit.</p>
<p><strong>AkitaOnRails:</strong> Are you the ones maintaining the Windows versions of Gems or each Gem developer takes care of his own project? Is there a central repository for Windows-ready Gems? Is the DevKit already available, by the way?</p>
<p><strong>Luis Lavena:</strong> For some projects I&rsquo;m the only one maintaining gems for Windows, for others I only had contributed patches and other users manage the builds. There is no central repository for Windows gems since I want RubyForge to be the central one.<br>
In any case, I&rsquo;m pushing MinGW specific ones based on github forks here:</p>
<pre><code>gem list --remote --source http://gems.rubyinstaller.org</code></pre>
<p>The devkit is already available, but we are wrapping it into a good Windows Installer package. You can get your hands dirty and grab the sandbox project from <a href="http://github.com/luislavena/rubyinstaller">Github</a> to get your environment, or simply <a href="http://www.rubyinstaller.org/sandbox/">download the packages</a>.</p>
<p><strong>AkitaOnRails:</strong> So, as far as tools and processes are concerned you're doing a great job. But then there is the Ruby code that, by itself, is a big challenge from what I hear. You mentioned to me that it doesn't even look like C. What are the biggest problems? Technical or getting help from the Ruby-Core mailing list, or both? And what about test suites, how are you squashing compatibility bugs?</p>
<p><strong>Luis Lavena:</strong> To be honest, sometimes peeking into Ruby C code gives me headaches. There are lot of macros and definitions and macro conditions that happens in the middle of a if .. else block… The hardest part, besides tracing the bug is getting feedback from ruby-core. Several times I've <a href="http://blog.mmediasys.com/2008/03/06/is-windows-a-supported-platform-for-ruby-i-guess-not/">expressed</a> my concerns about it on mailing lists, #irc and on my blog.</p>
<p>Several times I asked if it was OK to get some errors in the unit tests of Ruby itself and sometimes got answers, but sometimes didn't. Thankfully we no longer need to base our testing quality in bundled unit tests of Ruby. We started to find issues with the Ruby implementation on Window using the Ruby Specs created by the guys at the Rubinius project and that most of the Implementations (IronRuby and jRuby) actively contribute and use as foundation of their interpreters.</p>
<p><strong>AkitaOnRails:</strong> So, speaking of which, <a href="http://blog.emptyway.com/2008/04/06/the-rubyspecs-quick-starting-guide/">RubySpecs</a> how far is Ruby on Windows from passing it through? Or is it already?</p>
<p><strong>Luis Lavena:</strong> Well, that's a big tasks. First we started making MSpec to work properly on Windows, since RubySpec require some audit to remove some hardcoded paths in it. So we started to add guards around things that are not supported or don't even work on Windows in <span class="caps">MRI</span>.</p>
<p>That takes longer since we need to review the results on each platform, dig into the Ruby documentation (that is sometimes lacking) or take a deep breath and look at the C code to find what is actually doing.</p>
<p>If we had <strong>more man power</strong>, maybe we could finish guarding all the code and get a clear running specs on Windows. Right now there are many that just break or segfault.</p>
<p><strong>AkitaOnRails:</strong> You should document this process so people can help, if you didn't already :-) Now speaking of more practical stuff: Ruby on Windows, today, is it a viable runtime to run Rails apps on Windows? Even production apps? You worked with Zed Shaw on Mongrel for Windows, right? Did you try the newest FastCGI support from Microsoft for <span class="caps">IIS</span>?</p>
<p><strong>Luis Lavena:</strong> Hehee, documentation, documentation, it's totally overrated. We planned to have several screencasts in the RubyInstaller website, but it just remains as <em>'coming soon'</em> for now.</p>
<p>Not only you can develop Rails applications in Windows (as I do too), but I know several companies that run it side-to-side with <span class="caps">IIS</span> or even Tomcat.</p>
<p>Even 2 years after Zed created it, Mongrel still rules the scene of Ruby web servers. I didn't do too much to Mongrel itself, since Zed created something that worked out of the box on Windows with small tweaks.</p>
<p>I created something to run Mongrel as a service (mongrel_service), which helped several people to sneak in Ruby and Rails into their corporate environments, even talking to <span class="caps">MSSQL</span> Servers.</p>
<p>I personally didn't test the <a href="http://mvolo.com/blogs/serverside/archive/2007/02/18/10-steps-to-get-Ruby-on-Rails-running-on-Windows-with-IIS-FastCGI.aspx"><span class="caps">FCGI</span> support on <span class="caps">IIS</span></a>, but I was the one fixing it to be bundled with One-Click Installer so some users could enjoy it. We could say it works.</p>
<p><strong>AkitaOnRails:</strong> About performance, Windows seems to have an inherent condition: in the same machine when I start, let's say, a simple <span class="caps">IRB</span> in Windows, then I dual boot to Linux and run it, it seems to open up much faster (not exactly a scientific experiment :-). What is your experience around Ruby performance on Windows?</p>
<p><strong>Luis Lavena:</strong> There are performance issues related to the C code being generated by the compiler, and issues related to the OS and I/O handled by it. Loading <span class="caps">IRB</span> on Windows could be requiring RubyGems in the background, which in turn needs to scan and load all the gems specifications. I try to keep <code>RUBYOPT=rubygems</code> out of my environment variables.</p>
<p><strong>AkitaOnRails:</strong> By the way, why I have the impression that I see <span class="caps">RUBYOPT</span>=rubygems being recommended in every windows tutorial I see?</p>
<p><strong>Luis Lavena:</strong> <code>RUBYOPT=rubygems</code> is the part of the magic we must avoid.<br>
On Linux, if you start creating a script and you need a gem, you start with:</p>
<hr>
<pre><code>require 'rubygems'
require 'some_gem'</code></pre>
<p>The same should be done for Windows, it is not painful, it's good practice. <span class="caps">RUBYOPT</span> is a shortcut that I dislike, I haven't seen a Linux distro that enables that by default, and I dislike that being set on Windows. (of course, that's my personal point of view)</p>
<p>So to avoid falling into standard testing procedures, I keep using a simple but good sudoku solver that exercise recursion, array and conditions of the VM instead of being IO bound.</p>
<p>You can see that, with funny results on <a href="http://blog.mmediasys.com/2008/04/24/contributions-speedup-and-less-quirks-for-us/">my blog</a> (see <em>"Rubinius, RubySpecs, and speed."</em> section of the post).</p>
<p>The main thing is that VC6 make it slow. Then you have I/O bound stuff (I/O stuff on Windows is not as good as Linux). I consider the default VC6 build of Ruby on Windows painfully slow. On the other hand, the MinGW one is snappier but I still think that there is a huge path for improvement.</p>
<p><strong>AkitaOnRails:</strong> So, overall, Ruby on Windows is always evolving which is great, runs great on Windows, which is remarkable, but it could use some more help, right? Do you think more Windows C developers would help? I mean, adding more hands would help improve its quality?</p>
<p><strong>Luis Lavena:</strong> Definitely!</p>
<p><strong>AkitaOnRails:</strong> What kind of developers, I mean what one should know to help?</p>
<p><strong>Luis Lavena:</strong> Dunno if Ruby "core" will accept that, I lately only hear the fork word around <span class="caps">MRI</span> ruby. Moreover, we can squash bugs in the Ruby for Windows implementation, but we cannot improve the quality too much since those changes would affect other platforms too.</p>
<p>The bad thing is that there is no clear separation by platform of specific code, everything is around a series of macros and compilation conditions that makes it hard to track (for the non-sadistic developers).</p>
<p><strong>AkitaOnRails:</strong> Which reminds me of the Phusion guys with their <a href="http://www.rubyenterpriseedition.com/">Enterprise Edition</a> which is a fork of <span class="caps">MRI</span>. Did you try to take a look on the copy-on-write GC patches from them? Maybe have it on the Windows version? Ruby on Windows itself is a 'fork'. You end up having to synchronize your trunk with theirs, is that how it works?</p>
<p><strong>Luis Lavena:</strong> Honestly I didn't have time to look at Enterprise Edition, even though I followed all the posts and the discussion of those patches in ruby-core. The funny thing is that the latest releases of the Ruby 1.8.6 branch are giving me headaches (more than looking at the C code). They cannot even complete the self-tests and segfault with some extensions like the mysql gem.</p>
<p><strong>AkitaOnRails:</strong> Yes, it has been causing a lot of fuzz around the community, and it should. Hope they can get around it soon. Well, I think I already took a lot of your time. Is there any subject you would like to tackle, or at least some message for your younger brazilian community?</p>
<p><strong>Luis Lavena:</strong> Yeah, don't be afraid to ask questions, don't feel ashamed for using Windows as Platform. You can accomplish great applications using Windows, and you can infiltrate more easily into corporate environments with it.</p>
<p><strong>AkitaOnRails:</strong> Oh, which reminds me of one last question that everybody asks me all the time – and I shall forward it to you, as you're a Windows developer: what are your tools of choice to edit Ruby/Rails projects?</p>
<p><strong>Luis Lavena:</strong> I mostly use Free or Open Source stuff, so I've been using <a href="http://www.activestate.com/store/download.aspx?prdGUID=20f4ed15-6684-4118-a78b-d37ff4058c5f">Komodo Edit</a> (not Pro) and <a href="http://www.pnotepad.org/">Programmer Notepad</a>, since sometimes I use them to work on C, FreeBASIC and Assembler code for embedded hardware.</p>
<p>Lately I've been using a lightweight Editor called <a href="http://intype.info/home/index.php">Intype</a> that ships with some bundles to mimic TextMate, but I really don't take advantage of them. I used NetBeans for a while, but after 500MB I just closed it :-)</p>
<p><strong>AkitaOnRails:</strong> Haha, and what would you recommend for a beginner Rails programmer?</p>
<p><strong>Luis Lavena:</strong> To get started NetBeans is good, but with practice they will learn that even notepad is enough to code.</p>
<p>(PS: We are already including Enterprise patches for latest issues on MinGW build! :-)</p>
<p><strong>AkitaOnRails:</strong> Haha, right. Well, I think this is it. I think this will reach a broader audience and call the attention of Windows developers out there. Thanks a lot!</p>
<p><strong>Luis Lavena:</strong> Thanks to you Fabio.</p>
<p style="text-align: center; margin: 5px"><a href="http://www.flickr.com/photos/diegal/325555121/"><img src="http://s3.amazonaws.com/akitaonrails/assets/2008/7/2/325555121_e6e22ea444.jpg" alt=""></a></p>
]]></content:encoded><category>interviews</category><category>ruby</category><category>microsoft</category></item><item><title>Chatting with Evan Phoenix</title><link>https://akitaonrails.github.io/en/2008/02/11/chatting-with-evan-phoenix/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2008/02/11/chatting-with-evan-phoenix/</guid><pubDate>Mon, 11 Feb 2008 22:42:00 -0200</pubDate><description>&lt;p&gt;&lt;img src="http://s3.amazonaws.com/akitaonrails/assets/2008/2/11/524655980_8e68a871a0.jpg" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;It was &lt;a href="https://akitaonrails.github.io/en/2007/12/15/conversando-com-avi-bryant-parte-1"&gt;Avi&lt;/a&gt; &lt;a href="https://akitaonrails.github.io/en/2007/12/22/conversando-com-avi-bryant-parte-2"&gt;Bryant&lt;/a&gt; that evangelized the neat idea of “turtles all the way”, meaning that for a language to be called ‘complete’ it should be able to extend itself. So, the ideal world would have Ruby being extended in Ruby, not in C. JRuby goes as far as it can building up a sandbox for Ruby code to run under the JVM. As cool as it is, we still rely on Java to fully extend it.&lt;/p&gt;</description><content:encoded><![CDATA[<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2008/2/11/524655980_8e68a871a0.jpg" alt=""  loading="lazy" /></p>
<p>It was <a href="/en/2007/12/15/conversando-com-avi-bryant-parte-1">Avi</a> <a href="/en/2007/12/22/conversando-com-avi-bryant-parte-2">Bryant</a> that evangelized the neat idea of “turtles all the way”, meaning that for a language to be called ‘complete’ it should be able to extend itself. So, the ideal world would have Ruby being extended in Ruby, not in C. JRuby goes as far as it can building up a sandbox for Ruby code to run under the JVM. As cool as it is, we still rely on Java to fully extend it.</p>
<p>Enter <a href="http://rubini.us/"target="_blank" rel="noopener">Rubinius</a> and its author <strong>Evan Phoenix</strong> , currently a full-time employee for <a href="http://www.engineyard.com/"target="_blank" rel="noopener">EngineYard</a>. Rubinius borrows heavily from Smalltalk’s concepts of a virtual machine and does as little as possible in C just for the bootstrap and all the rest is developed over pure Ruby.</p>
<p>Rubinius answers lots of questions about going forward over the current Ruby MRI but also raises several other questions that I hope we can nail down today in this interview with Evan himself.</p>
<p>So let’s get started.</p>
<p><strong>AkitaOnRails:</strong> It is a tradition now in my interviews to ask about the background of the programmer. What was your path? I mean, what made you come in to the programming world and how did you get into Ruby?</p>
<p><strong>Evan Phoenix:</strong> I started programming in high-school with a friend of mine. We started a small computer company doing odds and ends and I really got into it. I had gotten into Linux a few years before that, so programming became a natural extension of using Linux.</p>
<p>When I applied to college, I declared myself as a Computer Science major on the application, so I’ve been doing this since about then I guess.</p>
<p>As for Ruby, I got into it in about 2002, when I first moved to Seattle. A friend had just found it and was writing some fun stuff in it and I picked it up on his suggestion. Eventually, I found the seattle.rb, and have been working in Ruby since.</p>
<p><a href="http://www.engineyard.com/"target="_blank" rel="noopener"><img src="http://s3.amazonaws.com/akitaonrails/assets/2008/2/11/ey_logo.png" alt=""  loading="lazy" /></a></p>
<p><strong>AkitaOnRails:</strong> EngineYard seems to have great faith in the future of Rubinius. How did this relationship start? Can you tell us what are EngineYard’s expectations regarding your work for them?</p>
<p><strong>Evan Phoenix:</strong> The relationship started mainly with them approaching me about working for them, on Rubinius. So they saw promise in Rubinius on their own, from my presentations and such, and approached me.</p>
<p>Their expectations are that I make Rubinius the best Ruby VM it can be. That’s my basic mandate with them. They’re pretty much the ideal stewards of the project. They allow me to work at the pace I want, they understand the rigors of the work I’m doing, and give me a lot of freedom.</p>
<p><strong>AkitaOnRails:</strong> Now let’s get into Rubinius. For non-starters how would you define Rubinius? We all know that this is an alternative Ruby implementation, so maybe it would be good to point out what makes it different than the MRI. What are the project main goals?</p>
<p><strong>Evan Phoenix:</strong> One of the primary goals is to have as much of the system written in Ruby itself. With MRI, none of the core classes are implemented in Ruby, all are in C. So we wanted a system that was easier to work with, and thus written in Ruby itself.</p>
<p>Another thing we’ve done is enrich the number of things which are objects, which adds considerable power. An easy example is the CompiledMethod class which Rubinius has. It contains the bytecode representation of a method and can be inspected, manipulated, etc, just like any other object. This opens a lot of new doors with regard to how problems can be solved.</p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2008/2/11/Picture_1_1.png" alt=""  loading="lazy" /></p>
<p><strong>AkitaOnRails:</strong> It’s not so obvious to the brazilian audience when we speak of “Squeak”, “Garnet”. Smalltalk is probably less known here than Ruby. The point is that it is well known that you were inspired by the way Squeak is implemented. This led to features like “Cuby”. Can you explain what is so great about the way Squeak is implemented and how it is helping you in the Rubinius project?</p>
<p><strong>Evan Phoenix:</strong> Well, we’re currently in the process of developing Garnet/Cuby, so those tools aren’t in use really yet. But almost the entire system architecture of Rubinius is modeled off the original Smalltalk-80 Virtual Machine. It defined things like CompiledMethod, etc, which I took name for name into Rubinius.</p>
<p>In addition, the execution model of Rubinius is almost identical to Squeak. A good example is the way in which the system calls methods and figures out how to keep track of where to return control to when a method call returns. All that information is kept in first class objects called MethodContexts. In a language such as C, that information is stored on a process’s memory stack. By keeping the data in first class objects, we’re able to query them directly to find out information about the running system. It also vastly simplifies how the garbage collector works.</p>
<p><strong>AkitaOnRails:</strong> Today you have shotgun. I read somewhere that you consider it ‘cheating’ because this is not an interpreter for Ruby written in Ruby, which will lead to Cuby. It’s more kind of a bootstrapping to ease development. What’s the current state of shotgun, can we use it outside its purpose of developing Rubinius?</p>
<p><strong>Evan Phoenix:</strong> Shotgun is a virtual machine written in C that provides instructions and primitive operations for running a Ruby-like language. Shotgun itself actually has no knowledge of parsing, compiling etc. It has a very simple way to load code in, and a way to execute it. You could easily write a new language which targets shotgun, in fact, <a href="/2007/06/21/chatting-with-ola-bini-jRuby-core-team-member/">Ola Bini</a> and I have talked a few times about writing a simple lisp-style language that would run directly on shotgun.</p>
<p>The primitive operations it provides are kinda like syscalls in a unix system. They provide very low level operations which are built on. For example, there is an add primitive which adds two Fixnum objects together and puts the result on the stack.</p>
<p><strong>AkitaOnRails:</strong> This is a personal curiosity. The MRI today uses a simple mark and sweep garbage collector (GC) whereas Java uses a highly customizable generational GC. What did you choose for memory management on the Rubinius VM?</p>
<p><strong>Evan Phoenix:</strong> Rubinius uses a generational GC, combining a copy collector for the young objects, with a mark/sweep collector for the old. It’s proved to work quite well for us. The trick has been tuning how long an object exists before it is promoted to the old object space. We’ve only tuned it a little. There is a lot more work that could be put into the GC, and it’s architected to only interact with the rest of the system at a few places, so its logic can be completely replaced if need be without disturbing anything else.</p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2008/2/11/421875792_79acde1fba.jpg" alt=""  loading="lazy" /></p>
<p><strong>AkitaOnRails:</strong> We have parties that favors green threads, we have parties that are all go native threads. How are you dealing with threading issues in Rubinius? Will we still have the same kind of global locking that MRI has today?</p>
<p><strong>Evan Phoenix:</strong> At the moment, Rubinius only has green threads, built on the first class MethodContext objects. It currently uses libevent to allow threads to wait on IO objects quickly.</p>
<p>The plan (likely for 2.0) is to support native threads as well as the current green threads. You’ll be able to allocate a pool of native threads that the green threads can all share. So perhaps you have 100 green threads, you could allocate 10 native threads for them to split time between. Because of the architecture, it’s trivial to migrate a green thread between native threads.</p>
<p>As for the global lock on native threads, no, we don’t consider a global lock a solution for using native threads. If there is a global lock, there is no reason to use them over green threads. Because so much of Rubinius is written in Ruby, we have an easier time of figuring out how to properly lock things to keep all the objects in the system safe. We haven’t really even started this work, but it’s been talked about quite a bit.</p>
<p><strong>AkitaOnRails:</strong> The current goal is probably to make Rubinius as compatible with the MRI 1.8 as possible. Did you already start any work toward YARV compatibility already? And speaking of YARV, it is the official virtual machine and bytecode compiler for the next release of Ruby. Is there any chance to make Rubinius and YARV byte-code compliant or this is not a short-term goal?</p>
<p><strong>Evan Phoenix:</strong> We’re actively working toward being 1.8.6 compliant. This a big goal because there is a lot of functionality in there. We’re going to do a 1.0 release of Rubinius once it’s able to run all the specs that 1.8.6 runs and properly runs Rails 1.2, which is a good benchmark.</p>
<p>No, we haven’t done any work yet toward YARV compatibility, but because of how things are architected, we’ll likely just be able to have —yarv flag that you pass to Rubinius to have it use YARV compatible versions of things.</p>
<p>We aren’t currently working toward a common bytecode format between Rubinius and YARV, mainly because there is nothing to be gained by doing that. YARV’s bytecode format is largely internal to YARV only, last I looked, you couldn’t easily save it out to a file. Rubinius operates primarily off .rbc files, which contain a serialized CompiledMethod, and thus contain bytecodes. That being said, they are actually similar and could be unified if we saw the need to.</p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2008/2/11/2211693208_bf14710240.jpg" alt=""  loading="lazy" /></p>
<p><strong>AkitaOnRails:</strong> Performance is always subject for a lot of discussion and it is still premature to talk about performance under Rubinius, as it is still work in progress. But I read in your blog that it is quite fast already, even surpassing MRI in many tests. How is performance evolving?</p>
<p><strong>Evan Phoenix:</strong> Currently, our performance is evolving slowly. This is mainly because it’s not a priority for people writing the kernel of Rubinius (the majority of the Ruby code which makes it up). As we get closer and closer to being compliant, we’ll begin tuning things. That being said, I do write code to make Rubinius faster here and there. We went ahead and implement fast math operations to speed up the simple math that people commonly do. We have a simple profiler which can easily be turned on to give developers feedback about how their code is run.</p>
<p><strong>AkitaOnRails:</strong> One of the main problems for any alternative implementation to Ruby is that it has a lot of C-based extensions, including a handful of core libraries. So if you want to stay “pure-Ruby” you have to re-implement all of them in Ruby. The JRuby guys had to go through something similar. Are there any cross-project collaborations already in this regard?</p>
<p><strong>Evan Phoenix:</strong> Actually, that’s not entirely true. We also saw that the landscape of Ruby includes a lot of C extensions. To make migration to Rubinius faster, we’ve written a layer into Rubinius which allows all those C extensions to run (nearly) unmodified, only requiring a simple recompile. These are so that things such as ImageScience, RMagick, postgres bindings, etc can all be used under Rubinius without having to be rewritten.</p>
<p><strong>AkitaOnRails:</strong> Still about C code, I know it is difficult to deliver a bytecode virtual machine and still be dependent on non-managed C code. Java has some jury rigging toward JNA, .NET has pinvoke. Do you plan something similar for Rubinius so that it can more or less easily speak with C libraries?</p>
<p><strong>Evan Phoenix:</strong> We actually directly support a mechanism called FFI (Foreign Function Interface), which allows a developer to bind a C function directly as a method call. Here is a simple example:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="k">module</span> <span class="nn">LibC</span>
</span></span><span class="line"><span class="cl"> <span class="n">attach_function</span> <span class="kp">nil</span><span class="p">,</span> <span class="ss">:puts</span><span class="p">,</span> <span class="o">[</span><span class="ss">:string</span><span class="o">]</span><span class="p">,</span> <span class="ss">:void</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="no">LibC</span><span class="o">.</span><span class="n">puts</span> <span class="s2">&#34;hello!&#34;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>The attach_function line is the primary interface into FFI. You simply indicate which library the function is in (in this case, nil is used because it’s included in the existing process), the name of the function (puts), the types of arguments it takes (just 1, a string), and finally, the type it returns (void, ie, nothing).</p>
<p>Using this, you can tie directly to C functions without having to write C wrapper code.</p>
<p><a href="http://rubini.us/"target="_blank" rel="noopener"><img src="http://s3.amazonaws.com/akitaonrails/assets/2008/2/11/Picture_2.png" alt=""  loading="lazy" /></a></p>
<p><strong>AkitaOnRails:</strong> You are very right when you say that formal language specs too early in the game can make it difficult to evolve the language. Ruby as been growing for 10 years now, and it feels that this is the right time to start thinking of something like this, so that we can have a baseline from where every other alternative implementation could start. Do you see any efforts towards this end?</p>
<p><strong>Evan Phoenix:</strong> We’ve been actively working to develop a set of specs (in <a href="http://rspec.info/"target="_blank" rel="noopener">rSpec</a> format) for 1.8. These form the primary mechanism with which we test how Rubinius is doing. These specs are being actively used by JRuby and IronRuby to test their respective Ruby environments. We’re currently in the process of moving these specs into a generic Ruby spec project to try and begin moving things toward a more formal standard.</p>
<p><strong>AkitaOnRails:</strong> Another recurring question is about Rails, of course. Any new Ruby implementation today will have to face the inevitable question: does it run Rails already? :-) Rails is serving kinda like a ‘mini test suite’ and baseline for most implementations. How is Rubinius performing on this matter?</p>
<p><strong>Evan Phoenix:</strong> When we run Rails, we know we’re close to a 1.0. :)</p>
<p><strong>AkitaOnRails:</strong> You have a very interesting approach toward open source management: everyone that sent you a good patch gains commit access to the repository. How is this working for you? Isn’t it a bit ad hoc or people tend to follow your lead and your list of priorities?</p>
<p><strong>Evan Phoenix:</strong> It’s actually working out great so far. By being spec/test oriented, new people have a place to start, either writing missing specs or making existing ones pass. Those become great intros into the whole system for them. They then begin to explore a bit more and commonly find more and more they’d love to help with. Because we have a lot of work to do in a lot of different places, people don’t have to worry about my priority list, since it’s usually involving things which others don’t need to be actively concerned with.</p>
<p>I really can’t say enough about the people who contribute. The one patch barrier has proved to work great because while we’ve now got over 60 committers, not once have I had to pull commit rights from someone. Sure, people mess up, but in every case, the person has corrected the behavior and/or code.</p>
<p><strong>AkitaOnRails:</strong> One byproduct of this commit access approach of yours is the integration of rSpec into the Rubinius project so that you have a nice requirements tool and test suite. Do you practice Behavior Driven Development? Or this is covering just a small sub-set of the project?</p>
<p><strong>Evan Phoenix:</strong> I’m largely a testing newbie, simply following the guidelines set by Brian Ford, the primary spec keeper of the project. It has proved to be a great tool for viewing how the project is progressing.</p>
<p><strong>AkitaOnRails:</strong> As many other Ruby projects, Rubinius is also managed over GIT. There’s been a lot of fuzz around Git and Ruby these days. Do you think there is a new trend here? Why did you decide to go with GIT?</p>
<p><strong>Evan Phoenix:</strong> Yeah, I think that GIT is picking up as a trend, because of the features it offers over subversion mainly.</p>
<p>The big reason we decided was it’s feature set. One big feature I love is local branches, allowing a person to manage a number of outstanding changes without trampling on each other.</p>
<p>We haven’t yet, but we plan to exercise the great merge / public branch capabilities.</p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2008/2/11/504590792_2819a866a8.jpg" alt=""  loading="lazy" /></p>
<p><strong>AkitaOnRails:</strong> We heard from Ezra’s <a href="http://podcast.RubyonRails.org/programs/1/episodes/ezra-zygmuntowicz"target="_blank" rel="noopener">recent interviews</a> about your new experiment on multi-VM. That would be a blessing for deployment without we having to deal with several processes in a mongrel cluster. Can you describe this feature and pin point its advantages?</p>
<p><strong>Evan Phoenix:</strong> It’s pretty experimental currently, but it will only get more stable over time. The idea is that you can spin up a whole new VM in the current process. This new VM is completely separate from other VMs, living in its own native thread and having its own garbage collector, etc.</p>
<p>There is a mechanism for VMs to communicate with each other though, and this allows them to coordinate work. This would mean that a primary thread could accept new connections, then pass them off to a new VM to actually process. This allows you to process connections in actual parallel, in addition, because the VMs are completely separated, this even works for non-thread safe applications like Rails.</p>
<p><strong>AkitaOnRails:</strong> Ezra also mentioned about a possible mod_rubinius in the making. How is it going? This definitely makes the Rubinius stack even stronger. Together with Merb, Rubinius plus multi-VM capabilities plus mod_rubinius would be a killer deployment package.</p>
<p><strong>Evan Phoenix:</strong> Yes, a mod_rubinius project is just beginning. The multi-VM code and mod_rubinius overlap a bunch, so you’ll be able to have VM pools for sites, all managed through apache. We’re hoping that mod_rubinius can really simplify the Rails/Ruby deployment picture. It will operate similarly to mod_python, allowing a VM to remain running between requests, and likely even run background tasks.</p>
<p><strong>AkitaOnRails:</strong> How long do you guess we are from a fully MRI-1.8 compatible release?</p>
<p><strong>Evan Phoenix:</strong> We still don’t have a firm date, mainly because what fully compliant MRI-1.8 is is still unknown. We are still adding specs, working to properly define 1.8. That being said, we’re really hitting a stride and progress is advancing rapidly. We’re very close to properly running Rubygems. Ezra recently was able to run Merb on top of Rubinius, running under webrick.</p>
<p>I’m going to be doing a 0.9 release this week, because we’ve made so much progress since 0.8. My big hope is that by RailsConf in May, we’ll be running Rails. But don’t hold me to that. This is open source after all. :)</p>
<p><strong>AkitaOnRails:</strong> Thanks, I think this is it.</p>
<p><strong>Evan Phoenix:</strong> Thanks for your patience!</p>
]]></content:encoded><category>interviews</category><category>ruby</category><category>programming-languages</category></item><item><title>Chatting with Hal Fulton</title><link>https://akitaonrails.github.io/en/2008/01/09/chatting-with-hal-fulton/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2008/01/09/chatting-with-hal-fulton/</guid><pubDate>Wed, 09 Jan 2008 21:27:00 -0200</pubDate><description>&lt;p&gt;&lt;img src="http://s3.amazonaws.com/akitaonrails/assets/2008/1/9/n767352779_362954_175.jpg" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://rubyhacker.com/"target="_blank" rel="noopener"&gt;The Ruby Way&lt;/a&gt; is the undisputed must-have book in any Rubyist bookshelf. Rather than being a &amp;lsquo;reference&amp;rsquo; book it explains what it takes to really dive into the intricacies and marvels of the Ruby programming style.&lt;/p&gt;
&lt;p&gt;Today I am very happy being able to engage in a conversation with one of my favorite authors, &lt;strong&gt;Hal Fulton&lt;/strong&gt;. This was a great chat and I know people will be delighted as well. He is one of the Ruby veterans and certainly has a lot of experience to share. So, let&amp;rsquo;s start:&lt;/p&gt;</description><content:encoded><![CDATA[<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2008/1/9/n767352779_362954_175.jpg" alt=""  loading="lazy" /></p>
<p><a href="http://rubyhacker.com/"target="_blank" rel="noopener">The Ruby Way</a> is the undisputed must-have book in any Rubyist bookshelf. Rather than being a &lsquo;reference&rsquo; book it explains what it takes to really dive into the intricacies and marvels of the Ruby programming style.</p>
<p>Today I am very happy being able to engage in a conversation with one of my favorite authors, <strong>Hal Fulton</strong>. This was a great chat and I know people will be delighted as well. He is one of the Ruby veterans and certainly has a lot of experience to share. So, let&rsquo;s start:</p>
<p><strong>AkitaOnRails:</strong> First of all, it is a tradition at my blog to ask for the guest&rsquo;s background. How long have you been in the programming career? How did you first get there? What inspires you about the computer world?</p>
<p><strong>Hal Fulton:</strong> I started college as a physics major, but I found that I was taking computer courses for fun. I switched to computer science and the rest was history.</p>
<p>Unlike most younger people now, I never was really exposed to computers until I was sixteen, because personal computers were much less common then. I was hooked right away. I saw the computer as a &ldquo;magic box&rdquo; that could do anything I was smart enough to instruct it to do. Really I still feel that way about it.</p>
<p><strong>AkitaOnRails:</strong> This is almost a cliché already but I have to ask: you were one of the &lsquo;first generation&rsquo; Rubyists. How did you come to find Ruby and what was it that &lsquo;clicked&rsquo; for you about the language?</p>
<p><strong>Hal:</strong> I was on a contract at IBM in Austin in the fall of &lsquo;99. In a conversation with a friend across the hall, I complained that I was never on the &ldquo;ground floor&rdquo; of any new technology — I was always a late adopter. And he said, <em>&ldquo;Well, you should learn Ruby then.&rdquo;</em> And I said: <em>&ldquo;What&rsquo;s that?&rdquo;</em> So I got on the English mailing list and started to learn Ruby (version 1.4).</p>
<p>My experience before was with very static languages. I had started (like many people in the earlier days) with BASIC, FORTRAN, and Pascal. Then I learned C, C++, Java, and various other things along the way. But I was never exposed much to LISP, and I never knew Smalltalk. So the whole concept of a dynamic language was a little foreign to me. I had always known that I wanted more power, but I wasn&rsquo;t sure exactly what I wanted. I tried to envision macros that would give me the kind of flexibility I wanted, but it seemed like the wrong solution.</p>
<p>Then I learned Ruby, and I felt that I had taken not just a single leap forward, but three leaps. It was clear to me that this was very similar to what I had been looking for subconsciously.</p>
<p><strong>AkitaOnRails:</strong> The Pickaxe is another must-have book, but it serves the role of a complete &lsquo;Reference&rsquo; book whereas your book is about inner underpinnings and foundations of the language – heck, you spend 40 pages just talking about String, if this isn&rsquo;t detailed enough I don&rsquo;t know what would be. What was your intent when you wrote the 1st edition, how it came to be?</p>
<p><strong>Hal:</strong> I met Dave Thomas and Andy Hunt online on that mailing list. At that time, their excellent book <em>The Pragmatic Programmer</em> had just come out, and they were working on the Ruby book. I was one of the reviewers of that book – helping to iron out little inaccuracies and problems.</p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2008/1/9/0672328844.jpg" alt=""  loading="lazy" /></p>
<p>A little later, Sams Publishing went looking for someone to write a book. At that time, the English mailing list had very few native speakers of English, so I had a good chance of being picked. I submitted a proposal, and they liked it.</p>
<p>The Pickaxe wasn&rsquo;t on the shelves yet, but I had intimate knowledge of its contents. So when I put together the proposal for the book, I tried to make sure it was <strong>not</strong> in direct competition; rather, I wanted it to be complementary. If you look on the &ldquo;praise page&rdquo; of the first edition, there is a quote from me, saying &ldquo;This is the first Ruby book you should buy.&rdquo; But privately I was already thinking: <em>&ldquo;And I know what the second one should be, too.&rdquo;</em></p>
<p><strong>AkitaOnRails:</strong> As detailed and complete as you try to be Ruby has several subtleties and nuances that are hard to capture. Was there anything that you didn&rsquo;t cover at that time that you would&rsquo;ve like to spend more time with?</p>
<p><strong>Hal:</strong> There are certainly some subtleties with classes and modules, reflection, metaprogramming, and that kind of thing, that are not mentioned or not stressed. But in general a programmer shouldn&rsquo;t be &ldquo;too clever&rdquo; when writing code anyhow.</p>
<p>The most glaring omission, I think, is that there is no coverage of writing C extensions. In the first edition, I simply ran out of time, energy, and space – I couldn&rsquo;t cover that. In the second edition, I omitted it because I thought the C API was going to undergo radical<br>
changes as we approached Ruby 2.0 – more radical changes than the core classes, for example. I think this is turning out not to be true, however.</p>
<p><strong>AkitaOnRails:</strong> You probably stumbled upon many Ruby students and enthusiasts that were learning Ruby through your book. By your experience, what do you think people get most amazed about the language, and what are the features that bite them initially?</p>
<p><strong>Hal:</strong> I think the conciseness is one really attractive feature. Take a look at this single line of Ruby, which creates two accessors for a class:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="kp">attr_accessor</span> <span class="ss">:alpha</span><span class="p">,</span> <span class="ss">:beta</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>How would you do that in C++? Well, you would declare two attributes; then you would write a pair of &ldquo;reader&rdquo; functions and a pair of &ldquo;writer&rdquo; functions. What&rsquo;s that, at least seven lines of code right there? But then what if you want to be able to assign different<br>
types to these? Now you have to get into overloading. It quickly becomes a nightmare. Meanwhile, in Ruby — it&rsquo;s still just one line of code.</p>
<p><strong>AkitaOnRails:</strong> What do you like the most about Ruby that sets it apart from other similar languages?</p>
<p><strong>Hal:</strong> One of the best features about Ruby is dynamic typing. Variables don&rsquo;t have types; only objects have types (or should I say, classes). Static typing was so ingrained in me that I <strong>assumed</strong> it was the right way. But when I gave it up, I felt as if I had removed weights that I didn&rsquo;t know I was wearing.</p>
<p>Its <strong>regularity</strong> is also an appealing feature. For example, a class in Ruby is in a sense a &ldquo;special&rdquo; thing – but not nearly so special as in (for example) C++. A class is &ldquo;just an object,&rdquo; so you can do things to classes that you can do to other objects – such as pass them around, store them in arrays, test their values, and so on.</p>
<p><strong>AkitaOnRails:</strong> And what would you improve if you were the guardian of it?</p>
<p>First of all, I&rsquo;m glad I&rsquo;m not the guardian of it. Matz does an excellent job, and he is much smarter than I am. I think there are some issues with reflection and dynamic programming that need to be cleaned up — exactly how, I&rsquo;m not sure.</p>
<p>I look forward to a truly usable virtual machine, and I look forward to some form of method combination (pre, post, wrap). I admit, though, there are small syntax and core changes I would like to make – mostly pretty minor.</p>
<p>For example, I&rsquo;ve always wanted an &ldquo;in&rdquo; operator that would be syntax sugar for calling the include? method – for example, <em>&ldquo;x in y&rdquo;</em> would mean <em>&ldquo;y.include?(x)&rdquo;</em> – this operator would be essentially the same as the set membership operator in mathematics (instead of the reverse) and would sometimes make code more readable and even make parentheses unnecessary sometimes. I&rsquo;ve used the &ldquo;in&rdquo; operator in Pascal since I was 18; Python has it, even SQL to an extent. I wish Ruby had it, too.</p>
<p>Many times I&rsquo;ve felt a need for a data structure that would be accessed like a hash, but would preserve the order specified in the code. For example, imagine a kind of &ldquo;dynamic case statement&rdquo; — we pass in possible matches and code to execute (as procs) for each of those matches. (It would have the advantage over a case statement that we can control the number of case limbs and their associated code at runtime.) Let&rsquo;s implement it as a method called &ldquo;choose&rdquo; that we call in this way:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="n">choose</span> <span class="n">regex1</span> <span class="o">=&gt;</span> <span class="nb">proc</span> <span class="p">{</span> <span class="n">handle_case1</span> <span class="p">},</span> <span class="n">regex2</span> <span class="o">=&gt;</span> <span class="nb">proc</span> <span class="p">{</span> <span class="n">handle_case2</span><span class="p">}</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Now, what&rsquo;s the problem here? The syntax fools us into thinking that regex1 somehow precedes regex2 – but when we iterate over a hash, the order is not guaranteed to be the same as in the code. (That is a property of hashes, of course, not a bug.) So we can&rsquo;t control or predict the order in which these are applied. And I have found several other cases where I wanted such a thing – an associative array, a set of tuples, that had a convenient syntax for literals and had an order.</p>
<p>There are two usual responses to my desire for an &ldquo;ordered hash.&rdquo; Some people say that I&rsquo;m crazy, that a hash isn&rsquo;t ordered and that&rsquo;s that. Some people say I could always make my own class that behaved that way – which is true, except that I wouldn&rsquo;t have the convenience of representing it as a &ldquo;first-class citizen&rdquo; in Ruby syntax. After all, a hash &ldquo;could&rdquo; be represented as a second-class citizen as well – I could say</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="no">Hash</span><span class="o">[</span><span class="s2">&#34;a&#34;</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="s2">&#34;b&#34;</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="s2">&#34;c&#34;</span><span class="p">,</span><span class="mi">6</span><span class="o">]</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>instead of saying:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="p">{</span><span class="s2">&#34;a&#34;</span> <span class="o">=&gt;</span> <span class="mi">2</span><span class="p">,</span> <span class="s2">&#34;b&#34;</span> <span class="o">=&gt;</span> <span class="mi">4</span><span class="p">,</span> <span class="s2">&#34;c&#34;</span> <span class="o">=&gt;</span> <span class="mi">6</span><span class="p">}</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>But I am glad for the expressiveness of the latter syntax.</p>
<p><strong>AkitaOnRails:</strong> Your second edition covers Ruby 1.8. Are you researching into Ruby 1.9 (YARV) already? Being a Ruby veteran, what do you think of the directions Matz and Koichi have been choosing for the next version? Is it satisfying for you? For you, what are the good, the bad and the ugly about Ruby right now and the next version?</p>
<p><strong>Hal:</strong> There have been minor points where I disagreed with Matz from time to time. But as I said, I am glad he is in charge. I like YARV from what I have seen so far. I am anxious for it to be 100% stable so that I can really get a feel for how it works.</p>
<p><strong>AkitaOnRails:</strong> Your book is in the second edition, and it is a huge book, covering not only the language itself but a few 3rd party components as pdf_writer. Are you working on a 3rd edition? Maybe we will have <em>&ldquo;The YARV Way&rdquo;</em>?</p>
<p><strong>Hal:</strong> I am not working on a third edition, and I think it would be very hard to write one. The second one was harder than I expected – although much content was re-used, it still had to be re-examined line by line – and more than 50 errors still crept into those 800+ pages.</p>
<p>I once joked that if there was a 3rd edition, it might have to be two volumes. But really, that might not be such a bad idea – basic concepts and core classes in one volume, standard and third-party libraries in the second. But that&rsquo;s idle speculation. There <strong>is</strong> a kind of add-on for the book being planned – but I won&rsquo;t mention that until we know more details. Ask me in a few months.</p>
<p>As for YARV – I think Ruby will always be Ruby. We may change the inside, but the name will remain the same for the foreseeable future.</p>
<p><strong>AkitaOnRails:</strong> Around 2002 Ruby was not widely adopted and only a handful of hobbyists and enthusiasts were using and helping to improve the language. Yourself, David Black, Nathaniel Talbott, and a lot of big guns from what I call &rsquo;the first Ruby generation&rsquo;. But in 2004 came this full fledged web framework called Rails that made Ruby publicly known and acknowledged, attracting many great minds but also a lot of trolls and amateurs. I hear that some in the first generation regret it because what was once a peaceful and insightful community became very noisy. What are your thoughts about this sudden celebrity status that Ruby gained and its side-effects?</p>
<p><strong>Hal:</strong> Well, Ruby isn&rsquo;t a private club. I wonder if the Japanese felt any offense when Europeans and others started to be interested in it? I think that we&rsquo;ve certainly lost a little bit from the old days, but I don&rsquo;t waste any time thinking about it. We&rsquo;ve gained quite a bit also. And it&rsquo;s interesting that the &ldquo;friendliness&rdquo; of the community has scaled better than many of us expected. Ruby is still Ruby, and Rubyists are still Rubyists. It&rsquo;s just that there are more of us now – also more projects, more activity, more opportunities. That can only be a good thing.</p>
<p><strong>AkitaOnRails:</strong> Do you work with systems development in pure Ruby or do you use Ruby on Rails for web development today? What&rsquo;s your occupation or day job?</p>
<p><strong>Hal:</strong> I&rsquo;ve done a little work with Rails here and there, but I&rsquo;m more of an old-fashioned generalist. I&rsquo;m not a web guy. Many younger programmers, of course, seem unaware that there is any other kind of programming to be done. But if you were writing a compiler or interpreter, a custom web server, any kind of daemon or background networking app… would you reach for your Rails book? Of course not.</p>
<p>I&rsquo;ve done system-level work in the past, but I can&rsquo;t imagine Ruby ever being appropriate for the kinds of things I did back then. For those things, we used C (the universal assembly language). In my day job, I&rsquo;m happily coding Ruby every single day – telecommuting for a Dallas<br>
company called <a href="http://www.personifi.com"target="_blank" rel="noopener">Personifi</a>. I&rsquo;d describe my work as internal applications and tools – a lot of text analysis and indexing, a little number-crunching and a lot of word-crunching.</p>
<p><strong>AkitaOnRails:</strong> Here in Brazil we have a lot of people that were initially attracted by the Rails hype machine, now they are struggling to learn the Ruby language. Metaprogramming, Closures, Mixins, make them go nuts. Do you have recommendations for new comers?</p>
<p><strong>Hal:</strong> What would be a good way to start experimenting with the language? Well, you can keep a copy of <em>The Ruby Way</em> nearby. :-)</p>
<p>Really, I only have three recommendations. First of all, the mailing list or newsgroup is a powerful source of information, and there are still friendly and knowledgeable people there who will answer your questions. Second, there are millions of lines of Ruby source<br>
out there. Study it and learn from it. Third, and most important: Just play around! You don&rsquo;t really learn a language by reading about it, but by using it.</p>
<p><strong>AkitaOnRails:</strong> By the way, are you already writing a new edition? :-)</p>
<p><strong>Hal:</strong> I&rsquo;m not, and I can&rsquo;t see ahead that far. But wait six or seven months, and I do hope to have a little surprise for you…</p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2008/1/9/p4250004_1.jpg" alt=""  loading="lazy" /></p>
<p><strong>AkitaOnRails:</strong> In the light of the current Zed episode, he said a lot of thing specifically against the Pickaxe. One of the things is his claim that the Pickaxe didn&rsquo;t mention clearly all the meta-programming stuff. Then I was talking to &lsquo;arton&rsquo; – a Ruby book author from Japan – and he reminded me: americans and japanese seem to do Ruby differently. He said that they don&rsquo;t usually do all that meta-programming in the level that Rails does, for example. As you said, they don&rsquo;t try to be &ldquo;too clever&rdquo;.</p>
<p>Now, I don&rsquo;t want to be apologetic because I don&rsquo;t think Dave needs it, but this explains a lot given that the Pickaxe mostly only had japanese sources to rely on back in 2001. I personally learned most of my Ruby reading the Rails source code at first (and books like yours later). What do you think about this? (meaning, about the Zed episode in general, and about the different american/japanese programming styles?)</p>
<p><strong>Hal:</strong> As for Zed, I won&rsquo;t take any sides in that discussion. Zed can say whatever he wants, and usually does. I&rsquo;m sure there is some truth on both sides of any controversy.</p>
<p>As for metaprogramming – well, I think those capabilities are in Ruby for a reason. They are meant to be used. But any tool has both appropriate and inappropriate uses. It&rsquo;s impossible to generalize and say &ldquo;this is always bad,&rdquo; but certainly metaprogramming can be misused.</p>
<p>As for Rails itself, I have no doubt there is both good and bad code in it. I suspect the developers working on it would admit as much. And it is possible that they have used &ldquo;too much magic&rdquo; here and there, though I couldn&rsquo;t say specifically where. But could Rails exist without metaprogramming features? Not in its current sense — not in any meaningful sense, I would argue.</p>
<p><strong>AkitaOnRails:</strong> I interviewed Avi Bryant, from Seaside fame, and one of his mottos is that &lsquo;a language is not finished until it can extend itself&rsquo; or &rsquo;turtles all the way down&rsquo; as he says. Meaning, that Ruby still relies a lot on C extensions to this day. Of course, the initial motivations for Ruby are different than Smalltalk. On the other hand people like Evan Phoenix are pursuing this very goal: make Ruby be extensible using pure Ruby. What do you think about this new direction?</p>
<p><strong>Hal:</strong> I like the idea of &ldquo;Ruby in Ruby&rdquo; in general, though Matz does not. And I am impressed with what I have seen of Rubinius so far – I think it is an important project and will grow more important.</p>
<p>If it&rsquo;s possible to move toward an elimination of C extensions without sacrificing speed, I suppose that&rsquo;s a good thing. I am not sure if it is possible. We might at least create a &ldquo;Ruby in Ruby&rdquo; that does not rely directly on MRI (Matz&rsquo;s Ruby Interpreter). But I don&rsquo;t expect to see the &ldquo;original Ruby&rdquo; replaced any time soon.</p>
<p><strong>AkitaOnRails:</strong> This was a very insightful conversation, thank you!</p>
]]></content:encoded><category>interviews</category><category>ruby</category><category>learning</category></item><item><title>Chatting with Peter Cooper</title><link>https://akitaonrails.github.io/en/2008/01/09/chatting-with-peter-cooper/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2008/01/09/chatting-with-peter-cooper/</guid><pubDate>Fri, 04 Jan 2008 09:30:00 -0200</pubDate><description>&lt;p&gt;&lt;a href="http://www.rubyinside.com/"target="_blank" rel="noopener"&gt;Ruby Inside&lt;/a&gt; is one of the greatest Ruby/Rails websites available and a great source of news. Its creator is the British entrepreneur &lt;a href="http://www.petercooper.co.uk/"target="_blank" rel="noopener"&gt;&lt;strong&gt;Peter Cooper&lt;/strong&gt;&lt;/a&gt;, also the author of the recently published book &lt;a href="http://www.apress.com/book/view/9781590597668"target="_blank" rel="noopener"&gt;Beginning Ruby, from Novice to Professional&lt;/a&gt;, an excellent source for anyone willing to learn the Ruby language.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://s3.amazonaws.com/akitaonrails/assets/2008/1/4/peter-good4.jpg" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;Peter speaks about Ruby on Rails, business, novices and, as a last-minute exclusive, he comments on the recent &lt;a href="http://www.akitaonrails.com/2008/1/3/zed-is-not-dead"target="_blank" rel="noopener"&gt;Nuclear Zed&lt;/a&gt; episode that shocked a lot of people in the community. Just to clarify, Peter answered my questions before New Years Eve, it’s only the last question that was added today.&lt;/p&gt;</description><content:encoded><![CDATA[<p><a href="http://www.rubyinside.com/"target="_blank" rel="noopener">Ruby Inside</a> is one of the greatest Ruby/Rails websites available and a great source of news. Its creator is the British entrepreneur <a href="http://www.petercooper.co.uk/"target="_blank" rel="noopener"><strong>Peter Cooper</strong></a>, also the author of the recently published book <a href="http://www.apress.com/book/view/9781590597668"target="_blank" rel="noopener">Beginning Ruby, from Novice to Professional</a>, an excellent source for anyone willing to learn the Ruby language.</p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2008/1/4/peter-good4.jpg" alt=""  loading="lazy" /></p>
<p>Peter speaks about Ruby on Rails, business, novices and, as a last-minute exclusive, he comments on the recent <a href="http://www.akitaonrails.com/2008/1/3/zed-is-not-dead"target="_blank" rel="noopener">Nuclear Zed</a> episode that shocked a lot of people in the community. Just to clarify, Peter answered my questions before New Years Eve, it’s only the last question that was added today.</p>
<p>Once again, I deeply apologize to the brazilian audience because I didn’t have time to translate this into Portuguese today, but I will do very soon. Stay tuned.</p>
<p><strong>AkitaOnRails:</strong> For the Ruby community Peter Cooper stands for <a href="http://www.rubyinside.com/"target="_blank" rel="noopener">Ruby Inside</a>. I personally enjoy reading your website as it accumulates most of the important Ruby and Rails news out there. Let me thank you again for adding my blog to your sidebar list. But how did it start? What do you think were the most important steps you made to build its good reputation?</p>
<p><strong>Peter Cooper:</strong> Ruby Inside began as a vehicle for promoting my forthcoming (now released) book, “Beginning Ruby.” The name itself came from a comment made in an interview Geoffrey Grosenbach did for the Rails podcast where someone adapted Ruby into the old “Intel Inside” slogan, which sounded like a great name for a blog covering Ruby issues. Initially, the blog was simply to promote the book, but it quickly turned into a digest of news from the whole Ruby community. I think the key to its success was that the larger Ruby blogs at the time, the O’Reilly Ruby blog being a good example, were posting less and less as their writers were getting more and more Ruby work. Ruby Inside filled a gap of providing heavily digested news from the whole Ruby community, with only one or two posts per day, allowing Ruby developers to keep up to date with things, but without having to subscribe to hundreds of blogs.</p>
<p><strong>AkitaOnRails:</strong> Looking through your <a href="http://www.linkedin.com/in/petercooper"target="_blank" rel="noopener">LinkedIn</a> profile I see that you’ve been quite involved with internet-based business for the last 10 years. You also describe yourself as a ‘serial entrepreneur’. Entrepreneurship is something very difficult here in Brazil, mainly because of economics and overwhelming bureaucracy involved. How difficult is it there in England to open and run your own business?</p>
<p><strong>Peter:</strong> It’s very easy to start up in business in the UK. Depending on what you want to do, you can just say you’re a business right away, without filing any papers (although you do have to call the tax office to let them know!), and operate as a “sole trader.” Registering a business officially, however, is quite easy too and gives you a number of legal protections and a more professional image. Getting funding and so forth isn’t particularly easy here, compared to the UK, but if you’re willing to bootstrap, then the UK’s very good for easy banking, fast communication, and trading with the rest of the world. With the natural advantage of the English language, the US market is easy to target from the UK.</p>
<p><strong>AkitaOnRails:</strong> Your other most well known products should be <a href="http://snippets.dzone.com/"target="_blank" rel="noopener">Code Snippets</a> and <a href="http://www.feeddigest.com/"target="_blank" rel="noopener">Feed Digest</a>. Can you introduce both of them to our Brazilian uninitiated? How did the idea occur to you? It was something like <em>‘scratching your own itch’</em> or it was something totally unrelated and maybe following some trend that you identified? What tools did you use to build them? Many people are interested to know what does it take to build a successful product. What do you think it takes to be a good internet entrepreneur?</p>
<p><strong>Peter:</strong> Code Snippets was the first del.icio.us-style “tagged” public code snippet repository. In fact, I believe it was the first Rails application to use tagging at all, as I wrote the earliest code which was appropriated into a number of following tagging libraries. The site was launched in early 2005 and I sold it in February 2007 to DZone. Feed Digest is a service for mashing up, processing, and re-publishing RSS and Atom feeds into other formats, such as HTML, JavaScript, Flash, images, and so on. I sold it to a Russian company in the summer of 2007.</p>
<p>Both businesses / sites were a result of <em>“scratching my own itch”</em> as you say. I needed a system to store code snippets in a tagged way, and del.icio.us was not suitable for this, so Code Snippets came out of a 24 hour coding marathon, was publicly released, and then grew to thousands of users over time. Feed Digest evolved from an earlier service called RSS Digest that I created to scratch another itch, republishing my del.icio.us links onto the header of my blog. It grew far beyond that though, and now has over 25,000 users and serves perhaps about half a billion requests each month. I no longer own or have a direct interest in either of those projects now though, but I must be doing okay on the chart of people selling Rails apps!</p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2008/1/3/9781590597668.gif" alt=""  loading="lazy" /></p>
<p><strong>AkitaOnRails:</strong> I congratulate you on your recently published book, from Apress, <a href="http://approachingnormal.com/2007/11/27/book-review-beginning-ruby-from-novice-to-professional"target="_blank" rel="noopener">Beginning Ruby, from Novice to Professional</a>. As Larry Wright states in his review, he is right that the Pickaxe is a good Reference book, but you take a different approach in being more careful about actually ‘teaching’ the environment. It does fill a gap as there are more and more people interested in learning Rails but lacking an introductory book to learn Ruby itself. Please, describe your book for our audience as I think many Brazilians don’t know about your book yet. What’s its target audience? What do you talk about?</p>
<p><strong>Peter:</strong> The book is currently only available in English, unfortunately, so the US has definitely been the biggest target market so far. Content-wise, the book is very reminiscent of the “classic” programming tuition books I was brought up on in the 1980s. It takes a very “walkthrough” approach, with the installation of Ruby coming first, followed by a walkthrough of all the main concepts regarding object orientation, Ruby’s syntax, and the basic data types. Eventually, by the end of the book, the reader has gone through file operations, database usage (there’s even an SQL primer), developed a text adventure game, built a simple Rails application, and so forth. It’s very much a book you’d go through, as a beginner, from beginning to end, and then move on to more advanced books like the Pickaxe or The Ruby Way. Hopefully we will see it in Portuguese one day!</p>
<p><strong>AkitaOnRails:</strong> And speaking of beginners, again I think it amusing to read at your LinkedIn profile: <em>Does “left school at 16” count? If so, I’m in. Education is great for most, but overrated if you’re a grafter.</em> I dropped college to work in the Internet bubble as well (though not as an entrepreneur, which I regret). I don’t recommend people to just drop college as I did, of course, this is a personal choice and everybody should take an educated decision about their own future. But there are a lot of people – at least here in Brazil – that praise certifications and diplomas much more than hands-on experience. Sure, there are very good certified developers, but there are more bad developers that actually ‘believe’ in their own certifications as a graduation for competency! I don’t see any correlation between diplomas and good developers. What is your opinion about this matter?</p>
<p><strong>Peter:</strong> I have a lot of respect for people who take the academic route, and feel that in general they turn out to be better at their jobs than the less well educated. One of the downsides to being indoctrinated in academia, however, is that people with many degrees, certifications and diplomas often act like technological automatons, only understanding one course of action, not able to think dynamically on the fly, and unwilling to try radical new directions. There is a lot of room in the world for people like that, but on the other foot we also need a lot of “crazy” people who try things that initially seem idiotic or radical.</p>
<p>The other problem with people who brag about their certifications is that in many cases they are just proving that they managed to pass a test. Passing a test and having a lot of knowledge doesn’t necessarily mean you develop good problem solving skills or can work as a true developer, architecting solutions from scratch. For example, a builder might be excellent at building houses, but he’s likely to be very poor at actually designing buildings, which is an architect’s job. In IT, especially within smaller companies, it’s often necessary for developers to fill both architectural and development roles, and many people with certifications, but little real world experience, struggle with the design of systems.</p>
<p><strong>AkitaOnRails:</strong> We are both Ruby and Rails evangelists, of course, but as myself I don’t see you as a ‘blind’ developer, meaning, the kind that needs to make everything else look bad just to justify putting Ruby up on a pedestal. I actually believe in the <em>‘right tool for the job’</em> approach. Not even DHH states that Rails is the solution for every use case. That said, I think Rails is the best approach for a niche of web development. Recently I involved myself – and I regret it – against a troll rant from a Brazilian .net advocate. I don’t dislike .net, far from that. Anyway, do you see yourself involved in rants like this? Or you do try to avoid them altogether? What is your opinion about ‘X vs Y’ type of discussions?</p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2008/1/4/Picture_1.png" alt=""  loading="lazy" /></p>
<p><strong>Peter:</strong> I think it’s possible to play interesting political games in any situation. As a regular human being I do have, of course, biases and preferences, but it’s important to recognize these for what they are and still be able to see the big picture. I believe in trying to use the right tool for the job (or, more accurately, the most efficient tool for the job – I’m not going to learn a whole new language just to solve one problem), so Ruby Inside runs on <strong>WordPress</strong> , a PHP-based weblog platform. In terms of bias, I’m certainly rather anti-Microsoft, although I do acknowledge that their approach to the development of GUI applications is light years ahead of everyone else.</p>
<p>I don’t try to avoid or become embroiled in X vs Y types of discussions, although I do tend to play devil’s advocate when they come up. It is important to remain as scientific and objective as possible in these situations, but I’ll certainly let a little bias show from time to time, as any human would. For example, I (and I’m far from alone on this, although a lot of people seem not to want to rock the boat publicly) am not particularly keen on David Heinemeier Hansson’s overprotection of the terms Ruby and Ruby on Rails, and especially the Rails logo to the point where he rejects the Rails logo’s usage on books that he has not personally worked on. I’m not afraid to show some bias and reference issues like these from time to time.</p>
<p><strong>AkitaOnRails:</strong> This leads to another question: everyday I see people here asking us <em>“Why should I choose Ruby on Rails over X?”</em> Personally, I think there is no clear answer for that. Being experienced in many platforms like ASP.NET, Java, PHP, Perl, I did my choice based not only on raw performance (which Ruby lacks, for now), not even a mature library set (which is evolving fast, though). Some reasons were based solely on me being happier with this platform. I do think Ruby enables me to write more ‘beautiful’ code as Marcel Molina Jr. explains. But <em>“Beauty is in the eye of the beholder”</em>. What’s your take on this matter? Being an experienced programmer in other platforms, why did you choose Rails?</p>
<p><strong>Peter:</strong> I was a Perl developer before I came across Ruby and Rails, and when I did see Rails, the first thing I did was try to clone it in Perl. Unfortunately, I’m definitely not in the top 10% of programmers, by any means, so my attempt was messy. I tried using Rails directly, reluctantly, with a self promise not to get suckered in to learning a whole new language, but merely to develop what I needed to develop at the time. Of course, the rest is history and I’ve been converted over to Ruby entirely, due to its consistency, ease of use, and the way it just feels like a “natural” language.</p>
<p>Back in 2004, Ruby’s library set was poor, RubyGems wasn’t popular, and there weren’t many books available, so it seemed like a poor choice, but these things have all changed very rapidly, and I’d say Ruby’s library set in 2007 competes very strongly with, say, Python, and while the raw numbers are behind those of Perl’s CPAN, the quality and modernity of Ruby’s libraries exceed it. Ruby is now a strong choice.</p>
<p><strong>AkitaOnRails:</strong> I have to extend this theme because I think it is relevant as we see more and more switchers to Rails. I see 2 kinds of developers coming on board: the first being experienced programmers that were not satisfied with their current day-jobs and tools and wanted to try something new and refreshing. The second being novice developers that think Java or .NET have a higher learning curve than Rails. The latter worries me a little bit because some tend to think that Rails is too easy to be considered professionally and some even get frustrated in finding out that Ruby is not Basic, and you do have to make an effort to learn its way. You do training as well, what is your experience dealing with newcomers?</p>
<p><strong>Peter:</strong> I have not dealt with anyone who’s completely new to Web application development, so I cannot give a strong answer. However, I certainly don’t feel that people are choosing to learn Ruby or Rails because it’s perceived as “easy.” Indeed, I think it’s the more experienced developers who consider Rails to be easy, and that’s why they’re giving it a go. Beginners tend to just go with whatever is in fashion at the time or what’s the most popular. There’s no shortage of newcomers to all of the major languages right now, it’s just that Ruby is now getting its fair share at last.</p>
<p><strong>AkitaOnRails:</strong> 3 years ago the majority of developers predicted the “demise” of Rails as a viable alternative. Today we just saw Rails 2.0 out of the door and the Rails community growing faster and stronger each day. Now people do think of Rails as the contender to beat. I think this is a good thing because we tend to move faster (develop more gems, innovate more) when we are under pressure. Do you think people are accepting Rails more or do you still see barriers for Rails adoption, at least there in England or Europe in general?</p>
<p><strong>Peter:</strong> I disagree with your assertion that three years ago a majority of developers predicted the demise of Rails. I think there were just a lot of defensive programmers choosing to disregard it. I also don’t think the majority of developers on other platforms see Rails as something to beat. There’s actually a lot of blindness in the branches of the programming community to the efforts being made in other branches. The majority of .Net developers don’t care about, and most likely haven’t heard of, Ruby or Rails. Developers on dying platforms, such as Cold Fusion, are more familiar with Rails, simply because they’ve been looking for alternatives, but Java and .Net are still taking on new developers at a far higher rate than Ruby and Rails. There is a large difference in what the blogs and other online media want to report and what’s actually happening out there.</p>
<p><strong>AkitaOnRails:</strong> There were many things that Ruby was lacking and now we just saw Ruby 1.9 released. It is still no stable 2.0 but this is a clear sign that the language is evolving fast as a mature platform. Free performance is always welcome, but this release will break many things. Are you already using 1.9 or do you feel it’s still not ready for prime time?</p>
<p><strong>Peter:</strong> I’ve played with Ruby 1.9 a bit, but I don’t routinely use it. I don’t consider myself a programmer in the academic sense. I like to be aware of, and dabble briefly with, technologies on the fringes, but I’m not one of these super-programmers who downloads, say, Erlang or Haskell and tries to learn it in a weekend. Ruby 1.8 will definitely remain my main Ruby interpreter for at least a few months yet.</p>
<p><strong>AkitaOnRails:</strong> Our Brazilian community is still very young and small, I usually describe it as the US community from 2004 ~ 2005. We still didn’t reach critical mass. How are things going there at England or Europe? Is your community big enough that the market started to demand Rails related professionals already?</p>
<p><strong>Peter:</strong> The market in the UK is still very small. There was literally nothing in 2005 but things have grown quickly in the last couple of years, although it’s still perhaps 1000th the size of the market for Java or .Net services. There are usually a handful of Rails related jobs floating around, but so far I’ve found that Rails is a technology that agencies are using for their clients behind the scenes, rather than something being actively demanded. I am not directly involved in the UK Ruby or Rails communities, however, so I cannot provide much more detail than this.</p>
<p><strong>AkitaOnRails:</strong> This is just for amusement: if you were DHH or Matz what would you like to change in Rails or Ruby? Or maybe, where do you see both of them leading to?</p>
<p><strong>Peter:</strong> If I were DHH, then Rails probably wouldn’t exist, simply because I think a lot of his excellent evangelism of Rails is driven by some craving of fame. At a more practical level, though, I would make Rails less opinionated and more customizable, simply because a lot of the opinions are too rigid to be practical in the real world. The initial opinion of relying on the database to provide information about model structure was a good one, but then along came migrations.. and suddenly we’re defining table layouts in code after all, often in many tens of different files! Why not just put the attributes into the models directly and let Rails take care of the schema changes transparently? DataMapper does this, and ActiveRecord is starting to look backwards in comparison with its bizarro approach.</p>
<p>On the Ruby side of things, I think Matz has done an excellent job technically, although whereas DHH scores high on the PR scale, Matz seems reluctant to promote Ruby at all. I think this is both because this sort of modesty is a honorable trait in Japanese culture, but also because Ruby is something he developed to scratch an itch, and another million or so developers using the language won’t benefit him significantly. He’s a great guy, but he lacks the craziness of Larry Wall (Perl) and the authority of Guido van Rossum (Python) and is incredibly lucky that he can rely on a very strong and vocal community to promote Ruby. One benefit of Matz’s hands-off approach is that people feel that they can take authority over various areas of the language and community for themselves without having to answer to a higher authority.</p>
<p>In terms of the technical side, the only thing I’d perhaps do if I were in control of the development of the Ruby language would be to make heavy pushes towards more functional constructs in Ruby 2.0. JavaScript and Perl 6 are taking strides into the world of functional programming, and Ruby needs to follow. I’d also be considering concurrency very strongly and making this a major focus for new language feature developments.</p>
<p><strong>AkitaOnRails:</strong> What would be your recommendation for novice Railers here in Brazil? I mean, for those that wants to learn both Ruby and Rails but may need some guidance to start?</p>
<p><strong>Peter:</strong> Well, if you can speak English, then naturally I’m going to suggest my book “Beginning Ruby” published by Apress! Unfortunately I’m not familiar with Portuguese resources for learning Ruby or Rails, although I’m sure you are! One free resource I would definitely recommend to newer developers is Chris Pine’s “Learn to Program.” It’s available as a print book, but a more raw version is available to read <a href="http://pine.fm/LearnToProgram/"target="_blank" rel="noopener">free online</a>.</p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2008/1/3/467593017_cd7871742c.jpg" alt=""  loading="lazy" /></p>
<p><strong>AkitaOnRails:</strong> Now, speaking of information, we had a very explosive new year beginning. Zed Shaw literally <a href="http://www.akitaonrails.com/2008/1/3/zed-is-not-dead"target="_blank" rel="noopener">exploded</a> in rants, cursing and every form of aggressive communication. As I stated in my previous article I was personally shocked at first, but I read it through – trying to filter down all the hatred, and uncivilized manners – and there’s actually some information buried there. What is your take about this episode?</p>
<p><strong>Peter:</strong> Personally, I think Zed is spot on. I don’t like the way he has specifically attacked a few people personally (Kevin Clark, for example) for minor infractions. His language is harsh, and he clearly has a lot of vitriol. Behind all the swear words and chest beating, however, is a lot of truth. I sympathize with his main arguments, especially those raised in the “round two” update published on January 3rd.</p>
<p>Zed touches on the way some people form into elitist, ego driven gangs, such as Rails Core and the <a href="http://blog.caboo.se/"target="_blank" rel="noopener">caboo.se</a>. I was involved with the caboo.se for a while myself, and I have a great respect for many of its members (Courtenay Gasking and Amy Hoy, for example), but the whole thing stank too much of elitism to me, and I’ve distanced myself from all of this Rails related online socialization. I could recall quite a few pathetic condescending incidents from members of these communities myself, but unlike Zed I leave quietly. I think one of the biggest causes of the tension, gang-forming, and general childishness is that many of the people involved with these gangs have no social life outside of this community. This probably explains why parlor games like <a href="http://headius.blogspot.com/2007/11/is-werewolf-killing-conference-hackfest.html"target="_blank" rel="noopener">Werewolf</a> and general goofery are so popular at the conferences, as opposed to, say, actually revolutionizing the field.</p>
<p>Lastly, Zed is spot on with his comments about the “Programming Ruby” book, more commonly known as the “Pickaxe.” I tend to remain politically correct on this subject, especially as I have a competing book, but the Pickaxe really is stunning in its mediocrity. It sells well because it has first mover advantage and name recognition, and no-one else has bothered writing a better reference book (The Ruby Way is excellent, but it’s not a reference book). For having the only printed Ruby reference book, Dave Thomas deserves credit, but it’s still mediocre.</p>
<p><strong>AkitaOnRails:</strong> For the good or the bad, I have mixed feelings about this whole episode. I won’t judge anyone yet. Let’s see how it unfolds. And of course, I really appreciate Peter Cooper’s patience with me, kindly answering all my questions. Thanks a lot!</p>
]]></content:encoded><category>interviews</category><category>ruby</category><category>blogging</category></item><item><title>Chatting with Avi Bryant - Part 1</title><link>https://akitaonrails.github.io/en/2007/12/15/chatting-with-avi-bryant-part-1/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2007/12/15/chatting-with-avi-bryant-part-1/</guid><pubDate>Sat, 15 Dec 2007 12:15:00 -0200</pubDate><description>&lt;p&gt;Someone once challenged all other frameworks implying that no one would get close to what we are doing in Rails … except for Avi. Seaside is such a departure from the status quo that Avi himself describes it as a ‘heretic’ framework. And he is right. He looked back in history and took what is considered ‘the’ father – and arguably ‘the’ best implementation – of object-oriented languages: Smalltalk.&lt;/p&gt;
&lt;p&gt;Taking clues from the venerable Apple WebObjects he set his way to implement Seaside and his very successful web product, &lt;a href="http://www.dabbledb.com"target="_blank" rel="noopener"&gt;Dabble DB&lt;/a&gt;. Check out who the man is, what are his opinions and why he is so relevant to the Ruby and Rails community even though he advocates another language and another framework. Sounds strange, but when Avi speaks, you listen.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Someone once challenged all other frameworks implying that no one would get close to what we are doing in Rails … except for Avi. Seaside is such a departure from the status quo that Avi himself describes it as a ‘heretic’ framework. And he is right. He looked back in history and took what is considered ‘the’ father – and arguably ‘the’ best implementation – of object-oriented languages: Smalltalk.</p>
<p>Taking clues from the venerable Apple WebObjects he set his way to implement Seaside and his very successful web product, <a href="http://www.dabbledb.com"target="_blank" rel="noopener">Dabble DB</a>. Check out who the man is, what are his opinions and why he is so relevant to the Ruby and Rails community even though he advocates another language and another framework. Sounds strange, but when Avi speaks, you listen.</p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2007/12/15/n517961878_373676_1188.jpg" alt=""  loading="lazy" /></p>
<p>He was very kind to provide me a very long interview. It is so long I divided it into 2 parts. This is the first Part. I will release the second one in a few days. Hope you all enjoy it.</p>
<p><strong>AkitaOnRails:</strong> Great. I am kind of nervous. Up until now I only interviewed Ruby and Rails advocates including Matz and DHH, this is the first time I am looking for an outside point of view.</p>
<p>And I know you’re very opinionated about Smalltalk and Seaside, but at the same time you have very strong ties to the Ruby community. May I start asking you more about Avi Bryant, the person? Meaning, what’s your history in the programming field?</p>
<p><strong>Avi Bryant:</strong> I started programming quite young; it was something I did with my brother and father for fun, mostly writing games in C on the early Mac. As I got closer to college age, my interests turned more to theatre and film, and so when I started university it was essentially as a film major.</p>
<p>But in the long run computer science sucked me in, and I ended up graduating with a CS degree and working in a software engineering lab on campus. That was when I first started programming seriously, and particularly where I got especially interested in software tools.</p>
<p>This was around the time that the very first builds of Mac OS X – when it was essentially still just NeXTStep, without Aqua or Carbon or anything – started to become available, and since I had always programmed for the Mac I set out to learn Objective-C and Cocoa. That was my first exposure to “real” OO, and it was intoxicating.</p>
<p>At the same time, I was doing some web consulting on the side for some extra money, and so I was looking for a language that reminded me of Objective-C but was more dynamic and better suited for the web, and so eventually stumbled across Ruby, which fit the bill nicely.</p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2007/12/15/n517961878_39359_1867.jpg" alt=""  loading="lazy" /></p>
<p>I was still enamored with all things NeXT and Objective-C, and so when I started to work on web tools for Ruby I took NeXT’s WebObjects framework as my model, and ended up with IOWA, which is very close to being a port of WebObjects to Ruby. I presented that at the first RubyConf, which was, I think, in 2000.</p>
<p>RubyConf was collocated with OOPSLA that year, which I was also attending to give a talk on my research from the software engineering lab. Now, when OOPSLA started out, it was full of Smalltalkers, and even though the mainstream of OO software development – and thus the main focus of OOPSLA – moved on to Java and C#, the Smalltalkers kept coming. But instead of participating in the rest of the conference, they’d just set up a semi-official “Camp Smalltalk” with their own projector and their own schedule and hack and demo Smalltalk stuff all day.</p>
<p>I had of course been aware of Smalltalk, as the source of a lot of the ideas behind things I was interested in – Objective-C and Ruby, obviously, but also TDD, wikis, even the Mac to some extent – but I had never gotten anywhere with actually using it; the environments were too different, the documentation too sparse, etc.</p>
<p>Sitting for a day at Camp Smalltalk was the boost I needed to get past that. And once I got a taste of Smalltalk, I couldn’t let go – I started right away on a port of IOWA to Smalltalk, and convinced my next couple of clients on web projects that I should use Smalltalk instead of Ruby. This port became Seaside, and over the next several years I built up a consulting business around Seaside training and development.</p>
<p>Smalltalk web development may seem like a small niche to build a business around, but the fact is that <strong>nobody</strong> else was doing it at the time (for that matter, nobody else was doing web development in Ruby at the time either – that situation is a little different now).</p>
<p>Some people to mention in this history – Julian Fitzell was my early partner on the web projects, and we worked together on the first version of Seaside. Colin Putney was one of my early clients, who had come to me based on my work in Ruby and I had to work hard to convince to use Smalltalk; he’s now a confirmed Smalltalker and works with me on Dabble DB. Andrew Catton worked with me at the software engineering lab, and was a frequent collaborator on various other projects over the years.</p>
<p>A few years in, a little fed up with consulting, Andrew and I started to work on a product on the side, and that project became Dabble DB. Last summer, we were lucky enough to get funded to work on that full time, and that’s what I’ve been doing since.</p>
<p><strong>AkitaOnRails:</strong> I see that you like the fact that Smalltalk is not “mainstream” in the Java-sense of the word. I can see the advantages and I agree with it. It’s like <em>“we are a small group of very smart people”</em>. Much like Apple’s own <em>“Think Different”</em> campaign. On the other hand the masses tend to like big bang marketing and support. What do you think of this culture clash? The most important part is: here in Brazil the market is very closed off to non-widely-commercially-supported tech. Meaning most of them don’t like anything different than Java or .NET. How do you convince your customers about using Smalltalk – if this is actually a matter there in the US?</p>
<p><strong>Avi Bryant:</strong> Yes, that’s a tricky balance. Some of the people I knew in the early days of Ruby’s popularity – post-Pickaxe, but pre-Rails – have complained about how much more popular Ruby has gotten lately, because inevitably the signal-to-noise ratio goes down on the mailing lists and at the conferences. Smalltalk doesn’t have that problem – in particular, Smalltalk has a nice mix of very experienced hackers – people like Dan Ingalls, who has been writing language implementations for more than 30 years, and has just an amazing depth of knowledge to share – and young troublemakers like myself. When you get too popular too quickly, you get a huge influx of young, inexperienced, energetic people, and the voice of experience tends to get drowned out. Not that new ideas aren’t valuable – they’re essential – but I think in this field we tend to overlook history far too much.</p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2007/12/15/198438575_ff982238f7.jpg" alt=""  loading="lazy" /></p>
<p>As for using non-standard tech, I think the best way to look at it is as a competitive advantage. Paul Graham points out that on average, startups fail, and the same could probably be said about software projects in general. So if you want not to fail, you have to do <strong>something</strong> different from the average, and using better technology is a great way to do that.</p>
<p>But you clearly have to be in a situation where results matter more than policy – it’s almost impossible to sell an enterprise IT department on a Smalltalk project. On the other hand, a small business owner couldn’t care less what technology you use when building a custom app for him – it’s not like he has an army of Java developers who are going to maintain it.</p>
<p>In general, the closer the alignment between the person who will be using the app, and the person who is writing the checks, the more they’ll care about having something that actually works, and the less about the buzzwords it involves.</p>
<p>That was my strategy when doing Smalltalk consulting, and that’s also our strategy with Dabble DB – we sell to users, not to CIOs.</p>
<p><strong>AkitaOnRails:</strong> That’s exactly how I think. Which boils down to you having a startup. I can understand being fed up by consulting work, but what led you to choose to open your own company to sell your own products? I heard that Tim Bray is also an investor for your company? Many people wouldn’t like to lose their comfortable job positions for something as risky as this. What was the reason for this direction in your career?</p>
<p><strong>Avi Bryant:</strong> When we were consulting, it became clear to Andrew and me that a) most companies, especially small businesses, couldn’t afford to hire us, and b) even those who could, they could only hire us for the very most important projects. The only way we were going to scale our business, and help as many people as possible, would be to effectively replace ourselves with software: build a product that would let them do the simple projects themselves.</p>
<p>We didn’t abandon everything to go and build this, however – we kept our existing clients (in fact, we took on some new ones to get a little extra capital to hire a web designer, etc), and we worked on the product on evenings and weekends, where we could.</p>
<p>As the product got further along, and it became more and more clear that there might be something worthwhile there, we started to work on it more in earnest, but still keeping some cash coming in with consulting.</p>
<p>Eventually, when the product was ready to launch, we knew we couldn’t handle Dabble DB customers at the same time as our consulting clients, and so we had to drop them entirely. That was when we took some investment from Ventures West and from Tim Bray.</p>
<p>So it was a fairly gradual transition, which made it a lot easier to do.</p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2007/12/15/dabbledb.gif" alt=""  loading="lazy" /></p>
<p><strong>AkitaOnRails:</strong> But even then, were you doing Smalltalk/Seaside consulting only? Or were you working on different languages/frameworks for customers and Smalltalk afterwork? And for non-starters how would you briefly describe <a href="http://www.dabbledb.com"target="_blank" rel="noopener">Dabble DB</a>? I hear that you’re about to release a companion product for it, right? Can you describe them?</p>
<p><strong>Avi Bryant:</strong> During that period, the consulting was all around Seaside, yes – there were some dark times earlier when I had to take some Java work :-)</p>
<p>Dabble DB is a hosted web app for small businesses and teams who need some kind of custom data management – maybe they need custom project management, or a custom contact database, or a custom HR application, or event planning, or just their DVD collection, but for whatever reason the off the shelf software doesn’t do what they need. Dabble lets them interactively build very rich reports on their data, with structured grouping and filtering, simple calculations and subtotals, and display it as a table, or a chart, or a map, or a calendar. You can then share these reports with people, or invite them in to enter or modify the data itself.</p>
<p>The companion product you’re referring to is, I think Dabble Pages. This is really just a new feature set on top of Dabble DB, which all Dabble customers get. What we’ve found is that in any organization there are usually a small number of people who want the full power of the Dabble DB user interface, and want to build new reports or add fields or restructure their data, etc. But there are also a much larger number of people who just want a simple web page where they can enter new data or view a report. So Pages lets that small core group build something for the larger group. It’s sort of like a souped up version of WuFoo or other form builders, but with Dabble DB as the administrative back-end.</p>
<p>It makes Dabble DB <strong>almost</strong> into a web development tool, in the sense that the administrative users really are building simple applications for the other people in their organizations – but without any whiff of programming, so of course the applications are very limited.</p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2007/12/15/Picture_2.png" alt=""  loading="lazy" /></p>
<p><strong>AkitaOnRails:</strong> Changing subjects a little bit, one thing that I do admire about you is your relationship with the Ruby/Rails community. Those are different paradigms and technologies, but you never dive in flame wars like ‘Smalltalk is better than Ruby’ just for the sake of it. On the contrary, to me it feels like you do like Ruby, as you presented at RailsConf about the possibility of running Ruby empowered by a modern VM like GemStone’s. But, you did switch from Ruby to Smalltalk. What was it that ‘clicked’ for you about Smalltalk? Continuations? The whole coding-in-runtime? The tighter environment integration?</p>
<p><strong>Avi Bryant:</strong> So, first of all, I very much do like Ruby, and Dabble DB includes about 3000 lines of Ruby code (I just checked) along with however much Smalltalk (and a sprinkling of Python).</p>
<p>What clicked about Smalltalk was a few things: one was simply the maturity, both of the community and of the technology. Smalltalk implementations have been refined over the last 25 years, and they’ve really benefited from it.</p>
<p>One of the major benefits, in my opinion, is that Smalltalk VMs are fast enough that it’s reasonable to implement all of the standard libraries – Array, Hash, Thread, and so on – in Smalltalk itself. So there’s no barrier where you switch from your Ruby code to the underlying C implementation; it’s “turtles all the way down”. This may not seem like a big deal but once you have it, it’s really hard to give it up.</p>
<p>Rubinius, of course, is moving in this direction for Ruby, and mad props to Evan and everyone else working on that project. For me, the Smalltalk environment is also key.</p>
<p>In some ways it’s the same things I talk about with Dabble DB: you don’t have to choose one way to organize your data, you can have one view that’s grouped by date and another filtered by customer and another where a map is the only way to understand. In Smalltalk, you don’t have to choose one file layout or order of methods and classes in your code; you’re constantly switching views on what’s basically a database of code.</p>
<p>My friend Brian Marick hates this, because you lose any “narrative” that might have existed by putting the code in a certain order in the file, and it’s hard to get used to, but for me, it’s the ultimate power tool for hacking on a large code-base.</p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2007/12/15/n517961878_38879_9189.jpg" alt=""  loading="lazy" /></p>
<hr>
<p>That’s it for Part 1. Stay tuned for more Avi, talking about Smalltalk and Ruby on Part 2 of this interview, to be released in a few days.</p>
]]></content:encoded><category>interviews</category><category>ruby</category></item><item><title>Chatting with John Lam (IronRuby)</title><link>https://akitaonrails.github.io/en/2007/11/12/chatting-with-john-lam-ironruby/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2007/11/12/chatting-with-john-lam-ironruby/</guid><pubDate>Mon, 12 Nov 2007 18:37:00 -0200</pubDate><description>&lt;p&gt;&lt;a href="http://www.iunknown.com/"target="_blank" rel="noopener"&gt;&lt;img src="http://s3.amazonaws.com/akitaonrails/assets/2007/11/12/n685772348_7884.jpg" alt="" loading="lazy" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It’s been a while since my last international interview, and I am back with none other than one of the people responsible for bringing Ruby to the .NET platform. That’s correct, I’ve been covering a lot about JRuby and Rubinius but we can’t neglect that one of the biggest platforms out there in the market is receiving the Ruby treatment as well. So I invited &lt;a href="http://www.iunknown.com/"target="_blank" rel="noopener"&gt;John Lam&lt;/a&gt; , who kindly answered several questions regarding this endeavor.&lt;/p&gt;</description><content:encoded><![CDATA[<p><a href="http://www.iunknown.com/"target="_blank" rel="noopener"><img src="http://s3.amazonaws.com/akitaonrails/assets/2007/11/12/n685772348_7884.jpg" alt=""  loading="lazy" /></a></p>
<p>It’s been a while since my last international interview, and I am back with none other than one of the people responsible for bringing Ruby to the .NET platform. That’s correct, I’ve been covering a lot about JRuby and Rubinius but we can’t neglect that one of the biggest platforms out there in the market is receiving the Ruby treatment as well. So I invited <a href="http://www.iunknown.com/"target="_blank" rel="noopener">John Lam</a> , who kindly answered several questions regarding this endeavor.</p>
<p>Remembering that <a href="http://www.ironruby.net/"target="_blank" rel="noopener">IronRuby</a> – named after <a href="http://www.ironpython.com/"target="_blank" rel="noopener">IronPython</a>, the first of the main open source dynamic languages built on top of .NET – is a <a href="http://www.opensource.org/node/207"target="_blank" rel="noopener">true open source</a> project, and also has a 3rd party addon for Visual Studio.NET, so programmers used to the VS.NET workflow can get onboard with a lower learning curve ahead of them.</p>
<p>Despite opinions against Microsoft just for the sake of arguing, the fact remains that Java and .NET represent the biggest corporate development market today. And this is also a fact that the Ruby meme is spreading in a very fast way. Being built to run on top of both the JVM and the CLR represents Ruby being enabled for market niches that it wouldn’t reach otherwise, and this is a huge win. I talked a little bit about this in my article (in portuguese): <a href="/2007/10/23/para-eu-ganhar-o-outro-precisa-perder">For myself to win, the other one has to lose</a>. There are very intelligent people at Microsoft, John Lam being one of them.</p>
<p>That said, let’s get started:</p>
<p><strong>AkitaOnRails:</strong> First of all, I always ask my guests about their careers: what was your path up until now? Meaning, how did you get yourself involved in computing, what drives you into it?</p>
<p><strong>John Lam:</strong> I wrote a lot of software before I graduated from High School in 1986. I shipped a bunch of commercial software for the Commodore ‘platform’ (aka PET, VIC-20, C-64/128) back in the day. In 1986 I decided that there was no future in computing (which shows why folks shouldn’t take my opinions seriously :)) and decided to study the physical sciences in University. I graduated in 1995 with my doctorate in Organic Chemistry and decided that there was no future in chemistry (which, if you look at how the reverse engineering of life today is based a lot on cross-discipline interaction with other branches of life sciences, shows why folks shouldn’t take my opinions seriously :)).</p>
<p>Once I decided to work in computing again, I took up an obscure new development platform called Delphi which shipped in 1.0 form around the time that I re-entered the field. I spent a bunch of time working on integrating Delphi with COM, which is where I originally hung my hat. The dark side of COM pulled me into its orbit and I’ve been working on Microsoft related stuff since then.</p>
<p><strong>AkitaOnRails:</strong> I see that you’re at Microsoft since January 2007, is that correct? How did you get in there, were you hired with the IronRuby project in mind? Is this your main assignment today?</p>
<p><strong>John Lam:</strong> Yes, I started in January. Before joining the company, I worked on an open source bridge between Ruby and the CLR called RubyCLR. When I decided to start promoting that work at conferences, I crossed paths with the DLR team at Microsoft. Mahesh Prakriya graciously donated half of his talk at Tech Ed in 2006 so that I could talk about RubyCLR. After much hand-wringing/mind-conditioning I wound up accepting their offer to work full time on a Ruby implementation on top of the DLR and we (my wife, two kids and dog) arrived in Redmond in January.</p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2007/11/12/166261351_2b04ab1086.jpg" alt=""  loading="lazy" /></p>
<p><strong>AkitaOnRails:</strong> What were the motivations behind starting IronRuby? How did it start? Were you the original and sole developer of a .NET<br>
implementation of Ruby?</p>
<p><strong>John Lam:</strong> We want to demonstrate that the DLR is truly a multi-language dynamic language runtime, so we had to build a number of languages on top of it. Ruby certainly fit the criteria: dynamic, strong user community, lots of attention, so it made sense to implement it. IronRuby has definitely forced a lot of design changes to the DLR, making it less ‘Pythonic’ which is a good thing for other folks who are interested in building a dynamic language on top of our platform.</p>
<p>I’m definitely not the sole developer on IronRuby. We have two great devs working on the project: Tomas Matousek and John Messerly and they’re doing awesome work. Our tester, Haibo Luo, is doing great work to make sure that we ship a high quality implementation. Haibo’s work will be released along with IronRuby, which means that the community can also benefit from his test suite.</p>
<p><strong>AkitaOnRails:</strong> Not many people here are familiar with the DLR and Silverlight, can you briefly describe them for non-starters? What makes a ‘DLR’ different from a ‘CLR’ besides jumping from “C” to “D”? :-)</p>
<p><strong>John Lam:</strong> The DLR is a platform that layers on top of the CLR. This means that we can run anywhere that the CLR can run, which of course includes Silverlight. Silverlight is our cross-platform browser-based platform that runs on Windows, Mac and Linux (via the Moonlight project). We ship a cross-platform version of the CLR which means that you’ll be able to run DLR-based languages with just a 5MB initial download into your web browser.</p>
<p><strong>AkitaOnRails:</strong> This is delicate: I once read Ola Bini and Charles Nutter criticizing the “Microsoft Way”, meaning that it would be extremely hard – if not impossible – for you to write a 100% complete Ruby 1.8 implementation on top of .NET without being able to peek into the source code. The reason being the company policy toward open source licenses. Was that the case?</p>
<p><strong>John Lam:</strong> I think that IronPython is the existence proof that you can build a compatible implementation of a dynamic language without looking at the original source code. In our work with IronRuby, I can tell you that not being able to look at the source code hasn’t prevented us from figuring out how Ruby accomplishes some feature – it’s all about designing the right experiments.</p>
<p><strong>AkitaOnRails:</strong> I also saw that IronRuby is going to be released under open source-compatible license from Microsoft, making it probably the first true open source project ever from Microsoft, meaning that you would not only allow people to take a look at the source code but also to contribute back to it. How far is this?</p>
<p><strong>John Lam:</strong> The Microsoft Public License was officially sanctioned by the OSI in early October. IronRuby, IronPython and the DLR are all released under this license.</p>
<p>We’ve already accepted contributions back in from the community, and are continuing to accept more contributions from the community.</p>
<p>We’re actually not the first Open Source project at Microsoft that accepts contributions back from the community. That honor belongs to the ASP.NET <a href="http://www.asp.net/ajax/ajaxcontroltoolkit/samples/"target="_blank" rel="noopener">AJAX control toolkit</a> which is an enormously successful project with &gt; 1M downloads to date.</p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2007/11/12/166261286_d084c57e46.jpg" alt=""  loading="lazy" /></p>
<p><strong>AkitaOnRails:</strong> The DLR was originally conceived as an experimental way to run Python on top of .NET. Did this make it easier for a Ruby implementation or do you feel that Python and Ruby were different enough to guarantee lots of tweaks into the DLR to make it feasible?</p>
<p><strong>John Lam:</strong> It’s fair to call the original version of the DLR the “Python Language Runtime”. Adding Ruby to the mix forced a lot of additional changes to the DLR, the most significant being the refactoring of the runtime to migrate all of the Python specific idioms (which were thought to be general but turned out not to be the case) into IronPython.dll. What remains is a core which our the 4 languages developed by MSFT (IronRuby, IronPython, Managed JScript and VB) continue to use effectively today.</p>
<p><strong>AkitaOnRails:</strong> Is it a goal to be 100% compatible with MRI 1.8? Or are you going toward a sub-set of the Ruby implementation? This would make it possible to write .NET programs in Ruby, using the full set of .NET libraries and frameworks as ASP.NET, Windows.Form, LINQ, etc. Or are you planning on a full blown MRI compatible implementation, enough to be able to run an entire Rails application?</p>
<p><strong>John Lam:</strong> Our #1 priority is being as compatible as possible with MRI 1.8.×. The one feature that we will not support is continuations, which is consistent with JRuby. Other than that (and in the absence of a Ruby spec), compatibility will be judged by whether we can run real Ruby applications and community developed Ruby test suites. Obviously Rails is an extremely important Ruby application, which we will absolutely run on top of IronRuby.</p>
<p>.NET interop is our #2 priority. We will integrate with the .NET platform, and allow you to write Ruby applications using the rich set of .NET libraries. Obviously things like Silverlight, WPF, LINQ, WinForms, and ASP.NET will be supported.</p>
<p><strong>AkitaOnRails:</strong> Ruby grew as a collective and low profile effort that really exploded 3 years ago because of Rails. That’s one reason no one ever bothered to write a formal specification and test suite. You have Alioth, you have the current YARV test suite. Did you have a hard time because of this lack of formal specs? Are you in contact with people like Charles from JRuby, Koichi Sasada from YARV or Evan Phoenix from Rubinius? What do you think of all these efforts going on in parallel? Is there any way you can contribute with one another?</p>
<p><strong>John Lam:</strong> We’re using the Rubinius spec suite today, and plan on shipping it along with our sources to ensure that we catch compat bugs early in the process. I’m guilty of not participating as much as I would like to in talking more with Charlie, Evan and Koichi about collaborating on specs. We’re focused on getting the core language up and running today, and, like a lot of other fast-moving projects, have been neglecting to document the things we have learned. Once the pace of the project slows down a bit, I’ll be able to spend more time engaging with the other implementers.</p>
<p><strong>AkitaOnRails:</strong> Ruby has a lot of known deficiencies. Koichi is trying to improve on some of them for Ruby 1.9. How are you tackling problems like lack of native threading, simple mark and sweep garbage collector, no virtual machine and thus no byte-code compilation, performance issues, lack of native internationalization (Unicode), lots of C-based extensions.</p>
<p><strong>John Lam:</strong> We get a lot of things for ‘free’ by running on top of the CLR. Native threading is supported in IronRuby. We use the CLR garbage collector, which is a world-class GC. We compile natively to IL, and our IL can be GC’d as well which is goodness for long-running server based applications. We will obviously support CLR strings, which are Unicode strings and we will also support Ruby mutable strings which are based on byte arrays. We will not support C-based extensions at all, instead we will be porting the existing C-based libraries in the Ruby Standard Library to C# (or Ruby).</p>
<p><strong>AkitaOnRails:</strong> Are there any benchmarks comparing IronRuby with the MRI? Do you think you’re already outperforming it? Are there any issues today around Ruby performance over the DLR? Or more interestingly: is there any comparison between Ruby on DLR and C# or VB.NET over the CLR?</p>
<p><strong>John Lam:</strong> We are faster than MRI in the YARV benchmarks, but that number changes daily. One great thing about our team is that we have a performance regression test suite that we regularly run across all of our code. This makes it trivial to pinpoint a build that causes a regression in performance, even if we postpone that work for a while.</p>
<p>We have done zero performance tuning so far; we’re just using features that exist in the DLR today, like polymorphic inline caches for efficient call-site method caching. As our implementation matures, we will tune IronRuby to perform well on application-level benchmarks (not just microbenchmarks which are useful to us but not so interesting to real customers). The DLR (and CLR) is becoming faster all the time, and any dynamic language that is built on top of the DLR will benefit from these improvements.</p>
<p>Obviously, languages like C# and VB.NET are faster than Ruby today. But we are confident that we can significantly narrow that gap over time.</p>
<p><strong>AkitaOnRails:</strong> What about tooling? I saw you tweaked your Visual Studio.NET to have the Vibrant Ink that we – TextMate users – are used to, and it looks nice. I even saw a screenshot of code folding of Ruby inside of Visual Studio. How is its support for Ruby?</p>
<p><strong>John Lam:</strong> Right now our team isn’t involved in VS integration. However, the good folks at <a href="http://www.sapphiresteel.com/IronRuby-Visual-Designer"target="_blank" rel="noopener">Sapphire in Steel</a> are doing great work at integrating IronRuby into VS.</p>
<p><a href="http://www.sapphiresteel.com/IronRuby-Visual-Designer"target="_blank" rel="noopener"><img src="http://s3.amazonaws.com/akitaonrails/assets/2007/11/12/editing_small.gif" alt=""  loading="lazy" /></a></p>
<p><strong>AkitaOnRails:</strong> You mentioned in an interview the possibility of Ruby running on top of Silverlight. How feasible is this today?</p>
<p><strong>John Lam:</strong> We demonstrated IronRuby running on top of Silverlight at RubyConf. The talk should be posted soon. We’re planning on rendezvousing with Silverlight in time for their next CTP (late this year / early next year). At that time, you will be able to code in Ruby that runs in your browser.</p>
<p><strong>AkitaOnRails:</strong> Microsoft is learning on how to deal with the open source community. Do you think the adoption of technologies as Python and Ruby are helping the company to understand the open source way? What do you think still has to improve? Meaning, if you could, what would you change?</p>
<p><strong>John Lam:</strong> Microsoft is a big company and we’re working very hard on working together with the Open Source community. IronRuby is one of the most visible Open Source projects in the company, and we’re helping to pave the way for other teams that want to engage with the Open Source community. Change happens incrementally at big companies and it’s been fun being a part of that change!</p>
<p><strong>AkitaOnRails:</strong> Silverlight was released over an open source license as well, so that the Mono guys were able to run it very quickly over Mono. Are you close to Miguel De Icaza? What do you think about Mono? An IronRuby running on top of it means a multi-platform Ruby that can run over Linux. If you ever get 100% compatibility with MRI and Rails, this means running over Apache+mod_mono on Linux and over IIS on Windows, everything developed under Orcas. Are there any plans for this kind of integration and end-to-end solution?</p>
<p><strong>John Lam:</strong> Actually, Silverlight is not released under an Open Source license. The DLR, IronPython and IronRuby are all released under the Microsoft Public License, which makes it possible for Miguel and his band of merry men to just ship it on top of their Moonlight implementation.</p>
<p>I love how pragmatic Miguel is. We showed IronRuby running on top of Mono at RubyConf and that was largely due to the Mono team fixing a bunch of bugs at the last minute so that we could demo (thanks!). DLR + Iron* tends to push the C# and the CLR pretty hard. We’ve uncovered bugs in the Microsoft C# compiler, and we’ve uncovered bugs in gmcs under Mono as well. But thankfully, both the C# team and the Mono team have been great at fixing those bugs to unblock us.</p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2007/11/12/481182714_62e1d07f7c.jpg" alt=""  loading="lazy" /></p>
<p><strong>AkitaOnRails:</strong> I think, that’s it for today. Any closing remarks for the Brazilian audience?</p>
<p><strong>John Lam:</strong> Thanks for sending along a great set of questions! Good luck with your Ruby adventures and I hope you’ll have a chance to check out IronRuby in the future.</p>
]]></content:encoded><category>interviews</category><category>ruby</category><category>programming-languages</category></item><item><title>Chatting with Jamis Buck</title><link>https://akitaonrails.github.io/en/2007/08/06/chatting-with-jamis-buck/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2007/08/06/chatting-with-jamis-buck/</guid><pubDate>Fri, 03 Aug 2007 22:46:00 -0300</pubDate><description>&lt;p&gt;&lt;img src="http://s3.amazonaws.com/akitaonrails/assets/2007/8/3/245186199_71f55cc3c7.jpg" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;This is another big interview. This time with Jamis Buck, the programmer that helped David Hansson himself right at the beginning of Rails, at 37signals.&lt;/p&gt;
&lt;p&gt;Today most renowned for his achievements in Capistrano and a lot of other Ruby libraries as sqlite-ruby bindings and Net::SSH. Jamis was very kind to give us the opportunity to know more about his career and the beginnings of the Ruby on Rails story.&lt;/p&gt;</description><content:encoded><![CDATA[<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2007/8/3/245186199_71f55cc3c7.jpg" alt=""  loading="lazy" /></p>
<p>This is another big interview. This time with Jamis Buck, the programmer that helped David Hansson himself right at the beginning of Rails, at 37signals.</p>
<p>Today most renowned for his achievements in Capistrano and a lot of other Ruby libraries as sqlite-ruby bindings and Net::SSH. Jamis was very kind to give us the opportunity to know more about his career and the beginnings of the Ruby on Rails story.</p>
<p><strong>AkitaOnRails:</strong> Ok, so let’s get started. first thing I always ask my guests: what’s your background? I mean, when, how, why did you start on computer programming? Did it begin the classic way, as a hobby, or was it a more recent thing because of career or something else?</p>
<p><strong>Jamis Buck:</strong> I started programming when I was in the 10th grade, when my mom got a brand-spanking-new Tandy personal computer. It had all of 20 megs of disk space, and came with <a href="http://en.wikipedia.org/wiki/GW-BASIC"target="_blank" rel="noopener">GW-BASIC</a>. I’d done some programming before, turtle-graphics and a bit of BASIC, but that Tandy was when I got serious about it. I taught myself GW-BASIC from the little reference book the computer came with and wrote a few simple games and utilities. Then I taught myself Turbo Pascal and Turbo C++ in 11th and 12th grades, and it’s gone from there :)</p>
<p><strong>AkitaOnRails:</strong> Then you decided to go for CS in college? I read at your profile in <a href="http://www.workingwithrails.com/person/5309-jamis-buck"target="_blank" rel="noopener">WorkingWithRails</a> that you’re a repentant Java programmer? How long have you been programming in Java?</p>
<p><strong>Jamis Buck:</strong> Yeah, I then jumped into Computer Science when I got to college. I graduated a bit late, in 1999, after working full-time for the university (<a href="http://www.byu.edu/webapp/home/index.jsp"target="_blank" rel="noopener">BYU</a>) as a programmer for a couple of years. That was where I did all my Java work. We were actually doing web-apps in C, which was not as insane as it sounds! But then we had a change of leadership when a new CIO came in, and he basically issued a blind mandate: <em>“learn Java, ditch C!”</em> So we had to massively retool and get certified and so forth. I was on the team that led the research into what Java tools we should use, and so got a lot of experience that way. I did Java work full-time there for about 2 years, until <a href="http://37signals.com/"target="_blank" rel="noopener">37signals</a> came along in Feb 2005 and made me a better offer, and I’ve never looked back!</p>
<p><strong>AkitaOnRails:</strong> Wow, so you jumped right in from Java in the university to Rails at 37signals? This is a little earlier than I expected, but as you already mentioned it: how did you get in touch with the 37signals guys? How did you start on Ruby being so overwhelmed with Java before?</p>
<p><strong>Jamis Buck:</strong> Well, I’d been involved with Ruby (primarily as a hobby) since about 2001. I’d written a few libraries, like the <a href="http://sqlite-ruby.rubyforge.org/"target="_blank" rel="noopener">sqlite</a> and sqlite3 bindings, and at RailsConf 2004, I met DHH. I did a bit of work at the conference there to make Rails speak to sqlite databases. After that, around November 2004, I think, David asked if I would be interested in doing some consulting for 37signals. In December and January I did a few odd jobs for them like adding SFTP and time zone support to Basecamp. And then in February they flew me to Seattle to attend the <a href="http://www.37signals.com/workshop-062504.php"target="_blank" rel="noopener">Building of Basecamp</a> workshop there and they made me an offer.</p>
<p><strong>AkitaOnRails:</strong> I understand that 37signals is a small company in terms of number of employees and most of its inner power comes from this very fact. Did it change much since you began, I mean, in the last 2 ~ 3 years? What did you like the most back then and what do you like the most right now?</p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2007/8/3/conf_room.jpg" alt=""  loading="lazy" /></p>
<p><strong>Jamis Buck:</strong> Well, when I came on, I was the 5th employee, and the second programmer. Previous to my coming, David did all the programming and sysadmin work, so I think it was a big relief to him to have someone to share the load! About a year later, we hired two more programmers, and we’ve since hired two more people, including a full-time sysadmin. The changes have been for the better :) I like having a real sysadmin. I can’t tell you how much I hated being a sysadmin, since I had little idea what I was doing!</p>
<p><strong>AkitaOnRails:</strong> You seem to be the kind of guy that like the <em>kitchen-sink</em> because you’ve been involved with ‘low-level’ stuff like sqlite-bindings, Net::SSH and so on. Is this the kind of thing that excites you the most? Or it’s just a coincidence and you actually rather do GUI work as well?</p>
<p><strong>Jamis Buck:</strong> I actually swore, some years ago, that I would never be a web-app developer :) I’ve always preferred writing the tools as opposed to writing the apps. But I’ve really enjoyed writing web-apps at 37signals. The team is great and the toolset (Rails!) is amazing. I still do enjoy writing libraries (working on <a href="http://raa.ruby-lang.org/project/net-ssh/"target="_blank" rel="noopener">Net::SSH</a> and <a href="http://raa.ruby-lang.org/project/net-sftp/"target="_blank" rel="noopener">Net::SFTP</a> v2 right now, in fact) but apps aren’t so bad either :)</p>
<p><strong>AkitaOnRails:</strong> But back then when you were literally second-in-command you didn’t have much choice, did you? I bet you did some of the Basecamp interfaces? And you mentioned that you didn’t like much of the sysadmin work because you didn’t know what you were doing, but now you probably are an expert because Capistrano rocks in this field. I remember it being called SwitchTower before. Can you tell us its story?</p>
<p><strong>Jamis Buck:</strong> I’ve done quite a bit of the work on all of the apps, some more than others. I don’t actually write the UI’s (that’s the domain of Jason Fried and Ryan Singer), but I’ve plugged them in and made them work.</p>
<p>I learned a ton about sysadmin work from when I had to do it. I’m still a major newbie at it but I learned more than I ever thought I’d learn about how mysql really works, for instance :)</p>
<p>When I first released Capistrano, a year and a half ago or so, it was called SwitchTower, but around March 2006 I got a <a href="http://en.wikipedia.org/wiki/Cease_and_desist"target="_blank" rel="noopener">C&amp;D</a> from a company that had the name trademarked, and so I had to scramble for a new name. The Rails Core Team helped immensely at that time, they offered a TON of suggestions for names. Marcel eventually IM’d me and suggested “Capistrano” which just clicked for me and I went with it. I got some flack from some people, who thought the name was lousy, but I laugh now because most people that use cap today probably came to it after the name change and never knew any other name, and they don’t even think twice about it.</p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2007/8/3/logo-big.png" alt=""  loading="lazy" /></p>
<p><strong>AkitaOnRails:</strong> You are probably very overwhelmed now because of the Capistrano 2.0 release. It is a major departure from the 1.4.1 if I understand correctly. You rewrote a lot of stuff, had to break backward compatibility. Do you feel you got what you wanted with this release or are you aiming for more in a 3.0 release?</p>
<p><strong>Jamis Buck:</strong> Cap2 is pretty much just what I wanted it to be. There are few minor tweaks in the pipeline, but nothing significant. It is about 90% backwards compatible with Cap1, so most people should have no problems switching. And since the 2.0 release, the maintenance load for cap has been really small. I’m very pleased with it. I still need to get busy with documentation though :) That’s the thing that still holds a lot of people back.</p>
<p><strong>AkitaOnRails:</strong> What is it that you like the most about cap? You obviously use it at your own deployments at 37signals. I fantasize you having a bunch of shell scripts more than a year ago and then weaving them together to build what was the first release of Capistrano.</p>
<p><strong>Jamis Buck:</strong> Prior to SwitchTower/Capistrano, we had a tool that David had written for deploying Basecamp. Back then, Basecamp ran on a single server, so deployment was little more than “svn up”. Later, we moved Basecamp to multiple servers and launched Backpack, and we realized we needed something more powerful for deployments. So I was tasked with writing something and Capistrano was the result. The thing I like most about it is how it takes the tedium out of being a sysadmin. The “cap shell”, in particular, lets you immediately and easily execute arbitrary commands on multiple servers, simultaneously, which is really handy. Of course, “cap deploy” is nice too :)</p>
<p><strong>AkitaOnRails:</strong> I remember one episode where David reported about a 72 hours glitch that let Basecamp out. Were you involved in that episode? :-) Headaches like this seems funny when you remember about them now, but obviously not so funny at the time.</p>
<p><strong>Jamis Buck:</strong> ha, yeah, that actually happened a few days after I was hired :) We were adding UTF-8 support to Basecamp and the database migration did not go well. We pulled an all-nighter. Quite the introduction to 37signals’ culture :) Fortunately, that kind of thing hasn’t happened since, though we’ve had our share of other emergencies, of course.</p>
<p><strong>AkitaOnRails:</strong> Lessons learned? I think that’s the most important outcome of these situations :-)</p>
<p><strong>Jamis Buck:</strong> The main lesson I learned that time: when you’re mucking with charsets, make sure you test it on as many non-Latin1 alphabets as possible :) Naturally, we tested it a lot before we deployed, but we didn’t really think to check any Russian or Japanese data that was in our database after the test, which seems obvious in hindsight. We did try some non-Latin1 alphabets during testing but the ones we tried just happened to work in spite of the bugs. Another lesson learned: no matter how hard you prepare, something’s going to fall through the cracks!</p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2007/8/3/245186199_71f55cc3c73.png" alt=""  loading="lazy" /></p>
<p><strong>AkitaOnRails:</strong> I headed a group of very committed volunteers and got your <a href="http://gettingreal.37signals.com/GR_por.php"target="_blank" rel="noopener">Getting Real</a> book translated into Brazilian Portuguese a while back. I believe you were involved in it too? This book is iconic to picture the 37signals spirit I guess. Do you really move the way it’s written? :-)</p>
<p><strong>Jamis Buck:</strong> I was actually not too involved in the composition of the book, though I gave some feedback during the writing process. But yes, that book describes our own processes. There really isn’t anything in that book that we don’t actually do.</p>
<p><strong>AkitaOnRails:</strong> How do you operate? I believe that not everybody work in the same physical location? Do you do a lot of remote work? How many programmers/sysadmins/designers are there now?</p>
<p><strong>Jamis Buck:</strong> Chicago is definitely the “heart” of 37signals: Jason, Ryan, David, and Sam all live and work there. We have an office there as well, and the Chicagoites go there pretty regularly to work (though they also work from home some, too) Matt Linderman is our writer, he lives and works in NYC. Mark Imbriaco, our sysadmin, lives and works in Chesapeake, Virginia and Jeremy Kemper is another programmer, living in Pasadena, California now. The distributed nature of it works very well for us. I really love working from home, it lets me be more involved in my kids’ lives, for instance, than I would otherwise be.</p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2007/8/3/building_djd.jpg" alt=""  loading="lazy" /></p>
<p><strong>AkitaOnRails:</strong> I hear you’re from Provo, Utah? It is a coincidence as my current boss, <a href="/en/2007/7/20/conversando-com-carl-youngblood">Carl Youngblood</a>, is also from there and also studied at BYU :-) You don’t possibly know each other, do you?</p>
<p><strong>Jamis Buck:</strong> I actually live in Caldwell, Idaho now, but I was in Provo for about 8 years and yes, I do know Carl! We were both in the <a href="http://groups.google.com/group/urug?hl=en"target="_blank" rel="noopener">Utah Ruby Users Group</a>. He’s a great guy.</p>
<p><strong>AkitaOnRails:</strong> You attended many conference for the Ruby community. I don’t remember if you wrote any books. Are you writing some now?</p>
<p><strong>Jamis Buck:</strong> I was originally going to write a book about Capistrano for Apress, but that’s fizzled. I’m not actively involved in any book writing at the moment, and don’t really have much interest in it, honestly. I much prefer writing software! And I try to post to my blog once in awhile, too.</p>
<p><strong>AkitaOnRails:</strong> Yes, the <a href="http://weblog.jamisbuck.org/"target="_blank" rel="noopener">buckblog</a>, it has lots of great tips that I like to read. Did you start it because of Rails or you already had a Java blog back then?</p>
<p><strong>Jamis Buck:</strong> I started it pre-Rails. If you read the early articles, you’ll see they were pretty eclectic. I was still trying to figure out this whole “blog” thing :) I’ve since come to focus on software-development and use my <a href="http://family.jamisbuck.org"target="_blank" rel="noopener">family blog</a> for more personal posts these days.</p>
<p><strong>AkitaOnRails:</strong> I was a Java programmer myself and I still try to maintain myself informed about what’s going on in other communities as Java, some PHP, Python. What do you think or feel about other frameworks and technologies as CakePHP, Avi Bryant’s <a href="http://www.seaside.st/"target="_blank" rel="noopener">Seaside</a> or even Django?</p>
<p><strong>Jamis Buck:</strong> Honestly, I’m a bit ashamed to admit that I don’t keep up on other frameworks as much as I should. Seaside has some neat ideas and my desire to improve my Smalltalk programming skills has made me want to poke into that further. But other than that, I haven’t shopped around much (to my own personal detriment, I’m sure).</p>
<p><strong>AkitaOnRails:</strong> And still about Java, I am very excited nowadays about JRuby. I interviewed <a href="/en/2007/06/21/conversando-com-ola-bini-jruby-core-team-member">Ola Bini</a> and I’m also kind of stalking Charles Nutter. Did you know the guys? Did you got interested in trying it?</p>
<p><strong>Jamis Buck:</strong> I know who they are, and I’ve met Charles at a few conferences, but I’ve never really had a chance to talk to them in depth. JRuby definitely sounds exciting. I’m very curious, in fact, to know whether it can support Net::SSH or not since that would mean you could run Capistrano under it. But I’ve not had a chance to actually try it out.</p>
<p><strong>AkitaOnRails:</strong> Insisting on the Java subject, I posted a while back about some discussions about Design Patterns pointing to <a href="/2007/07/30/gof-design-patterns-sobreviveu-ao-teste-do-tempo/">flaws in languages</a>, and I just read <a href="http://weblog.jamisbuck.org/2007/7/29/net-ssh-revisited"target="_blank" rel="noopener">a post</a> you wrote about Dependency Injection and your Net::SSH library. What do you think about Design Patterns now that you’re a full-time Ruby programmer?</p>
<p><strong>Jamis Buck:</strong> Design Patterns are wonderful. They give us a language to talk more concisely about programming. It is so much easier to say “use a factory method” than to circumlocate and confuse each other. As for specific design patterns, some are more useful than others in different environments. As I wrote in my post, Dependency Injection is just not something you need in Ruby, but in environments like Java, it can be a life-saver.</p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2007/8/3/276456883_dd0ae43334.jpg" alt=""  loading="lazy" /></p>
<p><strong>AkitaOnRails:</strong> About 37signals again, you are very committed to Apple products. I saw that video on <a href="http://www.apple.com/education/whymac/compsci/video.html"target="_blank" rel="noopener">Apple Education</a> with Jason and David. And now we see that <a href="http://weblog.rubyonrails.org/2006/8/7/ruby-on-rails-will-ship-with-os-x-10-5-leopard"target="_blank" rel="noopener">Leopard</a> will bring not only Ruby but also Rails, Mongrel and even Capistrano. How is your relationship with Apple?</p>
<p><strong>Jamis Buck:</strong> I wouldn’t say there is any “relationship” with Apple. We’re big fans of their designs and interfaces and I think that reflects in our own work. Apple itself is including Rails, Mongrel, and Capistrano in the wake of those tools’ successes. Mac OS X really is a powerful environment for programmers and adding those tools “out of the box” makes it even more so. It makes sense to include the popular Ruby tools, too, since Ruby is going to be a <a href="http://rubycocoa.sourceforge.net/HomePage"target="_blank" rel="noopener">first class citizen</a> when it comes to developing OS X applications, thanks to the adoption by Apple of the Cocoa bindings for Ruby.</p>
<p><strong>AkitaOnRails:</strong> You obviously use a Mac for your work. What are the tools you use the most besides Textmate?</p>
<p><strong>Jamis Buck:</strong> Well, Capistrano :) Firefox w/ Firebug, Parallels (for IE testing), iTerm (though I’m looking forward to the new Terminal.app in Leopard), <a href="http://www.campfirenow.com"target="_blank" rel="noopener">Campfire</a> is indispensable, AdiumX, NetNewsWire, Knox (for simpler encrypted filesystem access). I still fall back and use vim pretty often too, for quick edits. There are probably others :) But I can’t think of them off the top of my head.</p>
<p><strong>AkitaOnRails:</strong> There are a lot of talk about <a href="http://en.wikipedia.org/wiki/Getting_Things_Done"target="_blank" rel="noopener">GTD</a> nowadays. I think I saw your profile at 43folders. Are you into this kind of organization philosophy as well? How do you maintain your routine organized? Many people (myself included) have a hard time differentiating work from hobby and keeping ourselves within the project’s deadlines and such.</p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2007/8/3/502950270_7175d894c8.jpg" alt=""  loading="lazy" /></p>
<p><strong>Jamis Buck:</strong> I’m not a GTD fanatic. I guess I try to be pretty pragmatic about it. I’m terrible about procrastinating, though. Mostly, from 8-5 I try to focus on the tasks that have been assigned to me and outside of that, I work on my hobbies… which happen to overlap work sometimes :) I’m really the wrong person to ask about being organized! If it weren’t for my wife, I think I’d get very little done, actually.</p>
<p><strong>AkitaOnRails:</strong> What are you most interested nowadays besides Rails, Capistrano? Not only technology-wise. Any hobbies?</p>
<p><strong>Jamis Buck:</strong> I’ve lately become very interested in military history, which has lead me to read about the American Civil War among other things. My wife and I are really enjoying Harry Potter #7 right now, too :) And I’ve become quite attached to my Nintendo Wii lately, as well! I used to be quite into role playing games, but haven’t done that for a few years. I’ve still got a ton of books for <a href="http://en.wikipedia.org/wiki/Dungeons_&amp;_Dragons"target="_blank" rel="noopener">D&amp;D</a>, though, and maybe someday I’ll dust them off :) I enjoy spending time with my kids (Nathaniel is 5, and Katie is 3). We’ll be going camping for a few days in a week or two, actually. Always something to keep me busy!</p>
<p><strong>AkitaOnRails:</strong> Haha, I see. And do you travel a lot? Outside of the US, I mean.</p>
<p><strong>Jamis Buck:</strong> Not really. Last year I went to London for the first time, for RailsConf there, and this year I went to the Czech Republic. But aside from that, I’m really a homebody. I’d kind of like to do more traveling, but I don’t like to travel alone and having kids puts a damper on the spontaneous “get up and go” aspect of travel. We do occasional road trips and stuff, though, which is fun.</p>
<p><strong>AkitaOnRails:</strong> Do you hear what’s going on the Ruby/Rails communities around the world? What do you feel about the meteoric rise of Rails in the US? 37signals, of course, was the fuel for all this and the reason we – both Rubyists now – are talking today.</p>
<p><strong>Jamis Buck:</strong> I hear some news, but I’ve trimmed my newsfeed quite a bit. I think I only subscribe to 30 or 40 feeds these days. It was really exciting to go to the Czech Republic and see the excitement there about Rails. It reminded me a lot of how things were in the US a couple of years ago.</p>
<p>The rise of Rails has been incredible. There have been growing pains, of course. With wider adoption you begin to accumulate people who aren’t passionate about the tool, and only want to learn it for the resumé, or because a client has asked for it, and I think that dilutes the waters quite a bit. But there will always be a core of passionate users and that’s what makes the community so wonderful. It’s been a really amazing experience to have been a part of that core, almost since the beginning of Rails.</p>
<p><strong>AkitaOnRails:</strong> You have the rare opportunity of seeing all this from a VIP perspective near Jason and David. And of course, yourself, being one the propellers of the community. Many people think of David as an <a href="http://www.flickr.com/photos/eugevon/130610241/"target="_blank" rel="noopener">arrogant</a> :-) I can perfectly understand his opinionated point of view. What do you think of it, from the perspective of someone who actually know the man?</p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2007/8/3/245186199_71f55cc3c72.png" alt=""  loading="lazy" /></p>
<p><strong>Jamis Buck:</strong> David is one of the most confident people I have ever met. My biggest frustration with him is that he’s RIGHT so often. He’s a very clear thinker and jumps right to the core of the issue, which can be very disconcerting if you aren’t used to that. All those attributes combine, I think, to make people who don’t know him consider him “arrogant”. But he’s not arrogant. He doesn’t put people down in order to raise himself up. He’s just extremely gifted, very smart, and doesn’t beat around the bush. I’m very honored to be able to know him. I’ve learned a lot from both him and Jason.</p>
<p><strong>AkitaOnRails:</strong> I don’t know if I got it correctly but Jason Fried was the one that started 37signals? Can you give us a small glimpse on the origins of the company? I know that David is not from the US, how did they get to meet each other?</p>
<p><strong>Jamis Buck:</strong> Jason co-founded 37signals, in the late 90’s. It was originally a design consultancy. In 2003, Jason started to work on a project in PHP, and asked around online whenever he got stuck. David responded to his queries several times and Jason finally just asked David if he would write the project. David came on part-time for awhile, then, since he was still finishing school. But eventually, Jason wanted to write Basecamp, and David did all the work on that, part-time, in Ruby. His experiences with that, of course, led to Rails. And eventually David become a partner in the company. That was in 2004, if I remember correctly.</p>
<p><strong>AkitaOnRails:</strong> Great. And coming back about you. Now that Capistrano 2.0 is finally released, are you involved in some new open source tool?</p>
<p><strong>Jamis Buck:</strong> With Cap2 out the door, I’m really focused on rewriting Net::SSH and Net::SFTP. Some frustrations with their limitations in writing cap2 has made this necessary :) The only “new” thing to come of this is Net::SCP, which is an implementation of an SCP client in Ruby and which I will release when I release v2 of Net::SSH and Net::SFTP.</p>
<p><strong>AkitaOnRails:</strong> Oh, and speaking of which, I remember that the former Cap 1.4.1 didn’t play very well on Windows boxes. Is that correct? Any advances in this field or do you feel that supporting Windows is just too much?</p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2007/8/3/506252072_642ad7ea39.jpg" alt=""  loading="lazy" /></p>
<p><strong>Jamis Buck:</strong> Well, as far as I know, cap 1.4.1 worked fine on Windows machines. The limitation was that you can not deploy TO Windows. Deploying FROM Windows works fine. And as for making cap deploy TO Windows, I have no plans. The difficulty is that Windows is not a POSIX environment, which is one of the fundamental assumptions of Capistrano, regarding the target machines.</p>
<p><strong>AkitaOnRails:</strong> Ah, yes. I never tried that, therefore my confusion. You’re right. Well, I think I already got a lot from you. Anything that you would want to say to the Brazilian community? :-)</p>
<p><strong>Jamis Buck:</strong> <em>“Stay passionate”</em> :) Keep the passion for Rails burning, it’s what makes the community worth belonging to.</p>
<p><strong>AkitaOnRails:</strong> Couldn’t be better. Any plans for coming here?</p>
<p><strong>Jamis Buck:</strong> Ha, none in the immediate future :) I’ve got a baby coming in September, which puts a damper on travel plans :) I’d love to visit Brazil someday, though.</p>
<p><strong>AkitaOnRails:</strong> Didn’t know that. Congratulations!</p>
<p><strong>Jamis Buck:</strong> Thanks.</p>
<p><strong>AkitaOnRails:</strong> Well, thanks a lot for your time. It was a very insightful conversation. I know people will enjoy this.</p>
<p><strong>Jamis Buck:</strong> Thank you very much, Fabio. I’m grateful for the opportunity!</p>
]]></content:encoded><category>interviews</category><category>devops</category><category>ruby</category></item><item><title>Chatting with Carl Youngblood</title><link>https://akitaonrails.github.io/en/2007/07/20/chatting-with-carl-youngblood/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2007/07/20/chatting-with-carl-youngblood/</guid><pubDate>Fri, 20 Jul 2007 14:36:00 -0300</pubDate><description>&lt;p&gt;&lt;img src="https://akitaonrails.s3.amazonaws.com/files/carl.934570.jpeg" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;This will be a fun interview. My guest this time is my boss. He’s not only an employee of Surgeworks but an active Ruby contributor and participates mainly in the Utah Rails User Groups (URUG). Many of his values and ideas resemble my own.&lt;/p&gt;
&lt;p&gt;Carl Youngblood has worked professionally as a software engineer for over ten years, and is currently the Rails Practice Manager for &lt;a href="http://surgeworks.com"target="_blank" rel="noopener"&gt;Surgeworks&lt;/a&gt;, a software engineering consulting firm (where I happen to be as well :-). In addition to his work at Surgeworks, Carl is an owner of &lt;a href="http://confreaks.com"target="_blank" rel="noopener"&gt;Confreaks&lt;/a&gt;, a company that records conferences, seminars and workshops, and is a director of the &lt;a href="http://transfigurism.org"target="_blank" rel="noopener"&gt;Mormon Transhumanist Association&lt;/a&gt;. He received a bachelors degree in Portuguese from &lt;a href="http://www.byu.edu"target="_blank" rel="noopener"&gt;Brigham Young University&lt;/a&gt; and a masters degree in Computer Science from the &lt;a href="http://www.washington.edu"target="_blank" rel="noopener"&gt;University of Washington&lt;/a&gt;.&lt;/p&gt;</description><content:encoded><![CDATA[<p><img src="https://akitaonrails.s3.amazonaws.com/files/carl.934570.jpeg" alt=""  loading="lazy" /></p>
<p>This will be a fun interview. My guest this time is my boss. He’s not only an employee of Surgeworks but an active Ruby contributor and participates mainly in the Utah Rails User Groups (URUG). Many of his values and ideas resemble my own.</p>
<p>Carl Youngblood has worked professionally as a software engineer for over ten years, and is currently the Rails Practice Manager for <a href="http://surgeworks.com"target="_blank" rel="noopener">Surgeworks</a>, a software engineering consulting firm (where I happen to be as well :-). In addition to his work at Surgeworks, Carl is an owner of <a href="http://confreaks.com"target="_blank" rel="noopener">Confreaks</a>, a company that records conferences, seminars and workshops, and is a director of the <a href="http://transfigurism.org"target="_blank" rel="noopener">Mormon Transhumanist Association</a>. He received a bachelors degree in Portuguese from <a href="http://www.byu.edu"target="_blank" rel="noopener">Brigham Young University</a> and a masters degree in Computer Science from the <a href="http://www.washington.edu"target="_blank" rel="noopener">University of Washington</a>.</p>
<p><strong>AkitaOnRails:</strong> So, let’s get started. This is very strange to interview someone you already know. But let me try. Before talking about Ruby. The first thing most of my readers get intrigued is about your Portuguese skills. Can you tell them what led you to it?</p>
<p><strong>Carl Youngblood:</strong> Yes. My first introduction to Portuguese was as a Mormon missionary in Brazil. I arrived in Sao Paulo having only received a two-month crash course in Portuguese. When I got there, it seemed like I had to learn everything over again – this wasn’t the language they taught me! :-) But after spending two years in Brazil in a context in which it was imperative to converse with other people, I learned Portuguese well. However, I would say that my skills were primarily in conversational Portuguese. Later on I discovered Portuguese literature and developed my written skills further.</p>
<p>Upon returning to the States, I decided to do a double-major in Portuguese and Computer Science. I decided on Portuguese because I enjoyed the language so much, and felt like I had a real talent for it. I chose CS because I have been in love with computers ever since I was 12 and got my first Commodore 64. Or maybe it was 10 years old. I can’t exactly remember.</p>
<p><strong>AkitaOnRails:</strong> Where did you stay during these 2 years here in Brazil? What were your responsibilities here?</p>
<p><strong>Carl Youngblood:</strong> I spent time in <a href="http://en.wikipedia.org/wiki/Monte_Mor"target="_blank" rel="noopener">Monte Mor</a> (a small town just outside of <a href="http://en.wikipedia.org/wiki/Campinas"target="_blank" rel="noopener">Campinas</a>), <a href="http://en.wikipedia.org/wiki/Campinas"target="_blank" rel="noopener">Campinas</a>, <a href="http://en.wikipedia.org/wiki/Marilia"target="_blank" rel="noopener">Marilia</a>, <a href="http://en.wikipedia.org/wiki/Umuarama"target="_blank" rel="noopener">Umuarama</a>, <a href="http://en.wikipedia.org/wiki/Maring%C3%A1"target="_blank" rel="noopener">Maringa</a> and <a href="http://en.wikipedia.org/wiki/Campo_Grande"target="_blank" rel="noopener">Campo Grande</a>.</p>
<p><strong>AkitaOnRails:</strong> But did you do anything computer related here during this period? People here would be interested to know what do you think of our country, being an outsider that really spent a serious amount of time around us. What’re your personal impressions about the country, the people, the culture, our local habits? Maybe a few words about the good and the bad :-)</p>
<p><strong>Carl Youngblood:</strong> My first 4 months were spent mostly meeting people in the streets and in their homes and trying to teach them about our <a href="http://mormon.org/mormonorg/eng"target="_blank" rel="noopener">church’s doctrines</a>. Just to clarify, Mormon is a nick-name given to my church because they believe in a book of scripture called <a href="http://scriptures.lds.org/en/bm/contents"target="_blank" rel="noopener">The Book of Mormon</a>, along with the Bible. But the full name of the church is The Church of Jesus Christ of Latter-day Saints. Anyway, I spent the first four months teaching people and helping to conduct church meetings, and walking A LOT – we walked about 15 miles a day, and I frequently remember waking up in the middle of the night with pains in my legs :-) After the first four months, I was called to work in the mission office in Campinas as <em>Historiador da Missão</em> – a secretary of sorts. Here my computer skills came into play.</p>
<p>After spending four months in Campinas as mission historian, I was called to help open up a new mission in Marilia, and spent another four months working in that mission office on the computer.</p>
<p>I didn’t really develop any amazing software for the mission, although I did help design an Access database that promptly fell into disuse after my departure :-)</p>
<p><img src="https://akitaonrails.s3.amazonaws.com/files/campinas_lds_mormon_temple.jpg" alt=""  loading="lazy" /></p>
<p>Overall I really enjoyed my time in Brazil. I discovered how much I enjoyed learning another language, and this newfound fascination led me to study this language later at the university level. The Brazilian people I met were for the most part very friendly. It was not uncommon to be invited into peoples’ homes and offered food before we even knew them, and they were usually willing to give you the shirt off their backs. I also really like Brazilian music, especially <a href="http://en.wikipedia.org/wiki/M%C3%BAsica_Popular_Brasileira"target="_blank" rel="noopener">Brazilian Popular Music</a> (MPB). <a href="http://en.wikipedia.org/wiki/Tom_Jobim"target="_blank" rel="noopener">Tom Jobim</a> is my hero, along with other legends like <a href="http://en.wikipedia.org/wiki/Joao_Gilberto"target="_blank" rel="noopener">João Gilberto</a>, <a href="http://en.wikipedia.org/wiki/Luiz_Bonfa"target="_blank" rel="noopener">Luiz Bonfá</a>, <a href="http://en.wikipedia.org/wiki/Luiz_Bonfa"target="_blank" rel="noopener">Vinícius de Moraes</a>, and other more modern artists like <a href="http://en.wikipedia.org/wiki/Caetano_Veloso"target="_blank" rel="noopener">Caetano Veloso</a>, <a href="http://en.wikipedia.org/wiki/Gilberto_Gil"target="_blank" rel="noopener">Gilberto Gil</a> and <a href="http://en.wikipedia.org/wiki/Djavan"target="_blank" rel="noopener">Djavan</a>. It was wonderful to discover a whole world of music and literature that opened up to me when I learned Portuguese. The food was good too, although I missed a few items from home, like corn chips and peanut butter, strange as it sounds.</p>
<p>On the other hand, I frequently noticed a profound lack of ambition. Most Brazilians we met were content to have a roof over their heads, food in the fridge and a TV. Of course, my observations are bound to be skewed a little by the fact that I mostly interacted with the poorer class of people who did not live in closed highrise apartment complexes, which were difficult for us to make house calls in, unless we had a prior appointment. One of Brazil’s most difficult problems is the large disparity between rich and poor and the consequently small middle-class. When Brazil abolished slavery (one of the last countries to do so), little or no effort was made to assist emancipated slaves in transitioning towards gainful employment in the new economic system, which led to the development of many autonomous shanty towns that were nearly completely isolated from the more “respectable” centers of commerce. This isolation continues today. It is not uncommon to see a wealthy suburb right next to a sprawling slum, as if each were ignoring the existence of the other. Overall though, Brazil is really making headway and the standard of living is improving dramatically.</p>
<p>One event that I distinctly remember was the advent of public internet access and the <a href="http://en.wikipedia.org/wiki/WWW"target="_blank" rel="noopener">WWW</a> in 1995 while I was in Maringa, I believe. I had often commented to my brother back in the days of text-based bulletin-board systems that it would be cool to create a markup language that allowed computers to render graphics over a modem connection. When I saw the WWW in 1995, I said, “Somebody stole my idea!” :-)</p>
<p><strong>AkitaOnRails:</strong> Haha, so you were involved in online activities since before the advent of the Web per se? And, you went to college after this 2 year period here?</p>
<p><strong>Carl Youngblood:</strong> I was involved in modem-based <a href="http://en.wikipedia.org/wiki/BBS"target="_blank" rel="noopener">BBSes</a> in our local town of Provo, UT since about 1990 or so. My brother ran a BBS called London after Midnight. He was sort of into the goth/cyberpunk scene (or at least wanted to be :-) ). We mostly used them to pirate games, before I grew up and realized that other people were trying to earn a living off this stuff.</p>
<p>I had already done one year of college as a music major (Clarinet performance) before I went on a mission. After the mission I returned to college and changed majors.</p>
<p><img src="https://akitaonrails.s3.amazonaws.com/files/carl.fidonet.jpg" alt=""  loading="lazy" /></p>
<p>By the way, we were also connected to a worldwide network called <a href="http://en.wikipedia.org/wiki/Fidonet"target="_blank" rel="noopener">Fidonet</a>, where we participated in newsgroups and had delayed discussions. Every night our computer dialed up a system in Nevada to download the new messages.</p>
<p><strong>AkitaOnRails:</strong> Oh, that’s cool. Going back to this subject, I was into BBSes as well because of my neighbor. He hosted a hacking BBS called Medusa and we played a lot brute-forcing against passwd files, using Blue boxes and so on. (Damn, we’re confessing a lot of crimes here, hope we’re not going to litigation for that ;-)) Getting back on track. So were you also caught in the period of the Internet Bubble? Doing PHP websites and so on?</p>
<p><strong>Carl Youngblood:</strong> Haha, good point. Those BBS days were fun. We felt like we were on the cutting edge. Yes, I was involved in the Internet bubble. Omniture (called MyComputer.com at the time) was in the middle of an acquisition by <a href="http://www.netobjects.com"target="_blank" rel="noopener">NetObjects</a>. However, before the acquisition took place NetObjects’ share price had plummeted to the point where they were valued at half of the acquisition cost, which basically meant it wasn’t going to happen. MyComputer.com laid off a bunch of people, but I left a couple months before that happened. My boss, speaking after the fact, told me that I would have been able to keep my job (I was one of the first employees), but I saw signs of trouble and had another opportunity, so I took a job at Legato Systems developing mirroring drivers in Windows of all things :-)</p>
<p><strong>AkitaOnRails:</strong> Same thing for me here in Brazil. I was involved with a dotcom company that went bankrupt but I was able to get out a few months earlier. Anyway, so you went straight to low-level programming. How many programming skills do you have? From low-level assembler all the way to Ruby not to mention Pascal, VB, PHP, etc?</p>
<p><strong>Carl Youngblood:</strong> Legato eventually closed down their office in Orem, Utah, at which point I went back to school to get a masters degree. I began thinking I was going to do a masters in Portuguese and eventually work as a professor at a University after getting my PhD. However, I found myself constantly working on software projects, even while I was teaching Portuguese classes and doing my graduate studies. I eventually decided I should face the obvious and continue my passion of software development. So I switched over to the Computer Science department and began working towards a masters degree in CS. All this was at Brigham Young University in Provo, Utah.</p>
<p><img src="https://akitaonrails.s3.amazonaws.com/files/carl.provo.jpg" alt=""  loading="lazy" /></p>
<p>I first learned <a href="http://en.wikipedia.org/wiki/Pascal_%28programming_language%29"target="_blank" rel="noopener">Pascal</a> and C++ in high school Computer Science classes. My first professional experience was as a C++ programmer developing Windows applications using <a href="http://en.wikipedia.org/wiki/Microsoft_Foundation_Class_Library"target="_blank" rel="noopener">MFC</a>. I then got a job doing PHP/MySQL development for <a href="http://www.omniture.com"target="_blank" rel="noopener">Omniture</a>. After that I was doing C-based windows drivers but also doing Ruby, Perl and PHP work on the side. Drivers are really a totally different beast because you don’t even have the regular ANSI C libraries available to you. So the C syntax is the same but that’s about it. I later got a job at Boeing doing more C++ development on Linux platforms, all the while nurturing my Ruby/Rails skills with side projects. I also learned functional programming with<br>
<a href="http://en.wikipedia.org/wiki/Scheme_%28programming_language%29"target="_blank" rel="noopener">Scheme</a>, as well as a few other languages like <a href="http://en.wikipedia.org/wiki/OCaml"target="_blank" rel="noopener">OCaml</a>, <a href="http://en.wikipedia.org/wiki/Prolog"target="_blank" rel="noopener">Prolog</a> and <a href="http://www.cs.washington.edu/research/zpl/home/index.html"target="_blank" rel="noopener">ZPL</a> during my masters degree. I wouldn’t call myself anything but a beginner in most of those other languages, but they definitely opened up my mind to new development paradigms.</p>
<p><strong>AkitaOnRails:</strong> You’ve pretty much followed the paths described by Pragmatic Programmers as David Thomas and Chad Fowler: learn new languages, specially ones with very different paradigms. Did you already know their work around these recommendations? Or was it just a natural curiosity thing that led you to learn so many languages?</p>
<p><img src="https://akitaonrails.s3.amazonaws.com/files/thepragmaticprogrammer_thomas.jpg" alt=""  loading="lazy" /></p>
<p><strong>Carl Youngblood:</strong> Well, the CS programs I’ve studied in (BYU and the University of Washington) did a good job of giving us at least some exposure to a wide range of concepts and languages. I really am grateful for my education because it introduced me to ideas and concepts that I probably would not otherwise have studied. I had also read the Pragmatic Programmer and tried to follow the advice of always learning new things and exposing myself to new languages. I am also somewhat of an information junkie. I am nearly addicted to my RSS feeds, and I feel an incredible anxiety if I start to get behind on my reading—almost as if I’m being left behind while the world reinvents itself. The truth is that I usually don’t miss anything extremely revolutionary by being away from the computer for a few days, but sometimes it feels like it.</p>
<p>Or rather, I worry that it might happen. :-) It can be a problem. It’s hard to strike a balance, especially with a wife and kids to pay attention to.</p>
<p><strong>AkitaOnRails:</strong> You’re right. That’s another thing that I always shout at my blog posts: being well informed, all the time. There’s no excuse with tools like RSS aggregators nowadays. And if an American went all the way to learn Portuguese and still being a technology specialist like yourself, there’s even less excuse for Brazilians to avoid improving their English and read more.</p>
<p><strong>Carl Youngblood:</strong> I’m not sure if you’ve heard <a href="http://www.ornery.org/essays/warwatch/2005-02-20-1.html"target="_blank" rel="noopener">the theory</a> of maximizers vs. satisficers. I read about it on somebody’s blog, taken from a book (can’t remember which). Sometimes I … worry so much that there must be a more elegant solution out there that I can’t ever decide when it’s good enough and get down to the actual business of coding.</p>
<p><strong>AkitaOnRails:</strong> hm, yes I believe I read something about this.</p>
<p><strong>Carl Youngblood:</strong> That is a problem in this era of rapid innovation. It’s always a moving target, and sometimes you just have to say something is good enough for now and move on.</p>
<p>Joel Spolsky <a href="http://www.joelonsoftware.com/articles/fog0000000339.html"target="_blank" rel="noopener">talks about this</a> and compares it to the military tactic of laying cover fire and firing while advancing. Rarely is a new technology or buzzword all it promises, but it keeps the competition struggling to keep up.</p>
<p>In general, it seems like society is advancing toward ever-increasing levels of abstraction. <a href="http://rubyonrails.com"target="_blank" rel="noopener">Rails</a> is a good example of this. Its whole mentality is to predict as much as possible the things that the developer will be wanting to do all the time and make convenient abstractions for them. But I’m sure this is only the beginning. We can expect future frameworks to do more and more of the heavy lifting for us, which will in turn enable us to accomplish more and more with less and less effort.</p>
<p><strong>AkitaOnRails:</strong> Yes, this is a good very point. Because people tend to ‘fall in love’ with one particular super-new technology and forget about all the rest. This leads to pure obsession. And after a while, this ‘new trend’ is forgotten altogether and you just wasted your time.</p>
<p><strong>Carl Youngblood:</strong> Yes, we need to stay current on new technologies but try not to get too dogmatic about them. Chad Fowler’s <a href="http://mtnwestrubyconf2007.confreaks.com/keynote.html"target="_blank" rel="noopener">recent address</a> at the <a href="http://mtnwestruby.org"target="_blank" rel="noopener">MountainWest Ruby Conference</a> talked about this.</p>
<p><img src="https://akitaonrails.s3.amazonaws.com/files/carl.fullmtnwestlogo.png" alt=""  loading="lazy" /></p>
<p><strong>AkitaOnRails:</strong> Hey, sorry for the pun, but coming from someone with such a formal dogmatic religious formation like yourself, this is a very refreshing thing to listen: not being too dogmatic. In the end its all a matter of common sense, but even common sense has to be trained. Hence the need to be always informed, constantly studying and keeping an open mind toward new stuff while not closing the eyes to all the rest.</p>
<p><strong>Carl Youngblood:</strong> I believe that one’s belief structure should never be so rigid as to not allow for modification. I should always be willing to re-examine my beliefs in light of new evidence and be willing to reject or modify beliefs that seem wrong or misinformed upon closer scrutiny.</p>
<p>In defense of my Mormon upbringing, although it is a fairly conservative religion, it does place a high value on education, which inevitably leads to enlightenment and often to a modification of one’s prior beliefs. Fortunately my fellow parishioners still welcome me, though some of my beliefs may be a bit unorthodox and are different from those I had when I was younger.</p>
<p><strong>AkitaOnRails:</strong> We do need more of this way of thinking here in Brazil: pragmatics. Anyhow, coming back again, you were very busy for a long time. Learning Portuguese, finishing your major in CS, working in Internet companies, traditional companies. And all the time Ruby was sneaking somewhere, waiting. When did you finally realized you wanted to do more Ruby? Was it during some project at your day-job, or something you decided by yourself?</p>
<p><strong>Carl Youngblood:</strong> I think the real awakening was the meteoric rise of rails and <a href="http://37signals.com"target="_blank" rel="noopener">37signals</a> evangelization of the whole <a href="http://gettingreal.37signals.com"target="_blank" rel="noopener">getting real</a> mentality. I attended the <a href="http://www.37signals.com/svn/archives/000971.php"target="_blank" rel="noopener">Building of Basecamp</a> seminar in Seattle and went to the first RailsConf. I was really inspired by <a href="http://joeydevilla.com/2006/06/27/railsconf-2006-nathaniel-talbott-homesteading-a-thrivers-guide"target="_blank" rel="noopener">Nathaniel Talbott’s speech</a> about homesteading.</p>
<p>One thing that really struck me about my experience at RailsConf was that I saw colleagues there who started using Ruby at the same time I did and whose names appeared on the ruby-talk mailing list alongside mine. The main difference between them and me was that they decided to get actively involved, to develop open source projects of their own, and to build a reputation for themselves in the community, while I dabbled in Ruby as a mere hobby. Fast forward four or five years and they were running their own companies and really making a career for themselves in Ruby. Railsconf was a wake up call for me in which I realized that I needed to be more involved in the Ruby community.</p>
<p>So I decided to release some prior work of mine as a gem and give a presentation at our local MountainWest Ruby conference. I released the <a href="http://sbn.rubyforge.org"target="_blank" rel="noopener">SBN</a> (Simple Bayesian Networks) gem. Preparing my presentation and code was stressful but worth it.</p>
<p>Some colleagues and I are also working on a conference recording business called <a href="http://www.confreaks.com"target="_blank" rel="noopener">Confreaks</a>. We are hoping to do a better job of recording and disseminating technical conferences for posterity’s sake. It’s a shame that all these great conferences are going on and nobody is recording them.</p>
<p><img src="https://akitaonrails.s3.amazonaws.com/files/carl.DSC_0006.sized.jpg" alt=""  loading="lazy" /></p>
<p>Anyway, my increased involvement in the community has really helped to boost my career and allowed me to code in Ruby as a day job.</p>
<p><strong>AkitaOnRails:</strong> But where were you at the time Rails started to call attention to itself? Did your job allow you to have enough time to dedicate to Ruby or you switched jobs by then? I mean, were you not satisfied by the current state of your career and the technologies you were using? What was your ‘inflection point’? Just seeing RailsConf and the news around Rails?</p>
<p><strong>Carl Youngblood:</strong> I was working for Boeing when Rails first came out. It was a comfortable low-pressure job on a <a href="http://www.army.mil/fcs"target="_blank" rel="noopener">DoD project</a> with a long drawn-out timeline that allowed me time for study. I was already in the habit of staying current on technologies (Ruby in particular) and reading a wide range of blogs regularly. I would have accepted a Ruby position at any time but they were still fairly hard to come by. At my request, my boss paid for me to go to RailsConf, so I was already really interested. I had also been working on a freelance project that I had written earlier in PHP, and offered to rebuild it in Rails at a heavily discounted rate just to gain experience with Rails. So I guess you could say that I have been really interested in all things Ruby ever since 2000 but only recently has the job market begun supporting full-time Ruby positions.</p>
<p><strong>AkitaOnRails:</strong> And your first endeavor towards Ruby was your SBN open source project and the Mountain West keynote? Can you describe what it was like? At least for me, when I want to ‘say’ something, I get very excited and particularly anxious to have it written (in my case, my blog posts). I can imagine that you hardly slept before the conference. :-)</p>
<p><strong>Carl Youngblood:</strong> Yes, I was up many late nights preparing for <a href="http://mtnwestrubyconf2007.confreaks.com/session03.html"target="_blank" rel="noopener">my presentation</a>. In fact, most of my late nights were spent getting the code ready for human consumption. Knowing that the world at large is going to use your code makes you want to spruce it up a little more, write more unit tests, etc. So I spent the month or two before the conference working on the code and only had about a week to prepare my actual slides. My presentation material was fairly technical, so I ended up writing down my presentation in the slide notes, just to make sure that I didn’t explain something wrong during the pressure of the actual presentation. Had I had more time, I would have liked to have memorized the key points so that the presentation could be a little more natural, but overall I was pleased with the way things turned out. I was also working on the Confreaks project to record the conference, so I was busy on two fronts, not to mention my day job.</p>
<p><img src="https://akitaonrails.s3.amazonaws.com/files/carl.DSC_0017.sized.jpg" alt=""  loading="lazy" /></p>
<p><strong>AkitaOnRails:</strong> And by that time were you still at Boeing? Or were you already at Surgeworks? How did you get into Surgeworks to work on Rails full-time?</p>
<p><strong>Carl Youngblood:</strong> Around the time I was finishing my CS Masters degree at the <a href="http://www.washington.edu"target="_blank" rel="noopener">University of Washington</a> while working for Boeing, I received an offer from a friend of mine to return to Utah and work for him as CTO of a Construction Lending Company called <a href="http://ccsloans.com"target="_blank" rel="noopener">Construction Capital Source</a>. One of my main responsibilities would be to develop a construction lending system in my technology of choice, which just so happened to be Rails. I took the bait and had a great time there for about a year and a half. But the company went through some difficulties with the recent crash of the sub-prime lending market. Although their customers are only A-paper borrowers with excellent credit ratings, the sub-prime market has cast a pall on the entire industry, and our investors got scared. I ended up leaving my position and accepting a job at <a href="http://surgeworks.com"target="_blank" rel="noopener">Surgeworks</a> as their “Rails Practice Manager,” which means I supervise all the company’s Rails projects, hopefully while still getting to spend at least half my time coding, although at the moment it hasn’t exactly worked out that way. We have been getting a lot more work coming in since I started, so a lot of my time has been spent writing proposals and project estimates so far, but I’m starting to settle into a groove.</p>
<p><strong>AkitaOnRails:</strong> But how did you know about Surgeworks? I remember that you mentioned you already knew Dane Falkner from another occasion?</p>
<p><strong>Carl Youngblood:</strong> Dane and I both attend the <a href="http://groups.google.com/group/urug"target="_blank" rel="noopener">local Ruby users group</a> meetings in Salt Lake City, so I knew him from there. Upon leaving CCS, I posted a message on the URUG list and was happy to see that there are a lot of Ruby positions available. I don’t think I’ll have trouble finding Ruby work in the future for as long as I’m interested in coding in Ruby :-)</p>
<p><strong>AkitaOnRails:</strong> That’s very nice. There are a lot of local user groups there. We still are starting local groups here in Brazil. What can you say about the growth and enthusiasm of the community? What do you see for Rails in the time being?</p>
<p><strong>Carl Youngblood:</strong> In my experience, the key to a successful users group is having one or two dedicated individuals with the passion to organize and promote the meetings and line up interesting presentations. If you do that, people will attend. Our local groups have gone through ups and downs depending on the level of the organizers’ enthusiasm. Another thing that seems to help is providing content that is geared towards various skill levels. Making sure that you welcome and help beginners is important. The community is still growing, as evidenced by the many regional Ruby conferences that are cropping up around the US.</p>
<p>I was excited to see DHH’s planned features for Rails 2.0 and his more measured rhetoric as opposed to the first Railsconf, which some folks commented seemed more like Nuremburg rallies :-) I think Rails will continue to mature and has at least 2-3 more years of great success before being eclipsed by some new paradigm breaker.</p>
<p><strong>AkitaOnRails:</strong> This is important and maybe you can lay some ideas. Many of the core Ruby and Rails contributors in Brazil, from our local forums, user groups, blog and websites still don’t have the opportunity to work full time on Rails. So they have little to no time to devote do Ruby yet. I believe that there was a time like that there in the US. What do you think was the turning point for the community to flourish?</p>
<p><strong>Carl Youngblood:</strong> I think more than anything else, the incredible success (especially the marketing success) of Rails has been the largest contributor to this change. But that didn’t stop passionate Ruby developers from blazing their own trails before then. I think the thing that needs to change first in Brazil is the 9-5 just-a-job mentality. People need to start taking some of the recommendations from the Pragmatic Programmer to heart and making time for extracurricular skills-honing activities, including ruby meetings. This is what folks in the US did and I think something similar will be required in Brazil. I think there is also a cultural difference that is partly to blame. I don’t want to claim that either system is superior, but I think Americans (at least the ambitious types who are in the Ruby community) spend more than 40 hours a week focusing on their craft, whereas I think many folks in Brazil look at software development as something that just pays the bills.</p>
<p>Of course there are many programmers here with the same mentality.</p>
<p><strong>AkitaOnRails:</strong> Speaking of passion, David always states about the sense of aesthetics of the community, their inherent sense of beauty towards coding. Did you sense that when you first started? Many say that’s one of the reasons for the Ruby and Rails community being so Mac geared. What do you think about this?</p>
<p><img src="https://akitaonrails.s3.amazonaws.com/files/carl_iphone.jpg" alt=""  loading="lazy" /></p>
<p><strong>Carl Youngblood:</strong> I agree. Matz often quotes a <a href="http://oneproverb.net/bwfolder/chinesebw.html"target="_blank" rel="noopener">Chinese proverb</a> that says something like “the beginning of wisdom is naming things correctly.” Ruby people tend to spend a lot of time focusing on semantics and making sure that code is not only useful but elegant. I think when you are seeking to maximize your level of abstraction and hence your programming power, these kinds of issues are very important and can provide a huge productivity increase.</p>
<p><a href="http://www.apple.com"target="_blank" rel="noopener">Apple</a> seems to reflect a similar mentality in their designs.</p>
<p><strong>AkitaOnRails:</strong> I think its nice to mention that I was pretty surprised to see that almost everybody at Surgeworks are Apple-fans. I never expected that. I guess Apple is gaining into the developers workspace as a valuable productive tool. Well, and I know I already pushed you for too long :-) Any other remarks for the Brazilian audience?</p>
<p><strong>Carl Youngblood:</strong> I think a lot of Surgeworks’ passion for Apple comes from Dane, who is a big fan. My main advice to my friends in Brazil is to recognize the importance that your individual effort can make. You have a relatively <a href="http://www.ita.doc.gov/exportamerica/NewsFromCommerce/nfc_BrazilIT.pdf"target="_blank" rel="noopener">strong IT industry</a> for South America and a burgeoning <a href="http://www.mazine.ws/node/160"target="_blank" rel="noopener">open source community</a>. I have been very impressed with some of the more vocal Brazilian techies like yourself, Fabio, who have shared their opinions on the Internet. Change is not brought about by the masses, but by thoughtful courageous individuals who break free from the status quo. The more Brazilians take that to heart, the sooner Ruby jobs will start to appear. I am reminded of a quote along these lines:</p>
<p>“Never doubt that a small dedicated group of people can change the world; indeed it is the only thing that ever has.” (<a href="http://en.wikipedia.org/wiki/Margaret_Mead"target="_blank" rel="noopener">Margaret Mead</a>)</p>
<p><strong>AkitaOnRails:</strong> Very nice. Well, I think we can wrap it up for today. Thanks a lot! I think people will like this.</p>
<p><strong>Carl Youngblood:</strong> Great! Thanks for taking the time, Fabio.</p>
<p><img src="https://akitaonrails.s3.amazonaws.com/files/carl.JamesAndJoseph11.sized.jpg" alt=""  loading="lazy" /></p>
]]></content:encoded><category>interviews</category><category>ruby</category></item></channel></rss>