<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
  xmlns:content="http://purl.org/rss/1.0/modules/content/"
  xmlns:dc="http://purl.org/dc/elements/1.1/"
  xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd"
  xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>msol</title>
    <link>https://msol.io</link>
    <description>msol • a blog made of words</description>
    <pubDate>Sat, 15 Jun 2019 04:50:13 -0700</pubDate>
    <item>
      <title>Mac productivity tips for developers</title>
      <link>https://msol.io/blog/tech/work-more-efficiently-on-your-mac-for-developers/</link>
      <description><![CDATA[Working faster

]]></description>
      <pubDate>Sat, 15 Jun 2019 04:50:13 -0700</pubDate>
      <guid>https://msol.io/blog/tech/work-more-efficiently-on-your-mac-for-developers/</guid>
      <content:encoded><![CDATA[# Working faster

Software developers spend hour after hour on their machines,
so it's worth spending a little time improving common workflows now and then.

The time you can spend on this is virtually unbounded,
but I have found there are a few tricks that many people miss---a
handful of high-value improvements that can go a long way without hours of investment.

Some of these improvements require extra software,
(all of it free and open source)
and there's a [section][software] at the bottom to set that up when needed.



## 1: The "Hyper" key + transform Caps Lock into Escape

You know what would be great?
Having an extra modifier key open for whatever we want.

We can make use of [Steve Losh's idea][hyper] of emulating the extra "Hyper" key introduced
by the [Space Cadet keyboard][space-cadet] by defining Hyper as control+option+command+shift.
Since no sane application will expect a user to hold all those keys at once,
we can effectively create a new modifier key.

My primary use for Hyper is machine-global shortcut keys,
especially for window management with [Hammerspoon][hammerspoon-tip].

Vim users often remap caps lock to Escape to save their pinky finger some pain. We are going to do that too--but only when tapped. That way, we can user Hyper and Escape on the same key, without them interfering.

### Setup

First install [Karabiner Elements][karabiner-install].

Then, install [this karabiner configuration](karabiner://karabiner/assets/complex_modifications/import?url=https://msol.io/files/karabiner/hyper.json).

Alternatively, you can download [this file](https://msol.io/files/karabiner/hyper.json) and add it by hand to the complex modifications section of
`~/.config/karabiner/karabiner.json`.

Now that that's done,
it's time to set up some shortcuts that use Hyper in order to ease window management.


## 2: Managing windows with Hammerspoon

Hammerspoon is a macOS swiss army knife.
I mostly use it for window management, not unlike other tools like Divvy or SizeUp.
It lets you arrange, resize, switch between, and open applications and windows on one or more monitors.

By setting up a few basic commands in Hammerspoon,
switching between and resizing windows in macOS becomes much faster.
I have a simple set of related commands that are easy to learn and use,
but improve my daily efficiency manyfold.

First, I have the 10-15 most common applications I use bound to [Hyper][hyper-tip] + a single key, such as Hyper+space to open my editor. Next, I have shortcuts for window movement and resizing for the active window: full-screen, two half-screens, four quarter-screens, one to cycle the application between monitors, and one to cycle between instances of the same application.

Mastering these commands is enough to work extremely efficiently, but I have a few others included that I find useful as well.

### Setup

First [install Hammerspoon][hammerspoon].
Then open up `~/.hammerspoon/init.lua` and add this:

<noscript><pre>-- Mike Solomon @msol 2019

local log = hs.logger.new(&#39;main&#39;, &#39;info&#39;)
DEVELOPING_THIS = false -- set to true to ease debugging

HYPER = {&#39;ctrl&#39;, &#39;shift&#39;, &#39;alt&#39;, &#39;cmd&#39;}

-- App bindings
function setUpAppBindings()
  hyperFocusAll(&#39;w&#39;, &#39;React Native Debugger&#39;, &#39;Simulator&#39;, &#39;qemu-system-x86_64&#39;)
  hyperFocusOrOpen(&#39;e&#39;, &#39;Notes&#39;)
  hyperFocus(&#39;i&#39;, &#39;IntelliJ IDEA&#39;, &#39;IntelliJ IDEA-EAP&#39;, &#39;Xcode&#39;, &#39;Android Studio&#39;, &#39;Atom&#39;, &#39;Code&#39;)
  hyperFocusOrOpen(&#39;a&#39;, &#39;Finder&#39;)
  hyperFocusOrOpen(&#39;x&#39;, &#39;Calendar&#39;)
  hyperFocusOrOpen(&#39;m&#39;, &#39;Messages&#39;)
  hyperFocusOrOpen(&#39;r&#39;, &#39;Slack&#39;)
  hyperFocus(&#39;t&#39;, &#39;Safari&#39;)
  hyperFocusOrOpen(&#39;;&#39;, &#39;iTerm2&#39;)
  hyperFocusOrOpen(&#39;s&#39;, &#39;OmniFocus&#39;)
  hyperFocus(&#39;f&#39;, &#39;Google Chrome&#39;, &#39;Firefox&#39;)
  hyperFocusOrOpen(&#39;space&#39;, &#39;Sublime Text&#39;)
end

-- Window management
function setUpWindowManagement()
  hs.window.animationDuration = 0 -- disable animations
  hs.grid.setMargins({0, 0})
  hs.grid.setGrid(&#39;2x2&#39;)

  function mkSetFocus(to)
    return function() hs.grid.set(hs.window.focusedWindow(), to) end
  end

  local fullScreen = hs.geometry(&quot;0,0 2x2&quot;)
  local leftHalf = hs.geometry(&quot;0,0 1x2&quot;)
  local rightHalf = hs.geometry(&quot;1,0 1x2&quot;)
  local upperLeft = hs.geometry(&quot;0,0 1x1&quot;)
  local lowerLeft = hs.geometry(&quot;0,1 1x1&quot;)
  local upperRight = hs.geometry(&quot;1,0 1x1&quot;)
  local lowerRight = hs.geometry(&quot;1,1 1x1&quot;)

  hs.hotkey.bind(HYPER, &#39;l&#39;, mkSetFocus(fullScreen))
  hs.hotkey.bind(HYPER, &#39;h&#39;, mkSetFocus(leftHalf))
  hs.hotkey.bind(HYPER, &quot;&#39;&quot;, mkSetFocus(rightHalf))
  hs.hotkey.bind(HYPER, &quot;y&quot;, mkSetFocus(upperLeft))
  hs.hotkey.bind(HYPER, &quot;b&quot;, mkSetFocus(lowerLeft))
  hs.hotkey.bind(HYPER, &quot;u&quot;, mkSetFocus(upperRight))
  hs.hotkey.bind(HYPER, &quot;n&quot;, mkSetFocus(lowerRight))

  hs.hotkey.bind(HYPER, &quot;up&quot;, hs.window.filter.focusNorth)
  hs.hotkey.bind(HYPER, &quot;down&quot;, hs.window.filter.focusSouth)
  hs.hotkey.bind(HYPER, &quot;left&quot;, hs.window.filter.focusWest)
  hs.hotkey.bind(HYPER, &quot;right&quot;, hs.window.filter.focusEast)
  -- hs.hotkey.bind(HYPER, &quot;v&quot;, hs.window.filter.focusNorth)
  -- hs.hotkey.bind(HYPER, &quot;c&quot;, hs.window.filter.focusSouth)
  -- hs.hotkey.bind(HYPER, &quot;j&quot;, hs.window.filter.focusWest)
  -- hs.hotkey.bind(HYPER, &quot;p&quot;, hs.window.filter.focusEast)
  hs.hotkey.bind(HYPER, &quot;q&quot;, hs.hints.windowHints)
  -- HYPER &quot;d&quot; -- Bound in Karabiner to Cmd+Tab (application switcher)
  -- HYPER &quot;k&quot; -- Bound in Karabiner to Cmd+` (next window of application)

  -- throw to other screen
  hs.hotkey.bind(HYPER, &#39;o&#39;, function()
    local window = hs.window.focusedWindow()
    window:moveToScreen(window:screen():next())
  end)
end

-- focus on the last-focused window of the application given by name, or else launch it
function hyperFocusOrOpen(key, app)
  local focus = mkFocusByPreferredApplicationTitle(true, app)
  function focusOrOpen()
    return (focus() or hs.application.launchOrFocus(app))
  end
  hs.hotkey.bind(HYPER, key, focusOrOpen)
end

-- focus on the last-focused window of the first application given by name
function hyperFocus(key, ...)
  hs.hotkey.bind(HYPER, key, mkFocusByPreferredApplicationTitle(true, ...))
end


-- focus on the last-focused window of every application given by name
function hyperFocusAll(key, ...)
  hs.hotkey.bind(HYPER, key, mkFocusByPreferredApplicationTitle(false, ...))
end


-- creates callback function to select application windows by application name
function mkFocusByPreferredApplicationTitle(stopOnFirst, ...)
  local arguments = {...} -- create table to close over variadic args
  return function()
    local nowFocused = hs.window.focusedWindow()
    local appFound = false
    for _, app in ipairs(arguments) do
      if stopOnFirst and appFound then break end
      log:d(&#39;Searching for app &#39;, app)
      local application = hs.application.get(app)
      if application ~= nil then
        log:d(&#39;Found app&#39;, application)
        local window = application:mainWindow()
        if window ~= nil then
          log:d(&#39;Found main window&#39;, window)
          if window == nowFocused then
            log:d(&#39;Already focused, moving on&#39;, application)
          else
            window:focus()
            appFound = true
          end
        end
      end
    end
    return appFound
  end
end


function maybeEnableDebug()
  if DEVELOPING_THIS then
    log.setLogLevel(&#39;debug&#39;)
    log.d(&#39;Loading in development mode&#39;)
    -- automatically reload changes when we&#39;re developing
    hs.pathwatcher.new(os.getenv(&#39;HOME&#39;) .. &#39;/.hammerspoon/&#39;, hs.reload):start()
    hs.alert(&#39;Hammerspoon config reloaded&#39;)
    log:d(&#39;Hammerspoon config reloaded&#39;)
  end
end

function setUpClipboardTool()
  ClipboardTool = hs.loadSpoon(&#39;ClipboardTool&#39;)
  ClipboardTool.show_in_menubar = false
  ClipboardTool:start()
  ClipboardTool:bindHotkeys({
    toggle_clipboard = {HYPER, &quot;p&quot;}
  })
end

-- Main

maybeEnableDebug()
setUpAppBindings()
setUpWindowManagement()
setUpClipboardTool()
</pre></noscript><script src="https://gist.github.com/msolomon/db3ec8c1c7b2620b4ec242f15f042fa0.js"> </script>

Then run Hammerspoon (or "Reload Config" from the menu bar icon).

The configuration file is pretty easy to read with a little effort.
If you set up the [Hyper key][hyper-tip],
then this file should just work for you,
and I find these particular settings to be very useful.


## 3: Tap shift to move over words

I find that moving my cursor word-by-word is very useful even outside my text editor. OS X provides line-editing shortcuts similar to [Readline][readline]/[Emacs][emacs], for example Control+a to jump to the beginning of a line and Control+e to jump to the end (which I recommend you use). Even better is to do this without a modifier key!

Inspired by a [similar idea about parens][tap-parens] from Steve Losh, notice that tapping your shift key normally does nothing, and you rarely do so. Instead, why not tap left-shift to move one word to the left, and tap right-shift to move one word to the right?

I find this very useful for moving short distances in text of all kinds, and it soon becomes second nature.

### Setup

First install [Karabiner Elements][karabiner-install].

Then, install [this karabiner configuration](karabiner://karabiner/assets/complex_modifications/import?url=https://msol.io/files/karabiner/shift.json).

Alternatively, you can download [this file](https://msol.io/files/karabiner/shift.json) and add it by hand to the complex modifications section of
`~/.config/karabiner/karabiner.json`.


## 4: Right-thumb control key

How often do you use the right-side command key? Never.

Instead of wasting that key,
why not turn it into a control key?
Control is very useful if you spend time in the terminal
([iTerm2][iTerm2] is great) so you can do e.g.
control+p to get the previous command,
or control+r to search previous commands.

You press this key by curling your right thumb.
It may feel unnatural at first,
but before long the relief on your left pinky will be palpable.

### Setup

First install the excellent [Karabiner Elements][karabiner-install].

<img class="post-image"
     title="Right-side control configuration screenshot"
     alt="Command-R to Control-L configuration"
     src="/img/mac-dev/command-r-to-control-l.png"/>

Then open it and under "Simple Modifications" change the "From key" `right_command` and the "To key" to `left_control`. Done!


## 5: Ctrl+W deletes the previous word

When you make a typing mistake, it is often faster to rewrite the entire last word than to repeatedly press backspace to erase the typo. I find this to be much more efficient overall. Emacs users will already be familiar with the choice of Ctrl+W.

### Setup

First install [Karabiner Elements][karabiner-install].

Then, install [this karabiner configuration](karabiner://karabiner/assets/complex_modifications/import?url=https://msol.io/files/karabiner/ctrlw.json).

Alternatively, you can download [this file](https://msol.io/files/karabiner/ctrlw.json) and add it by hand to the complex modifications section of
`~/.config/karabiner/karabiner.json`.

This works especially well with the [right thumb control key][right-thumb-tip].


## 6: A better shell with [oh-my-zsh][oh-my-zsh]

Most people use Bash for their shell.
Assuming you spend some time in the terminal,
you probably already know your way around Bash pretty well.
Sadly, Bash has limited capabilities,
especially for command completion.
Other shells, like [Zsh][zsh], offer more but can be unfamiliar.

Enter [oh-my-zsh][oh-my-zsh]:
a layer of frosting on top of the powerful Z-shell that makes it Bash-compatible
and adds a self-updating system of [plugins][omz-plugins] and [themes][omz-themes].
You will find your autocomplete much improved
as well as available niceties like changing directories by typing directory names without `cd`,
and a very nice default prompt.

Oh-my-zsh also opens the door to more powerful customizations,
and boasts an active community of people who have often already implemented features you wish your shell had.

### Setup

First install Zsh. If you use [Homebrew][homebrew]---which I hope you do---then simply
`brew install zsh`.
You will also need Git (`brew install git`).
Then just run the [curl-to-shell command][omz-install] from oh-my-zsh's setup instructions,
open up `~/.zshrc` and enable a few [plugins][omz-plugins]
by adding them to the `plugins=( ... )` array you'll see in that file,
and you're done!
Be sure to open a new terminal window to see your changes.


## 7: Syntax highlighting in the terminal

I love syntax highlighting because it lets me catch errors in my code as I type.
Why not have the same thing for my bash commands in the terminal?

<img class="post-image"
     title="Syntax highlighing on oh-my-zsh"
     alt="Terminal syntax highlighting screenshot"
     src="/img/mac-dev/terminal-syntax-highlighting.png"/>

This syntax highlighting makes valid commands yellow,
invalid commands red, highlights strings, and underlines valid file paths.

### Setup

This one requires [oh-my-zsh][omz-tip] as seen in the previous tip.
Syntax highlighting is an oh-my-zsh plugin, but it doesn't come bundled by default.

Run the commands
<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nb">mkdir</span> ~/.oh-my-zsh/custom/plugins
git clone git://github.com/zsh-users/zsh-syntax-highlighting.git ~/.oh-my-zsh/custom/plugins/zsh-syntax-highlighting</code></pre></figure>
to install the plugin.
Then open up `~/.zshrc` and add `zsh-syntax-highlighting` to the end of the `plugins=( ... )` array.
Open up a new terminal and enjoy your syntax highlighting!

## 8: Faster key repeat

OS X defaults to a very slow key repeat rate,
but it also doesn't let you lower it enough to please me in System Preferences.
This often comes in handy for moving short distances in text.

### Setup

You can customize this by running commands in your Terminal.

Here are the settings I use, that I got from somewhere online (fractional values do not work). You may need to log out and back in to see them applied.

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">defaults write <span class="nt">-g</span> InitialKeyRepeat <span class="nt">-int</span> 10 <span class="c"># normal minimum is 15 (225 ms)</span>
defaults write <span class="nt">-g</span> KeyRepeat <span class="nt">-int</span> 1 <span class="c"># normal minimum is 2 (30 ms)</span></code></pre></figure>


## 9: File-searching aliases

Many terminal users set up aliases to shorten common tasks,
such as `alias gc='git commit'` so that the whole command doesn't need to be typed.
You should of course set up custom aliases,
but there are two in particular that I find useful quite often.

The first is `f`,
which searches the current directory subtree for files with names containing a string (ignoring case).
`f png` would find all PNG files in the current subtree,
as well as "PNGisMyFavorite.txt" and so forth.

The second is `r`,
which recursively greps the current directory subtree for files matching a pattern.
`r HTTP` would grep for files containing that exact string,
while `r '"http[^"]*"' -i` would search for double-quoted strings starting with "http", ignoring case.

### Setup

We will actually implement these as Bash (or Zsh) functions or aliases
in `~/.bashrc` or `~/.zshrc`.
Just add these lines anywhere in the file appropriate to your shell:

<noscript><pre>400: Invalid request</pre></noscript><script src="https://gist.github.com/9453299.js"> </script>


# Software

Some of these improvements require software. Here are some of the most important.

### [Karabiner Elements][karabiner]

Karabiner lets you rebind keys,
key combinations, trackpad gestures, set key delays, and more.
It allows customization through a GUI, or a configuration file which lives at `~/.config/karabiner/karabiner.json`.

### [Hammerspoon][hammerspoon]

Hammerspoon is a macOS swiss army knife.
I mostly use it for window management, not unlike other tools like Divvy or SizeUp. It lets you arrange, resize, switch between, and open applications and windows on one or more monitors, among many other things.
It can be customized through a Lua file at  `~/.hammerspoon/init.lua`.

### [Oh My Zsh][oh-my-zsh]

Oh My Zsh makes it easy to get a great shell configuration, making your work in the terminal much better. It is community maintained and has many plugins.


# More resources

I tried to hit high-value improvements that I don't think most people already have,
but there is a whole world of deeper customization out there.
Here are some links to resources I've found useful:

* [Toward a more useful keyboard](https://github.com/jasonrudolph/keyboard), Jason Rudolph
* [A Modern Space Cadet](http://stevelosh.com/blog/2012/10/a-modern-space-cadet/), Steve Losh
* [Holman does dotfiles](https://github.com/holman/dotfiles), Zach Holman
* [Hammerspoon documentation](https://www.hammerspoon.org/docs/index.html)
* [Karabiner Elements][karabiner] options

[emacs]: https://www.gnu.org/software/emacs/
[homebrew]: http://brew.sh/
[hyper-tip]: #1-the-hyper-key--transform-caps-lock-into-escape
[hyper]: http://stevelosh.com/blog/2012/10/a-modern-space-cadet/#hyper
[iterm2]: http://www.iterm2.com/
[karabiner-install]: #karabiner-elements
[karabiner]: https://pqrs.org/osx/karabiner/
[oh-my-zsh]: https://github.com/robbyrussell/oh-my-zsh
[omz-install]: https://github.com/robbyrussell/oh-my-zsh#setup
[omz-plugins]: https://github.com/robbyrussell/oh-my-zsh/tree/master/plugins
[omz-themes]: https://github.com/robbyrussell/oh-my-zsh/wiki/themes
[omz-tip]: #a-better-shell-with-oh-my-zshoh-my-zsh
[readline]: https://cnswww.cns.cwru.edu/php/chet/readline/rltop.html
[hammerspoon-tip]: #2-managing-windows-with-hammerspoon
[hammerspoon]: https://hammerspoon.org
[hammerspoon-download]: https://github.com/Hammerspoon/hammerspoon/releases
[right-thumb-tip]: #4-right-thumb-control-key
[software]: #software
[space-cadet]: http://en.wikipedia.org/wiki/Space-cadet_keyboard
[tap-parens]: http://stevelosh.com/blog/2012/10/a-modern-space-cadet/#shift-parentheses
[zsh]: http://www.zsh.org/
]]></content:encoded>
      <dc:date>2019-06-15T04:50:13-07:00</dc:date>
    </item>
    <item>
      <title>Nietzsche would write clickbait</title>
      <link>https://msol.io/blog/thoughts/nietzsche-would-write-clickbait/</link>
      <description><![CDATA[
  


]]></description>
      <pubDate>Fri, 08 Jan 2016 07:24:05 -0800</pubDate>
      <guid>https://msol.io/blog/thoughts/nietzsche-would-write-clickbait/</guid>
      <content:encoded><![CDATA[<div>
  <img class="post-image image-margins side-image" src="/img/nietzsche.jpg" width="200px">
</div>

Nietzsche's style is outrageous.

He [denies morality and immorality][dawn-103]. He criticizes popular religions like Christianity and Judaism, popular moral philosophies like utilitarianism, and popular virtues like modesty[^immodest].

His language is evocative and exaggerated. As Higgins & Solomon[^higgins-solomon] point out:

> ... it is evident that he was willing to be misunderstood if that was the price of attracting our attention.
{: .display-table}

and go on to cite Nietzsche's biblical tone in *Thus Spoke Zarathustra* among other things.

That sounds as close to clickbait as things got in the 19th century. And spreading new ideas, generating ad revenue---what's the difference, anyway?

[dawn-103]: https://www.gutenberg.org/files/39955/39955-h/39955-h.html#Sect_103

[^immodest]:
    [gutenberg.org/files/4363/4363-h/4363-h.htm](https://www.gutenberg.org/files/4363/4363-h/4363-h.htm), § 265

[^higgins-solomon]:
    p. xxv, Introduction to *Thus Spoke Zarathustra*, Barnes & Noble 2005. ISBN 978-1-59308-278-9.

    I have no relation to Robert C. Solomon.


]]></content:encoded>
      <dc:date>2016-01-08T07:24:05-08:00</dc:date>
    </item>
    <item>
      <title>Dirt-cheap client-encrypted online backups with Raspberry Pi</title>
      <link>https://msol.io/blog/tech/dirt-cheap-client-encrypted-online-backups-with-raspberry-pi/</link>
      <description><![CDATA[To be useful to me, backups must be:

]]></description>
      <pubDate>Thu, 07 Jan 2016 01:01:51 -0800</pubDate>
      <guid>https://msol.io/blog/tech/dirt-cheap-client-encrypted-online-backups-with-raspberry-pi/</guid>
      <content:encoded><![CDATA[To be useful to me, backups must be:

* Stored in a reliable and offsite location
* Readable only by me (client-side encryption)
* Cheap
* Automatic

We can achieve all of these goals with a combination of tools:

* [Duplicity][duplicity]
* [Google Nearline][nearline]
* [GPG][gpg]
* Raspberry Pi

I have been using this setup for about a year, and it costs me about $2 a month for about 100 GB of backups.

The Raspberry Pi is very useful because it uses very little power and can backup my Network Attached Storage (NAS) automatically over the network.



### Aside: backing up a computer

You should strongly consider using [Backblaze][backblaze][^bb-no-relation]. It's cheap, has no storage limit, and lets you use your own encryption key. It's going to be the simplest and most reliable bet if you only need to backup the computers you use frequently, instead of your NAS.


## Backing up your NAS, or multiple computers

There are five basic steps we need to get backups running:

1. [Set up the storage service: Google Nearline](#set-up-google-nearline)
2. [Set up the connection to the files to be backed up: sshfs](#mounting-via-ssh)
3. [Set up encryption software: GPG](#set-up-gpg-and-your-encryption-keys)
4. [Configure the backup software: Duplicity](#set-up-duplicity-and-the-backup-script-on-your-raspberry-pi)
5. [Run the backups on a schedule: cron](#scheduling-backups-with-cron)



### Set up Google Nearline

Go to the Google [Developer's Console](https://console.developers.google.com/project), and sign up as necessary. You may need to enter billing information. Create a new project on that page, perhaps called `duplicity-backups`.

Click on the `duplicity-backups` project and click the hamburger menu (three lines) button in the upper left corner and select "Storage" under "Storage." Press "Create bucket" and choose a name (perhaps "photos") and select "Nearline" for "Storage class."

The last piece needed is access credentials for this storage bucket. Press Settings on the left, then click Interoperability. Create a new key, then copy down the Access Key and Secret shown. We will use these later.


### Mounting via SSH

You will need to access the files you wish to backup (likely located on your NAS) over the network. I will assume that they are reachable via SSH. If they are not, you will need to mount them on the filesystem in a similar way (perhaps with NFS).

Run `sudo apt-get install sshfs` to make mounting drives over SSH possible.

It will be easier to connect to your NAS via SSH if you use passwordless authentication with a public/private key pair. Run `ssh-copy-id nasuser@mynashost` to copy it, substituting in your actual NAS information.

Run `mkdir ~/nas` to create a place to mount your NAS directories.

Add lines like this to `/etc/fstab` so your Raspberry Pi can treat the remote host as a drive:

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">root@mycroft:/my-nas/Photos /home/pi/nas/Photos fuse.sshfs      user,delay_connect,noauto,_netdev,uid<span class="o">=</span>1000,gid<span class="o">=</span>1000,idmap<span class="o">=</span>user,allow_other,reconnect 0 0
root@mycroft:/my-nas/write /home/pi/nas/write fuse.sshfs      user,delay_connect,noauto,_netdev,uid<span class="o">=</span>1000,gid<span class="o">=</span>1000,idmap<span class="o">=</span>user,allow_other,reconnect 0 0</code></pre></figure>

And test it with `sudo mount /home/pi/nas/Photos`, verifying that the files appear in that directory as expected.

I recommend that your create a second partition directory on your NAS (separate from that which you wish to back up) to store Duplicity's local cache and log files. Otherwise, you are likely to quickly fill your Raspberry Pi's local storage. This directory is called "write" in my examples. Run `touch /home/pi/nas/write/.useThisWriteDir` after it is mounted to use with the script below.


### Set up GPG and your encryption keys

GPG is supported by Duplicity for encryption, and provides a high level of security.

Run `sudo apt-get install gnupg`. Then run `gpg --gen-key` and follow the prompts, choosing the defaults. Be sure to choose a long (ideally random) passphrase and to write it down (preferably in a password manager). You won't be able to read your backups without the generated keys, so be sure to [back that up][back-up-gpg] as well.

We will need the fingerprint of the newly-generated key to tell Duplicity to use it. Run `gpg --fingerprint` to see it. `gpg --fingerprint | grep pub | grep -P "(?<=/)\\w{8} "` should highlight the 8-character fingerprint you require.


### Set up [Duplicity][duplicity] and the backup script on your Raspberry Pi

These instructions assume you use [Raspbian][raspbian]. They should be adaptable for use on other Linux (or Linux-like) systems.

Install duplicity by running `sudo apt-get install duplicity`.

A simple backup script is needed to store credentials and run the backup. I store it along with the files I wish to backup (Photos), but you could do something more secure instead.

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="c">#!/bin/sh</span>
<span class="c"># stored in Photos, the directory I wish to back up</span>

<span class="nb">export </span><span class="nv">SRC</span><span class="o">=</span>/home/pi/nas/Photos
<span class="nb">export </span><span class="nv">DEST</span><span class="o">=</span>gs://&lt;your Google Cloud Storage bucket name&gt;/Photos

<span class="nb">export </span><span class="nv">FTP_PASSWORD</span><span class="o">=</span><span class="s2">"&lt;password&gt;"</span>
<span class="nb">export </span><span class="nv">GS_ACCESS_KEY_ID</span><span class="o">=</span><span class="s2">"&lt;your Google access key&gt;
export GS_SECRET_ACCESS_KEY="</span>&lt;your Google secret&gt;<span class="s2">"

export KEY="</span>&lt;your GPG key fingerprint <span class="o">(</span>8 characters<span class="o">)&gt;</span><span class="s2">"
export PASSPHRASE="</span>&lt;your GPG passphrase&gt;<span class="s2">"

# Locking is handled by cron. This has helped it restart after problems.
killall duplicity
find /home/pi/nas/write/.cache/duplicity/ | grep lockfile.lock | xargs rm

# make sure we're using the right write dir.
# remote mounting issues can otherwise cause problems
if [ ! -f /home/pi/nas/write/.useThisWriteDir ]; then
  echo "</span>write directory does not appear to be mounted<span class="s2">"
  exit
fi

duplicity </span><span class="se">\</span><span class="s2">
  --sign-key </span><span class="nv">$KEY</span><span class="s2"> </span><span class="se">\</span><span class="s2">
  --encrypt-key </span><span class="nv">$KEY</span><span class="s2"> </span><span class="se">\</span><span class="s2">
  --log-file /home/pi/nas/write/duplicity.log </span><span class="se">\</span><span class="s2">
  --archive-dir /home/pi/nas/write/.cache/duplicity/ </span><span class="se">\</span><span class="s2">
  "</span><span class="nv">$SRC</span><span class="s2">" "</span><span class="nv">$DEST</span><span class="s2">" 2&gt;&amp;1 &gt;&gt; /home/pi/nas/write/duplicity-foreground.log</span></code></pre></figure>

Run the backup script on a small test directory to make sure it's all set up properly.


### Scheduling backups with cron

The last step is to run this backup automatically. Cron can do this for us, and is built-in.

We will use a [simple perl script][solo.pl] to keep things from running multiple times. Download it to `/home/pi` and make it executable with `chmod u+x /home/pi/solo.pl`.

Run `crontab -e` and add these lines:

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="c"># m h  dom mon dow   command</span>
<span class="k">*</span> <span class="k">*</span> <span class="k">*</span> <span class="k">*</span> <span class="k">*</span> <span class="nb">grep</span> <span class="nt">-qs</span> <span class="s1">'/home/pi/nas/write'</span> /proc/mounts <span class="o">||</span> /home/pi/solo.pl <span class="nt">-port</span><span class="o">=</span>3386 mount /home/pi/nas/write
<span class="k">*</span> <span class="k">*</span> <span class="k">*</span> <span class="k">*</span> <span class="k">*</span> <span class="nb">ls</span> /home/pi/nas/write <span class="o">||</span> /home/pi/solo.pl <span class="nt">-port</span><span class="o">=</span>3386 <span class="nb">sudo </span>umount <span class="nt">-f</span> <span class="nt">-l</span> /home/pi/nas/write
<span class="k">*</span> <span class="k">*</span> <span class="k">*</span> <span class="k">*</span> <span class="k">*</span> <span class="nb">grep</span> <span class="nt">-qs</span> <span class="s1">'/home/pi/nas/Photos'</span> /proc/mounts <span class="o">||</span> /home/pi/solo.pl <span class="nt">-port</span><span class="o">=</span>3385 mount /home/pi/nas/Photos
<span class="k">*</span> <span class="k">*</span> <span class="k">*</span> <span class="k">*</span> <span class="k">*</span> <span class="nb">ls</span> /home/pi/nas/Photos <span class="o">||</span> /home/pi/solo.pl <span class="nt">-port</span><span class="o">=</span>3385 <span class="nb">sudo </span>umount <span class="nt">-f</span> <span class="nt">-l</span> /home/pi/nas/Photos
<span class="k">*</span> <span class="k">*</span> <span class="k">*</span> <span class="k">*</span> <span class="k">*</span> <span class="nb">grep</span> <span class="nt">-qs</span> <span class="s1">'/home/pi/Drive'</span> /proc/mounts <span class="o">||</span> /home/pi/solo.pl <span class="nt">-port</span><span class="o">=</span>3384 mount /home/pi/Drive
<span class="k">*</span> <span class="k">*</span> <span class="k">*</span> <span class="k">*</span> <span class="k">*</span> /home/pi/solo.pl <span class="nt">-port</span><span class="o">=</span>3383 sh /home/pi/nas/Photos/backup.sh <span class="o">&gt;</span> /dev/null 2&gt;&amp;1

<span class="c"># optional: automatic reboots and software updates to keep things well-oiled</span>
0 5 <span class="k">*</span> <span class="k">*</span> <span class="k">*</span> ssh mynasuser@mynas <span class="s1">'reboot'</span>
0 5 <span class="k">*</span>/2 <span class="k">*</span> <span class="k">*</span> <span class="nb">sudo</span> /sbin/shutdown <span class="nt">-r</span> +1
0 6 <span class="k">*</span> <span class="k">*</span> <span class="k">*</span> <span class="nb">sudo </span>rpi-update
0 7 <span class="k">*</span> <span class="k">*</span> <span class="k">*</span> <span class="nb">sudo </span>apt-get update <span class="nt">-y</span> <span class="o">&amp;&amp;</span> <span class="nb">sudo </span>apt-get upgrade <span class="nt">-y</span>
0 10 <span class="k">*</span> <span class="k">*</span> <span class="k">*</span> <span class="nb">sudo </span>apt-get autoremove <span class="nt">-y</span> <span class="o">&amp;&amp;</span> <span class="nb">sudo </span>apt-get autoclean <span class="nt">-y</span> <span class="o">&amp;&amp;</span> <span class="nb">sudo </span>apt-get clean <span class="nt">-y</span></code></pre></figure>

This will start a new backup as soon as the last completes. This works well for my use case, adjust as necessary.

Be sure to test your backups to ensure you can restore in a disaster! `duplicity verify` may help you here.


## Future improvements

This could be improved with emails about failed backups, or when backups haven't run for some time. The overall process could also be simpler. Ideas? Let me know in the comments and I can update the article with them!

[back-up-gpg]: /blog/tech/back-up-your-pgp-keys-with-gpg/
[backblaze]: https://www.backblaze.com
[duplicity]: http://duplicity.nongnu.org/
[gpg]: https://www.gnupg.org/
[nearline]: https://cloud.google.com/storage/docs/nearline
[raspbian]: https://www.raspbian.org/
[solo.pl]: https://timkay.com/solo/

[^bb-no-relation]:
    I have no affiliation with Backblaze.
]]></content:encoded>
      <dc:date>2016-01-07T01:01:51-08:00</dc:date>
    </item>
    <item>
      <title>Pro-style testing</title>
      <link>https://msol.io/blog/tech/pro-style-testing/</link>
      <description><![CDATA[If you write software professionally, you probably write automated tests. This is fantastic.

]]></description>
      <pubDate>Sat, 10 Oct 2015 09:47:07 -0700</pubDate>
      <guid>https://msol.io/blog/tech/pro-style-testing/</guid>
      <content:encoded><![CDATA[If you write software professionally, you probably write automated tests. This is fantastic.

But have you ever thought about how to leverage the experiences of other software engineers to:

1. Write tests that are maximally likely to prevent bugs
2. Write tests that make locating and fixing the cause of a bug easy
3. Write as few (and as short and readable) tests as possible while achieving the above

Below are general guidelines to build a mental framework of what, how, and why to test in any language. There are also specific and hard-earned recommendations for and against a variety of possible testing strategies. Most recommendations come with links to more reading.

If you want to test like a pro, read on. If you disagree with a recommendation or would like elaboration, leave a comment or send me an email. There is always room to improve.


# Table of Contents

* TOC
{:toc}


# Terminology

Language around automated testing is often ambiguous and overloaded. I will use these terms:


## Test sizes


Terms like "unit test" and "integration test" can mean different things to different people, so we will use test sizes [as defined by Google](http://googletesting.blogspot.com/2010/12/test-sizes.html), recapped here:


* __Small__: Usually called unit tests, Small tests are each extremely narrow in scope, run quickly, and test behavior in isolation.
* __Medium__: Sometimes called integration tests, Medium tests check interactions between layers and components.
* __Large__: Also called end-to-end or system tests, Large tests are very coarse-grained and often touch many components and make use of the network.


Related reading:

* [Google definitions](http://googletesting.blogspot.com/2010/12/test-sizes.html)
* [from StackOverflow](http://stackoverflow.com/a/4904533)



## Properties of tests

* __Fidelity__: A high­-fidelity test is sensitive to defects in the code under test: the test fails when the code is broken.
* __Resilience__: A resilient test fails *only* when the code under test is broken--refactoring won't break it, and it is not flaky.
* __Precision__: A high-precision test tells you where the defect is. Ideally the exact line number and what differed from our expectations.


# General principles to follow


## Test one behavior per test

Each test should test one behavior. Many of your methods will have one behavior, so verify that behavior and as little else as possible (often nothing!). Asserting runtime invariants is okay, but usually there should be few assertions other than the primary expected behavior.

* [Test Behavior, Not Implementation](http://googletesting.blogspot.com/2013/08/testing-on-toilet-test-behavior-not.html)
* [Test Behaviors, Not Methods](http://googletesting.blogspot.com/2014/04/testing-on-toilet-test-behaviors-not.html)


## Test each behavior once

Testing the same thing more than once is a maintenance burden. Obviously you should not test the same behavior with two separate tests, but sometimes it is tempting to "cross-test" by adding an extra assertion in a related test. Avoid this, because it decreases the Precision when the test fails, and because it violates "Test one behavior per test."

* [Too Many Tests](http://googletesting.blogspot.com/2008/02/in-movie-amadeus-austrian-emperor.html)


## Write tests that provide value by reducing risk

*A test should reduce risk*, or it is not providing any value.

One way to check this is to ask "what class of bug could this test detect?" If there is no answer, there should be no test. You can rephrase as "what risk does this test help us avoid?", and if there is no answer, you need no test.

It works the other way too: think of what the risks (possible classes of bugs) are, and write the appropriate tests to detect them.

One case that obviously provides value is a regression test: you've encountered a bug before, so it's important to have a test to prevent it from reappearing in the future.

* [Risk-Driven Testing](http://googletesting.blogspot.com/2014/05/testing-on-toilet-risk-driven-testing.html)
* [Naming Unit Tests Responsibly](http://googletesting.blogspot.com/2007/02/tott-naming-unit-tests-responsibly.html)


## Name tests to describe the behavior precisely

Test names appear in test failures and in the code itself. If the names precisely describe the behavior being tested, readers do not need to read the test to understand what cases are covered and which aren't, and failures become easier to debug and fix.

Tests are often a good way to learn how an interface works, and clear test names can be useful to demonstrate an interface.

* [Writing Descriptive Test Names](http://googletesting.blogspot.com/2014/10/testing-on-toilet-writing-descriptive.html)


## Rework code until it is easy to test

You must test your code, so your code must be easy to test. If you write your code before your tests without keeping this in mind, you may not notice until you begin writing tests. When this happens, consider reworking your code to be more testable.

If your test is long, your code may need to change to improve testability.

These strategies can make your code more testable:

* Ensure your methods, classes, and modules each have only [one concern](http://programmers.stackexchange.com/a/32614), [one job](http://blog.codinghorror.com/curlys-law-do-one-thing/), one [reason to change](http://butunclebob.com/ArticleS.UncleBob.SrpInRuby). Each should deal with one thin layer only, and rely on other methods/classes/modules to deal with other layers.
* Reduce the number of dependencies. Are you sure the code under test has only has one reason to change?
* Use [dependency injection](http://stackoverflow.com/a/140655)
* [Avoid static methods](http://googletesting.blogspot.com/2008/12/static-methods-are-death-to-testability.html) (in Scala, look for companion objects and other objects)
* [Avoid singletons](http://googletesting.blogspot.com/2008/05/tott-using-dependancy-injection-to.html) (in Scala, look for companion objects and other objects)
* Wrap unavoidable singletons or static methods (such as those provided by a library) in a simple class that can be injected as a dependency
* [Inject small, single purpose methods that encapsulate dependencies](http://engineering.monsanto.com/2015/07/28/avoiding-mocks/)--these are easy to test, and prevent overreliance on mocking


## Watch it fail

It's tempting to write a test, see that it passes, and move on. But what if you made a mistake in your test? You probably don't have tests for your test, so instead, break your code in a way the test should detect, *and run it*.

This avoids two classes of bugs:

1. Your test won't detect the bug you thought it would (low Fidelity)
2. Your tests aren't actually being run (it happens)


## Tests should use literals where possible

In production code, deduplication and flexibility are very important. Surprisingly, in tests, it is often better to duplicate and inline simple values and literals to reduce the likelihood of mistakes and to improve the direct readability of the test. Simple immutable objects shared across tests are also acceptable.

For example, URLs strings should be literal values in tests instead of being constructed as URL objects. This sort of duplication is more readable, simpler, and less error prone. In exchange, it is very inflexible--but this is a better tradeoff in a test.

See [Don't put logic in tests](http://googletesting.blogspot.com/2014/07/testing-on-toilet-dont-put-logic-in.html)

This does not apply as much to property checks, which should use generators where possible.


## Leverage the type system

Careful use of statically type-checked languages render entire classes of Small tests unnecessary because the type checker can enforce certain guarantees. Availability of static typing features vary by language; make use of those that are available, and consider this when choosing a new language.

Carefully choose the types of primitives so they enforce as many guarantees as possible. For instance, prefer an unsigned integer over a signed integer when a value cannot be negative; this eliminates the need for one test. This principle applies similarly to objects and other derived types. Consider introducing new types that can only be constructed with guarantees that will later be relied upon, this removes the need for checking these guarantees in the code relying on them. Consider refining interfaces to accept only values maximally verified by the type system.

* [A unit tester walks into a bar](https://www.reddit.com/r/programming/comments/3myc9b/insider_oracle_has_lost_interest_in_java/cvjsoua)


# Mistakes to avoid


## Don't write change-detector tests

One way to test code is to duplicate some of the logic you are trying to test in the test itself, then assert that the results are equal.

This only detects when your code changes, and cannot catch any bugs apart from "the code changed." Such a test has low Fidelity and low Resilience. Such a test is a maintenance burden. Rewrite or delete.

One common form of change-detection is a test that checks each step of the implementation. Test behavior instead.

A very specific type of test that looks like (but is not) a useless change-detector can provide refactor/optimization safety (yet no value up until then): a test that reimplements the code under test and compares the outputs. This verifies that the underlying behavior has not changed. This type of test is easy to misapply. It is insufficient on its own. Prefer other types of tests when possible, perhaps simple property checks.

* [Change-Detector Tests Considered Harmful](http://googletesting.blogspot.com/2015/01/testing-on-toilet-change-detector-tests.html)


## Don't test code you don't own in Small or Medium tests

Tests should live in the same project as the code that they test, and should be maintained by the same people. This gives the owners freedom to refactor and make bug fixes as needed, provided their tests still pass. This lets the people best suited to test and maintain test code do so. This reduces your own maintenance burden. Note that it makes sense to test Adapter or other code that wraps a dependency.

Most dependencies will be services or libraries. If you do not trust a dependency, consider contributing new tests to cover the cases they do not. If you still don't trust a dependency, consider removing or replacing it. If you cannot contribute to a dependency directly, consider maintaining a patch, or if necessary, consider a fork. If you have a binary or service dependency that you cannot contribute to, eliminate, or trust, consider writing a **separate** suite of tests to ensure it works as you expect. In *no case* should you test an external dependency as a side effect of testing your own code in a Small or Medium test.

Large tests may implicitly test external dependencies; this is to be expected. Even so, they should not *explicitly* test external dependencies beyond, say, setting up connections.


# Red flags and code smells

* Long tests. Tests should generally be short and easy to follow. Arrange, act, assert (see AAA below)
* [Sleeping](http://googletesting.blogspot.com/2008/08/tott-sleeping-synchronization.html) (Thread.sleep, Future.sleep, sleep(), etc.). There are very few places this is actually what you want.
* [Many mocks](http://googletesting.blogspot.com/2013/05/testing-on-toilet-dont-overuse-mocks.html) (specifically mocking, not other test doubles). You may be testing the implementation too closely. The code under test may have too many dependencies, and it may have more than one concern.
* The test [generates](http://googletesting.blogspot.com/2014/07/testing-on-toilet-dont-put-logic-in.html) nontrivial data. There may be bugs in the data generation code. Consider separating it out and testing it. Consider using a property check, which can help make this reusable. Consider breaking the code under test into multiple methods which can be tested on simpler data.
* Tests with logic that also appears in the code under test. Is this a change-detector test?


# Concrete tips


Hat-tip to [Ryan Greenberg](https://twitter.com/greenberg), from whom I stole most of this section.


## AAA test structure

Many tests are easy to read if they are in the form: Arrange, Act, Assert. First Arrange the required objects, perform the Act you want to test, then Assert the results are as expected.


## Write the assertion first

Think of test cases in terms of properties that must be true, then assert them. It may be easier to think of the assertion first, then write code to arrange objects and act on them.


## Write exactly one test for each equivalence class

For example, if the code is intended to work the same on any number of items in a sequence, you don't need a test for 2 items, 3 items, and 4 items.


## When testing state changes, assert before as well as after

For example, if a method should increment a counter, assert that the counter value starts at what you expect before calling the method. This avoids certain bugs in tests.


## Only control direct dependencies, not dependencies of dependencies

Only set up and rely on direct dependencies of what you are testing (possibly using a [test double](http://googletesting.blogspot.com/2013/07/testing-on-toilet-know-your-test-doubles.html) such as a stub, mock or fake), never dependencies of dependencies.

For example, imagine:

* We have a request handler `logValidRequests` that validates a request `req` by calling `validate(req)` and then logs `req`
* `logValidRequests` won't log `req` when `validate` returns `false`
* One way `req` can be invalid is if it is all lowercase

You should *not* write your test by calling `logValidRequests` with an all-lowercase `req`. Instead, stub `validate` to return `false`, then assert that nothing is logged (and don't forget other test cases!). This improves Resilience and Precision.


## Assert on boundaries for functions accepting a contiguous range of inputs

`def isBig(num: Long) = num > 100`

You should test 100, but also 99 because it is at the boundary of the change. Even better, write a property test. Remember to test each equivalence class exactly once.


# More about testing


## Property-based tests

Property-based tests (also called property checks) are a different way to think about testing. The basic idea is to assert that some law holds about the code under test, and then let the test framework generate test cases in an attempt to disprove the law. When it does so, it will try to find a minimal failing case to help you find your bug.

It is worth writing property checks if you can, despite the initial learning curve. They allow you to declare laws and let the computer worry about coming up with cases that are likely to fail. They encourage writing reusable Generators that improve readability and reuse.

Property-based tests are most useful in unit tests.

In Scala there is [ScalaCheck](https://www.scalacheck.org/) and more can be found online.


## Large tests

Large tests are your last line of defense before production (or "reported by users"). Not all tests are equally useful at this level.

Test "happy path" behavior. This makes sure that the system works end-to-end in the real environment. Depending on your setup, you may be able to run this in a staging environment as well as the production environment.

Test for regressions in known high-level bugs. If you can write a Small or Medium test for this, prefer that instead. However, make sure each regression gets a test, and sometimes this means a Large test.

Don't attempt to test every way in which your system can fail. For example, if you have a suite of validations that are already tested in Small tests, do not repeat every test at the Large (or Medium) level. Instead, test one representative validation to ensure that the validations are wired in. Even better, test at the Medium level.


## Refactoring tests

It can be hard to refactor your tests, because unlike your production code, you don't have tests (for your tests).

One good strategy is to refactor your test code after manually (and temporarily) breaking the production code. This gives you some confidence that your tests fail when they ought to fail (showing their level of Fidelity).

* [Refactoring tests in the red](http://googletesting.blogspot.com/2007/04/tott-refactoring-tests-in-red.html)


# Reading and resources


## More terminology


### Box colors

* __Black box__: Knows nothing of internals--testing the interface's contract, not implementation
* __White box__: Testing the internals--testing the implementation, not the interface
* __Grey box__: Testing interface's contract as in black box, but sets up state beforehand with knowledge of internals


### Subtypes of tests

* __Regression__: did a bug we fixed reappear?
* __Performance__: how fast is the code? is it fast enough?
* __Security/Privacy__: will this leak data or allow unwanted access?
* __Code quality__: does the code meet standards we can automatically (statically) measure?
* __Acceptance__: Does it conform to specifications?
* __Stress__: How does it handle being put under increasing loads, up to failure?


## Good resources

* Google's [Testing Blog](http://googletesting.blogspot.com/), including [Testing on the Toilet](http://googletesting.blogspot.com/search/label/TotT)
* *Clean Code* by Robert C. Martin
* [Writing testable code](http://misko.hevery.com/code-reviewers-guide/)


## Short but valuable reading

* [What makes a good test?](http://googletesting.blogspot.com/2014/03/testing-on-toilet-what-makes-good-test.html)
* [Test behavior, not implementation](http://googletesting.blogspot.com/2013/08/testing-on-toilet-test-behavior-not.html)
* [Risk-driven testing](http://googletesting.blogspot.com/2014/05/testing-on-toilet-risk-driven-testing.html)
* [Effective testing](http://googletesting.blogspot.com/2014/05/testing-on-toilet-effective-testing.html)
* [Know your test doubles](http://googletesting.blogspot.com/2013/07/testing-on-toilet-know-your-test-doubles.html)
* [Testing state vs. testing interactions](http://googletesting.blogspot.com/2013/03/testing-on-toilet-testing-state-vs.html)
]]></content:encoded>
      <dc:date>2015-10-10T09:47:07-07:00</dc:date>
    </item>
    <item>
      <title>You're probably wrong about caching</title>
      <link>https://msol.io/blog/tech/youre-probably-wrong-about-caching/</link>
      <description><![CDATA[
  There are only two hard things in Computer Science: cache invalidation and naming things –Phil Karlton


]]></description>
      <pubDate>Sat, 05 Sep 2015 05:22:40 -0700</pubDate>
      <guid>https://msol.io/blog/tech/youre-probably-wrong-about-caching/</guid>
      <content:encoded><![CDATA[  > There are only two hard things in Computer Science: cache invalidation and naming things --Phil Karlton

Caching is a great tool. Lots of useful data fits easily in memory--so cache it! Improve your latencies, ease the load on your database, reduce your hardware costs! Can you spell free lunch?

Many of the costs of caching aren't paid up-front. This makes caching seem very attractive--and to be clear, there are many situations where caching your data is a great option--but if you're just looking to pick up some "quick wins," caching is a bad place to start.

I believe we, as software developers, have a very strong tendency to underestimate the complexities and issues caching brings along with it, *especially* when we look at oh-so-seductive early results of exploratory caching atop our data sources. In turn, I believe we often cache before the benefits actually outweigh the costs.

## Fine, why do you think caching is so hard?

I'm glad you asked.

### Reasoning about cached data is harder

Caching fundamentally means that you no longer read from your source of truth. Whenever you see something unexpected in your data (say, while debugging during an incident), you now must ask "does this data match our source of truth?" Every read or write to a piece of cached data is subject to mismatch with the source of truth and this must often be taken into account when tracking down issues.

### A new class of perspective bugs are possible with cached data

Not all data appears in the same way to all users. For example, a list of "Best Articles" on a news site might depend on which user is logged in. A classic caching mistake is caching these perspective-dependent values and serving them to users who should have a different perspective. This is avoidable enough once, but is easy to mistakenly introduce later on. This can lead to serious privacy or even security issues.

### Reproducing behavior involving caching is harder

When you introduce caching, you also introduce a new layer in which behavior can differ from your expectations. New race conditions are possible where they weren't before: items can expire from the cache when you don't expect them to, which objects are cached depends on access patterns that can vary by time of day or other factors. This means that issues can appear, but it is not obvious how to reproduce them to assist in fixing them.

### Access pattern changes can subtly lower cache hit rates which damages performance

When access patterns change, so can performance. A special case of this can occur when data is fronted by a cache and access patterns change. As cache misses increase, latency increases and throughput can drop. However, traffic levels may stay the same, masking the cause, and potentially overloading the underlying data source. Like any issue, this can be dealt with, but it makes dealing with certain incidents more difficult.

### In-process caching in garbage-collected languages increases GC pressure[^gc-pressure]

This only applies to certain scenarios, like in-process caches on the JVM, but it serves as another example of how caching can introduce unexpected issues. In this case, large numbers of long-lived cached objects can get promoted into older generations of the garbage collector and increase both the run time of individual collections and the frequency at which they must happen.

### Recovering from a failed cache is hard

Caches can let you scale up your serving capacity past what your underlying data source could serve alone, which is one reason to cache. Unfortunately, when your cache machines go down (or are unreachable on the network, or unresponsive, or...) you cannot simply bring them back online, as all data stored in memory will already be lost. You must warm your caches by reading from the underlying store while still trying to serve production traffic. Often your only choice will be to deny all but a fraction of traffic, slowly ramping up the amount you serve as your caches warm.


## Is it worth it?

It depends; the tradeoffs are yours to choose between.

But before you choose, consider that many of the downsides won't manifest themselves right away. Don't forget how easy it is to ignore these downsides and focus only on the benefits--the payoff is immediate, but the costs must be paid constantly throughout the cache's lifetime.


[^gc-pressure]:
    Garbage collector (GC) pressure happens when your application (running on the JVM, CLR, V8, and other garbage-collected runtimes) allocates then releases memory for many objects. The runtime must occasionally collect this garbage by walking through your memory graph to determine which objects are still needed, and which can be freed.

    When your application produces and discards many objects in a short amount of time--say, from an in-memory cache--the garbage collector needs to interrupt your running code and collect dead objects more frequently, and each collection can take longer.
]]></content:encoded>
      <dc:date>2015-09-05T05:22:40-07:00</dc:date>
    </item>
    <item>
      <title>Ruby on Rails: Don't delete, tombstone</title>
      <link>https://msol.io/blog/tech/ruby-on-rails-dont-delete-tombstone/</link>
      <description><![CDATA[In many web apps, things need to be deleted (no way!). But actually deleting records from your database has some side effects that aren’t immediately obvious:

]]></description>
      <pubDate>Tue, 18 Aug 2015 11:32:38 -0700</pubDate>
      <guid>https://msol.io/blog/tech/ruby-on-rails-dont-delete-tombstone/</guid>
      <content:encoded><![CDATA[In many web apps, things need to be deleted (no way!). But actually deleting records from your database has some side effects that aren't immediately obvious:

* Undelete isn't possible without additional work
* In small, simple apps, you may not have any other record of deleted rows
* You may be able to improve your product based on what has been deleted
* Extra work is required to "reactivate" deleted users or other models with their former data attached

One easy way to deal with this is with __tombstones__. A tombstone is simply a column in a table that marks whether a given record has been deleted.

This means that nearly all queries will need to filter based on this column to make sure it isn't reading "deleted" (tombstoned) data. How annoying!

Fortunately, in Rails it is easy to separate out this concern. We can define a mixin called `tombstoneable` such that any ActiveRecord model that mixes it in will automatically filter out deleted records by default, and add some easy methods to query for tombstoned records as well.


## Make it work

Create a new file `lib/mixins/tombstoneable.rb`:

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="k">module</span> <span class="nn">Mixins::Tombstoneable</span>
  <span class="kp">extend</span> <span class="no">ActiveSupport</span><span class="o">::</span><span class="no">Concern</span>

  <span class="n">included</span> <span class="k">do</span>
    <span class="n">default_scope</span> <span class="p">{</span> <span class="n">where</span><span class="p">(</span><span class="ss">deleted: </span><span class="kp">false</span><span class="p">)</span> <span class="p">}</span>
    <span class="n">scope</span> <span class="ss">:include_deleted</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="p">{</span> <span class="n">unscope</span><span class="p">(</span><span class="ss">where: :deleted</span><span class="p">)</span> <span class="p">}</span>
    <span class="n">scope</span> <span class="ss">:deleted</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="p">{</span> <span class="n">include_deleted</span><span class="p">.</span><span class="nf">where</span><span class="p">(</span><span class="ss">deleted: </span><span class="kp">true</span><span class="p">)</span> <span class="p">}</span>
  <span class="k">end</span>

  <span class="k">def</span> <span class="nf">destroy</span>
    <span class="n">update_attribute</span><span class="p">(</span><span class="ss">:deleted</span><span class="p">,</span> <span class="kp">true</span><span class="p">)</span>
  <span class="k">end</span>

  <span class="k">def</span> <span class="nf">delete</span>
    <span class="n">destroy</span>
  <span class="k">end</span>

  <span class="k">def</span> <span class="nf">undelete</span>
    <span class="n">assign_attributes</span><span class="p">(</span><span class="ss">deleted: </span><span class="kp">false</span><span class="p">)</span>
  <span class="k">end</span>

  <span class="k">def</span> <span class="nf">undelete!</span>
    <span class="n">update_attribute</span><span class="p">(</span><span class="ss">:deleted</span><span class="p">,</span> <span class="kp">false</span><span class="p">)</span>
  <span class="k">end</span>
<span class="k">end</span></code></pre></figure>

Nice! The magic is in the `included` block. We augment the default scope to always look for records that have not been deleted. If we wish to include deleted records as well, we can use the `include_deleted` scope:

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="no">User</span><span class="p">.</span><span class="nf">include_deleted</span><span class="p">.</span><span class="nf">find</span><span class="p">(</span><span class="o">...</span><span class="p">)</span></code></pre></figure>

Or if we wish to only select deleted (tombstoned) edges, we can do that too:

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="no">User</span><span class="p">.</span><span class="nf">deleted</span><span class="p">.</span><span class="nf">find</span><span class="p">(</span><span class="o">...</span><span class="p">)</span></code></pre></figure>


## Now mix it in

We never finished actually mixing this in to a model. Let's assume we have a model called User. Only one line is needed to mix in the tombstoning behavior:

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="k">class</span> <span class="nc">User</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">Mixins</span><span class="o">::</span><span class="no">Tombstoneable</span>
  <span class="o">...</span></code></pre></figure>


## And add the column

We also need to make sure the database has a column to track which records have been deleted. This will be necessary for each model we wish to make tombstonable. From the command line:

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">rails g migration AddDeletedToUser deleted:boolean</code></pre></figure>

Then modify the generated file to add a default and make the column `NOT NULL`:

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="k">class</span> <span class="nc">AddDeletedToUser</span> <span class="o">&lt;</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Migration</span>
  <span class="k">def</span> <span class="nf">change</span>
    <span class="n">add_column</span> <span class="ss">:users</span><span class="p">,</span> <span class="ss">:deleted</span><span class="p">,</span> <span class="ss">:boolean</span><span class="p">,</span> <span class="ss">null: </span><span class="kp">false</span><span class="p">,</span> <span class="ss">default: </span><span class="kp">false</span>
  <span class="k">end</span>
<span class="k">end</span></code></pre></figure>

And run the migration:

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">rake db:migrate</code></pre></figure>


## That's it!

I have found this to be a useful practice. Let me know how your experiences go (or have gone previously) in the comments. Enjoy your not-quite-deleted records!
]]></content:encoded>
      <dc:date>2015-08-18T11:32:38-07:00</dc:date>
    </item>
    <item>
      <title>How I doubled my Internet speed with OpenWRT</title>
      <link>https://msol.io/blog/tech/how-i-doubled-my-internet-speed-with-openwrt/</link>
      <description><![CDATA[OpenWRT is a powerful Linux distribution for embedded devices, such as my router, and this is the story of how I used it to double my bandwidth at no extra cost to myself.

]]></description>
      <pubDate>Tue, 10 Mar 2015 15:09:10 -0700</pubDate>
      <guid>https://msol.io/blog/tech/how-i-doubled-my-internet-speed-with-openwrt/</guid>
      <content:encoded><![CDATA[[OpenWRT][openwrt] is a powerful Linux distribution for embedded devices, such as [my router][router], and this is the story of how I used it to double my bandwidth at no extra cost to myself.

How? By doubling the number of Internet connections I have.

## My setup

### My internet

My internet is through Comcast (unfortunately).

Comcast has an initiative called Xfinity WiFi.
When you rent a cable modem/router combo from Comcast (as one of my nearby neighbors apparently does), in addition to broadcasting your own WiFi network, it is kind enough to also broadcast "xfinitywifi," a second "hotspot" network metered separately from your own.

This hotspot allows Comcast customers to connect with their credentials.


### My router

My router is a [Buffalo WZR-HP-AG300H][router].
Crucially, this router 1) supports OpenWRT and 2) has two independent radios.
I use one of them for my home WiFi network.

### My idea

By now, you've probably put two and two together.

I use my router's extra radio to connect to the xfinitywifi hotspot, then load balance my outbound traffic across the connection I pay for and the bonus xfinitywifi connection.

Obviously this is a pretty specific scenario, but if you have:

1. A hotspot you have credentials for within range
1. A router that supports both OpenWRT
1. That same router has a spare radio


## How to set this up

### 1. Install OpenWRT

Find your router on OpenWRT's [table of hardware][hardware] and follow the instructions to install it, getting your WiFi and network set up as usual.

### 2. Install multi-wan software in OpenWRT

Open your router's web interface and navigate to `/cgi-bin/luci/admin/system/packages` and install `luci-app-mwan3`.
This (along with its dependencies) allows you to support multiple internet connections with round-robin load balancing between them (with connection pinning for HTTPS).

### 3. Authenticate a MAC address with xfinitywifi

The xfinitywifi hotspot requires authentication, not via WPA2 or other normal network security, but with a Comcast login.
It remembers this login by way of your MAC address.
Unfortunately, it is not very easy to authenticate directly through the router, so instead we will authenticate a MAC address through a computer, then switch the apparent MAC address the router uses.

1. Generate a fake MAC address. Here's one: `02:67:1c:16:1f:21`
1. [Spoof your MAC address][spoof] (for your wireless adapter) on your computer.
Be sure to find out how to do it on your Linux/Mac/Windows system. Remember to record your old MAC address.
1. With your MAC address spoofed, connect to xfinitywifi and enter your Comcast credentials
1. Disconnect from xfinitywifi and restore your original MAC address

### 4. Connect the router to xfinitywifi

In your OpenWRT web (LuCI) interface at `/cgi-bin/luci/admin/network/wireless`, press Scan on your available radio, and select Join Network for `xfinitywifi`.
Name it `wan2` and add it to the `wan` firewall group.
Save & Apply your settings.

Now, go to `/cgi-bin/luci/admin/network/network/wan2` and go to the Advanced Settings tab.
Paste your fake and authenticated MAC address into the "Override MAC address" field.
Save & Apply your settings.

### 5. Prepare mwan3 for a wireless WAN

In your OpenWRT web (LuCI) interface at `cgi-bin/luci/admin/network/network/wan/`, click the Advanced Settings tab and enter 10 under Use gateway metric and Save your settings.

At `cgi-bin/luci/admin/network/network/wan2/`, click the Advanced Settings tab and enter 20 under Use gateway metric and Save your settings.

In your OpenWRT web (LuCI) interface at `/cgi-bin/luci/admin/network/mwan/advanced/networkconfig`, you will see your network config file.
Paste this section at the bottom, adjusting as necessary with settings from your xfinitywifi connection:

<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="n">config</span> <span class="n">route</span> <span class="s">'default_wan2'</span>
  <span class="n">option</span> <span class="n">interface</span> <span class="s">'wan2'</span>
  <span class="n">option</span> <span class="n">target</span> <span class="s">'0.0.0.0'</span>
  <span class="n">option</span> <span class="n">netmask</span> <span class="s">'0.0.0.0'</span>
  <span class="n">option</span> <span class="n">gateway</span> <span class="s">'192.168.1.1'</span>
  <span class="n">option</span> <span class="n">metric</span> <span class="s">'20'</span></code></pre></figure>

Normally this last step is not necessary, but for some reason mwan3 seems to need it to work with wireless networks.

Submit your changes.


## Check it!

Go to `cgi-bin/luci/admin/network/mwan` and you should see both networks green!

At least you will if you're the luckiest person ever.
More likely you'll run into problems, check out the [mwan docs][mwan3] and Google around.

Another good test is to a website that [tells you your IP][my-ip] and refresh several times and ensure you see two different IP addresses.

Good luck!


[openwrt]: https://openwrt.org/
[router]: https://wiki.openwrt.org/toh/buffalo/wzr-hp-ag300h/
[hardware]: https://wiki.openwrt.org/toh/start
[spoof]: https://www.google.com/webhp?q=how%20to%20spoof%20mac%20address#q=how+to+spoof+mac+address&qscrl=1
[mwan3]: https://wiki.openwrt.org/doc/howto/mwan3
[my-ip]: https://duckduckgo.com/?q=what+is+my+ip
]]></content:encoded>
      <dc:date>2015-03-10T15:09:10-07:00</dc:date>
    </item>
    <item>
      <title>Keybearer: Decrypt a secret using M of N keys</title>
      <link>https://msol.io/blog/tech/keybearer-decrypt-a-secret-using-m-of-n-keys/</link>
      <description><![CDATA[Keybearer uses several independent passwords to encrypt a file and later requires a subset of those passwords to decrypt it.

]]></description>
      <pubDate>Sat, 07 Mar 2015 09:02:56 -0800</pubDate>
      <guid>https://msol.io/blog/tech/keybearer-decrypt-a-secret-using-m-of-n-keys/</guid>
      <content:encoded><![CDATA[Keybearer uses several independent passwords to encrypt a file and later requires a subset of those passwords to decrypt it.

All operation are performed in client-side Javascript, so you can [try it live right now][kb].


## Example

For example, Magician Mike uses Keybearer to encrypt the password to his laptop containing his secret repertoire of tricks. He gives the 3 passcodes he used to his estranged siblings Alice, Bob, and Charlie, on the condition that at least 2 of them reunite on his death to gaze on the majesty of his secrets.

After Magician Mike is tragically sawed in half by his careless assistant, Alice and Bob meet to decrypt Mike's files using their passcodes. They are reunited through their Keybearer experience, while Charlie maintains his grudge and burns his passcode with fire.


## More on GitHub

Keybearer is open source, so feel free to [fork it on GitHub][gh-kb]!


## Disclaimer

I am not responsible for anything bad that results from the use of this software, nor am I liable: use this software at your own risk. **In no circumstances should you rely on this to protect you or your data**. This is a proof of concept created by someone with no security expertise.

[kb]: /keybearer/
[gh-kb]: https://github.com/msolomon/keybearer
]]></content:encoded>
      <dc:date>2015-03-07T09:02:56-08:00</dc:date>
    </item>
    <item>
      <title>Host your own web fonts</title>
      <link>https://msol.io/blog/tech/host-your-own-web-fonts/</link>
      <description><![CDATA[Web fonts are very popular these days, and sites like Google Fonts and Typekit make it very easy to use them on your website.

]]></description>
      <pubDate>Sat, 07 Mar 2015 04:45:10 -0800</pubDate>
      <guid>https://msol.io/blog/tech/host-your-own-web-fonts/</guid>
      <content:encoded><![CDATA[Web fonts are very popular these days, and sites like [Google Fonts][gfonts] and [Typekit][typekit] make it very easy to use them on your website.

Hosting them yourself is also pretty easy.
I recently moved away from Google Fonts for this site using this same process.


## Selecting a font

First, you must select a font.
Be sure that the license you have allows you to host it on the web.
We will use [Lato][lato], which is also [available][gfonts-lato] on Google Fonts.


## Making the font available for use

Let's say we want to use Lato and allow for bold, italic, and italic bold.
This is how we would make the font accessible from CSS using Google Fonts:

<figure class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;link</span>
  <span class="na">href=</span><span class="s">'//fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic'</span>
  <span class="na">rel=</span><span class="s">'stylesheet'</span>
  <span class="na">type=</span><span class="s">'text/css'</span><span class="nt">&gt;</span></code></pre></figure>

To self-host, the process is slightly different.
First, we must download the files and put them in a folder, such as `fonts`.

Ideally we want to have each font variant (regular, bold, italic, bold + italic) in three formats: `.woff` for modern browsers, `.eot` for old Internet Explorer, and `.ttf` for other browsers. Font Squirrel has an [online tool][webfont-generator] to convert easily between them if you're missing any.

Now it's just a matter of some simple CSS:

<figure class="highlight"><pre><code class="language-css" data-lang="css"><span class="c">/* Normal */</span>
<span class="k">@font-face</span> <span class="p">{</span>
    <span class="nl">font-family</span><span class="p">:</span> <span class="s2">'Lato'</span><span class="p">;</span>
    <span class="nl">src</span><span class="p">:</span> <span class="sx">url('fonts/Lato-Regular.eot')</span><span class="p">;</span>
    <span class="nl">src</span><span class="p">:</span> <span class="sx">url('fonts/Lato-Regular.eot?#iefix')</span> <span class="n">format</span><span class="p">(</span><span class="s2">'embedded-opentype'</span><span class="p">),</span>
         <span class="sx">url('fonts/Lato-Regular.woff')</span> <span class="n">format</span><span class="p">(</span><span class="s2">'woff'</span><span class="p">),</span>
         <span class="sx">url('fonts/Lato-Regular.ttf')</span> <span class="n">format</span><span class="p">(</span><span class="s2">'truetype'</span><span class="p">);</span>
    <span class="nl">font-style</span><span class="p">:</span> <span class="nb">normal</span><span class="p">;</span>
    <span class="nl">font-weight</span><span class="p">:</span> <span class="nb">normal</span><span class="p">;</span>
    <span class="nl">text-rendering</span><span class="p">:</span> <span class="n">optimizeLegibility</span><span class="p">;</span>
<span class="p">}</span>

<span class="c">/* Italic */</span>
<span class="k">@font-face</span> <span class="p">{</span>
    <span class="nl">font-family</span><span class="p">:</span> <span class="s2">'Lato'</span><span class="p">;</span>
    <span class="nl">src</span><span class="p">:</span> <span class="sx">url('fonts/Lato-Italic.eot')</span><span class="p">;</span>
    <span class="nl">src</span><span class="p">:</span> <span class="sx">url('fonts/Lato-Italic.eot?#iefix')</span> <span class="n">format</span><span class="p">(</span><span class="s2">'embedded-opentype'</span><span class="p">),</span>
         <span class="sx">url('fonts/Lato-Italic.woff')</span> <span class="n">format</span><span class="p">(</span><span class="s2">'woff'</span><span class="p">),</span>
         <span class="sx">url('fonts/Lato-Italic.ttf')</span> <span class="n">format</span><span class="p">(</span><span class="s2">'truetype'</span><span class="p">);</span>
    <span class="nl">font-style</span><span class="p">:</span> <span class="nb">italic</span><span class="p">;</span>
    <span class="nl">font-weight</span><span class="p">:</span> <span class="nb">normal</span><span class="p">;</span>
    <span class="nl">text-rendering</span><span class="p">:</span> <span class="n">optimizeLegibility</span><span class="p">;</span>
<span class="p">}</span>

<span class="c">/* Bold */</span>
<span class="k">@font-face</span> <span class="p">{</span>
    <span class="nl">font-family</span><span class="p">:</span> <span class="s2">'Lato'</span><span class="p">;</span>
    <span class="nl">src</span><span class="p">:</span> <span class="sx">url('fonts/Lato-Bold.eot')</span><span class="p">;</span>
    <span class="nl">src</span><span class="p">:</span> <span class="sx">url('fonts/Lato-Bold.eot?#iefix')</span> <span class="n">format</span><span class="p">(</span><span class="s2">'embedded-opentype'</span><span class="p">),</span>
         <span class="sx">url('fonts/Lato-Bold.woff')</span> <span class="n">format</span><span class="p">(</span><span class="s2">'woff'</span><span class="p">),</span>
         <span class="sx">url('fonts/Lato-Bold.ttf')</span> <span class="n">format</span><span class="p">(</span><span class="s2">'truetype'</span><span class="p">);</span>
    <span class="nl">font-style</span><span class="p">:</span> <span class="nb">normal</span><span class="p">;</span>
    <span class="nl">font-weight</span><span class="p">:</span> <span class="nb">bold</span><span class="p">;</span>
    <span class="nl">text-rendering</span><span class="p">:</span> <span class="n">optimizeLegibility</span><span class="p">;</span>
<span class="p">}</span>

<span class="c">/* Bold + Italic */</span>
<span class="k">@font-face</span> <span class="p">{</span>
    <span class="nl">font-family</span><span class="p">:</span> <span class="s2">'Lato'</span><span class="p">;</span>
    <span class="nl">src</span><span class="p">:</span> <span class="sx">url('fonts/Lato-BoldItalic.eot')</span><span class="p">;</span>
    <span class="nl">src</span><span class="p">:</span> <span class="sx">url('fonts/Lato-BoldItalic.eot?#iefix')</span> <span class="n">format</span><span class="p">(</span><span class="s2">'embedded-opentype'</span><span class="p">),</span>
         <span class="sx">url('fonts/Lato-BoldItalic.woff')</span> <span class="n">format</span><span class="p">(</span><span class="s2">'woff'</span><span class="p">),</span>
         <span class="sx">url('fonts/Lato-BoldItalic.ttf')</span> <span class="n">format</span><span class="p">(</span><span class="s2">'truetype'</span><span class="p">);</span>
    <span class="nl">font-style</span><span class="p">:</span> <span class="nb">italic</span><span class="p">;</span>
    <span class="nl">font-weight</span><span class="p">:</span> <span class="nb">bold</span><span class="p">;</span>
    <span class="nl">text-rendering</span><span class="p">:</span> <span class="n">optimizeLegibility</span><span class="p">;</span>
<span class="p">}</span></code></pre></figure>

Your fonts should now be available.
Be sure to adjust the `url` paths if you place your fonts in a different directory.

## Applying your font

Simply apply your font in CSS as usual (this will also work with Google Fonts or Typekit):

<figure class="highlight"><pre><code class="language-css" data-lang="css"><span class="nt">body</span> <span class="p">{</span>
  <span class="nl">font-family</span><span class="p">:</span> <span class="n">Lato</span><span class="p">,</span> <span class="s2">'Helvetica Neue'</span><span class="p">,</span> <span class="n">Helvetica</span><span class="p">,</span> <span class="n">Arial</span><span class="p">,</span> <span class="nb">sans-serif</span><span class="p">;</span>
<span class="p">}</span></code></pre></figure>

Now you're good to go!


## Extreme optimization

If you really want to get fancy, Google Fonts has a feature called subsetting that lets you strip unused characters out from the font before transmitting it to clients, saving bandwidth.

You basically have two options if you want to do it yourself.
The easy way is to use FontSquirrel's excellent [Webfont Generator][webfont-generator], and use the subsetting options there.

The hard way is complicated and you will need to work out the exact details, but a basic setup would be:

1. Determine what characters you use

    If you have a static website, you might be able to do this fairly easily, perhaps by finding every character displayed on any page (accounting for HTML encoding).

2. Set up a pipeline to subset your fonts

    [fontTools'][fonttools] [subset.py][fonttools-subset] is probably the best way to do this, or the related version in [Google Font Directory][gfonts-subset].

3. Use the generated files as above

Before going down this route, you probably want to measure your maximum possible speed improvement and see if it's actually worth the trouble.

[gfonts]: https://www.google.com/fonts/
[typekit]: https://typekit.com/
[lato]: http://www.latofonts.com/lato-free-fonts/
[gfonts-lato]: https://www.google.com/fonts/specimen/Lato
[webfont-generator]: http://www.fontsquirrel.com/tools/webfont-generator
[fonttools-subset]: https://github.com/behdad/fonttools/blob/master/Lib/fontTools/subset.py
[fonttools]: https://github.com/behdad/fonttools
[gfonts-subset]: https://code.google.com/p/googlefontdirectory/source/browse/tools/subset
]]></content:encoded>
      <dc:date>2015-03-07T04:45:10-08:00</dc:date>
    </item>
    <item>
      <title>How to win when you're small</title>
      <link>https://msol.io/blog/thoughts/how-to-win-when-youre-small/</link>
      <description><![CDATA[We all know it happens–the underdog wins, the smaller army emerges victorious, the startup overtakes the multinational.

]]></description>
      <pubDate>Wed, 04 Mar 2015 12:23:55 -0800</pubDate>
      <guid>https://msol.io/blog/thoughts/how-to-win-when-youre-small/</guid>
      <content:encoded><![CDATA[We all know it happens--the underdog wins, the smaller army emerges victorious, the startup overtakes the multinational.

But why?

And how can we apply this effect to our companies, sports teams, or lives?

## Modeling unequal conflict

Enter Colonel Blotto.

Colonel Blotto is a simple game, well-studied in game theory.
The Colonel must choose how to distribute troops over some number of battlefields.
The goal is to emerge victorious at more battlefields, but the Colonel doesn't know in advance how many opponents will arrive at a given field.
Victory is determined simply by allocating more troops at a given battlefield.

### Fighting and winning at a disadvantage

Unfortunately, our Colonel is at a disadvantage and doesn't have as many troops as the enemy.

For example, if we have 3 battlefields:

<table>
  <tr>
    <th>Battlefield</th>
    <th>Blotto</th>
    <th>Enemy</th>
  </tr>
  <tr>
    <td>A</td>
    <td>4</td>
    <td>5</td>
  </tr>
  <tr>
    <td>B</td>
    <td>4</td>
    <td>5</td>
  </tr>
  <tr>
    <td>C</td>
    <td>4</td>
    <td>5</td>
  </tr>
</table>

Despite this disadvantage, Blotto can still succeed:

<table>
  <tr>
    <th>Battlefield</th>
    <th>Blotto</th>
    <th>Enemy</th>
  </tr>
  <tr>
    <td>A</td>
    <td>6</td>
    <td>5</td>
  </tr>
  <tr>
    <td>B</td>
    <td>6</td>
    <td>5</td>
  </tr>
  <tr>
    <td>C</td>
    <td>0</td>
    <td>5</td>
  </tr>
</table>

This is our first bit of insight: picking your battles (and picking which to sacrifice) is unquestionably more effective given limited resources.
This is hardly earth-shaking news, but it is good to see that our model bears out conventional wisdom.

In fact, there is a common application of this in politics: gerrymandering.
By [carefully choosing districts][gerrymandering], politicians have learned to win elections without the popular vote.

Now, the obvious objection is that an Enemy with superior resources could easily reallocate troops to guarantee victory on a majority of battlefields---this is unfortunate for Blotto, but it reveals a second insight: the Enemy doesn't have enough resources to win at everything! Unless the Enemy has a truly overwhelming number of resources, Blotto has a good shot at winning at least some battlefields, just as a small business can often outperform larger competitors in a few key areas by focusing on filling needs unmet by those larger competitors.

### Fighting at a major disadvantage

But what can an outgunned Blotto do in a situation where the enemy has many more resources?
<table>
  <tr>
    <th>Battlefield</th>
    <th>Blotto</th>
    <th>Enemy</th>
  </tr>
  <tr>
    <td>A</td>
    <td>2</td>
    <td>4</td>
  </tr>
  <tr>
    <td>B</td>
    <td>2</td>
    <td>4</td>
  </tr>
</table>

Even if our good Colonel allocates all troops to one battlefield, the Enemy has enough resources to prevent a Blotto victory on either battlefield.

So why not add more battlefields?

<table>
  <tr>
    <th>Battlefield</th>
    <th>Blotto</th>
    <th>Enemy</th>
  </tr>
  <tr>
    <td>A</td>
    <td>3</td>
    <td>2</td>
  </tr>
  <tr>
    <td>B</td>
    <td>1</td>
    <td>2</td>
  </tr>
  <tr>
    <td>C</td>
    <td>0</td>
    <td>2</td>
  </tr>
  <tr>
    <td>D</td>
    <td>0</td>
    <td>2</td>
  </tr>
</table>

By adding new battlefields to the game, Blotto is able to be victorious on one battlefield despite having half the troops.

Of course this isn't allowed in the game theory version (and Blotto still hasn't won!), but it uncovers a third insight: adding new areas to compete in is advantageous for the underdog.
Doing one thing (or a few things) well is a better strategy for small companies, and it can be a great advantage in a career as well.

This applies even more in situations where a victory on one battlefield may be sufficient to win--imagine a small company suddenly competing on grounds no other company knew existed.


## The math behind the maxim

We have seen a few good insights suggested by Colonel Blotto that can be rephrased as more conventional wisdom:

1. Pick your battles. If you spread your resources too thin, you are easily defeated.
1. Know thy enemy. If you know how your opponents will use their resources, you can pick the right battles.
1. The underdog can win too. It's easy to get disheartened, but remember that you can win even with fewer resources.
1. If you can't win, cheat. Add a new dimension to the game, a new product, a new battlefield. It might just be the edge you need.


[blotto-wiki]: https://en.wikipedia.org/wiki/Blotto_games
[gerrymandering]: http://www.washingtonpost.com/blogs/wonkblog/wp/2015/03/01/this-is-the-best-explanation-of-gerrymandering-you-will-ever-see/

]]></content:encoded>
      <dc:date>2015-03-04T12:23:55-08:00</dc:date>
    </item>
    <item>
      <title>Back up your PGP keys with GPG</title>
      <link>https://msol.io/blog/tech/back-up-your-pgp-keys-with-gpg/</link>
      <description><![CDATA[Back up your keys

]]></description>
      <pubDate>Sun, 19 Oct 2014 12:10:00 -0700</pubDate>
      <guid>https://msol.io/blog/tech/back-up-your-pgp-keys-with-gpg/</guid>
      <content:encoded><![CDATA[## Back up your keys

To generate base64-encoded ASCII-armored backups,
issue these commands:

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">gpg <span class="nt">--armor</span> <span class="nt">--export</span> <span class="o">&gt;</span> pgp-public-keys.asc
gpg <span class="nt">--armor</span> <span class="nt">--export-secret-keys</span> <span class="o">&gt;</span> pgp-private-keys.asc
gpg <span class="nt">--export-ownertrust</span> <span class="o">&gt;</span> pgp-ownertrust.asc</code></pre></figure>

Done! Remember that your private key should be kept, well, private.
Even with a passphrase,
revealing your secret key reduces the security of your PGP key to just that passphrase.

Speaking of that, while you're backing up your keys,
you may also want to generate a [revocation certificate][revocation.cert]:

First, note your key ID in the second column after the slash:
<figure class="highlight"><pre><code class="language-bash" data-lang="bash">gpg <span class="nt">--list-keys</span></code></pre></figure>

Then, generate the certificate.
You will prompted several times, but you probably want to choose
"1 = Key has been compromised" as your reason:

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">gpg <span class="nt">--armor</span> <span class="nt">--gen-revoke</span> <span class="o">[</span>your key ID] <span class="o">&gt;</span> pgp-revocation.asc</code></pre></figure>


## Restore your keys

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">gpg <span class="nt">--import</span> pgp-public-keys.asc
gpg <span class="nt">--import</span> pgp-private-keys.asc
gpg <span class="nt">--import-ownertrust</span> pgp-ownertrust.asc</code></pre></figure>

## Revoke your certificate

If your key is compromised, you can revoke your certificate in the same way:

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">gpg <span class="nt">--import</span> pgp-revocation.asc</code></pre></figure>

Be sure to upload your revocation certificate to any keyservers you have
uploaded your public certificate to!

## Where should I back up my PGP key?

One great method is to [print it as a QR code][paperkey],
but printing the plain text files generated above is also reasonable.

Storing it with your backups is not the best choice if encrypt
your backups with the same PGP key you are trying to back up.

Uploading to a cloud service is the most convenient,
but you are obviously implicitly trusting that provider with your private keys.


[revocation.cert]: https://www.gnupg.org/faq/gnupg-faq.html#define_rev_cert
[paperkey]: http://www.jabberwocky.com/software/paperkey/
]]></content:encoded>
      <dc:date>2014-10-19T12:10:00-07:00</dc:date>
    </item>
    <item>
      <title>Create a self-signed SSL Certificate with OpenSSL</title>
      <link>https://msol.io/blog/tech/create-a-self-signed-ssl-certificate-with-openssl/</link>
      <description><![CDATA[Creating a self-signed certificate with OpenSSL

]]></description>
      <pubDate>Tue, 30 Sep 2014 13:15:13 -0700</pubDate>
      <guid>https://msol.io/blog/tech/create-a-self-signed-ssl-certificate-with-openssl/</guid>
      <content:encoded><![CDATA[## Creating a self-signed certificate with OpenSSL

OpenSSL comes installed with Mac OS X (but see below),
as well as many Linux and Unix distributions.
Creating a certificate with it is very easy.

### OpenSSL commands

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">openssl genrsa <span class="nt">-out</span> key.pem 2048
openssl req <span class="nt">-new</span> <span class="nt">-sha256</span> <span class="nt">-key</span> key.pem <span class="nt">-out</span> csr.csr
openssl req <span class="nt">-x509</span> <span class="nt">-sha256</span> <span class="nt">-days</span> 365 <span class="nt">-key</span> key.pem <span class="nt">-in</span> csr.csr <span class="nt">-out</span> certificate.pem
openssl req <span class="nt">-in</span> csr.csr <span class="nt">-text</span> <span class="nt">-noout</span> | <span class="nb">grep</span> <span class="nt">-i</span> <span class="s2">"Signature.*SHA256"</span> <span class="o">&amp;&amp;</span> <span class="nb">echo</span> <span class="s2">"All is well"</span> <span class="o">||</span> <span class="nb">echo</span> <span class="s2">"This certificate will stop working in 2017! You must update OpenSSL to generate a widely-compatible certificate"</span></code></pre></figure>

The first OpenSSL command generates a 2048-bit ([recommended][rsa.key.size]) RSA private key.

The second command generates a [Certificate Signing Request][csr],
which you could instead use to generate a CA-signed certificate.
This step will ask you questions;
be as accurate as you like since you probably aren't getting this signed by a CA.

The third command generates a self-signed x509 certificate suitable for use on web servers.
This is the file you were after all along, congrats!

The check at the end ensures you will be able to use your certificate beyond 2016. OpenSSL on OS X is currently insufficient, and will silently generate a SHA-1 certificate that will be [rejected by browsers][sha1.rejection] in 2017. Update using your package manager, or [with Homebrew][homebrew.openssl] on a Mac and start the process over.


## More about self-signed SSL certificates

Self-signed SSL certificates provide all of the encryption benefits of a certificate signed by a Certificate Authority (CA),
but essentially none of the authentication benefits.
This is obviously still useful,
and I find them particularly nice for staging sites,
in the early stages of a project,
and for use [behind CloudFlare][cloudflare.ssl].

Due the the lack of authentication,
web browsers will display a warning to users attempting to connect to your site.
If this is a production site or you don't want this warning,
you must get a certificate signed by a CA.
Google "free SSL certificate" and you'll easily find a free 1-year certificate.

### ECC certificates

While I would not recommend an ECC (elliptical curve) certificate,
I have a guide to [create a self-signed ECC certificate][self.signed.ecc].
ECC is a relatively new kind of key,
and can be used as an alternative to RSA which we used above.

[sha1.rejection]: https://developer.mozilla.org/en-US/docs/Web/Security/Weak_Signature_Algorithm
[homebrew.openssl]: https://solitum.net/openssl-os-x-el-capitan-and-brew/
[cloudflare.ssl]: https://blog.cloudflare.com/origin-server-connection-security-with-universal-ssl/
[rsa.key.size]: https://www.emc.com/emc-plus/rsa-labs/standards-initiatives/key-size.htm
[csr]: https://en.wikipedia.org/wiki/Certificate_signing_request
[self.signed.ecc]: /blog/tech/create-a-self-signed-ecc-certificate/
]]></content:encoded>
      <dc:date>2014-09-30T13:15:13-07:00</dc:date>
    </item>
    <item>
      <title>More useful shell aliases</title>
      <link>https://msol.io/blog/tech/more-useful-shell-aliases/</link>
      <description><![CDATA[Shell aliases

]]></description>
      <pubDate>Sun, 30 Mar 2014 14:35:33 -0700</pubDate>
      <guid>https://msol.io/blog/tech/more-useful-shell-aliases/</guid>
      <content:encoded><![CDATA[## Shell aliases

Most developers who spend time in their terminal use at least simple shell aliases.
Some, such as `alias ll="ls -l"` can make common commands much faster.
Aliases are very simple but also very limited,
so I have found myself using shell functions instead for their flexibility.

## Functions instead of aliases

Shell functions in Bash and Zsh allow more than one awkward line of commands,
which can be very helpful.

For example, I have a function that pulls my current git branch
from the corresponding remote branch on `origin`.
This can be accomplished in an alias,
but I would also like to print out the command I am executing to help prevent mistakes,
especially if I'm not on the branch I expect to be on:

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nb">alias </span><span class="nv">gcurrbranch</span><span class="o">=</span><span class="s1">'git rev-parse --abbrev-ref HEAD'</span>

<span class="k">function </span>gpull<span class="o">()</span> <span class="o">{</span>
    <span class="nb">echo</span> <span class="s2">"git pull origin </span><span class="k">$(</span>gcurrbranch<span class="k">)</span><span class="s2">"</span>
    git pull origin <span class="k">$(</span>gcurrbranch<span class="k">)</span>
<span class="o">}</span></code></pre></figure>

You can see that I use both an alias and a function to accomplish what I want.
There is some duplication that would be nice to get rid of
and it would be great to have a general way to print what I am executing without that duplication.

## Pretty-print and 'eval'

The most obvious thing to print to the terminal is a string.
Bash and Zsh let you use `eval` to execute a string
(this is [dangerous][bash-eval] if you `eval` user data in your commands,
including file names and contents--please be aware of the security risk).

First let's try out a using a string for our command:

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nb">alias </span><span class="nv">gcurrbranch</span><span class="o">=</span><span class="s1">'git rev-parse --abbrev-ref HEAD'</span>

<span class="k">function </span>gpull<span class="o">()</span> <span class="o">{</span>
    <span class="nb">command</span><span class="o">=</span><span class="s2">"git pull origin </span><span class="k">$(</span>gcurrbranch<span class="k">)</span><span class="s2">"</span>
    <span class="nb">echo</span> <span class="s2">"</span><span class="k">${</span><span class="nv">command</span><span class="k">}</span><span class="s2">"</span>
    <span class="nb">eval</span> <span class="s2">"</span><span class="k">${</span><span class="nv">command</span><span class="k">}</span><span class="s2">"</span>
<span class="o">}</span></code></pre></figure>

That's a bit better,
but we can extract the print-and-eval logic into a separate function.
While we're doing that, let's make it print in white so it's easily distinguishable:

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="k">function </span>print_and_eval<span class="o">()</span> <span class="o">{</span>
    <span class="nb">echo</span> <span class="s2">"</span><span class="se">\e</span><span class="s2">[0;37m</span><span class="nv">$1</span><span class="se">\e</span><span class="s2">[0m"</span>
    <span class="nb">eval</span> <span class="nv">$1</span>
<span class="o">}</span>

<span class="nb">alias </span><span class="nv">gcurrbranch</span><span class="o">=</span><span class="s1">'git rev-parse --abbrev-ref HEAD'</span>

<span class="k">function </span>gpull<span class="o">()</span> <span class="o">{</span> print_and_eval <span class="s2">"git pull origin </span><span class="k">$(</span>gcurrbranch<span class="k">)</span><span class="s2">"</span> <span class="o">}</span></code></pre></figure>


<img class="post-image"
     title="The bash shell alias printing nicely"
     alt="Command-R to Control-L configuration"
     src="/img/bash-white-alias.png"/>

Now we have commands that print in white and we've removed the duplication!

There are some drawbacks to this approach.
There are [security concerns][bash-eval],
we lose syntax highlighting for the commands in the editor,
and the printing is imprecise with non-printable escapes
(such as in certain `sed` commands).

Even so, I find this very useful for my git aliases (among others).
But please, be careful and do not use commands that could execute user data (including file names).


[bash-eval]: http://mywiki.wooledge.org/BashFAQ/048

]]></content:encoded>
      <dc:date>2014-03-30T14:35:33-07:00</dc:date>
    </item>
    <item>
      <title>Dvorak–QWERTY ⌘ on Mac, Windows, and Linux</title>
      <link>https://msol.io/blog/tech/dvorak-qwerty-on-mac-windows-and-linux/</link>
      <description><![CDATA[I use the Dvorak keyboard layout,
but prefer to retain my usual keyboard shortcuts from QWERTY.

]]></description>
      <pubDate>Wed, 26 Mar 2014 02:15:46 -0700</pubDate>
      <guid>https://msol.io/blog/tech/dvorak-qwerty-on-mac-windows-and-linux/</guid>
      <content:encoded><![CDATA[I use the [Dvorak keyboard layout][dvorak],
but prefer to retain my usual keyboard shortcuts from [QWERTY][qwerty].

Inspired by Mac OS X's Dvorak-QWERTY Command layout,
I have found ways to convert my Dvorak layout to QWERTY only while a modifier key is held down
on Windows, Mac, and Linux
for both the Dvorak Simplified and Programmer Dvorak layouts.

## Mac OS X

I came up with a Programmer Dvorak--QWERTY Command setup that I use daily on my MacBook.
It is effectively QWERTY when Control, Option, or Command (⌘) are not held down.

I have a [blog post][dq-mac] about how to duplicate my setup,
or you can use the [built-in Dvorak -- QWERTY ⌘][apple-dqc] which
only switches back to QWERTY when Command is held down.

## Windows

On Windows I used [AutoHotkey][ahk] to rebind my keys
when Control, Alt, or Super (Windows) are not held down.


<div class="scrollable has-scroll"><div class="table-scroll-wrapper">
<table>
    <thead>
        <tr>
            <th>Layout</th>
            <th colspan="2">Download</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>Dvorak Simplified (normal)</td>
            <td><a href="/files/dvorak/DvorakQWERTYCommand-Portable.ahk">Source</a></td>
            <td><a href="/files/dvorak/DvorakQWERTYCommand-Portable.exe">Binary</a></td>
        </tr>
        <tr>
            <td>Programmer Dvorak</td>
            <td><a href="/files/dvorak/ProgrammerDvorakQWERTYCommand-Portable.ahk">Source</a></td>
            <td><a href="/files/dvorak/ProgrammerDvorakQWERTYCommand-Portable.exe">Binary</a></td>
        </tr>
    </tbody>
</table>
</div></div>

## Linux

Back when I used desktop Linux,
I used [dvorak-qwerty][dvorak-qwerty] to swap my keyboard layout.
I found this to be the least reliable layout between the three operating systems,
but I never found a better way than this program which rebinds at the X11 level.

[pd]: http://www.kaufmann.no/roland/dvorak/
[ahk]: http://www.autohotkey.com/
[dvorak]: https://en.wikipedia.org/wiki/Dvorak_Simplified_Keyboard
[qwerty]: https://en.wikipedia.org/wiki/QWERTY
[dq-mac]: /blog/tech/programmer-dvorak-with-qwerty-shortcut-keys-on-os-x/
[apple-dqc]: http://support.apple.com/kb/PH6528
[dvorak-qwerty]: https://code.google.com/p/dvorak-qwerty/
]]></content:encoded>
      <dc:date>2014-03-26T02:15:46-07:00</dc:date>
    </item>
    <item>
      <title>Programmer Dvorak with QWERTY shortcut keys on OS X</title>
      <link>https://msol.io/blog/tech/programmer-dvorak-with-qwerty-shortcut-keys-on-os-x/</link>
      <description><![CDATA[Programmer Dvorak

]]></description>
      <pubDate>Mon, 17 Mar 2014 15:30:51 -0700</pubDate>
      <guid>https://msol.io/blog/tech/programmer-dvorak-with-qwerty-shortcut-keys-on-os-x/</guid>
      <content:encoded><![CDATA[# Programmer Dvorak

I type in [Programmer Dvorak][pd],
a somewhat obscure but useful variant of the [Dvorak keyboard layout][dvorak].
It keeps the improved placement of the letter keys found in Dvorak and moves
symbols commonly used in programming into better locations.
In particular, Shift must be held to press the number keys.
This frees up that entire row for symbols.

## Dvorak -- QWERTY ⌘ (Command)

Mac OS X comes with a keyboard layout called Dvorak -- QWERTY ⌘ that allows you
to type in Dvorak normally,
but when you hold Command,
all of the keys become their QWERTY equivalents.
When I used to type in plain Dvorak I loved using the familiar locations of shortcut keys,
but its behavior with Control and other modifier keys left me dissatisfied.

I tried to use [Ukelele][ukelele] to create a keyboard layout to support a similar
Programmer Dvorak -- QWERTY ⌘ (Command) mode,
but the built in facilities did not work everywhere.
In particular Java applications did not use QWERTY when I held modifier keys,
which became a significant problem when I started using Android Studio regularly.

To fix this, I wrote an XML snippet for
[Karabiner][karabiner] to enable the "correct" behavior.
It works by remapping all keys to Programmer Dvorak unless any modifier
key--that is: Control, Command, or Option--is held down,
in which case every key combination will behave as if it is in QWERTY.
This allows you to use normal shortcut keys in every app but still type
in Programmer Dvorak.

### Setup steps

First you must [install Karabiner][karabiner].
Then open `~/Library/Application Support/Karabiner/private.xml`
and add this snippet under the `<root>` element:

<noscript><pre>400: Invalid request</pre></noscript><script src="https://gist.github.com/9614362.js"> </script>

Then press ReloadXML in the upper-right corner of Karabiner,
and check the "Use Programmer Dvorak -- Qwerty Keyboard Layout" box.

<img class="post-image"
     title="Enable Programmer Dvorak -- QWERTY ⌘ Command in Karabiner"
     alt="Enabling Programmer Dvorak -- QWERTY ⌘ Command in Karabiner"
     src="/img/programmer-dvorak-kr4mb.png"/>

That's it! If you want to further customize the behavior,
edits to the XML should be reasonably straightforward.


## My Programmer Dvorak experience

I sometimes get asked if it is worth learning to type in Programmer Dvorak.
My short answer is no.

My longer answer is that while I find it more comfortable than QWERTY,
I do not find that I type faster or see a strong daily benefit
(I alone am too small a sample size to say anything useful about RSI).
It also requires work to maintain things like shortcut keys,
and it inhibits both my ability to work on other people's computers
as well as other people working on mine.
It also has decreased my QWERTY typing speed,
especially with numbers and symbols.

That said, I have largely solved these problems for myself,
and I will continue to use Programmer Dvorak day-to-day.


[pd]: http://www.kaufmann.no/roland/dvorak/
[dvorak]: https://en.wikipedia.org/wiki/Dvorak_Simplified_Keyboard
[ukelele]: http://scripts.sil.org/ukelele
[karabiner]: https://pqrs.org/osx/karabiner/
]]></content:encoded>
      <dc:date>2014-03-17T15:30:51-07:00</dc:date>
    </item>
    <item>
      <title>Android: Convert Drawable to Bitmap</title>
      <link>https://msol.io/blog/android/android-convert-drawable-to-bitmap/</link>
      <description><![CDATA[Recently when working on an Android app I needed to convert a Drawable object to a Bitmap object.
Rasterizing a Drawable is actually pretty easy if you use this method:

]]></description>
      <pubDate>Thu, 13 Mar 2014 02:20:13 -0700</pubDate>
      <guid>https://msol.io/blog/android/android-convert-drawable-to-bitmap/</guid>
      <content:encoded><![CDATA[Recently when working on an Android app I needed to convert a [Drawable][drawable] object to a [Bitmap][bitmap] object.
Rasterizing a Drawable is actually pretty easy if you use this method:

<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="kd">public</span> <span class="nc">Bitmap</span> <span class="nf">convertToBitmap</span><span class="o">(</span><span class="nc">Drawable</span> <span class="n">drawable</span><span class="o">,</span> <span class="kt">int</span> <span class="n">widthPixels</span><span class="o">,</span> <span class="kt">int</span> <span class="n">heightPixels</span><span class="o">)</span> <span class="o">{</span>
    <span class="nc">Bitmap</span> <span class="n">mutableBitmap</span> <span class="o">=</span> <span class="nc">Bitmap</span><span class="o">.</span><span class="na">createBitmap</span><span class="o">(</span><span class="n">widthPixels</span><span class="o">,</span> <span class="n">heightPixels</span><span class="o">,</span> <span class="nc">Bitmap</span><span class="o">.</span><span class="na">Config</span><span class="o">.</span><span class="na">ARGB_8888</span><span class="o">);</span>
    <span class="nc">Canvas</span> <span class="n">canvas</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Canvas</span><span class="o">(</span><span class="n">mutableBitmap</span><span class="o">);</span>
    <span class="n">drawable</span><span class="o">.</span><span class="na">setBounds</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="mi">0</span><span class="o">,</span> <span class="n">widthPixels</span><span class="o">,</span> <span class="n">heightPixels</span><span class="o">);</span>
    <span class="n">drawable</span><span class="o">.</span><span class="na">draw</span><span class="o">(</span><span class="n">canvas</span><span class="o">);</span>

    <span class="k">return</span> <span class="n">mutableBitmap</span><span class="o">;</span>
<span class="o">}</span></code></pre></figure>

First we create a mutable Bitmap object of the correct size in pixels.
I recommend you use ARGB_8888 instead of another Bitmap configuration unless you have a specific reason not to.

Then we create a new [Canvas][canvas] backed by that bitmap,
set the bounds appropriately on the drawable,
and draw the Drawable onto the Canvas.
This is when the Drawable actually gets mapped onto the pixels represented by the Bitmap.

We now have a Bitmap suitable for use elsewhere.
I have found this to be a useful technique for masking images with Path objects when antialiasing is required.

### Write Bitmap as a JPEG image

If you want to write a Bitmap (or a Drawable that has been converted to a Bitmap) as a JPEG image,
you can use this simple technique:

<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="kd">public</span> <span class="kt">void</span> <span class="nf">writeJpegImageToFile</span><span class="o">(</span><span class="nc">Bitmap</span> <span class="n">bitmap</span><span class="o">,</span> <span class="nc">FileOutputStream</span> <span class="n">jpegFileStream</span><span class="o">)</span> <span class="o">{</span>
    <span class="c1">// use JPEG quality of 80 (scale 1 - 100)</span>
    <span class="n">bitmap</span><span class="o">.</span><span class="na">compress</span><span class="o">(</span><span class="nc">Bitmap</span><span class="o">.</span><span class="na">CompressFormat</span><span class="o">.</span><span class="na">JPEG</span><span class="o">,</span> <span class="mi">80</span><span class="o">,</span> <span class="n">jpegFileStream</span><span class="o">);</span>
<span class="o">}</span></code></pre></figure>


[drawable]: http://developer.android.com/reference/android/graphics/drawable/Drawable.html
[bitmap]: http://developer.android.com/reference/android/graphics/Bitmap.html
[canvas]: http://developer.android.com/reference/android/graphics/Canvas.html
]]></content:encoded>
      <dc:date>2014-03-13T02:20:13-07:00</dc:date>
    </item>
    <item>
      <title>Bitshifting by example</title>
      <link>https://msol.io/blog/tech/bitshifting-by-example/</link>
      <description><![CDATA[If you are a programmer with a history similar to my own
then you have seen enough to know vaguely that the &lt;&lt; and &gt;&gt; operators in many languages shift bits
(usually in integers)
around and that there are some techniques to isolate certain blocks of bits out for reading,
but you haven’t actually tried these techniques.

]]></description>
      <pubDate>Sun, 02 Mar 2014 02:50:13 -0800</pubDate>
      <guid>https://msol.io/blog/tech/bitshifting-by-example/</guid>
      <content:encoded><![CDATA[If you are a programmer with a history similar to my own
then you have seen enough to know vaguely that the `<<` and `>>` operators in many languages shift bits
(usually in integers)
around and that there are some techniques to isolate certain blocks of bits out for reading,
but you haven't actually _tried_ these techniques.

Let's fix that by example.

### Bitshifting

Bitshifting is actually pretty simple.
Take the 32 bit unsigned integer 2<sup>32</sup> - 1,
which is represented by all ones.
I have separated it into octets (8-bit bytes).

<figure class="highlight"><pre><code class="language-text" data-lang="text">                 0xffffffff
&lt;-- most significant ... least significant --&gt;
     11111111 11111111 11111111 11111111
      byte 1   byte 2   byte 3   byte 4</code></pre></figure>

Let's represent this in some C code:
<figure class="highlight"><pre><code class="language-c" data-lang="c"><span class="kt">uint32_t</span> <span class="n">field</span> <span class="o">=</span> <span class="mh">0xffffffff</span><span class="p">;</span></code></pre></figure>

It is convenient to represent this value using hex notation,
since there is a 1:1 mapping between hex and the resultant bits.
This is the same value from above,
just written in hexadecimal notation instead of binary.

Here is a quick table to convert hex to binary,
in case you are unfamiliar or out of practice:

<div class="scrollable has-scroll">
    <div class="table-scroll-wrapper">
        <table>
            <thead>
                <tr>
                    <th>0x0</th>
                    <th>0x1</th>
                    <th>0x2</th>
                    <th>0x3</th>
                    <th>0x4</th>
                    <th>0x5</th>
                    <th>0x6</th>
                    <th>0x7</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td style="text-align: center;">0000</td>
                    <td style="text-align: center;">0001</td>
                    <td style="text-align: center;">0010</td>
                    <td style="text-align: center;">0011</td>
                    <td style="text-align: center;">0100</td>
                    <td style="text-align: center;">0101</td>
                    <td style="text-align: center;">0110</td>
                    <td style="text-align: center;">0111</td>
                </tr>
            </tbody>
        </table>
    </div>
</div>
<span />
<div class="scrollable has-scroll">
    <div class="table-scroll-wrapper">
        <table>
            <thead>
                <tr>
                    <th>0x8</th>
                    <th>0x9</th>
                    <th>0xa</th>
                    <th>0xb</th>
                    <th>0xc</th>
                    <th>0xd</th>
                    <th>0xe</th>
                    <th>0xf</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td style="text-align: center;">1000</td>
                    <td style="text-align: center;">1001</td>
                    <td style="text-align: center;">1010</td>
                    <td style="text-align: center;">1011</td>
                    <td style="text-align: center;">1100</td>
                    <td style="text-align: center;">1101</td>
                    <td style="text-align: center;">1110</td>
                    <td style="text-align: center;">1111</td>
                </tr>
            </tbody>
        </table>
    </div>
</div>

Now let's bitshift this left 4 bits:

<figure class="highlight"><pre><code class="language-c" data-lang="c"><span class="n">field</span> <span class="o">=</span> <span class="n">field</span> <span class="o">&lt;&lt;</span> <span class="mi">4</span><span class="p">;</span> <span class="c1">// equivalently, field &lt;&lt;= 4</span></code></pre></figure>

which results in:

<figure class="highlight"><pre><code class="language-text" data-lang="text">             0xfffffff0
11111111 11111111 11111111 11110000</code></pre></figure>

If each `1` were a buffalo and each `0` a plot of empty land,
then we just forced 4 buffalo off of the left hand cliff
in order to make more empty land on the right hand side.

The rule is simple:
when you bitshift left,
shift all the bits to the left and pad the right with zeros.
For some reason this makes me think of hunting by [buffalo jump][buffalo.jump].


#### Bitshift right

Bitshifting right is much like bitshifting left--in fact,
it is identical **unless** you are using signed integers,
in which case things get implementation-specific in some languages
(basically, sometimes you get padded with the [sign-bit][sign.bit] instead of always 0).

Today, let's just worry about unsigned integers.

Continuing with our result from before,
a small bitshift right

<figure class="highlight"><pre><code class="language-c" data-lang="c"><span class="n">field</span> <span class="o">=</span> <span class="n">field</span> <span class="o">&gt;&gt;</span> <span class="mi">1</span><span class="p">;</span></code></pre></figure>

results in

<figure class="highlight"><pre><code class="language-text" data-lang="text">             0x7ffffff8
01111111 11111111 11111111 11111000</code></pre></figure>

Notice that since `field` is unsigned we pad with a `0` on the left,
and that everything else has been shifted right by one location.

### UUIDs

Let's look at a time when all this bitshifting might come in handy.

[Universally Unique IDentifiers][uuid.wikipedia]
are 128-bit identifiers that are often displayed
in 36-character strings rendered thusly:

`63afa317-ef9e-4127-93a8-a8996d99d5ee`

But what do UUIDs have to do with bitshifting?

As it happens,
there is an [RFC][uuid.rfc] to standardize UUIDs and set certain bits
in order to identify a given 128 bit object as a UUID and to specify which variant it is.

The UUID specification breaks apart integers into fixed-width fields within each integer and assigns different meanings to each field.

The RFC gives us this diagram showing each field and is split into 4 vertically-stacked 32-bit ints:

<figure class="highlight"><pre><code class="language-text" data-lang="text">0                   1                   2                   3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                          time_low                             |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|       time_mid                |         time_hi_and_version   |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|clk_seq_hi_res |  clk_seq_low  |         node (0-1)            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                         node (2-5)                            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+</code></pre></figure>

It's time to use our new skills.
Let's try reading time_hi_and_version since it's one of the more complicated fields.


#### Simple field-reading by double bitshifting


A simple way to read such a field is to first "shift off" all of the bits
we don't care about that are to the left of the field of interest,
and then to shift that same field as far right as we can go without shifting that field "off the edge."
This technique leaves the field we care about in the least significant bits,
where it can be easily interpreted as an integer.

Let's take the second 32-bit integer,
the one that includes time_mid and time_hi_and_version.

<figure class="highlight"><pre><code class="language-text" data-lang="text">              0x11223344
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 0001000100100010 0011001101000100   |
|     time_mid    |time_hi_and_version|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+</code></pre></figure>

We can extract the version field out of this.
The RFC describes this field:

>   The version number is in the most significant 4 bits of the time
>   stamp (bits 4 through 7 of the time_hi_and_version field). 

Counting from most to least significant (left to right)
we can see that those are bits 20 through 23.
We should first shift out the 19 most significant bits we don't care about:

<figure class="highlight"><pre><code class="language-c" data-lang="c"><span class="n">field</span> <span class="o">&lt;&lt;=</span> <span class="mi">19</span><span class="p">;</span></code></pre></figure>

leaving us with

<figure class="highlight"><pre><code class="language-text" data-lang="text">              0x9a200000
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 1001101000100000 0000000000000000   |
|     time_mid    |time_hi_and_version|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+</code></pre></figure>

Now we want to remove everything but the 4 bits we care about:

<figure class="highlight"><pre><code class="language-c" data-lang="c"><span class="n">field</span> <span class="o">&gt;&gt;=</span> <span class="mi">28</span><span class="p">;</span></code></pre></figure>

yielding

<figure class="highlight"><pre><code class="language-text" data-lang="text">              0x00000009
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 0000000000000000 0000000000001001   |
|     time_mid    |time_hi_and_version|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+</code></pre></figure>

Looking this up in the table given in the RFC,
we see that this is not a valid version for a UUID!
The first bit must be zero,
but we can clearly see that it is not.


#### Summary

It turns out that bitshifting isn't as hard as it seems.
This simple technique won't cover every case
(in particular, [bitmasking][bitmasking] may be useful in related situations)
but it is a tool that is occasionally useful to have.


[uuid.wikipedia]: http://en.wikipedia.org/wiki/Universally_unique_identifier
[uuid.rfc]: http://www.ietf.org/rfc/rfc4122
[buffalo.jump]: http://en.wikipedia.org/wiki/Buffalo_jump
[sign.bit]: http://en.wikipedia.org/wiki/Sign_bit
[bitmasking]: http://en.wikipedia.org/wiki/Mask_(computing)
]]></content:encoded>
      <dc:date>2014-03-02T02:50:13-08:00</dc:date>
    </item>
    <item>
      <title>Know each system’s responsibilities</title>
      <link>https://msol.io/blog/tech/know-each-systems-responsibilities/</link>
      <description><![CDATA[When I was working on the web application flesh,
I needed to use the Go SQL package to run some queries.
Unsurprisingly, I needed to substitute values in for parameters using special methods in Go’s SQL API,
since simple string concatenation could potentially lead to SQL injection vulnerabilities.
I’ve done this sort of thing before,
so I recognized the question mark syntax I found in an example that read:

]]></description>
      <pubDate>Sun, 06 Oct 2013 07:56:13 -0700</pubDate>
      <guid>https://msol.io/blog/tech/know-each-systems-responsibilities/</guid>
      <content:encoded><![CDATA[When I was working on the web application [flesh][flesh],
I needed to use the [Go SQL package][go.sql] to run some queries.
Unsurprisingly, I needed to substitute values in for parameters using special methods in Go's SQL API,
since simple string concatenation could potentially lead to [SQL injection][sql.injection] vulnerabilities.
I've done this sort of thing before,
so I recognized the question mark syntax I found in an example that read:

<figure class="highlight"><pre><code class="language-go" data-lang="go"><span class="n">err</span> <span class="o">:=</span> <span class="n">db</span><span class="o">.</span><span class="n">QueryRow</span><span class="p">(</span><span class="s">"SELECT name FROM foo WHERE id=?"</span><span class="p">,</span> <span class="n">id</span><span class="p">)</span><span class="o">.</span><span class="n">Scan</span><span class="p">(</span><span class="o">&amp;</span><span class="n">s</span><span class="p">)</span></code></pre></figure>

Unfortunately, when I tried to run the code against my database (Postgres) the parameters weren't getting substituted in.

I quite literally spent hours pouring over the Go documentation and searching the Internet for anything that could tell me what was wrong.
The two examples in the Go documentation were very minimal but seemed to suggest that I was simply using the functions as expected.

My search ended when I finally realized that the substitution *didn't take place in Go*.

The Go package I was using forwarded the query and parameters along to Postgres,
which in retrospect is perfectly natural because Postgres knows how to substitute parameters appropriately,
while the Go code doesn't need to know the specifics.

The problem still isn't immediately obvious---shouldn't Postgres substitute the parameters correctly?
Well, it turns out that Postgres doesn't support question mark syntax for parameter substitution;
it instead uses numbered parameters such as $1, $2, ....
The Go examples simply chose a common (yet not universal) parameter substitution convention.

The point is that if I had understood which system was responsible for the action I was concerned about --
parameter substitution -- then I would have saved an immense amount of time debugging.
Instead of searching for a solution in Go documentation,
I would have checked how Postgres expected it to be done and found an answer in minutes.

Next time you have trouble figuring out why a system's behavior doesn't match your expectations,
make sure you are examining the right system---it could be you are looking at the client and not the provider.


[flesh]: https://github.com/Chandler/flesh
[go.sql]: http://golang.org/pkg/database/sql/
[sql.injection]: http://en.wikipedia.org/wiki/SQL_injection
]]></content:encoded>
      <dc:date>2013-10-06T07:56:13-07:00</dc:date>
    </item>
    <item>
      <title>Create a self-signed ECC certificate</title>
      <link>https://msol.io/blog/tech/create-a-self-signed-ecc-certificate/</link>
      <description><![CDATA[Self-signed certificates and Elliptic Curve Cryptography

]]></description>
      <pubDate>Sun, 06 Oct 2013 02:25:13 -0700</pubDate>
      <guid>https://msol.io/blog/tech/create-a-self-signed-ecc-certificate/</guid>
      <content:encoded><![CDATA[### Self-signed certificates and Elliptic Curve Cryptography

There are many reasons to self-sign SSL certificates,
but I find them particularly useful for staging sites and in the early stages of a project.

I have a [three command guide to self-signing an SSL certificate][self.signed.openssl]
if you aren't interested in ECC.

If you are interested in ECC,
you may know that the main reason for using elliptic curves as the basis for communication over SSL is the small key size --
where regular DSA would require 1024 bits, ECDSA (the elliptic-curve variant of DSA) would require about 160 bits.
The computational power required for communication over ECDSA is also less.

**This is only likely to matter in embedded systems or other highly-constrained environments.**

If you are considering specifically using an ECDSA certificate like the one generated here with OpenSSL,
it is probably worth reading [a more detailed description][ecdsa.schneier] by Bruce Schneier.

If you are sure you want an ECC-based certificate,
doing so is just as easy as any other self-signed certificate with OpenSSL,
*provided* that your version supports ECDSA.
The commands below have been verified to work on OSX 10.8.

### OpenSSL commands

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">openssl ecparam <span class="nt">-genkey</span> <span class="nt">-name</span> prime256v1 <span class="nt">-out</span> key.pem
openssl req <span class="nt">-new</span> <span class="nt">-sha256</span> <span class="nt">-key</span> key.pem <span class="nt">-out</span> csr.csr
openssl req <span class="nt">-x509</span> <span class="nt">-sha256</span> <span class="nt">-days</span> 365 <span class="nt">-key</span> key.pem <span class="nt">-in</span> csr.csr <span class="nt">-out</span> certificate.pem
openssl req <span class="nt">-in</span> csr.csr <span class="nt">-text</span> <span class="nt">-noout</span> | <span class="nb">grep</span> <span class="nt">-i</span> <span class="s2">"Signature.*SHA256"</span> <span class="o">&amp;&amp;</span> <span class="nb">echo</span> <span class="s2">"All is well"</span> <span class="o">||</span> <span class="nb">echo</span> <span class="s2">"This certificate will stop working in 2017! You must update OpenSSL to generate a widely-compatible certificate"</span></code></pre></figure>

The first command is the only one specific to elliptic curves.
It generates a private key using a standard elliptic curve over a 256 bit prime field.
You can list all available curves using
<figure class="highlight"><pre><code class="language-bash" data-lang="bash">openssl ecparam <span class="nt">-list_curves</span></code></pre></figure>
or you can use prime256v1 as I did.

The second command generates a [Certificate Signing Request][csr]
and the third generates a self-signed x509 certificate suitable for use on web servers.

The check at the end ensures you will be able to use your certificate beyond 2016. OpenSSL on OS X is currently insufficient, and will silently generate a SHA-1 certificate that will be [rejected by browsers][sha1.rejection] in 2017. Update using your package manager, or [with Homebrew][homebrew.openssl] on a Mac and start the process over.

### More on ECC

If you're interested in elliptic curve cryptography,
Wikipedia has a [good introduction][ecc] that includes the math behind it,
as well as more specific information on [ECDSA][ecdsa.wiki] in particular.
As usual, there are good links from there to learn more.


[sha1.rejection]: https://developer.mozilla.org/en-US/docs/Web/Security/Weak_Signature_Algorithm
[homebrew.openssl]: https://solitum.net/openssl-os-x-el-capitan-and-brew/
[ecdsa.schneier]: https://www.schneier.com/crypto-gram-9911.html#EllipticCurvePublic-KeyCryptography
[csr]: https://en.wikipedia.org/wiki/Certificate_signing_request
[ecc]: https://en.wikipedia.org/wiki/Elliptic_curve_cryptography
[ecdsa.wiki]: https://en.wikipedia.org/wiki/Elliptic_Curve_DSA
[self.signed.openssl]: /blog/tech/create-a-self-signed-ssl-certificate-with-openssl/
]]></content:encoded>
      <dc:date>2013-10-06T02:25:13-07:00</dc:date>
    </item>
    <item>
      <title>Sending links with custom URL schemes through e-mail</title>
      <link>https://msol.io/blog/tech/sending-links-with-custom-url-schemes-through-email/</link>
      <description><![CDATA[Note: This method no longer works

]]></description>
      <pubDate>Sun, 21 Jul 2013 03:39:13 -0700</pubDate>
      <guid>https://msol.io/blog/tech/sending-links-with-custom-url-schemes-through-email/</guid>
      <content:encoded><![CDATA[#### Note: This method no longer works

I haven't tried it myself, but I'm told this method no longer works.
Unfortunately, I no longer work in this area and don't have a workaround.
Perhaps the information below will inspire a different solution.

### Hating on Gmail

Recently I needed to e-mail a message that included a link to
open an app on iOS devices. iOS supports this so long as the app is
installed and has [registered a custom URL scheme][register-url-scheme].
Great, hyperlinking is a skill I have.

Normally, I would also worry about what happens when the link is clicked on non-iOS devices,
but I believe the expected behavior for clicking "Open MyiPhoneApp" on a PC is... nothing.
Which is what happens.

However, after a bit of testing it turns out that Gmail strips out these links entirely,
both in the browser and in the iOS app.
Not only does this mean Gmail app users can't use my link,
but viewing the email in the browser suggests that my Launch button *isn't even a link*.


### Link behavior

I had several very specific criteria that my link had to meet:

1. The app should open as quickly as possible
2. An Internet connection should not be required
3. There should be some reasonable behavior on non-iOS devices
4. The link should work even in the Gmail app


### Abusing HTML links

The first three of these can be accomplished with a plain hyperlink using the custom URL scheme.
Since that is my preference, let's take advantage of loose HTML interpretation.

The basic idea is to have two separate links:
one to link directly into the app,
and a second to do some simple redirect magic we will see in the next section.
The app link should be preferred,
but if it is automatically removed, say by Gmail, then we can use the second link instead.

Carefully crafting a (non-HTML compliant) link as follows is the solution:

<figure class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;a</span>  <span class="na">href=</span><span class="s">"my-app://deep-link"</span>
    <span class="na">href=</span><span class="s">"http://example.com/backup-link"</span>
    <span class="na">href=</span><span class="s">"my-app://deep-link"</span>
<span class="nt">&gt;</span>Link Text<span class="nt">&lt;/a&gt;</span></code></pre></figure>

By bracketing the backup link with the desired link,
browsers (at least those I've tested) will ignore the backup link,
except when the desired links have already been stripped out by Gmail.


### The backup link

Obviously, the backup link can be whatever you want.
I chose a link that goes to a dynamically-generated page (that I host) with a simple piece of logic.
If the user is on an iOS device ([by user-agent][ua-sniffing]),
then return a 301 or 302 HTTP Redirect to `my-app://deep-link`.
If not, then return a 301 or 302 HTTP Redirect to some sane location,
such as the app's website or App Store page.

The behavior of this link is slightly less desirable that the direct link.
The backup link requires an Internet connection,
and even when one is present the link first loads an intermediate page before the app
which is both slower and presents another opportunity for failure.
Even so, this is acceptable given that the direct link was removed on our behalf.


### Less than perfect

The astute reader may notice that there are still several situations
in which a user can click a link that has no apparent effect.
I think that this is totally acceptable given the context in which the link is presented,
but this method tries to ensure that the link is always clickable,
even if the destination is unavailable.

[register-url-scheme]: http://developer.apple.com/library/ios/#documentation/iphone/conceptual/iphoneosprogrammingguide/AdvancedAppTricks/AdvancedAppTricks.html#//apple_ref/doc/uid/TP40007072-CH7-SW20
[ua-sniffing]: http://stackoverflow.com/a/9039885

]]></content:encoded>
      <dc:date>2013-07-21T03:39:13-07:00</dc:date>
    </item>
    <dc:date>2019-06-15T04:50:13-07:00</dc:date>
  </channel>
</rss>