<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~files/feed-premium.xsl"?>
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             
<rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:feedpress="https://feed.press/xmlns" xmlns:media="http://search.yahoo.com/mrss/" xmlns:podcast="https://podcastindex.org/namespace/1.0" version="2.0">
  <channel>
    <feedpress:locale>en</feedpress:locale>
    <feedpress:newsletterId>olivierlacan</feedpress:newsletterId>
    <atom:link rel="via" href="https://feed.olivierlacan.com/"/>
    <atom:link rel="hub" href="https://feedpress.superfeedr.com/"/>
    <title>Olivier Lacan</title>
    <description>Thoughts on Ruby, Rails, open source software, programming, and life.</description>
    <link>https://olivierlacan.com</link>
    <atom:link href="https://feed.olivierlacan.com/" rel="self" type="application/rss+xml"/>
    <item>
      <title>Zoé</title>
      <description><![CDATA[<p>While 2022 was all about <a href="https://olivierlacan.com/posts/join/">joins</a>, this year we made a whole new 
record.</p>

<p>Her name is Zoé and she’s wonderful. I can’t wait for her to meet the 
world in spite of its flaws.</p>

<figure>
  <img src="https://olivierlacan.com/assets/zoé.jpg" alt="Le meilleur sandwich du monde" />
  <figcaption></figcaption>
</figure>

<p>Along the way, Zoé helped me refocus on what really matters:</p>

<ul>
  <li>getting lost in that afternoon shine</li>
  <li>holding hands (or fingers)</li>
  <li>~naps~</li>
  <li>the percussive pleasure of deep farts 💨</li>
  <li>improvising harmonies to soothing songs</li>
  <li>watching sunrises <em>and</em> sunsets like movie premieres</li>
  <li>singing <em>and</em> walking (at the same time)</li>
  <li>feelings within &amp; without</li>
  <li>blissful abandon</li>
</ul>

<p>Merci Zouzou et à demain matin ☺️</p>

<img src="https://feed.olivierlacan.com/link/8226/17244806.gif" height="1" width="1"/>]]></description>
      <pubDate>Wed, 31 Dec 2025 23:59:59 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/17244806/zo%C3%A9</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/zo%C3%A9/</guid>
    </item>
    <item>
      <title>The $PATH to Enlightenment</title>
      <description><![CDATA[<p><strong>This post is reproduced from an original I authored in 
<a href="https://alistapart.com/article/the-path-to-enlightenment/">A List Apart on November 4th, 2014</a>. A decade later it’s still so 
relevant to my daily work on a computer.</strong></p>

<p><em>Pierre Choffé was kind enough to translate it <a href="https://la-cascade.io/articles/le-path-vers-la-lumiere">en français sur son blog La Cascade</a>.</em></p>

<hr />

<p>Contributing to open source software always involves a bit of tedious
setup. While it often distracts from the end goal (solving problems), the setup
process is often an opportunity to discover how comfortable people are
with one of the main tools of their trade: the command line.</p>

<p>It’s possible to work on the web without dealing with the command line.
It’s also possible to build a house without using power tools.</p>

<p>I know the command line is inherently spooky to many people. It’s the
embodiment of arcane technology wielded by “hackers” and “computer
wizards”. Except it’s not. It’s a set of ridiculously simple tools
created by Bell (now AT&amp;T) employees to accomplish mostly simple tasks
in the 1970s. It’s just as much of a “space age” technology as your
micro-wave oven.</p>

<p>Thankfully, through a few concepts and metaphors, we can shine a light
on the darkest corners of this command line.</p>

<p>One of the most important of these concepts is the <code class="language-plaintext highlighter-rouge">$PATH</code>.</p>

<p>Several front-end frameworks, CSS preprocessors,
JavaScript libraries, and a flurry of other web development tools rely
on either Ruby or Node.js being installed on your machine. <a href="http://bower.io/">Bower</a>
is one such tool.</p>

<p>Invariably, these issues will lead you to the $PATH because it will need
to be aware of all the tools you install for your development
environment in order to function properly.</p>

<p>Taking a step back to understand how the $PATH works is indeed a step
backwards, but the more you use command line tools, the greater the
chances the $PATH will cause you to lose a lot more time, or even throw
heavy things at your computer screen.</p>

<h2 id="a-humble-little-variable">A humble little variable</h2>

<p><code class="language-plaintext highlighter-rouge">$PATH</code> as denoted by the dollar sign prefix and the shouty uppercase is
a Unix environment variable. What is stored inside of this variable (a
basic programming structure) is a colon-delimited list of directory
paths. Something like:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>/root/directory/binary:/root/other_directory/other_binary
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now, if you’re curious what other kinds of environment variables exist
on your system, you can type in the <code class="language-plaintext highlighter-rouge">env</code> command in your own command
line prompt [Note: does this work on Windows too?], hit <code class="language-plaintext highlighter-rouge">Enter</code> and you
will see a list of all the environment variables that currently exist.</p>

<p>Since <code class="language-plaintext highlighter-rouge">$PATH</code> is a variable, it can be modified as you wish, on the fly.
For instance by running this in your shell:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nv">$ </span><span class="nb">export </span><span class="nv">PATH</span><span class="o">=</span>banana
</pre></td></tr></tbody></table></code></pre></div></div>

<p>What does this do? Well, try to run the export command above in a new
window inside of your Terminal or whichever shell app (Terminal on OS X)
you use.</p>

<p>Now type any basic Unix command like <code class="language-plaintext highlighter-rouge">ls</code>. You’ll see <code class="language-plaintext highlighter-rouge">-bash: ls:
command not found</code>.</p>

<p>This sabotage was useful because now we know that without the content
inside our <code class="language-plaintext highlighter-rouge">$PATH</code>, shit just goes bananas — if you pardon my lovely
circular pun.</p>

<p>But why? Because as many load paths do (including in programming
languages and frameworks like Rails), this one determines what can be
executed in your shell.</p>

<p>Oh, by the way, just quit your shell application and restart it all your
commands will be back.</p>

<h2 id="a-tale-of-so-many-binaries">A tale of so many binaries</h2>

<p>In Unix, executable programs are called binaries. It’s a crappy name
because it’s based on the format of the executable program, not its
function. When you write a Unix program, you have to compile it before
it can be executed. This compiling process creates the ‘binary`. A file
that instead of using plain text uses some binary format to make
instructions easier to process for a computer.</p>

<p>Unix comes with multiple directories to store binaries. You can see
which are the default directory used to load binaries in the
<code class="language-plaintext highlighter-rouge">/etc/paths</code> file.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="c"># the cat command can print the content of a file</span>
<span class="nv">$ </span><span class="nb">cat</span> /etc/paths

/usr/bin
/bin
/usr/sbin
/sbin
/usr/local/bin
</pre></td></tr></tbody></table></code></pre></div></div>

<p>The file contains one directory per line. The paths are listed in a
meaningful order. When a binary is found in one path, it is loaded. If a
binary with the same name is found in another path, it is ignored. Paths
listed earlier take precedence over paths listed later.</p>

<p>This is why it’s common to run into problems when trying to install a
binary for something that already exists on your system. In the case of
OS X, git is good example.</p>

<p>If I <code class="language-plaintext highlighter-rouge">cd</code> into <code class="language-plaintext highlighter-rouge">/usr/bin</code> and run <code class="language-plaintext highlighter-rouge">ls</code> (list directory contents) I get
over 1000 results. If I run <code class="language-plaintext highlighter-rouge">ls | grep git</code> I’m able to filter the
results of the ls command that match the pattern “git”.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="nv">$ </span><span class="nb">ls</span> | <span class="nb">grep </span>git
git
git-cvsserver
git-receive-pack
git-shell
git-upload-archive
git-upload-pack
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Sure enough, there was a binary for it inside. On a clean OS X install
you will see <code class="language-plaintext highlighter-rouge">/usr/bin/git</code> returned when you run <code class="language-plaintext highlighter-rouge">which git</code>:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="nv">$ </span>which git
/usr/local/bin/git
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Why is mine different then? We can have an even better idea of what’s
going on by using the <code class="language-plaintext highlighter-rouge">-a</code> option when using <code class="language-plaintext highlighter-rouge">which</code>:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nv">$ </span>which <span class="nt">-a</span> git
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="changing-paths">Changing paths</h2>

<p>Using a great package manager for OS X called
<a href="http://brew.sh/">Homebrew</a> I installed my own version of Git because I
like to have control over the tools I use every day and update them when
necessary. I could update the system-installed Git from OS X but I have
no idea what other binaries or apps depend on it. More importantly, to
update it I would have to compile Git from source, and I’m just way too
lazy to do that.</p>

<p>Yes, this is a poor excuse because there are many ways to download
prepackaged versions of git that are easy to drop in, but bear with me,
this is where we get into the useful stuff.</p>

<p>We saw that the order of lookup for binary load paths was determined by
a file called <code class="language-plaintext highlighter-rouge">/etc/paths</code>, so why not change that order? Homebrew
installs all executable binaries into a directory called
<code class="language-plaintext highlighter-rouge">/usr/local/bin</code> in order not to step on the system’s toes.</p>

<p>In <code class="language-plaintext highlighter-rouge">/etc/paths</code> that is the last directory loaded, which means the <code class="language-plaintext highlighter-rouge">git</code>
binary inside <code class="language-plaintext highlighter-rouge">/usr/bin</code> will take precedence over it, and my fancy new
version of Git will be ignored.</p>

<p>Now, you could succumb to evil ways and simply try to modify the order
in <code class="language-plaintext highlighter-rouge">/etc/paths</code> so that it suits your needs. In this case you would
simply have to put <code class="language-plaintext highlighter-rouge">/usr/local/bin</code> at the top and now the Homebrew-
installed version of git would load first. But despite how many times
you see this terrible advice repeated in StackOverflow discussions,
please don’t do it. Configurations stored in <code class="language-plaintext highlighter-rouge">/etc/</code> are system-wide.
They’re not there for your personal convenience and you could very well
damage way your computer functions by altering things in there. For all
you know some utility used by OS X could be relying on the original
order of <code class="language-plaintext highlighter-rouge">/etc/paths</code>. No, instead you should modify the <code class="language-plaintext highlighter-rouge">$PATH</code> in
<em>your</em> environment, using <strong>your</strong> <code class="language-plaintext highlighter-rouge">.bash_profile</code>. The one stored in
<code class="language-plaintext highlighter-rouge">/Users/yourusername/.bash_profile</code> also known as <code class="language-plaintext highlighter-rouge">~/.bash_profile</code>.</p>

<p>To ensure <code class="language-plaintext highlighter-rouge">/usr/local/bin</code> is looked into first, this is all you need to
include in your <code class="language-plaintext highlighter-rouge">.bash_profile</code>:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="c"># inside ~/.bash_profile</span>
<span class="nb">export </span><span class="nv">PATH</span><span class="o">=</span>/usr/local/bin
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This is exporting a new PATH environment variable by printing the
existing one and simply prepending the <code class="language-plaintext highlighter-rouge">/usr/local/bin</code> path on the left
of all other paths. After saving your <code class="language-plaintext highlighter-rouge">~/.bash_profile</code> and restarting
your shell, this is what you should see when calling <code class="language-plaintext highlighter-rouge">echo</code> on the
<code class="language-plaintext highlighter-rouge">$PATH</code>:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="nv">$ </span><span class="nb">echo</span> <span class="nv">$PATH</span>
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin
</pre></td></tr></tbody></table></code></pre></div></div>

<p>As you can see <code class="language-plaintext highlighter-rouge">/usr/local/bin</code> is mentioned twice in the <code class="language-plaintext highlighter-rouge">$PATH</code>, and
that’s fine. Since it’s mentioned first, all the binaries that will be
loaded the first time around will be ignored when it is visited last. I
honestly wish there was a safe and simple way to change the order of
paths. You could always override the default $PATH altogether but I’ve
rarely seen this done:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="c"># inside ~/.bash_profile</span>
<span class="nb">export </span><span class="nv">PATH</span><span class="o">=</span>/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="a-fork-in-the-path">A fork in the path</h2>

<p>Now that you’ve changed the <code class="language-plaintext highlighter-rouge">$PATH</code> to your liking, you can check that
the proper binary is being called when you use the <code class="language-plaintext highlighter-rouge">git</code> command:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="nv">$ </span>which git
/usr/local/bin/git

<span class="nv">$ </span>git <span class="nt">--version</span>
git version 1.9.2

<span class="nv">$ </span>/usr/bin/git <span class="nt">--version</span>
git version 1.8.5.2 <span class="o">(</span>Apple Git-48<span class="o">)</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>There you go. git 1.9.2 (the Homebrew-installed version) is now the one
answering <code class="language-plaintext highlighter-rouge">git</code> command and the Apple-installed 1.8.5.2 version recedes
in the background. If git 1.9.2 interferes with your system at all you
can simply uninstall it and the default version will take over
seamlessly.</p>

<h2 id="protect-your-path">Protect your path</h2>

<p>There is a host of utilities out there for developers (and designers)
that automatically inject code into your <code class="language-plaintext highlighter-rouge">.bash_profile</code> upon
installation. Often they don’t even mention it to you, so if you find
odd paths listed in your profile, that may explain why loading a new
session (which happens when you open a new shell window or tab) takes
more time than it should: a bloated <code class="language-plaintext highlighter-rouge">$PATH</code> might take a while to load.</p>

<p>Here’s my path today:</p>

<p><code class="language-plaintext highlighter-rouge">/usr/local/heroku/bin:/Users/olivierlacan/.rbenv/shims:/Users/o
livierlacan/.rbenv/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr
/local/bin:/usr/local/MacGPG2/bin</code></p>

<p>It’s a little hard to read so I tend to break it into lines which can be
easily done with the <code class="language-plaintext highlighter-rouge">tr</code> command (translate characters):</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
</pre></td><td class="rouge-code"><pre><span class="nv">$ </span><span class="nb">echo</span> <span class="nv">$PATH</span> | <span class="nb">tr</span> <span class="s1">':'</span> <span class="s1">'\n'</span>
/Users/olivierlacan/.rbenv/shims
/Users/olivierlacan/.rbenv/bin
/usr/local/bin
/usr/local/heroku/bin
/usr/bin
/bin
/usr/sbin
/sbin
/usr/local/bin
</pre></td></tr></tbody></table></code></pre></div></div>

<p>There’s a lot of stuff going on here, but it’s much easier to understand
with some verticality. Try it out, and if you don’t know why one of
those lines is in your <code class="language-plaintext highlighter-rouge">$PATH</code> then make it your goal to figure it out.
You might just learn something useful.</p>
<img src="https://feed.olivierlacan.com/link/8226/16963152.gif" height="1" width="1"/>]]></description>
      <pubDate>Wed, 25 Dec 2024 07:00:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/16963152/the-$path-to-enlightenment</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/the-$path-to-enlightenment/</guid>
    </item>
    <item>
      <title>Constant Variable</title>
      <description><![CDATA[<p>12 years ago today, I spoke these words into a <a href="https://soundcloud.com/olivierlacan/a-constant-variable">microphone</a> after writing them late at night. If you forgive my 26 year old pompousness I think they aged… OK. The test of time might be passed when something you wrote for yourself ends up coming back in your mind for over a decade.</p>

<blockquote>
  <p>A constant variable.</p>

  <p>Life is, love is, work is.</p>

  <p>Things change, perpetually.</p>

  <p>Change is frightening but it’s good. We idealize it and rarely realize how tedious it is until we face it.</p>

  <p>The universe is nothing but change. Unstoppable, beautiful, change.</p>

  <p>Science brought us tools to understand the universe and ourselves.</p>

  <p>Out of these tools emerged the Internet, a tool originally designed to help scientists pool their efforts and communicate. 
One of these scientists, Tim Berners-Lee of CERN, decided in 1989 that it would be a great idea to take the concept of <a href="https://en.wikipedia.org/wiki/Hypertext">hypertext</a> and apply it to the network in order to create the World Wide Web.</p>

  <p>The web changed everything.</p>

  <p>And few people understood the ramifications of that change until recently. Most people still don’t.</p>

  <p>We do. We have imagination.
We think, design, and build. 
We won’t let other’s lack of imagination stand in the way of our ideas.
We make change real by creating tools and products that make people’s lives — and their jobs — easier, more efficient, and fun.</p>
</blockquote>

<p>Change is a prism. It reveals things in ourselves that we either ignore or avoid. But the constant variable never fails.</p>

<p>I was ready for this year to bring a lot of change. And it delivered all along the spectrum. But looking out of the window on the last day of the year — annoyed to have posted once a year for the fourth year in a row — I feel proud and grateful of all that we accomplished in the face of relentless adversity.</p>

<p>This year’s changes were multi-faceted: overdue, scary, frustrating, hopeful, tentative, bold.</p>

<p>After years of resisting change, my partner Tamar and I managed to find peace in a 
new city we’d struggled to call home, bought a house there, and finally 
our little family is all in one place for the first time in years.</p>

<p>I attended a (gigtantic and fascinating) speech-language pathology conference 
with Tamar this year. She worked so hard this year: treating patients at the hospital,
pushing her Ph.D. forward, learning how to run a pottery studio, and taking 
care of her family. Much of this would feel impossible to withstand 
without the best of partners.</p>

<p>Loved ones had to deal with the brunt of negative change this year, but 
thankfully things eventually improved for many of them. Shocking disease was tackled 
and tamed with immense group effort; challenging new horizons were explored yielding 
much-deserved accomplishments and renewed self-worth; and despite the looming 
shadow of the pandemic’s long tail we found time to discover and rediscover new things 
and places together.</p>

<p>On the work side, I received the title of Principal Engineer at Pluralsight. Although it took months to feel like I’d earned it. Despite many letdowns over the years, I’ve grown intensely proud of the <a href="https://olivierlacan.com/work/pluralsight/">work</a> my team and I have done to reshape the company for a multi-modal world.</p>

<p>This year, <a href="https://github.com/badges/shields/discussions/8867">Shields turned 10</a>. I think it’s safe to say no project I started is likely to have the reach this tiny key-value badge has had. I still delight in finding <a href="https://shields.io">Shields badges</a> on so many open source project repositories across the web.</p>

<p>Maybe I’ll manage to wrap up <a href="https://keepachangelog.com/">Keep a Changelog</a> 2.0 in 2024, who knows? 😅 
This year marked the 25th language translation for it. While the reach of Shields may be broader, I can’t believe how deep into the world this “little” project — which turned 8 this year — has gone.</p>

<p>Back in November 20, 2013 and December 21st, 2013 I wrote in <a href="https://olivierlacan.com/posts/i-am-an-alien/">I’m an Alien.</a> and <a href="https://olivierlacan.com/posts/i-need-to-write/">I need to write.</a> about my then expiring F-1 OPT visa. It now feels like a lifetime ago. I ended up spending five long years back in Paris. There was good in those years, but also quite a lot of bad. It’s not until 2019 that I made my way back to the U.S. with an H-1B visa.</p>

<p>A lot of what I said in “I need to write” was indeed pivotal. While my voice and contributions didn’t carry me professionally through these years, they sustained my spirit. Having a place in the Ruby community gave me friends and acquaintances to grow along with. People with different context than my co-workers, who I could confide in, and ask for help. I’m thankful for the countless times people lent me a hand along the way.</p>

<p>In July 2023 I finally received a permanent residency in the U.S. That was 12 years after I graduated from a U.S. university with an F-1 student visa. You’ve likely heard of people who managed to do this faster. Please think of the many others who are waiting after countless years, at the whims of tech barons, politicians, and voters. Immigration is a constant variable. It scares us to think our countries change outside our control. But countries are <em>always</em> changing. We can evolve with our environment, as long as we embrace this constant variable.</p>

<img src="https://feed.olivierlacan.com/link/8226/16514336.gif" height="1" width="1"/>]]></description>
      <pubDate>Sun, 31 Dec 2023 10:14:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/16514336/constant-variable</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/constant-variable/</guid>
    </item>
    <item>
      <title>Join</title>
      <description><![CDATA[<p>Some foreign keys you forget to create indices for. Then you start noticing that you’ve written many records together, and you enjoy retrieving those too. While it’s hard to explain and pointless to analyze, you’ve been filtering a single reference in particular.</p>

<p>This reference, it has familiar type that you can trust. It’s clear this will be a write-heavy relationship, but you’re also going to look these records up, as you watch this these two different tables grow in concert and complement each other just right.</p>

<p>In the past you might have preferred implicit joins, but this is different. You now relish in writing your joins explicitly, giving each other some cute aliases to make things a little more delightful. And since it defines what unites you two, you find yourself taking pleasure in writing out what unites you into a coherent set.</p>

<p>Tamar, here’s to the millions of rows we’ll insert in this big beautiful database we call our life together.</p>

<p>Love you,
Olivier</p>
<img src="https://feed.olivierlacan.com/link/8226/15957623.gif" height="1" width="1"/>]]></description>
      <pubDate>Sat, 31 Dec 2022 11:05:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/15957623/join</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/join/</guid>
    </item>
    <item>
      <title>High Fidelity Remote Communication</title>
      <description><![CDATA[<figure>
  <video poster="https://olivierlacan.com/assets/remote-720p-loop.jpg" autoplay="" playsinline="" loop="" muted="" class="zoot" src="https://olivierlacan.com/assets/remote-720p-loop.mp4"></video>
  <figcaption></figcaption>
</figure>

<p>Before the pandemic even started, remote work was already on the rise
around the world because <em>it makes sense</em>. Knowledge work doesn’t need
to depend on crammed, loud, and unhealthy open offices located in
expensive areas devoid of affordable housing. Bringing a laptop to
a room inside of a building you spend hours to travel to every day is 
the definition of absurdity.</p>

<p>Instead working remotely has become almost normal, except to corporate
leaders who prefer portraying it as “working from home” as if you need
to be grateful for the (temporary) perk. This patronizing
butts-in-seats mentality assumes that you’re not, you’re working <em>from
home</em>. Perhaps you’re really doing laundry or running errands, but not
actually “working”. This ignores the fact that work is already remote
by nature when it happens on the Internet. Large organizations 
<em>effectively</em> have remote offices. They coordinate work across cities 
and countries. Remote work is here, it’s just not evenly distributed.</p>

<h2 id="remote-shell-shock">Remote Shell Shock</h2>

<p>One of the first complaints from first-time remote workers in the spring
of 2020 when the pandemic led to an abrupt exodus from shared offices
all over the world: it’s hard to communicate remotely.</p>

<p>No shit.</p>

<p>It’s hard to communicate. Period. It was already hard for every remote 
worker who had to communicate with clustered workers crammed in loud 
conference rooms, often in blatant violation of fire codes. It’s only 
now more obvious to everyone how difficult it was for the remote workers 
to communicate before.</p>

<figure>
  <img src="https://olivierlacan.com/assets/remote-code-school-standup.jpg" alt="Picture of more than twenty people crowded together in the back of an office near an iMac sporting a tiny webcam in the foreground." />
  <figcaption>A whole-company standup meeting at Code School's office back in December 2013, featuring in the bottom right what would soon become my eyes and ears.</figcaption>
</figure>

<p>I was one of the first fully remote workers at my job back in 2013. One
month I was happily commuting at least three days a week to our Orlando
office, the next I was planning a move back to France. I set up shop as
an independent contractor in my 30 square meters (330 sq ft) studio in
Paris, six timezones away. My manager at the time was clear: be loud
about any friction you encounter, we want to make this work and you’re
going to be the canary in the coal mine.</p>

<h2 id="bad-meeting-habits">Bad Meeting Habits</h2>

<p>Quickly, I realized our stand-up meetings where quite awful remotely. A
dozen people standing in a circle in a large open space, talking in
turn about what they’re working on, doesn’t quite work. Especially with
distant webcam and a weak microphone. Soon, folks volunteered to pass a
laptop around so I could hear better. We worked on our own laptops all
day long but somehow crowded around one to give each other updates.
It’s obvious in hindsight that too many people were involved, but it
was easy to overlook the issue in person. We soon reduced the size of
teams which needed to share frequent updates. I partially credit remote
communication for accelerating this realization. Standups later became
video calls were each person used their own machine, making everyone as
visible and audible, wherever they worked.</p>

<p>It’s hard to say that I thrived working 7253 kilometers away from my 
co-workers, but somehow, I managed. I enacted a personal policy that has 
persisted ever since, sometimes I surmise to the annoyance of my more 
microphone or camera shy co-workers: any non-binary (yes or no) answer 
should lead to an audio or video call so that context can be provided 
much faster than through back and forth text-based chat. Any 
demonstration should be done over screensharing or recorded (and edited) 
screencast, not with lazily put together step-by-step instructions. 
That’s because there are always missing steps, and you never identify 
them when you’re writing them down. You waste other people’s time 
instead.</p>

<h2 id="the-before-times">The Before Times</h2>

<figure>
  <img src="https://olivierlacan.com/assets/remote-podcasting-setup.jpg" alt="Profile picture of the author using Sony MDR 7506 monitor headphones and the Shure SM7B dynamic microphone." />
  <figcaption></figcaption>
</figure>

<p>By definition being <em>remote</em> means not being <em>there</em>. But <em>feeling
present</em> goes a long way. A simple look can trigger a strong reaction
and a sense of shared understanding. A slight change in intonation can
convey doubt or excitement better than a paragraph. Cameras can’t
magically make your expressions visible when light isn’t bouncing off
your face. Backlighting or <a href="https://en.wikipedia.org/wiki/Contre-jour">contre-jour</a> for example is a very
<a href="https://olivierlacan.com/posts/in-sight/#point-the-light-toward-you">common mistake</a> that I see very smart people make over and over
again, even during important video calls featuring very important people
you’d assume would have staff to assist them.</p>

<p>When I moved back to Paris in 2014, I purchased my first Logitech C920
720p webcam. Since I was also co-hosting a podcast at the time, I did
some microphone research and bought an absurdly expensive but oh so
great <a href="https://olivierlacan.com/posts/loud-and-clear/#dynamic-cardioid-microphones">Shure SM7B microphone</a>, a <a href="https://focusrite.com/en/usb-audio-interface/scarlett/scarlett-2i2">Scarlett 2i2</a> XLR to USB
interface (to convert the analog signal to USB) and a cheap
pre-amplifier. This setup alone allowed me to stand out and be often 
seen and heard better than many of my in-office co-workers who crowded 
together in conference rooms and open spaces.</p>

<h2 id="sensors-arent-eyes-and-ears">Sensors Aren’t Eyes and Ears</h2>

<figure>
  <img src="https://olivierlacan.com/assets/remote-microphone-waveforms-compared.jpg" alt="Comparing the audio waveforms of three different microphones: the 2019 16-inch MacBook Pro, the Logitech Brio webcam, and the Shure SM7B." />
  <figcaption>The flatter the audio output of a microphone, the less lifelike you will sound.</figcaption>
</figure>

<p>Still, being <em>so</em> remote was challenging. I didn’t know how to set up
the audio interface properly. I mistakenly held out on purchasing a
good set of studio headphones thinking I had a sense of my own voice’s
volume. But a microphone, like a camera, doesn’t have a human
perspective on what <em>loud</em> means. It will blast your co-worker’s ears
off or sound like you’re far away. If you’re lucky someone will
complain that you’re heard to understand. Most people won’t
bother. Don’t use a microphone with live feedback without
monitoring headphones. The pros do it for a reason.</p>

<p>Your typical headphone microphones don’t count. You’ll only hear other
people’s voices when you wear them, not your own. This is even worse 
with noise cancellation, which gives you less awareness of your own 
voice’s volume. Even if <em>your</em> voice is a the appropriate level in your 
environment, you’d be surprised how differently you sound depending on 
what microphone you’re using and how far away it is from your face.</p>

<h3 id="comparing-microphone-outputs">Comparing Microphone Outputs</h3>

<p>Here are three radically different microphones recording the exact same
input albeit at different distances from my voice:</p>

<figure class="audio">
    <figcaption>2019 16-inch MacBook Pro (60 cm from face)</figcaption>
    <audio controls="" src="https://olivierlacan.com/assets/2019-16-inch-macbook-pro.mp3">
    </audio>
</figure>

<figure class="audio">
    <figcaption>Logitech Brio webcam (50 cm from face)</figcaption>
    <audio controls="" src="https://olivierlacan.com/assets/logitech-brio.mp3">
    </audio>
</figure>

<figure class="audio">
    <figcaption>Shure SM7B (10 cm from face)</figcaption>
    <audio controls="" src="https://olivierlacan.com/assets/shure-sm7b.mp3">
    </audio>
</figure>

<p>Here is a longer demo of the RODE NT-USB microphone where I to demonstrate how useful an articulated boom arm is:</p>

<figure class="audio">
    <figcaption>RODE NT-USB (10 cm from face)</figcaption>
    <audio controls="" src="https://olivierlacan.com/assets/rode-nt-usb.mp3">
    </audio>
</figure>

<p>And the cheapest microphone I’ve tested, the Samson Q2U is impressive 
and like the Rode can work with USB alone. But it can also support an 
analog XLR to USB interface which can allow you to push the gain 
(received input volume of the mic) higher and likely get cleaner output 
as well depending on your audio interface.</p>

<figure class="audio">
    <figcaption>Samson Q2U (10 cm from face over USB)</figcaption>
    <audio controls="" src="https://olivierlacan.com/assets/samson-q2u-usb.mp3">
    </audio>
</figure>

<figure class="audio">
    <figcaption>Samson Q2U (10 cm from face over XLR via Scarlett 2i2 interface)</figcaption>
    <audio controls="" src="https://olivierlacan.com/assets/samson-q2u-xlr-mono.mp3">
    </audio>
</figure>

<p>As a bonus, here’s are some popular Apple mobile devices frequently used 
to send audio and video but don’t fare particularly well even when 
recording directly on-device with the Voice Memos app:</p>

<figure class="audio">
    <figcaption>Apple Airpod Max (on your face)</figcaption>
    <audio controls="" src="https://olivierlacan.com/assets/apple-airpod-max.mp3">
    </audio>
</figure>

<figure class="audio">
    <figcaption>Apple iPhone 12 Mini (close to your face)</figcaption>
    <audio controls="" src="https://olivierlacan.com/assets/apple-iphone-12-mini.mp3">
    </audio>
</figure>

<figure class="audio">
    <figcaption>Apple 2019 iPad Pro (30 cm from your face)</figcaption>
    <audio controls="" src="https://olivierlacan.com/assets/apple-2019-ipad-pro.mp3">
    </audio>
</figure>

<p>I think these demonstrate how much more <strong>present</strong> you can sound with 
a better microphone. I talk in a bit more detail about this and 
microphone technique <a href="https://olivierlacan.com/posts/loud-and-clear/#microphone-technique">in a previous post</a>.</p>

<h2 id="face-time">Face Time</h2>

<figure>
  <img src="https://olivierlacan.com/assets/remote-code-school-platform-standup.jpg" alt="Screenshot of a fully-remote standup with three people each on their own webcams." />
  <figcaption>A Code School Platform team standup from December 2017, finally fully remote.</figcaption>
</figure>

<p>Now let’s talk about your face. Apple did something quite meaningful 
with FaceTime. They put the onus on precisely what makes you miss your 
family and friends: their face. Not where they happen to be at the time 
you call them, or the broad context of what’s around them in a 
horizontal view, but their vertical portrait. Somehow, Apple still 
manages to produce webcams that are as bad as they were a decade ago. 
Meanwhile, Apple makes some of the best selfie phone cameras in the 
world.</p>

<figure>
  <img src="https://olivierlacan.com/assets/remote-2015-logitech-c920.jpg" alt="Screen capture of the output of a Logitech C920 webcam shot with ambient lighting behind my monitor." />
  <figcaption>Cropped Logitech C920 output lit with an Ikea lamp &amp; soft white LED back in 2015.</figcaption>
</figure>

<p>I started out with a cheap and reliable webcam: the Logitech C920. It’s
from 2012 and outputs only 720p but for nearly a decade this webcam was
basically the best out there. Especially given limitations in
bandwidth. Later on in the 2010s, webcams manufacturers introduced full
HD or 1080p resolution, and eventually 4K. It’s still arguably too much 
for just showing a small face on a screen. As photo cameras became all 
about more megapixels, so did webcams. Focusing on raw output size over 
output quality, especially in low light.</p>

<p>Compared to camera sensors now common in mobile phones, webcams are a
decade behind. My friend Justin Searls found <a href="https://reincubate.com/camo/">a way</a> to use an old
iPhone as a webcam and I completely get it. It’s far more practical
than the solution I arrived at just before the pandemic: using a Sony
A6000 mirrorless camera with an expensive 50mm lens and an Elgato Cam
Link 4K acquisition card so I can use a sensor and lens combo no webcam
maker can compete with. The strange video you see at the top of this
post was filmed with this setup. One that I actively recommended
against to any fellow remoter. Particularly folks who aren’t into
photography or videography. It’s cumbersome, complex, and requires
constant fidgeting to keep the camera on, obtain a consistent color
temperature, or prevent automatic focus hunting due to shallow depth of
field. Plus you often have to replace the camera’s battery with an
adapter so you don’t run out of juice in the middle of a meeting.</p>

<p>Two long years into this pandemic, one of the few companies that seems
to have grasped the importance of a quality sensor and lens combo is
Elgato, with their (thankfully mic-less) Facecam. But its output is too
wide by default and according to <a href="https://mobile.twitter.com/JFest/status/1445382349257064448">Elgato’s own GM it’s best to tweak
exposure manually (at least for now)</a>. Logitech has been on top of
the webcam business for years, and their best offering is the Logitech
Brio. A decent camera sensor attached to a overly wide lens better
suited for YouTubers than remote workers whose face should be the sole
focus, not their fancy backdrops. You <em>can</em> force the 4K Logitech Brio
to crop most of the background it defaults to showing so you can
display what truly matters — your face — but it takes some futzing with
settings which should be unnecessary.</p>

<iframe width="675" height="381" src="https://www.youtube-nocookie.com/embed/uzXcK0hHvUM?controls=1" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>

<p>If you watch the above demo I’m curious if you’ll wonder like me why 
multi-lens setups are so common in modern phones but don’t exist in 
any webcam. The wide angle default is only appropriate to a minority of 
webcam users (streamers) while most people would benefit from a narrow 
35mm to 50mm lens equivalent that would focus on their face instead of 
their surroundings.</p>

<p>Generally speaking, I think the Logitech Brio is the best solution for
most people given adequate lighting and restricting yourself to the
standard non-widescreen mode (I think it’s the default but you can
adjust it with the <a href="https://support.logi.com/hc/en-my/articles/360025132114-Camera-Settings">Camera Settings app</a> Logitech provides).</p>

<figure class="compare">
  <div class="first">
    <a href="https://olivierlacan.com/assets/remote-macbook-pro-2019-key-light.jpg">
      <img src="https://olivierlacan.com/assets/remote-macbook-pro-2019-key-light.jpg" alt="2019 MacBook Pro webcam output" />  
    </a>
  </div>
  <div class="second">
    <a href="https://olivierlacan.com/assets/remote-brio-key-light.jpg">
      <img src="https://olivierlacan.com/assets/remote-brio-key-light.jpg" alt="Logitech Brio webcam output" />
    </a>
  </div>
  <figcaption>2019 MacBook Pro vs. Logitech Brio w/ Elgato Key Light Air (click for full-res)</figcaption>
</figure>

<h2 id="hardware-recommendations">Hardware Recommendations</h2>

<p><strong>Updated (2022-02-24)</strong>: The $99 <a href="https://www.elgato.com/en/key-light-mini">Key Light Mini</a> was released in
February 2022. I’ve had it for only a few days. Its peak brightness
is 800 lumen instead of the Key Light Air’s 1600 lumen but I very
rarely used the Air at more than 50/70% brightness, so it’s a great
way to save $80. It is now my recommendation for lighting. This brings 
the minimum total cost of my recommended hardware down to $570 from $650.</p>

<p>Here’s a list of gear I recently recommended as an alternative to my own
unwieldy custom setup. The minimum budget is more than double the
common “$300 remote stipend” reluctantly relinquished by most companies,
while they happily purchase snacks, ergonomic chairs, networking
equipment, as well as the typical utility and office leasing costs
required for in-office workers. This should give you pause.</p>

<p>This kit is one of the simplest to use and most reliable you’ll likely 
deal with. Yes, you can get find cheaper microphones and cameras if you 
sacrifice what I believe are essential features:</p>

<ul>
  <li>flicker-free consistent lighting (no headaches or artifacts)</li>
  <li>croppable video output that focuses on your face, not the room</li>
  <li>narrow pickup microphones with live headphone monitoring</li>
  <li>headphones to hear yourself and avoid noise feedback loops</li>
</ul>

<table>
  <thead>
    <tr>
      <th>Focus</th>
      <th>Brand</th>
      <th>Model</th>
      <th>Price</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Lighting — Option 1</td>
      <td>Elgato</td>
      <td><a href="https://www.elgato.com/en/key-light-mini">Key Light Mini</a></td>
      <td>$100</td>
    </tr>
    <tr>
      <td>Lighting — Option 2</td>
      <td>Elgato</td>
      <td><a href="https://www.elgato.com/en/key-light-air">Key Light Air</a></td>
      <td>$180</td>
    </tr>
    <tr>
      <td>Face — Option 1</td>
      <td>Logitech</td>
      <td><a href="https://www.logitech.com/en-us/products/webcams/brio-4k-hdr-webcam.html">Brio</a></td>
      <td>$200</td>
    </tr>
    <tr>
      <td>Face — Option 2</td>
      <td>Elgato</td>
      <td><a href="https://www.elgato.com/en/facecam">Facecam</a></td>
      <td>$200</td>
    </tr>
    <tr>
      <td>Voice — Option 1</td>
      <td>Samson</td>
      <td><a href="http://www.samsontech.com/samson/products/microphones/usb-microphones/q2u/">Q2U</a></td>
      <td>$70</td>
    </tr>
    <tr>
      <td>Voice — Option 2</td>
      <td>RODE</td>
      <td><a href="https://www.rode.com/microphones/nt-usb">NT-USB</a></td>
      <td>$170</td>
    </tr>
    <tr>
      <td>Voice — Option 3</td>
      <td>AudioTechnica</td>
      <td><a href="https://www.audio-technica.com/en-us/at2005usb">AT2005USB</a><sup id="fnref:1" role="doc-noteref"><a href="https://olivierlacan.com#fn:1" class="footnote" rel="footnote">1</a></sup></td>
      <td>$80</td>
    </tr>
    <tr>
      <td>Mic Distance</td>
      <td>RODE</td>
      <td><a href="https://www.rode.com/accessories/stands/psa1">PSA1</a></td>
      <td>$100</td>
    </tr>
    <tr>
      <td>Ears</td>
      <td>Sony</td>
      <td><a href="https://pro.sony/ue_US/products/headphones/mdr-7506">MDR 7506</a></td>
      <td>$100</td>
    </tr>
  </tbody>
  <tbody>
    <tr>
      <td><strong>Minimum Total</strong></td>
      <td> </td>
      <td> </td>
      <td><strong>$570</strong></td>
    </tr>
  </tbody>
</table>

<p>This list is by no means exhaustive, and yes it’s very different than 
what I’ve recommended <a href="https://olivierlacan.com/posts/in-sight/#point-the-light-toward-you">in the past</a> because the world of remote gear 
is evolving at last. I’d warn you against integrated 
solutions (all-in-one lighting, camera, microphone) but it’s possible a 
company like Elgato will come out a solution that does it all pretty 
well in the future. The most expensive single component is lighting 
which might surprise you, and you may find cheaper alternatives using 
LED work lamps with color temperature control but I haven’t tried those 
out and would only encourage you to get a precise maximum lumen 
brightness output number before you settle for one. The most powerful 
LED work lamp I found on Amazon maxed out at 600 lumen, while the Key 
Light Air goes up to 1400. You won’t need all that brightness but in 
my experience 800 to 1000 lumen is the sweet spot in most environments.</p>

<p>The one-stop-shop for remote communication gear doesn’t exist quite yet,
but even if <em>some</em> of the items listed here you’d communicate remotely
with higher fidelity than the large majority of office workers
worldwide did before the pandemic. While your three-dimensional
presence will never be replaceable, it’s possible for two-way
communication to have an unprecendented amount of subtlety.</p>

<h2 id="remote-presence">Remote Presence</h2>

<figure>
  <img src="https://olivierlacan.com/assets/remote-desk.jpg" alt="Photograph of my absurdly over-engineered remote worker desk." />
  <figcaption></figcaption>
</figure>

<p>I’ve had a much more <a href="https://olivierlacan.com/setup">intricate setup</a> than the one I recommend
above since February 2020. I was preparing to author a video course for
Pluralsight and wanted to offer students the best possible learning
experience. In countless meetings since, often involving leaders far
above my paygrade, it’s impossible to count the number of times someone
who matters noticed my facial expressions and asked me to share my
thoughts, or reached out to me in DMs afterwards to learn about my setup.</p>

<p>I’ll leave you with this unfair example of a quick video demo of my 
custom setup which I shot a few months ago during a time of the day 
where the typical webcam is easily drowned out by backlighting 
especially without some bright and diffused lighting pointed at your 
face to compensate. I’m being caricaturally animated (although not that 
much for me) to highlight how much of my tone, facial expressions, and 
overal feelings you can perceive from this video. This is not edited in 
any way other than to make the file smaller and more compressed for 
easier playback on the web. Granted your Internet bandwidth is 
sufficient (and that’s a big <strong>if</strong>) and your conferencing software of 
choice doesn’t overly compress audio and video you’d likely experience
something similar on the other end of a call.</p>

<figure>
  <video poster="https://olivierlacan.com/assets/remote-720p-demo.jpg" controls="" src="https://olivierlacan.com/assets/remote-720p-demo.mp4"></video>
  <figcaption>Why can't most webcams convey your presence this well? Your phone does.</figcaption>
</figure>

<p>An easily overlooked issue when discussing putting your face on camera
is that some folks may not be comfortable or even willing to be seen
inside their remote working location (home or otherwise). Especially in
larger meetings where they don’t expect to intervene. I don’t think
it’s anyone’s duty to always have a high quality camera on. That
kind of visibility is clearly not comfortable for everyone but I think 
within reason — when not using chat or asynchronous messaging — it’s 
extremely valuable for all parties.</p>

<p>It’s the responsibility of employers to deploy the kind of budgets
already allocated toward in-office communication to remote work
equipment. It’s also the role of folks like me (and you) to help
educate IT departments and business leaders on hardware solutions that
already exist today.</p>

<p>It has become quite absurd to argue that remoteness has to mean becoming
a less visible and valued contributor to your organization. I hope this 
post can help you convince anyone who might still believe that 
communicating remotely still has to be a pain.</p>

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1" role="doc-endnote">
      <p>Although cheaper than the Rode, the Audio-Technica microphone doesn’t come with a pop filter unlike the RODE NT-USB, but you can thankfully pick one of those up for fairly cheap and mount it on the microphone boom arm. The Samson does come with a windscreen which will reduce popping sounds but not quite as much as a pop filter might although I found it sufficient. <a href="https://olivierlacan.com#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>
<img src="https://feed.olivierlacan.com/link/8226/14838519.gif" height="1" width="1"/>]]></description>
      <pubDate>Thu, 30 Sep 2021 20:16:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/14838519/high-fidelity-remote-communication</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/high-fidelity-remote-communication/</guid>
    </item>
    <item>
      <title>In Sight</title>
      <description><![CDATA[<p><img src="https://olivierlacan.com/assets/webcams.jpg" alt="Close up of Razer Kiyo and Logitech C920 webcams on top of a computer monitor" /></p>

<p>In the last decade, while phone cameras have gone from shooting tiny
noisy pictures to producing DSLR-level quality shots, webcams have
coasted on the mediocre lane. As distributed or remote work became more
common, we’ve never relied on webcams more yet they’re just as bad as
they were ten years ago. The Logitech C920 (~$50), still The Wirecutter’s top
pick in 2020, came out in January 2012 — the year of the chamfered-edged
iPhone 5.</p>

<p>I can’t fix lazy hardware design for webcam manufacturers although I do
have a long wish list (larger lenses, better sensors, lighting rings,
etc.) but I can give you some tips to help your remote co-workers
interface with the most important tool next ot your finger tips: your
beautifully expressive face.</p>

<h2 id="point-the-light-toward-you">Point the light toward <em>you</em></h2>

<p>I can’t count the number of meetings I’ve participated in where the main
speaker – often someone important – chooses to sit with their back to a
window (or several). It’s a recipe for webcam disaster, and easily the most
common mistake.</p>

<figure>
  <img src="https://olivierlacan.com/assets/dont-point-your-fucking-webcam-at-the-window.jpg" alt="Still image of a webcam recording a man sitting in the dark with his back to two large windows." />
  <figcaption>With two large windows facing a webcam, you will always be underexposed.</figcaption>
</figure>

<p>Webcams calculate the average light ouput within a frame to determine how
to balance the exposure value. When you sit in front of a bright
daylight window, you’re turning yourself into a minority exposure sample
because the majority of the frame is much brighter than you. Innevitably,
your background washes you out and your face is shrouded in darkness.</p>

<p>Next time this happens to you, try to use your hands to prevent as much
light from reaching the webcam lens as possible. Immediately, you’ll see
your face brighten on the webcam feed. Since this isn’t really a
practical thing to do while having a conversation, please try never to
point your webcam toward a window while on a call. Your coworkers will
thank you.</p>

<figure>
  <img src="https://olivierlacan.com/assets/logitech-c920-vs-razer-kiyo.jpg" alt="Side-by-side comparison of the lighting captured by the Logitech C920 on the left and the Razer Kiyo on the right, showing much better face lighting on the Razer Kiyo." />
  <figcaption>Logitech C920 (left) vs. Razer Kiyo (right) both at their maximum digital zoom level.
Since the Kiyo ships with an adjustable ring light, it can easily compensate for bright backgrounds.</figcaption>
</figure>

<p>Some days, or inside of dark offices, pointing a window <em>at</em> your face
might not be an option. Try to find a bright desk lamp with a lampshade
that can diffuse light so it’s not too harsh on your face. I use a
simple double-bulb lamp with two 5.5 Watt LED soft white bulbs (2700
Kelvin) as a backup light source. If you can afford a higher webcam
budget, the newer Razer Kiyo webcam (~$80) has an adjustable LED light ring
around it which provides incredible lighting. I wish more webcams
offered this option. The improvement is staggering.</p>

<h2 id="if-you-cant-zoom-in-get-closer">If you can’t zoom in, get closer</h2>

<p>Your face matters. I know you might not <em>love</em> your face (therapy is
priceless) but if you’re going to represent less than 50% of the total
size of the webcam frame, you might as well turn your video off and rely
on your voice alone, or just type an email with what you mean to say and
send it to your team.</p>

<figure>
  <img src="https://olivierlacan.com/assets/webcam-wide-vs-zoomed.jpg" alt="Screenshot of the Zoom call interface with webcam set to its default wide angle mode and no backlighting compensation, causing the author of this diatribte to uncharacteristically gloomy-looking,
compared to the same webcam zoomed in." />
  <figcaption>Webcams show too much of your surrounding by default and their auto-exposure struggles with bright backgrounds. Using the maximum zoom settings can improve both instantly.</figcaption>
</figure>

<p>Faces are incredibly detailed interfaces. If I can see your face on a
video call, smile, and tell you to go to hell in response to a joke,
it’s likely you’d understand that I’m not actually offended nor that I
mean to actually insult you. When that situation unfolds with little or
no visual context, it can be a lot more tricky to determine if the
conversation is in good fun or not. One of the most difficult aspects of
remote work is the lack of high bandwidth communication. Unsurpsingly,
and despite the many advantages of distributed work, face-to-face
conversation tend to prevent ambiguity. But the comparison is often
unfair because little to no effort is made to increase the
conversational bandwidth of remote discussions.</p>

<figure>
  <img src="https://olivierlacan.com/assets/webcam-settings-interface.png" alt="Screenshot of the interace of the macOS app Webcam Settings which
showing its Advanced Settings where the digital zoom level of an external webcam
can be changed." />
  <figcaption>Webcam Settings (macOS) can alter the digital zoom level of most
external webcams, allowing you to focus on your face but also avoid drawing
attention to your messy work area.</figcaption>
</figure>

<p>I use a macOS Menu Bar app called <a href="https://apps.apple.com/us/app/webcam-settings/id533696630?mt=12">Webcam Settings</a> to tweak my
external webcam’s default setting. It’s not free ($7.99) but worth the
cost and compatible with most third-party webcams. It allows you to dig
into settings that your operating system or the webcam don’t expose:
white balance, brightness, saturation, zoom level and exposure time.</p>

<p>You might be able to find alternative tools for your own OS. If you
can’t, perhaps try to find a way to bring your webcam closer to you.
Screen-mounted webcams can only get so close, which is why zooming is
such a good option in my mind.</p>

<figure>
  <img src="https://olivierlacan.com/assets/zoom-in-your-webcam.jpg" alt="Screenshot of a Zoom video meeting in screensharing mode with 6 participants displayed as small thumbnail, with their faces hard to distinguish, except the leftmost face, yours truly smirking
with an of smugh satisfaction at his fancy webcam setup which probably allows his coworkers
to notice how distracted he is in this meeting." />
  <figcaption>Most webcams default to wide angles which make no sense in many group
calls where your webcam video will only be displayed as a tiny thumbnail, so
zoom in if you can, or get closer.</figcaption>
</figure>

<p>Sadly the Webcam Settings app doesn’t work with Apple’s embedded FaceTime
webcams on most of the MacBook models I’ve tried it on. Thankfully, webcams like
the Riyo and the C920 are easy to carry while traveling – although you’ll need 
a USB-C to USB-A hub to use them with recent machines. By the way, try to avoid
the chin-o-vision distorsion effect that occurs when a laptop is
pointed up toward your face. Laptops webcams are rarely very flattering to
begin with, and this kind of angle also tends to accentuate lighting issues
because ceilings are often brighter than most skintones which once again will
make you look too dark. Laptop stands can help with this, but external webcams
that can be mounted on top of your monitor are best.</p>

<h2 id="no-peeking">No peeking</h2>

<p>It’s unlikely someone’s spying on your via your webcam unless you’ve angered
a nation-state or you have exceptionally bad <a href="https://ssd.eff.org/en">operational security</a> but it
doesn’t hurt to cover your bases.</p>

<p>Webcam cover are fine, especially if you get them for free (some new
C920 models ship with one). But if you don’t want to bother puting the
cap on and off a webcam cover, I’d recommend at least making sure you’re
notified when your webcam is active or not. Patrick Wardle from
Objective-See makes a little utility called <a href="https://objective-see.com/products/oversight.html">OverSight</a> which does
exactly that. It can also let you know when your microphonne is
activated.</p>

<h2 id="dont-talk-to-webcams">Don’t talk to webcams</h2>

<p>Embedded microphones on webcams are just bad. The reasons are simple:</p>
<ul>
  <li>manufacturers have little incentive to improve them.</li>
  <li>webcams are too far from your mouth to pick up sound properly.</li>
  <li>embedded microphones are tiny, cheap, and usually terrible.</li>
  <li>the <a href="https://en.wikipedia.org/wiki/Audio_feedback">Larsen effect</a> (proximity to speakers) can cause feedback loops.</li>
</ul>

<p>I wrote a <a href="https://olivierlacan.com/posts/loud-and-clear/">whole post about microphones</a> but if you want a one liner:
just use a standalone microphone with or without headphones attached to
it. You’ll avoid nasty feedback loops. But if you (or your employer)
can afford it, how your words are transmitted is just as important
as the face that gives those words context, emotions, and a human touch.</p>

<img src="https://feed.olivierlacan.com/link/8226/14157003.gif" height="1" width="1"/>]]></description>
      <pubDate>Wed, 29 Jan 2020 21:19:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/14157003/in-sight</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/in-sight/</guid>
    </item>
    <item>
      <title>Loud &amp; Clear</title>
      <description><![CDATA[<p>It’s strange how many people who work or communicate in a distributed
fashion treat the transmission of their voice as an
afterthought.</p>

<p>My audio setup is a bit excessive for most people. You would probably
be better served by something as pricey-yet-simple like AirPods. Despite
their size, they carry a surprisingly decent microphone, as do EarPods.
And unlike a serious microphone setup, you’re much more likely to carry
them with you when you travel.</p>

<p>There are, however, some noticeable drawbacks to AirPods:</p>
<ul>
  <li>they’re tied to the Apple ecosystem.</li>
  <li>you have to be mindful of <a href="https://support.apple.com/en-us/HT207012">their battery</a> level.</li>
  <li>they do a lot of heavy-handed audio compression</li>
  <li>you can’t hear your own voice, this is worse than it… sounds.</li>
</ul>

<p>Large image sensors tend to produce drastically better image quality
on digital cameras. Large microphone sensors (capsules) similarly
produce noticeably better audio quality. These microphones don’t
<em>have to be</em> incredibly expensive and they will dramatically improve the
impact of your voice when it’s sent across a wire to another person.</p>

<p>Your voice will be clearer, more life-like, and the modulations of your
speech will allow you to stand out when you speak. Especially compared
to speakers who are communicating through a tin can of a microphone. You
already know the value of a good headshot, or maybe you’re aware of the
importance of good lighting with webcams, but microphones are recording
the actual message, not just the medium. They matter a lot.</p>

<h2 id="condenser-cardioid-microphones">Condenser Cardioid Microphones</h2>

<p><img src="https://olivierlacan.com/assets/microphone-setup.jpg" alt="Close up shot of a sideways Samson CL8 cardioid microphone attached to
a boom arm with a shockmount and a pop filter attached" /></p>

<p>The microphone I use most of the time isn’t <em>that</em> impressive. It can be
found new for as low as $70, and even less used. But don’t get fooled,
you can’t use it without some accessories I’ll go into later.</p>

<p>It’s an old <a href="http://www.samsontech.com/samson/products/microphones/condenser-microphones/cl8/">Samson CL8</a> <a href="https://en.wikipedia.org/wiki/Microphone#Cardioid,_hypercardioid,_supercardioid,_subcardioid">cardioid microphone</a> from the
now bygone era when we hosted podcasts weekly at Envy Labs and Code
School. It’s a workhorse and it’s been working without a glitch for at
least a decade. We routinely used it for voice-over work on screencasts.</p>

<p>Cardioid microphones like the CL8 have a very narrow pickup pattern: the
area where the microphone actually receives audio input. That makes them
great at isolating sound, especially if you learn decent microphone
technique. The capsule inside of the microphone receives vibrations from
your mouth hole and converts them into an analog signal. Because of the
fairly sensitive capsule, the CL8 is quite sensitive to <a href="https://en.wikipedia.org/wiki/Stop_consonant">plosives</a>
(P, T, F, D sounds) but it’s nothing some care or a good pop filter can’t prevent.</p>

<h2 id="xlr-to-usb-audio-interface">XLR to USB Audio Interface</h2>

<p>As an analog output microphone, the CL8 ends in a male XLR connector
which means it requires an XLR to USB audio interface to convert the
signal into a digital one. I use the simple and mostly user-friendly
<a href="https://focusrite.com/en/usb-audio-interface/scarlett/scarlett-2i2">Scarlett 2i2</a> (2 inputs, 2 outputs) which is about as small as
these things get. The 2i2 includes a decent <a href="https://en.wikipedia.org/wiki/Preamplifier">preamplifier</a>
(“preamp”) that allows you to increase the gain (sensitivity) of the mic
with hardware but also to receive live monitor feedback from the mic.</p>

<p>When I said you can’t hear yourself when speaking into AirPods, this is
what I meant. With live monitoring, you hear how you actually sound to
your audience. This feedback look is immensely valuable to improve your
microphone technique. It’s especially useful when recording screencasts,
participating in calls or podcasts, and surprisingly when writing. You
end up hearing your words as listeners would and it’s much easier to
write something that flows well. I use it constantly to edit my own
writings.</p>

<h2 id="desktop-mounted-articulated-boom-arm">Desktop-mounted articulated boom arm</h2>

<p>I highly recommend a desktop boom arm like the <a href="http://www.rode.com/accessories/psa1">RODE PSA1</a>. It
lets your microphone float over your desk and follow your mouth without
requiring you to stand awkwardly near the mic. Mine is paired with a
Samson SP01 spider shock mount. Since the boom arm is clamped onto my
desk, any typing or involuntary finger drumming I do while recording
would otherwise easily transfer as vibrations to the mic. Some folks use
pop filters to reduce plosive sounds since those can hold back some of
your breath to prevent loud popping sounds. I find them unwieldy and
I’ve managed to become good enough at avoid blowing air directly into
the microphone capsule so I’ve stopped using them, but you might find
them useful at least at first considering how cheap they are.</p>

<p>You can probably tell at this point that this all requires a serious
<em>level</em> of dedication to sound quality, similar to espresso nerdery. As
with any domain, you can always simplify the setup by spending a lot
more money. You can also easily spend yourself into diminishing
audiophile returns. My alternative microphone setup requires no shock
mount, or pop filter, but it does require additional signal boosting.</p>

<h2 id="dynamic-cardioid-microphones">Dynamic Cardioid Microphones</h2>

<p>The <a href="https://www.shure.com/en-GB/products/microphones/sm7b">Shure SM7B</a> is often used in radios because it’s incredibly
easy to use. You can get insanely close and you won’t cause
pops by saying words with plosives or even blowing into the mic. That’s
because, as a dynamic microphone, it’s designed to record loud sounds
like instruments or singers. Instead of a capsule, it uses a wire coil
inside of its elogated body and you talk into the end of it rather than
a side as you would with condenser microphones like the CL8. This means
the microphone technique is similar to what you’d do with a handheld
singing microphone like the kinds you’ve probably used at karaoke.</p>

<p>The SM7B comes with an internal shock mount so it doesn’t need any
spidery-looking contraptions to avoid picking up vibrations from your
desk. I still use a Scarlett 2i2 to interface with my computer since it
also uses an XLR cable instead of USB, but I also need an additional amp
since its base signal is very quiet (it’s usually used with expensive
audio capture equipment which includes powerful signal processing). The
easiest solution for this is the <a href="https://www.cloudmicrophones.com/cloudlifter-cl-1">Cloudlifter CL-1</a> in front of the
Scarlett 2i2. The RODE PSA1 boom arm works just as well for that mic
since the thread on the back is compatible.</p>

<p>Biggest difference? Price. The SM7B is $400 where the CL8 is $90. And it
needs a dedicated pre-amp like the Cloudlifter CL-1 ($160). It adds up
quick.</p>

<h2 id="wireless-vs-condenser-vs-dynamic-microphones">Wireless vs. Condenser vs. Dynamic Microphones</h2>

<table>
  <thead>
    <tr>
      <th>Model</th>
      <th>Shock</th>
      <th>Boom</th>
      <th>Pre</th>
      <th>USB</th>
      <th>Total</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><a href="https://www.apple.com/airpods/">AirPods</a></td>
      <td>None</td>
      <td>None</td>
      <td>None</td>
      <td>None</td>
      <td>$160</td>
    </tr>
    <tr>
      <td><a href="http://www.samsontech.com/samson/products/microphones/condenser-microphones/cl8/">Samson CL8</a></td>
      <td><a href="http://www.samsontech.com/samson/products/accessories/microphone-accessories/sp01/">SP01</a></td>
      <td><a href="http://www.rode.com/accessories/psa1">PSA1</a></td>
      <td>None</td>
      <td><a href="https://focusrite.com/en/usb-audio-interface/scarlett/scarlett-2i2">2i2</a></td>
      <td>$400</td>
    </tr>
    <tr>
      <td><a href="https://www.shure.com/en-GB/products/microphones/sm7b">Shure SM7B</a></td>
      <td>None</td>
      <td><a href="http://www.rode.com/accessories/psa1">PSA1</a></td>
      <td><a href="https://www.cloudmicrophones.com/cloudlifter-cl-1">CL-1</a></td>
      <td><a href="https://focusrite.com/en/usb-audio-interface/scarlett/scarlett-2i2">2i2</a></td>
      <td>$650</td>
    </tr>
  </tbody>
</table>

<p>You can always find cheaper setups, and I’ve recommendded some in the
past for distributed co-workers and acquaintances. For instance you’ll
find $60 kits on Amazon with a cheap cardioid mic, shock mount, pop
filter, and arm. These will feel like great deals because they’re
all-in-one. But you’ll quickly realize those often don’t have live
monitoring or any hardware gain/volume control. This means you’ll end up
spending a lot of time fiddling with software sound input controls
(worse, at the OS level) and you’ll likely struggle to get a sense for
what you sound like. So be warned.</p>

<h2 id="microphone-technique">Microphone Technique</h2>

<p>No matter how much money you spend, if you don’t <em>spend</em> more time
learning <em>how</em> to use the tool, you’ll be pissing money down the drain.</p>

<p>A $3000 double boiler espresso machine is a marvel of engineering but in
the hands of someone who isn’t interested in learning the ins and outs
of coffee making, it’s just a hulking heap of metal that draws 1000
watts of power and constant comparisons to the wasteful ease of a K-cup
trash printer.</p>

<p>I first got interested in microphones in 2010 when I bought my first
Yeti from Blue Microphones (skip it). Ten years later and I’d say
I’m competent with most of the variables of voice recording:</p>
<ul>
  <li>Appropriate distance from the noise hole.</li>
  <li>Angled away from the line-of-breath.</li>
  <li>Grounded power delivered by a <a href="https://superuser.com/questions/912679/when-do-i-need-a-pure-sine-wave-ups">sine wave UPS</a>.</li>
  <li>Avoid electromagnetic interference with quality cables.</li>
  <li>Decibels should stay below 0 even when you raise your voice.</li>
  <li>Loudness is relative, trust the tools not your ears.</li>
  <li>Remember to breathe, slow down.</li>
</ul>

<p>The capsule inside of your microphone is like a partner’s very sensitive
eardrum when your mouth is centimeters away from it. Stop. Yelling.</p>

<p>Listen to some of the greatest podcasts out there: Radiolab, Serial, 99%
Invisible, Criminal. One thing you’ll realize quickly is how airy the
voices of their hosts are. Jad Abumrad and Sarah Koenig in particular
actually sound <em>earnest</em>. It might sound absurd, but just as you can
hear someone smile, so can you sound honest and authoritative if you do
the right thing.</p>

<p><img src="https://olivierlacan.com/assets/microphone-sweet-spot.jpg" alt="Schematic showing the cardioid polar pattern of a microphone and how the sweet spot for placing one's mouth is roughly a fist away from the front of the microphone and roughly 30 degrees around the center" /></p>

<p>The sweet spot will vary depending on the timber of your voice but my
rule of thumb for most people is “a fist away” because it’s easy to
measure. The size of your fist doesn’t matter than much.</p>

<p>An easy trap to fall into when you get into serious voice recording
gear is accoustic room treatments such as foam, bass traps, and even
recording booth kits. The whole point of cardioid polar pattern
microphones is that they already ignore much of a room’s reflective
noise. Unless you record in the largest and most reflective (tile, glass,
hard and wide surfaces) room, you probably shouldn’t worry about
accoustics until you have an unmistakable sound reflection/echo problem.</p>

<p>Finally, remember that your body will affect the way you sound. Try
placing your microphone higher than your head on the boom arm so you
don’t slouch to speak into it. Keep water nearby so you don’t sound
parched and raspy. There’s nothing worse than the high fidelity sound of
someone sticky jowls. Nasal congestion will ruin your diction. Learn to
decompress your sinuses or keep some safe nasal decongestant around. And
if you find yourself slurring, stretch out your mouth muscles a bit with
some diction excercises (“Unique, New York”) to relax these muscles and
help you articulate.</p>

<p>I’m sure it sounds like a lot in the aggregate, but these are not things
you have to do all at once. Microphone technique can help someone using
corded EarPods and other crappy wire-mounted microphones. You can start
small. But if you do anything about the way you sound, make it recording
yourself and listening back to how you sound to people who aren’t in the
room with you. It will give you a great idea of how much room for
improvement you have.</p>

<p><strong>Note: you can go a long way with great sound, but sometimes watching
someone’s facial expression when they speak – and when they don’t – can
make all the difference in the world. I wrote a follow up to this post on
the topic of <a href="https://olivierlacan.com/posts/in-sight">webcams and how to make them suck less</a>.</strong></p>

<img src="https://feed.olivierlacan.com/link/8226/14157004.gif" height="1" width="1"/>]]></description>
      <pubDate>Fri, 20 Dec 2019 13:18:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/14157004/loud-and-clear</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/loud-and-clear/</guid>
    </item>
    <item>
      <title>Immunity</title>
      <description><![CDATA[<p><strong>The following post is reproduced from <a href="https://github.com/orientation/orientation">Orientation</a> — Code School’s
internal documentation system. I wrote it many years ago when we first
decided to build out the team that took care of codeschool.com. I was an
early member of that team and many things we had built were created
under very different circumstances by a rotating cast of developers who
rarely stuck around for more than a few weeks or months. This could be
very disorienting for someone joining to work on the largest codebase
in the company by far, which is why our approach to onboarding was so
important.</strong></p>

<p>Whenever someone joins our team and I have the chance to talk to them at
the very beginning, the first thing I make sure to have with them is the
Immunity Talk.</p>

<p>It shouldn’t be this way, but in many companies the first few months
after you join are generally the ones during which it seems like your
opinion matters the least. You haven’t built relationships with people
yet. You don’t know who’s receptive to criticism and comments yet. You
feel like you have everything to prove and so whenever you encounter
something odd — something that doesn’t quite make sense to you — you
tend to brush it aside.</p>

<p>A lot of people do this, and it makes me really sad.</p>

<p>Whenever you’re stuck working on something for too long it’s common to
ask for a “fresh pair of eyes”. You want someone with a different
perspective or a different set of assumptions to look at what you’ve
been struggling with. It often works amazingly well because after
working on the same thing for a while, lots of things become part of the
noise. You don’t notice typos. You don’t realize that there’s a glaring
mistake or a bad assumption. People with fresh eyes, however, can often
spot what the problem is instantly.</p>

<p><img src="https://olivierlacan.com/assets/rubber-duck-debugging.jpg" alt="Rubber Duck People" /></p>

<p>This logic is so obvious to so many people that we’ve even invented a
way to simulate it: <a href="http://en.wikipedia.org/wiki/Rubber_duck_debugging">Rubber Duck Debugging</a>. That’s when you pretend
to talk to a Rubber Duck on your desk and explain every step of the
problem you’re facing to them. Just like the fresh pair of eyes, it’s
often within the first few steps that you realize you’ve made a
fundamental mistake that can easily be corrected. It avoids you the
embarassment of asking for help and having someone immediately realize
that you forgot a single semicolon in the most obvious spot.</p>

<p>Somehow though, this logic is never applied to new hires or recent
additions to a team. We don’t realize the value of their fresh eyes on
this thing we’ve been working on for so long. In our context at Code
School, it could be some code that we forgot about and is causing
obvious performance issues. Or it could be a policy that we’ve
established years ago and never really reconsidered, until someone
asks: “Why do we do this?”. And we realize that no one has a clue.</p>

<p>So instead of thinking of yourself or your new teammates as people with
not enough knowledge to hold a valuable opinion, I challenge you to
think of all the things that could be fixed by a few pairs of fresh
eyes and some well-needed critical thinking.</p>

<img src="https://feed.olivierlacan.com/link/8226/9590945.gif" height="1" width="1"/>]]></description>
      <pubDate>Wed, 27 Jun 2018 02:06:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/9590945/immunity</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/immunity/</guid>
    </item>
    <item>
      <title>The Fear of Pairing</title>
      <description><![CDATA[<p><strong>These days</strong>, I’m always eager when I have a chance to <a href="https://en.wikipedia.org/wiki/Pair_programming">pair program</a>
with someone for the first time. Whether they’re more or less
experienced than I am, I know that we’ll most likely learn a ton from
each other. Maybe they’ll make me explain something I thought I
understood, but in fact had incomplete knowledge of; or maybe they’ll
take something that used to intimidate me and make it easily relatable.
It’s always a learning opportunity for both parties in some way.</p>

<p><strong>A few years into my programming career</strong>, it was often an anxiety-inducing
experience for me to even <em>think</em> about working with a more senior
developer so closely. To see them see me work. Would they think I’m
useless? Would they notice that I don’t understand some basic computer
science principle they might deem necessary to do my job? Or would they
find my tools inadequate compared to theirs?</p>

<p>These fears were all rooted in my convinction that my pairs would
discover that I had no idea what I was doing. Which to be fair, was
true and still is, in many respects.</p>

<p>Thankfully, as many programmers find out as their career unfolds, the
dreaded unmasking moment doesn’t really ever happen. That is, unless
you’re unfortunate enough to encounter a toxic programmer who feels
powerful when they put down other people or who somehow decides to self-
righteously gatekeep against the uncivilized hordes of junior
programmers.</p>

<p>If you ever encounter someone like that — or if you already did — please
know that the problems is theirs, not yours. I hope you can find a way
to isolate yourself from such toxic people or find diplomatic ways to
ask them to quit acting like assholes. Sure, you may be able to learn
some techniques from them, but you also risk adopting horrible habits
that will negatively impact your own career and the well-being of your
team. Additionally, these toxic people survive by turning other people
into toxic people. That way, they don’t seem that bad. They are bad.</p>

<p>What should happen after a few uncomfortable pairing sessions is that
you find some comfort in pair programming and you start to realize that
everybody has some knowledge or perspective that can benefit the other
pair. But also that everyone becomes a bit better at pretending they
have their shit together as time goes by. Whether it’s because it
bolsters someone to feel like their expertise and opinions are valued by
their peers and pairs, or because they start to notice their own growth
through engaged collaboration and discussion.</p>

<p>Although it might be anecdotal evidence, I didn’t get fired right after
my first pairing session with a much more senior developer. After a
while, I started finding solace in the fact that if I had been so
<em>shockingly bad</em> my pair might have taken the time to put me out my
misery. Or at least take me aside to tell me what I needed to improve.</p>

<p>I know that proponents of pair programming can often seem a little too
eager. It’s also hard not to feel intimated by people who seem so
comfortable with their own skills that they’re willing to have them
scrutinized up close. It feels as if they actually want to be
micro-managed by a fellow programmer.</p>

<p>But this is not what healthy pairing looks like — even beyond
programming. There are many styles and flavors of pairing. Some, like
<a href="https://en.wikipedia.org/wiki/Mob_programming">mobbing</a> even sound dangerously close to the dreaded <a href="https://en.wikipedia.org/wiki/Design_by_committee">Design by
Committee</a>. My simplest token for a successful pairing session is
engagement. It’s harder to get this right in remote pair programming
scenarios — which is what I do the most — because you often can’t <em>see</em>
your pair. You may start to get the creeping sensation that one of the
pairs is going too fast and that their pair <em>checked out</em> either because
they don’t feel comfortable enough to ask a question, or because the
rhythm doesn’t work for them, or worse, because they feel that they have
nothing to contribute — which is not true.</p>

<p>Even a very senior programmer has something to gain from collaborating
with a complete beginner. For example, while they have many more
experiences to draw from, experts also make many assumptions based on
past experience or reject ideas because of past battle scars which may
not longer be relevant. Beginners don’t have past that much experience
to build biases from and they naturally have fewer horring stories
scaring them away from trying something new or different.</p>

<p>In the case of software, an experienced programmer could be trying to
shoehorn a solution that has worked before instead of trying something
that may be more appropriate to the specific problem at hand. Or they
could assume that a complex solution will be more sustainable without
bothering to make the case for its upfront cost to their less
experienced collaborator. Even if it worked before, you still have to
convince your pair that it’s good idea. Having to prove the worthiness
of a solution that may appear not to require proof is precisely why
pairing with diverse people is incredibly valuable.</p>

<p>By diverse I mean <strong>actually</strong> diverse: ethnically, linguistically,
philosophically, sexually, physically, gender-wise and age-wise. Biases
and assumptions are everywhere and they are preventing us from seeing
alternative paths and solutions that can be simpler, more elegant, and
more sustainable just because we’re dogmatically holding on to the
solutions and perspectives we’re comfortable with. More importantly this
is how the best teams are built.</p>

<p>Some of my best pairing experiences ever came from working with people
who had different gender, ethnicity, and knowledge than me. They might
have known more about computer science, but I had a bit more practical
experience with building software; we weren’t offended or bothered by
the same things; we didn’t even feel challenged by the same kinds of
problems which meant we could take turns supporting each other depending
on what kind of task lay ahead.</p>

<p>All of this is to say that the fear of pair programming is <em>valid</em>.
You’re not weird and sheepish for having it. If you’ve managed to
prevail over that feer, great! Help others do the same. But don’t forget
how hard it was to imagine before you succeeded over the hurdle. If
you’re still looking at pairing like a huge monolith looming over you,
also know that there are plenty of people who successfully work without
it. My opinion is that they’re missing out, but that doesn’t mean I
don’t like to work alone from time to time so I can dive deeply into a
problem on my own. Even if the growing rabbit ears often remind me that
I’m missing my pairs.</p>

<img src="https://feed.olivierlacan.com/link/8226/8804667.gif" height="1" width="1"/>]]></description>
      <pubDate>Sun, 08 Apr 2018 20:06:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8804667/the-fear-of-pairing</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/the-fear-of-pairing/</guid>
    </item>
    <item>
      <title>cd is Wasting Your Time</title>
      <description><![CDATA[<p>As a programmer or someone who spends a lot of time in command line
shells, it’s likely that you regularly move around directories in ways
that might feel less than efficient. Especially if you often visit the
same directories every day.</p>

<p>The routine probably goes a bit like this:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
</pre></td><td class="rouge-code"><pre><span class="nb">cd</span> ~/Development
<span class="nb">ls</span> <span class="c"># look around...</span>
<span class="nb">cd </span>project
<span class="c"># whoops, never mind, let's go back...</span>
<span class="nb">cd</span> ..
<span class="c"># time to start something new...</span>
<span class="nb">mkdir </span>new_project
<span class="nb">cd </span>new_project
<span class="c"># need to check something in that other directory...</span>
<span class="nb">cd</span> ../project
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Maybe with a bit more experience, you have some tab-completion tricks up
your sleeve to avoid typing these full directory names, so in reality it
looks more like:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="nb">cd</span> ~/Dev&lt;TAB&gt;
<span class="nb">ls</span> <span class="c"># look around...</span>
<span class="nb">cd </span>pro&lt;TAB&gt;
<span class="nb">cd</span> ..
<span class="nb">mkdir </span>new_project
<span class="nb">cd </span>new&lt;TAB&gt;
<span class="nb">cd</span> ../pro&lt;TAB&gt;
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Great. You saved about 20 keystrokes. That’s commendable. Yes, you could
also use the return value from the <code class="language-plaintext highlighter-rouge">mkdir</code> command to immediately move
into the newly created directory (<code class="language-plaintext highlighter-rouge">cd !$</code>). And you could just remember
that <code class="language-plaintext highlighter-rouge">project/</code> is nested inside <code class="language-plaintext highlighter-rouge">Development/</code> so that you don’t need
to <code class="language-plaintext highlighter-rouge">ls</code> around to find your way. The reality is that people are not
computers and memorizing your entire directory’s tree structure is a
trick that only impresses people who far too much time on their hands.</p>

<p>But what about this?</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre>j d
j p
<span class="nb">cd</span> ..
<span class="nb">mkdir </span>new_project
<span class="nb">cd </span>new&lt;TAB&gt;
j p
</pre></td></tr></tbody></table></code></pre></div></div>

<p>The most obvious benefit is that this took 18 fewer keystrokes to
accomplish the same goals but what may not be so obvious is that the <code class="language-plaintext highlighter-rouge">j
d</code> (or <code class="language-plaintext highlighter-rouge">j dev</code>, <code class="language-plaintext highlighter-rouge">j develop</code>, etc.) command will now take you to
<code class="language-plaintext highlighter-rouge">~/Development/</code> and <code class="language-plaintext highlighter-rouge">j p</code> to <code class="language-plaintext highlighter-rouge">~/Development/project</code> from anywhere
inside your filesystem. So this relatively small gain in typing
efficiency will compound with time.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="nb">cd</span> /usr/local/lib/something/log/
j p
<span class="nb">pwd</span>
~/Development/project
</pre></td></tr></tbody></table></code></pre></div></div>

<p>How does it work? <a href="https://github.com/wting/autojump">AutoJump</a></p>

<p>AutoJump is magic cape that lets you fly around directories in your
command line. The official description of the tool is “a faster way to
navigate your filesystem” — but that doesn’t quite do it justice. It a
bit of an undersell. My <strong>completely made up</strong> estimate is that Autojump
has saved me from at least a whole year of typing. At the very least
that’s how it feels.</p>

<h2 id="how-autojump-works">How Autojump works</h2>

<p>This command:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre>j project
/Users/olivierlacan/Development/project
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Works just the same as this command:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre>j p
/Users/olivierlacan/Development/project
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Why? Because AutoJump remembers all of the directories you move
into with the <code class="language-plaintext highlighter-rouge">cd</code> command or with its own <code class="language-plaintext highlighter-rouge">j</code> command. And more
important, AutoJump does <a href="https://en.wikipedia.org/wiki/Fuzzy_matching_(computer-assisted_translation)">fuzzy matching</a>. Meaning it will look
for a directory you’ve visited before that contains the same string of
letters you provide, even if you only provide one letter.</p>

<p>What if you have two directories that start with the letter <code class="language-plaintext highlighter-rouge">p</code>? That’s
where it gets interesting.</p>

<p>The first time you type <code class="language-plaintext highlighter-rouge">cd directory_name</code>, Autojump logs the absolute
path to that directory and assigns it as weight (or rating) of <code class="language-plaintext highlighter-rouge">10.0</code>.</p>

<p>So if you do:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nb">cd</span> /var
</pre></td></tr></tbody></table></code></pre></div></div>

<p>You will see the following in the <code class="language-plaintext highlighter-rouge">j -s</code> command (<code class="language-plaintext highlighter-rouge">s</code> stands for “stats”):</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>10.0: /var
</pre></td></tr></tbody></table></code></pre></div></div>

<p>What if you visit <code class="language-plaintext highlighter-rouge">/var</code> again?</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>14.1: /var
</pre></td></tr></tbody></table></code></pre></div></div>

<p>And so on. If you visit a directory often the rating for that directory
will increase. In my case, you can easily guess what I spend most
of my time doing by looking at my top 5:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="rouge-code"><pre>j <span class="nt">-s</span>

<span class="o">(</span>...<span class="o">)</span>
234.7:  /Users/olivierlacan/Development/cs/campus
262.7:  /Users/olivierlacan/Development/rubyheroes/rubyheroes.com
417.4:  /Users/olivierlacan/Development/perso/orientation
874.1:  /Users/olivierlacan/Development/cs/CodeSchool
________________________________________

10810:   total weight
198:   number of entries
0.00:  current directory weight

data:  /Users/olivierlacan/Library/autojump/autojump.txt
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Since both my first (<code class="language-plaintext highlighter-rouge">CodeSchool</code>) and fourth (<code class="language-plaintext highlighter-rouge">campus</code>) directories
contain the letter <code class="language-plaintext highlighter-rouge">c</code>. How does AutoJump decide where to go? Once again,
the rating.</p>

<p>Since <code class="language-plaintext highlighter-rouge">campus</code> has a much lower rating, AutoJump will first take me to
<code class="language-plaintext highlighter-rouge">CodeSchool</code>. However, if I repeat the <code class="language-plaintext highlighter-rouge">j c</code> command, it will try the
next highest rated directory that matches the letter <code class="language-plaintext highlighter-rouge">c</code>.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre>j c
/Users/olivierlacan/Development/cs/CodeSchool
j c
/Users/olivierlacan/Development/cs/campus
</pre></td></tr></tbody></table></code></pre></div></div>

<p>If you don’t like to fly blind and assume AutoJump will make the right
choice for you, it’s also possible to see what directories match a
specific string of letters you provide:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre>j c&lt;TAB&gt;&lt;TAB&gt;&lt;TAB&gt;
<span class="nv">$ </span>j c__
c__1__/Users/olivierlacan/Development/cs/CodeSchool
c__2__/Users/olivierlacan/Development/cs/campus
c__3__/Users/olivierlacan/Development/perso/keep-a-changelog
c__4__/Users/olivierlacan/Development/perso/olivierlacan.com
<span class="nv">$ </span>j c__4
/Users/olivierlacan/Development/perso/olivierlacan.com
</pre></td></tr></tbody></table></code></pre></div></div>

<p>After display a numbered list of directories that match the supplied
argument, AutoJump will prefill the command <code class="language-plaintext highlighter-rouge">j c__</code> and let you type
the number for whichever directory you which to jump to.</p>

<h2 id="advanced-features">Advanced Features</h2>

<ul>
  <li>the <code class="language-plaintext highlighter-rouge">jc</code> (child) command will scope the search to only subdirectories
of the current directory, which is very useful to find nested <code class="language-plaintext highlighter-rouge">log</code>
directories.</li>
  <li>the <code class="language-plaintext highlighter-rouge">jo</code> (open) command will open the matched directory in your
operating system’s file manager.</li>
  <li>the <code class="language-plaintext highlighter-rouge">j -i</code> command will increase the weight of the current directory.</li>
  <li>the <code class="language-plaintext highlighter-rouge">j -d</code> command will decrease the weight of the current directory.</li>
  <li>the <code class="language-plaintext highlighter-rouge">j --purge</code> command will wipe the weighted list of directories
AutoJump relies on if you need to start from scratch.</li>
</ul>

<h2 id="installing-autojump">Installing AutoJump</h2>

<p>While AutoJump does require Python, it’s such a simple tool supported by
most shells (bash, zsh, fish) that you can install AutoJump via many
<a href="https://github.com/wting/autojump#linux">Linux package managers</a>. For macOS I recommend Homebrew’s <code class="language-plaintext highlighter-rouge">brew
install autojump</code> which couldn’t be simplier although do remember that
you have to source AutoJump in your <code class="language-plaintext highlighter-rouge">.bash_profile</code> or <code class="language-plaintext highlighter-rouge">.zshrc</code> by
adding the following line:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="o">[</span> <span class="nt">-f</span> /usr/local/etc/profile.d/autojump.sh <span class="o">]</span> <span class="o">&amp;&amp;</span> <span class="nb">.</span> /usr/local/etc/profile.d/autojump.sh
</pre></td></tr></tbody></table></code></pre></div></div>

<p>It checks that the AutoJump script is available and simply loads it in
your shell.</p>

<p>You can also clone the git repository and use the manual <a href="https://github.com/wting/autojump#manual">installation
procedure</a> if you want to stay on the bleeding edge but it’s an
incredibly stable tool thanks to its simplicity. I don’t think I’ve
encountered a single bug in years of usage.</p>

<img src="https://feed.olivierlacan.com/link/8226/8673321.gif" height="1" width="1"/>]]></description>
      <pubDate>Mon, 26 Mar 2018 17:34:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8673321/cd-is-wasting-your-time</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/cd-is-wasting-your-time/</guid>
    </item>
    <item>
      <title>Changelogs on RubyGems.org</title>
      <description><![CDATA[<p><img src="https://olivierlacan.com/assets/changelogs_on_rubygems.png" alt="RubyGems.org screenshot showing the new changelog link in action" /></p>

<p>Did you know that changelog URLs have been valid metadata <a href="https://github.com/rubygems/rubygems.org/pull/1553">since
2017</a> on <a href="https://rubygems.org">RubyGems.org</a>? If you maintain a gem you can now make
it easier for your users to find out what’s changed in a specific version.</p>

<p>You can easily update your gems’s <a href="http://guides.rubygems.org/specification-reference/"><code class="language-plaintext highlighter-rouge">.gemspec</code></a> to point to a rendered
or plain text version of your changelog using the <code class="language-plaintext highlighter-rouge">changelog_uri</code> key in
the <code class="language-plaintext highlighter-rouge">metadata</code> hash, like this:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
</pre></td><td class="rouge-code"><pre><span class="no">Gem</span><span class="o">::</span><span class="no">Specification</span><span class="p">.</span><span class="nf">new</span> <span class="k">do</span> <span class="o">|</span><span class="n">s</span><span class="o">|</span>
  <span class="n">s</span><span class="p">.</span><span class="nf">name</span>        <span class="o">=</span> <span class="s2">"Tapdance"</span>
  <span class="n">s</span><span class="p">.</span><span class="nf">version</span>     <span class="o">=</span> <span class="no">Tapdance</span><span class="o">::</span><span class="no">VERSION</span>
  <span class="n">s</span><span class="p">.</span><span class="nf">license</span>     <span class="o">=</span> <span class="s2">"MIT"</span>
  <span class="n">s</span><span class="p">.</span><span class="nf">summary</span>     <span class="o">=</span> <span class="sx">%q{ Make tap dance on nil }</span>
  <span class="n">s</span><span class="p">.</span><span class="nf">description</span> <span class="o">=</span> <span class="sx">%q{ With tapdance you can call tap on nil and it will swallow gamma rays like a collapsing wormhome! }</span>
  <span class="n">s</span><span class="p">.</span><span class="nf">homepage</span>    <span class="o">=</span> <span class="s2">"http://github.com/olivierlacan/tapdance"</span>
  <span class="n">s</span><span class="p">.</span><span class="nf">authors</span>     <span class="o">=</span> <span class="p">[</span><span class="s2">"Olivier Lacan"</span><span class="p">]</span>
  <span class="n">s</span><span class="p">.</span><span class="nf">email</span>       <span class="o">=</span> <span class="p">[</span><span class="s2">"hi@olivierlacan.com"</span><span class="p">]</span>
  <span class="n">s</span><span class="p">.</span><span class="nf">files</span>       <span class="o">=</span> <span class="sb">`git ls-files -z`</span><span class="p">.</span><span class="nf">split</span><span class="p">(</span><span class="s2">"</span><span class="se">\x0</span><span class="s2">"</span><span class="p">).</span><span class="nf">reject</span> <span class="p">{</span> <span class="o">|</span><span class="n">f</span><span class="o">|</span> <span class="n">f</span><span class="p">.</span><span class="nf">match</span><span class="p">(</span><span class="sr">%r{^(test|spec|features)/}</span><span class="p">)</span> <span class="p">}</span>
  <span class="n">s</span><span class="p">.</span><span class="nf">metadata</span>    <span class="o">=</span> <span class="p">{</span>
    <span class="s2">"homepage_uri"</span> <span class="o">=&gt;</span> <span class="s2">"https://github.com/olivierlacan/tapdance"</span><span class="p">,</span>
    <span class="s2">"changelog_uri"</span> <span class="o">=&gt;</span> <span class="s2">"https://github.com/olivierlacan/tapdance/blob/master/CHANGELOG.md"</span><span class="p">,</span>
    <span class="s2">"source_code_uri"</span> <span class="o">=&gt;</span> <span class="s2">"https://github.com/olivierlacan/tapdance/"</span><span class="p">,</span>
    <span class="s2">"bug_tracker_uri"</span> <span class="o">=&gt;</span> <span class="s2">"https://github.com/olivierlacan/tapdance/issues"</span><span class="p">,</span>
  <span class="p">}</span>
<span class="k">end</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>You can use the metadata hash for a lot of other URIs relevant to your project
like <code class="language-plaintext highlighter-rouge">homepage_uri</code>, <code class="language-plaintext highlighter-rouge">source_code_uri</code>, and <code class="language-plaintext highlighter-rouge">bug_tracker_uri</code>.</p>

<p>Note that I’m using the <a href="https://github.com/olivierlacan/keep-a-changelog/blob/master/CHANGELOG.md">GitHub URL for the changelog</a> above when a
link to the <a href="https://raw.githubusercontent.com/olivierlacan/keep-a-changelog/master/CHANGELOG.md">raw source</a> would have worked just as well. Since <a href="https://keepachangelog.com">good
changelogs</a> are made for humans, I strongly recommend you point people to
the rendered HTML output of a nicely formatted Markdown (or other markup source
language) changelog.</p>

<p>It’s also fine to link to a project website that formats the rendered
output from the project changelog, <a href="https://emberjs.com/blog/2017/03/19/ember-2-12-released.html">like Ember does</a>. You can even link
to the <a href="https://github.com/olivierlacan/keep-a-changelog/releases">GitHub Releases page</a> if you generate release notes using
git tags on GitHub.</p>

<h2 id="version-specific-changelog-links">Version-specific Changelog Links</h2>

<p>What’s great about the way <a href="https://twitter.com/kbrock">Keenan Brock</a> implemented this feature compared to my
<a href="https://github.com/rubygems/rubygems.org/pull/728">original proposal</a> is that along with other gemspec metadata, the
changelog URI can be different between different versions of a gem.</p>

<p>This means that if your project has version-specific changelogs files, you can
point people who look at version 0.1.0 on rubygems.org to a <code class="language-plaintext highlighter-rouge">changelog-0-1-0.md</code>
file that only lists changes within this minor version.</p>

<h2 id="keeping-a-changelog">Keeping a Changelog</h2>

<p>What if your project doesn’t have a changelog? Or if instead you simply point
people to git diffs of the commits between each version.</p>

<p>About a year after making the original pull request to add these
changelog links to RubyGems.org, I created <a href="https://keepachangelog.com">keepachangelog.com</a>.
Give it a read if you’re not sure what a changelog should
contain or why you should keep one for your project.</p>

<img src="https://feed.olivierlacan.com/link/8226/8654033.gif" height="1" width="1"/>]]></description>
      <pubDate>Sat, 24 Mar 2018 18:11:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8654033/changelogs-on-rubygems-org</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/changelogs-on-rubygems-org/</guid>
    </item>
    <item>
      <title>Why Won't Bundle Update?</title>
      <description><![CDATA[<p>You just received notification from GitHub’s nifty new repository
<a href="https://blog.github.com/2017-11-16-introducing-security-alerts-on-github/">dependency scanner</a> that there is a critical vulnerability report for
the Nokogiri Ruby gem you currently have locked to version 1.6.8.1 in
your Rails application’s Gemfile.</p>

<p>It looks a little bit like this:</p>

<p><img src="https://olivierlacan.com/assets/bundler_update_nokogiri.png" alt="" /></p>

<p>Concerned, you decide to immediately update this dependency, run your
test suite, and deploy to production to prevent even the remote
possibility of an exploitation of this vulnerability in your application.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre>bundle update nokogiri
Fetching gem metadata from https://rubygems.org/.........
(... coffee (or Mamba) time! ...)
Bundler attempted to update nokogiri but its version stayed the same
Bundle updated!
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Wait, what? Why is it saying “Bundle update!” if “Bundler attempted to
update nokogiri but its version stayed the same”? That’s not really
what I call updated. But sure. In a situation like this I really wish
that Bundler would tell me why it failed its attempt to update nokogiri.</p>

<p>Why won’t it bundle update nokogiri? There visibly was no error, so
there must be a version requirement preventing this update I just
requested. My first insinct is to check the <code class="language-plaintext highlighter-rouge">Gemfile.lock</code> and sift
through any mention of <code class="language-plaintext highlighter-rouge">nokogiri</code> to see if there isn’t one requirement
that’s a bit too strict and causing this issue.</p>

<p>But then I stop myself. Why the hell isn’t my supposed best package
manager of any language ever not doing this work for me. Why am I left
grepping through a Lockfile of all things like a lowly machine?</p>

<p>There has to be a better way, right? Well…</p>

<p>There is something in RubyGems that allows you to check the installed
gem dependencies for a specific gem. You can ask <code class="language-plaintext highlighter-rouge">gem dependency nokogiri</code>
and RubyGems will tell you — for each version of nokogiri — what gems
depend on that specific version:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
</pre></td><td class="rouge-code"><pre>$ gem dependency nokogiri
Gem nokogiri-1.6.8.1
  mini_portile2 (~&gt; 2.1.0)
  minitest (~&gt; 5.8.4, development)
  racc (~&gt; 1.4.14, development)
  rake (~&gt; 10.5.0, development)
  rake-compiler (~&gt; 0.9.2, development)
  rake-compiler-dock (~&gt; 0.5.1, development)
  rdoc (~&gt; 4.0, development)
  rexical (~&gt; 1.0.5, development)
</pre></td></tr></tbody></table></code></pre></div></div>

<p>You might hope that perhaps Bundler implements similiar functionality
that is instead Gemfile-aware. Wouldn’t that be neat? Something like:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre>bundler dependencies nokogiri
  mini_portile2 (~&gt; 2.1.0)
  minitest (~&gt; 5.8.4, development)
  racc (~&gt; 1.4.14, development)
  rake (~&gt; 10.5.0, development)
  rake-compiler (~&gt; 0.9.2, development)
  rake-compiler-dock (~&gt; 0.5.1, development)
  rdoc (~&gt; 4.0, development)
  rexical (~&gt; 1.0.5, development)
</pre></td></tr></tbody></table></code></pre></div></div>

<p>I’m sorry to say, Bundler offers no such thing. At least none that I
could find in its documentation, source, issues, or pull requests.</p>

<p>But there’s hope. The kind <a href="http://josephmastey.com/">Joe Mastey</a> has created a little gem called
<a href="https://github.com/jmmastey/bundler-stats">bundler-stats</a> which allows to get some basic statistics about your
Gemfile dependencies. bundler-stats can sift through your Gemfile and
figure out how many transitive dependencies each of the gems declared
in your Gemfile are pulling along, which is quite useful. What I wanted
however is an extension to the <code class="language-plaintext highlighter-rouge">bundler-stats show &lt;gemname&gt;</code> command
which finds all gems in your Gemfile which depend on the target gem.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="rouge-code"><pre>$ bundle-stats show nokogiri
bundle-stats for nokogiri

depended upon by (34) | actioncable, actionmailer, actionpack,
actionview, approvals, capybara, capybara-screenshot, chromedriver-
helper, coffee-rails, devise, devise-two-factor, draper, formtastic,
gretel, haml-rails, html2haml, inline_svg, loofah, prawn_rails, rails,
rails-controller-testing, rails-dom-testing, rails-html-sanitizer,
railties, responders, rspec-rails, sassc-rails, sprockets-rails, xpath
depends on (1)      | mini_portile2
unique to this (1)   | mini_portile2
</pre></td></tr></tbody></table></code></pre></div></div>

<p>If only I could have had the version of nokogiri required for each of
those gems listed alongside them I could have easily figured out which
was holding nokigiri’s update back.</p>

<p>…</p>

<p>So I added <code class="language-plaintext highlighter-rouge">bundle-stats versions nokogiri</code>. :-D</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
</pre></td><td class="rouge-code"><pre>$ bundle-stats versions nokogiri
bundle-stats for nokogiri

depended upon by (34):
+------------------------------|-------------------+
| Name                         | Required Version  |
+------------------------------|-------------------+
| capybara-screenshot          | &gt;= 1.3.3          |
| capybara                     | &gt;= 1.3.3          |
| loofah                       | &gt;= 1.5.9          |
| rails-html-sanitizer         | &gt;= 1.5.9          |
| coffee-rails                 | &gt;= 1.6            |
| devise                       | &gt;= 1.6            |
| formtastic                   | &gt;= 1.6            |
| google-rails                 | &gt;= 1.6            |
| haml-rails                   | &gt;= 1.6            |
| prawn_rails                  | &gt;= 1.6            |
| rails                        | &gt;= 1.6            |
| rails-controller-testing     | &gt;= 1.6            |
| rails-dom-testing            | &gt;= 1.6            |
| xpath                        | ~&gt; 1.3            |
| inline_svg                   | ~&gt; 1.6            |
| chromedriver-helper          | ~&gt; 1.6            |
| approvals                    | ~&gt; 1.6            |
| html2haml                    | ~&gt; 1.6.0          |
+------------------------------|-------------------+
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This tells me that haml2haml (2.0.0) is being a little overspecific
with the version of nokogiri it is requiring. All the other requirements
should allow nokogiri 1.8.x to be installed but this one won’t.</p>

<p>A quick check on RubyGems.org shows me that html2haml 2.1 and later
fixed this restrictive requirement.</p>

<p>After checking <code class="language-plaintext highlighter-rouge">bundle-stats versions html2haml</code>, I don’t see a specific
requirement for html2haml 2.0.0:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre>$ bundle-stats versions html2haml
bundle-stats for html2haml

depended upon by (1):
+------------------------------|-------------------+
| Name                         | Required Version  |
+------------------------------|-------------------+
| haml-rails                   | &gt;= 1.0.1          |
+------------------------------|-------------------+
</pre></td></tr></tbody></table></code></pre></div></div>

<p>I can now be confident that running the following command will
successfully update nokogiri:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>bundle update html2haml nokogiri
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This new <code class="language-plaintext highlighter-rouge">bundle-stats versions &lt;gemname&gt;</code> is not yet available in the
released version of bundler-stats but it hopefully will be soon. I hope
this will convince the Bundler team that this sort of feature is a
must-have for a modern package manager. I honestly didn’t think I could
learn all I needed to learn about Bundler to implement this as a Pull
Request to Bundler but I did learn a ton about how the internals of
RubyGems’ <code class="language-plaintext highlighter-rouge">Gem::Version</code>, <code class="language-plaintext highlighter-rouge">Gem::Requirement</code>, and <code class="language-plaintext highlighter-rouge">Gem::Dependency</code>
work thanks to Joe’s work on <code class="language-plaintext highlighter-rouge">bundler-stats</code>.</p>

<p>If you’re curious about this stuff, you can take a look at the changes
introduced in <a href="https://github.com/jmmastey/bundler-stats/pull/1">the Pull Request</a>.</p>

<h2 id="update-march-15th-2018">Update (March 15th, 2018)</h2>
<p>Since this post was published yesterday, Joe Mastey kindly worked with
me to merge the pull request and he released <a href="https://rubygems.org/gems/bundler-stats/versions/1.1.0">version 1.1.0</a> of
bundler-stats that now includes the <code class="language-plaintext highlighter-rouge">bundle-stats versions</code> command so
all you have to do is <code class="language-plaintext highlighter-rouge">gem install bundler-stats</code> and you can start
using it on your Gemfiles. He even added a <a href="https://github.com/jmmastey/bundler-stats/blob/master/CHANGELOG.md#added">lovely changelog</a> to the
project.</p>

<p>Additionally, André Arko from Bundler <a href="https://twitter.com/indirect/status/974343146430595072">reached out on Twitter</a> to let
me know that he’d accept a pull request to add this behavior to Bundler’s
<code class="language-plaintext highlighter-rouge">bundle show &lt;gemname&gt;</code> command which currently prints the installation
directory for a given gem. I think I’ll try to find some time before the
end of the week to get started on that pull request although it’ll
probably be a bit more tricky than to do this cleanly inside Bundler.</p>

<p>If you want to help, feel free to reach out on Twitter or to open a
pull request on Bundler yourself and let me know.</p>

<img src="https://feed.olivierlacan.com/link/8226/8558667.gif" height="1" width="1"/>]]></description>
      <pubDate>Wed, 14 Mar 2018 18:20:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8558667/why-wont-bundle-update</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/why-wont-bundle-update/</guid>
    </item>
    <item>
      <title>Migrating Homebrew Postgres to a New Version</title>
      <description><![CDATA[<p>This post was originally published as a <a href="https://gist.github.com/olivierlacan/e1bf5c34bc9f82e06bc0">Gist</a> which I since forgot
about and accidentally rediscovered recently when the need arose to
resolve a similar accidental upgrade. I felt like it deserved to
live somewhere where there is a chance I might update it.</p>

<h2 id="update">Update</h2>

<p>In Homebrew 1.5 and above, there’s a new process to upgrade your
Postgres database across major versions using the <code class="language-plaintext highlighter-rouge">brew postgresql-upgrade-database</code>
command which was <a href="https://github.com/Homebrew/homebrew-core/pull/21244">recently added by Mike McQuaid</a>.</p>

<p>This is a fantastic one-step improvement over the lengthy guide you’ll
see below, but since this new command isn’t foolproof (it will fail if
you haven’t killed all processes connected to your database) it seems
like a good idea to still understand the way it works behind the scenes.</p>

<p>I’ve learned a cool new trick from Homebrew’s upgrade command however and you
can find it in the last section of this updated post.</p>

<h2 id="accidental-homebrew-upgrades">Accidental Homebrew Upgrades</h2>

<p>This guide assumes that you recently ran <code class="language-plaintext highlighter-rouge">brew upgrade postgresql</code> and
discovered to your dismay that you accidentally bumped from one major
version to another: say 9.3.x to 9.4.x. Yes, that is a major version
bump in PG land.</p>

<p>Some of the common signs of this issue are the following statements in
your logs:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre>FATAL:  database files are incompatible with server
DETAIL:  The data directory was initialized by PostgreSQL version 9.5, which is not compatible with this version 9.6.
</pre></td></tr></tbody></table></code></pre></div></div>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre>PG::InternalError: ERROR:  incompatible library <span class="s2">"/usr/local/lib/postgresql/dict_snowball.so"</span>: version mismatch
DETAIL:  Server is version 9.5, library is version 9.6.
</pre></td></tr></tbody></table></code></pre></div></div>

<p>No need to panic. Your data should be fine. While you’ve upgraded the Postgres
library, your existing databases have not been removed. They simply need to be
upgraded to run with the new library.</p>

<h3 id="important-caveat-for-non-incremental-upgrades">Important Caveat for Non-Incremental Upgrades</h3>

<p>The process I describe below will work for incremental
version updates: for example 9.5 to 9.6. But it will probably not work
if you jump versions: for example 9.5 to 10.0.</p>

<p>In order to upgrade properly you will first need to downgrade the
Postgres version in Homebrew to the version directly after the one of
your data directory.</p>

<p>How do you figure out what version your data directory uses? Ask it.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="nb">cat</span> /usr/local/var/postgres/PG_VERSION
9.5
</pre></td></tr></tbody></table></code></pre></div></div>

<p>There we go. And what is your currently activated Postgres version in
Homebrew?</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="nv">$ </span>psql <span class="nt">--version</span>
psql <span class="o">(</span>PostgreSQL<span class="o">)</span> 9.6.6
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Good. If you find yourself one step further than you should be, say
on <code class="language-plaintext highlighter-rouge">10.0</code> like I was. You can do the following to step back down to
<code class="language-plaintext highlighter-rouge">9.6</code>:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre>brew uninstall postgresql
brew <span class="nb">install </span>postgresql@9.6
brew services start postgresql@9.6
brew <span class="nb">link </span>postgresql@9.6 <span class="nt">--force</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Couldn’t you use this to go back to Postgres 9.5? Yes, you could. But
it’s never a bad idea to stay up to date with newer versions, so why
not use the opportunity to be less worried about upgrades?</p>

<p>Now, check the active version of Postgres with:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="nv">$ </span>psql <span class="nt">--version</span>
psql <span class="o">(</span>PostgreSQL<span class="o">)</span> 9.6.6
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="checking-versions">Checking Versions</h2>

<p>You can check all the versions of postgres that are installed in
Homebrew with:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="nv">$ </span>brew list <span class="nt">--versions</span> | <span class="nb">grep </span>postgres
postgresql 9.4.5_2 9.5.0 9.5.4_1 9.5.3
postgresql@9.6 9.6.6
</pre></td></tr></tbody></table></code></pre></div></div>

<p>In this case you can see that I don’t have Postgres 9.6 installed in the
usual postgres formula, since I had to specifically install that version
in order to be able to upgrade from 9.5 with
<code class="language-plaintext highlighter-rouge">brew install postgresql@9.6</code>.</p>

<p>So there are 5 different versions of PostgreSQL installed on my machine
in different subfolders. We can find out where those are with:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
</pre></td><td class="rouge-code"><pre><span class="nv">$ </span>brew info postgresql
postgresql: stable 10.1 <span class="o">(</span>bottled<span class="o">)</span>, HEAD
Object-relational database system
https://www.postgresql.org/
Conflicts with:
  postgres-xc <span class="o">(</span>because postgresql and postgres-xc <span class="nb">install </span>the same binaries.<span class="o">)</span>
/usr/local/Cellar/postgresql/9.4.5_2 <span class="o">(</span>3,030 files, 33.6MB<span class="o">)</span>
  Poured from bottle on 2015-11-09 at 05:23:00
/usr/local/Cellar/postgresql/9.5.0 <span class="o">(</span>3,122 files, 34.9MB<span class="o">)</span>
  Poured from bottle on 2016-02-11 at 22:16:06
/usr/local/Cellar/postgresql/9.5.3 <span class="o">(</span>3,142 files, 35.0MB<span class="o">)</span>
  Poured from bottle on 2016-06-16 at 16:19:04
/usr/local/Cellar/postgresql/9.5.4_1 <span class="o">(</span>3,147 files, 35MB<span class="o">)</span>
  Poured from bottle on 2016-10-08 at 02:50:55
...
</pre></td></tr></tbody></table></code></pre></div></div>

<p>As you can see I have my old versions installed in
<code class="language-plaintext highlighter-rouge">/usr/local/Cellar/postgresql/</code>. And what about this new <code class="language-plaintext highlighter-rouge">postgres@9.6</code>?</p>

<p>That one’s in a standalone directory:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="nv">$ </span>brew info postgresql@9.6
postgresql@9.6: stable 9.6.6 <span class="o">(</span>bottled<span class="o">)</span> <span class="o">[</span>keg-only]
Object-relational database system
https://www.postgresql.org/
/usr/local/Cellar/postgresql@9.6/9.6.6 <span class="o">(</span>3,273 files, 36.8MB<span class="o">)</span> <span class="k">*</span>
  Poured from bottle on 2018-02-07 at 09:24:03
...
</pre></td></tr></tbody></table></code></pre></div></div>

<p>One final check to make sure we have the correct versions of the
Postgres commands running:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre>psql <span class="nt">--version</span>
psql <span class="o">(</span>PostgreSQL<span class="o">)</span> 9.6.6
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This means that the <code class="language-plaintext highlighter-rouge">pg_upgrade</code> binary we’ll be using is also the new
one. But let’s not assume:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre>pg_upgrade <span class="nt">--version</span>
pg_upgrade <span class="o">(</span>PostgreSQL<span class="o">)</span> 9.6.6
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Good good.</p>

<h2 id="mise-en-place">Mise en place</h2>

<p>The directory where your actual database data is stored is different
from the one where your PostgreSQL binaries are installed. Homebrew
installs the data directory in <code class="language-plaintext highlighter-rouge">/usr/local/var/postgres/</code> and doesn’t
touch that data folder when you upgrade from one version to the next.
This is a good thing because if Homebrew tried to install a brand new
database (with <code class="language-plaintext highlighter-rouge">initdb</code>) it could squash all your existing data.</p>

<p>First I recommend moving your existing data to a directory with a
different name:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nb">mv</span> /usr/local/var/postgres/ /usr/local/var/postgres.9.5.backup/
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now that the old data directory has been “moved”, you can safely create
a brand new clean database:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
</pre></td><td class="rouge-code"><pre>initdb /usr/local/var/postgres/
The files belonging to this database system will be owned by user "olivierlacan".
This user must also own the server process.

The database cluster will be initialized with locale "en_US.UTF-8".
The default database encoding has accordingly been set to "UTF8".
The default text search configuration will be set to "english".

Data page checksums are disabled.

creating directory /usr/local/var/postgres ... ok
creating subdirectories ... ok
selecting default max_connections ... 100
selecting default shared_buffers ... 128MB
selecting dynamic shared memory implementation ... posix
creating configuration files ... ok
creating template1 database in /usr/local/var/postgres/base/1 ... ok
initializing pg_authid ... ok
initializing dependencies ... ok
creating system views ... ok
loading system objects' descriptions ... ok
creating collations ... ok
creating conversions ... ok
creating dictionaries ... ok
setting privileges on built-in objects ... ok
creating information schema ... ok
loading PL/pgSQL server-side language ... ok
vacuuming database template1 ... ok
copying template1 to template0 ... ok
copying template1 to postgres ... ok
syncing data to disk ... ok

WARNING: enabling "trust" authentication for local connections
You can change this by editing pg_hba.conf or using the option -A, or
--auth-local and --auth-host, the next time you run initdb.

Success. You can now start the database server using:

    postgres -D /usr/local/var/postgres
or
    pg_ctl -D /usr/local/var/postgres -l logfile start
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Your output will be slightly different. For one, the user won’t be
<code class="language-plaintext highlighter-rouge">olivierlacan</code> but whatever your system user is. You can find that out
easily with <code class="language-plaintext highlighter-rouge">whoami</code>.</p>

<p>Interesting to note, but if you use PostgreSQL with Rails. This means
there will be no password on your development database, so you can skip
the <code class="language-plaintext highlighter-rouge">password</code> field in <code class="language-plaintext highlighter-rouge">database.yml</code> or leave it <em>*completely</em> empty.</p>

<h3 id="shutting-things-down">Shutting Things Down</h3>

<p>First we have to make sure both database servers are not running when we
do the upgrade:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre>pg_ctl <span class="nt">-D</span> /usr/local/var/postgres stop <span class="nt">-m</span> fast
pg_ctl <span class="nt">-D</span> /usr/local/var/postgres.9.5.backup stop <span class="nt">-m</span> fast
</pre></td></tr></tbody></table></code></pre></div></div>

<p>If you get the following message it’s possible that you have PG in
launchctl which may prevent you from stopping the server:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>pg_ctl: server does not shut down
</pre></td></tr></tbody></table></code></pre></div></div>

<p>In that case let’s remove PG from launchctl for now, you can add it back
later by following the instructions given on <code class="language-plaintext highlighter-rouge">brew info postgres</code>:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre>launchctl unload <span class="nt">-w</span> ~/Library/LaunchAgents/homebrew.mxcl.postgresql.plist
<span class="nb">rm</span> ~/Library/LaunchAgents/homebrew.mxcl.postgresql.plist
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Then try stopping the server again:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>pg_ctl <span class="nt">-D</span> /usr/local/var/postgres stop <span class="nt">-m</span> fast
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This would be good news:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre>pg_ctl: PID file <span class="s2">"/usr/local/var/postgres/postmaster.pid"</span> does not exist
Is server running?
</pre></td></tr></tbody></table></code></pre></div></div>

<p>If you’re using a recent version of Homebrew (as you should), then it’s
likely you’re using Homebrew Services instead of launchctl to manage
persistent processes like postgres. So use this instead:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>brew services stop postgresql
</pre></td></tr></tbody></table></code></pre></div></div>

<p>While Homebrew Services should do the job of stopping postgres, it’s not
guaranteed that you don’t have a server process connected to postgres
and locking it’s <code class="language-plaintext highlighter-rouge">pid</code> (process ID) file. It’s always a good idea to
check for that file which may exist at
<code class="language-plaintext highlighter-rouge">/usr/local/var/postgres/postmaster.pid</code>. If it does, remove it with
<code class="language-plaintext highlighter-rouge">rm /usr/local/var/postgres/postmaster.pid</code> and you’ll save yourself
some surprises later on.</p>

<h2 id="upgrading">Upgrading</h2>

<p>I’ve based this article on the fairly detailed <a href="https://www.postgresql.org/docs/10/static/pgupgrade.html">pg_upgrade guide in the
PostgreSQL documentation</a>. If you have specific needs (very large
data directory for example), you should consult it too. This section
is also not specific to a macOS Homebrew install of Postgres since it
uses the same commands you should be able to use on other operating
systems like Linux.</p>

<p>Assuming you’re dealing with the same version numbers I’m dealing with
(you probably aren’t, so change them when running this on your machine),
this is what the <code class="language-plaintext highlighter-rouge">pg_upgrade</code> command should look like when you run it:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="nv">$ </span>pg_upgrade <span class="nt">-b</span> /usr/local/Cellar/postgresql/9.5.4_1/bin/ <span class="se">\</span>
             <span class="nt">-B</span> /usr/local/Cellar/postgresql@9.6/9.6.6/bin/ <span class="se">\</span>
             <span class="nt">-d</span> /usr/local/var/postgres.9.5.backup/ <span class="se">\</span>
             <span class="nt">-D</span> /usr/local/var/postgres
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Lowercase flags (<code class="language-plaintext highlighter-rouge">-b</code> and <code class="language-plaintext highlighter-rouge">-d</code>) are for old <code class="language-plaintext highlighter-rouge">binary</code> and <code class="language-plaintext highlighter-rouge">data</code>
directories respectively. Their uppercase counterparts are for their new
equivalents.</p>

<p>I really dislike short form flags because they make self-descriptive discovery
very difficult so here is the alternative with long-form flags:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="nv">$ </span>pg_upgrade <span class="nt">--old-bindir</span> /usr/local/Cellar/postgresql/9.5.4_1/bin/ <span class="se">\</span>
             <span class="nt">--new-bindir</span> /usr/local/Cellar/postgresql@9.6/9.6.6/bin/ <span class="se">\</span>
             <span class="nt">--old-datadir</span> /usr/local/var/postgres.9.5.backup/ <span class="se">\</span>
             <span class="nt">--new-datadir</span> /usr/local/var/postgres <span class="se">\</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>How nice is this?</p>

<p>You should see the following output immediately if the upgrade process
is starting:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
</pre></td><td class="rouge-code"><pre>Performing Consistency Checks
<span class="nt">-----------------------------</span>
Checking cluster versions                                   ok
Checking database user is a superuser                       ok
Checking <span class="k">for </span>prepared transactions                          ok
Checking <span class="k">for </span>reg<span class="k">*</span> system OID user data types                ok
Checking <span class="k">for </span>contrib/isn with bigint-passing mismatch       ok
Checking <span class="k">for </span>invalid <span class="s2">"line"</span> user columns                    ok
Creating dump of global objects                             ok
Creating dump of database schemas
                                                            ok
Checking <span class="k">for </span>presence of required libraries                 ok
Checking database user is a superuser                       ok
Checking <span class="k">for </span>prepared transactions                          ok

If pg_upgrade fails after this point, you must re-initdb the
new cluster before continuing.

Performing Upgrade
<span class="nt">------------------</span>
Analyzing all rows <span class="k">in </span>the new cluster                       ok
Freezing all rows on the new cluster                        ok
Deleting files from new pg_clog                             ok
Copying old pg_clog to new server                           ok
Setting next transaction ID and epoch <span class="k">for </span>new cluster       ok
Deleting files from new pg_multixact/offsets                ok
Copying old pg_multixact/offsets to new server              ok
Deleting files from new pg_multixact/members                ok
Copying old pg_multixact/members to new server              ok
Setting next multixact ID and offset <span class="k">for </span>new cluster        ok
Resetting WAL archives                                      ok
Setting frozenxid and minmxid counters <span class="k">in </span>new cluster       ok
Restoring global objects <span class="k">in </span>the new cluster                 ok
Adding support functions to new cluster                     ok
Restoring database schemas <span class="k">in </span>the new cluster
                                                            ok
Creating newly-required TOAST tables                        ok
Removing support functions from new cluster                 ok
Copying user relation files
                                                            ok
Setting next OID <span class="k">for </span>new cluster                            ok
Sync data directory to disk                                 ok
Creating script to analyze new cluster                      ok
Creating script to delete old cluster                       ok

Upgrade Complete
<span class="nt">----------------</span>
Optimizer statistics are not transferred by pg_upgrade so,
once you start the new server, consider running:
    analyze_new_cluster.sh

Running this script will delete the old cluster<span class="s1">'s data files:
    delete_old_cluster.sh
</span></pre></td></tr></tbody></table></code></pre></div></div>

<p>You’re done!</p>

<h2 id="restarting">Restarting</h2>

<p>You manually shut down PG during this upgrade so now it won’t be running
unless you follow the (old) <code class="language-plaintext highlighter-rouge">brew info postgres</code> instructions:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="nb">ln</span> <span class="nt">-sfv</span> /usr/local/opt/postgresql/<span class="k">*</span>.plist ~/Library/LaunchAgents
launchctl load <span class="nt">-w</span> ~/Library/LaunchAgents/homebrew.mxcl.postgresql.plist
</pre></td></tr></tbody></table></code></pre></div></div>

<p>With Homebrew Services, the operation is even simpler:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre>brew services start postgresql
<span class="o">==&gt;</span> Successfully started <span class="sb">`</span>postgresql<span class="sb">`</span> <span class="o">(</span>label: homebrew.mxcl.postgresql<span class="o">)</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Once PG is running you could run the optimization script recommended by
<code class="language-plaintext highlighter-rouge">pg_upgrade</code>. It was created in whichever directory you ran <code class="language-plaintext highlighter-rouge">pg_upgrade</code>
in, and you can run it with:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
</pre></td><td class="rouge-code"><pre>./analyze_new_cluster.sh
This script will generate minimal optimizer statistics rapidly
so your system is usable, and <span class="k">then </span>gather statistics twice more
with increasing accuracy.  When it is <span class="k">done</span>, your system will
have the default level of optimizer statistics.

If you have used ALTER TABLE to modify the statistics target <span class="k">for
</span>any tables, you might want to remove them and restore them after
running this script because they will delay fast statistics generation.

If you would like default statistics as quickly as possible, cancel
this script and run:
    <span class="s2">"/usr/local/Cellar/postgresql/9.5.4_1/bin/vacuumdb"</span> <span class="nt">--all</span> <span class="nt">--analyze-only</span>

<span class="o">(</span>...<span class="o">)</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="troubleshooting">Troubleshooting</h2>

<p>You may encounter the following error:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="k">*</span>failure<span class="k">*</span>
Consult the last few lines of <span class="s2">"pg_upgrade_server.log"</span> <span class="k">for
</span>the probable cause of the failure.

There seems to be a postmaster servicing the new cluster.
Please shutdown that postmaster and try again.
Failure, exiting
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This means you have at least one PG server running. So go back to the
beginning of this section and make real sure you shut down all your
servers.</p>

<p>You can also check this <code class="language-plaintext highlighter-rouge">pg_upgrade_server.log</code> file to be certain of
the issue. It should be located in
<code class="language-plaintext highlighter-rouge">/usr/local/var/log/pg_upgrade_server.log</code> but you can always use the
find command to locate it:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>find / <span class="nt">-name</span> pg_upgrade_server.log
</pre></td></tr></tbody></table></code></pre></div></div>

<p>When using <code class="language-plaintext highlighter-rouge">brew postgresql-upgrade-database</code>, this log should contain
the reason the upgrade process failed as well as the actual command
used, which will be very useful for you to restart the upgrade process
manually.</p>

<p>I’ve found that running <code class="language-plaintext highlighter-rouge">brew postgresql-upgrade-database</code> again after
an initial failed attempt usually results in an error message saying
that the data was already upgraded when it’s not actually true or at
least the process hasn’t fully completed.</p>

<p>You can see how this script works by <a href="https://github.com/Homebrew/homebrew-core/blob/ac2ba2b02772708fe648363e4ef9dad891d89ef6/cmd/brew-postgresql-upgrade-database.rb">checking its source code</a>. It
seems like it’s comparing the Homebrew-installed version to the
version of the currently active Postgres database inside of the <code class="language-plaintext highlighter-rouge">/var/postgres</code>
data directory. It references the <a href="https://www.postgresql.org/docs/10/static/pgupgrade.html">PostgreSQL documentation upgrade article</a>
as well. The only notable difference with the instructions I’ve listed above
is the use of the <code class="language-plaintext highlighter-rouge">-j</code> flag, which defines how many threads or processes the
<code class="language-plaintext highlighter-rouge">pg_upgrade</code> command will use. Homebrew sets that number to
<code class="language-plaintext highlighter-rouge">Hardware::CPU.cores.to_s</code> which would be 2, 4, 6 or more CPU cores your machine
may have to handle CPU-intensive tasks like these.</p>

<p>However I’d recommend not doing this since you may have operations already
using some CPU on your machine. My best tip is to use one less core than your
total, which I learned from this excellent <a href="https://thoughtbot.com/blog/parallel-gem-installing-using-bundler">Thoughbot blog post on parallel
RubyGem install configuration for Bundler</a>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre>number_of_cores=`sysctl -n hw.ncpu`
echo "$(expr $number_of_cores - 1)"
11
</pre></td></tr></tbody></table></code></pre></div></div>

<p>So here’s the final command in its full glory for all of you who skipped
straight to the bottom of this post:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="nv">$ </span>pg_upgrade <span class="nt">--old-bindir</span> /usr/local/Cellar/postgresql/9.5.4_1/bin/ <span class="se">\</span>
             <span class="nt">--new-bindir</span> /usr/local/Cellar/postgresql@9.6/9.6.6/bin/ <span class="se">\</span>
             <span class="nt">--old-datadir</span> /usr/local/var/postgres.9.5.backup/ <span class="se">\</span>
             <span class="nt">--new-datadir</span> /usr/local/var/postgres <span class="se">\</span>
             <span class="nt">--jobs</span> <span class="si">$(</span><span class="nb">expr</span> <span class="si">$(</span>sysctl <span class="nt">-n</span> hw.ncpu<span class="si">)</span> - 1<span class="si">)</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Safe upgrades!</p>

<img src="https://feed.olivierlacan.com/link/8226/8521048.gif" height="1" width="1"/>]]></description>
      <pubDate>Wed, 07 Feb 2018 08:21:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521048/migrating-homebrew-postgres-to-a-new-version</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/migrating-homebrew-postgres-to-a-new-version/</guid>
    </item>
    <item>
      <title>Keep a Changelog 1.0</title>
      <description><![CDATA[<p><img src="https://olivierlacan.com/assets/keep-a-changelog-badge.svg" alt="Keep a Changelog Badge" /></p>

<p>After years of small improvements and two years since the last minor release,
Keep a Changelog finally reached <a href="http://keepachangelog.com/en/1.0.0/">version 1.0 today</a>.</p>

<p>What’s new? Well, <a href="https://github.com/olivierlacan/keep-a-changelog/blob/master/CHANGELOG.md#100---2017-06-20">read the changelog!</a></p>

<p>In short we have 6 new language translations, simplified version-aware language
navigation, much clearer and succinct sections that describe the <a href="http://keepachangelog.com/en/1.0.0/#what">What</a>,
<a href="http://keepachangelog.com/en/1.0.0/#why">Why</a>, and <a href="http://keepachangelog.com/en/1.0.0/#who">Who</a> of changelogs, and a lot of refinements.</p>

<p>For people who like clear guidelines, there are now
<a href="http://keepachangelog.com/en/1.0.0/#how">guiding principles</a> that summarize the key components of good
changelogs. There’s also a section about changelog <a href="http://keepachangelog.com/en/1.0.0/#bad-practices">bad practices</a>
to help your friendly maintainers understand that a git log dump doesn’t
helping anyone.</p>

<p>Finally, we now document changelog maintenance details and edge cases in a neat
little FAQ section to avoid confusing everybody with specifics upfront.</p>

<p>I’d like to thank the incredibly talented Tyler Fortune for his work
on the new visual identity of the project. And of course, I’m incredibly
grateful to the many contributors who helped translate this project in 14
different languages.</p>

<p>You can see Tyler’s incredible branding work <a href="https://www.tylerfortune.me/keep-a-changelog/">on his website</a>.
His work allowed me to create the kind of strong and clear project
website I didn’t have the courage to build back in May 2014 when this
project originally started.</p>

<p>PS: I’m <a href="https://github.com/olivierlacan/keep-a-changelog/issues/164">looking for help</a> porting the following languages to this new
version: Czech, German, Spanish, Italian, Polish, Brazilian Portugese, Russian,
Slovenian, Swedish, Turkish, Simplified &amp; Traditional Chinese, and any other
language you’d like to <a href="https://github.com/olivierlacan/keep-a-changelog#translations">contribute</a>.</p>

<img src="https://feed.olivierlacan.com/link/8226/8521049.gif" height="1" width="1"/>]]></description>
      <pubDate>Tue, 20 Jun 2017 09:47:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521049/keep-a-changelog-1-0</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/keep-a-changelog-1-0/</guid>
    </item>
    <item>
      <title>Ruby Heroes Farewell</title>
      <description><![CDATA[<p>I’m sad to announce that there won’t be a <a href="https://rubyheroes.com">Ruby Heroes</a> ceremony at
RailsConf 2017 and going forward.</p>

<p><img src="https://olivierlacan.com/assets/ruby-heroes-logo.svg" alt="Ruby Facets Banner with a chunky red heart full of chunky bacon" /></p>

<p>The responsibility of organizing the voting, judging, travel accomodations, and
ceremony has rested largely on my shoulders (with much needed assistance from
Ruby Central and Code School) for the past two years after I was handed the
reins of the event. I’ve also been maintaining the Rails <a href="https://github.com/rubyheroes/rubyheroes.com">codebase</a> for many
years now.</p>

<p>I’m at a point in my life where I can’t spare the time to dedicate to this
project every year, but I’d be lying if I said this was my sole reason for
pulling the plug.</p>

<p>It’s possible that someone in the community will want to keep Ruby Heroes going
on in some form as several copycat events (which have no association to Ruby
Heroes) have been sprouting at diverse Ruby conferences around the world
in recent years. I’ve considered that myself.</p>

<p>But truthfully, I don’t think an award ceremony — however friendly and informal
— is an appropriate solution to try and foster a culture of appreciation in the
Ruby community anymore.</p>

<p>I worry that despite the initial focus of Ruby Heroes having been to shine a
light on underappreciated members of the community, it has invariably become a
place to annoint respected members of the community who — despite being
quite worthy of accolades — don’t really need them. I say this knowing full well
that some well-known recipients have been deeply touched by receiving a Ruby
Hero Award in the past.</p>

<p>Then there’s the contentious issue of praise and rewards. Even a cursory reading
of Alfie Kohn’s seminal book <a href="http://www.alfiekohn.org/punished-rewards/">Punished by Rewards</a> can shake the conviction
that good intentions excuse all unintended side-effects of handing people
awards. To summarize Kohn’s argument, it’s very likely that rewards motivate
people for the wrong reasons, demotivate those who didn’t need awards to be
motivated in the first place, and generally tend to turn something enjoyable
into a chore because only chores must prompt compensation with a reward.</p>

<p>While I believe that Ruby Heroes has benefited some of its recipients personally
and professionally over the years, I can’t shake the feeling that it’s also had
a much less visible negative impact on their and other people’s long term
motivation in the long run. I could be wrong.</p>

<p>Although they have a different focus, initiatives like <a href="http://saythanks.io/">Ruby Friends</a> and
<a href="http://saythanks.io/">SayThanks.io</a> are giving Rubyists a way to appreciate each other and the
community members they look up to. I welcome all initiatives from the open
source and Ruby communities to spread thankfulness, appreciation, and gratitude.</p>

<p>One of the best perks of the job has been to read the amazingly kind comments
people sent throughout the years about their Ruby Heroes nominees. I don’t know
if these kind words are best kept private or public. But I know how something so
simple as a grateful tweet or email can have a similar deep lasting impact on
the recipients.</p>

<p>There are many ways to appreciate the people who inspire you and make your
community better. You can thank them, hug them or you can help them by
supporting the efforts they hold dear. <a href="https://rubygems.org">RubyGems.org</a> recently made it
possible to find reverse dependencies for gems. Think about the human
dependency graph of our community. Who depends on whom and vice versa?</p>

<p><a href="https://libraries.io/">Libraries.io</a> offers a fantastic tool called “Improve the Bus Factor” which
lists the most highly dependended upon libraries with the fewest maintainers and
contributors. If that’s not a call to action, I don’t know what is.</p>

<p>PS: Thanks to everyone who has supported the mission of Ruby Heroes throughout
the years in spite of its failings. I’ve never been more proud of the Ruby
community now that it’s out of the brightest limelight, and I can’t wait to see
all the amazing people and projects that will make it up in the years to come.</p>

<img src="https://feed.olivierlacan.com/link/8226/8521050.gif" height="1" width="1"/>]]></description>
      <pubDate>Wed, 15 Mar 2017 17:34:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521050/ruby-heroes-farewell</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/ruby-heroes-farewell/</guid>
    </item>
    <item>
      <title>Concurrency in Ruby 3 with Guilds</title>
      <description><![CDATA[<p><strong>Note</strong>: Since this post was written four years ago, Guilds were renamed
<em>Ractors</em> and were released as an <a href="https://www.ruby-lang.org/en/news/2020/09/25/ruby-3-0-0-preview1-released/">experimental feature in Ruby 3.0</a>.
The feature now includes great documentation and copious usage examples in the
<a href="https://docs.ruby-lang.org/en/master/doc/ractor_md.html">Ruby API documentation</a>.</p>

<p>At <a href="http://rubykaigi.org/2016">Ruby Kaigi</a> 2016, <a href="http://www.atdot.net/~ko1/">Koichi Sasada</a> — designer of the current
<a href="https://en.wikipedia.org/wiki/YARV">Ruby virtual machine</a> and garbage collector — presented<sup id="fnref:1" role="doc-noteref"><a href="https://olivierlacan.com#fn:1" class="footnote" rel="footnote">1</a></sup> his
proposal for a new concurrency model in Ruby 3.</p>

<p>While Ruby has a thread system to allow for concurrency, <a href="https://en.wikipedia.org/wiki/Ruby_MRI">MRI</a> doesn’t
allow parallel execution of Ruby code. Koichi looked at the various challenges
of running Ruby in parallel including object mutation, race conditions, and
synchronization across Threads. The result was a <a href="http://www.atdot.net/~ko1/activities/2016_rubykaigi.pdf">proposal</a> for a new
concurrent <em>and</em> parallel mechanism called Guilds.</p>

<h2 id="concurrency-goals">Concurrency Goals</h2>

<p>If like me you’re not a computer science graduate, or if concurrency just tends
to hurt your brain, you can read this clear explanation of the <a href="http://bytearcher.com/articles/parallel-vs-concurrent/">differences
between concurrency and parallelism</a>.</p>

<p>The stated goals for Guilds in Ruby 3 are to retain compatibility with Ruby 2,
allow for parallelism, reconsider global locks that prevent parallel execution,
try to allow fast object sharing, and provide special objects to share
mutable objects.</p>

<p>Concurrency in Ruby today is difficult because programmers have to manually
ensure that Threads don’t create <a href="https://en.wikipedia.org/wiki/Race_condition">race conditions</a>. Common ways
around this issue involve introducing locks, like Ruby’s
<a href="https://ruby-doc.org/core-2.3.1/Thread/Mutex.html"><code class="language-plaintext highlighter-rouge">Thread::Mutex</code></a>, which somewhat defeat the initial purpose of
parallelism. Locks tend to slow down programs, and improperly placed locks can
even make concurrent programs run slower than synchronous equivalents.</p>

<h2 id="how-guilds-work">How Guilds Work</h2>

<p><em>Note: With Koichi’s permission, I’ve reproduced some illustrations from his
<a href="http://www.atdot.net/~ko1/activities/2016_rubykaigi.pdf">proposal</a> since they’re helpful for understanding the concepts.</em></p>

<p>Guilds are implemented in terms of the existing <a href="https://ruby-doc.org/core-2.3.1/Thread.html"><code class="language-plaintext highlighter-rouge">Thread</code></a> and
<a href="https://ruby-doc.org/core-2.3.1/Fiber.html"><code class="language-plaintext highlighter-rouge">Fiber</code></a> classes. While Threads allow for concurrent execution of code
scheduled by the operating system scheduler on your behalf, Fibers allow for
cooperative concurrency with execution scheduling that can be manually
controlled.</p>

<p>Guilds are composed of at least one Thread which in turn has at least one Fiber.
Threads from different Guilds can run in parallel while Threads in the same
Guild can’t. Objects from one Guild cannot read or write to objects from another
Guild.</p>

<p><img src="https://olivierlacan.com/assets/ruby_3_guilds_threads_and_fibers.png" alt="Illustration of Guilds containing at least one Thread which contain at least
one Fiber" /></p>

<p>Threads that belong to the same Guild can’t execute in parallel since there’s
a GGL (Giant Guild Lock) ensuring that each thread within a Guild executes one
after another. However, Threads from different Guilds can execute in parallel.</p>

<p>You can think of a Ruby 2.x program as having a single Guild.</p>

<figure>
  <img src="https://olivierlacan.com/assets/ruby_3_guilds_concurrency.png" alt="Illustration of thread concurrency within Guilds and between Guilds" />
  <figcaption>
    Threads T1 &amp; T2 belong to Guild G1 and can't run in parallel, but T3 belongs
    to G2, and it can run while Threads from G1 are executing.
  </figcaption>
</figure>

<h2 id="communication-between-guilds">Communication Between Guilds</h2>

<p>An object from one Guild will not be able to read or write to a mutable object
from a different Guild. Preventing mutation allows Guilds to operate concurrently
without running the risk of both accessing and modifying the same objects.</p>

<figure>
  <img src="https://olivierlacan.com/assets/ruby_3_guilds_object_access_restrictions.png" alt="Illustration of Guilds being unable to read or write each other's objects" />
  <figcaption>
    Objects from one Guild can't access objects from a different Guild.
  </figcaption>
</figure>

<p>However, Guilds can communicate with each other using the <code class="language-plaintext highlighter-rouge">Guild::Channel</code>
interface which allows for the copying or moving of objects across the channel
to another Guild.</p>

<p>The <code class="language-plaintext highlighter-rouge">Guild::Channel</code>’s <code class="language-plaintext highlighter-rouge">transfer(object)</code> method sends a deep copy of the <code class="language-plaintext highlighter-rouge">object</code> to
a destination Guild.</p>

<p><img src="https://olivierlacan.com/assets/ruby_3_guilds_channels_object_copy.png" alt="Illustration of Guild Channels copying objects from one channel to another" /></p>

<p>It’s also possible to completely move an object from one Guild to another using
<code class="language-plaintext highlighter-rouge">Guild::Channel</code>’s <code class="language-plaintext highlighter-rouge">transfer_membership(object)</code>.</p>

<p><img src="https://olivierlacan.com/assets/ruby_3_guilds_channels_object_move.png" alt="Illustration of Guild Channels moving objects from one channel to another" /></p>

<p>Once an object’s membership has been transferred to a new Guild, it is no longer
accessible from its original Guild, and any attempt to access the object will
raise an error.</p>

<p>While Guilds can’t share mutable objects without previously copying or
transferring to one another, it’s important to note that <strong>immutable objects can
be shared (read) across Guilds</strong> as long as they’re “deeply frozen”, meaning
every object they reference is also immutable.</p>

<p>Here’s an example to distinguish mutable from immutable objects:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="c1"># While Numeric types like Integers are immutable by</span>
<span class="c1"># default, Hash instances aren't.</span>
<span class="n">mutable</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="p">{</span> <span class="s2">"key"</span> <span class="o">=&gt;</span> <span class="s2">"value"</span> <span class="p">},</span> <span class="mi">3</span><span class="p">].</span><span class="nf">freeze</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="c1"># But if you freeze String or Hash instances and the</span>
<span class="c1"># Array instances that reference them, then you have</span>
<span class="c1"># a "deeply frozen" immutable object.</span>
<span class="n">immutable</span> <span class="o">=</span> <span class="p">[</span>
  <span class="s2">"bar"</span><span class="p">.</span><span class="nf">freeze</span><span class="p">,</span>
  <span class="p">{</span> <span class="s2">"key"</span> <span class="o">=&gt;</span> <span class="s2">"value"</span><span class="p">.</span><span class="nf">freeze</span> <span class="p">}.</span><span class="nf">freeze</span>
<span class="p">].</span><span class="nf">freeze</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="usage-example">Usage Example</h2>

<p>During his talk, Koichi Sasada gave a few succinct examples of how Guilds could
work. I’d like to reproduce the simplest one that applies Guilds to computing
Fibonacci in parallel. The example below has been modified slightly for clarity.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
</pre></td><td class="rouge-code"><pre><span class="k">def</span> <span class="nf">fibonacci</span><span class="p">(</span><span class="n">n</span><span class="p">)</span>
  <span class="k">return</span> <span class="n">n</span> <span class="k">if</span> <span class="n">n</span> <span class="o">&lt;=</span> <span class="mi">1</span>
  <span class="n">fibonacci</span><span class="p">(</span> <span class="n">n</span> <span class="o">-</span> <span class="mi">1</span> <span class="p">)</span> <span class="o">+</span> <span class="n">fibonacci</span><span class="p">(</span> <span class="n">n</span> <span class="o">-</span> <span class="mi">2</span> <span class="p">)</span>
<span class="k">end</span>

<span class="n">guild_fibonacci</span> <span class="o">=</span> <span class="no">Guild</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="ss">script: </span><span class="sx">%q{
  channel = Guild.default_channel

  while(n, return_channel = channel.receive)
    return_channel.transfer( fibonacci(n) )
  end
}</span><span class="p">)</span>

<span class="n">channel</span> <span class="o">=</span> <span class="no">Guild</span><span class="o">::</span><span class="no">Channel</span><span class="p">.</span><span class="nf">new</span> <span class="p">\</span>
  <span class="n">guild_fibonacci</span><span class="p">.</span><span class="nf">transfer</span><span class="p">([</span><span class="mi">3</span><span class="p">,</span> <span class="n">channel</span><span class="p">])</span>

<span class="nb">puts</span> <span class="n">channel</span><span class="p">.</span><span class="nf">receive</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="advantages-of-guilds-over-threads">Advantages of Guilds over Threads</h2>

<p>With Threads, it’s difficult to figure out which objects are shared mutable
objects. Guilds prevent their use altogether and instead makes sharing
<em>immutable</em> objects much easier. Koichi has planned for “special data
structures” to share mutable objects with Guilds. These structures would
automatically isolate risky mutable code.</p>

<p>There is, however, a trade-off, since communication between Guilds is much more
tedious than between Threads.</p>

<h2 id="performance">Performance</h2>

<p>It’s my understanding that the current C implementation of Guilds is roughly 400
lines of code. While the source isn’t yet available, Koichi hinted at the
performance benefits of Guilds by comparing a single-guild execution of the
fibonacci example with a multi-guild one.</p>

<p>On a <strong>dual core</strong> Linux virtual machine running within Windows 7, Koichi
observed the following results:</p>

<p><img src="https://olivierlacan.com/assets/ruby_3_guilds_fibonacci_performance.png" alt="Illustration of single vs. multi-guild performance at fibonacci function solving" /></p>

<p>It may not be representative of real-world improvement in most Ruby
applications, but I can’t wait to see the impact of Guilds on
<a href="https://rubybench.org/">RubyBench</a>.</p>

<h2 id="conclusions">Conclusions</h2>

<p>The Guild concept is an exciting way to introduce easier mutation-safe
concurrency workflows to Ruby. I can’t wait for Koichi Sasada and the Ruby core
team to share more about this proposal in the future.</p>

<p>I do have minor concerns about the naming of the object copy and move methods
for <code class="language-plaintext highlighter-rouge">Guild::Channel</code>. <code class="language-plaintext highlighter-rouge">transfer(object)</code> seems to imply an exchange, but it
merely results in a deep copy of the object. I believe <code class="language-plaintext highlighter-rouge">transfer_copy(object)</code>
or simply <code class="language-plaintext highlighter-rouge">copy(object)</code> would be less confusing. And
<code class="language-plaintext highlighter-rouge">transfer_membership(object)</code>, the move/transfer method, could simply be named
<code class="language-plaintext highlighter-rouge">channel.transfer(object)</code>. Thankfully, it seems that the method names
aren’t set in stone.</p>

<p>I’d encourage the Ruby core team to release this new feature under an opt-in
experimental flag so that the Ruby community can participate in testing.
Hopefully, this would allow us to have this feature available before 2020 — the
expected release date of Ruby 3.0. Guilds will have a positive impact on Ruby’s
reputation as a concurrent-friendly language. It would be welcome soon, warts
and all.</p>

<hr />

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1" role="doc-endnote">
      <p>A video of the talk is <a href="https://www.youtube.com/watch?v=WIrYh14H9kA&amp;feature=youtu.be">already available</a>. <a href="https://olivierlacan.com#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>
<img src="https://feed.olivierlacan.com/link/8226/8521051.gif" height="1" width="1"/>]]></description>
      <pubDate>Tue, 27 Sep 2016 13:21:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521051/concurrency-in-ruby-3-with-guilds</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/concurrency-in-ruby-3-with-guilds/</guid>
    </item>
    <item>
      <title>Ruby Facets</title>
      <description><![CDATA[<p><img src="https://olivierlacan.com/assets/ruby-facets-logo_1600.png" alt="Ruby Facets Banner with a chunky red heart full of chunky bacon" /></p>

<p>Although the circumstances are more rushed than I would have hoped, I’m starting
a weekly Ruby news podcast called <a href="http://rubyfacets.com/">Ruby Facets</a>. The <a href="http://rubyfacets.com/1">first episode is
already available</a> and <a href="https://www.patreon.com/rubyfacets">I’m using Patreon</a> to fund the ongoing
production of the show.</p>

<p>If you were a <a href="https://ruby5.codeschool.com">Ruby5</a> listener in the past, Ruby Facets may sound
familiar to you. There’s a reason for that. Ruby5 is no more. After 7 years,
645 episodes, 69 hosts, and lots of fun, Code School — who’s been producing and
funding the show for about 3 years — decided it was time to move on.</p>

<p>It’s not really a judgement of Ruby5 as a show, Code School simply stopped
producing all the five-minute podcasts based on Ruby5 — <a href="https://fivejs.codeschool.com/">FiveJS</a> and
<a href="https://iosbytes.codeschool.com/">iOS Bytes</a> too. I have very mixed feelings about this
decision but ultimately it’s up to us as community members to decide what we’d
like to contribute.</p>

<p>I think I still have something to contribute to the Ruby community in the form
a news podcast. Ruby Facets will not try to be exactly everything that Ruby5
was. For one I don’t intend on working with co-hosts for now, simply because
the logistics of producing the show need to be as simple as possible considering
I’m trying to fund the show without sponsors.</p>

<p>If there’s one thing I gathered from working with <a href="https://twitter.com/greggpollack">Gregg</a>,
<a href="https://twitter.com/nbibler">Nate</a>, <a href="https://twitter.com/caike">Carlos</a>, and many others on Ruby5 is that quality and
curation matter. Ruby5 ran <em>about</em> 5 minutes with approximately 5 news stories
which is a pretty dense information to airtime ratio compared to most podcasts.
The show valued the listener’s time and had a clear purpose: keeping people
up-to-date with community news.</p>

<p>I learned a lot from the sound quality we thrived for on Ruby5. There are sadly
still plenty of podcasters who don’t recognize that if copywriting and proper
grammar are not just a nice-to-have on a blog, then audio quality isn’t just a
nice-to-have either on a podcast. Both are a reflection of attention to details
and respect for your audience.</p>

<p>There’s another aspect I want to infuse Ruby Facets with as much as possible: a
sense of community. Although it will be difficult to achieve with a single host,
I’m going to try to synthesize the good and exciting things I see happening in
the Ruby community. That will require discipline on my part since the show will
be biased by my own point of view for now. Thankfully there’s all of you out
there with your own opinions and ideas and exciting projects that the whole
community should hear about.</p>

<p>If this vision for the show excites you too, <a href="https://www.patreon.com/rubyfacets">you can become a patron of Ruby
Facets on Patreon</a>. Monthly donations range from $1 to $5 and I’m
very interested to hear your thoughts about the show <a href="https://twitter.com/rubyfacets">on Twitter at @rubyfacets</a>. Instead of hoarding news until the show is released each week I plan
to tweet and retweet links to stories during the week as I gather them.</p>

<img src="https://feed.olivierlacan.com/link/8226/8521052.gif" height="1" width="1"/>]]></description>
      <pubDate>Wed, 21 Sep 2016 08:19:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521052/ruby-facets</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/ruby-facets/</guid>
    </item>
    <item>
      <title>Taking Care of Things</title>
      <description><![CDATA[<p>Since this past week I’ve been staying in a place that I’ve been coming
to for over 15 years. I come back every time around the same time of
year: the last month of summer.</p>

<p>Here there’s a forest behind us and hills before us. I always come here
driving too fast and because they don’t have enough people living here
to maintain the road well, I have to slow down.</p>

<p>It’s annoying at first to drive more slowly. You want to go from point A
to point B. But when you lower your pace, you start noticing these
cracks in the road. They tell the story of the trucks and cars and bikes
that slowly beat up the road. That road wasn’t just laying there. It was
holding on to this piece of land and that land is not having any of
that. The river nearby is pulling it over as it strolls by. The mountain
back there is pushing it away as it rolls down.</p>

<p>Things are moving, nothing is <em>really</em> standing still. It takes great
care to make it look like things aren’t going anywhere.</p>

<p>That takes me to my friend Claus. Claus was an auto salesman at a
Volkswagen dealership for years. He’s Canadian but from Germany and he’s
small but packs a punch. I don’t mean that he’s aggressive, no, just
that he’s intense. He’s got one of those furious brows that can turn
from anger to roaring laughter in a split second. He doesn’t like
solving problems, he likes to make them disappear.</p>

<p>Claus was a cook for years after retiring from selling cars. He made
French and German food, some of the best I’ve ever eaten. It was
delicious and simple and got the job done right. Just like he does. I
can still remember the taste and color of his roasted potatoes. The ones
he served with his famous Bavette. When I was younger I disliked how
many vegatables he mixed into the side, and how he loves to drop a ton
of lightly roasted scallions on top of the steak. Now I wish I could go
back in time and slap myself for not eating them.</p>

<p>First Claus and his wife Paulette had a restaurant on the side of the
highway outside of Ste-Agathe-des-Monts in the 90’s. I mean as far as I
know. Then in the naughties, they moved to a fancier location in
downtown Ste-Agathe. A super cute place in an old wooden house where
they had a wide <em>terrasse</em> and could sit a lot more people.</p>

<p>I have some of the best memories of my life in this place but that’s not
what I want to focus on. While he and Paulette had so much of this stuff
going on — the whole business of running a restaurant, hiring and firing
people, getting provisions for the restaurant, prepping, cleaning, all
that shit — he took care of things.</p>

<p>He took care of the old roof on the old house his parents left him. He
took care of the concrete pavement on the side of the pool that I
vaguely recall him telling me his dad blasted out of the rock with
dynamite — that one’s not going anywhere. He took care of the little
garden until the fucking forest deer starting eating all his nice
zuchinis, tomatoes, and cucumbers, at which point he said “fuck it” and
put up an electrical fence around the whole garden. It’s not pretty, but
it does the job.</p>

<p>Claus’ basement workshop is a place of wonders. If you care remotely
about tools, building stuff or even older houses, you’d fall in love
with that place in an instant. There’s even a meat smoker in there,
under the house, and the smoke runs out throught same pipe as the
chimney above. Or a different pipe, I don’t know for sure.</p>

<p>I mentioned that he’s not a tall man, and I guess his father wasn’t
either or I guess he made due because that basement is just tall enough
for him. There’s storage everywhere, tools everywhere. A few years ago
he even had the old oil tank (Canadian winters, are rough) that was
taking up so much space and cut it out of there since electric heating
makes a lot more sense these days. Now the place looks like a mini-
Batcave.</p>

<p>Beyond impressing on me the value of hard and thoughtful work, Claus and
people like him reminds me constantly that him and I are people who like
to take care of things. His car is old, but you wouldn’t know it. He
knows exactly how to make it last as long as it can possibly last. Rust
is a fact of life with winters that harsh, so every summer he sets out
time to sand off the rust, repaint the damaged bits, and finish it off
with some clear coat. I didn’t even know what clear coat was before he
showed me. Now I feel like an idiot for not properly maintaining my
car’s clear coat now that it’s starting to age. I could have done a much
better job making it last, if I had taken care of things.</p>

<p>I guess what I’m getting at is that it bothers me to see so many people
scoffing at how things cost when they don’t even understand that stuff
doesn’t last forever. The expensive stuff — at least the one that isn’t
a scam — lasts a whole lot longer than the cheap shit but that doesn’t
mean it’ll take care of itself. You can throw as much money at the world
as you want, it’s not going to freeze time. Metal will fade and rust.
Glass will crack and shatter. Even the strongest concrete will shatter
and slowly turn back into sand.</p>

<p>And that’s not sad thing. It’s a good thing. Nothing stagnates. Things
move under the road. You can’t just live your life prentending it’s
somebody else’s problem to tend to the cracks. At some point you’ll have
to start patching things up.</p>

<p>A beautiful thing I notice when looking at things people made is to see
if I can spot “deviations from the plan”. Everything is aligned and
straight in the beginning. Then you notice that water is pooling in that
one spot, so you have to pour some new concrete. When gasoline runs out
of style you end up having to pull electric cables from the house to the
shed where the pump for the pool is. You first start drilling that one
beam to pass the cable through it but you realize it’s too low, so you
make another hole. And you leave the first one, because the sun is
getting low and you have to finish before night.</p>

<p>Those pragmatic alterations are one of the most interesting things you
can look at as someone who makes things for a living, or just for fun.
How people handled evolving requirements. How the best laid plans always
need a little adjustement once reality sets in. Like those fucking deer
who couldn’t help but eat the goddamned zuchini.</p>
<img src="https://feed.olivierlacan.com/link/8226/8521053.gif" height="1" width="1"/>]]></description>
      <pubDate>Fri, 19 Aug 2016 00:08:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521053/taking-care-of-things</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/taking-care-of-things/</guid>
    </item>
    <item>
      <title>The Upgrade Trails</title>
      <description><![CDATA[<p>Recently I completed a Rails 4 upgrade for <a href="https://www.codeschool.com">codeschool.com</a> which I
originally started in the fall of 2014. Almost two years to upgrade from
Rails 3.2 to Rails 4.2.</p>

<p><img src="https://olivierlacan.com/assets/the-upgrade-trails.png" alt="You think it only took these four pull requests I'm showing in this screenshot to upgrade to Rails 3.2 back in 2014? Ha... haaa hahahahaha. Oh boy. If only." /></p>

<h2 id="rationalizations">Rationalizations</h2>

<p>What took us so long? Why didn’t we do it faster? Are we just really bad at
upgrading things? Do we not care about security? Is it because Rails can’t
scale? Or maybe Rails 4 is bad?</p>

<p>No. It was just hard. Because I did it wrong. Because I did it mostly alone.
Because I tried to do it too fast, and too slow, and everything in between.
Because when a startup like Code School is born people take a lot of shortcuts.
They (and I) wrote a lot of terrible code, used a lot of terrible dependencies,
hacked together a lot of terrible patches.</p>

<p>Eventually, if those terrible things don’t surface in bugs or build failures,
you end up paying the price for them on the upgrade trails. The circuitous,
slippery, and depressing paths that you can barely see when you’re riding
high on the shiny new Rails.</p>

<p>I didn’t spend most of those two years working on these upgrades, of course.
Deplore it if you will, framework upgrades are not always a business priority.
In my mind they should be because updating often means avoiding getting the
short end of the stick with bug fixes. <em>Most</em> important bug fixes are
backported to earlier minor versions of frameworks like Rails — <em>some</em> slip
through the cracks.</p>

<p>Over time, the body of knowledge surrounding the software your business depends
on the most grows stale. People drop support for the version you use in their
test builds. Gems stop trying to fix compatibility issues with it. Framework
contributors and maintainers accidentally break or deprecate features you came
to rely on. Features you’ll have to rewrite in order to upgrade.</p>

<p>On the scarier side, you don’t realize that you’re missing out on some new
security features that — while they wouldn’t require a security release that
would be backported to your older version — still leave you and your customers
a little less safe than the folks on the bleeding edge.</p>

<p>You hear about performance improvements in your <a href="https://en.wikipedia.org/wiki/Object-relational_mapping">ORM</a> and you eagerly start
building internal apps using the new version of the framework in order to
giddily confirm that yes — it’s much, much faster. You convince yourself that
this internal app side project written in Rails 4 and kept up-to-date with every
minor release since will better equip you to upgrade your shining 30,000 line of
code monolith — but it won’t. No “greenfield” app can ever allow you to judge
how a “reddungeon” app will behave on the upgrade trails.</p>

<p>Things will break deep down at what seems to be the interpreter level. That is,
until you notice that a ridiculously ancient version of the antediluvian
<a href="https://github.com/swanandp/acts_as_list">acts_as_list</a> gem is attempting to pass hilariously unsupported arguments
to a core ActiveRecord method.</p>

<p>You start developing a near-animal instinct about what really causes exceptions
when reading stacktraces and this instinct betrays you because you’re still
not reading the goddamned stacktraces.</p>

<p>Eventually you start reminiscing on the past two years and boil them down to
some recommendations that can hopefully prevent good people from spending as
much time as you did on those treacherous trails.</p>

<h3 id="hindsights">Hindsights</h3>

<h3 id="1--dont-rush">1 — Don’t Rush</h3>

<p>Don’t rush to update to a new version until at least a month (or two) after a
major or minor release because one tenth of your 238 transitive dependencies are
not compatible yet or their maintainers still don’t know how to losen dependency
constraints. Get a pull request and a build going for sure, but wait until that
first bugfix release comes out, and maybe a second one.</p>

<h3 id="2--dont-lag">2 — Don’t Lag</h3>

<p>Don’t wait to update until the following version is released. You will miss out
on all the blog posts, GitHub issues, and otherwise fresh conversations of
people with similar apps in similar situations and whose experiences you could
benefit from. I get that it’s easier for other people to feel the upgrade pain,
but it’s time to become a better community citizen. Also your assumption that
people who upgrade before you will save you from the weird bugs your app will
encounter is flawed. There are always edge cases sitting in the dark waiting for
<strong>you</strong>.</p>

<p>No, I’m not talking about <a href="https://www.netflix.com/title/80057281">Stranger Things</a>.</p>

<h3 id="3--subtract">3 — Subtract</h3>

<p>Do use every single opportunity (Pull Request) to remove code and <a href="http://www.mikeperham.com/2016/02/09/kill-your-dependencies/">drop third-
party dependencies</a>. Not because they’re evil, but because they will
make you wish demogorgons were real and could take some people away for ever to
the upside-down world of wheel reinventing.</p>

<p>Seriously though, go <a href="https://www.netflix.com/title/80057281">watch that show</a>.</p>

<h3 id="4--new-defaults">4 — New Defaults</h3>

<p>Do learn about new framework defaults as early as you possibly can. Before
Rails 5, the only ways you could do that was by making new empty apps, or
running <code class="language-plaintext highlighter-rouge">rails rails:update</code>, or using <a href="http://railsdiff.org/">RailsDiff</a>. But now you
have <a href="https://github.com/rails/rails/blob/6107a40c0e4d05614493bddf33d5ae8d9ce8a8d2/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults.rb.tt">new_framework_defaults.rb</a> and that’s
pretty cool.</p>

<h3 id="5--dont-skip">5 — Don’t Skip</h3>

<p>Don’t skip minor versions because you really really want to use ActionCable.
First off, <a href="https://github.com/SamSaffron/message_bus">MessageBus is probably way better</a>. More importantly,
you will miss all the deprecation warnings. You know what happens after a
deprecation warning? Shit gets removed. That shit that gets removed will be gone
and you will cry because your eyes can’t process this many red dots at once and
you will think your eyes are bleeding. Yes. They are.</p>

<h3 id="6--mini-majors">6 — Mini-majors</h3>

<p>Take any opportunity to turn any framework minor version upgrade into a
mini-major version upgrade if that makes sense. From watching Rails 4, I knew
that <a href="http://api.rubyonrails.org/classes/ActionController/StrongParameters.html">Strong Parameters</a> were coming when I upgraded us to Rails
3.2, so I added the <a href="https://github.com/rails/strong_parameters">strong_parameters</a> and converted our
models and controllers <strong>before</strong> we upgraded to Rails 4 so we would have one
less variable to account for.</p>

<h3 id="7--changelogs">7 — Changelogs</h3>

<p>Always read changelogs. <a href="http://keepachangelog.com">Keep changelogs</a>. Yeah, those Rails
release changelogs are not great because they’re all split between indedepent
sub-components of the framework that few end-users care about. Yeah, there
should be more end-user friendly entries in the <a href="http://guides.rubyonrails.org/upgrading_ruby_on_rails.html">Rails Upgrade Guides</a>
but they are still very useful and you never know what you might notice and
get ready for <strong>before</strong> it’s time for the big upgrade. Every Monday I get a
rundown of the new versions released for every single dependency we have
thanks to <a href="https://gemnasium.com/orientation/orientation">Gemnasium</a>. Yes, that even includes the dreaded Bower
and npm ones.</p>

<h3 id="8--breaking-news">8 — Breaking News</h3>

<p>Read the news. If you’re not subscribed to <a href="http://rubyweekly.com">Ruby Weekly</a>, that’s
the very <strong>least</strong> you could be doing to keep your ear to the ground. Even
better, learn about what the Rails core team is working on by reading
<a href="http://weblog.rubyonrails.org/news/">This Week in Rails</a> or great podcasts like <a href="http://bikeshed.fm/">The Bikeshed</a>.
You know what your team is currently working on and will work on for the
next few months. So why don’t you have the same curiosity when it comes to
the people maintaining your most important software dependency? Want to go
commando on this one? Go to <a href="http://rubyconf.org/">RubyConf</a>, <a href="http://railsconf.com/">RailsConf</a>, and
great regional Ruby conferences so you can talk to these people. They are really
nice and will gladly listen to you, talk to you, and perhaps even empathize with
your upgrade pains or <a href="https://github.com/rails/rails/issues/25978#event-746667419">fix regressions that affect you</a> in new releases!</p>

<h3 id="9--experiment">9 — Experiment</h3>

<p>Play with new versions. I started working on an internal app called
<a href="http://orientation.io/">Orientation</a> while suffering from Rails 5 envy in late 2012
because I felt we needed a better way to document our knowledge dependencies
(sense a theme?). It allowed me to learn what we could benefit from in this
new version without having to worry about our dependency baggage and
technical debt (yet). While I expected our main application to follow sooner,
I was still able to keep Orientation in lockstep with all minor and major
releases of Rails, which helped a lot with regards to the previous point.</p>

<h3 id="10---blank">10 - Blank</h3>

<p>There is no tenth point. You make it. Share your upgrade stories; good or
bad. They’ll help people like you and me make better and more informed decisions
about upgrading. The community will also benefit because we’ll all talk about
and work on making the upgrade process a little better with each new release.</p>

<hr />

<p>This post was inspired by <a href="https://olivierlacan.com/talks/the-upgrade-trails">a talk I first gave at the Orlando Ruby Users Group
on August 11th</a>.</p>

<p>Want me to share these Rails upgrade battle stories with your company or
conference attendees? You can find ways to reach below.</p>

<p>Stay safe, stay upgraded.</p>

<img src="https://feed.olivierlacan.com/link/8226/8521054.gif" height="1" width="1"/>]]></description>
      <pubDate>Sat, 13 Aug 2016 11:01:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521054/the-upgrade-trails</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/the-upgrade-trails/</guid>
    </item>
    <item>
      <title>Increasing the Sidebar Font Size in Sublime Text</title>
      <description><![CDATA[<p>I still use Sublime Text. If you do too, great, I’m sure you love it. That said
if you own a screen larger than 13” it’s very likely you find the default font
size in the sidebar madeningly small.</p>

<p>I used to wear glasses with a very strong prescription. The sidebar font size in
Sublime drove me nuts because it’s one of those things so clearly created by
someone who has excellent vision — or someone who just doesn’t
know what’s good for them. Squinting at a screen is good for no one.</p>

<p>Last year I had LASIK. No more glasses. Near “perfect” vision. Still, the
Sublime Text sidebar font size gives me headaches. On this 9th day following the
anniversary of my bionic eyes, let’s fix this damn sidebar for good.</p>

<h2 id="packageresourceviewer">PackageResourceViewer</h2>

<p>This step assumes you have <a href="https://packagecontrol.io/installation">Package Control installed</a>.
If you don’t, go do it, trust me, you’re missing on a world of Sublime goodness.</p>

<p>It appears that the files we need to modify (at least in Sublime 3) are now
zipped and not as easy to edit as they were in Sublime 2. If you’re still on
Sublime 2 the file names should be the same and you probably won’t need this
step.</p>

<p>On Sublime 3, run <code class="language-plaintext highlighter-rouge">Shift</code> + <code class="language-plaintext highlighter-rouge">Command/Control</code> + <code class="language-plaintext highlighter-rouge">P</code>.
Select <code class="language-plaintext highlighter-rouge">Package Control: Install Package</code>, then type <code class="language-plaintext highlighter-rouge">PackageResourceViewer</code> and
press <code class="language-plaintext highlighter-rouge">Enter</code> to install it.</p>

<p><img src="https://olivierlacan.com/assets/sublime-sidebar-install-package.png" alt="Screenshot of how to open the Install Package mode" /></p>

<p>Now that it’s installed, you can summon PackageResourceViewer with the <code class="language-plaintext highlighter-rouge">prv</code>
command inside of the <code class="language-plaintext highlighter-rouge">Shift</code> + <code class="language-plaintext highlighter-rouge">Command/Control</code> + <code class="language-plaintext highlighter-rouge">P</code> prompt.</p>

<h2 id="open-resource">Open Resource</h2>

<p>Let’s open the resource we need to modify in order to fix this damn sidebar.
First <code class="language-plaintext highlighter-rouge">Shift</code> + <code class="language-plaintext highlighter-rouge">Command/Control</code> + <code class="language-plaintext highlighter-rouge">P</code>, then type <code class="language-plaintext highlighter-rouge">prv open</code> and <code class="language-plaintext highlighter-rouge">Enter</code>.</p>

<p><img src="https://olivierlacan.com/assets/sublime-sidebar-prv-open.png" alt="Screenshot of how to run prv open" /></p>

<p>You should see a list of resources. At this point your current theme name is
going to matter a lot. If you’re using the default theme (you animal!) you can
just type <code class="language-plaintext highlighter-rouge">Default.sublime-theme</code> and <code class="language-plaintext highlighter-rouge">Enter</code> to modify that. If you’re anything
like me, you have a roster of different themes that you rotate through. I use
the <strong>Themr</strong> package to list and switch themes, so before remembering which
theme I was currently using I had to check Themr’s <code class="language-plaintext highlighter-rouge">List themes</code> command. That
said one quick scroll through your user preferences (<code class="language-plaintext highlighter-rouge">Command/Control</code> + <code class="language-plaintext highlighter-rouge">.</code>)
and you should be able to figure out the name of the theme you’re using.</p>

<p>When you know for sure which theme you’re using, type its name in the <code class="language-plaintext highlighter-rouge">prv open</code>
listing and it should filter it down to a few results. You’re looking for a
<code class="language-plaintext highlighter-rouge">.sublime-theme</code> file. I’m using <code class="language-plaintext highlighter-rouge">Sodarized Dark</code>. So first I had to open the
<code class="language-plaintext highlighter-rouge">Theme - Sodarized</code> directory, then select the <code class="language-plaintext highlighter-rouge">Sodarized Dark.sublime-theme</code>
file.</p>

<p><img src="https://olivierlacan.com/assets/sublime-sidebar-filter-sodarized.png" alt="Screenshot of how to open the Install Package mode" /></p>

<p><img src="https://olivierlacan.com/assets/sublime-sidebar-selecting-theme.png" alt="Screenshot of how to open the Install Package mode" /></p>

<p>If you pick the wrong file, the final step will have no immediate effect so
it’ll be easy to come back to this one and try a different file.</p>

<h2 id="modifying-the-theme">Modifying the Theme</h2>

<p><img src="https://olivierlacan.com/assets/sublime-sidebar-sodarized-dark-theme-file.png" alt="Screenshot of an open .sublime-theme file" /></p>

<p>We’re almost done! Wooh! Use your trusty old <code class="language-plaintext highlighter-rouge">Command</code> + <code class="language-plaintext highlighter-rouge">F</code> to find the
<code class="language-plaintext highlighter-rouge">sidebar_label</code> property. This is what defines the style for the text label
that displays file and directory names in the sidebar.</p>

<p><img src="https://olivierlacan.com/assets/sublime-sidebar-sidebar-label.png" alt="Screenshot of the sidebar_label property" /></p>

<p>To start adjusting the font size you’ll need to add a new property called
<code class="language-plaintext highlighter-rouge">"font.size"</code>.</p>

<p>Before I changed it, my Sodarized Dark <code class="language-plaintext highlighter-rouge">sidebar_label</code> settings looked like this:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre>{
    "class": "sidebar_label",
    "color": [52, 106, 127],
    "shadow_color": [0, 0, 0],
    "shadow_offset": [0, -1]
}
</pre></td></tr></tbody></table></code></pre></div></div>

<p>After, they looked like this:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre>{
    "class": "sidebar_label",
    "color": [52, 106, 127],
    "shadow_color": [0, 0, 0],
    "shadow_offset": [0, -1],
    "font.size": 16
}
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Don’t forget to add a comma (<code class="language-plaintext highlighter-rouge">,</code>) at the end of the previous property’s line
(<code class="language-plaintext highlighter-rouge">shadow_offset</code> in this case) otherwise you’ll cause a syntax error.</p>

<h2 id="sweating-the-details">Sweating the Details</h2>

<p>I recommend playing with the <code class="language-plaintext highlighter-rouge">font.size</code> value. I settled on <code class="language-plaintext highlighter-rouge">16</code> but only
after messing with the <code class="language-plaintext highlighter-rouge">sidebar_tree</code> property’s <code class="language-plaintext highlighter-rouge">row_padding</code> values that
determine the padding (spacing) within each sidebar row.</p>

<p>I also found that changing them from their default value of <code class="language-plaintext highlighter-rouge">[8, 3]</code> to <code class="language-plaintext highlighter-rouge">[8, 5]</code>
made the sidebar rows much easier to read.</p>

<p>I’d recommend making a backup of the original values. Otherwise you can always
remove the Theme package you were modifying and re-install it from Package
Control. That should restore the default theme settings.</p>

<h3 id="my-sidebar-before">My sidebar before:</h3>

<p><img src="https://olivierlacan.com/assets/sublime-sidebar-default-font-size.png" alt="Screenshot of my sidebar using the default settings" /></p>

<h3 id="my-sidebar-after">My sidebar after:</h3>

<p><img src="https://olivierlacan.com/assets/sublime-sidebar-improved-font-size.png" alt="Screenshot of my sidebar using the improved settings" /></p>

<p>It may not look like much, but in the context of a larger screen, it matters and
my eyes thank me for spending the time to finally address this issue.</p>

<h2 id="conclusions">Conclusions</h2>

<p>This post was drawn from personal frustration and it’s very much an expansion
of this <a href="http://stackoverflow.com/questions/23045968/increase-the-font-size-of-text-in-sublime-side-bar/23046654#23046654">excellent StackOverflow response</a>. I have to admit that
it’s a bit baffling how difficult this ordeal was to accomplish such a basic
change that would surely benefit many Sublime Text users. If there’s a much
simpler way to achieve this (using a simple Package perhaps) then let me know
and I’ll be glad to shorten this.</p>

<p>In the meantime, remember that it’s important to take some time to chip away
at the rough edges of your tools every day. You don’t need to switch editors
because something isn’t perfect in the one you’re using. You can often find
solutions that don’t involve uppending your entire workflow for a few weeks.</p>

<p>That said, there should be a breaking point. I could have switched to Atom for
less, and I have. I just haven’t found the productivity equilibrium to satisfy
me in another editor yet. That doesn’t mean it won’t happen.</p>

<img src="https://feed.olivierlacan.com/link/8226/8521055.gif" height="1" width="1"/>]]></description>
      <pubDate>Tue, 09 Aug 2016 10:17:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521055/increase-the-sidebar-font-size-in-sublime-text</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/increase-the-sidebar-font-size-in-sublime-text/</guid>
    </item>
    <item>
      <title>Logging Changes All Over The World</title>
      <description><![CDATA[<p>After months of slow but steady work, <a href="http://keepachangelog.com">keepachangelog.com</a> is now officially
versioned and translated in <strong>nine</strong> languages!</p>

<p>Prior to this, we have of course been using an <a href="https://github.com/olivierlacan/keep-a-changelog/blob/c844dcacdcce8d026f0867b7782866d6d5b11492/CHANGELOG.md">internal changelog</a> to
document minor version evolutions but so far this wasn’t properly reflected on
the website.</p>

<p>I’ve been impressed with how popular this rant-turned-project<sup id="fnref:1" role="doc-noteref"><a href="https://olivierlacan.com#fn:1" class="footnote" rel="footnote">1</a></sup>
has been. It looks like many more people than I’ve ever expected are finding it
useful in communities much broader than open source software.</p>

<p><img src="https://olivierlacan.com/assets/keep-a-changelog-popularity.png" alt="Illustration of Keep a CHANGELOG popularity with a graph of traffic over the past three years" /></p>

<p>Now that the latest version (0.3.0) is public, it will be much easier to
coordinate the translations that have been streaming in steadily over the
past year.</p>

<p>If you know anyone who could help translate the project in a
new language, please point them to the <a href="https://github.com/olivierlacan/keep-a-changelog#translations">Translations section in the project
README</a> for details on how to contribute.</p>

<p>I’m grateful to all the contributors to this project<sup id="fnref:2" role="doc-noteref"><a href="https://olivierlacan.com#fn:2" class="footnote" rel="footnote">2</a></sup> but in particular to
the following folks for submitting pull requests with translations:</p>

<ul>
  <li><a href="https://github.com/tianshuo">Tianshuo</a> for the Chinese translation(s)</li>
  <li><a href="https://github.com/mpbzh">Michael Burri</a> for German</li>
  <li><a href="https://github.com/magol">Magnus Österlund</a> for Swedish</li>
  <li><a href="https://github.com/karalamalar">Emre Erkan</a> for Turkish</li>
  <li><a href="https://github.com/aishek">Alexandr Borisov</a> for Russian</li>
  <li><a href="https://github.com/tallesl">Talles L</a> for Brazilian Portugese</li>
  <li><a href="https://github.com/ZeliosAriex">Omar del Real</a> for Spanish</li>
</ul>

<h2 id="why-keep-a-changelog">Why Keep a CHANGELOG?</h2>

<p>The mission of Keep a CHANGELOG is to help software developers understand the
value of purposeful version documentation.</p>

<p>Anyone can try to read a commit log between the software version they’re using
and a new one they would like to update to. Few people can understand the meaning
of each individual commit, assuming project contributors know
<a href="https://robots.thoughtbot.com/5-useful-tips-for-a-better-commit-message">how to write good commit messages</a>. Even fewer people can
understand what commit is going to break their software because you didn’t
bother to properly document the changes in yours.</p>

<p><strong>Open source software is certainly valuable, but without proper documentation you
might as well keep it closed. Show that you care about the people you share
your software with, <a href="http://keepachangelog.com">keep a changelog</a>.</strong></p>

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1" role="doc-endnote">
      <p>Not my first <a href="https://olivierlacan.com/posts/an-open-source-rage-diamond/">rage diamond</a>. <a href="https://olivierlacan.com#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:2" role="doc-endnote">
      <p>Including <a href="https://github.com/jswanner">Jacob Swanner</a> (from <a href="http://madewithenvy.com/">Envy</a> and the wonderful <a href="http://railsdiff.org/">RailsDiff</a>) who was my rubber duck while going through the final changes last Friday so I could finally release this. Speaking of Envy, I drew tons of inspiration and advice from <a href="https://github.com/nbibler">Nate Bibler</a>’s beautiful changelogs throughout the past five years, and he’s provided great advice and feedback, so he gets an awkwardly long hug as well. <a href="https://olivierlacan.com#fnref:2" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>
<img src="https://feed.olivierlacan.com/link/8226/8521056.gif" height="1" width="1"/>]]></description>
      <pubDate>Sun, 07 Aug 2016 12:22:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521056/logging-changes-all-over-the-world</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/logging-changes-all-over-the-world/</guid>
    </item>
    <item>
      <title>Hash Comparison in Ruby 2.3</title>
      <description><![CDATA[<p>Update (November 18th, 2015): Since these new methods have been announced a few
people have expressed concerns that they would interfere with <code class="language-plaintext highlighter-rouge">Hash#sort</code>. I
addressed those concerns in an addendum to this post below.</p>

<p>It’s been over a year since I wrote my initial <a href="https://olivierlacan.com/posts/proposal-for-a-better-ruby-hash-include/">“Proposal for a better Ruby Hash#include?”</a>
and I’m so happy to announce that since Tuesday November 10, 2015, Hash comparison
methods have been <a href="https://github.com/ruby/ruby/commit/d68c3ecf98bf3b5802a6b0f9a6bcf7825addd9e5">committed to MRI’s trunk branch</a>
by the fabulous <a href="https://github.com/nobu">Nobuyoshi Nakada</a>.</p>

<p>This means the following Hash comparison methods will be available in Ruby 2.3
when it’s released this coming Christmas. In the meantime you can <a href="https://gist.github.com/nurse/f95ead4fc08b5a454e12">install Ruby 2.3.0-preview1</a>
which was released today and already includes this new feature.</p>

<h2 id="comparing-hashes">Comparing Hashes</h2>

<p>What is hash comparison? This may be hard to visualize, so here’s a short example:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="n">hash_one</span> <span class="o">=</span> <span class="p">{</span> <span class="ss">a: </span><span class="mi">1</span> <span class="p">}</span>
<span class="n">hash_two</span> <span class="o">=</span> <span class="p">{</span> <span class="ss">a: </span><span class="mi">1</span><span class="p">,</span> <span class="ss">b: </span><span class="mi">2</span> <span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>It’s clear just by looking at <code class="language-plaintext highlighter-rouge">hash_two</code> that it includes the same single
key and value as <code class="language-plaintext highlighter-rouge">hash_one</code> plus one extra key and value. So how do you check
that with Ruby? Intuitively you may try the <a href="http://docs.ruby-lang.org/en/2.2.0/Hash.html#method-i-include-3F"><code class="language-plaintext highlighter-rouge">Hash#include?</code></a>
method, right? Let’s see.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="c1"># Ruby MRI 2.2 and earlier</span>
<span class="p">{</span> <span class="ss">a: </span><span class="mi">1</span><span class="p">,</span> <span class="ss">b: </span><span class="mi">2</span> <span class="p">}.</span><span class="nf">include?</span><span class="p">({</span> <span class="ss">a: </span><span class="mi">1</span> <span class="p">})</span>
<span class="o">=&gt;</span> <span class="kp">false</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Hmmm. Strange, no? Well that’s because <code class="language-plaintext highlighter-rouge">Hash#include?</code> doesn’t compare hashes, it
only looks at the keys. Worse, it will only work properly with keys as arguments.
So in Ruby 2.2 and earlier, the only thing you
can do is check that a hash includes the same key, like this:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="c1"># Ruby MRI 2.2 and earlier</span>
<span class="p">{</span> <span class="ss">a: </span><span class="mi">1</span><span class="p">,</span> <span class="ss">b: </span><span class="mi">2</span> <span class="p">}.</span><span class="nf">include?</span><span class="p">(</span><span class="ss">:a</span><span class="p">)</span>
<span class="o">=&gt;</span> <span class="kp">true</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This is because <code class="language-plaintext highlighter-rouge">Hash#include?</code> is in fact a method alias for <a href="http://docs.ruby-lang.org/en/2.2.0/Hash.html#method-i-has_key-3F"><code class="language-plaintext highlighter-rouge">Hash#has_key?</code></a>.</p>

<p>This is surprising behavior to say the least, and some Ruby libraries like RSpec
implement <a href="https://github.com/rspec/rspec-expectations/blob/bb731e29f7800f5cef736cf8850293276a0d3f90/lib/rspec/matchers/built_in/include.rb#L94-L97">their own Hash inclusion logic</a> to circumvent the strange behavior of Hash#include?. As you’d expect,
RSpec’s <code class="language-plaintext highlighter-rouge">include</code> matcher checks hashes for both key <strong>and</strong> value matching. So
you can write:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="c1"># RSpec</span>
<span class="n">expect</span><span class="p">({</span> <span class="ss">a: </span><span class="mi">1</span><span class="p">,</span> <span class="ss">b: </span><span class="mi">2</span> <span class="p">}).</span><span class="nf">to</span> <span class="kp">include</span><span class="p">({</span> <span class="ss">a: </span><span class="mi">1</span> <span class="p">})</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="hash-comparison-methods">Hash Comparison Methods</h2>

<p>My original feature proposal suggested introducing an new <code class="language-plaintext highlighter-rouge">Hash#contain?</code> method,
but the semantics didn’t work well enough for the Ruby core developers. Matz himself
said the following in the November developer meeting:</p>

<blockquote>
  <p>Hash#contain? has [a] slight ambiguity problem. I’d vote for adding &gt;=, along with &lt;=.</p>
</blockquote>

<p>At first I was a little taken aback by Matz’s proposal, but <a href="https://twitter.com/sferik">Erik Michaels-Ober</a>
pointed out that I should be happy my little method proposal was becoming an
operator on Hashes. And now I see, Matz and Erik were right, look how great this is:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="c1"># Ruby MRI 2.3.0 (trunk)</span>
<span class="p">{</span> <span class="ss">a: </span><span class="mi">1</span><span class="p">,</span> <span class="ss">b: </span><span class="mi">2</span> <span class="p">}</span> <span class="o">&gt;=</span> <span class="p">{</span> <span class="ss">a: </span><span class="mi">1</span> <span class="p">}</span>
<span class="o">=&gt;</span> <span class="kp">true</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>For the less mathy people (like me), this may take a second to wrap your head
around. I find it easier to say the operator out loud:</p>

<blockquote>
  <p>“Is this hash greater than or equal to this other hash?”.</p>
</blockquote>

<p>A hash that contains another smaller hash is greater, so this returns true.
A hash that contains the same hash is equal, so this returns true.</p>

<p>Here are a few more examples provided by Akira Tanaka:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
</pre></td><td class="rouge-code"><pre><span class="c1"># Ruby MRI 2.3.0 (trunk)</span>
<span class="p">{</span> <span class="ss">a: </span><span class="mi">1</span> <span class="p">}</span> <span class="o">&lt;=</span> <span class="p">{</span> <span class="ss">a: </span><span class="mi">1</span> <span class="p">}</span> <span class="o">=</span> <span class="kp">true</span>
<span class="p">{</span> <span class="ss">a: </span><span class="mi">1</span> <span class="p">}</span> <span class="o">&lt;=</span> <span class="p">{</span> <span class="ss">a: </span><span class="mi">2</span> <span class="p">}</span> <span class="o">=</span> <span class="kp">false</span>
<span class="p">{</span> <span class="ss">a: </span><span class="mi">2</span> <span class="p">}</span> <span class="o">&lt;=</span> <span class="p">{</span> <span class="ss">a: </span><span class="mi">1</span> <span class="p">}</span> <span class="o">=</span> <span class="kp">false</span>
<span class="p">{</span> <span class="ss">a: </span><span class="mi">2</span> <span class="p">}</span> <span class="o">&lt;=</span> <span class="p">{</span> <span class="ss">a: </span><span class="mi">2</span> <span class="p">}</span> <span class="o">=</span> <span class="kp">true</span>
<span class="p">{</span> <span class="ss">a: </span><span class="mi">1</span> <span class="p">}</span> <span class="o">&gt;=</span> <span class="p">{</span> <span class="ss">a: </span><span class="mi">1</span> <span class="p">}</span> <span class="o">=</span> <span class="kp">true</span>
<span class="p">{</span> <span class="ss">a: </span><span class="mi">1</span> <span class="p">}</span> <span class="o">&gt;=</span> <span class="p">{</span> <span class="ss">a: </span><span class="mi">2</span> <span class="p">}</span> <span class="o">=</span> <span class="kp">false</span>
<span class="p">{</span> <span class="ss">a: </span><span class="mi">2</span> <span class="p">}</span> <span class="o">&gt;=</span> <span class="p">{</span> <span class="ss">a: </span><span class="mi">1</span> <span class="p">}</span> <span class="o">=</span> <span class="kp">false</span>
<span class="p">{</span> <span class="ss">a: </span><span class="mi">2</span> <span class="p">}</span> <span class="o">&gt;=</span> <span class="p">{</span> <span class="ss">a: </span><span class="mi">2</span> <span class="p">}</span> <span class="o">=</span> <span class="kp">true</span>
<span class="p">{</span> <span class="ss">a: </span><span class="mi">1</span> <span class="p">}</span> <span class="o">&lt;</span>  <span class="p">{</span> <span class="ss">a: </span><span class="mi">1</span> <span class="p">}</span> <span class="o">=</span> <span class="kp">false</span>
<span class="p">{</span> <span class="ss">a: </span><span class="mi">1</span> <span class="p">}</span> <span class="o">&lt;</span>  <span class="p">{</span> <span class="ss">a: </span><span class="mi">2</span> <span class="p">}</span> <span class="o">=</span> <span class="kp">false</span>
<span class="p">{</span> <span class="ss">a: </span><span class="mi">2</span> <span class="p">}</span> <span class="o">&lt;</span>  <span class="p">{</span> <span class="ss">a: </span><span class="mi">1</span> <span class="p">}</span> <span class="o">=</span> <span class="kp">false</span>
<span class="p">{</span> <span class="ss">a: </span><span class="mi">2</span> <span class="p">}</span> <span class="o">&lt;</span>  <span class="p">{</span> <span class="ss">a: </span><span class="mi">2</span> <span class="p">}</span> <span class="o">=</span> <span class="kp">false</span>
<span class="p">{</span> <span class="ss">a: </span><span class="mi">1</span> <span class="p">}</span> <span class="o">&gt;</span>  <span class="p">{</span> <span class="ss">a: </span><span class="mi">1</span> <span class="p">}</span> <span class="o">=</span> <span class="kp">false</span>
<span class="p">{</span> <span class="ss">a: </span><span class="mi">1</span> <span class="p">}</span> <span class="o">&gt;</span>  <span class="p">{</span> <span class="ss">a: </span><span class="mi">2</span> <span class="p">}</span> <span class="o">=</span> <span class="kp">false</span>
<span class="p">{</span> <span class="ss">a: </span><span class="mi">2</span> <span class="p">}</span> <span class="o">&gt;</span>  <span class="p">{</span> <span class="ss">a: </span><span class="mi">1</span> <span class="p">}</span> <span class="o">=</span> <span class="kp">false</span>
<span class="p">{</span> <span class="ss">a: </span><span class="mi">2</span> <span class="p">}</span> <span class="o">&gt;</span>  <span class="p">{</span> <span class="ss">a: </span><span class="mi">2</span> <span class="p">}</span> <span class="o">=</span> <span class="kp">false</span>
<span class="p">{</span> <span class="ss">a: </span><span class="mi">1</span> <span class="p">}</span> <span class="o">==</span> <span class="p">{</span> <span class="ss">a: </span><span class="mi">1</span> <span class="p">}</span> <span class="o">=</span> <span class="kp">true</span>
<span class="p">{</span> <span class="ss">a: </span><span class="mi">1</span> <span class="p">}</span> <span class="o">==</span> <span class="p">{</span> <span class="ss">a: </span><span class="mi">2</span> <span class="p">}</span> <span class="o">=</span> <span class="kp">false</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Look at how consistent this is. You can now compare hashes exactly the same way
you would compare integers.</p>

<p>I can’t wait for Ruby 2.3.</p>

<h2 id="does-it-mean-comparable-is-now-included-in-hash">Does it mean Comparable is now included in Hash?</h2>

<p>No.</p>

<p>The methods added to Hash are as follows:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">Hash#&gt;</code> — this hash instance includes the argument hash</li>
  <li><code class="language-plaintext highlighter-rouge">Hash#&gt;=</code> — this hash instance includes or is the same as the argument hash</li>
  <li><code class="language-plaintext highlighter-rouge">Hash#&lt;</code> — this hash instance is included in the argument hash</li>
  <li><code class="language-plaintext highlighter-rouge">Hash&lt;=</code> - this hash instance is included or the same as the argument hash</li>
</ul>

<p>Conspicuously absent is the <code class="language-plaintext highlighter-rouge">&lt;=&gt;</code> method used by the Comparable module to sort
objects. What this means is that these new methods will not interfere with your
existing calls to <code class="language-plaintext highlighter-rouge">Hash#sort</code>.</p>
<img src="https://feed.olivierlacan.com/link/8226/8521057.gif" height="1" width="1"/>]]></description>
      <pubDate>Wed, 11 Nov 2015 18:00:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521057/hash-comparison-in-ruby-2-3</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/hash-comparison-in-ruby-2-3/</guid>
    </item>
    <item>
      <title>Diving into Ruby, Head First.</title>
      <description><![CDATA[<p>I did technical reviewing for Jay McGavren’s new and excellent Head First Ruby book
which comes out November 30th. I can tell you that it’s by far the best book
I’ve ever read for people who are new to programming, new to Ruby, and new to
Object-oriented thinking. That said, I’m neither, and I still found it a great read.</p>

<p>You should <a href="http://www.amazon.com/dp/1449372651/ref=cm_sw_su_dp">pre-order a copy on Amazon</a>
while it’s still 43% off ($25.70 instead of $44.99).</p>

<p>After five years, Ruby is still a joy for me to use every single day. It baffles
me that people refrain from using it because their friend’s uncle’s sister’s
brother’s mother’s friend told them “it doesn’t scale”. You know what scales
incredibly well with Ruby? The code. Refactoring code, expanding it, breaking it
into parts that communicate with each other like a living organism would. Most of
what you do with software is not scaling, it’s changing the code.</p>

<p>It’s not just Ruby, the tool, that I cherish. It’s the people of Ruby. Its
creators, maintainers, and the people who sustain its community by inviting
more people to it. Often, I see people making technological choices based
solely on the merits of the tools. They forget to care about whether the makers
of the tools are friendly or helpful human beings. But tools are made by
people, and people are flawed. The flaws of their tools reflect their own
flaws. Put differently, if people who dislike other people make tools, then
their tools will tend to disregard people or even treat them poorly, as a
second thought.</p>

<p>I don’t think I have to give you examples of people-unfriendly technology. There’s
still far too much of it around. I believe Ruby is a beacon in a sea of tools
designed to achieve an end at whatever human cost. It’s not the only beacon, but
it’s the one I chose, and I’m still very happy with it.</p>

<p>I’ve managed to scale my professional life with Ruby. We run a
<a href="https://www.codeschool.com">business</a> with 2 Million users using mostly Ruby
and yet we don’t wake up in the middle of the night because Ruby stopped
scaling. We spend far more time stressing out about operations, support,
building course content, designing the best software we can for our users, and
communicating with each other.</p>

<p>I wish the kinds of programming joys I experience daily to everyone who wants to
learn how to build good, sustainable, satisfying software that focuses on helping
human beings learn more and build better tools. I think Head First Ruby is a good
place to start.</p>

<p>PS: Amazon doesn’t offer the ebook version of this book. You can
<a href="http://shop.oreilly.com/product/9780596803995.do">buy the early release ebook version</a>
if you want to start reading today. It will be updated once the book is published.</p>
<img src="https://feed.olivierlacan.com/link/8226/8521058.gif" height="1" width="1"/>]]></description>
      <pubDate>Sat, 07 Nov 2015 18:01:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521058/diving-into-ruby-head-first</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/diving-into-ruby-head-first/</guid>
    </item>
    <item>
      <title>Migrating an ad-hoc URL slug system to FriendlyId</title>
      <description><![CDATA[<p>I recently decided to migrate from a ad-hoc solution for URL slugs on <a href="https://github.com/orientation/orientation">Orientation</a> to <a href="https://github.com/norman">Norman Clarke</a>’s excellent <a href="https://github.com/norman/friendly_id">FriendlyId gem</a>.</p>

<p>The main reason was that wanted to keep a slug history in order to avoid <code class="language-plaintext highlighter-rouge">404 File Not Found</code>
errors when users decide to change an article title. I have to be able to guarantee that you will
find a piece of documentation regardless of how many time its title has changed in the past.</p>

<h2 id="before">Before</h2>

<p>This is how slugs were generated originally in the Article model:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
</pre></td><td class="rouge-code"><pre><span class="c1"># app/models/article.rb</span>
<span class="k">class</span> <span class="nc">Article</span> <span class="o">&lt;</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Base</span>

  <span class="c1"># ...</span>

  <span class="n">before_validation</span> <span class="ss">:generate_slug</span>

  <span class="c1"># ...</span>

  <span class="n">validates</span> <span class="ss">:slug</span><span class="p">,</span> <span class="ss">uniqueness: </span><span class="kp">true</span><span class="p">,</span> <span class="ss">presence: </span><span class="kp">true</span>

  <span class="c1"># ...</span>

  <span class="k">def</span> <span class="nf">to_param</span>
    <span class="n">slug</span>
  <span class="k">end</span>

  <span class="c1"># ...</span>

  <span class="kp">private</span>

  <span class="k">def</span> <span class="nf">generate_slug</span>
    <span class="k">if</span> <span class="nb">self</span><span class="p">.</span><span class="nf">slug</span><span class="p">.</span><span class="nf">present?</span> <span class="o">&amp;&amp;</span> <span class="nb">self</span><span class="p">.</span><span class="nf">slug</span> <span class="o">==</span> <span class="n">title</span><span class="p">.</span><span class="nf">parameterize</span>
      <span class="nb">self</span><span class="p">.</span><span class="nf">slug</span>
    <span class="k">else</span>
      <span class="nb">self</span><span class="p">.</span><span class="nf">slug</span> <span class="o">=</span> <span class="n">title</span><span class="p">.</span><span class="nf">parameterize</span>
    <span class="k">end</span>
  <span class="k">end</span>
<span class="k">end</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>And this is how they were used in the controller:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="rouge-code"><pre><span class="c1"># app/controllers/articles_controller.rb</span>
<span class="k">class</span> <span class="nc">ArticlesController</span> <span class="o">&lt;</span> <span class="no">ApplicationController</span>
  <span class="n">respond_to</span> <span class="ss">:html</span><span class="p">,</span> <span class="ss">:json</span>

  <span class="c1"># ...</span>

  <span class="k">def</span> <span class="nf">show</span>
    <span class="vi">@article</span> <span class="o">=</span> <span class="no">Article</span><span class="p">.</span><span class="nf">find_by</span><span class="p">(</span><span class="ss">slug: </span><span class="n">params</span><span class="p">[</span><span class="ss">:id</span><span class="p">])</span> <span class="o">||</span> <span class="no">Article</span><span class="p">.</span><span class="nf">find</span><span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="ss">:id</span><span class="p">])</span>
    <span class="n">respond_with</span> <span class="vi">@article</span>
  <span class="k">end</span>
<span class="k">end</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>One important note here about <code class="language-plaintext highlighter-rouge">find_by</code>. Unlike the regular ActiveRecord <code class="language-plaintext highlighter-rouge">find</code>, <code class="language-plaintext highlighter-rouge">find_by</code> does not raise a <code class="language-plaintext highlighter-rouge">RecordNotFound</code> exception when it finds no matches. Instead it returns <code class="language-plaintext highlighter-rouge">nil</code> which is falsey. This is why it comes before the <code class="language-plaintext highlighter-rouge">find</code> call, which was only present as a legacy concern to allow people to access <code class="language-plaintext highlighter-rouge">/articles/33</code> instead of using Article 33’s slug.</p>

<h2 id="after">After</h2>

<p>After installing FriendlyId and creating the <code class="language-plaintext highlighter-rouge">friendly_id_slugs</code> table, I replaced the code above with this:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
</pre></td><td class="rouge-code"><pre><span class="c1"># app/models/article.rb</span>

<span class="k">class</span> <span class="nc">Article</span> <span class="o">&lt;</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Base</span>
  <span class="kp">include</span> <span class="no">Dateable</span>
  <span class="kp">extend</span> <span class="no">ActionView</span><span class="o">::</span><span class="no">Helpers</span><span class="o">::</span><span class="no">DateHelper</span>
  <span class="kp">extend</span> <span class="no">FriendlyId</span>

  <span class="n">friendly_id</span> <span class="ss">:title</span><span class="p">,</span> <span class="ss">use: </span><span class="p">[</span><span class="ss">:slugged</span><span class="p">,</span> <span class="ss">:history</span><span class="p">]</span>

  <span class="k">def</span> <span class="nf">should_generate_new_friendly_id?</span>
    <span class="o">!</span><span class="n">has_friendly_id_slug</span> <span class="o">||</span> <span class="n">title_changed?</span>
  <span class="k">end</span>

  <span class="k">def</span> <span class="nf">has_friendly_id_slug?</span>
    <span class="n">slugs</span><span class="p">.</span><span class="nf">where</span><span class="p">(</span><span class="ss">slug: </span><span class="n">slug</span><span class="p">).</span><span class="nf">exists?</span>
  <span class="k">end</span>
<span class="k">end</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
</pre></td><td class="rouge-code"><pre><span class="c1"># app/controllers/articles_controller.rb</span>
<span class="k">class</span> <span class="nc">ArticlesController</span> <span class="o">&lt;</span> <span class="no">ApplicationController</span>
  <span class="n">respond_to</span> <span class="ss">:html</span><span class="p">,</span> <span class="ss">:json</span>

  <span class="c1"># ...</span>

  <span class="k">def</span> <span class="nf">show</span>
    <span class="vi">@article</span> <span class="o">=</span> <span class="no">Article</span><span class="p">.</span><span class="nf">friendly</span><span class="p">.</span><span class="nf">find</span><span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="ss">:id</span><span class="p">])</span>
    <span class="n">respond_with_article_or_redirect</span>
  <span class="k">end</span>

  <span class="c1"># ...</span>

  <span class="kp">private</span>

  <span class="k">def</span> <span class="nf">respond_with_article_or_redirect</span>
    <span class="c1"># If an old id or a numeric id was used to find the record, then</span>
    <span class="c1"># the request path will not match the post_path, and we should do</span>
    <span class="c1"># a 301 redirect that uses the current friendly id.</span>
    <span class="k">if</span> <span class="n">request</span><span class="p">.</span><span class="nf">path</span> <span class="o">!=</span> <span class="n">article_path</span><span class="p">(</span><span class="vi">@article</span><span class="p">)</span>
      <span class="k">return</span> <span class="n">redirect_to</span> <span class="vi">@article</span><span class="p">,</span> <span class="ss">status: :moved_permanently</span>
    <span class="k">else</span>
      <span class="k">return</span> <span class="n">respond_with</span> <span class="vi">@article</span>
    <span class="k">end</span>
  <span class="k">end</span>
<span class="k">end</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>The useful method here is <code class="language-plaintext highlighter-rouge">has_friendly_id_slug?</code> because it allows me to check
whether an article has a slug that was generated by FriendlyId or by my old
ad-hoc system.</p>

<p>FriendlyId creates a simple <code class="language-plaintext highlighter-rouge">has_many</code> association between the model and <code class="language-plaintext highlighter-rouge">FriendlyId::Slug</code>. I could have used <code class="language-plaintext highlighter-rouge">friendly_id</code> (the dynamic reader method) because the default database column name for the locally-stored (on the <code class="language-plaintext highlighter-rouge">articles</code> table instead of the <code class="language-plaintext highlighter-rouge">friendly_id_slugs</code> table) slug is… <code class="language-plaintext highlighter-rouge">slug</code>. That’s configurable of course, but I know for a fact that the column name I had used with my ad-hoc system was <code class="language-plaintext highlighter-rouge">slug</code> so there’s no point in relying on FriendlyId to figure out the actual column name for me.</p>

<h2 id="why-bother">Why bother?</h2>

<p>So anyway, say we have an article titled “Banana”. That article’s slug column should already be set to <code class="language-plaintext highlighter-rouge">banana</code> (per my ad-hoc slug system) but a freshly installed FriendlyId should mean that there is not <code class="language-plaintext highlighter-rouge">friendly_id_slugs</code> record for <code class="language-plaintext highlighter-rouge">banana</code>. Thanks to <code class="language-plaintext highlighter-rouge">has_friendly_id_slug?</code>, we can check.</p>

<p>And thanks to that check, we can decide to easily migrate all the cached slugs (i.e. on the <code class="language-plaintext highlighter-rouge">articles</code> table) to FriendlyId. All it takes is:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="no">Article</span><span class="p">.</span><span class="nf">all</span><span class="p">.</span><span class="nf">each</span><span class="p">(</span><span class="o">&amp;</span><span class="ss">:save!</span><span class="p">)</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Why bother? Because if we’re using FriendlyId’s History module, we need its <code class="language-plaintext highlighter-rouge">friendly_id_slugs</code> table to contain the original slug. Without doing this, the first slug stored in FriendlyId would be a future one (when an article’s title is eventually modified) and not the current one stored inside of the <code class="language-plaintext highlighter-rouge">articles.slug</code> column.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre>a = Article.friendly.find("banana")
a.title = "Pamplemousse"
a.save!

a.friendly.find("banana")
=&gt; #&lt;Article:0x0000010b6913b8
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Everybody’s happy and nobody bumps into 404s! The end.</p>

<p>PS: Thanks to Normal Clarke for <a href="https://twitter.com/compay/status/588696133817520129">the tip that helped me</a> find this solution.</p>
<img src="https://feed.olivierlacan.com/link/8226/8521059.gif" height="1" width="1"/>]]></description>
      <pubDate>Thu, 16 Apr 2015 13:42:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521059/migrating-an-ad-hoc-url-slug-system-to-friendly-id</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/migrating-an-ad-hoc-url-slug-system-to-friendly-id/</guid>
    </item>
    <item>
      <title>Better Feedback on Ruby 2.2 Keyword Argument Errors</title>
      <description><![CDATA[<p>I was building a class yesterday and I wanted the instantiation process of the class
to be self-documenting so I decided to use a keyword argument in the <code class="language-plaintext highlighter-rouge">initializer</code> method.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="k">class</span> <span class="nc">HallMonitor</span>
  <span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="ss">user: </span><span class="kp">nil</span><span class="p">)</span>
    <span class="vi">@user</span> <span class="o">=</span> <span class="n">user</span>
  <span class="k">end</span>
<span class="k">end</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>As you can see, I also decided to make the <code class="language-plaintext highlighter-rouge">user</code> keyword argument optional by
making it default to nil.</p>

<p>Later while pairing and refactoring the implementation of the class and the
associated specs, I forgot about my fancy keyword argument and simply wrote
the following:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="no">HallMonitor</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">user</span><span class="p">)</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This raised the following error:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="no">ArgumentError</span><span class="p">:</span> <span class="n">wrong</span> <span class="n">number</span> <span class="n">of</span> <span class="n">arguments</span> <span class="p">(</span><span class="mi">1</span> <span class="k">for</span> <span class="mi">0</span><span class="p">)</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>I was confused for a second. I hesitated, then said “it makes no sense” out loud
because I remembered making the <code class="language-plaintext highlighter-rouge">user</code> argument optional. Of course I had misread
the exception as “wrong number of arguments (<strong>0 for 1</strong>)”, which it wasn’t.</p>

<p>Then I went back to the class, looked up the method definitation and went “aaaahhh!”.</p>

<p>But here, Ruby could have been far more helpful to me. It made sense before we
had keyword arguments for Ruby to respond with an exception that would just compare
the number of provided arguments against the number of required arguments. Nowadays
we have keyword arguments, Ruby can tell us exactly what argument is missing and
what its name is (if we use keyword arguments of course), so why not throw this exception
instead:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="no">ArgumentError</span><span class="p">:</span> <span class="n">wrong</span> <span class="n">number</span> <span class="n">of</span> <span class="n">arguments</span> <span class="p">(</span><span class="mi">1</span> <span class="k">for</span> <span class="mi">0</span><span class="p">),</span> <span class="n">keyword</span> <span class="ss">arguments: </span><span class="p">[</span><span class="ss">user: </span><span class="kp">nil</span><span class="p">]</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This kind of simple error feedback improvements, similar to <a href="https://bugs.ruby-lang.org/issues/10982">one proposed by
Richard Schneeman</a> earlier this year
would probably save a Rubyists time debugging simple mistakes. And that’s bound
to make them happier, isn’t it?</p>

<p>If you agree or disagree, let me know on <a href="http://twitter.com/olivierlacan">Twitter</a> or by
email. I’ll submit a feature suggestion to <a href="http://bugs.ruby-lang.org">bugs.ruby-lang.org</a>
if nobody objects for a sensible reason.</p>
<img src="https://feed.olivierlacan.com/link/8226/8521060.gif" height="1" width="1"/>]]></description>
      <pubDate>Mon, 30 Mar 2015 19:21:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521060/better-feedback-on-ruby-2-2-keyword-argument-errors</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/better-feedback-on-ruby-2-2-keyword-argument-errors/</guid>
    </item>
    <item>
      <title>Ego Time Machine</title>
      <description><![CDATA[<p><a href="http://en.wikipedia.org/wiki/Impostor_syndrome">Impostor Syndrome</a> is
much more pervasive in our industry than even many successful people are
willing to admit. I’ve been crippled by it many times in my life.</p>

<p>Over time, the only reliable system I’ve developed to combat it is
something I called the “ego time machine”.</p>

<p><em>Once in a while, get lost in your own brain and try to remember a time
when you knew less about the topic you find yourself focused on right
now.</em></p>

<p>Sometimes it’s almost impossible not to feel like a fraud. You see any
evidence to the contrary as a sweet lie hiding an awful awful truth.</p>

<p>The exercise I describe above is useful because it comes from within.
It’s not external validation you can be tempted to brush off as a kind
compliment. It helps you take a step back. It equips you a thought
machine that will can hopefully help you to chip away at your own
feelings of inadequacy.</p>

<ul>
  <li><strong>5 years ago</strong> basic Object-oriented programming baffled me.</li>
  <li><strong>4 years ago</strong> I thought I would never understand Ruby on Rails.</li>
  <li><strong>3 years ago</strong> caching seemed like it was too much work.</li>
  <li><strong>2 months ago</strong> I was still afraid to look at C code.</li>
  <li><strong>1 month ago</strong> I didn’t know how databases search for records.</li>
</ul>

<p>Looking at it this way, it’s impossible to deny the progress I’ve made
and how far I’ve come.</p>

<p>Progress in knowledge acquisition is often hard to measure, hard to
sense internally. It’s common for the people generalized as “knowledge
wokers” not to realize how much they know. We often worry about whether
we know enough, instead of worrying about whether we’re good at learning
more. The fact that there are entire portions of my daily workload that
contain activities which would have baffled me just a few years ago is
immensely useful to combat the lingering sense that I’m not pulling my
own weight.</p>

<p>In a great post called <a href="http://blog.42floors.com/imposter-syndrome/">Impostor Syndrome</a>
Jason Freedman describes a ritual he follows when he fells out of his
element:</p>

<blockquote>
  <p>I actually have this little tradition I do personally when I’m most
stressed out and my body feels weak – I have this strange craving for
McDonald’s. It happens every time. And I don’t really eat McDonald’s
any other time in my life except for when I’m really feeling stressed.
So now I have this thing whenever I’m really feeling pushed a bit too
hard, I head straight to McDonald’s and have my little ceremony with
my hamburger, chicken mcnuggets and fries. And I think back to all the
times I have sat in this exact same seat, eating this exact same
thing, feeling this exact same way. It helps me, in the moment, gain
that temporal perspective that allows me to remember that this too
shall pass.</p>
</blockquote>

<p>This is the Ego Time Machine at its best. It reconnects you to your past
accomplishments in a way that makes it near impossible for your to
willfully ignore them. It forces you to see that there’s a good chance
your fear and doubt are not rational. They’re part of the cycle. It gets
better.</p>

<img src="https://feed.olivierlacan.com/link/8226/8521061.gif" height="1" width="1"/>]]></description>
      <pubDate>Fri, 02 Jan 2015 17:49:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521061/ego-time-machine</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/ego-time-machine/</guid>
    </item>
    <item>
      <title>How to Install Your Own Version of git</title>
      <description><![CDATA[<p>Yesterday, a <a href="https://github.com/blog/1938-vulnerability-announced-update-your-git-clients">pretty serious security vulnerability was revealed</a> which affects all versions of git.</p>

<p>You should upgrade to one of the maintenance releases described in the
link above, but that’s assuming you can.</p>

<p>A lot of people don’t know how to do that. A lot of people are using the
git version that ships with Apple’s OS X or their operating system of
choice. I can’t help you if you use Windows or Linux but head over to the
<a href="http://git-scm.com/downloads">Downloads section of the official git website</a> for help.</p>

<p>Now if you use OS X, and if you use git regurlarly like many people who
build websites and software, you now may understand why people like me
recommend against using the software packages that are bundled with
operating systems like OS X:</p>

<ul>
  <li>The versions are often very old.</li>
  <li>It’s either hard or impossible to upgrade them without the operating
system vendor.</li>
  <li>Operating sytem security updates don’t always update these packages,
or at least not promptly.</li>
</ul>

<h2 id="git-your-own">git your own</h2>

<p>First step to controlling your development software,
<a href="http://brew.sh/">install Homebrew</a>. It’s a package manager.
It works similarly to the App Store — but on the command line.</p>

<p>So first open the Terminal app. <code class="language-plaintext highlighter-rouge">Command</code> + <code class="language-plaintext highlighter-rouge">Space</code> to open Spotlight
and just type <code class="language-plaintext highlighter-rouge">Terminal</code> if you don’t know where it is. You should see
something like this:</p>

<p><img src="https://olivierlacan.com/assets/terminal.png" alt="Terminal" /></p>

<p>Now I’m curious if you already have Homebrew installed. We can be sure
by using the <code class="language-plaintext highlighter-rouge">which</code> command like this:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre>which brew
/usr/local/bin/brew
</pre></td></tr></tbody></table></code></pre></div></div>

<p>If you don’t see <code class="language-plaintext highlighter-rouge">/usr/local/bin/brew</code> displayed when you press <code class="language-plaintext highlighter-rouge">Enter</code>
after entering the command, you don’t have Homebrew installed.
So let’s do that.</p>

<p><strong>WARNING</strong>: I’m about to tell you to do something dangerous.
Downloading and executing an unknown and potentially nefarious script
whose source code you’ve never read. You <strong>should not</strong> do this willy
nilly. The only reason I ask you to trust me is that I trust this
specific script. It’s written in Ruby. I’ve read it. And I’m mildly
confident no one has hacked my blog to replace the link with a nefarious
one.</p>

<p>In any case, you can find the source code of the script right here: <a href="https://raw.githubusercontent.com/Homebrew/install/master/install">https://raw.githubusercontent.com/Homebrew/install/master/install</a></p>

<p>Paste the following command in your Terminal window and press <code class="language-plaintext highlighter-rouge">Enter</code>:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>ruby <span class="nt">-e</span> <span class="s2">"</span><span class="si">$(</span>curl <span class="nt">-fsSL</span> https://raw.githubusercontent.com/Homebrew/install/master/install<span class="si">)</span><span class="s2">"</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Once the installation is over, I recommend you run the following command:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre>brew doctor
Your system is ready to brew.
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Homebrew can’t heal itself but it can diagnose anything on your system
that may hinder its functioning. Usually that will involve installing a
version of Xcode which you can now simply find on the App Store.</p>

<p>Whenever <code class="language-plaintext highlighter-rouge">brew doctor</code> answers with <code class="language-plaintext highlighter-rouge">Your system is ready to brew.</code>, you’re
ready to install git. Just run:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>brew <span class="nb">install </span>git
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Once you do, I suggest you quit (<code class="language-plaintext highlighter-rouge">Command</code> + ‘Q’) the Terminal app. I
don’t say this because restarting the app magically makes everything
works right. It’s because we installed a new binary and it may not be
available on the load path immediately. You can check that by running:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>which <span class="nt">-a</span> git
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This command looks for all available binaries matching the name <code class="language-plaintext highlighter-rouge">git</code>
anywhere on your load path (<code class="language-plaintext highlighter-rouge">$PATH</code>). Whereas <code class="language-plaintext highlighter-rouge">which git</code> will only tell
you the one which will be used to answer calls to git. The first directory
path in the list will be the one used. If you see <code class="language-plaintext highlighter-rouge">/usr/local/bin/git</code> at
the top, congratulations, you’ve installed your own git. You can check
the version of the git you installed with <code class="language-plaintext highlighter-rouge">git --version</code>.
It should be higher than <code class="language-plaintext highlighter-rouge">2.2.1</code>.</p>

<p>If <code class="language-plaintext highlighter-rouge">which git</code> yields <code class="language-plaintext highlighter-rouge">/usr/bin/git</code> then the Apple-installed git is still
taking precedence over the one we just installed with Homebrew. That’s
completely normal and okay. It just means we have a wee bit of work left to do.</p>

<p>Let’s talk about your <code class="language-plaintext highlighter-rouge">$PATH</code>. The reason why you’re seeing the Apple-installed
version respond first is because of that loading path. I’ve written a long
piece for <a href="http://alistapart.com/article/the-path-to-enlightenment">A List Apart on this topic if you care to learn more</a> but if you want to get it over with quick, let’s do this:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nb">echo</span> <span class="nv">$PATH</span> | <span class="nb">tr</span> <span class="s2">":"</span> <span class="s2">"</span><span class="se">\n</span><span class="s2">"</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This should list all the paths in your load path in order of precedence.
For you, I can bet that <code class="language-plaintext highlighter-rouge">/usr/local/bin</code> is showing up <em>below</em> <code class="language-plaintext highlighter-rouge">/usr/bin</code>.</p>

<p>All we need to do is <strong>prepend</strong> the <code class="language-plaintext highlighter-rouge">/usr/local/bin</code> path in the load
order.</p>

<p>First run these commands:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="nb">cd
ls</span> <span class="nt">-a</span> | <span class="nb">grep </span>bash
</pre></td></tr></tbody></table></code></pre></div></div>

<p>The first command takes you to your home directory wherever you are.
It’s a neat trick to quickly go home without having to type anything else.</p>

<p>The second command lists all directory contents including dotfiles (<code class="language-plaintext highlighter-rouge">-a</code>)
and then filters the list of returned files and directories to only show
the ones which have the word <code class="language-plaintext highlighter-rouge">bash</code> inside them.</p>

<p>Mine only outputs:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre>.bash_history
.bash_profile
</pre></td></tr></tbody></table></code></pre></div></div>

<p>If you have a <code class="language-plaintext highlighter-rouge">.bashrc</code> file it’s likely you created it following someone’s
advice on the internet. Check to make sure it doesn’t contain path modifications:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nb">cat</span> .bashrc
</pre></td></tr></tbody></table></code></pre></div></div>

<p>If you don’t see anything that ressembles <code class="language-plaintext highlighter-rouge">PATH=</code> then you’re fine,
otherwise I recommend you put all your path modifications in the same
place. I put mine in <code class="language-plaintext highlighter-rouge">.bash_profile</code>. If you want to read more about
configuration files, I recommend <a href="http://superuser.com/questions/789448/choosing-between-bashrc-profile-bash-profile-etc">this</a> and <a href="http://superuser.com/questions/789448/choosing-between-bashrc-profile-bash-profile-etc">that</a> StackOverflow discussions.</p>

<p>Here’s how to modify your path to prepend the <code class="language-plaintext highlighter-rouge">/usr/local/bin</code> directory:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nb">export </span><span class="nv">PATH</span><span class="o">=</span><span class="s2">"/usr/local/bin:</span><span class="nv">$PATH</span><span class="s2">"</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Make sure to put that near the top of your <code class="language-plaintext highlighter-rouge">.bash_profile</code> and annotate
it with a note about its purpose so you can understand it when you find it
later. I often leave links to the resources I’ve used, like this blog
post, so I can understand why I modified my configuration later.</p>
<img src="https://feed.olivierlacan.com/link/8226/8521062.gif" height="1" width="1"/>]]></description>
      <pubDate>Fri, 19 Dec 2014 17:59:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521062/how-to-install-your-own-version-of-git</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/how-to-install-your-own-version-of-git/</guid>
    </item>
    <item>
      <title>The Cover Matters</title>
      <description><![CDATA[<blockquote>
  <p>You can’t judge a book by its cover</p>
</blockquote>

<p>You’ve surely had this trope dogmatically thrown at you at some
point. Perhaps by someone fond of prepackaged thinking and unsolicited
advice. It may have had uses as a tool to protect people against easy
judgement, but when generalized in its popular form, it’s thoughtless.</p>

<p>I’m going to make a daring assumption: you and I agree that design
usually tends to improve things. I know, a certain Jony has recently
proved to us that designers who achieve a little bit too much power can
in fact make things worse for a lot of people. But in general, design is
a system of thinking with the purpose of achieving something not only
beautiful but functional and friendly to its user as well.</p>

<p>If we do agree on this definition, here’s what a book’s cover tells me
about what’s inside. It tells me that someone involved in the creation
of the book cared about its initial perception. The perception that
someone with no prior knowledge of the book, its author, its publisher,
its subject — anything — would have about the book.</p>

<p>Caring about a the cover takes humility and empathy. Despite their
involvement bias, whoever does care about the cover realizes that there
may be humans on earth who do not know why <em>this</em> book matters. Why they
should read it.</p>

<p>There are some essential elements to a cover. Just imagine for a second
an utterly blank cover: a pure white piece of thick paper. What does it
tell you about the book? It tells you that someone, perhaps the author,
believes that it’s unnecessary for the book to have any external means
of identification. This is an extreme example. It’s always
easier to reveal the cracks in an argument when you push its to its
logical limit.</p>

<p>Now let’s take a beautiful cover. It has everything. The title and the
author’s name are carefully printed with an elegant typeface and located
unambiguously on the front and the spine. There’s an interesting
illustration that attracts attention in a bookstore regardless of the
prospective reader’s artistic preference. If the title doesn’t make the
subject of the book self-evident, perhaps there’s a short subtitle which
will secure the interest of someone whose attention was captured from
afar but perhaps wasn’t exactly sure of the subject matter. If there are
pull-quotes in the back, they’re not ridiculously superlative but they
simply ignite more curiosity if they originate from people who the
passerby respects and whose opinion they trusts.</p>

<p>Let’s stop here. Wouldn’t you judge this cover significantly differently
that you would the blank one? Aside from the fact that a blank cover
would admittedly make a book stand out, the odds of you not even being
able to judge the blank cover because you won’t see it are great.</p>

<p>It doesn’t take bad design to make good design stand out. It helps, of
course. In a sea of blue icons, a red one stands out. It’s a statement.
You will judge that statement. It will give you information, however
tenuous, about the application behind the icon.</p>

<p>A few years ago I was looking for an accountant. Despite being the son
of an accountant, I know next to nothing about the topic. Especially
because what little I knew related to accounting in France, not in the
U.S. From experience, I only had a few keywords to help me in my search.
I knew I was looking for a CPA, Certified Public Accountant. After
unsuccessfully asking a few friends for a recommendation, my patience
ran short and I decided to take two approaches: Google and Yelp.</p>

<p>I assumed that Google would be littered with paid ads and SEO-gamed
results (it was) which would limit my ability to discern good choices
from bad ones considering I basically had no criteria to compare a good
from a bad CPA. Moreover I didn’t expect an accountant’s website to help
me judge whether they were good at what they do. Unlike web designers,
their job isn’t to maintain an attractive website.</p>

<p>My one hope laid in the book’s cover. Devoid of an ability to judge the
substance of something, appearances turn into a powerful signal. So I
loaded up a dozen of CPA websites. I filtered the ones with the highest
ratings on Yelp and the ones that appeared to be from my local area in
Google. I wanted to meet this person. I needed to be able to trust them.</p>

<p>Immediately I saw a barage of stock photography. Some woefully
inadequate for accounting matter. I spotted some obvious and
unimaginative WordPress themes which were poorly adapted to the task of
conveying trustworthiness and experience.</p>

<p>Then something strange happened. I found a beautiful website. Clear
navigation focused on what I wanted to know: who this person is, what
they do, why it matters, and why they should be trusted.</p>

<p>More importantly, there was a sense of taste pervading from the
site. You could question the choice of style, but it was unquestionably
applied by someone who knew what they were doing. It didn’t matter to me
whether this CPA built the site themselves or paid someone to do it. All
that mattered was that they cared. That told me a lot. The tone of the
website’s copy was concise, it was fresh. It made me want to trust them
because it wasn’t boilerplate and it wasn’t stuffy.</p>

<p>Now it’s possible that this website may have had a different effect on
someone older than me or someone from a less web-savvy background who
doesn’t respond to these cues because they have no special appreciation
for good typography, good copy, good content design. But I believe an
effect nonetheless. Even ill-equipped to measure professionalism, people
can smell it. They can feel it. I know I did.</p>

<p>After leaving a message using the contact form conveniently accessible
on the home page of the site, I received a phone call from the CPA
herself. She matched her cover perfectly. She was warm, professional,
sharp and before calling me she even did her homework by looking me up
based on the email address I purposefully used on the contact form. She
knocked it out of the park.</p>

<p>This <em>superficial</em> impression was later confirmed when I met her and the
rest of her team. I judged a book by its cover, and it was a damn good
book. This is not the first time it has worked out well for me: books,
music, restaurants, programming language communities, and even people.</p>

<p>It’s true that I’ve discovered bad books with great covers, but unless
I’m letting confirmation bias get the best of me, I’ve had more lucky
strikes than bad apples.</p>

<p>PS: Skeptics of this conclusion may delight in the fact that for whatever 
reason, a few after I started working with the CPA I mention in this post, 
they entirely ghosted me. I’m not sure if they went under, had an influx 
of much more profitable clients, a huge technical issue, or if something 
else happened. So my little anecdote took a hit. While I know some beautiful 
covers might hide nastiness, that doesn’t completely change my point of 
view on the signal that a well-crafted one sends.</p>
<img src="https://feed.olivierlacan.com/link/8226/15981872.gif" height="1" width="1"/>]]></description>
      <pubDate>Wed, 17 Dec 2014 21:20:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/15981872/the-cover-matters</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/the-cover-matters/</guid>
    </item>
    <item>
      <title>Pairing is the Potion</title>
      <description><![CDATA[<p>The way <a href="https://twitter.com/jbalauat">John</a> and I pair together works
like this. He’ll ask me a pointed question which will require some
thinking. John won’t rush me. Beyond the answer, he is looking to
understand how I think. I’m a programmer. He’s a sales person. Our
audience is composed of programmers. Whenever I have a chunk of free
time I’ll hop on <a href="https://screenhero.com/">Screenhero</a> with John so that
he can see my screen or me his. When we talk we often want to show each
other examples, context, articles to read and sites to visit. Through our
conversations John and I will take detours to talk about cognitive
science because we both love that.</p>

<p><a href="https://twitter.com/katiedelfin">Katie</a> is a programmer and a damn good
one. Yet we probably only write code together 15% of the time. Most of
the time we talk about code. We talk about interfaces. How names feel.
How things fit together. We get excited about deleting huge chunks of
code. We pause while I try to paraphrase something brilliant she just
said because the world needs to know and I must tweet it now.</p>

<p><a href="https://twitter.com/morganlaco">Morgan</a> is bothered by not
understanding something. When she wants to understand, at first I think:
“Sure, I know how that works. We can take a short detour so I can
explain that.”. Then I realize: “Shit, actually I have no idea how that
works. How the fuck have I never bothered to look into this?”. So we
pair. I can use the accumulated system knowledge I have and, with her,
come to a satisfying solution faster. Perhaps because she doesn’t know
yet where and what to look for. Yet, without her I would have never
looked. I owe her that fresh perspective. This renewed attention to
details that you often lose when so many things need fixing.</p>

<p><a href="https://twitter.com/joeltayl">Joel</a> is a linguistics nerd like me so
together we defy the adage that programmers suck at naming things.
That said, we sure talk about naming things a lot. When we pair,
I spend a lot of time making Joel comfortable with the fact that I have
<a href="http://themultilogue.com/episodes/3475-v0-0-3-no-idea-what-i-m-doing">no idea what I’m doing</a>
either. But we can figure it out together. What will benefit Joel from
pairing with me is discovering the connective tissue of my workflow that
you can’t really learn by reading programming books. I liken it to the
colloquialisms and slang I learned from TV shows and my friends while I
was on my way to become billingual. It can’t be taught, it can only be
experienced.</p>

<p>Knowing John, Katie, Morgan, and Joel better; understanding how they
think, what frustrates them, what they cares about, what makes them lose
sleep at night; that’s how we can all design and develop a better
interface to work with each other and build software for other real
human beings.</p>

<p>My kind of pairing is simple. It’s loose. All it takes a pair of people
working together to achieve something or simply to learn something from
each other.</p>

<p>We do not spend 100% of our time on task. Ever. If you think that’s a
waste of valuable company time then you don’t understand that the most
crucial pieces of the entire machine are the relationships between the
humans that keep it running.</p>
<img src="https://feed.olivierlacan.com/link/8226/8521063.gif" height="1" width="1"/>]]></description>
      <pubDate>Thu, 11 Dec 2014 10:41:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521063/pairing-is-the-potion</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/pairing-is-the-potion/</guid>
    </item>
    <item>
      <title>Optimizing the Wrong Code</title>
      <description><![CDATA[<p>Today I was going through some of our worst queries on <a href="http://www.skylight.io/r/YNE-Q1twTyT-">Skylight</a> and trying to find some <a href="http://en.wiktionary.org/wiki/low-hanging_fruit">low-hanging fruit</a> to improve performance with the least effort possible. I like Skylight because it’s a tool designed to reduce noise. Whenever you get into the optimization mindset, noise is your worst enemy. It turns the most innocent pursuit of necessary speed improvements into a rabbit hole chase of diminishing gains.</p>

<p>After a few successful optimizations for which I successfully <a href="https://tomafro.net/2009/08/using-indexes-in-rails-choosing-additional-indexes">added table indices and compound indices</a> to dramatically speed up some queries on very large tables, I found that our <a href="http://codeschool.com/users/olivierlacan">Report Card</a> had a ridiculously slow SQL query in it taking basically 50% of the request time.</p>

<p><img src="https://olivierlacan.com/assets/users-show-trace.png" alt="Request Trace from Skylight" /></p>

<p>Much to my surprise, that terribly slow (about 700 ms) query appeared very simple:</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="k">SELECT</span>  <span class="nv">"users"</span><span class="p">.</span><span class="o">*</span> <span class="k">FROM</span> <span class="nv">"users"</span>  <span class="k">WHERE</span> <span class="p">(</span><span class="nv">"users"</span><span class="p">.</span><span class="nv">"username"</span> <span class="k">ILIKE</span> <span class="o">?</span><span class="p">)</span> <span class="k">LIMIT</span> <span class="mi">1</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">ILIKE</code> is a Postgres-specific <a href="http://www.postgresql.org/docs/9.3/static/functions-matching.html">case insensitive <code class="language-plaintext highlighter-rouge">LIKE</code> comparison</a>.</p>

<p>Since I had spent so much time researching, analyzing, and implementing table <a href="http://english.stackexchange.com/a/3126">indices</a> my first instinct was to research the possibility of adding an index to this ILIKE clause and I did find some interesting information about using Postgres’ <a href="http://www.postgresql.org/docs/9.1/static/pgtrgm.html">Trigram extension</a> to make a relatively fast <a href="http://www.postgresql.org/docs/9.3/static/gin-intro.html">GIN index</a> on this relatively tricky clause.</p>

<p>I got started on adding a migration to our database to enable the pg_trgm extension in Postgres but remembered that database extension support was only <a href="https://github.com/rails/rails/pull/9203">added to Rails’ <code class="language-plaintext highlighter-rouge">schema.rb</code> files in Rails 4.0</a> and for now at least we’re still running a patched Rails 3.2 so I wouldn’t be able to make this migration portable without switching to a <code class="language-plaintext highlighter-rouge">structure.sql</code> file which is a nope.</p>

<p>Then to clear my mind a little bit I searched for the line of code that was triggering this rogue query.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="no">User</span><span class="p">.</span><span class="nf">where</span><span class="p">(</span><span class="no">User</span><span class="p">.</span><span class="nf">arel_table</span><span class="p">[</span><span class="ss">:username</span><span class="p">].</span><span class="nf">matches</span><span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="ss">:id</span><span class="p">])).</span><span class="nf">first</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now, I understand that using hardcoded SQL strings in Rails feels weird. That said — and I’ll admit I forgot what I base this opinion on — I consider Arel a private Rails API. It may not change often and unpredictably but I will treat it as if can. Harcoded SQL strings on the other hand are unlikely to surprisingly break with no deprecation notice. I’m aware someone could extend this line of argument to say mean things about ActiveRecord but I think that’s silly. ActiveRecord has an API and when it changes we generally tend to hear about it ahead of time.</p>

<p>What really bothers me here is that this <code class="language-plaintext highlighter-rouge">User.arel_table[:username].matches(params[:id])</code> is completely obfuscating the <code class="language-plaintext highlighter-rouge">ILIKE</code> statement it generates. If you don’t call <code class="language-plaintext highlighter-rouge">to_sql</code> on this thing, or see the full SQL output in your console or on something like Skylight, you won’t notice it’s doing something potentially very slow.</p>

<p>And then it hit me. Why the hell were we doing an <code class="language-plaintext highlighter-rouge">ILIKE</code> query? If a user matches the username in a URL, it should be displayed. It’s not like the goal of this action was to display usernames that start with <code class="language-plaintext highlighter-rouge">params[:id]</code> and maybe end with something else like a <code class="language-plaintext highlighter-rouge">where("username ILIKE ?", "#{params[:id]}%")</code> would. No this was purely focused on dealing with the problem of case. If someone typed in <code class="language-plaintext highlighter-rouge">OlivierLacan</code> we want to look for the username <code class="language-plaintext highlighter-rouge">olivierlacan</code> or <code class="language-plaintext highlighter-rouge">OLIVIERLACAN</code> or <code class="language-plaintext highlighter-rouge">OlIvIeRlAcAn</code>.</p>

<p>We could use <code class="language-plaintext highlighter-rouge">User.where("lower(username) = ?", id.downcase).first</code> instead and considering we already have an index on the <code class="language-plaintext highlighter-rouge">username</code> column this would be much faster. In the best cases that would take the query down to 270 ms.</p>

<p>That’s when I remembered that we had an internal column named <code class="language-plaintext highlighter-rouge">system_username</code> where we simply lowercase the <code class="language-plaintext highlighter-rouge">username</code> column every time it’s updated. That meant I could let Ruby deal with the (easy) job of downcasing a string:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="no">User</span><span class="p">.</span><span class="nf">where</span><span class="p">(</span><span class="ss">system_username: </span><span class="n">params</span><span class="p">[</span><span class="ss">:id</span><span class="p">].</span><span class="nf">downcase</span><span class="p">)</span>
<span class="c1"># or</span>
<span class="no">User</span><span class="p">.</span><span class="nf">find_by_system_username</span><span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="ss">:id</span><span class="p">].</span><span class="nf">downcase</span><span class="p">)</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Query speed? 1 milisecond. Instead of optimizing the database for inefficient code, I ended up rewriting the code to be less silly and take advantage of prior optimizations we had (thankfully) done. I didn’t have to install a Postgres extension usually reserved for full-text search, and — more importantly — I didn’t have to create a potentially costly index on an operation (the case insensitive comparison) that ended up being unnecessary.</p>

<p>PS: I’ll be following this post up with a new one detailing my methodology with the more indexing-focused performance optimizations I mentioned at the beginning. If you have any tips and tricks in your toolbag, please send me a quick email to let me know so I don’t look silly. Here are <a href="https://gist.github.com/olivierlacan/dc56a96bb2fd3742db5b">some of mine</a>.</p>
<img src="https://feed.olivierlacan.com/link/8226/8521064.gif" height="1" width="1"/>]]></description>
      <pubDate>Thu, 23 Oct 2014 07:46:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521064/optimizing-the-wrong-code</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/optimizing-the-wrong-code/</guid>
    </item>
    <item>
      <title>The 'Little Things'</title>
      <description><![CDATA[<p>When I have a conversation with a fellow programmer — and they know that I’m a programmer too — the tone of the conversation is adjusted to exclude explanations of commonly understood concepts.</p>

<p>They assume I know about variables, functions, objects, caching, blocks (or closures), loops, and flurry of other programming concepts. I do know about these concepts, at least I think I do. There’s a good chance I would be challenged if I had to explain each and everyone of these concepts succinctly and clearly to someone with no prior knowledge.</p>

<p>Knowing how to use stuff is easy, knowing how stuff works and how to explain it to someone else is much, much harder. Regardless, as a caucasian male programmer, I benefit from the assumption that I must know about this stuff. No explaining necessary<sup id="fnref:1" role="doc-noteref"><a href="https://olivierlacan.com#fn:1" class="footnote" rel="footnote">1</a></sup>.</p>

<p>Have you seen a group of programmers talk to a woman who happens to share their occupation recently? If not I suggest you crank up your awareness. Solely due to gender, many programmers will disqualify female programmers from the assumptions I benefit from. Suddenly it becomes “only fair” to ask someone you just met whether they “know how blocks work, right?”.</p>

<p>It’s really fucked up because it’s utterly insidious. What’s really happening there is that dudes have a positive bias towards other dudes. They’re overcompensating. Although I can’t deny that there must be many cases of blatant sexism and superiority complex leveled against women, what I believe to be happening is that when talking to fellow female programmers, men are indeed being as fair as they can be. They don’t make any assumptions. But making assumptions that other guys “know their stuff” is almost second nature.</p>

<p>I’ll admit that I’m simplifying. In many cases (I hope female programmers can testify to this themselves, it’s not really my place to speak for them) these “fair” conversations devoid of any assumptions are laden with blatant condescension and other unsubtle cues. These act like rocket boosters to propel women into a place where they’re made to feel like outsiders, like they don’t belong here.</p>

<p>It’s your responsibility as a professional to call out this bullshit as it happens. If a co-worker suddenly changes their tone when talking to someone of the opposite gender or from a different ethnic background as them. If what used to be a conversation seems to almost imperceptibly shift towards a lecture.<sup id="fnref:2" role="doc-noteref"><a href="https://olivierlacan.com#fn:2" class="footnote" rel="footnote">2</a></sup>  It’s very difficult for someone who’s being put down to call out the person putting them down. Often the offense seems too small to warrant a remark.</p>

<p>Sadly these “little things”  — as Anthony Colangelo described them in <a href="http://themultilogue.com/episodes/4663-v0-0-6-groupthink-to-the-max">a recent episode of The Multilogue</a> — do a lot of damage. They’re not as obviously reprehensible as sexual harassment. It’s far too common for people submitted these “little things” to dismiss them and keep their anger to themselves because there are worse problems to be dealt with. The “little things” quickly add up. It’s past time we crush them down before they turn into big things. A single woman leaving the industry because she was made to feel constantly out of place is a tragedy for our industry, and our society.</p>

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1" role="doc-endnote">
      <p>Philip Guo talks about this in detail in <a href="http://pgbovine.net/tech-privilege.htm">Silent Technical Privilege</a> and refers what I call “little things” here as <a href="http://en.wikipedia.org/wiki/Microinequity">“micro-inequities”</a>. <a href="https://olivierlacan.com#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:2" role="doc-endnote">
      <p>I believe this is the textbook definition of <a href="http://en.wikipedia.org/wiki/Mansplaining">“mansplaining”</a>. <a href="https://olivierlacan.com#fnref:2" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>
<img src="https://feed.olivierlacan.com/link/8226/8521065.gif" height="1" width="1"/>]]></description>
      <pubDate>Fri, 26 Sep 2014 23:20:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521065/the-little-things</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/the-little-things/</guid>
    </item>
    <item>
      <title>The Semantics of Software</title>
      <description><![CDATA[<p>Jeremy Ashkenas shared some <a href="https://gist.github.com/jashkenas/cbd2b088e20279ae2c8e">counter-current thoughts about Semantic Versioning</a> recently.</p>

<p>You should read his entire piece. It’s very enlightening to hear the frustrations of a major open source project maintainer, there’s always a lot to learn about how we could improve things.</p>

<h2 id="unsemantic-versioning">Unsemantic Versioning</h2>

<p>Jeremy’s gripes are quite valid. It is hard for maintainers to figure out how to communicate about possible breaking changes using merely a number. You want people to not be too afraid of upgrading otherwise you’d have to maintain very old version of your software for decades, yet you want them to be aware of what could break when they do upgrade. It’s hard to get right, but I don’t believe that makes Semantic Versioning entirely worthless. I wish we could learn to voice our concern about problems without threatening to move to another country.</p>

<p>Versioning and change-logging go hand in hand. Versions are much more machine-oriented, or at least they’re much more superficial ways to communicate meaning. Change logs, however, offer essential context about versions so that — regardless of whether the maintainers of the project adhere to <a href="http://semver.org">Semantic Versioning</a> or not — you (the open source software user) can know what they mean by <code class="language-plaintext highlighter-rouge">version 2.0.0</code>:</p>

<ul>
  <li>Does it introduce a major API rewrite? Check the CHANGELOG.</li>
  <li>Does it reflect the introduction of a single (but important) breaking change in the <code class="language-plaintext highlighter-rouge">1.x</code> branch? Check the CHANGELOG.</li>
  <li>Does it mean that — despite the lack of a breaking change — a sufficient amount of new features were introduced to warrant opening a new “version chapter”. Check the CHANGELOG.</li>
</ul>

<p>Yes, semantic versioning numbers have low resolution. They can be ambiguous. They can be unclear. This why I believe it’s so essential that maintainers make it a priority to a keep a thorough CHANGELOG. I don’t think you can encode three dot-separated numbers with clearer meaning that actual human language.</p>

<h2 id="numbers--language">Numbers + Language</h2>

<p>Over the past few months I’ve been working on guidelines to improve how we log changes in open source projects. I called it <a href="http://keepachangelog.com">keepachangelog.com</a> because I’ve noticed that it’s surprisingly common for some popular projects to not even have a change log.</p>

<p>I don’t mean to pretend that I walked back from the mountain with truth-bearing tablets. I’m asking for <a href="https://github.com/olivierlacan/keep-a-changelog/issues">help and feedback</a> from the community. That’s because the best guidelines — as with science — are based on consensus.</p>

<p>I don’t really want everyone to agree on what a change log’s filename should be (it’s CHANGELOG, deal with it). No, what I want is to gather the most common and sensible change-logging practices and try to get as many people to use them — reliably, consistently, predictably, boringly.</p>

<p>What I do want is for us to improve open source user experience. I’d like to bias the change log conventions towards sensible practices instead of popular or entrenched practices. Sayings like “we’ve always done it this way” and “everybody else does it that way” are noxious. I want to end the practice of periodically dumping git logs diffs into a file and calling that CHANGELOG. It’s useless handwaving and it’s an insult to users and contributors alike.</p>

<h2 id="badly-breaking">Badly Breaking</h2>

<p>Now, to get back to versioning, it sucks when <a href="https://github.com/jashkenas/underscore/issues/1805">tons of things stop working because one library changes its API just enough to cause breakage</a>. Yep, it’s a great opportunity for us to have a much-needed conversation about how we communicate <strong>about</strong> our open source software. As mentioned on <a href="http://5by5.tv/changelog/127">The Changelog</a>, the idea that open source software is a gift to the world can be dangerous.</p>

<p>Publishing open source software is not virtuous in vacuum. There are many parts to a praise-worthy open source project :</p>
<ul>
  <li>defined use cases</li>
  <li>installation steps</li>
  <li>usage examples</li>
  <li>sensible versioning</li>
  <li>bug reporting infrastructure</li>
  <li>contribution guidelines</li>
  <li>clear licensing</li>
  <li>thorough change log</li>
  <li>up-to-date documentation</li>
  <li>reasonable test suite</li>
</ul>

<p>Notice how I haven’t even mentioned the actual software? Ask any open source maintainer what they spend most time doing or worrying about? I’d be surprised if many said “the software itself”.</p>

<p>The guidelines I’ve established on <a href="http://keepachangelog.com">keepachangelog.com</a> are based on my experience as a developer. For the past two years I’ve been working on a now <a href="https://codeschool.com">nearly four-years old Rails application</a>. We have 76 direct production dependencies on the Ruby side alone. Yes, that is a lot. And those dependencies often have their own dependencies. While we try to spend most of time producing things of value for our customers, I’ve been doing my best to keep these dependencies up-to-date for security releases. But of course we’ve also had to fight dependency rot<sup id="fnref:1" role="doc-noteref"><a href="https://olivierlacan.com#fn:1" class="footnote" rel="footnote">1</a></sup> or simply upgrade smaller dependencies whenever we’ve decided it was worthwhile for us to upgrade one of our Alpha dependencies<sup id="fnref:2" role="doc-noteref"><a href="https://olivierlacan.com#fn:2" class="footnote" rel="footnote">2</a></sup>.</p>

<p>This all means that I’ve been spending a <strong>lot</strong> of time upgrading things, fixing things that minor (or even patch) versions shouldn’t have broken, searching in vain for CHANGELOGs. This has recently become an easier task thanks to <a href="http://gemnasium.com">Gemnasium</a> but it’s still very difficult, time consuming, and more importantly it’s time I can spend producing software for our customers.</p>

<p>Should we not have this many dependencies? Sure. Yet, I’d rather take a chance on community-maintained libraries rather than betting that our small team (four people) can produce and maintain some software we have little expertise over (but need regardless). That feels like a much more safer bet, at least for now.</p>

<p>Let’s all try to make our open source project more mindful of their end-users. For instance by offering better information (or <a href="http://shields.io/">metadata</a>) about the projects themselves. I don’t think I’d be the only grateful one around if we infused more meaning in our software.</p>

<h2 id="resources">Resources</h2>
<p>Here’s a list of interesting projects I’ve gathered recently and which can help you as an open source contributor improve how your project documents and communicate about changes:</p>

<ul>
  <li><a href="http://semver.org">Semantic Versioning</a></li>
  <li><a href="https://github.com/jonathanong/ferver/">Fear-Driven Versioning</a></li>
  <li><a href="http://gemnasium.com/">Gemnasium</a> and <a href="https://github.com/tech-angels/vandamme">Vandamme</a> (the CHANGELOG parser they use)</li>
  <li><a href="https://github.com/piwik/github-changelog-generator">GitHub Changelog Generator</a></li>
  <li><a href="https://github.com/securactive/gitchangelog">gitchangelog</a></li>
  <li><a href="https://github.com/rpflorence/rf-changelog">rf-changelog</a></li>
</ul>

<p>If you are aware of more (or better) tools that can help maintainers and contributors produce higher quality change logs, please send me a note and I’ll update this list.</p>

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1" role="doc-endnote">
      <p>Dependency rot happens when you inevitably bet on the wrong horse and one of your dependencies ends up either unmaintained (and eventually incompatible with other evolving dependencies) or poorly maintained. <a href="https://olivierlacan.com#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:2" role="doc-endnote">
      <p>Alpha dependencies being major things like Ruby, Rails, jQuery, PostgreSQL,  or even Sass. <a href="https://olivierlacan.com#fnref:2" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>
<img src="https://feed.olivierlacan.com/link/8226/8521066.gif" height="1" width="1"/>]]></description>
      <pubDate>Sat, 30 Aug 2014 12:15:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521066/the-semantics-of-software</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/the-semantics-of-software/</guid>
    </item>
    <item>
      <title>Jumping between words in the console</title>
      <description><![CDATA[<p>There are many obvious ways to waste one’s time, and there are the less
obvious ones. Let’s talk about the latter.</p>

<p>One of the first thing I notice when pairing with co-workers and friends
is whether or not they have what is often described as “option as meta
key” enabled in their Shell app.</p>

<p>Even in a basic text editor like OS X’s TextEdit, whenver you type words
separated by spaces, you can easily jump to the beginning of each word by
using the <code class="language-plaintext highlighter-rouge">Option</code> key alongside with either the <code class="language-plaintext highlighter-rouge">Left</code> or <code class="language-plaintext highlighter-rouge">Right</code> arrow
keys. Nothing amazing, maybe you think this is neat.</p>

<p><img src="https://olivierlacan.com/assets/flying-between-words.gif" alt="Flying between words in TextEdit" /></p>

<p>Well, inside of a Shell, you often can’t use your mouse to place your
cursor wherever you wish. This seems backwards (because it is) but it’s
a remnant of a world where the mouse didn’t exist. Regardless, many
developers eschew the mouse altogether for the sake of keyboard
efficiency. Yet it seems like few developers realize that this fast
jumping between words is also possible in their Shell.</p>

<h2 id="terminal">Terminal</h2>

<p>On OS X, in the default Terminal app, when you open Preferences (please
use <code class="language-plaintext highlighter-rouge">Command</code> + <code class="language-plaintext highlighter-rouge">,</code> to do that in any OS X app worth its salt) and go to
the <code class="language-plaintext highlighter-rouge">Settings</code> tab, under <code class="language-plaintext highlighter-rouge">Keyboard</code> you will find a checkbox named
<code class="language-plaintext highlighter-rouge">Use option as meta key</code>.</p>

<p><img src="https://olivierlacan.com/assets/terminal-option.png" alt="Terminal Option as meta key setting" /></p>

<p>Enabling this option will let you fly between
words with your arrow keys when holding <code class="language-plaintext highlighter-rouge">Option</code>.</p>

<p>You’re welcome.</p>

<p><img src="https://olivierlacan.com/assets/still-flying-between-words.gif" alt="Flying between words in Terminal" /></p>

<h2 id="iterm">iTerm</h2>

<p>And if you’re one of those fancy cats using iTerm, the process is a bit
more involved. Go to <code class="language-plaintext highlighter-rouge">Preferences</code> (you better be using <code class="language-plaintext highlighter-rouge">Command</code> + <code class="language-plaintext highlighter-rouge">,</code>
this time), under the <code class="language-plaintext highlighter-rouge">Keys</code> tab. In there you’ll see a list of
<code class="language-plaintext highlighter-rouge">Global Shortcut Keys</code>. You’ll need to add the following two global
shortcuts.</p>

<h3 id="jumping-left">Jumping Left</h3>

<p><img src="https://olivierlacan.com/assets/iterm-option-left.png" alt="iTerm Setting to Jump Left" /></p>

<p>Hold the <code class="language-plaintext highlighter-rouge">Option</code> and <code class="language-plaintext highlighter-rouge">Left Arrow</code> keys in the <code class="language-plaintext highlighter-rouge">Keyboard Shortcut</code>
input field, then select the <code class="language-plaintext highlighter-rouge">Send Escape Sequence</code> Action, and finally
set the <code class="language-plaintext highlighter-rouge">Esc+</code> field to <code class="language-plaintext highlighter-rouge">B</code> (for back).</p>

<h3 id="jumping-right">Jumping Right</h3>

<p><img src="https://olivierlacan.com/assets/iterm-option-right.png" alt="iTerm Setting to Jump Right" /></p>

<p>Hold the <code class="language-plaintext highlighter-rouge">Option</code> and <code class="language-plaintext highlighter-rouge">Right Arrow</code> keys in the <code class="language-plaintext highlighter-rouge">Keyboard Shortcut</code>
input field, then select the <code class="language-plaintext highlighter-rouge">Send Escape Sequence</code> Action, and finally
set the <code class="language-plaintext highlighter-rouge">Esc+</code> field to <code class="language-plaintext highlighter-rouge">F</code> (for forward).</p>

<p>You’ll see a warning whenever you save those shortcuts. I believe it’s
okay to ignore these unless you already use a keyboard shortcut profile
that has the same combinations of keys. In this situation you will have
to delete your Profile-specific shortcuts otherwise they will override
the global ones presented below, otherwise this won’t work as expected.</p>

<p><img src="https://olivierlacan.com/assets/iterm-shortcut-warning.png" alt="iTerm Global Shortcut Warning Prompt" /></p>

<p>This optimization is an example of something you can apply to your life
every single day. What task or step of a task are you repeating over and
over again. Have you tried to find a better, faster way to do it?</p>

<p>It it seems too difficult? What about working with someone by your side
(pairing) and asking them if they have a solution, perhaps? Every single
time I pair with someone on our team at <a href="http://codeschool.com">Code School</a>
I learn something new like this.</p>

<p>What I like even more is that these tricks don’t always correlate with
experience. Many people with experience settle for inefficient workflows
because they’ve become comfortable with them. Sometimes, that’s fine.
Changing a workflow that works can be a distraction. More often though,
you can chip away at the little frustrations of your day and hone your
tools little by little, until you master them.</p>

<p>PS: If this topic interests you I highly recommend listening the
<a href="http://rubyrogues.com/129-rr-sharpening-tools-with-ben-orenstein/">Sharpening Tools episode of the Ruby Rogues podcast</a>
with <a href="https://twitter.com/r00k">Ben Orenstein</a>. His daily ritual to find
something inefficient from the days or weeks before and search for a way
to optimize it is an excellent idea.</p>
<img src="https://feed.olivierlacan.com/link/8226/8521067.gif" height="1" width="1"/>]]></description>
      <pubDate>Wed, 20 Aug 2014 00:33:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521067/jumping-between-words-in-the-console</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/jumping-between-words-in-the-console/</guid>
    </item>
    <item>
      <title>The Greatest Lie</title>
      <description><![CDATA[<p>The greatest lie we tacitly perpetuate as programmers is that somehow,
one day, with enough experience, it’s possible for someone to stop
writing code that creates bugs.</p>

<p>If you believe this because someone told you: they are wrong. If you
believe this because you really want to: please stop.</p>

<p>This idea of evolving above bugs is a very dangerous because it creates
an unrealistic expectation. Worse, I see many eager programming
beginners (many of them our own students at Code School) subscribe to
this idea. I’m sure they believe it’s a manifestation of healthy
optimism in their ability to improve as a programmer. It’s not.</p>

<p>Thinking there are such things as programming superheroes that are ten
times faster than everybody else and yet somehow leave an equal or
smaller amount of bug in their wake is a delusion. These so-called “10X”
programmers don’t exist. It’s akin to believing that
magicians can really make objects disappear out of thin air.</p>

<p>They can’t. It’s a trick. There is always a trick. The biggest trick of
all is the one you play on yourself when you rule out the obvious truth:
you cannot fathom how much time these people have spent practicing,
failing, hating themselves, trying again and eventually succeeding at
fooling you. Penn &amp; Teller aren’t supernatural, their dedication to
deception simply borders on  mental illness.</p>

<p>You actually don’t want to know what their secret is. That’s because you
already know it and you don’t want to accept it. They work very very
hard. Harder than you can imagine, and for something you may deem an
utter waste of a human life. And they do that because they like it. I
could say it’s their passion but as a few people (Avdi Grimm) in the
tech industry have aptly pointed out recently, passion is something
lovers and parents feel. Dedication feels like a better word. I’m sure
Penn &amp; Teller like their job a lot but I’m also convinced that there are
times when they hate it too. Saying workers have to be passionate is
dangerous because passion tends to smooth over things that shouldn’t be
acceptable at work.</p>

<p>With programmers, the trick is similar. Whatever unreasonable amount of
time it would take to perfectly understand how — for example — HTTP
caching works, there exists people who have spent those hours patiently
learning when I really don’t feel like doing that. It’s easy and frankly
unfair for me to call these people geniuses and wizards. When compared
to my baseline laziness, a lot of people qualify for the genius status.
Yet all they’ve done is read code I assumed was probably too hard to
understand.</p>

<p>Maybe you told yourself you had too much work to do and couldn’t justify
spending time learning about something you didn’t understand. You looked
for an easier answer elsewhere. Maybe on <a href="http://stackoverflow.com">Stack
Overflow</a>, or in a blog post that matches your
precise problem better. Those are useful solutions and I regularly use
them myself, but they’re not answers.</p>

<p>An answer or a proof in Math (a subject I nearly failed high school for)
is something that displays your clear understanding of the problem at
hand and the path you took to achieve a given solution. Even though I
hated Math in school (mostly because I disliked school in general), I
remember how virtuous that seemed to me. Many students see it as an
annoying deterent to cheating, and that seems appropriate.</p>

<p>Finding the solution is something most people can do, even with limited
time. Finding the answer requires patience, attention to detail and
critical thinking.</p>
<img src="https://feed.olivierlacan.com/link/8226/8521068.gif" height="1" width="1"/>]]></description>
      <pubDate>Mon, 28 Jul 2014 22:11:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521068/the-greatest-lie</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/the-greatest-lie/</guid>
    </item>
    <item>
      <title>There is no such thing as magic.</title>
      <description><![CDATA[<blockquote>
  <p>“So this is, like, if I took a spaceship to Titan — the moon of
Jupiter — and I saw Taco Bell there, I’d be like: ‘No.’”.</p>
</blockquote>

<p>This comes from a conversation I had while pairing the other day. Let me
bring in some context. I had showed Morgan — the newest member of our
Internal Code School team — how awesome Bash autocompletions are inside
a shell session, especially when dealing with unfamiliar file names.</p>

<p>For example you want to <code class="language-plaintext highlighter-rouge">cd</code> into a folder called <code class="language-plaintext highlighter-rouge">banana</code>, all you have
to do is type <code class="language-plaintext highlighter-rouge">cd bana</code> then hit the <code class="language-plaintext highlighter-rouge">Tab</code> key and tadaaa it suddenly
morphs into <code class="language-plaintext highlighter-rouge">cd banana/</code> before your very eyes.</p>

<p>Morgan and I had to debug a spec in which we put a <code class="language-plaintext highlighter-rouge">binding.pry</code> call
from the excellent <a href="http://pryrepl.org/">Pry gem</a> in order to stop
execution and fumble around to figure out why a specific test was
behaving oddly. We had defined a <code class="language-plaintext highlighter-rouge">user</code> variable and I asked morgan to
call a method on that <code class="language-plaintext highlighter-rouge">ActiveRecord</code> instance this variable was pointing
too. As she started to type out the full method name I think I sneakily
hit her Tab key with the swiftness of a famished Fox.</p>

<p>To my surprise, Morgan wasn’t happy about this at all. Her response was:</p>

<blockquote>
  <p>“No.”</p>
</blockquote>

<p>She didn’t say that because this little trick wasn’t cool. She didn’t
say it because it wasn’t useful. She didn’t say it because it’s kind of
a dick move to take over your pair’s keyboard — it is — while pairing.
She said “No.” because she didn’t understand how the Pry session could
possibly allow her to do this: use autocompletion on a Ruby object’s
methods.</p>

<p>After laughing (a lot) she used the sentence I started this post with to
help me understand how she felt. Aside from being hilarious, it was a
very good example. Magic (in the context of programming) isn’t cool,
it’s simply useful — sometimes. What’s really cool, and I bet Morgan
would agree with me, is how what appears to be magic actually works.
Because there is no such thing as magic.</p>

<p>Do you think I took the time to explain to Morgan how this awesome
method autocompletion trick works? Nope. Why? Well, I had no idea how it
worked.</p>

<p>Now, thanks in part to a great blog post by Ross Kaff — <a href="http://rosskaff.com/blog/2014/02/ruby,-you-autocomplete-me.html">Ruby, You
Autocomplete Me</a> — I do understand how it works. So I thought I’d
share it with you too.</p>

<p>Guess what?
It’s definitely not magic. Ross’ post didn’t fully satisfy my
curiosity so I ended up looking at the <code class="language-plaintext highlighter-rouge">IRB::InputCompletor</code> <a href="https://github.com/ruby/ruby/blob/trunk/lib/irb/completion.rb">source
code in
Ruby</a> and
it was illuminating.</p>

<p>This is one of the few times in my life when — despite being a Ruby
programmer — I have looked at the actual Ruby source
code to understand how something works. Every time I discover coding
conventions I’m either not familiar with or didn’t expect to find there.</p>

<p>What’s amusing when you start [unweaving the magic rainbow]
(http://en.wikipedia.org/wiki/Unweaving_the_Rainbow) is that you
discover how simple things actually are.</p>

<p><code class="language-plaintext highlighter-rouge">IRB::Completion</code> uses a gigantic <code class="language-plaintext highlighter-rouge">case</code> statement against the inputed
text on which completion is attempted. So if you run <code class="language-plaintext highlighter-rouge">pry</code><sup id="fnref:3" role="doc-noteref"><a href="https://olivierlacan.com#fn:3" class="footnote" rel="footnote">1</a></sup> and type:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="s2">"Howdy"</span><span class="p">.</span><span class="nf">rev</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>And hit the <code class="language-plaintext highlighter-rouge">Tab</code> key, it will complete to <code class="language-plaintext highlighter-rouge">"Howdy".reverse</code>. Why?</p>

<ol>
  <li>the input before you hit the <code class="language-plaintext highlighter-rouge">Tab</code> key starts with a double quote
which means <code class="language-plaintext highlighter-rouge">IRB::Completion</code>’s <a href="https://github.com/ruby/ruby/blob/trunk/lib/irb/completion.rb#L44">first <code class="language-plaintext highlighter-rouge">when</code> statement</a> catches it.</li>
  <li>the <a href="https://github.com/ruby/ruby/blob/trunk/lib/irb/completion.rb#L46"><code class="language-plaintext highlighter-rouge">receiver</code></a> (first match returned by <a href="https://github.com/ruby/ruby/blob/trunk/lib/irb/completion.rb#L44">the regular expression</a>) is
saved to a variable using the <code class="language-plaintext highlighter-rouge">$1</code> global variable<sup id="fnref:1" role="doc-noteref"><a href="https://olivierlacan.com#fn:1" class="footnote" rel="footnote">2</a></sup>.</li>
  <li>the third match from the regular expression (the second one being the
<code class="language-plaintext highlighter-rouge">.</code> separating the receiver from method (or method call) is saved to
the <a href="https://github.com/ruby/ruby/blob/trunk/lib/irb/completion.rb#L47"><code class="language-plaintext highlighter-rouge">message</code></a> variable.</li>
  <li>Using one of my favorite bit of Ruby introspection, all the possible
instance methods available<sup id="fnref:2" role="doc-noteref"><a href="https://olivierlacan.com#fn:2" class="footnote" rel="footnote">3</a></sup> to the String class are collected (an
alias of the <code class="language-plaintext highlighter-rouge">Enumerable#map</code> method) into a <code class="language-plaintext highlighter-rouge">candidates</code> array.</li>
  <li>The <a href="https://github.com/ruby/ruby/blob/trunk/lib/irb/completion.rb#L216-L226"><code class="language-plaintext highlighter-rouge">select_message</code></a> class method is called with the
<code class="language-plaintext highlighter-rouge">receiver</code>, <code class="language-plaintext highlighter-rouge">message</code>, and <code class="language-plaintext highlighter-rouge">candidates</code> in order to determine what
methods should be suggested for completion.</li>
</ol>

<p>That’s it. All the possible candidate methods will now be displayed in
the console as completion suggestions when you hit the <code class="language-plaintext highlighter-rouge">Tab</code> key twice.
If there is only one match, hitting the <code class="language-plaintext highlighter-rouge">Tab</code> key once will complete the
method name using that match.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="s2">"Howdy"</span><span class="p">.</span><span class="nf">reverse</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><img src="https://olivierlacan.com/assets/tadaaa.gif" alt="Tadaaa!" /></p>

<p>Having people with different skill levels and backgrounds on our team
has been a perfect opportunity for me to rediscover the things that I
take for granted. When you’re new it’s often difficult (but not
impossible) to understand how some of the things you use work. There are
many tools I grown comfortable using and yet I don’t fully understand
how they work. As I hope I’ve demonstrated, it doesn’t take very long to
understand how the tricks are done.</p>

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:3" role="doc-endnote">
      <p>If you really don’t want to use Pry you can turn on IRB completion by either calling <code class="language-plaintext highlighter-rouge">require 'irb/completion'</code> or <a href="http://stackoverflow.com/a/1382216/385622">adding a few settings to an <code class="language-plaintext highlighter-rouge">~/.irbrc</code> file</a>. <a href="https://olivierlacan.com#fnref:3" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:1" role="doc-endnote">
      <p>You can see all global variables by running <code class="language-plaintext highlighter-rouge">puts global_variables</code> or <a href="https://github.com/ruby/ruby/blob/trunk/lib/English.rb#L147-L153">read some more Ruby source code documentation</a> to understand all that the global variables can do. <a href="https://olivierlacan.com#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:2" role="doc-endnote">
      <p>Including instance methods from any ancestor class to String (i.e. classes String inherits from and which you can inspect by calling <code class="language-plaintext highlighter-rouge">String.class.ancestors</code>) <a href="https://olivierlacan.com#fnref:2" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>
<img src="https://feed.olivierlacan.com/link/8226/8521069.gif" height="1" width="1"/>]]></description>
      <pubDate>Wed, 09 Jul 2014 14:51:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521069/there-is-no-such-thing-as-magic</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/there-is-no-such-thing-as-magic/</guid>
    </item>
    <item>
      <title>Bose Mode</title>
      <description><![CDATA[<p>My friend Anthony Colangelo and I just recorded the third episode of <a href="http://themultilogue.com">our
new podcast</a> on Monday. Anthony’s the kind of
guy I could have hourlong phone conversations with on anything and it would
be the most entertaining thing ever.</p>

<p>While he was retelling a memorable moment, Anthony reminded me of a funny
little concept we came up with while we were studying at Full Sail University:
Bose Mode.</p>

<p>Although Bose inarguably makes the best noise canceling headphones and
earbuds on the planet, this moniker wasn’t really meant as an endorsement.
When this concept emerged, I think we were at the beginning of the second
third of our academic path. This meant that regardless of prior knowledge
everyone in our class had by this point acquired a hefty amount of knowledge.</p>

<p>With the acquisition of knowledge comes an odd phenomenon: it becomes much
more intricate to accomplish something that involves that knowledge. I want
to pause here to emphasize the fact that I’m not saying it’s harder, because
that’s not true. Knowledge should give you the tools to solve problems more
easily, but there’s another edge to that sword.</p>

<p>When taught properly, knowledge is often accompanied with wisdom. I would define
wisdom as the humility to appreciate the extent of one’s ignorance. It’s
almost a trope but the more you know, the more you realize how much you
don’t know and have yet to learn.</p>

<p>I think a byproduct of knowledge and wisdom is <em>thoughtfulness</em>.
It can help you make fewer rash decisions by encouraging you to spend
more time weighing the variables at stake when solving a problem.</p>

<p>In order to weigh variables, you need to be able to hold them all in your
mind at the same time. This is why being a judge must be excruciating.</p>

<p>In this industry of what people sometimes refer to as “knowledge work”,
there is an almost unstated understanding that what we refer to as “flow”
is the state of mind required in order to make thoughftul decisions while
weighing all the necessary variables.</p>

<p>When I try to explain this process to outsiders, I often use a computer
as a metaphor — which seems fitting. In order to compute, a computer often
needs to download data before it can even parse and analyze it. This is
exactly what I believe flow helps “knowledge workers” like programmers
and designers achieve. Slowly at first, faster as time elapses, we start
placing all the facts about a problem at the forefront of our mind — our
<a href="http://en.wikipedia.org/wiki/Random-access_memory">Random-access memory</a>.</p>

<p>The reason Bose Mode is so crucial is because any interruption, any loss
of focus during such a critical phase means starting from scratch may be
necessary. At the very least you will need to retrace your steps
in order to make sure you didn’t lose an important fact due to the
interuption. When electrical current stops flowing through a computer’s
RAM, all the information it contained is irretrievably lost. That’s
because RAM is <em>volatile memory</em>, unlike the <em>non-volatile</em> memory of a
hard drive or SSD. I find the similarity between humans and machines here
striking.</p>

<p>Physically isolating yourself from the sounds of the world is a way to
achieve flow which doesn’t rely on the courtesy or cooperation of others.
During my time at Full Sail, I’ve managed to achieve flow in a busy Firehouse
Subs restaurant at rush hour while sitting under a TV blasting ESPN’s SportCenter.
All this thanks to my pair of noise canceling headphones and a base layer of
lyric-less music<sup id="fnref:1" role="doc-noteref"><a href="https://olivierlacan.com#fn:1" class="footnote" rel="footnote">1</a></sup> that didn’t subtract from my attention. The advantage
of “Bose Mode” is that most actively noise canceling heaphones have an LED
which shows whether the noise canceling mode is on. This can act as a mild
deterrent to interruptions if people notice that not only you have headphones
on, but you’re clearly trying to block out external noise as well.</p>

<p>If you talk to any programmer who travels regularly, ask them what they
do on a plane. On flights with no Internet access available, a roomful of
strangers in the sky with the right pair of headphones can encourage rare
feats of concentration and complex problem-solving. Thanks to Bose Mode, you
will also barely even notice the heavy hum of the plane’s engines.</p>

<p>All in all I’d encourage any “knowledge worker” to be aware of how
volatile their optimal state of mind to achieve productive work is.
You don’t need to receive a popup notification and sound whenever an
email comes in. You don’t need to see a little badge number increment on
your phone for that either. Email is not chat, it should be able to wait
at least a few hours. If you have urgent email, then simply check it
more often. At least you’ll be doing that on your own schedule and not be
at the mercy of other people’s schedule.</p>

<p>Start using great isolation features like OS X and iOS’s Do Not Disturb
modes. On OS X, hold <code class="language-plaintext highlighter-rouge">⌥ (Option)</code> and click on the Notification Center
in your Menu Bar (the rightmost icon). This will grey out the icon and
will turn off all notifications until you <code class="language-plaintext highlighter-rouge">⌥</code> click it again. It’s a
really useful tool to use when your brain is fully loaded and you’ve
achieved flow with the help of Bose Mode.</p>

<p>There are many other ways you can exert more control over what is allowed
to interrupt you during your work, but none is as important as the
realization of how costly these interruptions are to your ability to do
good work with velocity.</p>

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1" role="doc-endnote">
      <p>I highly recommend <a href="http://www.rdio.com/artist/Tycho/">Tycho</a>, the <a href="http://www.rdio.com/artist/Hans_Zimmer/album/Inception_(Music_From_The_Motion_Picture)">Inception soundtrack</a>, the <a href="http://www.rdio.com/artist/Daft_Punk/album/TRON_Legacy/">Tron: Legacy soundtrack</a>, <a href="http://www.rdio.com/artist/Zero_7/">Zero 7</a>, <a href="http://www.rdio.com/artist/Bonobo/">Bonobo</a> or any music with sufficiently steady rythm and few lyrics. If you don’t know where to get started, you can try my own <a href="http://www.rdio.com/people/OlivierLacan/playlists/344415/Flow/">Flow playlist</a> <a href="https://olivierlacan.com#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>
<img src="https://feed.olivierlacan.com/link/8226/8521070.gif" height="1" width="1"/>]]></description>
      <pubDate>Tue, 08 Jul 2014 12:34:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521070/bose-mode</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/bose-mode/</guid>
    </item>
    <item>
      <title>The Internet's Own Boy</title>
      <description><![CDATA[<p>It’s 5:58 and I just finished watching <a href="http://www.takepart.com/internets-own-boy">The Internet’s Own Boy</a> 
by <a href="https://twitter.com/knappB">Brian Knappenberger</a>. I have some dried 
tears and some fresh ones running down my cheeks because the subject of 
this important movie — <a href="http://en.wikipedia.org/wiki/Aaron_Swartz">Aaron Swartz</a> — 
would have been proud today.</p>

<p>Today an ambitious campaign lead by <a href="http://en.wikipedia.org/wiki/Lawrence_Lessig">Lawrence Lessig</a> 
called <a href="https://mayday.us">Mayday</a> reached an incredible funding goal of 
five million US Dollars which will be matched by another five million US Dollars.</p>

<p>The goal of this fundraising is to create a “SuperPAC” to end all SuperPAC. 
A PAC is a <a href="http://en.wikipedia.org/wiki/Political_action_committee">Political Action Committee</a>
which allows US candidates to elections to pool money in order to finance 
their campaigns. There is enormous abuse and corruption in campaign finance 
in the United States of America. This matters to the entire world because 
the entire world is virtually led by the United States of America — its 
last remaining super power, and the one nation with the greatest stranglehold 
on the Internet.</p>

<p>The entire unfortunate end of Aaron Swartz’ life was dedicated to doing the most good 
he could possibly do. For him this meant allowing the public to access 
publicly funded research currently locked away in the proprietary grips 
of for-profit publishers who benefit handsomely from access tolls to 
invaluable public domain research. Swartz also played a huge role in 
deafeating the greatest threat to freedom of speech and the Internet ever 
— the so-called <a href="http://en.wikipedia.org/wiki/Stop_Online_Piracy_Act">SOPA</a>
  US bill.</p>

<p>Lawrence Lessig was a friend of Aaron Swartz’s. He’s featured in the movie 
The Internet’s Own Boy quite a bit. It’s humbling to think that despite 
Aaron having committed suicide a little over a year ago, Lessig has already 
been working so hard to uphold his legacy. And I’m sure many others have 
as well.</p>

<p>If you care about justice, freedom, and you believe the Internet is a 
tool for good, I urge you to <a href="http://www.takepart.com/internets-own-boy#watch">watch The Internet’s Own Boy</a>.</p>

<p>If you are an American Citizen or permanent resident, I kindly urge you 
to take a second and <a href="https://mayday.us/">donate to the Mayday campaign</a>.</p>
<img src="https://feed.olivierlacan.com/link/8226/8521071.gif" height="1" width="1"/>]]></description>
      <pubDate>Sat, 05 Jul 2014 05:58:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521071/the-internets-own-boy</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/the-internets-own-boy/</guid>
    </item>
    <item>
      <title>A Tiny Little .</title>
      <description><![CDATA[<p>For your own sake, don’t run commands with <code class="language-plaintext highlighter-rouge">.</code> without thinking hard
about what you’re doing.</p>

<p>Why? Because <code class="language-plaintext highlighter-rouge">.</code> means every directories here, right? So in your
development environment that probably means the cute little directories
you expected to be there.</p>

<p>In my development environment (Ruby on Rails), the only thing with spec files in it
for RSpec to run is that <code class="language-plaintext highlighter-rouge">/spec</code> folder. But what happens in my <a href="http://en.wikipedia.org/wiki/Continuous_integration">CI</a>
environment if you use a wonderful testing service like <a href="https://travis-ci.com/">Travis CI</a> (like we do) for instance?</p>

<p>There’s a good chance you’re also using the <a href="http://bundler.io/v1.6/man/bundle-install.1.html#DEPLOYMENT-MODE"><code class="language-plaintext highlighter-rouge">--deployment</code> Bundler flag</a> for <code class="language-plaintext highlighter-rouge">bundle install</code>.</p>

<p>And if you ever try this, like I did today. Something really weird may
happen in your build, like this:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="rouge-code"><pre>Could not load native IDN implementation.
/.../vendor/bundle/ruby/1.9.1/gems/backports-3.4.0/spec/tags/1.8.6/core/array/rotate_spec.rb:1:in `&lt;top (required)&gt;': undefined method `fails' for main:Object (NoMethodError)
  from /.../vendor/bundle/ruby/1.9.1/gems/activesupport-3.2.17/lib/active_support/dependencies.rb:245:in `load'
  from /.../vendor/bundle/ruby/1.9.1/gems/activesupport-3.2.17/lib/active_support/dependencies.rb:245:in `block in load'
  from /.../vendor/bundle/ruby/1.9.1/gems/activesupport-3.2.17/lib/active_support/dependencies.rb:236:in `load_dependency'
  from /.../vendor/bundle/ruby/1.9.1/gems/activesupport-3.2.17/lib/active_support/dependencies.rb:245:in `load'
  from /.../vendor/bundle/ruby/1.9.1/gems/rspec-core-2.14.8/lib/rspec/core/configuration.rb:896:in `block in load_spec_files'
  from /.../vendor/bundle/ruby/1.9.1/gems/rspec-core-2.14.8/lib/rspec/core/configuration.rb:896:in `each'
  from /.../vendor/bundle/ruby/1.9.1/gems/rspec-core-2.14.8/lib/rspec/core/configuration.rb:896:in `load_spec_files'
  from /.../vendor/bundle/ruby/1.9.1/gems/rspec-core-2.14.8/lib/rspec/core/command_line.rb:22:in `run'
  from /.../vendor/bundle/ruby/1.9.1/gems/rspec-core-2.14.8/lib/rspec/core/runner.rb:80:in `run'
  from /.../vendor/bundle/ruby/1.9.1/gems/rspec-core-2.14.8/lib/rspec/core/runner.rb:17:in `block in autorun'
</pre></td></tr></tbody></table></code></pre></div></div>

<p>The first thing you’ll notice is this super weird <code class="language-plaintext highlighter-rouge">Could not load native IDN implementation.</code>
error. And you’ll stare at it. You’ll try to poke holes through it like this fella:</p>

<p><img src="https://olivierlacan.com/assets/clint_eastwood_death_stare.jpg" alt="Clint Eastwood Trying Kill Your Stracktrace With His COLD BARE EYES" /></p>

<p>Eventually, you’ll Google this weird error message and find this line in the
<a href="https://github.com/sporkmonger/addressable/blob/master/spec/addressable/idna_spec.rb#L249">addressable</a> gem:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="k">rescue</span> <span class="no">LoadError</span>
  <span class="c1"># Cannot test the native implementation without libidn support.</span>
  <span class="nb">warn</span><span class="p">(</span><span class="s1">'Could not load native IDN implementation.'</span><span class="p">)</span>
<span class="k">end</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Hmm. <code class="language-plaintext highlighter-rouge">libidn</code>, what is that? And do I even have addressable in my Gemfile?
Nope… Wait, it’s a dependency of <a href="https://github.com/copiousfreetime/launchy"><code class="language-plaintext highlighter-rouge">launchy</code></a>
and <a href="https://github.com/bblimke/webmock"><code class="language-plaintext highlighter-rouge">webmock</code></a>. So… maybe I did
something wrong… but WAIT?</p>

<p><img src="https://olivierlacan.com/assets/house_epiphany.gif" alt="A fake epiphany that actually never happened because it's really Josh Kalderimis who figured this out" /></p>

<p>Why is the <a href="https://github.com/marcandre/backports/blob/master/spec/tags/1.8.6/core/array/rotate_spec.rb#L1"><code class="language-plaintext highlighter-rouge">rotate_spec.rb</code></a> from the <code class="language-plaintext highlighter-rouge">backports</code> gem even running in
my build?! How is that even…</p>

<blockquote>
  <p>As a result, bundle install –deployment installs gems to the <strong>vendor/bundle</strong> directory in the application. This may be overridden using the –path option.
— http://bundler.io/</p>
</blockquote>

<p>Since I was using the following features in my <code class="language-plaintext highlighter-rouge">.travis.yml</code> file:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="na">bundler_args</span><span class="pi">:</span> <span class="s">--deployment</span>
<span class="c1"># ...</span>
<span class="na">script</span><span class="pi">:</span>
  <span class="pi">-</span> <span class="s">bin/rspec . --color --profile --format RSpec::Instafail</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">vendor/bundle</code> directory was filled with cached gems before the build
started running with <code class="language-plaintext highlighter-rouge">bin/rspec .</code>. Because of that single little <code class="language-plaintext highlighter-rouge">.</code> RSpec
went to town on all the spec files inside of all my gems, and eventually
(thankfully) exploded one which had dependencies that couldn’t be satisfied.</p>

<p>I have to thank <a href="http://bitsandthoughts.com/">Josh Kalderimis</a> from Travis CI
for his invaluable help figuring this out. Basically the entire “eureka moment”
in this post actually went on in his head as I sat there stuck in
my Clint Eastwood phase.</p>

<p>This was a good reminder of something I’ve oddly been repeating to people
a lot lately: <strong>DO NOT FLIP OUT WHEN AN ERROR OCCURS</strong>.</p>

<p>Reading stacktraces is most definitely a path down the rabbit hole.
Although the first time I encountered this error I didn’t
have time to pursue its debugging, I really should have <em>made</em> some time.</p>

<p>As I suspected — and as Josh also found — the stacktrace was a <a href="http://en.wikipedia.org/wiki/Red_herring">red herring</a>
since it was in fact not the cause of the problem, but a symptom. Following
the stacktrace only made us more and more bewildered as to why this
spec was even running in the first place. Especially since it didn’t happen
on my development machine.</p>

<p>Thankfully, Josh started looking at stuff I took entirely for granted.
That’s why sanity checking with somebody else is so important in exceptional
situations like this. You don’t have to love pairing to use a pair of fresh eyes and
sometimes (often) they’ll question something you would have looked at but
never <strong>seen</strong> at the first glance. That’s basically what happened here.</p>

<p>There’s a thing that happens a lot when you don’t really understand something.
You go into a “there’s an error message on the screen” mode.</p>

<p>Despite the fact that all you need is to relax and read everything carefully, you (I) tend to
get upset and flail your arms uncontrollably at your screen somehow hoping
that the singularity will occur and it will develop shame and fix itself
to appease you.</p>

<p>That won’t happen. Errors mean you have to grab something that relaxes you
(tea, a book, a teddybear) and go into Sherlock mode. Everything is up for
grabs. Every little detail matters, especially the most mundane one, like
a tiny little fucking dot.</p>
<img src="https://feed.olivierlacan.com/link/8226/8521072.gif" height="1" width="1"/>]]></description>
      <pubDate>Sun, 29 Jun 2014 18:51:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521072/a-tiny-little-dot</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/a-tiny-little-dot/</guid>
    </item>
    <item>
      <title>Listening to her.</title>
      <description><![CDATA[<p>When I was a teenager I went to see a late night movie in a theater 
on Sainte-Catherine Ouest in Montréal. After the movie, I didn’t 
feel like going back to my hotel room so I decided to wander around for a few hours. 
I walked by a church on my way to the older part of town. I saw people in groups: lonely
people like me, drunk people, happy people. I was fascinated by this 
big dark city at night. By how different it looked and felt.</p>

<p>I grew up in one of the less safe neighborhoods of Paris. Back there I knew where 
and when to be on my guard: mostly at night, or in the quieter spots.</p>

<p>In Montréal, whether it was due the adrenaline rush from the movie, 
or the excitement of this foreign metropolis I was roaming in, I felt more safe 
than I had ever felt in Paris.</p>

<p>A few years ago, as I told this story to a friend of mine, a sad 
look grew on her face. Either she interrupted me, or I stopped talking 
when I noticed her discomfort, I can’t remember.</p>

<p>She told me why such 
a seemingly simple story was inconceivable for her. How this reality affected 
her daily life, even her outlook on other people. How she, essentially, 
wasn’t as free I was. She told me how vulnerable she felt in situations 
I would have found mundane: getting in and out of her car, taking a 
short walk alone from point A to point B anywhere, partaking alone in 
conversations with unknown individuals or groups. Had I been her, there’s 
a good chance this moment I cherish in my life would have never happened.</p>

<p>I feel that these are things every man should hear from friends, mothers, 
sisters, lovers. I don’t mean just hear them, but listen to them. Let them 
ring in your head until they make you sick.</p>

<p>There’s something heart-stopping about listening to someone tell you the 
impact that discrimination has had on their life. Ideally, we should all 
be able to empathize with the misfortune of complete strangers, but 
sometimes the injustice has to hit closer to home for us to finally react.</p>

<p>All you need to do is reach out to human beings around you. Don’t force 
them to share something they don’t want. Just be there and lend a friendly 
ear. You don’t have to try to fix things. Odds are your probably won’t 
know where to begin. The truth is that there are human beings suffering 
from things you can’t or won’t see. Some of them are dealing with it in 
silence. Others understandably refuse to do that.</p>

<p>It’s possible you’re not the one who can do something about it. But maybe 
you can help empower someone else. By amplifying their voice, 
helping them cope, lending a hand or an ear.</p>

<p>It might be hard because it’s foreign to you, just as it was to me. It still is,
because I don’t have to face these struggles every single day. But at least 
I’m aware of them.</p>

<p>It’s really difficult to understand that kind of suffering, at least at first. 
Empathy is tricky when you’re missing so many points of references but 
it’s not that hard. It took one evening and one patient friend to get me 
started, to challenge my assumptions on how half of humanity live their life.</p>

<p>All I had to do was start listening to her.</p>
<img src="https://feed.olivierlacan.com/link/8226/8521073.gif" height="1" width="1"/>]]></description>
      <pubDate>Sat, 21 Jun 2014 13:07:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521073/listening-to-her</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/listening-to-her/</guid>
    </item>
    <item>
      <title>Product Gardening</title>
      <description><![CDATA[<p>Recently, I announced that we were <a href="https://www.codeschool.com/jobs">hiring a software developer for Code School’s 
internal team</a>:</p>

<p><a href="https://twitter.com/olivierlacan/status/474604224945614848">My tweet</a></p>

<p>The good Philip Arndt answered that:</p>

<p><a href="https://twitter.com/parndt/status/474639718278508544">Philip Arndt’s tweet</a></p>

<p>It’s a fair question since the meaning isn’t self-evident. 
To me there are two basic circumstances in which you build software:</p>

<ul>
  <li>the one where you build the software <em>you own</em></li>
  <li>the one where you build the software <em>somebody else owns</em></li>
</ul>

<p>I think it’s reasonable to call the first is “product work” and the 
second “client work”. It’s true that client work often still caters to 
an end-user that isn’t directly <em>your</em> client, but with product work 
you are the owner. There is no interface between you and your end-user.</p>

<p>There’s a certain appeal in the kind of freedom that product work affords. 
While you trade one client for thousands, it’s much easier to say no to 
these thousands of clients, even if they’re vocal. It imparts you with 
much more control over your priority.</p>

<p>I think of people who write software as tool builders. It follows 
in my mind that a tool builder should know how to construct a <em>better</em> 
tool. That doesn’t mean the intended users of that tool are clueless 
about what exactly defines a good tool. It also doesn’t mean that the user of the 
tool can’t define constraints, requirements and suggestions to whoever 
builds it for them. Yet, what the user (or customer) pays the tool builder
for is their expertise in the crafting of reliable and useful tools.</p>

<p>Now, what do I mean by “product gardener”? Well, just like a tool maker, 
there is a specific set of variables a gardener has to account for when 
building and maintaining a garden. When planting something, they need to prepare the 
ground properly; use the right kind of soil; the right amount of watering. 
As time goes by, a gardener can’t just sit, enjoy the fruits of their 
initial labor, and move on to something else. In order for their garden 
to thrive, they have to follow a discipline. They have to attend to what 
they’ve planted; every day, every week, every month, every year. 
If they don’t, well, the product of their labor will disappear. And despite 
my allergies, I really like gardens, so that makes me sad.</p>

<p>I think this silly analogy helps to outline the tension here. 
If you’re excited by initial struggles, but tend to find the long-term 
work of sustaining something to be tedious or unfulfilling, then there’s 
a good chance you’re not made to be a product gardener. Maybe you’re an 
explorer, opening new paths for people who couldn’t find or see them before. 
That doesn’t make you less valuable. Michael Lopp would describe you as a 
<a href="http://randsinrepose.com/archives/stables-and-volatiles/">“volatile”</a>, then
explain how crucial you can be to an organization’s ability to innovate.</p>

<p>I once thought of myself as this kind of explorer. Somehow, I was able 
to crank out work from scratch in an afternoon, something I find very 
difficult to do today. Yet as the years passed by I kept stumbling on 
half-finished remnants of “good ideas” that had ignited fiery passion from
me for a few hours or a few days or a few weeks. But that fire burned too 
quickly, it exhausted all the fuel. I honestly thought I would never be 
able to commit to any project that would last more than three or six months.</p>

<p>Then something clicked. Maybe <em>I</em> changed. Somehow, though, I feel like 
I’ve always had this
<a href="http://en.wikipedia.org/wiki/The_Constant_Gardener_(film)">constant gardener</a> 
seed inside of me. It was just unfulfilled for a long time because 
I hadn’t yet found a discipline and an environment where it could blossom.</p>

<p>I think that environment was <a href="http://envylabs.com">Envy Labs</a>, and 
especially Code School. I found a place where I didn’t have to waste energy 
convincing my peers of things that I felt should be normal. Instead I 
could focus on my work. Oddly the nature and specific function of my work 
within Code School has evolved very often over the course of two years. 
I spent quite some time on support, so I was in direct contact with our 
end-users and their needs.</p>

<p>I think getting lost in the forest of people who use the tools you build 
is a rejuvenating experience. At first it might seem noisy. It’s easy to 
let yourself be swayed by the people that complain the loudest. 
But eventually a sort of music emerges. You stop hearing
the voices of individual people, instead you start sensing a breeze of 
discontent here, a buzzing of excitement there. In a very cheesy New Age 
kind of way, you start getting in touch with the nature of your users. 
A mix contexts, problems and potential solutions.</p>

<p>I could pursue this little metaphor yet further, but I think I’ve 
planted the seed of that idea firmly at this point. Now, concretely, 
what it means for us to be product gardeners is that we 
have to be careful not to lose ourselves by taking on too many tasks at 
once. Our main task is to sustain what has grown so far, and make sure 
people remain our priority. We have to accept that we can’t be 
everywhere at the same time and that sometimes things must die so others 
can survive.</p>

<p>For example, in the past two years I’ve wanted to go on a rampage and 
build new features for <a href="https://www.codeschool.com/code_tv">Code TV</a>,
our repository of screencasts: to add @replies and better notifications, 
a full-text search feature, mark videos as watched only when people watch 
are done watching them, or provide subtitles and transcripts of all our episodes 
for people with disabilities or who don’t speak English as a native language.</p>

<p>There are many more things <em>I want</em> to do. But eventually I had to resign 
myself to the fact that, while I want them, I don’t <em>need</em> to build them 
right now. Somebody else can, and certainly will.</p>

<p>While talking with our team I often say that we should try to 
become the owners of whatever makes us lose sleep at night. While 
unfortunate, the absence of the features I listed above doesn’t make me 
lose any sleep. But many more things do, and I have to make time for these.</p>

<p>If any of these thoughts made you sit up, shake your fist 
in the air and yell “YES! That!” at your screen while passers-by raised 
their eyebrows with concern at your rapidly declining sanity, 
then I beg you, send me an email, and come help us tend to 
<a href="https://www.codeschool.com">our little garden</a>.</p>
<img src="https://feed.olivierlacan.com/link/8226/8521074.gif" height="1" width="1"/>]]></description>
      <pubDate>Fri, 06 Jun 2014 00:34:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521074/product-gardening</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/product-gardening/</guid>
    </item>
    <item>
      <title>An Open Source Rage Diamond</title>
      <description><![CDATA[<p>One <a href="https://github.com/badges/shields/commit/a99b4db912b8ccd2350c417db301eea99ef4996a">late night of January 2013</a>,
I had a little bout of anger. The culprit: these badges I was starting to
notice all over the place on open source project README files.
The idea behind the badges was great: provide useful metadata regarding
how well tested the project is, whether those tests are passing or not,
how well factored the codebase is, etc. Yet, most of these badges seemed
were lazy clones of each other. Worse, it seemed like each new copy turned
out uglier. Somehow, the people making these badges had managed to achieve
“perfect” visual inconstency. It didn’t seem to shock anyone. Perhaps,
maintainers didn’t care or couldn’t tell the difference.</p>

<p><img src="https://olivierlacan.com/assets/pre-shields_inconsistency.png" alt="How open source badges looked before Shields" /></p>

<p>Some of these badges weren’t helpful at all. They looked a lot like
stealth advertising for the third-party services powering them.
Instead, they could have been focusing on providing actual value first,
and profit from people clicking on the badges to discover what was
providing this useful info.</p>

<p>Basically, the badges were often neither functionally optimal nor
aesthetically pleasing. I saw a missed opportunity there. So, despite my
rusty design skills, I hopped into Photoshop. Some time later I emerged
with a <a href="https://github.com/badges/shields/commit/0a6bc1ab5be03d6369799303ac6c1db3c8c50bb4">rage diamond</a>.
It was a simple Photoshop file with a badge template that I
took the time to design properly: consistent padding, a more
legible typeface despite a similar font size, better contrast, softer
colors, a more subtle gradient, etc.</p>

<p><img src="https://olivierlacan.com/assets/shields_original.png" alt="The Original Shields Design" /></p>

<p>I called the project Shields as a nod to one of the greatest TV
shows of all time — <a href="http://en.wikipedia.org/wiki/The_Shield">The Shield</a>
— and because in the US, a police officer’s badge is sometimes referred to as
their “shield”.</p>

<p>Over time the design for the badge evolved. It became good enough that people
started paying attention to my little project. The maintainers of <a href="http://travis-ci.org">Travis CI</a>,
<a href="https://gemfury.com/">Gemfury</a>, <a href="http://codeclimate.com">Code Climate</a>,
<a href="https://coveralls.io/">Coveralls</a>, <a href="https://www.gittip.com/">Gittip</a>,
<a href="https://gemnasium.com/">Gemnasium</a>, and more became involved.
Many of these vendors asked us to design a badge for their service, or for help
integrating the design into their service by generating PNG files for them.</p>

<p>After some much needed help from <a href="https://github.com/ackerdev">Nicholas Acker</a>
with an <a href="http://en.wikipedia.org/wiki/Scalable_Vector_Graphics">SVG</a> template,
we started toying with the idea of an API that
would generate badges on the fly based on a key, a value, and a color.
It seemed obvious because people were already implementing their own
internal APIs to generate them for their service, why not provide a
centralized one and never have to crank out PNGs and SVGs by hand?</p>

<p>One issue that caught us by surprise was how poorly the badges (being
PNG <a href="http://en.wikipedia.org/wiki/Bitmap">bitmaps</a> looked on high density
(or “Retina”) displays because none of us had a swanky Retina MacBook Pro
at the time. Thankfully
<a href="https://twitter.com/kneath/status/300327792879476738">Kyle Neath</a> from
GitHub chimed in and we quickly came up with
<a href="https://github.com/badges/shields/issues/12#issuecomment-13397282">a temporary yet satisfying solution</a>.</p>

<p>Thankfully the API idea meshed quite well with the resolution issue
because SVG images scale to any resolution and they adapt to the
pixel density of the screen. Through a slightly tortuous path that took
much longer than we anticipated, less than a year after my original
rage diamond people in and around the
<a href="https://github.com/badges/shields">Shields community</a> converged and
<a href="http://shields.io/">shields.io</a> was launched thanks to the help of many
contributors including <a href="https://github.com/espadrine">Thaddee Tyl</a>,
<a href="https://github.com/mathiasbynens">Mathias Bynens</a>,
<a href="https://github.com/whit537">Chad Whitacre</a>,
<a href="https://github.com/nathany">Nathan Youngman</a> and many more.</p>

<p>This API has yet to be as widely adopted as the original PNG Shields badges
have been across much of the open source community, but I consider this
second major phase of the project a great success. Adoption of the API is
slowed by the fact that many of the services (Travis CI, Code Climate, etc.)
for which we originally produced badges have since created and hosted their
own versions. They obviously couldn’t wait for us to release this API.
Now, many of them understandably don’t want to depend on a third-party API to provide a
badge feature to their users, which is understandable.</p>

<p>Until all these services get around to updating their websites and
internal badge generation services, we will see inconsistencies because
the new SVG badges don’t look exactly the same as the first generation.</p>

<p><img src="https://olivierlacan.com/assets/shields_inconsistency.png" alt="Illustration of the inconsistency between PNG and SVG Shields badges" /></p>

<p>I’ve wanted to avoid this since inconsistency is what led to this rage
diamond in the first place, but it’s alright. In the end my goal with this
project was surpassed by a few lightyears. I’m still amazed when I visit
the repos of <a href="https://github.com/rails/rails#code-status">some</a>
<a href="https://github.com/vmg/redcarpet">of</a> <a href="https://github.com/plataformatec/devise">my</a>
<a href="https://github.com/intridea/omniauth">favorite</a> <a href="https://github.com/pry/pry">open</a>
<a href="https://github.com/rack/rack">source</a> <a href="https://github.com/jekyll/jekyll#jekyll">projects</a> and discover that
little badge design I put together in Photoshop a year ago.</p>

<p>Shields is also the most successful open source project I’ve ever been
involved with in a major way, and for a while it didn’t contain a single
line of code. I think design-savvy developers and designers have a lot to
contribute to the open source world, and Shields is my proof.</p>

<p>Although the initial impulse for this project was frustration, I think my fellow
contributors and I have had a non-negligible impact on the open source
community. I’ve spent hours talking back and forth with people involved
with the services that fuel the data displayed on the badges. Through
these conversations, I’ve convinced nearly all of them to focus on
semantic clarity (how the badges are named and the data expressed) and
the value they provide to end-users (the people who use and contribute
to open source projects).</p>

<p>Even though they break the visual guidelines I had originally
established, I couldn’t be more proud of seeing new takes on Shields-style
badges like <a href="http://inch-pages.github.io/">Inch Pages</a>. These folks took the
concept and tweaked it in order to display far more dense data than I
ever thought possible.</p>

<p>In the end, when I find projects READMEs like the
<a href="https://github.com/sferik/twitter">Twitter Gem’s</a>, I’m really
happy because there is now so much more valuable metadata available at a
glance for someone who’s just discovering the project, or even someone
who’s coming back to it.</p>

<p><a href="http://shields.io">Shields.io</a> allows open source projects like
this to be more transparent and approachable. It also makes it easier to
tell what their maintainers care about, by showcasing:</p>

<table>
  <thead>
    <tr>
      <th> </th>
      <th> </th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>dependencies</td>
      <td><a href="http://img.shields.io/gemnasium/badges/shields.svg"><img src="https://olivierlacan.com/assets/shields_dependencies.svg" alt="Dependency status badge" /></a></td>
    </tr>
    <tr>
      <td>code quality</td>
      <td><a href="http://img.shields.io/codeclimate/github/rails/rails.svg"><img src="https://olivierlacan.com/assets/shields_code_quality.svg" alt="code quality badge" /></a></td>
    </tr>
    <tr>
      <td>test coverage</td>
      <td><a href="http://img.shields.io/codeclimate/coverage/github/triAGENS/ashikawa-core.svg"><img src="https://olivierlacan.com/assets/shields_test_coverage.svg" alt="test coverage badge" /></a></td>
    </tr>
    <tr>
      <td>donations</td>
      <td><a href="http://img.shields.io/gittip/Shields.svg"><img src="https://olivierlacan.com/assets/shields_donations.svg" alt="donations badge" /></a></td>
    </tr>
    <tr>
      <td>build status</td>
      <td><a href="http://img.shields.io/travis/badges/shields.svg"><img src="https://olivierlacan.com/assets/shields_build_status.svg" alt="build status badge" /></a></td>
    </tr>
    <tr>
      <td>version awareness</td>
      <td><a href="http://img.shields.io/gem/v/rails.svg"><img src="https://olivierlacan.com/assets/shields_version_awareness.svg" alt="version awareness badge" /></a></td>
    </tr>
    <tr>
      <td>licensing</td>
      <td><a href="http://img.shields.io/packagist/l/doctrine/orm.svg"><img src="https://olivierlacan.com/assets/shields_licensing.svg" alt="licensing badge" /></a></td>
    </tr>
  </tbody>
</table>
<img src="https://feed.olivierlacan.com/link/8226/8521075.gif" height="1" width="1"/>]]></description>
      <pubDate>Thu, 05 Jun 2014 06:14:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521075/an-open-source-rage-diamond</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/an-open-source-rage-diamond/</guid>
    </item>
    <item>
      <title>Burnout Buddies</title>
      <description><![CDATA[<p>I went to a private full-time university where you go to class at least 40 hours
a week and generally spend between 60 and 70 hours a week working on learning things.</p>

<p>In late 2009 a few months after I had started school, my classmate and friend Zachary Nicoll
and I co-founded our first little company. Although we were still both in school,
by the summer of 2010 we had worked on three professional projects together.</p>

<p>We were doing some sub-contracting work for Envy Labs at some point and we had our
own clients to deal with.</p>

<p>During that time, I would wake up at 8 AM (which is ridiculously early for me)
and drive to the Envy Labs office in Downtown Orlando. Around lunch time I would
head back to Full Sail University to attend a lecture from 1 to 5 PM.</p>

<p>After that, Lab could last between one to four hours. When lab was over,
I would head home, do some work for school then start working on our client project.</p>

<p>That sometimes lasted until 3 or 4 in the morning, at which point the exhaustion
would lead to really strange arguments about things that really didn’t matter that
much. I remember us looking at each other and saying something like “Why are we
yelling at each other? Let’s go to sleep.”.</p>

<p>We were burning out. I was burning out even worse than anybody else. I was upset
at my closest friends for a project that we had painted ourselves into a corner with
and wasn’t even earning us any money.</p>

<p>The most important thing I learned from this experience was the value of a friend’s
perspective when you need it most. Zach noticed how bitter things were becoming and
I’m pretty sure I was pushing him to do even more. One day, he sent me an email.
A long, heartfelt email in which he dragged me back down to earth in kind and calm words.</p>

<p>He said he didn’t sign up for this, that we couldn’t neglect school as much as
we had. It made so much sense, but I couldn’t see it before he wrote it down.</p>

<p>Zach was my Burnout Buddy™ that day.</p>

<p>I’ve been trying to be one for the people I work with ever since.</p>

<p>When I started working on Code School in early 2012, another friend from Full Sail
had started just before me. It was Adam’s first Ruby gig. After
months of courtship the year before, I had finally managed to have him try the language out.
He’s one the best programmers I know and I knew Ruby would give him wings, and it did.</p>

<p>In early 2012, there were less than a handful of people working full-time
on Code School. Adam and I were both in trenches doing customer support every day
along with whatever else we were working on.</p>

<p>During that first year I definitely went through burnout a few times and I saw him
go through it too. There were moments when I had to tell him to relax and I hope it helped.</p>

<p>Since I think I’m pretty good at hiding my problems, I don’t think too many people
noticed I was spreading myself thin. But then, once in a while Nick Walsh — a very tall front-end
wizard at Envy Labs — would arrive at the office ridiculously early (which is “normal” for him)
and find me still there from the night before.</p>

<p>He would stand there in front of my desk, cross his arms, and say “Go home!” in
a very serious tone. I would laugh and brush it off because: “I was just trying
to get that one thing done. I’m fine. I’ll go home in a little bit.”</p>

<p>And I did go home. But then those “stunts” put me out of whack.</p>

<p>First, it fucked with my sleep cycle which is of course fertile ground for more
late nights. Second, it sometimes made me resent people who went home regularly every day,
seemingly regardless of how busy they were.</p>

<p>Then, and it took some time, I learned from them. Many had kids, a wife, a baby,
or pets to go home to. During my worst burnouts I was single, and I didn’t have any pets
so it was easy to let the clock run.</p>

<p>Time was this rubber band I thought I could stretch as much as I could. But doing
that didn’t lead me to more actual work. It didn’t make me more efficient or better
at what I did. It just made me better at doing busy work. Better at staying there, overwhelmed,
instead of actually producing something and going home when it was done.</p>

<p>When I eventually got better, thanks to the good examples around me, I made it a point
to start checking in on my co-workers to make sure they were okay. This can mean
allowing a conversation to run a little longer so you can arrive at more important
topics. Nobody tells the truth when you ask them how they’re doing, it often
takes bit of bluntness.</p>

<p>When someone shows up to work with circles around their eyes, instead of pretending
it’s normal, I sometimes use my cover as a loudmouth to tell them: “Hey, you look
like shit. Are you sleeping enough?”.</p>

<p>With the right kind of people, in the right situation, this can be an arrow that
shatters their facade and lets you peek into the true state of their mind. But it’s
not a panacea, there are many other ways to get people to talk. Some people are like cats,
you need to let them come to you. Make yourself available, and please, don’t say
“my door is always open”. If it actually was, you wouldn’t need to say that. People
would be stepping in already. But are they?</p>

<p>Recently I’ve been taking on more Burnout Buddies. Not just my co-workers but other
friends and acquaintances. It feels great because helping someone else can equip
you to deal with your own problems better. Or the people you helped can help you back, or pay
it forward. It’s a virtuous cycle.</p>

<iframe width="100%" height="166" scrolling="no" frameborder="no" src="https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/150798632&amp;color=ff5500&amp;auto_play=false&amp;hide_related=false&amp;show_artwork=false"></iframe>
<img src="https://feed.olivierlacan.com/link/8226/8521076.gif" height="1" width="1"/>]]></description>
      <pubDate>Thu, 22 May 2014 01:46:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521076/burnout-buddies</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/burnout-buddies/</guid>
    </item>
    <item>
      <title>Proposal for a better Ruby Hash#include?</title>
      <description><![CDATA[<h2 id="the-use-case">The Use Case</h2>
<p>Earlier I was writing a test to ensure that a Hash contains a specific key and value.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="n">it</span> <span class="s2">"sets the anonymous key to true"</span> <span class="k">do</span>
  <span class="n">expect</span><span class="p">(</span><span class="n">properties</span><span class="p">).</span><span class="nf">to</span> <span class="kp">include</span> <span class="p">{</span> <span class="ss">a: </span><span class="kp">true</span> <span class="p">}</span>
<span class="k">end</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>It then dawned on me that this kind of comparison, while possible in the RSpec
DSL with its built-in matchers<sup id="fnref:1" role="doc-noteref"><a href="https://olivierlacan.com#fn:1" class="footnote" rel="footnote">1</a></sup> was actually impossible in raw Ruby.</p>

<p>Take a Hash:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="n">x</span> <span class="o">=</span> <span class="p">{</span> <span class="ss">a: </span><span class="kp">true</span><span class="p">,</span> <span class="ss">b: </span><span class="kp">false</span> <span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now take another Hash:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="n">y</span> <span class="o">=</span> <span class="p">{</span> <span class="ss">a: </span><span class="kp">true</span> <span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>You want to check whether <code class="language-plaintext highlighter-rouge">y</code> is included within <code class="language-plaintext highlighter-rouge">x</code> or not. So what’s the first
thing that comes to mind? For me, it’s <code class="language-plaintext highlighter-rouge">String#include?</code>, which works like this:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="s2">"Olivier"</span><span class="p">.</span><span class="nf">include?</span><span class="p">(</span><span class="s2">"Oli"</span><span class="p">)</span>
<span class="c1"># =&gt; true</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This is probably one of the most famous whoa-worthy Ruby demonstrations when
someone wants to show the object-oriented power of the language. So naturally,
when I’m dealing the <code class="language-plaintext highlighter-rouge">x</code> and <code class="language-plaintext highlighter-rouge">y</code> hashes above, I reach for <code class="language-plaintext highlighter-rouge">include?</code>:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="n">x</span><span class="p">.</span><span class="nf">include?</span><span class="p">(</span><span class="n">y</span><span class="p">)</span>
<span class="c1"># =&gt; false</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Well, obviously that’s not (pardon incoming pun) true! Let’s look at the <a href="http://www.ruby-doc.org/core-2.1.1/Hash.html#method-i-include-3F">Ruby API
docs to see how <code class="language-plaintext highlighter-rouge">Hash#include?</code> is defined</a>:</p>

<blockquote>
  <p>include?(key) → true or false
Returns true if the given key is present in hsh.</p>
</blockquote>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="n">h</span> <span class="o">=</span> <span class="p">{</span> <span class="s2">"a"</span> <span class="o">=&gt;</span> <span class="mi">100</span><span class="p">,</span> <span class="s2">"b"</span> <span class="o">=&gt;</span> <span class="mi">200</span> <span class="p">}</span>
<span class="n">h</span><span class="p">.</span><span class="nf">has_key?</span><span class="p">(</span><span class="s2">"a"</span><span class="p">)</span>   <span class="c1">#=&gt; true</span>
<span class="n">h</span><span class="p">.</span><span class="nf">has_key?</span><span class="p">(</span><span class="s2">"z"</span><span class="p">)</span>   <span class="c1">#=&gt; false</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>If this leaves you puzzled, I can empathize. The fact that the example isn’t
even using <code class="language-plaintext highlighter-rouge">include?</code> shows that it’s used as a method alias for <code class="language-plaintext highlighter-rouge">Hash#has_key?</code>
which does have a good name. <code class="language-plaintext highlighter-rouge">Hash#include?</code> however, is very poorly named because
it breaks a reasonable expectation.</p>

<p>You cannot say that <code class="language-plaintext highlighter-rouge">Hash#include?</code> is checking whether something “is included
in the Hash instance” because this method only checks keys. If it were checking
both the keys <strong>and</strong> the values then perhaps this would make sense.</p>

<h2 id="the-basic-implementation">The Basic Implementation</h2>
<p>So here’s my proposition for a reasonable and simple re-implementation<sup id="fnref:2" role="doc-noteref"><a href="https://olivierlacan.com#fn:2" class="footnote" rel="footnote">2</a></sup> of <code class="language-plaintext highlighter-rouge">Hash#include?</code>:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="k">class</span> <span class="nc">Hash</span>
  <span class="k">def</span> <span class="nf">include?</span><span class="p">(</span><span class="n">other</span><span class="p">)</span>
    <span class="nb">self</span><span class="p">.</span><span class="nf">merge</span><span class="p">(</span><span class="n">other</span><span class="p">)</span> <span class="o">==</span> <span class="nb">self</span>
  <span class="k">end</span>
<span class="k">end</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>It seems incredibly simple but by that token, why not offer such a useful
method to Ruby developers instead? It seems silly to monkey patch the Hash class
for something like this when it could benefit all Ruby developers to have in Ruby core.</p>

<h2 id="demonstration">Demonstration</h2>

<p>And here’s a demonstration of it in use:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="rouge-code"><pre><span class="p">{</span> <span class="ss">a: </span><span class="kp">true</span><span class="p">,</span> <span class="ss">b: </span><span class="kp">false</span> <span class="p">}.</span><span class="nf">include?</span><span class="p">({</span> <span class="ss">a: </span><span class="kp">true</span><span class="p">})</span>
<span class="c1"># =&gt; true</span>

<span class="p">{</span> <span class="ss">a: </span><span class="kp">true</span><span class="p">,</span> <span class="ss">b: </span><span class="kp">false</span> <span class="p">}.</span><span class="nf">include?</span><span class="p">({</span> <span class="ss">b: </span><span class="kp">false</span><span class="p">})</span>
<span class="c1"># =&gt; true</span>

<span class="p">{</span> <span class="ss">a: </span><span class="kp">true</span><span class="p">,</span> <span class="ss">b: </span><span class="kp">false</span> <span class="p">}.</span><span class="nf">include?</span><span class="p">({</span> <span class="ss">a: </span><span class="kp">false</span><span class="p">})</span>
<span class="c1"># =&gt; false</span>

<span class="p">{</span> <span class="ss">a: </span><span class="kp">true</span><span class="p">,</span> <span class="ss">b: </span><span class="kp">false</span> <span class="p">}.</span><span class="nf">include?</span><span class="p">({</span> <span class="ss">c: </span><span class="kp">true</span><span class="p">})</span>
<span class="c1"># =&gt; false</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>I’m was thinking about submitting this implementation to the Ruby core team to see if
they would consider including it in a major version of the language. Obviously,
this would be an API breaking change since all existing programs using the current
implementation of <code class="language-plaintext highlighter-rouge">Hash.include?</code> would suddenly stop working properly.</p>

<p>A way to alleviate that concern would be to use another method name than <code class="language-plaintext highlighter-rouge">include</code>
which I don’t think is a good idea. That said, I could be convinced that
<code class="language-plaintext highlighter-rouge">Hash#contain?</code> could be a suitable alternative. This name would prevent an API
breaking change and could potentially allow this method to be shipped with Ruby 2.2.</p>

<p>What surprises me is that the very
<a href="http://www.ruby-doc.org/core-2.1.1/Array.html#method-i-include-3F">definition of the equivalent <code class="language-plaintext highlighter-rouge">Array#include?</code></a>
is hinting at what <code class="language-plaintext highlighter-rouge">Hash.include?</code> should be:</p>

<blockquote>
  <p>Returns true if the given object is present in self (that is, if any element == object), otherwise returns false.</p>
</blockquote>

<p>And with that, I rest my case.</p>

<p>I’d like to thank <a href="http://www.saturnflyer.com/">Jim Gay</a>, <a href="http://patshaughnessy.net/">Pat Shaughnessy</a>
and <a href="http://hone.heroku.com/">Terence Lee</a> for their feedback and support. I’ll
submitting a <a href="https://bugs.ruby-lang.org/projects/ruby-trunk">feature request</a> for
Ruby 2.2 shortly unless someone can find a reason for me not to.</p>

<h2 id="update-1-august-28th-2014">Update 1 (August 28th, 2014)</h2>
<p>Some time has passed since this post and shortly after Nobu — the amazing
Ruby core team member known as “Patch Monster” — <a href="https://gist.github.com/nobu/dfe8ba14a48fc949f2ed">created a patch that
actually implements this proposal</a>, albeit with name I find confusing.</p>

<p>After talking with some Ruby developers, including Adam Rensel who works with
me at Code School and also often has the need to check whether a Hash is
partially or completely included in an other Hash, I settled on a better
name for this method: <code class="language-plaintext highlighter-rouge">Hash#contain?(Hash)</code></p>

<p>I know I said I would be submitting a feature suggestion to Ruby Core
and sadly I haven’t done that yet because I wanted to make sure that this
wasn’t frivolous. But I swear I’ll do it before RubyConf 2014.</p>

<p>To be honest I wish we could extend the capabilities of <code class="language-plaintext highlighter-rouge">Hash#include?</code>
because <a href="http://www.ruby-doc.org/core-2.1.1/Hash.html#method-i-include-3F">its current implementation</a>
seems woefully simplistic. It’s a mere alias to <code class="language-plaintext highlighter-rouge">Hash#has_key?</code> which is
inconsistent with the meaning of “include” in my book. I believe that if
<code class="language-plaintext highlighter-rouge">Hash#include?</code> (a real one, not an alias) receives a Hash, it should do
<em>actually</em> compare the two hashes (both keys and values). If it receives
a String or a Symbol, it should defer to <code class="language-plaintext highlighter-rouge">Hash#has_key?</code>.</p>

<h2 id="update-2-march-19th-2015">Update 2 (March 19th, 2015)</h2>

<p>After a busy end of 2014 I finally found the time to submit <a href="https://bugs.ruby-lang.org/issues/10984">a proper feature
proposal to bugs.ruby-lang.org</a>.</p>

<p>The feature is being debated with fellow Rubyists at the moment.</p>

<h2 id="update-3-november-9th-2015">Update 3 (November 9th, 2015)</h2>

<p>After some stagnation, the feature proposal was discussed in two separate Ruby
core team developer meetings. First on <a href="https://bugs.ruby-lang.org/projects/ruby/wiki/DevelopersMeeting20150514Japan">May 14th, 2015</a>
and then <a href="https://docs.google.com/document/d/1D0Eo5N7NE_unIySOKG9lVj_eyXf66BQPM4PKp7NvMyQ/edit#heading=h.bnqkvf9ajejv">this morning for the November meeting</a>. Matz said he favored a comparison operator (<code class="language-plaintext highlighter-rouge">&lt;=</code> or <code class="language-plaintext highlighter-rouge">&gt;=</code>) because
it’s less ambiguous than <code class="language-plaintext highlighter-rouge">contain?</code>.</p>

<p>This means that the syntax I originally proposed would evolve to something like
this:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
</pre></td><td class="rouge-code"><pre><span class="p">{</span> <span class="ss">a: </span><span class="mi">1</span><span class="p">,</span> <span class="ss">b: </span><span class="mi">2</span> <span class="p">}</span> <span class="o">&gt;=</span>  <span class="p">{</span> <span class="ss">b: </span><span class="mi">2</span> <span class="p">}</span>
<span class="o">=&gt;</span> <span class="kp">true</span>
<span class="p">{</span> <span class="ss">b: </span><span class="mi">2</span> <span class="p">}</span> <span class="o">&lt;=</span>  <span class="p">{</span> <span class="ss">a: </span><span class="mi">1</span><span class="p">,</span> <span class="ss">b: </span><span class="mi">2</span> <span class="p">}</span>
<span class="o">=&gt;</span> <span class="kp">true</span>

<span class="c1"># also</span>
<span class="p">{</span> <span class="ss">b: </span><span class="mi">2</span> <span class="p">}</span> <span class="o">&gt;=</span>  <span class="p">{</span> <span class="ss">b: </span><span class="mi">2</span> <span class="p">}</span>
<span class="o">=&gt;</span> <span class="kp">true</span>
<span class="p">{</span> <span class="ss">a: </span><span class="mi">1</span> <span class="p">}</span> <span class="o">&gt;=</span>  <span class="p">{</span> <span class="ss">b: </span><span class="mi">2</span> <span class="p">}</span>
<span class="o">=&gt;</span> <span class="kp">false</span>

<span class="p">{</span> <span class="ss">b: </span><span class="mi">2</span> <span class="p">}</span> <span class="o">&lt;=</span>  <span class="p">{</span> <span class="ss">b: </span><span class="mi">2</span> <span class="p">}</span>
<span class="o">=&gt;</span> <span class="kp">true</span>
<span class="p">{</span> <span class="ss">b: </span><span class="mi">2</span> <span class="p">}</span> <span class="o">&lt;=</span>  <span class="p">{</span> <span class="ss">a: </span><span class="mi">1</span> <span class="p">}</span>
<span class="o">=&gt;</span> <span class="kp">false</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>I have to admit I was originally surprised by Matz’ proposal (it was early) but
I’ve since then been convinced by its versatility and simplicity. I really hope
it can be included in Ruby 2.3 for the December 25th release. That would be quite
the Chritmas present. :-)</p>

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1" role="doc-endnote">
      <p>You can see how this include matcher is implemented in the <a href="https://github.com/rspec/rspec-expectations/blob/bb731e29f7800f5cef736cf8850293276a0d3f90/lib/rspec/matchers/built_in/include.rb#L94-L97">rspec-expectations source</a>. <a href="https://olivierlacan.com#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:2" role="doc-endnote">
      <p>I’m using <a href="http://www.ruby-doc.org/core-2.1.1/Hash.html#method-i-merge"><code class="language-plaintext highlighter-rouge">Hash#merge</code></a> for convenience and as a hack. I don’t know if it’s appropriate or performant enough. <a href="https://olivierlacan.com#fnref:2" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>
<img src="https://feed.olivierlacan.com/link/8226/8521077.gif" height="1" width="1"/>]]></description>
      <pubDate>Thu, 01 May 2014 01:53:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521077/proposal-for-a-better-ruby-hash-include</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/proposal-for-a-better-ruby-hash-include/</guid>
    </item>
    <item>
      <title>Launch Sublime Text 3 from the command line</title>
      <description><![CDATA[<p>Sublime Text 3 ships with a <a href="http://en.wikipedia.org/wiki/Command-line_interface">CLI</a> called <code class="language-plaintext highlighter-rouge">subl</code>. By default you can’t use this command line utility unless you do some fiddling.</p>

<h2 id="a-word-about-the-load-path">A word about the load $PATH</h2>

<p>The <a href="http://www.sublimetext.com/docs/3/osx_command_line.html">Sublime Text documentation</a> on this tool does explain where it’s located (<code class="language-plaintext highlighter-rouge">/Applications/Sublime Text.app/Contents/SharedSupport/bin/subl</code>) but it assumes you have <code class="language-plaintext highlighter-rouge">~/bin</code> (or <code class="language-plaintext highlighter-rouge">/Users/username/</code>) in your load path (<code class="language-plaintext highlighter-rouge">$PATH</code>) which is downright silly. There’s a better way.</p>

<p>The <code class="language-plaintext highlighter-rouge">/usr/local/bin</code> is in the load path by default on OS X, so it’s a much better place to symlink (create a <a href="http://en.wikipedia.org/wiki/Symbolic_link">symbolic link</a> — or shortcut) that will allow you to run the <code class="language-plaintext highlighter-rouge">subl</code> utility from your Terminal app.</p>

<p>First up, check your own <code class="language-plaintext highlighter-rouge">$PATH</code> by running: <code class="language-plaintext highlighter-rouge">echo $PATH</code>. This is what mine returns:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin
</pre></td></tr></tbody></table></code></pre></div></div>

<p>As you can see the <code class="language-plaintext highlighter-rouge">/usr/local/bin</code> path is included by default on OS X.</p>

<h2 id="installation">Installation</h2>

<p><em>Note: These instructions assume you’re using the Terminal app out of the box, without ZSH or any fancy prompts like that. I trust you will be able to adapt these instructions yourself if you do.</em></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>ln -s "/Applications/Sublime Text.app/Contents/SharedSupport/bin/subl" /usr/local/bin/sublime
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Yes, I name the symlink <code class="language-plaintext highlighter-rouge">sublime</code> instead of <code class="language-plaintext highlighter-rouge">subl</code> because I believe you should always be explicit. You should never have to type the full word anyway. Typing <code class="language-plaintext highlighter-rouge">sub</code> + <code class="language-plaintext highlighter-rouge">Tab</code> should auto-complete the full name of the symlink.</p>

<h2 id="testing">Testing</h2>

<p>Open a Terminal window and run:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>sublime ~/Documents
</pre></td></tr></tbody></table></code></pre></div></div>

<p>or</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre>cd
sublime Documents/
</pre></td></tr></tbody></table></code></pre></div></div>

<p>or even</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre># to open the entire current directory
sublime .
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="conclusion">Conclusion</h2>

<p>Now you don’t need to get out of Terminal to simply open a file or a folder, you didn’t have to add an “alias” or yet another bin directory to your <code class="language-plaintext highlighter-rouge">.bash_profile</code> which the official instructions given by the Sublime team seems to recommend.</p>

<p>Have fun, Sublime is a great editor. Check out the most recent <a href="http://www.sublimetext.com/3">beta release of Sublime Text 3</a>.</p>
<img src="https://feed.olivierlacan.com/link/8226/8521078.gif" height="1" width="1"/>]]></description>
      <pubDate>Mon, 20 Jan 2014 15:00:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521078/launch-sublime-text-3-from-the-command-line</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/launch-sublime-text-3-from-the-command-line/</guid>
    </item>
    <item>
      <title>The Sabotaging of America</title>
      <description><![CDATA[<p><strong>Update</strong>: It has been over 8 years since I wrote this post and since then Jacob Applebaum has been credibly accused by several people in cryptography circles 
of multiple instance of sexual abuse and deeply troubling manipulation, threats, and blackmail. I still think the subject of this post 
deserves attention which is why I’m not pulling it down, but I’d like to highlight how disappointing it is to discover that people in the some most 
important walks of public life abuse the trust and reputation they earned to prey on innocent victims who then have to face the insurmountable task of 
denouncing a publicly beloved private monster like Harvey Weinstein or Bill Cosby.</p>

<p>You can find more information about the credible allegations that led to Jacob Applebaum’s exclusion of the Tor project and many other cryptography-related 
communities in this <a href="https://www.dailydot.com/debug/tor-project-jacob-appelbaum-sexual-assault-rape-investigation/">Daily Dot piece</a></p>

<hr />

<p>If you’re technologically savvy, there’s no doubt you’ve been watching the information being released about the myriad of NSA intelligence collection programs.</p>

<p>I don’t think I’m qualified to comment on their extent, legality, or even if I know what to think of them.</p>

<p>However, I think you should watch this chilling presentation by Jacob Applebaum at the <a href="http://en.wikipedia.org/wiki/Chaos_Communication_Congress">Chaos Communication Congress</a> in Hamburg, Germany today.</p>

<iframe width="640" height="360" src="https://olivierlacan.com//www.youtube-nocookie.com/embed/b0w36GAyZIA?rel=0" frameborder="0" allowfullscreen=""></iframe>

<p>Yes, you should spend an hour watching this. But if you chose not to, let me boil it down for you: an American governmental agency mandated by the Congress of the United States of America has been systematically subverting and sabotaging security protocols designed and manufactured by foreign <strong>and American companies</strong>.</p>

<p>This means that instead of reporting and encouraging American companies to fix extremely serious security vulnerabilities that put US businesses and private individual at risk of corporate espionage or privacy invasion by anyone — terrorist groups, foreign governments, criminals, hackers, competitors — the NSA has been subverting these security vulnerabilities to further its own goal: communication <a href="http://en.wikipedia.org/wiki/Omniscience">omniscience</a>.</p>

<p>I believe in democracy, freedom of speech, and the privacy of all law-abiding citizen. The NSA doesn’t, and nothing stands in their way.</p>

<p>The German newspaper <em>Der Spiegel</em> has more about these revelations in a multi-part piece titled <a href="http://www.spiegel.de/international/world/the-nsa-uses-powerful-toolbox-in-effort-to-spy-on-global-networks-a-940969-3.html">Inside TAO</a>.</p>
<img src="https://feed.olivierlacan.com/link/8226/8521079.gif" height="1" width="1"/>]]></description>
      <pubDate>Mon, 30 Dec 2013 19:00:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521079/the-sabotaging-of-america</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/the-sabotaging-of-america/</guid>
    </item>
    <item>
      <title>Why is Git HTTPS not working on GitHub?</title>
      <description><![CDATA[<p>If you have no patience or aren’t interested in my debugging process, skip to
the last section.</p>

<p>On September 3rd, 2013 GitHub <a href="https://github.com/blog/1614-two-factor-authentication">announced</a>
a long awaited implementation of <a href="http://en.wikipedia.org/wiki/Two-step_verification">two-factor authentication</a> on github.com.
Of course I immediately turned that feature on, and you should too.</p>

<h2 id="authentication-failed">Authentication failed</h2>

<p>After setting up 2FA on GitHub, I moved on and forget about it. I imagined that
my week would go on merrily, until one fateful day when I jumped into a repo and
this happened:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre>$ git pull
remote: Invalid username or password.
fatal: Authentication failed for 'https://github.com/codeschool/kraken.git/'
</pre></td></tr></tbody></table></code></pre></div></div>

<p>I clearly remembered pulling from this same repository without a hitch a few
weeks prior. How could my authentication suddenly fail. That damned
<a href="https://help.github.com/articles/set-up-git#password-caching">osxkeychain credential helper</a>
felt like a perfect culprit, since I had issues with it in the past.</p>

<p>Strange. I definitely typed the correct password here.</p>

<p>Remembering that git has a way to talk to Keychain (the credential helper),
I thought maybe it had stored the wrong password so I checked the credential
helper for signs of life:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre>git config --global credential.helper
osxkeychain

$ git credential-osxkeychain
Usage: git credential-osxkeychain &lt;get|store|erase&gt;
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Seemed all right. Maybe Keychain had the wrong password stored somehow?</p>

<h2 id="keychain">Keychain</h2>

<p>After checking my own Keychain, there was indeed a record in there that
matched <code class="language-plaintext highlighter-rouge">https://github.com</code>:</p>

<p><img src="https://olivierlacan.com/assets/keychain-github-record.png" alt="Screenshot of the Keychain app showing a github.com entry" /></p>

<p>Since this obviously wasn’t working I checked the info for that record:</p>

<p><img src="https://olivierlacan.com/assets/keychain-github-record-info.png" alt="Screenshot of the Keychain app entry info for github.com" /></p>

<p>It all checked out. The password was correct since <strong>I had just logged into
github.com itself using it</strong>. You can even see that the <code class="language-plaintext highlighter-rouge">git-credential-osxkeychain</code>
binary is allowed to access that credential from Keychain in the Access Control tab:</p>

<p><img src="https://olivierlacan.com/assets/keychain-github-record-info-access-control.png" alt="Screenshot of the Keychain app entry info access control tab for github.com" /></p>

<p>So it’s not an access problem. What the hell is going on here?
I decided to delete the Keychain record for github.com and try to re-submit them.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre>$ git pull
Username for 'https://github.com': olivierlacan
Password for 'https://olivierlacan@github.com':
remote: Invalid username or password.
fatal: Authentication failed for 'https://github.com/example/thing.git/'
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Still not a fan of my password, uh.</p>

<h2 id="it-all-makes-sense-now">It all makes sense now!</h2>

<p>In a last effort, I googled the term “https github error” and found a GitHub Help
article on <a href="https://help.github.com/articles/https-cloning-errors">HTTPS cloning errors</a>.
Since cloning didn’t work either, I thought it could be useful.
And that’s when the answer <a href="https://help.github.com/articles/https-cloning-errors#provide-access-token-if-2fa-enabled">jumped at me</a>.</p>

<blockquote>
  <p>If you have enabled two-factor authentication, <strong>you must provide a personal
access token instead of entering your password for HTTPS Git</strong>.
You can <a href="https://help.github.com/articles/creating-an-access-token-for-command-line-use">create a personal access token</a>
for accessing GitHub by going to the <a href="https://github.com/settings/applications">application settings page</a>.</p>
</blockquote>

<p><img src="https://olivierlacan.com/assets/wee-bey.gif" alt="It all makes sense now!" /></p>

<p>I willingly setup two-factor authentication on github.com and
expected that my single-factor password would still work to authenticate
through HTTPS via Git. And I probably glossed over some essential warning
copy while doing so.</p>

<p><img src="https://olivierlacan.com/assets/github-personal-access-tokens.png" alt="Screenshot of GitHub's Personal Access Tokens interface" /></p>

<p>Creating a <a href="https://github.com/settings/tokens/new">new Personal Access Token</a>
on GitHub is easy and you get a hash to use as a password. <strong>That</strong> is what the
osxkeychain credential helper saves to use whenever you use HTTPS to clone or pull
GitHub repositories.</p>

<p>After the first prompt for credentials (on clone or pull), Git saves the credentials in
your Keychain and everything works as it’s supposed to.</p>

<h2 id="conclusion">Conclusion</h2>

<p>Remember to make sure that you <strong>do</strong> have the keychain credential installed.
If you do, you should see this:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre>git credential-osxkeychain
usage: git credential-osxkeychain &lt;get|store|erase&gt;

# to configure git to use it:
git config --global credential.helper osxkeychain
</pre></td></tr></tbody></table></code></pre></div></div>

<p>If you don’t have the credential helper installed or if you’re using an operating
system other than OS X, read GitHub’s new <a href="https://help.github.com/articles/caching-your-github-password-in-git/">Caching your GitHub password in Git</a> guide.</p>

<p>Outdated credentials stored in Keychain Access for <code class="language-plaintext highlighter-rouge">github.com</code> can also cause issues.
GitHub now has a <a href="https://help.github.com/articles/updating-credentials-from-the-osx-keychain/">guide on how to delete outdated credentials</a>
from either the Keychain Access interface or from the credential helper.</p>

<p>PS: I highly recommend using <a href="https://github.com/github/hub">GitHub’s Hub</a>
wrapper for Git since it allows you to clone repos with a simple
<code class="language-plaintext highlighter-rouge">git clone rails/rails</code> command. It automatically fetches the full HTTPS URL
for you and uses that for the origin remote.</p>
<img src="https://feed.olivierlacan.com/link/8226/8521080.gif" height="1" width="1"/>]]></description>
      <pubDate>Sun, 22 Dec 2013 08:30:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521080/why-is-git-https-not-working-on-github</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/why-is-git-https-not-working-on-github/</guid>
    </item>
    <item>
      <title>Put a Date on It</title>
      <description><![CDATA[<p>As I sat here tweaking some HTML &amp; CSS on my About page to use a swanky <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/figure"><code class="language-plaintext highlighter-rouge">&lt;figure&gt;</code> element</a> that I learned how to properly use from the great <a href="https://www.codeschool.com/courses/front-end-formations">Drew Barontini</a>, I realized it was silly that I had to manually refresh my browser every time. I’m using <code class="language-plaintext highlighter-rouge">jekyll serve --watch</code> to automatically update the page in the background when any file is updated so I don’t have to shut down jekyll server and restart it every time I make a change.</p>

<p>I knew about <a href="http://livereload.com/">LiveReload</a>, an app &amp; browser extension that allows you monitor files and refresh the browser only when needed and I was curious if someone else had used it with Jekyll before so I did a typical Google search: <code class="language-plaintext highlighter-rouge">jekyll livereload</code>. The first result was a StackOverlow discussion. Generally those are reliable and to the point but I was attracted by the second result, <a href="http://thanpol.as/jekyll/jekyll-and-livereload-flow/">a personal blog post from Thanasis Polychronakis</a>.</p>

<p><img src="https://olivierlacan.com/assets/jekyll-livereload-google-search.png" alt="Screenshot of my &quot;jekyll livereload&quot; google search" /></p>

<p>Hard to pass on such an amazing name and the title is right on the nose for what I was looking for.</p>

<p>As soon as the page loaded a slight panic started setting in. This is a feeling I’m extremely familiar with because as a software developer, I basically spend 50% of my time researching how to do or fix something on Google (not kidding, expert-level Google searching should be a job requirement). And once in a while, I come across an apparently well written blog post that looks like it’s the one — it’s going to solve my problem I know it!</p>

<p><strong>And there’s no date anywhere.</strong></p>

<p>I scroll down all the way to the bottom. <em>No date.</em></p>

<p>Twitter share and follow buttons, <em>but no date</em>.</p>

<p>Mostly irrelevant Disqus comments, <em>but… no date</em>.</p>

<p>The post title with no by-line should have tipped me off but I was hopeful. This is a technical topic involving fast-evolving software on the web. These things change every single day. A blog post about <a href="http://jekyllrb.com/">Jekyll</a> written two weeks ago could be obsolete because of <a href="https://github.com/jekyll/jekyll/releases">a new release</a>. Because this — potentially useful — post isn’t dated I can’t know with confidence that it applies to the same version of Jekyll I’m using.</p>

<p>There’s no way to know — at a glance — that this information isn’t irrelevant and a dead end.</p>

<p>Yes, I can sift through the Disqus comments at the bottom of the page and try to infer based on their dates when the original publication was, but that’s not how it’s supposed to go.</p>

<p>A blog post dedicated to a time-sensitive topic should include:</p>
<ul>
  <li>the title of the blog post</li>
  <li>the full name (or pseudonym) of the author</li>
  <li>the (absolute) date of publication</li>
  <li>the content of the post itself, hopefully with a reference to the version numbers of all mentioned software</li>
</ul>

<p>It is possible to customize a Google search to only return pages created during a certain time frame — for instance <a href="https://www.google.com/search?q=jekyll+livereload&amp;oq=jekyll+livereload&amp;aqs=chrome..69i57j0l5.2721j0j1&amp;sourceid=chrome&amp;espv=210&amp;es_sm=91&amp;ie=UTF-8#es_sm=91&amp;espv=210&amp;q=jekyll+livereload&amp;safe=off&amp;tbs=qdr:y">the last year</a> — but this shouldn’t be necessary.</p>

<p><img src="https://olivierlacan.com/assets/jekyll-livereload-google-search-date-filter.png" alt="Screenshot of the Google Search Tools options to select a date range" /></p>

<p>I’m making an example of Thanasis’ post (<em>say that out loud!</em>) even before I’ve finished reading it because I think nailing little details like this can help a lot of people, not because I’m trying to nitpick him for trying to help.</p>

<p>So remember, if you’re going to publish it, put a date on it.</p>
<img src="https://feed.olivierlacan.com/link/8226/8521081.gif" height="1" width="1"/>]]></description>
      <pubDate>Sat, 21 Dec 2013 13:30:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521081/put-a-date-on-it</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/put-a-date-on-it/</guid>
    </item>
    <item>
      <title>I need to write.</title>
      <description><![CDATA[<p>It’s enraging that at the time in my life when I truly need to write, somehow I worry if I’m still able to.</p>

<p>It’s not really about attempting to write and failing, it’s the perpetual problem of finding every possible distraction to keep me away from the keyboard so I can’t discover that — in fact — I have nothing to say.</p>

<p>I know I have things to say. I know some of them are relevant to a great many people because they are relevant to me. Despite being odd and loudmouthed, I’m not so different from everybody else.</p>

<p>Yet, I make myself overwhelmed with things to do, and places to go to. I convince myself that there’s a perfect environment in which the words will flow through me and out onto the screen. When I get to that perfect environment, I find a reason:</p>

<ul>
  <li>I want to talk to this person, maybe they’ll inspire me</li>
  <li>I need this drink, and then I can start</li>
  <li>There’s someone out who sent me an email and is waiting for a reply, why make them wait a second more?</li>
  <li>Shit, I need to pee now</li>
  <li>Hmm, I’m sure checking Twitter or Instagram won’t distract me</li>
  <li>Oh I know, I’ll take out my notepad and start writing with a pen instead!</li>
  <li>Wait a minute, I had a nice draft on a similar topic before, I should finish that instead</li>
</ul>

<p>So many excuses.</p>

<p>What’s even more enraging is that this digressive nature plays a great part in my creative thinking and problem solving abilities. But in moments like this, when writing isn’t the relief but the task at hand, it becomes so difficult to turn down the volume of a world I find so exciting and inspiring. It feels like disconnecting from the very thing that keeps me alive just so I can better talk about it.</p>

<p>It feels hard, but the solution is obvious: start writing.</p>
<img src="https://feed.olivierlacan.com/link/8226/8521082.gif" height="1" width="1"/>]]></description>
      <pubDate>Sat, 21 Dec 2013 11:51:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521082/i-need-to-write</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/i-need-to-write/</guid>
    </item>
    <item>
      <title>I'm an Alien.</title>
      <description><![CDATA[<p>With some very minor modifications, below is a reproduction of a Basecamp message I sent to my co-workers this afternoon.</p>

<blockquote>
  <p>Hello everyone,</p>
</blockquote>

<blockquote>
  <p>I’ve been putting off writing this because I like to think of myself as feisty and I didn’t really want to admit defeat.</p>
</blockquote>

<blockquote>
  <p>I’ve been working in the US for the last 2 and half years under a non-renewable work visa that is set to expire on December 15th, 2013. The USCIS is kind enough to extend me a grace period of 60 days beyond that date during which I can remain in the US but will no longer be allowed to work in any capacity.</p>
</blockquote>

<blockquote>
  <p>That means that unlike you suckers, I’ll be on vacation in 25 days. Haha.</p>
</blockquote>

<blockquote>
  <p>I spent about an hour on a call with an immigration attorney from San Francisco. Unsurprisingly, she deals with a lot of similar cases, and she was recommended to me by a nice British Ruby developer I met at RubyConf and who — like a bunch of other recognized or famous folks in the tech industry — obtained a prized O-1 visa. Unlike the H-1B visa I unsuccessfully applied for earlier this year (65,000 slots, over 150,000 applicants), the O-1 is not tied to a single employer-sponsor but has much stricter requirements — it’s for aliens with “special abilities”.</p>
</blockquote>

<blockquote>
  <p>Since I haven’t practiced shooting gamma rays out of my finger tips in quite some time, this is a bit of a longshot. I’ll most likely need to put on my writing cap to publish articles (in major publications if possible), apply to speak at more conferences, and hopefully extract an ebook or print book out of my brain with forceps. If you or anybody you know can help me in this process, I’ll repay you in mountains of authentic French cheese, pastries, cookies, wine and other delicacies.</p>
</blockquote>

<blockquote>
  <p>The most sensible option for me beyond December will be to fly back to France and scramble to setup a way for me to work for Code School either as a third-party or as a foreign employee. I’ve talked with an American citizen living in France about this quite a bit, and I’m doing my best to figure out how to navigate the extremely business unfriendly French legislation to avoid being buried in taxes if I’m paid in dollars while living in Euroland with 20% VAT and 50% professional taxes.</p>
</blockquote>

<blockquote>
  <p>The San Francisco attorney advised me to avoid travelling back to the US with an O-1 or H-1B application in process. That’s because the USCIS (Citizenship &amp; Immigration Services) is very sensitive about “immigration intent”. You see, while I’ve been living legally in the US for nearly 5 years, I’m a “non-immigrant”. Clearly I’m still checking out this whole USA thing, and I need to hear about payment plans before making up my mind.</p>
</blockquote>

<blockquote>
  <p>My goal now is to bump up my profile (if you thought I was self-centered before, boy you’re gonna love me next year!) as much as I can to make the O-1 possible in the medium to long term. Meanwhile I’ll be getting ready to re-apply for the H-1B on April 1st, 2014 despite the poor odds. Both O-1 and H-1B are costly (especially when using legal counsel) and time-consuming affairs, which means it’s very likely I’ll be reducing the amount of hours I work each week to a minimum. Slap me if you hear me complain about anything else, because I’m extremely fortunate to be able to work with all of you, but not being able to put 100% into Code School enrages me. I’ve never been more proud of anything else I’ve ever worked on in my life, and I don’t intend on giving up because of archaic immigration legislation.</p>
</blockquote>

<blockquote>
  <p>Now if you want to see the bright side of this, realize that a guy who can get one of the most envied Health Care coverage in the world, who can live in the city with unarguably the best selection of cheese, bread, meat, chocolate and alcohol the universe has ever known, who can quite literally live like a king by taking a bus that passes through the royal courtyard of the Louvre Palace, that this guy would rather be hanging out with you in sweaty old Orlando, Florida — where people don’t know how to drive very much but at least they’re not honking arrogant smelly pricks.</p>
</blockquote>

<blockquote>
  <p>So, there. Cuddles. And prepare for regular French onslaughts.</p>
</blockquote>

<blockquote>
  <p>Olivier.</p>
</blockquote>

<p>I’m going to write about this a lot more in the future but for now I don’t really have it in me to add much. Wherever you’re from, if you’ve been or are in this situation, I’d love to hear your story.</p>
<img src="https://feed.olivierlacan.com/link/8226/8521083.gif" height="1" width="1"/>]]></description>
      <pubDate>Wed, 20 Nov 2013 19:27:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521083/i-am-an-alien</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/i-am-an-alien/</guid>
    </item>
    <item>
      <title>Conventions: the silent feature</title>
      <description><![CDATA[<p>In the Rails world, it seems to be a truth universally acknowledged that <a href="http://en.wikipedia.org/wiki/Convention_over_configuration">convention over configuration</a> is a great philosophy.</p>

<blockquote>
  <p>“I think empty folders and empty files are two of the pivotal innovations in Rails that have encouraged us to write clean applications since the framework appeared.” — David Heinemeier Hansson during his <a href="http://www.rubyinside.com/dhh-keynote-streaming-live-from-railsconf-2011-right-here-right-now-4769.html">Keynote at RailsConf 2011</a></p>
</blockquote>

<p>Empty files and folders, isn’t that just clutter? If the files cause your application to load more slowly (because Rails needs to load them all) then yes, maybe it’s a good idea to get rid of the empty files.</p>

<p>The empty folders, however, are a gift that keeps on giving. They invite all developers who use Rails to organize their codebases in the same fashion. They ensure that you can:</p>

<ul>
  <li>look in <code class="language-plaintext highlighter-rouge">test/</code> for tests</li>
  <li>expect application-specific CSS files to be <code class="language-plaintext highlighter-rouge">app/assets/stylesheets</code> for any application CSS files</li>
  <li>search in <code class="language-plaintext highlighter-rouge">app/assets/javascripts</code> for any JavaScript or CoffeeScript code</li>
  <li>etc.</li>
</ul>

<p>I was reminded of the value of these folders this week as I started updating 35 of our Code School Rails apps to add a third-party JavaScript library. All I had to do was drop a JavaScript file in <code class="language-plaintext highlighter-rouge">vendor/assets/javascripts</code>. Semantically the location of the file implies that the code is not application-specific and from a third-party, I don’t need to document that in any other fashion.</p>

<p>Thanks to the often derided (deservedly so) <a href="http://guides.rubyonrails.org/asset_pipeline.html">Asset Pipeline</a>, I can be confident this new file will be added to the load path and available for me to require inside of <code class="language-plaintext highlighter-rouge">app/assets/javascripts/application.js</code> (or equivalent CoffeeScript files).</p>

<p>One of my favorite feature of Apple’s MacBooks is the Magsafe power adapter. I’m not talking about the fancy magnetic connector that snaps out when the power cable is accidentally yanked in order to prevent the computer to be hurled towards the ground as well. That thing is actually a sexy feature for which the value proposition is quite obvious to most customers. No, what I really love is the brick itself, it’s an often overlooked work of exquisite attention to details.</p>

<p><img src="https://olivierlacan.com/assets/conventions-apple-magsafe-adapter.png" alt="Apple Magsafe 1 Power Adapter" />
<em>Apple Magsafe Power Adapter</em></p>

<p>First, this custom-designed power brick is beautiful. Unlike most other laptop manufacturers, Apple didn’t pick a huge off the shelf power adapter unlike Sony, Samsung and other manufacturers who usually do a good job of valuing (or <a href="http://www.engadget.com/gallery/hp-envy-15-vs-the-macbook-pro/">cloning</a>) design. You could be cynical and see that as a ploy for Apple to sell non-standard plugs at a high margin. Sure, they’re non-standard and Apple likes to make a profit. But when the standard sucks, why tolerate it when your goal is to offer a better product experience?</p>

<p><img src="https://olivierlacan.com/assets/conventions-sony-vaio.jpg" alt="Sony Vaio Power Adapter" />
<em>Sony Vaio Power Adapter</em></p>

<p>Second, look at the prongs sticking out of the brick. In North America, these are foldable, which allows the brick to become a perfect square. That’s a dream when traveling light as you can fit this power adapter in the smallest bags (or purses).</p>

<p>Third, the reason you see a line separating the actual prongs and the rest of the power adapter body is because the module is (easily) removable. By sliding it out, you can swap it for a longer extension cord in case you’re sitting in a coffee shop with a distant power outlet. Better yet, this makes the body of the adapter universal. It can be used anywhere in the world as long as you swap the proper plug for the region you’re travelling to. Of course Apple sells an <a href="http://store.apple.com/us/product/MB974ZM/B/apple-world-travel-adapter-kit">Apple World Travel Adapter Kit</a> to solve that.</p>

<p>Last, and defnitely not least, the sides of the brick have little retracktable arms you can pull out to neatly fold the cable that connects directly to your laptop. At the end of that cable, a small plastic holder allows you to secure the loose end of your cable.</p>

<p>Regardless of wattage requirements necessary for different laptops, every single power adapter Apple ships behaves the same way, even some of the tiny power bricks that ship with the iPad and come with a USB cable instead. This is an amazing convention that keeps on delivering value to users, and I can’t remember a recent time where Apple touted it in their marketing material.</p>
<img src="https://feed.olivierlacan.com/link/8226/8521084.gif" height="1" width="1"/>]]></description>
      <pubDate>Tue, 19 Nov 2013 21:00:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521084/conventions-the-silent-feature</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/conventions-the-silent-feature/</guid>
    </item>
    <item>
      <title>Upgrading to OS X 10.9 with a Development Environment</title>
      <description><![CDATA[<p>I held back for a few weeks because new OS X releases are usually pretty unstable when it comes to development tools. I finally decided to update to Mavericks after encountering some Bluetooth connection issues I hoped Mavericks would resolve (nope).</p>

<p>First, I made sure I had my portable hard drive back up my system using Time Machine, to account for dire situations. I have most of my absolutely crucial files backed up to Dropbox continually anyway, but it would be a pain to re-install everything if I didn’t have a Time Machine backup handy.</p>

<p>The Mavericks update process was uneventful and took about 35 minutes which were a perfect excuse to brew some tea and read a few pages on the hammock. Tough trade we’re in.</p>

<p>My first step after restarted with a wall of Californian water was to jump to <code class="language-plaintext highlighter-rouge">System Preferences &gt; Security &amp; Privacy</code> since two apps I use were asking for me to turn the “assistive devices” feature back on. This feature has basically moved around the System Preferences in every recent release of OS X so it’s a good thing Mizage (the makers of <a href="http://mizage.com/divvy/">Divvy</a>) offers a guide. Sadly their guide is out-of-date (made for 10.8), so here’s where you can enable access for assistive devices on 10.9.</p>

<p><img src="https://olivierlacan.com/assets/mavericks-privacy-security-screen.png" alt="Screenshot of OS X System Preferences Privacy &amp; Security screen" /></p>

<p>I enjoy the fact that this is now a <a href="http://en.wikipedia.org/wiki/Whitelist">whitelist</a> instead of a global toggle as it was in 10.8. I can now control which apps can take control of my operating system’s input devices, instead of granting that privilege to anything I have installed. Thumbs up for security there, Apple.</p>

<p>Second step once <a href="http://smilesoftware.com/TextExpander/index.html">TextExpander</a> and Divvy were back in service was to open the Terminal app and run <code class="language-plaintext highlighter-rouge">brew doctor</code>. <a href="http://brew.sh/">Homebrew</a> is a package manager for command line utilities that makes life extremely easy for developers. If you don’t already use it (or you still use the antiquated MacPorts) you should.</p>

<p><img src="https://olivierlacan.com/assets/mavericks-brew-doctor-results.png" alt="Screenshot of brew doctor command results" /></p>

<p><a href="http://xquartz.macosforge.org/landing/">XQuartz</a> started being necessary (as a standalone install) since 10.8 I believe, and it’s fairly simple to <a href="http://xquartz.macosforge.org/trac/wiki/X112.7.5">download and install</a>, especially since the Homebrew folks do most of the work for your.</p>

<p>Next step was <code class="language-plaintext highlighter-rouge">xcode-select --install</code> which will open Xcode and make it prompt you to download and install Command Line Tools. Remember that the CLTs which Apple now ships independently of Xcode make it unecessary to use Kenneth Reitz’ nifty <a href="https://github.com/kennethreitz/osx-gcc-installer">OS X GCC Installer</a> which was often necessary with OS X 10.7 (Lion) and 10.8 (Mountain Lion) when Apple screwed up most Mac development environments pretty badly.</p>

<p>I’m not exactly sure why autoconf, automake and libtool showed up as unlinked. This may have something to do with the upgrade process messing with the file system. mysql is something I manually uninstalled prior to upgrading to Mavericks, so you can ignore that one.</p>

<p>Fixing those is rather easy.</p>

<p><img src="https://olivierlacan.com/assets/mavericks-brew-link-autoconf.png" alt="Screenshot of brew link autoconf results" />
<img src="https://olivierlacan.com/assets/mavericks-brew-link-automake.png" alt="Screenshot of brew link automake results" />
<img src="https://olivierlacan.com/assets/mavericks-brew-link-autoconf.png" alt="Screenshot of brew link libtool results" /></p>

<p>After all this, re-running <code class="language-plaintext highlighter-rouge">brew doctor</code> is a good idea, to see where things are.</p>

<p>Since I couldn’t <code class="language-plaintext highlighter-rouge">brew link mysql</code> because I had uninstalled it, I googled around and found that <code class="language-plaintext highlighter-rouge">brew remove --force mysql</code> would get rid of it altogether. Nifty trick, especially since Homebrew insisted I had “multiple versions installed”. I didn’t. I never use the damn thing. Switch to <a href="http://www.postgresql.org/">PostgreSQL</a> by the way, you’ll thank me in a few years.</p>

<p>Finally a little <code class="language-plaintext highlighter-rouge">brew update</code> to fetch new formulae (recipes to install packages in Homebrew parlance). One last <code class="language-plaintext highlighter-rouge">brew doctor</code> and the satisfying result:</p>

<blockquote>
  <p>Your system is ready to brew.</p>
</blockquote>

<h2 id="state-of-the-rubies">State of the Rubies</h2>
<p>I use <a href="http://rbenv.org/">rbenv</a> to manage a myriad of different Ruby versions required by old apps I built in college which use Ruby MRI 1.8.x, somewhat old apps I built after college which use Ruby MRI 1.9.2, and most of our Envy Labs and Code School apps which use various patch levels of MRI 1.9.2, 1.9.3, 2.0.0, JRuby, etc.</p>

<p>After using <a href="http://rvm.io/">RVM</a> for several years, I highly recommend rbenv because of its simplicity. There’s a caveat. I’m fairly familiar with Unix by now, and it’s very likely that if you’re not as familiar you will prefer RVM overall. That said, as someone who easily becomes frustrated with latency, I’m under the impression rbenv is faster. It’s very likely bias on my part because I used RVM a while back on older machines and because I’ve become better at streamlining my system. Aesthetically, I find myself enjoying the simplicity of rbenv as well.</p>

<p>I use rbenv with the following plugins installed in <code class="language-plaintext highlighter-rouge">~/.rbenv/plugins</code>:</p>
<ul>
  <li><a href="https://github.com/carsomyr/rbenv-bundler">rbenv-bundler</a> which prevents me from having to type <code class="language-plaintext highlighter-rouge">bundle exec &lt;gemname&gt;</code> for gems with executables installed via a project’s Gemfile.</li>
  <li><a href="https://github.com/sstephenson/rbenv-gem-rehash">rbenv-gem-rehash</a> which automatically runs <code class="language-plaintext highlighter-rouge">rbenv rehash</code> for you after installing gems with executable binaries so you can instantly use said binaries without reloading your prompt or manually running <code class="language-plaintext highlighter-rouge">rbenv rehash</code>.</li>
  <li><a href="https://github.com/sstephenson/ruby-build">ruby-build</a> which allows me to run <code class="language-plaintext highlighter-rouge">rbenv install 2.0.0-p247</code> directly when I need to install a Ruby version.</li>
</ul>

<p>After installing Mavericks, <code class="language-plaintext highlighter-rouge">rbenv</code> was fully functional and I managed to install Ruby 2.1.0-preview1 without a hitch. Better yet, all my existing Rubies worked fine and I was able to fire up <a href="https://github.com/Rodreegez/powder">Powder</a> — a lovely little gem I use to manage <a href="http://pow.cx/">Pow</a> for all my Rails projects so I don’t have to manually setup their <code class="language-plaintext highlighter-rouge">rails server</code> on different ports.</p>

<p>This was by far the smoothest OS X upgrade experience I’ve ever had with a Rails development environment installed on my machine. That doesn’t mean I won’t run into some hiccups later, but it’s reassuring for people like me who stay away from upgrades for fear of having a day of work ruined trying to get things back to normal.</p>

<p>PS: If you enjoy all these talks of tools, you should check out my <a href="https://olivierlacan.com/tools/">toolbelt</a>.</p>
<img src="https://feed.olivierlacan.com/link/8226/8521085.gif" height="1" width="1"/>]]></description>
      <pubDate>Tue, 12 Nov 2013 16:00:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521085/upgrading-to-os-x-10-9-mavericks-with-a-development-environment</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/upgrading-to-os-x-10-9-mavericks-with-a-development-environment/</guid>
    </item>
    <item>
      <title>Tiny Features</title>
      <description><![CDATA[<p>Whether you consider yourself a designer, a developer, or a balanced hybrid of both, we all tend to have the mindset of engineers. Every day I work on growing <a href="http://codeschool.com">Code School</a>, a product I care deeply about. Naturally, there’s an urge that develops in my brain: I need to find the next great feature. The thing that will delight my users. The well-thought out system that will make them go: “Whoa, I would never have thought of that, but that’s exactly what I needed.”.</p>

<p>Sadly I have a tendency to become blind to low-hanging fruits. The tiny features that can drastically affect our users’ experience but may not involve impressive engineering feats.</p>

<p>Last year I worked on adding the ability for Code School <a href="http://www.codeschool.com/enroll?team=true">teams</a> to have Managers. No, we weren’t trying to introduce middlemen between our team members and their learning. We had been receiving an increasing number of customer support requests from people who worked in companies where developers and designers were using Code School. The people who reached out to us weren’t themselves developers or designers but they needed to be able to invite new employees to their Code School team. Perhaps they were in charge of all company expenses and therefore weren’t comfortable giving the company’s credit card information to another employee.</p>

<p>We hadn’t considered this yet. It would have been hard for us to derive a usage pattern from a situation we weren’t familiar with within our own team at <a href="http://envylabs.com">Envy Labs</a>. Instead of trying to predict that people would need a feature like this, we reacted when our own paying customers proved to us that it would be worth spending time developing it.</p>

<p>We started working on the feature, and during one our pairing sessions, I decided (and my pair agreed) that it would make sense for people who created a Code School team to not become a playing member of that team. We made it so that they would be offered an easy way to join the team and have access to all our content, which meant using up a paid seat.</p>

<p>I know what you’re thinking. It makes no sense because this person just paid for a subscription (which defaults to one paid seat) and they can’t access our content until they express the intention to do so. Through a combination of over-focus on the details of the feature, and over-exposure to the customer support data that prompted this feature to be considered, somehow, it made absolute perfect sense to me at the time. I thought it was fucking brilliant.</p>

<p>Except it so very much wasn’t. After a few weeks we started receiving complaints from people who had just subscribed to a team account and said they couldn’t access our courses when they tried right after subscribing. At first I scoffed with the overconfidence of someone who has come to trust something they contributed to building way too much, and then it hit me. Oh shit, they didn’t notice the button and the carefully worded copy that offered them to join their team as a playing member.</p>

<p>“Oh, people”, I thought to myself. “Can’t be bothered to read an easy little button, huh?”. Bullshit! When a user proceeds with an action (subscribing) that involves upfront payment, they except the goods to be given to them as soon as the payment clears. What did I do? I introduced an extra step in that process, in way that would have made Windows Vista proud.</p>

<p>And this is where I get to my point. This is the code that ultimately determined this behavior:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="k">if</span> <span class="n">subscription</span><span class="p">.</span><span class="nf">team?</span>
  <span class="n">ensure_owner_in_members</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>And this is all I had to do to provide a much nicer initial flow to our team customers:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="k">if</span> <span class="n">subscription</span><span class="p">.</span><span class="nf">team?</span>
  <span class="n">ensure_owner_in_members</span>
  <span class="n">ensure_owner_in_managers</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This was a minuscule feature. I really can’t call it a bug fix. There was no bug in here, only intentional behavior, however poorly thought out. Yet, the impact this feature had on our customers wasn’t miniscule at all.</p>

<p>PS: I recently asked the <a href="http://tenderapp.com">Tender</a> team to add a keyboard shortcut (the mighty <code class="language-plaintext highlighter-rouge">Command + Enter</code>) to submit a comment in their customer discussion interface. Our community manager, <a href="http://twitter.com/yooosef">Joseph</a>, had mentioned to me that he mashes his <code class="language-plaintext highlighter-rouge">Tab</code> key 5 times in a row and presses <code class="language-plaintext highlighter-rouge">Space</code> in order to comment &amp; close a support discussion on Tender. It has become muscle memory to him, so it will be hard to remap that behavior to the new <code class="language-plaintext highlighter-rouge">Command + Shift + Enter</code> shortcut that allows him to do that in a single stroke, but thankfully it will stave off his carpal tunnel syndrome.</p>

<p>Julien, the Tender developer who took care of this, inspired this post with his response when I thanked him in a tweet for the feature:</p>

<p>https://twitter.com/asciithoughts/status/370314878470193152</p>
<img src="https://feed.olivierlacan.com/link/8226/8521086.gif" height="1" width="1"/>]]></description>
      <pubDate>Thu, 22 Aug 2013 09:28:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521086/tiny-features</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/tiny-features/</guid>
    </item>
    <item>
      <title>Expert Bias</title>
      <description><![CDATA[<p>Craftsmanship is a fascinating thing. I’ve yearned for it for as long as I can remember.</p>

<p>Recently, I started becoming aware of a downside to increasing expertise in a specific domain and the attention to details it affords. I refer to it as “Expert Bias” and define it as follows: the inability for a person who has mastered a skill to understand how useful that skill can be to laypeople.</p>

<p>It’s rather broad, so let me clarify. As a computer programmer, I’m surrounded by scores of intelligent people with a knack for problem solving. They like to better themselves in order to improve their workflow and to create better, and more maintainable software for their customers and for themselves. They, and I, see this pursuit as something that can obviously benefit the end goal: solving people’s problems.</p>

<p>The problem I see lies in the inexorable erosion of empathy that seems to accompany the accumulation of expertise. Mastery requires perpetually increasing one’s standards in order to achieve better, faster, stronger work. In doing so, you disconnect yourself more and more from the common tastes and standards of the people who need your help most: business owners, creative minds, and customers. All of them who seek your expertise to help solve their problems.</p>

<p>That disconnection is pernicious. People in domains that require highly specialized knowledge often marvel at the illiteracy of others in that specific domain, especially if they’re expected to interact with those Others.</p>

<p>In my world, those Others are customers, although we like to refer to them as students. Those students give us money in exchange for knowledge. They need this knowledge and trust that we can provide it to them.</p>

<p>The proposition that we can teach them what we know in exchange for money holds as long as their skill level and ours are within the same order of magnitude. They have some knowledge. We have some other knowledge. They wish to acquire the knowledge which we have and they don’t. It is possible for us to have a mental image of the skills they currently possess and imagine a path from their existing knowledge to the set of knowledge we aim to impart on them.</p>

<p>An issue arises when the amount of knowledge we possess is radically different from our students. If operating a modern computer is already a tedious process for them, there’s a good chance it will be much more difficult for us to:</p>

<ol>
  <li>Empathize with their current state of knowledge and what they currently struggle with.</li>
  <li>See a path between their current knowledge and the knowledge they wish to obtain from us.</li>
</ol>

<p><a href="http://maxvoltar.com/">Tim Van Damme</a> once gave <a href="https://speakerdeck.com/maxvoltar/web-designers-unite">an excellent demonstration</a> of this problem using the slope of a mountain. From the base of the mountain, the top seems unreachable. From the top of the mountain, it doesn’t seem like the climb was so hard after all.</p>

<p><img src="https://olivierlacan.com/assets/expert-bias-climbing-to-knowledge.png" alt="Climbing to Knowledge" /></p>

<p>You, at the top of the mountain, tend to forget the fear, the confusion, the shame, the sweat, the impasses, and the temptation to give up you had up until the summit was within reach.</p>

<p>You are not the most suited to give advice to the people at the base of the mountain. Sure, this has a lot to do with emotions. If not everything. It’s much easier to empathize with people you know, or who are not so different from you. From the perspective of the beginners, it’s easy to develop an inferiority complex or find it aggravating when people who seem to have it all figured out try to help you.</p>

<p>But I think it’s not just about emotions. Human beings have an extremely selective memory. We’re great at remembering the hits and forgetting the misses.</p>

<p>To stay vaguely in the realm of mountaineering, think of a brick wall. To me that’s what getting started as a beginner feels like: standing in front of a two-story tall wall separating you from a fucking mountain of knowledge. Before you can even start to worry about the mountain, you’re left without a clue as to how to get past this wall.</p>

<p>Experts are masters at forgetting the wall even exists.</p>

<p>Can you blame them? If you spend your days miles high on a mountain top, what’s a two-story wall to you?</p>

<p>The base of that brick wall is littered with the hopes of people who were given advice by people standing on top of a fucking mountain.</p>

<p>Thanks to Tim’s metaphor, it’s easier to understand that the people best suited to give advice to the wall climbers are the people who just figured out how to get past it.</p>

<p>It’s true that expert climbers have better technique. They know how to deal with severe weather during a high altitude climb for instance. But all that knowledge is not going to help the bricketeers right now. At best it will confuse them.</p>

<p>What’s worse, the experts have probably forgot what it’s like to climb masonry. They don’t have to deal with that anymore. They have bigger fish to climb.</p>

<p>That last part gnaws at me perpetually. I obviously strive to become the best I can be at what I do, but I do care about the people climbing behind me. More importantly, since I love building products, I care about the people whose problems I’m trusted to solve. What if I’m climbing an ivory tower and my trophy will be to lose all empathy?</p>

<p>I need my students. They’re not a means to my end, they are my end. They fuel my passion, they provide me with an endless stream of problems to solve. What if in the process of becoming better at solving things I became unable to care about what I solve? If this sounds like the fiery pits of cynic hell to you then maybe we have a shared incentive to help each other re-focus on what matters.</p>

<p>The way I achieve that renewed focus is by running all the way to the bottom of the damned mountain. What does that mean? Well for once, you can try spending a whole day doing customer support instead of rushing to ship that new feature you’ve been working on for weeks and months. You might just realize that, in fact, most of your customer’s problems are much easier to solve than the overengineered solutions you like to challenge yourself with.</p>

<p>The breeze on the way down from the top of the mountain is quite refreshing. When I get back to the base, the scenery is always much nicer than I remember. Things are much clearer somehow, and it helps me remember what really matters. Yes, I can’t see miles ahead any longer, but the beautiful mountain of knowledge I was sitting on becomes apparent. It’s harder to take it for granted, or to feel like an impostor because it seems like you’re making it up as you go along.</p>

<p>The people at the base of the knowledge mountain aren’t simplistic barbarians kept away by the brick wall. They’re curious souls with simple problems that I might just have the ability to solve. They’ll be thankful and I will feel amazing having shipped simple and efficient solutions to simple and real problems.</p>

<p>I understand intelligent people — programmers especially — are attracted to hard problems. I’m not, or at least I try not to be. The simpler problems may not look like they amount to much when looked down upon, but they matter to many people. It’s easy to forget how much.</p>

<p>What’s the point in learning magic if you don’t use it to help and delight people?</p>

<hr />

<p>PS: There’s apparently a phenomenon referred to in psychology as <a href="http://www.psychologytoday.com/blog/everybody-is-stupid-except-you/201008/the-expertise-bias">“The Expertise Bias”</a> which I didn’t know about before writing this piece.</p>

<p>PPS: <a href="http://seriouspony.com/about/">Kathy Sierra</a> posted a <a href="https://www.youtube.com/watch?v=tTfKbKlgwAY">great video entitled Expertise Induced Amnesia</a> from a different domain — horse-riding. In it Mary Wanless explains the issue I’ve tried to surface in this post in a much more concise way. I highly recommend watching this.</p>
<img src="https://feed.olivierlacan.com/link/8226/8521087.gif" height="1" width="1"/>]]></description>
      <pubDate>Fri, 12 Jul 2013 11:47:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521087/expert-bias</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/expert-bias/</guid>
    </item>
    <item>
      <title>I fell off my bike</title>
      <description><![CDATA[<p>This afternoon I fell off my bike. I had just spent a lovely afternoon
and wanted to ride in the gentle sun before two weeks away from home. I
was even more excited because a few hours earlier I just had my front
wheel fixed at Orange Cycle — a few days ago I accidentally bumped into
my bike with my car while parking.</p>

<p>The sun was warm but at an angle low enough to not even make me sweat.
There were a few clouds in the sky, tall beautiful ones that bring out
the rich blue and green colors all around. I felt so good after a few
paces I lifted my hands up and let the wind dance through my fingers.</p>

<p>I often do this. I bought this bike — a road bike, not a fixie, I enjoy
well-engineered bikes, not sweating and breaking with my feet to feel
authentic — about a year and a half ago. I’ve ridden quite a few
different bikes throughout my life:</p>

<ul>
  <li>A crappy golden cross bike my parents got me at a garage sale that
looked like a beat up Harley</li>
  <li>A cheap all-terrain bike we won with supermarket loyalty points and
which disintegrated (chain and all) in the middle of traffic while I
was riding home from work in busy Parisian boulevard traffic</li>
  <li>A fancy urban bike with front and back suspensions, a kick-ass black
design, a comfortable seat for the taint-hating Parisian pavement &amp;
sidewalks that I rode with in Paris through traffic jams and got me to
college faster than any engine-bearing vehicle in the city could</li>
  <li>And the most recent, my first road bike, which I decided to buy when I
realized that Central Florida was lizarded (can’t believe that’s not a
verb here) with beautiful bike trails that let you see much more of
the Florida wildlife (lakes, fields, rivers) than you would ever see
otherwise</li>
</ul>

<p>Since it was my first road bike, it took me a while to feel comfortable
riding it, especially since it’s hard to use a bike as a commute vehicle
in Florida. For most of the year it’s too hot to ride one comfortably,
but more importantly I promised myself I would never ride outside of
trails. Because Florida is so vast, it’s extremely uncommon for drivers
to cohabitate with cyclists. Unsurprisingly, since drivers don’t expect
cyclists, they don’t account for them in their manoeuvers. It’s easy to
blame the drivers, since too many people I know were seriously injured
in bike/car collisions, but not every driver in the world has been
subjected to the constant flow of brazenly inexperienced cyclists a city
like Paris has. That shit — along with smart cars, vespas, buses and
taxis — turns you into an expert defensive driver, and a misanthrope.</p>

<p>Anyway, I fell off the damn bike. She doesn’t deserve that moniker,
although I still dislike how easily road bikes swerve when they’re
rarely ever used for sharp turns, that makes no sense to me. My point
with the long history of my bike ownership was to show that while I’m
not an accomplished cyclist, I’ve been around the block on a bike.</p>

<p>Since road bikes sacrifice comfort for aerodynamism, they invite
dangerous behavior when riding in long straight stretches. You perk your
head up, lock your feet and knees in a stable stance and off go the
hand, caressing the flow of oxygen drifting by.</p>

<p>It’s a design flaw. Having handlebars slight elevated compared to the
seat makes sense, it also lowers you and the bike’s center of gravity.
The front axis not being so fucking loose wouldn’t hurt either. But I’m
doing that thing when you hit a terrible shot at ping pong or tennis (or
baseball, let’s make it colloquial) and then immediately look at the
damn racket as if it was operating on its own and you weren’t the single
point of failure.</p>

<p>Yes, I got cocky. I felt awesome. I felt safe. Not invincible, I’m not
that stupid, but safe enough. It’s been years since I fell off a bike
this hard. I think the last time was when the chain and entire front
wheel axis of a cheap bike decided to bail when I was crossing a very
quiet street by a lovely little bridge south of the Seine. I had it
easy, just a bleedy elbow scrape and some minor carpet burns on my
hands. Some cold water took care of it.</p>

<p>This one wasn’t bad but it could have been. It might have been a bump in
the road or I just lost my balance and it all went really fast.</p>

<p>I think my shoulder hit the pavement first, which would explain the
small hole in my brand new t-shirt and the friction burn. Then came
something I really didn’t like. I wasn’t wearing a helmet — doesn’t
really work with the long hair, although I often wear one if I’m going
to ride on roads with motor vehicles — so while it’s possible that the
contact of my head with the pavement made my lose a few seconds I
remember the very uncomfortable feeling of the pavement rubbing against
my head (at about 5 to 10 miles an hour and decelerating). I really
didn’t enjoy that, thankfull I quick rolled on my thigh and hip.</p>

<p>That didn’t feel great on the hip but at least there’s more bumper
there. Can’t wait to see the size of that bruise though.</p>

<p>I quickly got on my feet and a minivan that was following behind me
slowed down and parked, the driver asked if I was alright after lowering
his side window. I ran a quick mental check list:</p>

<ul>
  <li>no gushing wounds: check</li>
  <li>no weird feeling of nausea/lightheadedness or stars from the head
trauma: check</li>
  <li>wobbly legs but no apparent foreign objects: check</li>
  <li>fingers intact (my livelihood, that would suck): check</li>
  <li>phone in working condition I’m just trying to save face: check</li>
  <li>within reasonable walking distance of my car (less than 5 min): check</li>
</ul>

<p>I told the nice human being that I was alright, and dragged my bike away
from the path. The bike path was large and well delineated but right
alongside the roadway. Good thing I make it a habbit to stop fucking
around the with no handlebars thing whenever a car is too close or this
could have gone wrong. There was no traffic anywhere close to me when I
fell. But I got really lucky on the obstacle (during my fall) front.</p>

<p>It’s several hours later now and while some of my burns &amp; scrapes are
painful I’ll survive and my head trauma is extremely minor with no
bleeding. I’ll get it checked out as soon as I can figure out where the
nearest urgent care clinic is (this clearly doesn’t warrant an Emergency
Room visit).</p>

<p>That said the very fact I decided to write all this down (after calling
a friend to see if someone can drive me to a clinic, calm down) shows
that accidents like this cause reflection. I subscribe to the idea that
failure isn’t necessarily something you can learn anything valuable
from. It teaches you about failure, that’s about it, maybe about caution
too. I will not cease to ride my bike with no handle bars, and while I
will make it a point to wear a helmet whenever I’m close to a roadway,
all the precautions in the world won’t change the fact that at some
point in the future, I will fall off my bike again.</p>

<p>It will hurt, it will piss me off, I will have let my guard down,
because it’s impossible to be constantly cautious. Or if it is, I don’t
want to be. I’d rather live and lick a few mean wounds once in a while.</p>

<p>No what I enjoyed about this incident is that it has shown me that the
minimum amount of security I practice is reasonable. I have two first
aid kits at my house, sufficient material to clean up and dress wounds.
I know where the nearest urgent care and ER are. I keep enough battery
in my phone to be able to find help if necessary. I know not to lie down
after any head trauma, to stay alert and make sure someone I know is
aware of my state so they can help me out if something goes wrong.</p>

<p>In other words, while I fucked up, my system worked. If hadn’t been able
to use my own system, I trust that my fellow human beings’ systems would
have worked to get me help. Like many accidents, this is a reminder that
everything isn’t so bad.</p>

<p>It’s easy to overreact to failure, or try in vain to learn from it.</p>
<img src="https://feed.olivierlacan.com/link/8226/8521088.gif" height="1" width="1"/>]]></description>
      <pubDate>Sat, 27 Apr 2013 21:02:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521088/i-fell-off-my-bike</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/i-fell-off-my-bike/</guid>
    </item>
    <item>
      <title>Problem Solvers</title>
      <description><![CDATA[<p>If there’s a common thread uniting all the people that inspire me, motivate me, and who I work with, it’s that they’re addicted to solving problems.</p>

<p>When I was a kid I thought raising the seat of a bicycle was a tedious process. Tools were still partly within the realm of adults, and carrying tools on a ride didn’t make sense to me.</p>

<p>So I took a pencil and a piece of paper and started designing a solution to that problem. It had been solved elsewhere. Nobody takes out a wrench every time they want to raise and lower their office chair. Instead office chairs are built with a hydraulic cylinder that can easily raise and lower, sometimes even while still remaining seated.</p>

<p>I didn’t have the skills necessary to make my idea come true, or even to see what could challenge its implementation, but I was using my imagination to try to solve a problem that was very real to me, and certainly to more people in the world.</p>

<p>This was an instance where my ambitions exceeded my abilities, but with maturity, some creative people learn to tame their ambitions and take on simpler problems.</p>

<p>For several summers while I was a teenager I worked as a summer intern in the factoring company my dad worked at in Paris’ Central Business District — known as “La Défense”. I’ve always been fascinated by skyscrappers and this was the only place in Paris where skycrappers are allowed to be built (that’s another story) so it was a great opportunity to make some money while being surrounded by cool stuff I could take pictures of.</p>

<p>Most summer interns for that company weren’t hired because of particular skills, so most of the tasks that were assigned to us were tedious filling tasks. Some enlightened employees did understand that they could benefit from our basic skills by letting us parse through smaller clients and actually lessen their current workload.</p>

<p>Over the course of several mornings I started noticing a strange ritual. Account managers whose specific task was to… manage accounts were spending up to 45 minutes routing external and internal mail that was deposited in a huge pile twice a day in the mail room.</p>

<p>People with a substantially higher salary than mailroom employees were doing the job of mailroom employees, for almost four hours a week, and seemingly for every individual department in the company.</p>

<p>This drove me nuts, and I didn’t even work there. It was repetitive, never-ending tedium that no one seemed to rebel against. Worse, each department had a copy/mail room with dozens of unlabelled racks.</p>

<p>The problem was there, in front of everyone, every day, and the solution was starring them in the face. In fit of “trouble making”, I spent an entire morning doing a census of all the employees on my floor, asked them the volume of mail they usually received every day (to gauge the rack space they might require) and tried to figure out how to designate any “catch-all” inboxes for mail without a specific receiver.</p>

<p>Better yet, I established an index of which companies belonged to which account manager to ensure that the mail people could figure out that an envelope with a “Sofradec” logo should go straight to Michel Denis.</p>

<p>I then printed labels in a very legible font (either Helvetica or the company’s slab font) and taped each rack in the mail room with the name of its rightful owner.</p>

<p>Reactions were a mix of boredom and amazement (yep…) and within a few days, the mail distribution rotations were reduced to a mere 5 minutes. I was elated, because I made people’s lives a little less repetitive. I don’t know if the system lasted, was replaced or improved upon later on.</p>

<p>As an outsider, I was able to spot the inefficiencies of that team very easily and provide an even easier fix that was completely painless to them. I don’t want to put all the blame on them for not figuring out something that simple earlier, it’s very easy to become stuck in tedium when it creeps up on you slowly.</p>

<p>This was a valuable lesson for me, now whenever I find myself acclimating to some inefficiency I have an allergic reaction against it and I do all I can to eliminate it. The most recent examples that come to mind:</p>

<ul>
  <li>buying new trash cans for our office at <a href="http://envylabs.com">Envy Labs</a> because we were spending each day filling and emptying the shitty Ikea trash cans we bought when we first moved in</li>
  <li>buying a cheap plastic paper towel dispenser for our bathrooms because we were all ripping towels in pieces from the default metal dispenser</li>
  <li>grabbing a screwdriver to tighten the hinges of a door that was becoming increasingly difficult to open</li>
  <li>buying cheap Ikea lamps to use diffused lighting instead of bright overhead lights when working after sunset in the office, to prevent eyestrain that turns into headaches</li>
</ul>

<p>Yes, many of these involve a purchase. Sometimes you can save a lot of time and frustration by investing a little money. You spend most of your life at work, make the best of it.</p>

<p>Most importantly, keep <a href="https://speakerdeck.com/jasonvnalue/three-pipe-problems">solving problems</a>.</p>
<img src="https://feed.olivierlacan.com/link/8226/8521089.gif" height="1" width="1"/>]]></description>
      <pubDate>Thu, 27 Dec 2012 14:46:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521089/problem-solvers</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/problem-solvers/</guid>
    </item>
    <item>
      <title>In Their Shoes</title>
      <description><![CDATA[<p>When’s the last time your put yourself in your customers’ shoes? Not just their shoes, their skin?</p>

<p>When is the last time you had a long hard day of work and tried to use your own product like someone who expects things to be easy after a though one?</p>

<p>When is the last time you got really angry because something didn’t work right when you finally had time to play with it?</p>

<p>The clarity such empathy can offer you is tremendous. You can find easy fixes, simple rewrites that will have a much more massive impact than some of the ambitious engineering and design projects you have underway.</p>

<p>All it takes is to stop building for a moment and experience the other side, and you just have to do that once in a while.</p>
<img src="https://feed.olivierlacan.com/link/8226/8521090.gif" height="1" width="1"/>]]></description>
      <pubDate>Sun, 02 Dec 2012 09:59:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521090/in-their-shoes</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/in-their-shoes/</guid>
    </item>
    <item>
      <title>Associations in Rails 4 (Erratum)</title>
      <description><![CDATA[<p><strong>Update (2013-12-29)</strong>: <em>I can’t believe I’ve never corrected this post over the last year. The changes in JSON output I describe below have nothing to do with Rails 4. What I (shamefully) forgot to mention was that I had replaced jbuilder with <a href="https://github.com/rails-api/active_model_serializers">active_model_serializers</a> in the app I was testing Rails 4 with, that is why the JSON output was different.</em></p>

<p>Associations in Rails 4 return a CollectionProxy instead of an Array. Calling a model’s association in Rails 4 might yield <del>some surprises and unexpected breakage if you don’t take a careful look at what’s changed</del> <em>no difference whatsoever</em>.</p>

<p>Considering two models with a has_and_belongs_to_many (HABTM) association to each other.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="k">class</span> <span class="nc">Article</span> <span class="o">&lt;</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Base</span>
  <span class="n">has_and_belongs_to_many</span> <span class="ss">:tags</span>
<span class="k">end</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="k">class</span> <span class="nc">Tag</span> <span class="o">&lt;</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Base</span>
  <span class="n">has_and_belongs_to_many</span> <span class="ss">:articles</span>
<span class="k">end</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="array-vs-collectionproxy">Array vs. CollectionProxy</h2>

<p>First, let’s create some records to play with.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="n">tag</span> <span class="o">=</span> <span class="no">Tag</span><span class="p">.</span><span class="nf">create</span><span class="p">(</span><span class="ss">name: </span><span class="s2">"Movie"</span><span class="p">)</span>
<span class="c1">#&lt;Tag id: 1, name: "Movie", created_at: "2012-11-02 06:18:29", updated_at: "2012-11-02 06:18:29"&gt;</span>

<span class="n">article</span> <span class="o">=</span> <span class="no">Article</span><span class="p">.</span><span class="nf">create</span><span class="p">(</span><span class="ss">title: </span><span class="s2">"Inception"</span><span class="p">,</span> <span class="ss">tag: </span><span class="n">tag</span><span class="p">)</span>
<span class="c1">#&lt;Article id: 1, title: "Inception", created_at: "2012-11-02 06:20:46", updated_at: "2012-11-02 06:20:46"&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now time to see how they behave differently.</p>

<h3 id="in-rails-3x">In Rails 3.x</h3>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="n">article</span><span class="p">.</span><span class="nf">tags</span>
<span class="o">=&gt;</span> <span class="p">[</span><span class="c1">#&lt;Tag id: 1, name: "Movie", created_at: "2012-11-02 06:18:29", updated_at: "2012-11-02 06:18:29"&gt;]</span>

<span class="n">article</span><span class="p">.</span><span class="nf">tags</span><span class="p">.</span><span class="nf">class</span>
<span class="o">=&gt;</span> <span class="no">Array</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="in-rails-400">In Rails 4.0.0</h3>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="n">article</span><span class="p">.</span><span class="nf">tags</span>
<span class="o">=&gt;</span> <span class="p">[</span><span class="c1">#&lt;Tag id: 1, name: "Movie", created_at: "2012-11-02 06:18:29", updated_at: "2012-11-02 06:18:29"&gt;]</span>

<span class="n">article</span><span class="p">.</span><span class="nf">tags</span><span class="p">.</span><span class="nf">class</span>
<span class="o">=&gt;</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Associations</span><span class="o">::</span><span class="no">CollectionProxy</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>So far nothing too different, right? Sure it’s a different class but the output is the same.</p>

<p>Well, let’s add controllers and a basic JSON API. The console is a nice sandbox but I wonder how this new CollectionProxy works in the real world.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="k">class</span> <span class="nc">TagsController</span> <span class="o">&lt;</span> <span class="no">ApplicationController</span>
  <span class="n">respond_to</span> <span class="ss">:json</span><span class="p">,</span> <span class="ss">:html</span>

  <span class="k">def</span> <span class="nf">index</span>
    <span class="vi">@tags</span> <span class="o">=</span> <span class="no">Tag</span><span class="p">.</span><span class="nf">all</span>
  <span class="k">end</span>
<span class="k">end</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Nothing too fancy here, we’re only responding with JSON and trusting Rails to format the output for the index action of the tags controller.</p>

<h2 id="fetching-tagsjson">Fetching <code class="language-plaintext highlighter-rouge">/tags.json</code></h2>

<h3 id="in-rails-3x-1">In Rails 3.x</h3>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="p">[</span>
  <span class="p">{</span>
    <span class="ss">created_at: </span><span class="s2">"2012-11-02T06:18:29-05:00"</span><span class="p">,</span>
    <span class="ss">id: </span><span class="mi">1</span><span class="p">,</span>
    <span class="ss">name: </span><span class="s2">"Movie"</span><span class="p">,</span>
    <span class="ss">updated_at: </span><span class="s2">"2012-11-02T06:18:29-05:00"</span>
  <span class="p">}</span>
<span class="p">]</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="in-rails-400-1">In Rails 4.0.0</h3>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
</pre></td><td class="rouge-code"><pre><span class="p">[</span>
  <span class="p">{</span>
    <span class="ss">tag: </span><span class="p">{</span>
      <span class="ss">created_at: </span><span class="s2">"2012-11-02T06:18:29-05:00"</span><span class="p">,</span>
      <span class="ss">id: </span><span class="mi">1</span><span class="p">,</span>
      <span class="ss">name: </span><span class="s2">"Movie"</span><span class="p">,</span>
      <span class="ss">updated_at: </span><span class="s2">"2012-11-02T06:18:29-05:00"</span>
    <span class="p">}</span>
  <span class="p">}</span>
<span class="p">]</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Alright, now the records being returned are surrounded by a <code class="language-plaintext highlighter-rouge">tag</code> object. Not really sure why it isn’t called <code class="language-plaintext highlighter-rouge">tags</code> instead since this is supposed to be a collection of tags, but let’s move on.</p>

<p><strong>Update (2013-12-29)</strong>: <em>Yes, that’s because I’m using <a href="https://github.com/rails-api/active_model_serializers">active_model_serializers</a> instead of the Rails 4 default of jbuilder. Nothing else.</em></p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="k">class</span> <span class="nc">ArticlesController</span> <span class="o">&lt;</span> <span class="no">ApplicationController</span>
  <span class="n">respond_to</span> <span class="ss">:json</span><span class="p">,</span> <span class="ss">:html</span>
 
  <span class="k">def</span> <span class="nf">show</span>
    <span class="n">respond_with</span> <span class="vi">@article</span> <span class="o">=</span> <span class="no">Article</span><span class="p">.</span><span class="nf">find</span><span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="ss">:id</span><span class="p">])</span>
  <span class="k">end</span>
<span class="k">end</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>We built a simple show action of the articles controller.</p>

<h2 id="fetching-articles1json">Fetching <code class="language-plaintext highlighter-rouge">/articles/1.json</code></h2>

<h3 id="in-rails-3x-2">In Rails 3.x</h3>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="p">{</span>
  <span class="ss">created_at: </span><span class="s2">"2012-11-02T00:57:19Z"</span><span class="p">,</span>
  <span class="ss">title: </span><span class="s2">"Billing thing"</span><span class="p">,</span>
  <span class="ss">id: </span><span class="mi">1</span><span class="p">,</span>
  <span class="ss">updated_at: </span><span class="s2">"2012-11-02T05:58:10Z"</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="in-rails-400-2">In Rails 4.0.0</h3>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="rouge-code"><pre><span class="p">{</span>
  <span class="ss">model: </span><span class="p">{</span>
    <span class="ss">article: </span><span class="p">{</span>
      <span class="ss">id: </span><span class="mi">1</span><span class="p">,</span>
      <span class="ss">title: </span><span class="s2">"Inception"</span><span class="p">,</span>
      <span class="ss">created_at: </span><span class="s2">"2012-11-02T06:20:46-05:00"</span><span class="p">,</span>
      <span class="ss">updated_at: </span><span class="s2">"2012-11-02T06:20:46-05:00"</span>
    <span class="p">}</span>
  <span class="p">},</span>
  <span class="ss">options: </span><span class="p">{</span> <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Holy nesting Batman! Now instead of spitting out the attributes for the single record being fetched through the GET request, <del>Rails</del> <em><a href="https://github.com/rails-api/active_model_serializers">active_model_serializers</a></em> becomes a lot more specific. It reminds us that this record is a model called article and then prioritizes columns a little better. The ID makes sense at the top, then the data followed by the timestamps. I’m not certain what the options’ hash is supposed to contain but at first glance this seems like a cleaner default output.</p>

<p>As you can see, default JSON returns in Rails 4 are <del>quite different from their Rails 3.x counterparts</del> <em>exactly the same unless you forget that you added a completely different JSON serialization gem like <a href="https://github.com/rails-api/active_model_serializers">active_model_serializers</a></em>. The formatting is better, but this is likely to require some work on whatever consumes your JSON API, for instance in some cases I either had to rewrite the JavaScript I was using to call my app’s API. In others, it made more sense (at least for now) to change this default output. Either on the fly using <code class="language-plaintext highlighter-rouge">map</code> or with JSON formatting tools like <a href="https://github.com/rails/jbuilder">Jbuilder</a> or <a href="https://github.com/nesquena/rabl">rabl</a>.</p>
<img src="https://feed.olivierlacan.com/link/8226/8521091.gif" height="1" width="1"/>]]></description>
      <pubDate>Fri, 02 Nov 2012 02:43:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521091/associations-in-rails-4</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/associations-in-rails-4/</guid>
    </item>
    <item>
      <title>Stop Controlling Traffic</title>
      <description><![CDATA[<p>There’s a fundamental problem in the way most work environments encourage interruptions. I find it’s vaguely similar to the way well-intentioned people stop their vehicle to let someone cross the road, because they think it’s the courteous thing to do. At best you’re breaking the traffic code, at worst you’re risking this person’s life because you cannot — in fact — control traffic, and a vehicle who hasn’t seen the pedestrian starting to cross the road may very well pass you and seriously harm or kill them.</p>

<p>But you <em>just</em> wanted to be nice.</p>

<p>For many workers, the notion of being “in control” implies having what they consider urgent addressed right away. I’ve noticed this sort of regression to the mean in the way people tend to interact with their co-workers, whether they are hierarchically on the same level or not. People who were asked to do something, just got something done, or need to get something done will display the most callous behavior towards other people’s workflow simply because they can’t bear the thought of being stuck or not telling people — right now — about something they’ve just done.</p>

<blockquote>
  <p>“I need a minute of your time for this.”</p>
</blockquote>

<blockquote>
  <p>“You need to take a look at this.”</p>
</blockquote>

<blockquote>
  <p>“Just so you know, I took care of that thing for you.”</p>
</blockquote>

<p>Shut up. Just. Shut. The. Fuck. Up. Your brain is grasping for reassurance, for feedback, and you’re not even noticing that you’re trampling on people in the process of trying to acquire that feedback.</p>

<p>You <strong>don’t”</strong> need a minute of their time for this, you probably need five or fifteen, but you don’t need them right now. You can leave them a note, an email — maybe even an instant message if you think it really warrants it — and they will get back to you at the optimal time for them. That time can be optimal for you as well, provided they don’t interrupt you callously while you’re in the middle of another task. But you assume that’s going to happen, because that’s just the way <strong>you</strong> would do it.</p>

<p>They <strong>don’t</strong> need to take a look at this. There’s no rush, unless you’re an EMT or a soldier. Nobody’s life is on the line. They <strong>can</strong> look at this later, on their own time, and get back to you with remarks if need be. Move on to your other task, drop this one off, keep moving. Quit controlling traffic.</p>

<p>They <strong>will</strong> know that you took care of “that thing” for them, eventually, it doesn’t need to be now. You <strong>do not</strong> need to tell them right away and feel be satisfied that they recognized how useful you were. They wouldn’t have asked you to do something for them in the first place if they didn’t think you were in fact helpful. You <em>will</em> get the satisfaction of them noticing on their own that you accomplished what they asked of you, and you will not prevent them from accomplishing something of their own in the process.</p>

<p>This may seem like a rant, but I sometimes wonder if these counter-intuitive notions can be taught to everyone. I have been the guy who constantly interrupts people for feedback and reassurance. It took a fair amount of listening and reading about people’s experience for me to notice that I was doing something wrong. Somehow, few people will complain directly to you when you’re breaking their flow. They will just accept it as the ransom of collaboration. It doesn’t need to be that way.</p>

<p>People can collaborate without asphyxiating each other. They can have parallel workflows without the constant need to collide.</p>

<p>This doesn’t mean that you shouldn’t ask questions, it simply means there is always a time and a place for questions to be raised, reassurance to be given, and thumbs to be shot in the air. Learn to respect other people’s flow.</p>
<img src="https://feed.olivierlacan.com/link/8226/8521092.gif" height="1" width="1"/>]]></description>
      <pubDate>Tue, 11 Sep 2012 13:29:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521092/stop-controlling-traffic</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/stop-controlling-traffic/</guid>
    </item>
    <item>
      <title>Gender Gravity</title>
      <description><![CDATA[<p>Many words are hammered every day about what men and women do and should do in an environment when women are scarce and men aren’t.</p>

<p>I was taken aback by <a href="http://liza.id.au/male-female-interaction-and-the-thing-that-i-just-realized-has-been-nagging-at-me/">Liza Shulyayeva’s thoughtful blog post</a> about coming to terms with the fact that since most people who surround her professionally are men, it’s likely that a large proportion of them harbor some sexual attraction to her.</p>

<p>She confesses that she didn’t come to terms with this because of any uncomfortable situation she directly had to face but simply because of someone whose opinion she values and who pointed it out.</p>

<p>Reading those lines is one of those moments. A moment like the one when a friend told me she had to plan her life around the absolute rule that she could never be alone walking somewhere at night.</p>

<p>Let that sink in for a moment. How often do you, as a man, wander about in the night from your office to a restaurant, or from a restaurant to a movie theather? How often do you think about your safety? Or the perception your loneliness projects on other people?</p>

<p>I’m sure you do think about your safety, you keep an eye out for your surroundings and the behavior of strangers around you, but on the whole as a man you can roam, freely. Now I invite you to consider for a moment, how you would consider a woman behaving as you do. Do you think it’s foolish? Irresponsible? Why do you? How can you possibly justify that if you value personal freedom?</p>

<p>Yes, reality is what it is. Men are often violent and abuse their average physical superiority over women in many ways, some discreet, others abject. But can you imagine having your life chained to that reality? Wouldn’t you revolt?</p>

<p>Let me come back to Liza’s premise, the emotional and physical attraction that seems impossible to avoid attracting when you are a woman in a world overwhelmingly dominated by men. While I’m certain there is a non-negligible proportion of men who simply want to enjoy the balance of power as it is, as a humanist and an optimist I like to think that people are often more vertuous than we like give them credit for. Ironically, this point of view is surely informed by a masculine bias.</p>

<p>My colleague <a href="http://happymediumblog.com/">Aimee Booth Simone</a> was recently compelled to create a Meetup group called <a href="http://www.meetup.com/Central-Florida-Women-In-Tech/">Central Florida Women in Tech</a> and organize a <a href="http://workshops.railsbridge.org/">Rails Bridge</a> event dedicated to helping women learn to build web applications using Ruby on Rails. When she was in the early stages of organizing it she and I were talking about the rules of the event when it came to male students. She told me the only men allowed to participate were either teaching assistants or people accompanying women coming to the event. I found the rule interesting and asked her why she believed it had been established. Her answer boiled down to one feeling: comfort. It would be far less intimidating for women to get together in an environment where male-female interactions were essentially removed.</p>

<p>While this may sound drastic, I try to imagine if the situation were reversed. If a few geeky men were invited to join an large group of knowledgeable and often socially awkward women. While it’s easy to joke that men would hardly dislike the situation, in reality I doubt they would. The feeling of minority is never an easy one.</p>

<p>Now allow me to turn the tables on you.</p>

<p>Do you know why I came across Liza’s article? I was browsing Kickstarter for some of the comments left on the <a href="http://www.kickstarter.com/projects/eallam/try-ios-iphone-app-development-course/comments">Try iOS campaign</a> we recently launched. While doing so I noticed some positive comments, one of which attracted my attention more than the others.</p>

<p><img src="https://olivierlacan.com/assets/gender-gravity-lizas_comment.png" alt="liza’s comment" /></p>

<p>Why? Because:</p>

<ul>
  <li>it came from a woman who used the words “very happy to see this got funded”.</li>
  <li>it didn’t contain any typos</li>
  <li>the profile picture was quite attractive</li>
</ul>

<p>So what did I do? I clicked on her name to learn more about her of course. Is that stalkerish? Maybe. I believe my curiosity isn’t unwarranted since any interest from women in technical matters is a boon to everybody. That said, I can’t deny that I wanted to learn more about her specifically, and not just “the person who was happy to see this funded”.</p>

<p>When I got to Liza’s profile page, here’s the order of things I noticed:</p>

<ol>
  <li>She had only backed one project on Kickstarter, ours. <strong>Proud.</strong></li>
  <li>She’s a web designer who likes JavaScript and AI. <strong>Cool.</strong></li>
  <li>She’s from Australia. <strong>Far. Awesome.</strong></li>
  <li>“Have superpowers. Can fly”. <strong>Quirky.</strong></li>
  <li>Her enlarged profile picture. <strong>Wow, she’s really cute.</strong></li>
  <li>Her website. <strong>Hmm.</strong></li>
</ol>

<p>Feeling curious I visited her website, because I wanted to know more about her, and wondered if her website would be interesting. When I got there I saw the title of her most recent blog post (“Male-female interaction and the thing that I just realized has been nagging at me”) and it hit me.</p>

<p>Like many passionate people working in an industry of passionate people, I was excited about the idea of finding someone from the opposite sex who could share that passion, someone that could even challenge me in that domain. Yes, it was directed by physical attraction and common interests. But, in the end, I struggle to think of a better way to define how anybody else on this planet finds people they want to maybe, perhaps, someday, if things work out, spend their time with and love.</p>

<p>It know this doesn’t make it easier to live surrounded by so many people whose longing is directed at so few of you, but hopefully my point of view will provide some women out there with a less gloomy perception on all this attention.</p>
<img src="https://feed.olivierlacan.com/link/8226/8521093.gif" height="1" width="1"/>]]></description>
      <pubDate>Tue, 07 Aug 2012 21:13:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521093/gender-gravity</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/gender-gravity/</guid>
    </item>
    <item>
      <title>Rails Blank Slate Differences</title>
      <description><![CDATA[<h2 id="the-problem">The Problem</h2>
<p>Upgrading Rails apps has become a lot easier over the years. Most of the time you can simply update your Gemfile, try to <code class="language-plaintext highlighter-rouge">bundle</code> and make sure all your existing Gems are compatible with the new version, if not run <code class="language-plaintext highlighter-rouge">bundle update &lt;gemname&gt;</code> on each of them one at a time until all dependencies resolve and then finally run <code class="language-plaintext highlighter-rouge">rake rails:update</code>, letting Rails make sure you’re setup properly for a new version.</p>

<p>The problem is that new versions of Rails often come with new default configrations inside of the following files and directories:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">config/application.rb</code></li>
  <li><code class="language-plaintext highlighter-rouge">config/environments/development.rb</code></li>
  <li><code class="language-plaintext highlighter-rouge">config/environments/production.rb</code></li>
  <li><code class="language-plaintext highlighter-rouge">config/initializers/</code></li>
  <li><code class="language-plaintext highlighter-rouge">Gemfile</code></li>
</ul>

<p>And there’s always a lot to learn from those new default configuration. Even if we should, we don’t often catch all the subtle changes and improvements made to those Rails defaults. The result is that problems arising from upgrading to a new Rails version often come from not knowing about these new defaults.</p>

<p>To address this, Jacob Swanner had written a blog post for the Envy Labs blog last year offering <a href="http://blog.envylabs.com/2011/10/upgrading-to-rails-3-1-1/">useful Git diffs</a> for the modified files between several different Betas and Release Candidates of Rails 3.1 and the 3.1.1 final release.</p>

<h2 id="the-solution">The Solution</h2>
<p>Dwayne Henderson took it one step further by writting a useful Bash script that automated this process between a selected “old version” and the newest version of Rails available. Making it a lot less painless to get relevant information for the versions you care about.</p>

<h2 id="refining-the-solution">Refining the Solution</h2>
<p>His script didn’t really work on my system so I took it as an opportunity to improve it a bit and despite my serious illiteracy when it comes to Bash scripting, I came up with a version that:</p>

<ul>
  <li>uses Bundler instead of RubyGems to create a version-specific skeleton Rails app, it’s much faster and doesn’t mess with your system Rubies or RVM Gemsets</li>
  <li>allows you to set which <code class="language-plaintext highlighter-rouge">new_version</code> of Rails you want to compare with the <code class="language-plaintext highlighter-rouge">base_version</code></li>
  <li>if <code class="language-plaintext highlighter-rouge">new_version</code> is left blank it compares against the latest stable version of Rails</li>
  <li>provides descriptive colorized output for all actions being done by the script</li>
  <li>outputs the resulting Git diffs to your system’s default <code class="language-plaintext highlighter-rouge">$EDITOR</code> instead of less</li>
</ul>

<p>true<script src="https://gist.github.com/3068005.js?file=rails_default_diff.sh"> </script></p>

<p><a href="https://gist.github.com/raw/3068005/70431270f82a826a97ce8e854a87995ce782999a/rails_default_diff.sh"><strong>Download the script here</strong></a> and make sure you save it as a <code class="language-plaintext highlighter-rouge">rails_default_diff.sh</code>.</p>

<p>Here’s an <a href="https://gist.github.com/3068318">example diff from Rails 3.1.4 to 3.2.6</a>.</p>

<h2 id="possible-improvements">Possible Improvements</h2>
<p>I would love it if someone could help me test this script to make sure it works across environments and not just on my local machine, since I use ZSH and OS X I don’t know if this will act the same elsewhere.</p>

<p>Better yet, Jacob mentioned it would be a great idea to directly ping the Rails repo on GitHub for specific version tags to perform this without even needing to install new Rails versions locally. He’s working on a solution for that.</p>

<p>Finally, I think it would make sense to create a web service that outputs differences between blank slate Rails apps when you query it like this: <code class="language-plaintext highlighter-rouge">site.org/from/v3.1.4/to/v3.2.6</code></p>
<img src="https://feed.olivierlacan.com/link/8226/8521094.gif" height="1" width="1"/>]]></description>
      <pubDate>Sat, 07 Jul 2012 17:37:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521094/default-rails-app-differences</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/default-rails-app-differences/</guid>
    </item>
    <item>
      <title>Essential Rails Tools</title>
      <description><![CDATA[<p>I’ve presented a talk called Essential Rails Tools at <a href="http://railsconf2012.com/">RailsConf 2012</a> in Austin, Texas last April and more recently at the <a href="http://orug.org/">Orlando Ruby User Group</a> (ORUG) on May 10th, 2012.</p>

<p>My contention was that despite contrary claims made in <a href="http://news.ycombinator.com">some venues</a>, there is no reason to be nostalgic of the <em>good old days</em> of Rails 1.x and 2.x. The simplicity of those early versions was far less joyful than <a href="http://en.wikipedia.org/wiki/Rosy_retrospection">rosy retrospection</a> would have you remember, providing you do. Rails 3.0 and later version have introduced refinement, which can be confused with complexity but only on a superficial level.</p>

<p>Rails has always been about convention over configuration, and in order for conventions to be attained iteration and refinements must occur. Convention by its very nature implies a steeper learning curve, but its payback comes in the reusabibility of standardized knowledge.</p>

<p>My goal with this talk was to introduce newcomers to the Rails ecosystem by showing them some of the best development tools available. Another focus was trying to reassure people who come from Integrated Development Environments (IDEs) like Xcode, Eclipse or — dog forbid — Visual Studio and show them that a lightweight toolbelt can offer plenty of support for debugging, managing dependencies and a development environment.</p>

<h2 id="slides">Slides</h2>

<script async="" class="speakerdeck-embed" data-id="4f9718f96fda0a001f01f174" data-ratio="1.3333333333333333" src="https://olivierlacan.com//speakerdeck.com/assets/embed.js"></script>

<h2 id="command-line-tools">Command Line Tools</h2>

<p>I’ve gathered here some information and resources about the tools I introduced in this talk. Let’s start with some Unix tools that should be the foundation of your development environment.</p>

<h3 id="homebrew"><a href="http://mxcl.github.com/homebrew/">Homebrew</a></h3>

<p>Homebrew is the best package manager for the OS X ecosystem.</p>

<p>A package manager is tool that does several key things for you:</p>

<ol>
  <li>Resolve dependencies for the piece of software you’re trying to install.</li>
  <li>Download each piece of software’s source code.</li>
  <li>Configure the source to be compatible with your system.</li>
  <li>Compile the source into an executable <em>binary</em> program.</li>
  <li>Allow you to upgrade any of these binaries very easily.</li>
</ol>

<p>That’s a lot of stuff right there. Things that you don’t have to worry about when installing something from a disk image (.dmg files) or from the Mac App Store since those are already compiled into executable programs for you.</p>

<p>You might (and should) ask: why not download pre-compiled executables instead of their source code? For several programs, Git for instance, you can actually do that by going to <a href="http://git-scm.com/">Git’s official website</a> and hit the download section.</p>

<p>For many other programs, it’s not that easy. There are intricate interractions with other programs on your system that need to be accounted for before an executable version can be created and function properly on your system. Just to be clear, an executable is a program that can be launched, an application in modern parlance. The source code of a Unix program can’t be executed before that program has been compiled, that’s just the way it is.</p>

<p>Now if you’ve been doing development on a Mac for a while, you might have heard of MacPorts. It’s also a package manager which was a predecessor to Homebrew and up until a few years ago was used by a majority. The reason a majority of developers have moved on to using Homebrew are multiple.</p>

<p>For one, MacPorts used convoluted ways to install programs since it didn’t use several libraries and software already available on OS X which resulted in slow installation and complex dependencies. Complexity is something people shy away with in this realm because having many moving parts is often a recipe for issues.</p>

<p>Homebrew takes a simpler and more lightweight approach. While at first it didn’t offer as many installation recipes (or formulaes in Homebrew-speak) as MacPorts, the fact that formulaes are written in simple Ruby allowed the stable of programs it was capable of installing to grow at a fast rate. So much that it’s hard to find anything that you can’t install with Homebrew.</p>

<p>I mentioned several of the popular packages available through Homebrew in a previous post called <a href="http://blog.olivierlacan.com/posts/brewing-with-homebrew/">Brewing with Homebrew</a>. You’ll also find instructions on how to install it there.</p>

<p>If you had been using MacPorts for a while, <a href="http://bitboxer.de/2010/06/03/moving-from-macports-to-homebrew/">Moving from MacPorts</a> is a great article that more reasons to switch and simple instructions on how to do so.</p>

<h3 id="autojump"><a href="https://github.com/joelthelion/autojump">AutoJump</a></h3>

<p>A great little utility that remembers folders you’ve <code class="language-plaintext highlighter-rouge">cd</code>-ed into and allows you to “jump” to them from anywhere simply by typing <code class="language-plaintext highlighter-rouge">j &lt;foldername&gt;</code>. For instance, once I’ve done <code class="language-plaintext highlighter-rouge">cd ~/Development/envylabs/codeschool/</code> once, I can just type in <code class="language-plaintext highlighter-rouge">j code</code> and it will take me straight there. <code class="language-plaintext highlighter-rouge">j c</code> will also work until you <code class="language-plaintext highlighter-rouge">cd</code> into another folder that starts with a C, at which point you’ll have to be a little more specific. It’s extremely useful once you start navigating around many different folders and files on the command line. It feels like using Spotlight, Quicksilver or Alfred on the Terminal.</p>

<h2 id="ruby-gems">Ruby Gems</h2>

<p>Here’s a quick breakdown of the interesting gems I mention in this talk. All of them offer command line interfaces (or CLIs) which allow you to interact directly with them from the command line and send them commands.</p>

<h3 id="rvm"><a href="http://rvm.io">RVM</a></h3>

<p>RVM has been for years the only way to manage multiple versions of Ruby on a single development machine, and before the advent of Bundler with Rails 3, it also served as a way to prevent collisions between gems (Ruby libraries) installed on your system. Its relevance has nowadays been lessened by the more simple <a href="https://github.com/sstephenson/rbenv">rbenv</a>  and the <code class="language-plaintext highlighter-rouge">bundle exec</code> command offered by Bundler, but it’s still a good choice for beginners.</p>

<p>If you’re not a fan of managing Ruby versions and Gemsets through the command line on a daily basis (you shouldn’t if you’re using <code class="language-plaintext highlighter-rouge">.rvmrc</code> files, but nobody’s perfect) you should take a look at <a href="http://unfiniti.com/software/mac/jewelrybox">JewelryBox</a>, a free graphical user interface for RVM for OS X.</p>

<h3 id="pow"><a href="http://pow.cx">Pow</a></h3>

<p>Once you start working with more than a single Rails application and you need to run more than one at the same time it can become tedious to start a web server for each using the <code class="language-plaintext highlighter-rouge">rails server</code> command every time. It also means you have to start assigning ports to each server to prevent collisions.</p>

<p>Pow is a simple little tool built by the 37signals team that allows you to assign a made-up domain name to each of your apps. Whenever you enter that domain name in your favorite browser, Pow will start a Rails server for you and launch the app in your browser. Not only is it convenient, it can become crucial when you’re building two apps that depend on one another to function.</p>

<p>Better yet, in this world of powerful little tools, another Gem called <a href="https://github.com/rodreegez/powder">powder</a> provides you with an interface to install and manage all your Pow servers. It gives you convenient commands to create specific domain names for a given app, watch its development log, and restart it.</p>

<p>There’s an inherent issue with Pow that causes it to stop working once an Internet connection isn’t available for your machine, and sure enough powder solves that with a convenient command called <code class="language-plaintext highlighter-rouge">powder host</code>. This will add all your Pow application domain names to your system’s host file, which is where your system ends up looking when no Domain Name Server (or DNS) is available on the Internet. And now you can use Pow on your next plane ride!</p>

<h3 id="pry"><a href="https://pry.github.com">Pry</a></h3>

<p>Debugging is something many people coming from Integrated Development Environments (IDEs) worry about when coming into the Rails ecosystem. Setting break points to inspect code at a specific point within a program is a common and very straightforward way of figuring out why something isn’t working the way you expect it to.</p>

<p>Sadly the most popular debugging tool for Ruby and Rails, ruby-debug19, hasn’t been updated since 2009. An eternity for a vibrant open source community like Rails.</p>

<p>Pry offers a slightly different approach to debugging by offering an interface similar to the classical Unix command line. When stepping through a program frozen by a break point, Pry lets you <code class="language-plaintext highlighter-rouge">cd</code> into objects and classes to inspect their properties and methods the way you would inside of a directory structure. It’s literarly like code spelunking, which somehow makes debugging a more concrete experience.</p>

<p>Pry has several other great features that for instance allow you to jump the line of source code your currently debugging within your favorite editor to fix a bug in place. It also has several extensions like:</p>

<ul>
  <li><a href="https://github.com/nixme/pry-nav">pry-nav</a> which allows you to resume execution your program line by line and even step backwards</li>
  <li><a href="https://github.com/pry/pry-stack_explorer">pry-stack_explorer</a> which lets you climb inside the call stack, examine the state of each <em>frame</em> of the stack and even evaluate code in there.</li>
  <li><a href="https://github.com/mon-ouie/pry-remote">pry-remote</a> goes hand in hand with Pow since unlike the traditional Webrick or Thin web servers launched through the <code class="language-plaintext highlighter-rouge">rails server</code> command, you can’t add a breakpoint and interact directly with Pry when using Pow since it’s running remotely. Pry Remote offers you a new <code class="language-plaintext highlighter-rouge">binding.remote_pry</code> statement that will interrupt the execution of the Pow server and wait for a client to connect to the debugging session. You’ll then just have to run <code class="language-plaintext highlighter-rouge">pry-remote</code> from any command line on your system and you will be taken into the usual Pry session, minus the pretty colors.</li>
</ul>

<p>You can find more great information about the <a href="http://banisterfiend.wordpress.com/2012/02/14/the-pry-ecosystem/">Pry Ecosystem in this excellent blog post</a>.</p>

<h3 id="bundler"><a href="http://gembundler.com/">Bundler</a></h3>

<p>Hard to overstate how amazing Bundler has made working with myriads of gems with different version dependencies inside of an application. This used to be hell for developers, hence the usefulness of segragated Gemsets through RVM.</p>

<p>Thankfully Bundler offers the <code class="language-plaintext highlighter-rouge">bundle exec</code> command which will run whatever command you pass it <code class="language-plaintext highlighter-rouge">bundle exec rake db:migrate</code> for instance with the version of rake it resolved as compatible with the Gems declared in your Gemfile.</p>

<p>It’s a bit complex to understand. To summerize, you may have installed and activated version 0.9.2.2 while your Gemfile.lock — the file Bundler creates once it has resolved all the cross-dependencies of all the Gem versions in your Gemfile — requires version 0.9.1 to be used. Since you don’t have version 0.9.1 anymore — you’ve upgraded — you need to tell Bundler to point to rake 0.9.1 instead, which it does through <code class="language-plaintext highlighter-rouge">bundle exec rake</code>.</p>

<p>You can verify that by running <code class="language-plaintext highlighter-rouge">rake --version</code> and <code class="language-plaintext highlighter-rouge">bundle exec rake --version</code> in a project whose Gemfile requires an older version of rake. The two versions should be different.</p>

<h4 id="semantic-versioning--loose-version-dependency">Semantic Versioning &amp; Loose Version Dependency</h4>

<p>Semantic Versioning is a concept that tries to hold developers to meaningful versioning of their software.</p>

<p>A major version (1.0.0, 2.0.0) should be expected to introduce major non-backward compatible changes. A minor version (1.1.0, 2.1.0) should be expected to introduce minor non-backward compatible changes. And finally, a patch version (1.1.1, 2.0.1) should only contain backward compatible bug fixes.</p>

<p>This is a simplified explanation of the more nuanced explanations and rules covered at <a href="http://semver.org/">semver.org</a> but it should give you an idea.</p>

<p>Now loose version dependency is a practice whereby declaring gem dependencies in your Gemfile, you don’t specify a safer specific version (<code class="language-plaintext highlighter-rouge">gem "rails", "3.2.2"</code>), or a much more dangerous minimal version (<code class="language-plaintext highlighter-rouge">gem "rails", "&gt;=3.2.2"</code>) but instead make the version dependency loose: <code class="language-plaintext highlighter-rouge">gem "rails", "~&gt; 3.2.2"</code>.</p>

<p>With this notation. Bundler will automatically try to update the Rails gem if it finds a newer version than 3.2.2 but will never upgrade to version 3.3.0, which would be a more unpredictable non-backward compatible minor version bump by the definition of semantic versioning. This notation only tries to update the latest number declared, so the much less safe <code class="language-plaintext highlighter-rouge">gem "rails", "~&gt;3.2"</code> can also be used, but isn’t recommended.</p>

<h2 id="more-tools">More Tools</h2>

<p>That’s about it for this long foray into the constellation of open source tools available for Rails development. Here are a few excellent resources available to find more:</p>

<ul>
  <li><a href="http://ruby-toolbox.com">ruby-toolbox.com</a></li>
  <li><a href="http://rubygems.com">rubygems.com</a></li>
  <li><a href="http://railscasts.com">railscasts.com</a></li>
</ul>

<p>And if you’re a <a href="http://codeschool.com">Code School</a> subscriber, we regularly release <a href="http://codeschool.com/code_tv">Code TV screencasts</a> on various useful tools and libraries for Ruby and Rails development, I can’t recommend them enough.</p>
<img src="https://feed.olivierlacan.com/link/8226/8521095.gif" height="1" width="1"/>]]></description>
      <pubDate>Fri, 11 May 2012 00:56:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521095/essential-rails-tools</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/essential-rails-tools/</guid>
    </item>
    <item>
      <title>Raise Your Hand</title>
      <description><![CDATA[<p>There’s something I’ve rarely seen pointed out about the kind of online educational experiences we provide at <a href="http://codeschool.com">Code School</a>, it’s how easy we make it for people to screw up.</p>

<p>That seems rather contrived but screwing up is not a small matter when it comes to learning. Our inhibitions as human beings make us go to great length to avoid failure. Few people associate it with a positive experience. And if you think back to your experiences at school (good luck if you’re still going through it), try to picture the number of times you had an answer to a question posed by one of your teachers but sat in silence for fear of getting it wrong.</p>

<p>You didn’t learn that day. You wasted that opportunity because the fear of embarassment was greater than your self-confidence.</p>

<p>Now what if your initial exposure to new information was made in a context in which social pressures were taken out of the equation? What if you were shown concepts and asked questions about them in a shame vacuum?</p>

<p>That’s precisely what can make practicing through interactive challenges such a fertile ground for growth-inducing failure. For instance, most of our students at Code School put in dozens of attempts before they even consider asking for a hint.</p>

<p>They’re far more active towards their learning experience than I would wager the majority of High School and College students are towards the lectures and labs their participate in.</p>

<p>As shown by <a href="http://www.wired.com/wiredscience/2011/10/why-do-some-people-learn-faster-2/">this excellent Wired article</a> and the studies it presents, a student’s mindset towards failure can have a dramatic influence on how well they learn. If we can foster an environment where students only care about disappointing themselves when they screw up, I think we’re on the right track. And it may even catch on in the classroom.</p>
<img src="https://feed.olivierlacan.com/link/8226/8521096.gif" height="1" width="1"/>]]></description>
      <pubDate>Fri, 24 Feb 2012 02:12:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521096/raise-your-hand</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/raise-your-hand/</guid>
    </item>
    <item>
      <title>The People That Do Things</title>
      <description><![CDATA[<p>For a dear friend.</p>

<iframe width="420" height="315" src="https://www.youtube.com/embed/zkTf0LmDqKI?rel=0&amp;start=7" frameborder="0" allowfullscreen=""></iframe>

<blockquote>
  <p>“Most people never pick up the phone, most people never ask. And that’s what separates, sometimes, the people that do things from the people that just dream about them. You gotta act. And you gotta be willing to fail… if you’re afraid of failing, you won’t get very far.”  — Steve Jobs</p>
</blockquote>
<img src="https://feed.olivierlacan.com/link/8226/8521097.gif" height="1" width="1"/>]]></description>
      <pubDate>Sat, 18 Feb 2012 12:16:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521097/the-people-that-do-things</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/the-people-that-do-things/</guid>
    </item>
    <item>
      <title>Fumble-driven Development</title>
      <description><![CDATA[<p>My digressive brain started to run wild while watching Bret Victor’s fascinating talk <a href="https://vimeo.com/36579366">Inventing on Principle</a> a few minutes ago.</p>

<iframe src="https://player.vimeo.com/video/36579366?byline=0" width="500" height="281" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen=""></iframe>

<h2 id="what-if-were-wrong">What if we’re wrong?</h2>

<p>What if Bret is right and the red, green, refactor isn’t a feedback loop that promotes creativity and discovery? Sure, it’s fast. It’s iterative and it gives us a suite of clearly defined assumptions to rely on in order to gauge the stability of the programs we’re building.</p>

<p>But what if such a science-based programming — as I like to think of it — is sacrificing an essential component of the process of building?</p>

<p>I recognize that as someone who begun as a designer I have a tendency to regress to that mean. The one of experimentation, trial and error. The one of repeated fumbles and smudges that with perseverance can turn into a great thing. That’s how I instinctively want to write my code even though I know that I’m not skilled or controlled enough to be trusted without the safety net provided by testing.</p>

<h2 id="another-way">Another way</h2>

<p>Or maybe the kind of programming that Bret presents through his innovative development environment is just one other way to code. A way more suited for creating visual output, animations, interfaces. Maybe that’s where the front-end development community will gravitate toward. Come to think of it, it would make a lot of sense.</p>

<p>It’s difficult for me to resist the appeal of a human and feedback-friendly interface. I believe the feedback loop is something too many creators neglect. A sanity check where sanity equates to reality and can take developers back down to the ground when they get lost in abstractions.</p>

<p>Having spent a good part of the afternoon toying with <a href="https://github.com/guard/guard">Guard</a> and its various extensions I realize that this kind of fast and tangible output is something I have been craving for.</p>
<img src="https://feed.olivierlacan.com/link/8226/8521098.gif" height="1" width="1"/>]]></description>
      <pubDate>Fri, 17 Feb 2012 00:36:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521098/fumble-driven-development</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/fumble-driven-development/</guid>
    </item>
    <item>
      <title>Envy</title>
      <description><![CDATA[<p>I joined Envy Labs a month ago today. It has been the most fulfilling four weeks of my professional life. So forgive me while I reflect on how I got there. Maybe this can be an example of what reaching outside of your comfort zone can result in for people who aspire to make things for a living.</p>

<h2 id="seeds">Seeds</h2>
<p>The first time I ever heard of Envy was through a young social game called Gowalla. I lived in East Orlando at the time and since very few spots had been “created” in the area, I took it upon myself to correct that, hoping that it would allow me to amass riches of badges, icons and other virtual carrots.</p>

<p>There were a few people I regularly saw in the list of recently checked-in at some popular spots in the area, and then there was Gregg Pollack. With his double set of double consonants, this guy seemed to be everywhere. I discovered by snooping his profile that he was in possession of badges (or pins) I had never heard of before. One of them — “Code Monkey” — was awarded to people who had checked in at an impressive amount of startups or tech company headquarters. Color me intrigued and envious.</p>

<p>One click on the URL listed under his profile and I discovered a colorful website with tons of personality describing a then young web development consultancy. From what I could gather, these guys were actually from Orlando. I was impressed. I had no idea – at the time – that there even was the semblance of a serious tech scene in central Florida, let alone Orlando.</p>

<h2 id="happenstance">Happenstance</h2>
<p>A few months passed and after thousands of drive-by checkins and an ever increasing addiction to Gowalla and the virtual copies of Zeldman &amp; Vaynerchuk books it awarded me, I found myself in Miami for the Future of Web Apps conference put on by Carsonified. While I was strolling around with friends from Full Sail trying to creep up on Dan Benjamin — whose <a href="http://5by5.tv">5by5 network</a> was barely blossoming at the time — I noticed a bunch of guys <a href="http://www.flickr.com/photos/brupm-photos/4386430710/in/photostream/">sitting nearby</a>. One of them looked a little too much like my Gowalla Nemesis for it to be a coincidence, and I therefore decided to introduce myself to him by using that very moniker:</p>

<blockquote>
  <p>“Hi, I believe you’re my nemesis on Gowalla…”.</p>
</blockquote>

<p>He looked at me like I was insane for a second, paused, and then giggled after — I assume — remembering that he had seen my mug around East Orlando’s Gowalla Elite as well. I doubt Gregg realized it at the time, but I had been trying to break the ice with some of the shut-in types at the conference for a while, with very little success until then. And while I was still glowing in the satisfaction of my ballsy self-introduction, I forgot to foresee that this was to be one of the key moments of my life.</p>

<p>The conference went on, things were learned, bladders were maimed, and deep conversations were exchanged on the invaded roof lounge of an overly loud South Beach bar. I then came back to Orlando and failed an introduction to programming class for the second time because I chose much needed sleep over cramming for the following day’s final exam. And even that proved worthwhile.</p>

<h2 id="opportunity">Opportunity</h2>
<p><a href="http://barcamporlando.org">BarCamp Orlando</a> was scheduled several weeks later and Gregg was interested in getting some Full Sail students to attend so we met over lunch to discuss that and he gave us – cleverCode, a little company I had co-founded with my friend Zach Nicoll from Full Sail – the opportunity to revamp a site called <a href="http://rubyheroes.com">Ruby Heroes</a> which had been used the previous year to reward the unsung contributors of the Ruby community at <a href="http://railsconf.com/">RailsConf</a>. More surprisingly, he offered to pay us, bringing our contingent of paid clients to the whooping number of two. We did a pretty good job for the amount of skills we had at the time and kept in touch over the following year, collaborating on another project with cleverCode later that year.</p>

<p>Ruby Heroes was the first Rails project I ever participated in, as a web designer at the time. I had very little experience with back-end development and even front-end development. When Envy Labs presented the first version of Rails for Zombies in August or September of 2010, I jumped on the occasion to start learning Rails inside and out since the Ruby and Rails community had impressed me deeply with design standards that were much higher than most developer-centric communities I had encountered. But there was something deeper than that. Through a collective focus on educating new users, practicing test-driven development, allowing fast iteration through simple library dependency management, there was just something more sane and thoughtful about that community.</p>

<p>This comes from a science-minded skeptical guy. I had been weary of joining groups and clubs for years and my strong opinions on design and user experience often put me at odds with developers and engineers who often forgot about human beings and ended up caring more about the systems they built than the people they were building them for.</p>

<h2 id="envious">Envious</h2>
<p>The group of people that makes up Envy Labs represents to me some of the finest qualities you can look for in builders. Despite my early reservations regarding Code School’s potential, they have regularly impressed me by not just doing what’s sufficient, but what’s best. Screencasts are nice, you can be introduced to a high quantity of concepts in a short amount of time. Practice is better because it’s the only true way to hone in a skill. The problem is that while screencasts get you pumped up about a specific topic, there are always good excuses to delay the practice of those newly acquired concepts. Code School meshed those together in a very successful way, honoring its  “Learn by Doing” motto. Doing it this way wasn’t the easy way.</p>

<p>Coming from a school like Full Sail, where instructors and course directors are encouraged to practice freelance work in order to maintain their proficiency in modern development skills, an environment like Code School seems like a perfect transition. Full-time designers and developers, some of the best in their field, regularly churning out dense educational content for people who already are in the web industry with some basic knowledge, but who are looking to discover the best practices and techniques used by thoughtful craftspeople.</p>

<p>The working environment at Envy Labs is unlike anything I’ve ever imagined before I joined the web world a few years ago. I’m familiar with the well documented excesses of trendy startups, but this is no startup. It’s a profitable business that was gradually built on hard work. And it focuses on being the best place for a developer or designer to work in — or out.</p>

<p>What this environment results in is some of the best work I feel I’ve ever produced. And I’m saying that after a mere four weeks where I haven’t produced that many significant things. But a good team isn’t necessarily defined by the complete things you work on individually, it’s defined by the cumulative efforts of people who feel the confidence of deeply investing themselves into what they do. It’s not that easy to trust that if you raise your hand to say something isn’t right, somebody will listen and agree to let you fix it. And when this someone responds by fixing that problem themselves because they recognize the value of what you brought up, there is no better token of trust and respect. Which in turns motivates you to pay it forward.</p>

<p>I could fill pages with the thoughtful and enlightening conversations I’ve had with Thomas, Nate, Chris, Dray, Eric, Gregg, Adam, Aimee, Drew, Mark, Josh, Nick, Violette, Caike, Jennifer, Jason, Matt, Jacob, Tim and Adam.</p>

<p>And it’s only been four weeks. I can’t wait to write about the next forty.</p>
<img src="https://feed.olivierlacan.com/link/8226/8521099.gif" height="1" width="1"/>]]></description>
      <pubDate>Thu, 16 Feb 2012 14:27:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521099/envy</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/envy/</guid>
    </item>
    <item>
      <title>Launch Sublime Text 2 from the command line</title>
      <description><![CDATA[<p>Sublime Text 2 ships with a <a href="http://en.wikipedia.org/wiki/Command-line_interface">CLI</a> called <code class="language-plaintext highlighter-rouge">subl</code>. It’s similar to the <code class="language-plaintext highlighter-rouge">mate</code> utility that is available for TextMate to open any file or folder straight from the command line.</p>

<p>In Sublime, the utility is hidden in the application package, and assuming you installed Sublime in <code class="language-plaintext highlighter-rouge">/Applications</code> you can check that it’s available on your system by running the commands below:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre>cd /Applications/Sublime\ Text\ 2.app/Contents/SharedSupport/bin/
ls
</pre></td></tr></tbody></table></code></pre></div></div>

<p>The only thing you should see displayed is <code class="language-plaintext highlighter-rouge">subl</code>. If not, go install the <a href="http://www.sublimetext.com/2">latest version</a>.</p>

<p>You can find more (official) documentation <a href="http://www.sublimetext.com/docs/2/osx_command_line.html">here</a>.</p>

<h2 id="installation">Installation</h2>

<p><em>Note: These instructions assume you’re using the Terminal app out of the box, without ZSH or any fancy prompts like that. I trust you will be able to adapt these instructions yourself if you do.</em></p>

<p>The official documentation I linked to above recommends creating a <code class="language-plaintext highlighter-rouge">~/bin</code> folder (in your home directory). That’s weird, I don’t recall ever being asked to do that on OS X since most people install binaries within <code class="language-plaintext highlighter-rouge">/usr/local/bin</code> which – if you’re a developer – is likely to already have tons of other binaries.</p>

<p>So let’s stay within the OS X conventions by doing:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>ln -s /Applications/Sublime\ Text\ 2.app/Contents/SharedSupport/bin/subl /usr/local/bin/sublime
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This will simply create a <a href="http://en.wikipedia.org/wiki/Symbolic_link">symlink</a> called <code class="language-plaintext highlighter-rouge">sublime</code> (remember, we like names that don’t suck to type 500 times a day) between the <code class="language-plaintext highlighter-rouge">subl</code> binary stashed in the Sublime application package, and a folder where your system usually looks for binaries to execute (launch). Think of it as a wormhole of awesome.</p>

<p>Now let’s do a check to see if everything will run smoothly. Enter this:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>open ~/.bash_profile`
</pre></td></tr></tbody></table></code></pre></div></div>

<p>You should see at the top of the file a line that starts with:
<code class="language-plaintext highlighter-rouge">export PATH=</code></p>

<p>This contains all the directories that will be looked into for executable binaries when you type a command in Terminal. Since we create a symlink to <code class="language-plaintext highlighter-rouge">subl</code> called <code class="language-plaintext highlighter-rouge">sublime</code> in the <code class="language-plaintext highlighter-rouge">/usr/local/bin</code> directory let’s check if this directory is listed on that same line.</p>

<p>If it is, perfect. Let’s keep going. If not, simply add it like this and save the file:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>export PATH=/usr/local/bin:(...)
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Note: The “(…)” in this example represents other folders that would be listed on the same line and separated by a colon.</p>

<p>If you had to add <code class="language-plaintext highlighter-rouge">/usr/local/bin</code> to your PATH, run the following command before continuing:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>source ~/.bash_profile
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This will reload your <code class="language-plaintext highlighter-rouge">.bash_profile</code> with the newly added directory.</p>

<h2 id="testing">Testing</h2>

<p>Open a Terminal window and run:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre># replace &lt;filename&gt; by an actual file name
sublime &lt;filename&gt;
</pre></td></tr></tbody></table></code></pre></div></div>

<p>or</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre># replace "foldername" by an actual folder name
sublime &lt;foldername&gt;
</pre></td></tr></tbody></table></code></pre></div></div>

<p>or even</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre># to open the entire current directory
sublime .
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="conclusion">Conclusion</h2>

<p>Now you don’t need to get out of Terminal to simply open a file or a folder, you didn’t have to add an “alias” or yet another bin directory to your <code class="language-plaintext highlighter-rouge">.bash_profile</code> which you would been have needed with the official instructions given by the Sublime team.</p>

<p>Have fun, Sublime is a great editor showing a lot of promise and you should check out the recent <a href="http://www.sublimetext.com/2">beta release</a>.</p>
<img src="https://feed.olivierlacan.com/link/8226/8521100.gif" height="1" width="1"/>]]></description>
      <pubDate>Wed, 11 Jan 2012 14:02:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521100/launch-sublime-text-2-from-the-command-line</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/launch-sublime-text-2-from-the-command-line/</guid>
    </item>
    <item>
      <title>Don't Repeat Yourself</title>
      <description><![CDATA[<h2 id="humble-html-beginings">Humble HTML beginings</h2>

<p>One my first website ever, which I built in 1999 with Microsoft Front Page, I decided to have on the left side a menu that listed each page. There’s a good chance my brain is constructing this memory but I think that the first time around I only had two or three pages, so I simply copied and pasted the same list of links on each.</p>

<p>It surely looked like this abberation:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;P&gt;&lt;A</span> <span class="na">HREF=</span><span class="s">page1.htm</span><span class="nt">&gt;</span>- Page 1<span class="nt">&lt;/A&gt;&lt;BR&gt;&lt;BR&gt;</span>
<span class="nt">&lt;A</span> <span class="na">HREF=</span><span class="s">page2.htm</span><span class="nt">&gt;</span>- Page 2<span class="nt">&lt;/A&gt;&lt;BR&gt;&lt;BR&gt;</span>
<span class="nt">&lt;A</span> <span class="na">HREF=</span><span class="s">page3.htm</span><span class="nt">&gt;</span>- Page 3<span class="nt">&lt;/A&gt;&lt;BR&gt;&lt;BR&gt;</span>
<span class="nt">&lt;/P&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This is atrocious code, please don’t ever use this.</p>

<p>Then after I had organized everything <em>so neatly</em> I thought about adding a fourth page. Boy, the agony. Imagine that. I had to open every single one of those (three) files and add a new link to <code class="language-plaintext highlighter-rouge">&lt;A HREF=page4.html&gt;-Page 4&lt;/A&gt;&lt;BR&gt;&lt;BR&gt;</code>. With my then collosal experience in web mastery, I could not stand for this. I had to find a way to make this more efficient.</p>

<hr />
<p>Oh, hi! This is a reality break.
<em>Efficiency</em> as described in the paragraph above is nothing else than pure and utter laziness. There’s no way around it. But you know what? Laziness is the mother of all invention. If less people settled for repetitive crap, you can bet we would already have our flying cars. So don’t settle, you’re making me wait for the future, and I don’t like that.</p>
<hr />

<p>So, back to efficiency. How do you achieve that kind of feat in <a href="http://en.wikipedia.org/wiki/HTML">HTML 4.01</a> when <a href="http://en.wikipedia.org/wiki/Internet_Explorer_5">Internet Explorer 5</a> was on the cutting edge of browser technology?</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;FRAMESET</span> <span class="na">ROWS=</span><span class="s">"15%,*"</span><span class="nt">&gt;</span>
   <span class="nt">&lt;FRAME</span> <span class="na">SRC=</span><span class="s">"title.html"</span> <span class="na">NAME=</span><span class="s">TITLE</span> <span class="na">SCROLLING=</span><span class="s">NO</span><span class="nt">&gt;</span>

   <span class="nt">&lt;FRAMESET</span> <span class="na">COLS=</span><span class="s">"20%,80%"</span><span class="nt">&gt;</span>
      <span class="nt">&lt;FRAME</span> <span class="na">SRC=</span><span class="s">"menu.html"</span> <span class="na">NAME=</span><span class="s">SIDEBAR</span><span class="nt">&gt;</span>
      <span class="nt">&lt;FRAME</span> <span class="na">SRC=</span><span class="s">"page1.html"</span> <span class="na">NAME=</span><span class="s">MAIN</span><span class="nt">&gt;</span>
   <span class="nt">&lt;/FRAMESET&gt;</span>
<span class="nt">&lt;/FRAMESET&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>You guessed it! Frames!
Perfect. Until you actually open than in a browser.</p>

<p><img src="https://olivierlacan.com/assets/frames.gif" alt="Grey Scrollbars are FUN " /></p>

<p>Even for my highly tolerant (I used Papyrus and thought it looked <em>awesome</em>) 1999 self, this kind of thing was just too ugly to live. So I tried to find a better way.</p>

<h2 id="server-side-seduction">Server-side seduction</h2>

<p>I didn’t have any idea at the time, but it turns out my ideal solution involved using the <em>server</em>. Something I had never heard of outside of a restaurant. I could ask my little server guy to include the menu page of my site for me everywhere I wanted it and it could do it by simply injecting the content of the <code class="language-plaintext highlighter-rouge">menu.html</code> file wherever I put the following code:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="c">&lt;!--#include virtual="header.html" --&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>I then needed to rename all of my existing pages to a <code class="language-plaintext highlighter-rouge">.shtml</code> extension for this decidedly not so smart server to understand that I wanted what looks like an HTML comment to act like an order: “Include this file right here, Mr Server man. No, I will not tip you, you didn’t bring me any food.”.</p>

<p>I soon discovered a thing know as <a href="http://php.net/">PHP</a> could allow me to do a lot more nifty things like this if I found a server which knew whatever that acronym meant and enjoyed bad phpuns about <a href="http://www.google.com/search?q=elephpant">elephants</a>.</p>

<p>So now I could do things like:</p>

<div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="cp">&lt;?php</span> <span class="k">require</span><span class="p">(</span><span class="s2">"menu.html"</span><span class="p">)</span> <span class="cp">?&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>That little trick would reward me with a nasty error if by any chance my menu.html file was missing and stop loading my page altogether until the issue was addressed and all was right again in the world. And that was about the extent of my PHP knowledge for several months after that. I remember seeing <code class="language-plaintext highlighter-rouge">echo()</code> statements here and there and a few <a href="http://php.net/manual/en/function.mysql-query.php">MySQL query</a> examples but I didn’t get into fiddling with server-side programming until a few months and years later when I found a guy crazy enough to build a back-end system for one of my websites.</p>

<h2 id="stay-hungry-stay-dry">Stay hungry, stay DRY.</h2>

<p>That’s the end of that trip down memory lane but I want to underline the interesting part here. Despite a total lack of technical knowledge, it’s my laziness and drive for efficiency that eventually led me down the slow path of acquiring enough skills to repeating myself less with websites, eventually evolving to dynamic websites, discussion boards, and database storage.</p>

<p>Between this first bit of awful HTML code and now, there are 13 years of tinkering, curiosity, foolish explorations and long night of frustration and pleasure. So the next time you find yourself doing a repetitive task, stop for a moment and explore the web to see if you can find a way to do it the smarter way. You might end up a Web Developer a few years down the line, or you might simply save yourself a good chunk of time and learn some cool things along the way.</p>
<img src="https://feed.olivierlacan.com/link/8226/8521101.gif" height="1" width="1"/>]]></description>
      <pubDate>Sat, 07 Jan 2012 00:34:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521101/dont-repeat-yourself</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/dont-repeat-yourself/</guid>
    </item>
    <item>
      <title>Is it better to know?</title>
      <description><![CDATA[<p>I finally started watching this fascinating <a href="http://www.youtube.com/watch?v=YXh9RQCvxmg">interview of Neil deGrasse Tyson by an out-of-character Stephen Colbert</a> today and the first question Stephen asks to Neil sounds like a joke:</p>

<blockquote>
  <p>“Is is better to know or not to know?”</p>
</blockquote>

<p>I think this is a fundamental question that is often ignored or brushed off by both the pro-science and the anti-science factions.</p>

<p>There is a certain beauty in ignorance that I can’t ignore, even as a science lover. But I think what I define as beauty is very different from reveling in the “mysterious ways” of the universe. I don’t like mystery. What I like is imagination.</p>

<p>Yesterday I was looking at an automatic pool vacuum cleaner — at least I think it uses vacuum — wondering once again how the hell this thing was making its way across the bottom of the pool. I don’t know how it moves, how it cleans, or what it is able to clean. Yet there I was staring at this thing having short spasms and trying to imagine what mechanism could possibly make it function.</p>

<p>On my own, I wasn’t able to come up with a satisfying answer. That, in my mind, creates something very similar to a vacuum, or a gap. That gap needs to be filled or I will be frustrated every time I see this thing again. It will remind me of my laziness and lack of will to inquire about it and find some kind of definitive answer. It prevents me from moving on to hunting another mystery.</p>

<p>I can’t deny that when I finally find the answer to how it works (and I plan to do that, soon after I publish this) I will be satisfied. Yet as someone who prides himself in understanding the world around him, I will have a slight disappointment that I could not predict how it works before I looked up the answer.</p>

<p>Not knowing also provided me with a catalyst for my imagination, which I believe is one of the greatest reasons why people dislike science. Science is there to confirm one hypothesis, and deny all the others any legitimacy. It feels unfair, because your pet theory wasn’t chosen to be the truth. But that’s not at all what it is. No one decides or chooses truth, it just is. All you have to do is be willing to discover it.</p>

<p>So to answer the question I posed as a title, yes, it is better to know. It’s sometimes unsettling, surprising and it can be frightening. But those adjectives can be taken to describes some of the most wonderful things about life. Sheltering oneself from knowledge isn’t nearly as satisfying as gathering the abilities to discover knowledge on your own. The excitement, the joy of discovering are far greater than the comfort of imagining.</p>

<p>And no, it doesn’t take the poetry out of the world, because there are always bigger mysteries to discover.</p>
<img src="https://feed.olivierlacan.com/link/8226/8521102.gif" height="1" width="1"/>]]></description>
      <pubDate>Sun, 01 Jan 2012 04:54:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521102/is-it-better-to-know</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/is-it-better-to-know/</guid>
    </item>
    <item>
      <title>Delaying the IE Showdown</title>
      <description><![CDATA[<p>I asked the lovely people on Twitter how they dealt with Internet Explorer during their development process in 2011 and what tools they used to do so.</p>

<p><a href="https://twitter.com/olivierlacan/status/144039798145957890">My initial question</a></p>

<p>Alan – nicest guy in the world &amp; very talented lead developer of <a href="http://teamtreehouse.com">Treehouse</a> was the first to opine:</p>

<p><a href="https://twitter.com/commondream/status/144040509885784064">Alan 1</a>
<a href="https://twitter.com/commondream/status/144040553057755137">Alan 2</a>
<a href="https://twitter.com/coryperry/status/144041538052304897">Cory 1</a></p>

<p>I then asked a follow-up.</p>

<p><a href="https://twitter.com/olivierlacan/status/144042582291398657">Follow-up</a></p>

<p><a href="https://twitter.com/commondream/status/144042513739694080">Alan 3</a>
<a href="https://twitter.com/commondream/status/144042750520729600">Alan 4</a></p>

<p>Speaking of talented fellas, Nick – a web designer at <a href="http://envylabs.com">Envy Labs</a> who worked on <a href="http://codeschool.com">Code School</a> and the fabulous Why-flavored redesign of <a href="http://tryruby.org">TryRuby.org</a> – answered:</p>

<p><a href="https://twitter.com/nickawalsh/status/144042925922336768">Nick 1</a>
<a href="https://twitter.com/coryperry/status/144042963339722753">Cory 2</a></p>

<p>Ryan – a swell guy from NY, designologist, co-founder and web designer at <a href="http://thinkbigr.com">Think Bigr</a> – replied:</p>

<p><a href="https://twitter.com/ryanbarresi/status/144043308572880896">Ryan 1</a></p>

<p>Last but not least, Mark – a terrific web designer at <a href="http://shopify.com">Shopify</a>, said:</p>

<p><a href="https://twitter.com/markdunkley/status/144073547038461952">Mark 1</a></p>

<p>To conclude almost every single response presented an approach where styles are written in a standards-compliant environment (today that would be Chrome or Safari, more so than Firefox) then adjusted for IE’s obsolete ways.</p>

<p>Keep this in mind, because a production process tied by IE-compatibility from the get-go is likely to create frustrations and creative limitations very early on. It doesn’t mean one shouldn’t consider IE before the end-stages of a project (as Nick pointed out, the demographic matters a lot) but be weary of efforts towards graceful degradation that may be rendered unnecessary by late design decisions.</p>

<p>Project managers are rarely as cautious with CSS since it doesn’t directly impact business logic (back-end), which means they are more likely to propose modifications to styles later on in a project than they would with controller-logic that could cause functionality breakage.</p>

<p>Managers also often expect websites to <a href="http://dowebsitesneedtolookexactlythesameineverybrowser.com/">look the same in every browser</a>. If you catch any flak when adopting such a process, don’t hesitate to point out that many web professionals adopt a similar technique because it is the most efficient use of their time. Going and back and forth between standard CSS and IE fallbacks after each design iteration is a waste of your time and their money.</p>

<p>If managers or clients somehow insist of having fully IE compatible sites after each iteration, several people have suggested introducing an IE tax to give everyone a clear picture of the <a href="http://www.informationweek.com/news/windows/microsoft_news/229401795">true cost of obsolete browsers</a> on development schedules.</p>

<p>I highly recommend Andy Clarke’s thorough <a href="http://stuffandnonsense.co.uk/blog/about/what_does_browser_testing_mean_today/">breakdown of his Canny Bill redesign</a> across progressively less advanced browsers and his benchmark browser approach.</p>

<p>Finally, one of the best tools to further the cause of graceful degradation (a much more logical moniker than “progressive enhancement”) is <a href="http://www.modernizr.com/">Modernizr</a>, spearheaded by <a href="http://farukat.es/">Faruk Ateş</a>, <a href="http://paulirish.com">Paul Irish</a> and <a href="http://alexsexton.com/">Alex Sexton</a>.</p>
<img src="https://feed.olivierlacan.com/link/8226/8521103.gif" height="1" width="1"/>]]></description>
      <pubDate>Tue, 06 Dec 2011 20:27:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521103/delaying-the-ie-showdown</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/delaying-the-ie-showdown/</guid>
    </item>
    <item>
      <title>That Salmon Color</title>
      <description><![CDATA[<p>This morning I decided to go back and finally watch the end of the <a href="http://www.apple.com/apple-events/october-2011/">iPhone 4S keynote presentation</a>. I had just left off the other day before the bit about the new camera system.</p>

<p>I was stuck by the careful details Phil Schiller went into just to describe how this camera was made, why it was made and exactly why it was so good.</p>

<p>And then he said this:</p>

<blockquote>
  <p>I’ll end it with this one – I could go on and on, but I’ll end it here. This is a nice begining of evening shot. You see a little bit of depth of field, right? You’ve seen that in a couple of these photos. The background’s blurred because that aperture 2.4 allows us a little depth of field. And you get just want you want in a sunset photo, <strong>the start of that salmon color that the sun makes</strong>. A bad auto white balance setting would make this sort of a neutral grey and ruin the beautiful color but not the iPhone 4S.</p>
</blockquote>

<p><img src="https://olivierlacan.com/assets/salmon.jpg" alt="Phil Schiller Salmon Sunset" /></p>

<p>This is just one of many details aimed at people who know this stuff – and with my short experience as an amateur photographer and camera salesman, I think I do. One of my favorite conversations with customers at the electronics store I worked at in Paris was the “Megapixel Conspiracy”. Most would-be photographers would come to me as the approachable long-haired 23-year old and ask me which camera had the highest pixel count.</p>

<p>These people were not stupid, despite what many cynical salespeople will have you believe. Pixel density in a digital camera sensor is one of the few quantifiable things about these gizmos that normal people can grasp at a glance and use to differentiate them. The digital camera industry never did anything to dispell those misconceptions, it even stamped the pixel counts on the cases of each camera as if it were even more relevant than maximum aperture – it’s not.</p>

<p>Phil does in this short segment what I would have had to do with customers who seemed receptive to my advice: explain to them that cramming pixels in a camera sensor makes for <em>bad</em> photos, not good ones. And granted, this knowledge is a little more widely spread these days than just a few years ago, but since the iPhone’s inception in 2007 this litany of pixel count inferiority has been the rallying cry of clueless competitors.</p>

<p>It used to be Nokia and its atrocious N95 (possibly the worst phone camera I have ever seen). Nowadays it’s Motorola, HTC and the like with their humongous screens <a href="http://dcurt.is/2011/10/03/3-point-5-inches">that can barely be operated one-handed</a> and with cameras boasting feature-checklist-friendly megapixel counts.</p>

<p>Guess why the iPhone is <a href="http://www.flickr.com/cameras">beating some worthy DSLR rivals in photo sharing site popularity</a>?</p>

<ol>
  <li>despite some obvious shortcomings, iPhone shots don’t look like ass.</li>
  <li>iPhone users actually use their cameras, and they have an easy path to sharing them.</li>
</ol>

<p>To finish off, here are some of the thoughtful details mentioned by Schiller: group facial exposure, lack of barrel distortion, shot-to-shot time, time-to-photo, depth of field, wide aperture, large dynamic range, accurate skin tones, etc.</p>

<p>I don’t know if Schiller is a camera enthusiast himself – it sure sounds that way – but at least this small presentation of the iPhone 4S’ visual chops reassures me that whoever is in charge of iPhone photography knows what they’re talking about.</p>

<p>I’ve owned a Canon EOS 5D Mark II for 2 years now. I bought it on a whim with money I should have saved for tuition in college. I made some of the technically best shots in my life with it, yet I have consistently made better and more memorable photos with my iPhone.</p>

<p>Why? Because it’s always there and it can take almost anything I throw at it. I’m thinking about selling my Mark II shortly after I receive my 4S.</p>

<blockquote>
  <p>“Do you know how hard it is to get a squirrel to stand still? Not easy.”</p>
</blockquote>

<p><img src="https://olivierlacan.com/assets/squirrel.jpg" alt="That Hairy Squirrel" /></p>

<p>PS: You can find actual shots (full size original files) from the 4S on <a href="http://www.apple.com/iphone/features/#camera">Apple’s website</a>.</p>
<img src="https://feed.olivierlacan.com/link/8226/8521104.gif" height="1" width="1"/>]]></description>
      <pubDate>Sat, 08 Oct 2011 11:27:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521104/that-salmon-color</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/that-salmon-color/</guid>
    </item>
    <item>
      <title>Anchors</title>
      <description><![CDATA[<p>Three years ago my grandfather died while I was 7000 kilometers away from him. My friends and I were getting ready for a day of fun. It was my first summer in Florida, my second in the United States.</p>

<p>I had last seen my grandfather in a small hospital not far from where he lived with my grandmother in a very rural part of central France. I say that I saw him but in truth what I saw wasn’t anything like him, his eyes were lost, he had lost a considerable amount of weight for a man who never seemed to have an ounce of fat on his bones.</p>

<p>He used to be tall and proud. He was a working man. He was a farmer and a wood carver.</p>

<p>When the phone rang and my mom told me that her dad had died, she sounded broken. That got to me even more than the news did. She’s an anchor, and she was loose.</p>

<p>I don’t know whether it was a concern for ruining everyone’s day or the fact that I was stunned, but it seemed like I felt nothing when I hung up the phone. My friends asked me about the call and I misdirected to avoid telling them what had happened. It was time for us to leave and I was the driver. I decided to go to the bathroom. I opened the door, intent on actually using the bathroom. I closed the door, sat down. Facing me was a mirror projecting my face. In it I saw my mom’s pain and despair. I started crying uncontrollably. I was losing it. I turned on the restroom fan to cover the sound of my whimpers and I stared myself blank in the eye.</p>

<p>I let the pain take its stab at me. I thought about my grandma and the loneliness she would now have to face living in a hamlet with a population of less than 20. She didn’t know how to drive, only he did. She lost her anchor too.</p>

<p>Yesterday, I left work frustrated over something trivial. It had mostly been a good day, but that little thing angered me enough that I needed some fresh air and stimulating company. I drove to my alma mater and sent a few messages around to see if any of my old classmates who currently work in the Web degree there were on campus.</p>

<p>Adam replied, we had dinner together and talked about my frustration, his fruitful discovery of Ruby on Rails, and he told me he was in charge of a lab at 9PM. I told him I would stick around until then.</p>

<p>After dinner we got back to the faculty offices, he went away for a second and I went to see if some of my favorite instructors and mentors were in the office. I was hoping Edward Almeida – who’s in charge in Final Projects – would be there. He was. I could see light emanating from his desk. I put my head above the separator of his workspace and made a silly joke about being “ahead”. He didn’t smile, he looked weary. He nodded toward his computer screen.</p>

<p>Black on white, the words read:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>Steve Jobs   1955 – 2011
</pre></td></tr></tbody></table></code></pre></div></div>

<p>“Fuck me.”, I uttered, and walked away.</p>

<p>Adam came back and asked me if I had heard. I said yes, and made some banal comment about the night being ruined.</p>

<p>Then without agreeing to it, we fell silent. Some people around the office discovered the news in the minutes that followed and were in disbelief. I saw a message from my friend Andrew telling me he was crying and his mother didn’t understand why. It was his birthday.</p>

<p>As I am now, I told him I was holding back tears. I felt an overwhelming need for privacy and headed to the office restrooms. I locked the door, sat down, and let the pain have at it once again.</p>

<p>That summer when my grandpa died I bought my first Mac, it was a refurbished MacBook Pro I ordered for a little cheaper online. Half of me had been swayed by the first iPod I bought in 2006 at the 5th Avenue Apple Store in New York City with my friend Clément. The other half wanted to prove all those Mac jerks wrong. I also felt I was at a turning point in my life. I was done with college in Paris and I harbored the foolish hope that I could find a good excuse to work or study in Florida, with which I fell in love the year before.</p>

<p>I was using computers regularly before I was even 10 years old. In 1995 that was still a huge deal, no one at my school owned a computer. My dad bought a beige Compaq anvil for Christmas, sometime before 1994. Since then every computer we had owned was powered by a Microsoft operating system.</p>

<p>We were tinkerers, we made our own machines. Despite the fact that they barely ever worked properly, we were proud of that. I regularly laughed at and had arguments with Mac owners during my teenage years when I became an amateur web designer. They were overly expensive, slower than cheaper Windows machines.</p>

<p>Somewere along the line we didn’t realize that what most of those weird Mac people were saying was that they loved their computers. We didn’t. We hated our computers. Despised them for crashing constantly and being the antithesis of what a tool should be. Tools should help us make things.</p>

<p>Since that summer of 2008, I’ve been a proud Mac owner. I own a professional DSLR camera, yet my favorite camera is my iPhone. Most importantly, at the begining of 2009 I moved to the US to design and build things I love. I took the reins. I would not have enrolled to Full Sail University and left my friends and family 7000 kilometers away if it weren’t for <a href="http://www.youtube.com/watch?v=D1R-jKKp3NA">these words</a>.</p>

<p>Yesterday I lost another anchor.</p>

<p><img src="https://olivierlacan.com/assets/crazy_ones.png" alt="Here's to the Crazy Ones" /></p>
<img src="https://feed.olivierlacan.com/link/8226/8521105.gif" height="1" width="1"/>]]></description>
      <pubDate>Thu, 06 Oct 2011 11:08:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521105/anchors</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/anchors/</guid>
    </item>
    <item>
      <title>The Nimble Workflow</title>
      <description><![CDATA[<p>Do work, instead of talking about it.</p>

<h2 id="morning">Morning</h2>

<h3 id="get-back-into-context">Get back into context</h3>

<ul>
  <li>What were you working on yesterday?</li>
  <li>Is it finished? What’s left to do?</li>
  <li>What should you do today?</li>
  <li>Are you in anybody’s way? Is someone in your way?</li>
</ul>

<h3 id="find-the-flow">Find the flow</h3>

<p>Mornings are one of the few quiet moments in an office, and in life in general. Take advantage of that. Start slow, make sure no one can or should break your rythm for at least 1 or 2 hours.</p>

<h3 id="stand-on-the-summit-look-around">Stand on the summit, look around</h3>

<p>Once you hammered out some of the most productive work of the day, take a break when no more critical loose threads are hanging.</p>

<h2 id="noon">Noon</h2>

<h3 id="hunger-is-the-enemy-of-focus">Hunger is the enemy of focus</h3>
<p>As soon as you feel the growlies take over, try to find a way to slide a bookmark into your flow. Make sure you leave off a not too steep path back to the summit. Your satiated self is a lazy beast.</p>

<h3 id="dont-put-your-digestive-system-into-overdrive">Don’t put your digestive system into overdrive</h3>
<p>There’s a reason we have sandwhiches, salads and other reasonably-sized portions. Light meals don’t sit in the belly for hours, reminding you that your digestive system always calls your brain to say that you’re full 10 minutes too late.</p>

<h3 id="make-sure-no-urgent-matter-is-ignored">Make sure no urgent matter is ignored</h3>
<p>Notice, I didn’t tell you to check your emails this morning? There’s a reason: so you can focus on your work when you can do it best.</p>

<p>That said, it’s best not to ignore urgent stuff altogether. The afternoon is a better time to react to unplanned events. You can get back to people before the end of the day, and that’s fine.</p>

<h2 id="afternoon">Afternoon</h2>

<h3 id="dont-resist-distractions">Don’t resist distractions</h3>
<p>People assume creativity dwells in quiet times, that it officiates only in early mornings and late evenings. That’s a misconception. Creatitity never sleeps. It lurks there all the time, especially when you’re not conscious of it.</p>

<p>Distractions are fertile ground for creative thoughts, they are essential breaths, punctuations that allow meaning to emerge from a misty problem you have been trying to evaporate.</p>

<p>You can’t replace distractions with work, they can’t be converted, they’re not using the same cognitive encoding. Regardless, fighting human nature is often a bad idea. You think you have it under control until it rebels against you, it’s a smarter bet to live in harmony with it.</p>

<h3 id="if-you-cant-finish-today-theres-always-tomorrow">If you can’t finish today, there’s always tomorrow</h3>
<p>Nothing should ever make you feel compelled to stay all night at the office. Being on tilt isn’t productive, it’s self-destructive.</p>

<p>That’s not to say you can’t be on a roll, but you have to remember that you can’t always finish everything. And in environment when you make productive time less of an exception, it shouldn’t be hard to get back on a roll.</p>

<h3 id="sustain-momentum">Sustain momentum</h3>
<p>You can run as fast as you want, you will always need to draw breath. It’s going to catch up to you.</p>

<p>Run steady, stop to rest. You’ll get there fast enough, and you’ll be ready to keep going instead of lying on the floor, a sweaty mess.</p>

<p><strong>Note</strong>: I intend on updating this article with any useful feedback, so don’t hesitate to provide some to me on Twitter. It was inspired by my own thoughts on productivity, as well as the works of <a href="http://merlinmann.com">Merlin Mann</a>, <a href="http://37signals.com/">Jason Fried</a> and <a href="http://david.heinemeierhansson.com">David Heinemeier Hansson</a>.</p>
<img src="https://feed.olivierlacan.com/link/8226/8521106.gif" height="1" width="1"/>]]></description>
      <pubDate>Sun, 21 Aug 2011 17:50:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521106/the-nimble-workflow</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/the-nimble-workflow/</guid>
    </item>
    <item>
      <title>Brewing With Homebrew</title>
      <description><![CDATA[<h2 id="what-is-homebrew">What is Homebrew?</h2>

<p><a href="http://mxcl.github.com/homebrew/">Homebrew</a> is the best package manager available for Mac. If you’ve heard of <a href="http://www.macports.org/">MacPorts</a>, I strongly urge you to consider switching to it.</p>

<p>If the concept of a package manager is foreign to you, let me explain. Most development tools are open-source projects, you can’t really do much with the source code of something if it’s an application supposed to run on your computer. In order to run an app, you have to compile the source code into an executable file.</p>

<p>If you have a unix/linux background, that’s something you would be used to do, it would also increase dramatically the chances that you sport a neckbeard. So I’ll assume almost none of you do.</p>

<p>Compiling source code can be tricky, there are dependencies (other executables that this application needs in order to function) and configurations that can turn a simple installation into hours of scouring for contradictory bits of information on obscure forums.</p>

<p>That’s where Homebrew comes it. It’s easy to install and the way it avoids making you configure and check for dependencies is by offering “formulas” – simple little scripts written in <a href="http://rubylang.info/">Ruby</a> (which comes bundled with Mac OS X) – that will do dependency checking and configuration for you. And while Homebrew is a command line utility, it gives you a lot of intelligible feedback on what it needs from you, and what it’s doing.</p>

<p>Better yet, unlike MacPorts, Homebrew installs itself within your <code class="language-plaintext highlighter-rouge">/usr/local/</code> directory and makes you the owner of all directory it installs applications into. It sounds banal, but it means you’ll never have to “sudo” (perform actions as the administrator account) when you need to install or upgrade executables.</p>

<p>The other advantage of installing things in <code class="language-plaintext highlighter-rouge">/usr/local/Cellar</code> is that Homebrew does not override any system installation. All it does is “symlink” (think of it as putting a shortcut) to its own Cellar.</p>

<h2 id="what-can-i-install-with-homebrew">What can I install with Homebrew?</h2>

<ul>
  <li><a href="http://rubylang.info/">Ruby</a></li>
  <li><a href="http://www.python.org/">Python</a></li>
  <li><a href="http://nodejs.org/">NodeJS</a></li>
  <li><a href="http://www.ffmpeg.org/">ffMPEG</a></li>
  <li><a href="http://www.mongodb.org/">MongoDB</a></li>
  <li><a href="http://redis.io/">Redis</a></li>
  <li><a href="http://memcached.org/">Memcached</a></li>
  <li><a href="http://www.mysql.com/">MySQL</a></li>
  <li><a href="http://www.postgresql.org/">PostgreSQL</a></li>
  <li><a href="http://code.google.com/p/macvim/">MacVim</a></li>
  <li><a href="http://developer.yahoo.com/yui/compressor/">YUIcompressor</a></li>
  <li><a href="http://www.imagemagick.org/script/index.php">ImageMagick</a></li>
  <li><a href="http://git-scm.com/">Git</a></li>
  <li><a href="http://clojure.org/">Clojure</a></li>
  <li><a href="http://www.erlang.org/">Erlang</a></li>
  <li><a href="http://jashkenas.github.com/coffee-script/">CoffeeScript</a></li>
</ul>

<p>And the list goes on, just type <code class="language-plaintext highlighter-rouge">brew search something</code> to find out if a formula exists. If you want the whole list, simple type <code class="language-plaintext highlighter-rouge">brew search</code>.</p>

<h2 id="great-where-do-i-get-it">Great, where do I get it?</h2>

<p><a href="http://mxcl.github.com/homebrew/">Learn more about Homebrew here</a></p>

<p><a href="https://github.com/mxcl/homebrew/wiki/installation">Install it quickly with these simple instructions.</a></p>
<img src="https://feed.olivierlacan.com/link/8226/8521107.gif" height="1" width="1"/>]]></description>
      <pubDate>Sat, 06 Aug 2011 14:05:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521107/brewing-with-homebrew</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/brewing-with-homebrew/</guid>
    </item>
    <item>
      <title>Teach to Learn</title>
      <description><![CDATA[<p>Many of my friends are teachers, children of teachers or people with a general disposition toward helping out others to learn stuff. For a while it puzzled me that I would somehow associate naturally with people like that. As I went through school, I kept thinking that you had to be a special kind of masochist to be willing to come back behind the bars (that’s really how I saw it) to try to shove some sense into the bunch of ungrateful bastards that surrounded me. And I didn’t exclude myself from the blame. Most of the time, I either didn’t want to learn, didn’t care or wanted to learn about anything except what was taught in school.
And while I still believe there is something fundamentally wrong about classical education through general knowledge courses, I’ve recently realized quite inadvertently that I’m turning into a teacher myself.</p>

<p>There were hints along the way. As soon as I started making websites during my last year of middle school, I became addicted to sharing things with the word, even if that world consisted of 10 random visitors and 20 search bots. When I became billingual after teaching myself English through tv shows (mainly), movies and books, I had this urge to try and help people around me (in France) to learn to stop being afraid of their lousy accents. Shame is one of the worst barriers to knowledge.</p>

<p>Finally more recently, as I was explaining a concept to a fellow student at Full Sail who was much earlier in the cursus than I was at the time, one of my favorite instructors looked at me and asked me if I had ever considered teaching. I was a little surprised by the question, then I realized what he meant. Teaching there, at Full Sail. I had never even considered it before, it flew completely past my radar, and somehow the thought felt right.</p>

<p>Since then I’ve noticed that every time I explain a design concept, an object-oriented principle, or one of the tennet of skepticism I somehow become almost instantly more at ease with the topic I just attempted to convey to another person. This practice of breaking down knowledge to its core essentials and bring it to the level of a specific person with specific biases and preconceptions is addictive.</p>

<p>I think I’m a slow learner, and while it’s disadvantage in many aspects it allows me to somehow remember better than some people the stumbling blocks I struggle with as I was learning a concept. While it doesn’t automatically make me a better teacher since the explanation matters, the ability to empathize with a student facing a seemingly insurmountable obstacle is something invaluable in an educational setting.</p>

<p>I believe many educated people forget how much they struggled to understand difficult concepts as soon as they do understand them. I vaguely remember reading about a psychological study outlining how this functioned. Basically, people have a tendency to forget how long they failed to grasp something and what exactly prevented from doing so. And with this post-success amnesia comes a general attitude of slight disdain toward people who seem to struggle more than you remember struggling yourself. It’s yet another cognitive failibility of the human mind but I think it explains why so many accomplished scholars make poor teachers.</p>
<img src="https://feed.olivierlacan.com/link/8226/8521108.gif" height="1" width="1"/>]]></description>
      <pubDate>Fri, 10 Jun 2011 00:00:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521108/teach-to-learn</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/teach-to-learn/</guid>
    </item>
    <item>
      <title>Gag</title>
      <description><![CDATA[<p>An anonymous contributor to the Washington Post:</p>

<blockquote>
  <p>Three years ago, I received a national security letter (NSL) in my capacity as the president of a small Internet access and consulting business. The letter ordered me to provide sensitive information about one of my clients. There was no indication that a judge had reviewed or approved the letter, and it turned out that none had. The letter came with a gag provision that prohibited me from telling anyone, including my client, that the FBI was seeking this information. Based on the context of the demand — a context that the FBI still won’t let me discuss publicly — I suspected that the FBI was abusing its power and that the letter sought information to which the FBI was not entitled.</p>
</blockquote>

<p>How somber that America’s worst enemy turned out to be its own government, using the threat of terrorism as a way to destroy the very tenets of what it should have been standing up for: the American Democracy.</p>

<blockquote>
  <p>If I hadn’t been under a gag order, I would have contacted members of Congress to discuss my experiences and to advocate changes in the law.</p>
</blockquote>

<p>If this sentence doesn’t chill you to the bone, realize that this is something to expect from a repressive dictatorship.</p>

<p>I started to properly learn about American history after 2001, and I found it fascinating. Here was a country founded on a near-scientific approach to perfecting government, with the idea (taken from <a href="http://en.wikipedia.org/wiki/Charles_de_Secondat,_Baron_de_Montesquieu">Montesquieu</a>) that there needed to be a <a href="http://en.wikipedia.org/wiki/Separation_of_powers_under_the_United_States_Constitution">separation and balance of powers</a>. Instead of trying to imagine what should be forbidden, this country focused on what should be absolutely safeguarded. It agreed on a concise, beautiful and imperfect definition of what it meant to be part of a free society.</p>

<p>But despite my continued hopes, America has proven to be shaken off balance for the last 10 years. Instead of reacting like a free nation, it was constricted by fear and paranoïa. It turned into an Ouroboros, devouring itself for an untangible threat.</p>

<p>I wouldn’t be here today if I had lost hope, but America needs to wake up.</p>
<img src="https://feed.olivierlacan.com/link/8226/8521109.gif" height="1" width="1"/>]]></description>
      <pubDate>Thu, 12 May 2011 00:00:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521109/gag</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/gag/</guid>
    </item>
    <item>
      <title>Extreme Atheism</title>
      <description><![CDATA[<p>I recently replied to a friend, as a response to her reaction to this admittedly imperfect article from the Washington Post’s opinion column entitled <a href="http://www.washingtonpost.com/opinions/why-do-americans-still-dislike-atheists/2011/02/18/AFqgnwGF_story.html">Why do Americans still dislike atheists?</a>.
Here’s her response:</p>

<blockquote>
  <p>I think that if you remove the group of people for whom the rules of their religion are so central to their being that that have all sorts of hatreds, and instead look at what is uncomfortable about atheism for the large group of reasonable people who remain, the answer would be that people dislike extremism of all kinds. Atheism is as extreme as fundamentalism. It’s not nearly as harmful, but ideologically, it is as extreme. For atheists and fundamentalists, the question is answered. For everyone else, there is a long way to go.</p>
</blockquote>

<p>And here’s mine to hers:</p>

<p>That’s a common misconception.</p>

<p>Atheism is the absence of religious dogma, it couldn’t be more different than fundamentalism which implies the strict orthodox application of religious dogma without concern for modern society.
Atheism is absence of a doctrine, without doctrime there is nothing to be “fundamental” about. That’s about it. How one could even begin to describe that as extreme boggles my mind. But if you can make a solid argument as to how exactly, I’ll be sure to listen.</p>

<p>As many atheist choose to describe it, Atheism is about as extreme as refusing to believe that there is Flying Spaghetti Monster out there in the universe because you can’t prove to absolute certainty that there isn’t. It just happens to be extraordinarily unlikely.</p>

<p>Now if it is extreme to find reality sufficiently elegant a companion that one doesn’t wish to agree to the existence of supernatural beings with powers defying just about every law of nature for comfort or sense of meaning, I’ll gladly join the fundamentalists, I’m they will be as open to logic and reason as I am.</p>

<p>That said, I almost wish Atheist were despised for their extremism as you believe it would be easier to dispell. In truth many Americans think them without morals whatsoever because they cannot conceive of morality or ethics without religion.</p>

<p>Bear in mind, this is not to say that there aren’t extremist atheists (quite a difference here) and misguided ones. I’ve met a few of them and most often in and around campuses here. Many of them were recent apostates who are enraged enough to draw generalizations and behave in a way that is not condoned by anyone civilized (religious or otherwise).</p>

<p>But if I could leave you with a lasting thought it would be the <a href="http://pewforum.org/other-beliefs-and-practices/u-s-religious-knowledge-survey.aspx">revealing discovery</a> recently that self-described Atheists &amp; Agnostics were found to be <a href="http://www.nytimes.com/2010/09/28/us/28religion.html">more knowledgeable about Christianity, the Bible and other world religions than any other group of religious Americans</a>. If this doesn’t make you doubt your assumptions about Atheists, nothing will. Opinion based on knowledge isn’t extreme, it’s reasonable.</p>

<p><img src="https://olivierlacan.com/assets/pew-forum-survey-atheism.png" alt="Pew Forum Survey on Religious Knowledge" /></p>

<p>PS : I found this thorough takedown of the fallacious argument I tried to quickly tackle above on <a href="http://www.atheistrev.com/2007/03/atheist-extremism.html">Atheist Revolution</a> blog after I wrote my response. I think it covers all the bases I didn’t and still addresses the (rare for now) case of atheist extremists.</p>
<img src="https://feed.olivierlacan.com/link/8226/8521110.gif" height="1" width="1"/>]]></description>
      <pubDate>Wed, 04 May 2011 00:00:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521110/extreme-atheism</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/extreme-atheism/</guid>
    </item>
    <item>
      <title>It Gets Better</title>
      <description><![CDATA[<p>I had an uncomfortably heated discussion with someone dear to me today about the <a href="http://www.itgetsbetter.org/video/entry/iwyqsajk_u8/">“It Gets Better” video</a> released by the lesbian, gay, bi and transexual employees of Apple Inc. today on YouTube (Adobe Systems employees released a similar video).
It came as a shocking surprise to me that anyone would see these people talking about the struggles they went through and the peace and happiness they have achieved and find it anything else than uplifting.
It wasn’t for her. She found it depressing and was sad that we even had to wait so long to achieve something like this, having adults — many of them extremely successful and talented individual in some of the most renowned companies in America — discuss their difference so openly on camera.</p>

<p>The thought that they were doing this to help younger fellow human beings going through the same shit didn’t reassure her, it seemed to make her angrier.</p>

<p>I didn’t understand, I think I tried to, but I couldn’t. I thought she may have something on her mind, something affecting her outlook on things, something bothering her and making her pessimistic. She denied it, but I honestly didn’t want to accept that.</p>

<p>It was rude of me I’m sure, but I can’t help it. Optimism isn’t escapism. I don’t ignore all the bad in the world to sleep better at night. But humanity has never done better. We’ve never lived so long, never known so much about ourselves, our planet and the Universe.</p>

<p>We’ve never been so peaceful either. It’s something most people don’t only find hard to believe, they refuse to.</p>

<p>Crime &amp; warfare have decreased so much that most deaths today are due to age-related diseases, it’s unprecedented in the history of man. Cardiovascular diseases — the greatest killer in the world — accounted for 30% of worldwide mortality in 2002. War &amp; violent crimes (bundled together with suicide and other causes) are only responsible for 3%.</p>

<p>Diseases still rule the death toll. Yet if I had lived a mere 200 years ago all I could have hoped for was a mere 10 years to live past my upcoming twenty-sixth birthday. Today I can look forward to a good 50 years, perhaps much more.</p>

<p>That doesn’t mean things are easy for everyone, and too recently racial and sexual discriminations are a harsh reminder of that. Yet once again, things are going better. It’s not a fallacy to say that a black man born of an African father and and American mother at the head of the greatest superpower in the world is an outstanding event in a country that two centuries prior saw blacks as nothing more than inferior beings only fit for slavery.</p>

<p>And while the amoral defenders of morality still deny basic human and civil rights to homosexuals or anyone that challenges their narrow iron-age mentality, there too things are improving, around the world.</p>

<p>How many more moments of joy, pain, pleasure and sadness will we enjoy? How many more things will we have the opportunity to build? How many beautiful sunsets and moon rises will we have the chance to witness? How many people will we discover who will affect the course of our lives those we already met did? How many answers will we find and how many more questions will we think of?</p>

<p>I don’t know.</p>

<p>All I know is that it gets better. But I couldn’t always afford the perspective to see that, and fellow human beings’ kind reminder would have helped.</p>

<p>I know that much.</p>
<img src="https://feed.olivierlacan.com/link/8226/8521111.gif" height="1" width="1"/>]]></description>
      <pubDate>Thu, 14 Apr 2011 00:00:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521111/it-gets-better</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/it-gets-better/</guid>
    </item>
    <item>
      <title>Free Inquiry Starts in the Classroom</title>
      <description><![CDATA[<blockquote>
  <p>“You can’t understand Google,” vice president Marissa Mayer says, “unless you know that both Larry and Sergey were Montessori kids.” She’s referring to schools based on the educational philosophy of Maria Montessori, an Italian physician born in 1870 who believed that children should be allowed the freedom to pursue their interests. “In a Montessori school, you go paint because you have something to express or you just want to do it that afternoon, not because the teacher said so,” she says. “This is baked into how Larry and Sergey approach problems. They’re always asking, why should it be like that? It’s the way their brains were programmed early on.”
– Steven Levy, http://www.wired.com/magazine/2011/03/mf_larrypage/all/1 Larry Page Wants to Return Google to Its Startup Roots</p>
</blockquote>

<p>It’s sad that so many children are berated out of asking crucial questions like “Why?” by parents, teachers and relatives who perpetuate the medieval notion that curiosity killed the cat.</p>

<p>Curiosity is the fuel of inquiry, it’s the essence of Science. It should be safeguarded at all costs.</p>

<p>This is not that say that a mischievous kid who is testing boundaries by uttering an endless stream of “why this? why that?” at every explanation given to him shouldn’t be punished for abusing people’s patience.</p>

<p>But too often true curiosity and wonder at the mysteries of life and the universe is sacrificed because some brats have abused the system, ruining the chance for all the other bubbling little minds to ask questions their elders too often haven’t thought of asking, or worse, have given up on trying to ask.</p>

<p>As a kid I was revolted against this idea that children “shouldn’t talk back” which in France meant that if an adult offered an irrational proposition, children should be punished for even questioning the validity of such a proposition with their natural skepticism. Thankfully, it was something that my parents never enforced on me, they would do their best to answer me honestly and on some rare occasions even admitted ignorance, giving me a clue early on that adults didn’t necessarily know everything. Despite that, the rest of my family and even strangers often did their best to try to plant that awful shame of questioning appeals to authority.</p>

<p>The more I read about the Montessori approach in articles like the recent one from the Wall Street Journal – <a href="http://blogs.wsj.com/ideas-market/2011/04/05/the-montessori-mafia/">The Montessori Mafia</a>, the more I come to think it may be one of the solutions to the many woes of modern education, which sadly is nothing short of an oxymoron for now.</p>
<img src="https://feed.olivierlacan.com/link/8226/8521112.gif" height="1" width="1"/>]]></description>
      <pubDate>Sat, 09 Apr 2011 00:00:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521112/free-inquiry-starts-in-the-classroom</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/free-inquiry-starts-in-the-classroom/</guid>
    </item>
    <item>
      <title>Virtual Ideas</title>
      <description><![CDATA[<p>Note : This article was originally intended for fellow students at Full Sail University’s Web Design &amp; Development program. Since I expect it could be useful for anyone, I decided to post it here as well.
Since most of you guys are especially mum these days I’d like to tackle something I’ve heard way too often around campus when people mention final presentations: “Oh, I’ve got a good idea but it’s too early to talk about it.”.</p>

<p>What I’ve noticed is that is never too early to talk about it, because most of you, I’ll tell you right, will not talk about it until it’s too late. Your idea sounds exciting, amazing and maybe challenging in your head. But your idea has never been out in the real world, it never had to cross the street and watch out for better ideas zooming by. In your head your amazing idea is never going to get shot down by a one-liner from a friend you expect to be in your target demographic.</p>

<p>Now I’m certain some of you think that if you talk about your idea someone is going to take it. Sure, that can happen, but this is a school, things like that don’t go unnoticed, or unpunished. If you think you’d rather stay mum about your idea because it might have some weight in the real world, after you graduate at Full Sail, then let’s see if it can even stand on its own legs in our little world before you take it out to the big leagues.</p>

<p>A good idea is infectious, people get excited about it, they want to help you with it, will make suggestions to make it better or you will find out who doesn’t like it, and why.</p>

<p>Exposing your idea doesn’t mean you have to shout it out to the entire school, but you can start testing the waters, as early as possible. Go see course director, a lab instructor, a fellow student who’s early in the program or about to start his final project so you get the benefit of the knowledge he gathered.</p>

<p>If you manage to get someone else excited, do you have any idea how motivated it’s going to make you?</p>

<p>And what’s the worst that can happen? You could learn about your idea. Isn’t that why we’re here?</p>
<img src="https://feed.olivierlacan.com/link/8226/8521113.gif" height="1" width="1"/>]]></description>
      <pubDate>Fri, 11 Feb 2011 00:00:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521113/virtual-ideas</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/virtual-ideas/</guid>
    </item>
    <item>
      <title>Path to America</title>
      <description><![CDATA[<p>I was looking around old photos for something I’m making for a great friend and I realized that I had never connected two important events in my life.
In January 2007, after having moved out of my parent’s house the previous summer, I decided on a whim to go to New York City for something like 3 or 4 days. My university’s winter break was longer than usual that year and I thought I had enough money to afford the cheaper than usual trip (post-New Year’s hotels and flights were deserted). In reality I couldn’t as I got slammed with a huge bill for my apartment’s utilities when I got back.</p>

<p>It was the first time in my life I took a plane — a transatlantic flight — alone. It was hard to express why exactly I wanted to go to NYC like that, in a cold season, alone, with no clear purpose. I remember wondering how my girlfriend at the time would take it, but I couldn’t reason myself, I had to go.</p>

<p>The feeling of absolute control of making a decision by myself, and executing it on my own was exhilarating. I didn’t do anything very interesting for those three days. I would wake up, walk around the city, shop around, eat, take pictures of buildings, billboards and people, then go back to my hotel and browse the web.</p>

<p>One slight excuse I had used on myself was that huge rumors were going around that Apple was going to introduce the elusive iPhone to the world at a special event on the second day of my trip. I wasn’t really familiar with Apple’s practices at the time as I had purchased my first Apple device (an iPod Video 5G) the previous summer at the 5th Avenue Apple Store in NYC with my friend Clément Dague. I somehow hoped the device would be released immediately at Apple’s flagship store and that I could snatch one before flying home, and maybe sell it to pay for my journey.</p>

<p>The iPhone was announced, and even though it wasn’t even on display at the 5th Avenue Apple store I felt like I was closer to technological history being made. It might have sounded foolish if I had voiced that feeling at the time, but I don’t think anyone would laugh at that today.</p>

<p>Walking around the streets of New York, not like a tourist, but like a free man (minus a job and responsibilities) gave me a glimpse into what at the time I only felt was a crazy dream.</p>

<p>A few months later, I met two American girls that are now my friends, one stayed at my apartment that summer, the other one jumped from joy when she realized I was the only fluent English speaker at a house party in Paris a few weeks later.</p>

<p>In August I flew to Quebec with my parents to visit friends and I sneaked out on a Greyhound bus from Montréal to go visit a friend from college with dual citizenship who was working in New York City for the summer. I finally got my hands on that damned iPhone on display at the 5th Avenue Apple Store and called my mom in Canada (for free) with it.</p>

<p>When I came back to France, and eventually to college I couldn’t keep the sound of the world buzzing in my head quiet anymore during tedious lectures on British Civilization. So I sent a text to one of the girl I had met that summer, she replied.</p>

<p>When my friend Guillaume told me he was visiting his brother for Halloween, I bought tickets to Orlando, Florida. A friend from class had never travelled outside of France, I took her with me. We landed on November 5th 2007. When I left on November 10th, I cried.</p>

<p>PS : I’m writing this on February 11th, 2011 from Winter Park, Florida.</p>
<img src="https://feed.olivierlacan.com/link/8226/8521114.gif" height="1" width="1"/>]]></description>
      <pubDate>Fri, 11 Feb 2011 00:00:00 +0000</pubDate>
      <link>https://feed.olivierlacan.com/link/8226/8521114/path-to-america</link>
      <guid isPermaLink="true">https://olivierlacan.com/posts/path-to-america/</guid>
    </item>
  </channel>
</rss>
