<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
 
 <title>Hoopla! - Jack Danger Canty</title>
 <link href="http://6brand.com/atom.xml" rel="self"/>
 <link href="http://6brand.com/"/>
 <updated>2022-03-02T00:22:45-08:00</updated>
 <id>http://6brand.com/</id>
 <author>
   <name>Jack Danger Canty</name>
   <email>codeblogfeed@6brand.com</email>
 </author>

 
 <entry>
   <title>What does `bundle exec` do?</title>
   <link href="http://6brand.com/what-does-bundle-exec-do.html"/>
   <updated>2015-07-14T00:00:00-07:00</updated>
   <id>http://6brand.com/what-does-bundle-exec-do.html</id>
   <content type="html">&lt;p&gt;A &lt;a href=&quot;https://twitter.com/rmason3&quot;&gt;colleague&lt;/a&gt; asked me why sometimes we’ll run a command that’s provided by a Ruby gem (e.g. “rspec”) and it fails unless we type &lt;code&gt;bundle exec&lt;/code&gt; before it.&lt;/p&gt;

&lt;h2 id=&quot;what-bundler-gives-us&quot;&gt;What Bundler gives us&lt;/h2&gt;
&lt;p&gt;Bundler is a Ruby gem that’s a little special because it manages other Ruby gems. It does basically three things:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;It does a &lt;a href=&quot;http://ruby-doc.org/stdlib-2.0.0/libdoc/tsort/rdoc/TSort.html&quot;&gt;topological sort&lt;/a&gt; of the gems listed in your &lt;code&gt;Gemfile&lt;/code&gt; to print a complete graph of your project’s dependencies into &lt;code&gt;Gemfile.lock&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;It retrieves the gems your project needs from the source(s) you’ve defined&lt;/li&gt;
  &lt;li&gt;And it makes it so when you &lt;code&gt;require&lt;/code&gt; files the right file is loaded.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;the-importance-of-env-in-ruby&quot;&gt;The importance of ENV in Ruby&lt;/h2&gt;
&lt;p&gt;The two most popular Ruby version managers are &lt;a href=&quot;https://rvm.io/&quot;&gt;&lt;code&gt;RVM&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;http://rbenv.org/&quot;&gt;&lt;code&gt;rbenv&lt;/code&gt;&lt;/a&gt; (though I strongly recommend &lt;a href=&quot;https://github.com/postmodern/chruby&quot;&gt;&lt;code&gt;chruby&lt;/code&gt;&lt;/a&gt;). They work in totally different ways (&lt;code&gt;RVM&lt;/code&gt; overwrites your &lt;code&gt;cd&lt;/code&gt; shell builtin function!) but the output of all these tools is the same: They export environment variables so your Ruby code operates on a particular version of Ruby with a particular set of gems.&lt;/p&gt;

&lt;p&gt;Here’s a diff&lt;a href=&quot;#links-1&quot; name=&quot;cite-1&quot; class=&quot;cite&quot;&gt;[1]&lt;/a&gt; of the environment when we’re using one version of Ruby versus another:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ diff &amp;lt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;rvm use &lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;.2 &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; env&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &amp;lt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;rvm use &lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;.1 &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; env&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
1c1
&amp;lt; Using /Users/jackdanger/.rvm/gems/ruby-2.2.1
---
&amp;gt; Using /Users/jackdanger/.rvm/gems/ruby-2.1.5
&lt;span class=&quot;m&quot;&gt;13&lt;/span&gt;,14c13,14
&amp;lt; &lt;span class=&quot;nv&quot;&gt;GEM_HOME&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/Users/jackdanger/.rvm/gems/ruby-2.2.1
&amp;lt; &lt;span class=&quot;nv&quot;&gt;GEM_PATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/Users/jackdanger/.rvm/gems/ruby-2.2.1:/Users/jackdanger/.rvm/gems/ruby-2.2.1@global
---
&amp;gt; &lt;span class=&quot;nv&quot;&gt;GEM_HOME&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/Users/jackdanger/.rvm/gems/ruby-2.1.5
&amp;gt; &lt;span class=&quot;nv&quot;&gt;GEM_PATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/Users/jackdanger/.rvm/gems/ruby-2.1.5:/Users/jackdanger/.rvm/gems/ruby-2.1.5@global
19c19
&amp;lt; &lt;span class=&quot;nv&quot;&gt;IRBRC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/Users/jackdanger/.rvm/rubies/ruby-2.2.1/.irbrc
---
&amp;gt; &lt;span class=&quot;nv&quot;&gt;IRBRC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/Users/jackdanger/.rvm/rubies/ruby-2.1.5/.irbrc
37c37
&amp;lt; &lt;span class=&quot;nv&quot;&gt;MY_RUBY_HOME&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/Users/jackdanger/.rvm/rubies/ruby-2.2.1
---
&amp;gt; &lt;span class=&quot;nv&quot;&gt;MY_RUBY_HOME&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/Users/jackdanger/.rvm/rubies/ruby-2.1.5
42c42
&amp;lt; &lt;span class=&quot;nv&quot;&gt;PATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/Users/jackdanger/.rvm/gems/ruby-2.2.1/bin:...
---
&amp;gt; &lt;span class=&quot;nv&quot;&gt;PATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/Users/jackdanger/.rvm/gems/ruby-2.1.5/bin:...
51c51
&amp;lt; &lt;span class=&quot;nv&quot;&gt;RUBY_VERSION&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;ruby-2.2.1
---
&amp;gt; &lt;span class=&quot;nv&quot;&gt;RUBY_VERSION&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;ruby-2.1.5
103c103
&amp;lt; &lt;span class=&quot;nv&quot;&gt;rvm_ruby_string&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;ruby-2.2.1
---
&amp;gt; &lt;span class=&quot;nv&quot;&gt;rvm_ruby_string&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;ruby-2.1.5&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Looking at just the keys, you can see that RVM sets a little bit of internal stuff but mostly it just sets the &lt;code&gt;PATH&lt;/code&gt; for running commands like &lt;code&gt;ruby&lt;/code&gt; and &lt;code&gt;rspec&lt;/code&gt; and it sets &lt;code&gt;GEM_HOME&lt;/code&gt; and &lt;code&gt;GEM_PATH&lt;/code&gt; and such:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ diff &amp;lt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;rvm use &lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;.2 &amp;gt;/dev/null &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; env&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &amp;lt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;rvm use &lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;.1 &amp;gt;/dev/null &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; env&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
awk -F&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;{print $1}&amp;#39;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; awk &lt;span class=&quot;s1&quot;&gt;&amp;#39;{print $2}&amp;#39;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; sort &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; uniq

GEM_HOME
GEM_PATH
IRBRC
MY_RUBY_HOME
PATH
RUBY_VERSION
rvm_ruby_string&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Ruby core source has no unified way of resolving dependencies from these environmental variables. Rubygems is a project outside of Ruby core that is periodically imported in to the main Ruby trunk as a vendored dependency. It reads &lt;code&gt;GEM_HOME&lt;/code&gt; and &lt;code&gt;GEM_PATH&lt;/code&gt; and  such. And then Bundler is a separate project that overloads the Rubygems functionality.&lt;/p&gt;

&lt;p&gt;And all of this song and dance is to make it possible for you to type &lt;code&gt;require &apos;my_file&apos;&lt;/code&gt; and the right &lt;code&gt;my_file.rb&lt;/code&gt; or &lt;code&gt;my_file.bundle&lt;/code&gt;&lt;a href=&quot;#links-2&quot; name=&quot;cite-2&quot; class=&quot;cite&quot;&gt;[2]&lt;/a&gt; or &lt;code&gt;my_file.so&lt;/code&gt; is read from disk, parsed, and evaluated line-by-line.&lt;/p&gt;

&lt;p&gt;The actual implementation is full of edge cases but actually kind of simple to understand: &lt;code&gt;require&lt;/code&gt; and &lt;code&gt;gem&lt;/code&gt; are just methods in Ruby, not reserved keywords. It works like this:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Ruby core defines &lt;a href=&quot;https://github.com/ruby/ruby/blob/9d64a542094efdbcf8fc8b192750d6b0343665c3/load.c#L816&quot;&gt;Kernel.require&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;then Rubygems &lt;a href=&quot;https://github.com/ruby/ruby/blob/effdbf5936cc090a618e13c8f9a1b5412ebab2fa/lib/rubygems/core_ext/kernel_require.rb#L20&quot;&gt;saves require&lt;/a&gt; as &lt;code&gt;Kernel.gem_original_require&lt;/code&gt; for its own use but totally redefines &lt;code&gt;Kernel.require&lt;/code&gt; and &lt;a href=&quot;https://github.com/ruby/ruby/blob/effdbf5936cc090a618e13c8f9a1b5412ebab2fa/lib/rubygems/core_ext/kernel_gem.rb#L43&quot;&gt;defines&lt;/a&gt; a &lt;code&gt;Kernel.gem&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Then&lt;/em&gt; Bundler &lt;a href=&quot;https://github.com/bundler/bundler/blob/a88f0b989f5e3d4ad9e6618fc780f3e18e6a1f1d/lib/bundler/rubygems_integration.rb#L266-L276&quot;&gt;reverses&lt;/a&gt; what Rubygems did to &lt;code&gt;require&lt;/code&gt; and &lt;a href=&quot;https://github.com/bundler/bundler/blob/a88f0b989f5e3d4ad9e6618fc780f3e18e6a1f1d/lib/bundler/rubygems_integration.rb#L283-L318&quot;&gt;overrides&lt;/a&gt; the &lt;code&gt;gem&lt;/code&gt; method.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;right-but-why-do-we-need-bundle-exec&quot;&gt;Right, but why do we need “bundle exec”?&lt;/h2&gt;

&lt;p&gt;Let’s use the same diff trick to compare a process’s environment with and without &lt;code&gt;bundle exec&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ diff &amp;lt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;bundle &lt;span class=&quot;nb&quot;&gt;exec&lt;/span&gt; env&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &amp;lt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;env&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&amp;lt; &lt;span class=&quot;nv&quot;&gt;_ORIGINAL_GEM_PATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/Users/jackdanger/.rvm/gems/ruby-2.2.0:/Users/jackdanger/.rvm/gems/ruby-2.2.0@global
&amp;lt; &lt;span class=&quot;nv&quot;&gt;RUBYOPT&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;-rbundler/setup
&amp;lt; &lt;span class=&quot;nv&quot;&gt;RUBYLIB&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/Users/jackdanger/.rvm/gems/ruby-2.2.0/gems/bundler-1.10.5/lib&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That &lt;code&gt;-rANYTHING&lt;/code&gt; is the same as evaluating &lt;code&gt;require &quot;ANYTHING&quot;&lt;/code&gt; in Ruby source code. It’s weird that there’s no space but it, hilariously, allows there to be an &lt;a href=&quot;https://github.com/ruby/ruby/blob/effdbf5936cc090a618e13c8f9a1b5412ebab2fa/lib/ubygems.rb&quot;&gt;ubygems.rb&lt;/a&gt; so &lt;code&gt;ruby -rubygems&lt;/code&gt; works.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;RUBYOPT&lt;/code&gt; is the flag that’s passed to Ruby when invoked. For example, the following two lines are equivalent:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ ruby -rrails -e &lt;span class=&quot;s1&quot;&gt;&amp;#39;puts defined?(Rails)&amp;#39;&lt;/span&gt;
$ &lt;span class=&quot;nv&quot;&gt;RUBYOPT&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;-rrails ruby -e &lt;span class=&quot;s1&quot;&gt;&amp;#39;puts defined?(Rails)&amp;#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And &lt;code&gt;RUBYLIB&lt;/code&gt; is the default load path that Ruby searches when you &lt;code&gt;require&lt;/code&gt; something:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;puts :hi!&amp;#39;&lt;/span&gt; &amp;gt; myfile.rb
jackdanger $ ruby -rmyfile -e &lt;span class=&quot;s1&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;
/Users/jackdanger/.rvm/rubies/ruby-2.2.0/lib/ruby/2.2.0/rubygems/core_ext/kernel_require.rb:54:in &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;require&lt;span class=&quot;s1&quot;&gt;&amp;#39;: cannot load such file -- myfile (LoadError)&lt;/span&gt;
&lt;span class=&quot;s1&quot;&gt;        from /Users/jackdanger/.rvm/rubies/ruby-2.2.0/lib/ruby/2.2.0/rubygems/core_ext/kernel_require.rb:54:in `require&amp;#39;&lt;/span&gt;
jackdanger $ &lt;span class=&quot;nv&quot;&gt;RUBYLIB&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;. ruby -rmyfile -e &lt;span class=&quot;s1&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;
hi!&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Bundler’s &lt;code&gt;bundle exec&lt;/code&gt; requires the Bundler setup file which lets Bundler do all its file-finding hacks for when you later require something. But you may find in some cases that if your environment variables are already set up just right the requires might just work without Bundler’s help. Even then it doesn’t hurt to use &lt;code&gt;bundle exec&lt;/code&gt; so you always know you’re using the right versions of everything from the &lt;code&gt;Gemfile&lt;/code&gt; you have defined.&lt;/p&gt;

&lt;h3 id=&quot;do-i-have-to-keep-typing-this&quot;&gt;Do I have to keep typing this?&lt;/h3&gt;

&lt;p&gt;No, you don’t. You could hide this command behind aliases:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; cmd &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; rspec ruby rubocop rails&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;alias&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$cmd&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;bundle exec &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$cmd&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;done&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Special thanks to &lt;a href=&quot;https://github.com/agis&quot;&gt;Agis&lt;/a&gt; for reviewing this post and providing critical feedback.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;Footnotes:&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;links-1&quot;&gt;1.&lt;/a&gt; &lt;a href=&quot;#cite-1&quot;&gt; ^&lt;/a&gt;  That odd &lt;code&gt;&amp;lt;()&lt;/code&gt; notation I’m using for executing subcommands is pretty useful. Check this out:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ cat &amp;lt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;sleep &lt;span class=&quot;m&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; date&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &amp;lt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;sleep &lt;span class=&quot;m&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; date&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
Mon Jul &lt;span class=&quot;m&quot;&gt;13&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;18&lt;/span&gt;:32:09 EDT &lt;span class=&quot;m&quot;&gt;2015&lt;/span&gt;
Mon Jul &lt;span class=&quot;m&quot;&gt;13&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;18&lt;/span&gt;:32:09 EDT &lt;span class=&quot;m&quot;&gt;2015&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;cat&lt;/code&gt; is short for ‘concatenate’ and was originally written to squish two files together (&lt;code&gt;cat file1 file2 &amp;gt; file3&lt;/code&gt;). What I’m doing here is concatenating the output of two different subcomands. We can see how this works if I print the arguments to &lt;code&gt;cat&lt;/code&gt; to the screen rather than trying to read them and then print them:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &amp;lt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;sleep &lt;span class=&quot;m&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; date&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &amp;lt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;sleep &lt;span class=&quot;m&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; date&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
/dev/fd/11 /dev/fd/12&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The terminal not only creates subprocesses for the stuff in parentheses but makes a new file descriptor that’s readable by any program (&lt;code&gt;/dev/fd/{n}&lt;/code&gt;) and swaps that in as the argument to the current command. So it’s the same as if I’d done this:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ date &amp;gt; date1
$ date &amp;gt; date2
$ &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; date1 date2&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The bonus here is that the subcommands are executed in parallel, hence the datestamps matching on the above example. This allowed me to diff the relatively slow &lt;code&gt;rvm use &amp;amp;&amp;amp; env&lt;/code&gt; subcommand in half the time as would normally be required.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;links-2&quot;&gt;2.&lt;/a&gt; &lt;a href=&quot;#cite-2&quot;&gt; ^&lt;/a&gt; &lt;code&gt;.bundle&lt;/code&gt; is a packaging format for Mach executables on OS X. &lt;code&gt;.so&lt;/code&gt; is for shared objects (binaries meant to be used as libraries rather than executed directly).&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Getting Started as a Software Engineer</title>
   <link href="http://6brand.com/getting-started-as-a-software-engineer.html"/>
   <updated>2015-07-14T00:00:00-07:00</updated>
   <id>http://6brand.com/getting-started-as-a-software-engineer.html</id>
   <content type="html">&lt;p&gt;&lt;small&gt;
&lt;strong&gt;Audience&lt;/strong&gt;: total beginner software engineers &lt;br /&gt;
&lt;strong&gt;Reading time&lt;/strong&gt;: not that long
&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;This January Square hosted the 4th &lt;a href=&quot;https://squareup.com/code-camp&quot;&gt;College Code Camp&lt;/a&gt; by welcoming women who are studying engineering in college to &lt;a href=&quot;https://squareup.com/careers&quot;&gt;Square’s SF office&lt;/a&gt; for five days of nerdventure.&lt;/p&gt;

&lt;p&gt;I’m always really impressed with these students and I tell them in complete honesty that I’m really glad they’re doing what they’re doing so that one day I can work for them.&lt;br /&gt;
I’ve said the same when speaking to folks from &lt;a href=&quot;http://www.hackbrightacademy.com/&quot;&gt;Hack Bright&lt;/a&gt;, &lt;a href=&quot;https://www.codefellows.org/&quot;&gt;Code Fellows&lt;/a&gt;, &lt;a href=&quot;http://adadevelopersacademy.org/&quot;&gt;Ada Developers Academy&lt;/a&gt;, &lt;a href=&quot;https://generalassemb.ly/san-francisco&quot;&gt;General Assembly&lt;/a&gt;, and &lt;a href=&quot;http://www.hackreactor.com/&quot;&gt;Hack Reactor&lt;/a&gt;.&lt;br /&gt;
The response I get is just about always the same: The students laugh nervously, smile at me, and probably wonder why I think that joke is funny.&lt;br /&gt;
It’s not a joke though – they really are going to have bright careers.&lt;br /&gt;
Each one of the students currently struggling with the concept of recursion will, if they keep working at it, eventually get it and move on to reach some far further goal. Maybe they’ll build a service that attracts thousands of new users overnight or they’ll make the front page of Reddit or they’ll be condescended to on Hacker News. Then they’ll know they’ve made it in this ridiculous industry.&lt;br /&gt;
But at this point in their career where they’re talking to me those things are all a far-away dream. And it’s hard to see how to get from where they are to where they want to be.&lt;/p&gt;

&lt;h2 id=&quot;learn-to-code-in-three-and-a-half-days&quot;&gt;Learn to code in three and a half days&lt;/h2&gt;
&lt;p&gt;When I was starting my career in the mid-2000s there were two ways to educate myself: Reading the source code or giving up. The latter offers terrible odds of success.&lt;br /&gt;
Now there’s &lt;a href=&quot;https://www.coursera.org/&quot;&gt;Coursera&lt;/a&gt;, &lt;a href=&quot;http://teamtreehouse.com/&quot;&gt;Treehouse&lt;/a&gt;, &lt;a href=&quot;https://www.khanacademy.org/&quot;&gt;Khan Academy&lt;/a&gt;, any number of bootcamp-style programs (including the unbelievably good &lt;a href=&quot;http://adadevelopersacademy.org/&quot;&gt;Ada Developers Academy&lt;/a&gt;), &lt;a href=&quot;http://stackoverflow.com/&quot;&gt;Stack Overflow&lt;/a&gt;, &lt;a href=&quot;http://shop.oreilly.com/&quot;&gt;O’Reilly&lt;/a&gt; and basically the entire rest of the internet.&lt;br /&gt;
It’s now almost trivially easy to take your first steps as a software engineer.&lt;br /&gt;
In fact, thanks to &lt;a href=&quot;http://hourofcode.com/us&quot;&gt;Hour of Code&lt;/a&gt; there are tens of millions of people who’ve tried their hand at programming for the first time.&lt;/p&gt;

&lt;p&gt;I’m a huge proponent of getting people into engineering and I disregard the critics who say we’re letting prospective students underestimate how difficult it is. Underestimating the difficulty of a task is one of the most consistent character failings of an engineer. So anybody who thinks they can build a distributed messaging graph after 9 weeks is gonna fit right in.&lt;/p&gt;

&lt;p&gt;However.&lt;/p&gt;

&lt;h2 id=&quot;the-stuff-youre-missing&quot;&gt;The stuff you’re missing&lt;/h2&gt;

&lt;p&gt;The skills you have after a Coursera class or a multi-week code school are not enough to get a good job. Unless you’re either independently wealthy or happily poor you don’t really have time to futz around for a few months on hobby projects while making no money. Even more importantly, the skills you have aren’t enough to let you feel confident in your abilities. You can solve some simple problems but you’re going to spend all day faced with terms and concepts that are still far beyond you.&lt;/p&gt;

&lt;p&gt;More aggravating is you don’t even know what skills you’re lacking. If you interview you may get feedback that they’re “only looking for very senior people right now” which is code for “we don’t know how to train you and we actually need to hire somebody who can train us.” So I’ll break it down for you: You’re missing two large, entirely separate categories of skills.&lt;/p&gt;

&lt;h3 id=&quot;category-1-a-broad-knowledge-of-libraries-and-development-patterns&quot;&gt;Category 1: A broad knowledge of libraries and development patterns&lt;/h3&gt;
&lt;p&gt;The first category is what employers say they’re looking for: Senior experience in software engineering. They want somebody who knows &lt;a href=&quot;http://visualgo.net/&quot;&gt;every data structure&lt;/a&gt;. They want somebody who knows why Nginx can process hundreds of megabytes per second with almost zero CPU usage and they want somebody who knows the difference between a linearizable and non-linearizable system. Somebody who can debug a Linux box where all application processes are ‘zombied’ and can explain why Rust is an appropriate language for embedding inside a Ruby gem. They want somebody who can do TDD and write a parser for ARVUN in a day.&lt;/p&gt;

&lt;p&gt;Sound intimidating? Yeah, it’s totally intimidating. But you know what? Nobody knows all that stuff. I even made that last one up (ARVUN is just some random letters I typed). As a natural byproduct of your daily work you will absolutely collect these insights into how computers function. What you learn will be different than what your peers will learn. This means you’ll always think everybody around you is a genius for what they know and they’ll think the same thing of you. Software engineering is an infinite field&lt;a href=&quot;#links-1&quot; name=&quot;cite-1&quot; class=&quot;cite&quot;&gt;[1]&lt;/a&gt; so when a prospective employer lists stuff you should know they’re basically selecting a random set of acronyms that they’ve heard some of their peers mention. You already know stuff that they don’t even know that they need you to know.&lt;/p&gt;

&lt;p&gt;A fantastic example of the ridiculous breadth of knowledge required to build software is illustrated by &lt;a href=&quot;https://www.codefellows.org/blog/this-is-why-learning-rails-is-hard&quot;&gt;this Code Fellows blog post&lt;/a&gt;. I happen to know all of those things (because I learned them one at a time over about 8 years) but I have absolutely no idea how to, say, design a network. Seriously. No idea at all. Network engineers seem like gods to me and I to them.&lt;/p&gt;

&lt;p&gt;So you’re screwed – permanently – because you’ll never know most of engineering.&lt;/p&gt;

&lt;h3 id=&quot;category-2-comfort-with-your-language-and-fundamental-concepts&quot;&gt;Category 2: Comfort with your language and fundamental concepts&lt;/h3&gt;
&lt;p&gt;Luckily, those &lt;em&gt;aren’t&lt;/em&gt; the skills you need to get a good job. When I hire people at Square and when I’ve hired in the past I look for teachability and familiarity with the primitives of building software. No matter what your training or experience I can’t hire you if you’re unable to learn. No matter how junior you are if you know your tools and know how to build pieces of software with me guiding you through the hard parts I can hire you and I know you’ll keep learning and contributing for your whole tenure at my company.&lt;/p&gt;

&lt;p&gt;The largest blocker to your employment is that the tools of your trade don’t yet feel comfortable in your hands. You haven’t mastered your editor, you can’t reflexively set up a new project and get boilerplate code running while your mind is distracted. You haven’t yet tried all the wrong ways to write a recursive function. This is the primary thing keeping you from passing a coding interview (at a good company that actually tests your skill and doesn’t just ask you trick questions). Luckily, it’s also a set of skills that’ll help you be successful on the job as an engineer. Training yourself this way for an interview isn’t cheating yourself or your employer – it’ll really make you more valuable on the job.&lt;/p&gt;

&lt;p&gt;You’re going to have to ignore that whole first category of stuff. Learning how each piece of software works is a fun lifetime journey and you can always learn things right when you need to. But if you want to get your first programming job you’ll need to develop a real comfort with the primitive pieces of your craft.&lt;/p&gt;

&lt;h3 id=&quot;an-aside-how-to-actually-learn-to-program&quot;&gt;An aside: How to actually learn to program&lt;/h3&gt;
&lt;p&gt;Let’s get one thing straight: You can’t just watch a video online and know how to do something. This isn’t just about code. You can’t learn to sail a boat that way, you can’t learn to juggle that way, and you can’t learn to type that way. Unless you actually have a project and work on it until it’s done-ish and you face all the hurdles that crop up on your way you can’t develop your skill. And if you want to truly understand what you’ve been learning there’s one ancient, highly-successful method for making the knowledge fixed in your brain: Teach it.&lt;/p&gt;

&lt;p&gt;I learned Ruby on Rails at &lt;a href=&quot;https://railsforum.com&quot;&gt;Rails Forum&lt;/a&gt; way back in 2006. And I did it not by asking questions but by answering them. Somebody would be stuck with “How do I make an ActiveRecord query that uses multiple tables” or a similarly impossible question and I’d dive into the Rails source code to find an answer - even though I knew nothing more than the person who asked it. This is still the best way make concepts clear in your head. Find a project you want to complete to pick up the basics and teach somebody else those basics in order to master them.&lt;/p&gt;

&lt;h3 id=&quot;what-to-learn-learn-your-editor&quot;&gt;What to learn: Learn your editor&lt;/h3&gt;
&lt;p&gt;I can’t stress enough how much easier your whole career will go if you make it a habit of &lt;a href=&quot;https://www.shortcutfoo.com/&quot;&gt;memorizing shortcut keys&lt;/a&gt; and learning the advanced features of your editor. Whether you’re using Vim and Emacs like some 1980’s proto-hipster or Sublime Text like a modern day one there are advanced features in each that you don’t even know about. In every good editor you can select rectangular blocks of text and manipulate them. You can find all instances of a term in a single file or multiple files and modify them all at once. You can jump automatically from where a method or function is called to where it’s defined. Seriously, every editor can do this.&lt;/p&gt;

&lt;h3 id=&quot;what-to-learn-one-language&quot;&gt;What to learn: One language&lt;/h3&gt;
&lt;p&gt;Somebody you know is really excited about the hot new language. Ignore them like you would ignore your crazy uncle’s politics at Thanksgiving. Nod and smile and just keep working on whatever language you have started learning.&lt;br /&gt;
Every language is fine to learn because they’re all terrible. Just like human languages&lt;a href=&quot;#links-2&quot; name=&quot;cite-2&quot; class=&quot;cite&quot;&gt;[2]&lt;/a&gt; – each programming language can do some stuff super well and falls down at others. Ruby is elegant but psychotically inconsistent. Python is straightforward but will literally murder you if you try to upgrade to version 3. Java is powerful but will make you type the word ‘logger’ 5 times if you want to create a new logger (&lt;code&gt;Logger logger = Logger.loggerFactory.iHateMyself.CreateLogger()&lt;/code&gt;). Lisp and Haskell will allow you to represent human life in just a single, mathematically-provably perfect line but nobody will care. JavaScript is the blunted stump of what could have grown into a computer language.&lt;/p&gt;

&lt;p&gt;So learn a language and figure out how to express yourself in it. Learn its quirks and learn to love it despite its ugly parts. If you like your primary language start reading more about why it’s broken and terrible. It should probably take you about a week to figure out the serious limitations of any language. And only once you hate it a little would I trust you to build something important with it.&lt;/p&gt;

&lt;h3 id=&quot;what-to-learn-building-small-things&quot;&gt;What to learn: Building small things&lt;/h3&gt;
&lt;p&gt;The best developers I know aren’t the ones who’ve crafted some huge system (though many have). The best developers can start and finish a small project in a single day. Maybe it just mashes up Instagram data with their Google Calendar but it’ll be about fifty lines of code and it’ll do exactly one thing properly. The more of these you write the more confidence you will have when solving any kind of technical problem.&lt;/p&gt;

&lt;p&gt;I even have some suggestions for stuff to build as practice. These little things will give you the reflexes you need to pass a technical interview and they’ll also make the act of programming move from an intellectual exercise to muscle memory.&lt;/p&gt;

&lt;h4 id=&quot;project-1-building-a-hip-hop-name-generator&quot;&gt;Project #1: Building a hip-hop name generator.&lt;/h4&gt;

&lt;p&gt;This is an easy and a fun one. Pick a list of first words and a list of second words then randomly print bad rap names for people by combining one element from each. “Lil’ Dicey”, “Ebenezer Money”, “Shady Slurpdog”. Set aside an hour and you’ll be able to print randomly generated names to the screen. Skills you’ll learn: arrays, using randomness, concatenation, printing to the screen.&lt;/p&gt;

&lt;h4 id=&quot;project-2-building-a-word-search-solver&quot;&gt;Project #2: Building a word search solver.&lt;/h4&gt;
&lt;p&gt;You know those boring airport time-waster puzzles where there’s a grid of letters and you have to find the words in it? Make a program that can find the words ‘jack’, ‘danger’, and ‘coding’ in this:&lt;/p&gt;
&lt;pre&gt;&lt;code style=&quot;line-height: 1.3em;&quot;&gt;CRZJPHJ
OEEMAAS
DGUGCCJ
INSKNEK
NAKATAD
GDSHJED&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This’ll take you a couple hours if you’re familiar with your tools or all day if this kind of problem is new to you. Skills you’ll learn: depth-first or breadth-first search, nested arrays.&lt;/p&gt;

&lt;h4 id=&quot;project-3-generating-a-maze-on-a-screen&quot;&gt;Project #3: Generating a maze on a screen.&lt;/h4&gt;

&lt;p&gt;Give this one a full day. It requires solving two different problems: You need to figure out the logic of how to generate a maze and you need to decide on some way of drawing something on the screen. A primitive, perfectly acceptable way would be to print “|” and “_” characters on a screen to symbolize walls.&lt;br /&gt;
Here’s an example of a pretty sweet-looking one: &lt;a href=&quot;http://www.mazegenerator.net/&quot;&gt;mazegenerator.net&lt;/a&gt;&lt;br /&gt;
The way you should build this is by cheating as hard as you possibly can. Seriously, just Google “building a maze generator” and follow along with how other people have done it. Skills you’ll learn: recursion, depth-first search, managing multiple data structures at once.&lt;/p&gt;

&lt;h4 id=&quot;project-4-building-a-sudoku-solver&quot;&gt;Project #4: Building a sudoku solver.&lt;/h4&gt;

&lt;p&gt;SO. FUN. Okay, maybe not the funnest thing ever, but if you like Sudoku it’s a blast. Same instructions as above and I recommend cheating on this one as well. Peter Norvig has &lt;a href=&quot;http://norvig.com/sudoku.html&quot;&gt;a lovely and complete example&lt;/a&gt; of doing this in Python.&lt;/p&gt;

&lt;h4 id=&quot;project-5-project-euler&quot;&gt;Project #5: Project Euler&lt;/h4&gt;

&lt;p&gt;&lt;a href=&quot;https://projecteuler.net/&quot;&gt;Project Euler&lt;/a&gt; is kind of the gold standard for programming puzzles. It asks you to use any programming language in any environment you want to solve simple number questions. The first few problems are very easy and if you sort the problems by the number of people who’ve finished them you can find all the most accessible ones. Don’t worry if one is too tough, there are questions there for kids learning to code and questions for math Ph.Ds. Hopefully you’ll even find yourself accidentally learning the fun parts of math as you go. Project Euler will definitely make you a better developer because you’ll need to set up simple functions over and over and over and the nuts and bolts of programming will start to become muscle memory while you let your brain work on higher-level stuff.&lt;/p&gt;

&lt;h4 id=&quot;project-6-my-interview-question&quot;&gt;Project #6: My interview question&lt;/h4&gt;

&lt;p&gt;&lt;a href=&quot;http://jackdanger.github.io/bike-europe/&quot;&gt;Let’s Bike Across Europe!&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That link above is the question I would ask you if I were to interview you for a job. It will be harder to solve the problem on your own at home rather than alongside me because you don’t have me explaining the hard parts but you’re welcome to try it. Cheat as hard as you can. If you come in to interview at Square and I asked you that question and you say “I tried it at home until I was good at it - watch this!” and then you did it really well I’d just hire you on the spot. That kind of initiative is what makes people successful in this industry.&lt;/p&gt;

&lt;h2 id=&quot;youre-going-to-be-fine&quot;&gt;You’re going to be fine&lt;/h2&gt;
&lt;p&gt;With each of these (except the first) you’re sure to run into some walls where you feel stuck and when that happens I’d love if you reached out to me on &lt;a href=&quot;https://twitter.com/jackdanger&quot;&gt;Twitter&lt;/a&gt; and we’ll crowd-source some help.&lt;/p&gt;

&lt;p&gt;Even after building several projects you may still be feeling like computers are magic and you’re a dummy and maybe you don’t have what it takes to do this work. You may feel like everybody else ‘gets it’ and you’re missing something but don’t know what it is. You may even feel like everybody else is the same as each other and you’re the odd person out. Regardless, you’re going to do really well in this industry. You can type, you can think, and you can make computers obey you. In a couple years it’ll be your turn to teach newcomers the basics and to help them calm down and trust that they can do this. Until then just practice with your editor, practice with your language, and above all remember that you &lt;em&gt;do&lt;/em&gt; have what it takes and you’re going to be fine.&lt;/p&gt;

&lt;p&gt;Special thanks to the engineers &lt;a href=&quot;http://lizmrush.com/&quot;&gt;Liz Rush&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/daniellesublett&quot;&gt;Danielle Sublett&lt;/a&gt;, and &lt;a href=&quot;https://twitter.com/DavidaMarion&quot;&gt;Davida Marion&lt;/a&gt; who reviewed drafts of this post.&lt;/p&gt;

&lt;p&gt;Footienotes:&lt;a name=&quot;links&quot;&gt; &lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;links-1&quot;&gt;1.&lt;/a&gt; &lt;a href=&quot;#cite-1&quot;&gt; ^&lt;/a&gt; The process of learning software involves writing&lt;br /&gt;
   software which adds to the overall corpus of what there is to learn.&lt;br /&gt;
   We have ten million people making new (often confusing APIs) and the&lt;br /&gt;
   percentage of the whole that even the experts know is only&lt;br /&gt;
   decreasing.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;links-2&quot;&gt;2.&lt;/a&gt; &lt;a href=&quot;#cite-2&quot;&gt; ^&lt;/a&gt; Chinese is terrible for crosswords, a complete set of rules for English is impossibly large, Arabic and Hebrew don’t write down their vowels, Proto-Indo European had the singular, the plural, and a separate number form for “more than two”, Bengali distinguishes ‘bh’, ‘b’, ‘p’, and ‘ph’ (the only variance is the timing of when your vocal cords vibrate), Finnish has 16 (!!) cases, and French is wrong.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Danger's rules for working remotely</title>
   <link href="http://6brand.com/danger-s-rules-for-working-remotely.html"/>
   <updated>2015-07-11T00:00:00-07:00</updated>
   <id>http://6brand.com/danger-s-rules-for-working-remotely.html</id>
   <content type="html">&lt;p&gt;At the time of this writing I’ve been working full time in the Square San Francisco office for about four years. The culture here relies on high-bandwidth interpersonal interactions and working in close physical collaboration. Some of my colleagues, when they work from home for a day or two, will return to the office and say they’re happy to be back because home “has too many distractions”. Others can’t wait to get home and away from the distractions of the office to focus.&lt;/p&gt;

&lt;p&gt;My career in professional software started when I was 21 and until I joined Square 8 years later I only ever worked remotely and with flexible hours. The first three or so years I struggled to keep a schedule and stay on task but I eventually found a system that works for me really well. So well, actually, that when I joined Square my productivity took a hit as I tried to adjust to the distractions of a communal working space. Here are the rules that I developed for myself over most of a decade to make remote, flexible work more productive than being physically close to my colleagues.&lt;/p&gt;

&lt;h2 id=&quot;rule-1-dress-up&quot;&gt;Rule #1 Dress up&lt;/h2&gt;

&lt;p&gt;One of the side-effects of going to an office that we tend to miss is that it forces us to look and act respectably. When you dress well you’re going to feel good. It’s not just for other people - it’s something you do for yourself.&lt;/p&gt;

&lt;p&gt;One of the oft-lauded benefits of working from home is the ability to work naked or be in your underwear or pajamas. The fact that you &lt;em&gt;can&lt;/em&gt; do this is great. But this should be exceedingly rare. Because the moment it no longer feels special to work in your pajamas you become a human who lives in your pajamas. It’s a self-image you have to spend energy fighting against if you want to feel professional.&lt;/p&gt;

&lt;p&gt;I once founded a company with a partner and worked for a full year on it without ever seeing him or any of the rest of our company in person. Everything was over the phone, email, chat, or laggy, low-fidelity video chat. It worked great. But it also meant that I could have spent 12 full months wearing nothing but the same greasy clothes and forewent every form of personal hygiene until I cried myself to sleep every night in a sweaty ball of self-disrespect.&lt;/p&gt;

&lt;p&gt;So don’t skimp on nice clothes and a good morning bathing routing. You’re not doing it because somebody else expects it of you, you’re doing it because you’re a professional and you’re good at what you do and you should look good doing it - even if the only person who sees you is yourself in the mirror.&lt;/p&gt;

&lt;h2 id=&quot;rule-2-dont-touch-your-computer-until-you-go-outside-once&quot;&gt;Rule #2: Don’t touch your computer until you go outside once&lt;/h2&gt;

&lt;p&gt;This is both the hardest rule to follow and the easiest. Years ago I had a morning workout routine that saw me at the gym at 7am. Once I stopped going so early I just began work that much earlier. And then I started hating every day because I’d wake up and immediately open my email. There were a few days where the sun had set and I was still in bed, furiously trying to do something that seemed really urgent.&lt;/p&gt;

&lt;p&gt;Maybe you don’t need this rule but I am a person of extremes. So, to keep myself from forgetting about the unfathomable wonder of our planet, I go outside – even just to walk around the block – before my email gets a chance to eat me alive. As a side effect this forces me to also put on clothes which, if I want to keep them clean, forces me to shower.&lt;/p&gt;

&lt;h2 id=&quot;rule-3-initiate-relational-connections&quot;&gt;Rule #3: Initiate relational connections&lt;/h2&gt;

&lt;p&gt;The Square SF office has some 600 people all in one giant room. This is amazing when you want to make friends out of your colleagues; there are so many people around that it’s really easy to start a conversation.&lt;/p&gt;

&lt;p&gt;But even having so many lovely people all in the same place every day isn’t enough to prevent loneliness. Building a relationship requires more than “Hi, how are you? I’m fine” with a hundred different people each day - it takes initiating vulnerably and sharing your real self with someone.&lt;/p&gt;

&lt;p&gt;The difference between how this works in an office or remotely is only in the very first step. If you see someone while walking past their desk then you might stop to chat. If you’re remote you have to go initiate a chat. You can do this without having a work-related question, without any particular topic to discuss, solely for the purpose of building a relationship.&lt;/p&gt;

&lt;p&gt;One-on-one meetings serve this function but so do watercooler-style chat rooms and end-of-week Google Hangouts where everybody in the team joins and just plays around with putting on funny hats and sharing jokes. Getting past that first step – just saying you want to connect with somebody – is the only distinct skill needed to work remotely.&lt;/p&gt;

&lt;h2 id=&quot;rule-4-record-your-daily-accomplishments&quot;&gt;Rule #4: Record your daily accomplishments&lt;/h2&gt;

&lt;p&gt;An unfortunate truth of office work is that we evaluate the output of our colleagues and reports by how much time they seem to spend at work. If they’re in the office before us and leave after us we say they’re hard workers. And if we don’t see them for two weeks we assume they’re at home marathoning Netflix.&lt;/p&gt;

&lt;p&gt;In my opinion this creates work cultures where there’s no distinction between the cost of the work and the value. The cost is how much of your time and energy and willpower and emotional investment it took to perform a task. And the value is how much competitive advantage and/or profit was provided to the business. Your company should seek to minimize its costs and maximize value, right? Which would mean minimizing how much of employee time is spent at work doing non-valuable things. And maximizing what each person produces.&lt;/p&gt;

&lt;p&gt;Sadly, if you don’t provide a clear story about the value you provide you’ll be measured by the cost you incur working. If you want to prove your value to your colleagues/lead/clients you need to actually communicate what you’ve accomplished. Not what you’re working on – your accomplishments. When your face isn’t visible your output neds to be. I did this for years and it allowed me to find tasks that took only an hour but would provide a full day’s value. Then I could either take off the rest of the day or, more likely, work on things that I wanted to do that I knew wouldn’t have a direct visible output.&lt;/p&gt;

&lt;p&gt;When I first started managing a team at Square I set up an &lt;a href=&quot;https://idonethis.com&quot;&gt;iDoneThis.com&lt;/a&gt; account that asked each of us the same question every evening: “What is different in the world because of your work today?” I like this question because you don’t get to say how you spent your time. I don’t care how somebody I’m paying spent their time – I care what they accomplished. And I’m not interested in providing an incentive structure that rewards worthless, hard tasks.&lt;/p&gt;

&lt;p&gt;This is one of the great liberations of remote work – you can just think about the value. What have you &lt;em&gt;actually&lt;/em&gt; accomplished today? Is your client/customer satisfied? If so, you did a great job, even if you did it in 15 minutes.&lt;/p&gt;

&lt;h2 id=&quot;rule-5-spine&quot;&gt;Rule #5: SPINE&lt;/h2&gt;

&lt;p&gt;Several years ago a close friend pointed out to me that it was obvious to him why I’d get depressed during the work day. He introduced me to a silly acronym “SPINE” that represents the things you need to get each and every day.&lt;/p&gt;

&lt;h3 id=&quot;sleep&quot;&gt;Sleep&lt;/h3&gt;
&lt;p&gt;A full night’s sleep, no exceptions. If you report to me and you didn’t get enough sleep the night before I’ll ask you to take an afternoon nap. We’re about as useful working while sleep-deprived as we are driving while sleep-deprived: You can do most of it fine but you’ll miss a few details and that can make all the difference.&lt;/p&gt;

&lt;h3 id=&quot;pleasure&quot;&gt;Pleasure&lt;/h3&gt;
&lt;p&gt;This might be reading a book or dancing to music. It might be sex or going to a movie. Whatever you do for pleasure, do at least one of those things every day.&lt;/p&gt;

&lt;h3 id=&quot;intimacy&quot;&gt;Intimacy&lt;/h3&gt;
&lt;p&gt;We need intimacy with someone every day. Parents who’re stuck at home with little ones understand this best when they realize they’d chop off an arm for a single adult conversation. Just being close to someone who understands you whom you can understand makes a world of difference. I believe this is something that needs to be scheduled in alongside work stuff at a very high priority.&lt;/p&gt;

&lt;h3 id=&quot;nutrition&quot;&gt;Nutrition&lt;/h3&gt;
&lt;p&gt;One of the great advantages that Silicon Valley-style startups have is that they provide healthy food to their employees. In my time at Square I’ve seen people look healthier a few weeks into joining the company thanks to the food.&lt;/p&gt;

&lt;h3 id=&quot;exercise&quot;&gt;Exercise&lt;/h3&gt;
&lt;p&gt;When I was first dating my ex-wife we’d plan a day together and she would ask “But when am I going to get exercise?” I was baffled the first few times because she had just exercised the previous day, why’s she doing it again? After a while that question burrowed into me and I started asking it, too. Between 2006 and 2009 I lost 50 pounds and transitioned from being a non-runner to finishing a half-Ironman. Yeah, this is me all braggy-braggy but it’s true and it’s because I made exercise a daily thing, not a sometimes thing. Walking totally counts. So does dancing. Anything where I move my body.&lt;/p&gt;

&lt;p&gt;These rules could be distilled into just two: Take care of yourself and take care of the needs of the person who’s paying you. If you do that then there’s no reason you can’t make your job happen in a hammock on a beach somewhere.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Figuring out what's in any Unix file</title>
   <link href="http://6brand.com/figuring-out-what-s-in-any-unix-file.html"/>
   <updated>2015-06-28T00:00:00-07:00</updated>
   <id>http://6brand.com/figuring-out-what-s-in-any-unix-file.html</id>
   <content type="html">&lt;p&gt;If you have a file that ends in a known extension like &lt;code&gt;list.txt&lt;/code&gt; or &lt;code&gt;mountain.jpg&lt;/code&gt; then you can guess what’s inside it. But how do you actually know? After all, you could &lt;code&gt;mv list.txt kitten.png&lt;/code&gt; and suddenly your plain text file is pretending to be an image of an adorable little cat.&lt;/p&gt;

&lt;p&gt;If the contents of the file are text then the easiest way to look inside is the &lt;code&gt;head&lt;/code&gt; command:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;&amp;gt; $ head kitten.png
Go to the store and buy:
* Overpriced avocados
* Organic lawn furniture
* Seven gallons of &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;% milk&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;head&lt;/code&gt; shows you the first 10 (by default) lines of any file. And as long as it’s a text file with newline characters signifying line breaks then this shows you something readable. But what if it’s actually an image file?&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;&amp;gt; $ head actually_a_kitten.png
âPNG
IæãR
+iCCPICC Profile&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;œùíw&lt;span class=&quot;se&quot;&gt;\ì&lt;/span&gt;˚æŸÉïÜå∞˜^Dˆô≤D!&lt;span class=&quot;nv&quot;&gt;$1&lt;/span&gt;$
                                        ≈Öà
T.ê¢à´eHùà&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;HQk±ä®®4ëœßıˆˆ~û&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;ê&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;∏º
⎼▒☃┌⎽ └▒⎽├e⎼ $&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Oh lovely. That last line there (ending in a &lt;code&gt;$&lt;/code&gt;) is actually the prompt for your next command. We just accidentally sent so many weird characters to the screen that some of them changed the encoding of your terminal. No fun.&lt;/p&gt;

&lt;p&gt;A safer way to do this would be with the &lt;code&gt;less&lt;/code&gt; command which creates a new full-terminal buffer and safely returns you to your (working) prompt when you’re done. But even then you need to parse this binary with your eyes and hope that the &lt;code&gt;âPNG&lt;/code&gt; is, in fact, a sign that this is a valid png file.&lt;/p&gt;

&lt;h2 id=&quot;the-file-command&quot;&gt;The &lt;code&gt;file&lt;/code&gt; command&lt;/h2&gt;

&lt;p&gt;Luckily, any Unixy OS has the &lt;code&gt;file&lt;/code&gt; utility installed. This is a program that will try to guess the type of a file based on examining details of the contents.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;&amp;gt; $ file actually_a_kitten.png
actually_a_kitten.png: PNG image data, &lt;span class=&quot;m&quot;&gt;8&lt;/span&gt; x &lt;span class=&quot;m&quot;&gt;8&lt;/span&gt;, &lt;span class=&quot;m&quot;&gt;8&lt;/span&gt;-bit/color RGBA, non-interlaced&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Not only do we know for sure that it’s a PNG but we know the resolution and the color depth. Handy.&lt;/p&gt;

&lt;h2 id=&quot;how-does-file-work&quot;&gt;How does &lt;code&gt;file&lt;/code&gt; work?&lt;/h2&gt;

&lt;p&gt;This utility first tries to make a distinction about whether the argument is a file that’s safe to print on the screen (“text”), executable, or any other kind of data.&lt;/p&gt;

&lt;p&gt;The procedure for determining this is to first look at the file on disk and see if it’s special in some way, empty, or if there’s some other significant issue with it that makes examining the contents unnecessary. It basically runs the &lt;code&gt;stat&lt;/code&gt; command on your file:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;&amp;gt; $ stat kitten.png
  File: &lt;span class=&quot;s1&quot;&gt;&amp;#39;kitten.png&amp;#39;&lt;/span&gt;
  Size: &lt;span class=&quot;m&quot;&gt;3084&lt;/span&gt;            Blocks: &lt;span class=&quot;m&quot;&gt;8&lt;/span&gt;          IO Block: &lt;span class=&quot;m&quot;&gt;4096&lt;/span&gt;   regular file
Device: fd00h/64768d    Inode: &lt;span class=&quot;m&quot;&gt;533679&lt;/span&gt;      Links: &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;
Access: &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0644&lt;/span&gt;/-rw-r--r--&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;  Uid: &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1193&lt;/span&gt;/jackdanger&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;   Gid: &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1193&lt;/span&gt;/jackdanger&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
Access: &lt;span class=&quot;m&quot;&gt;2015&lt;/span&gt;-06-28 &lt;span class=&quot;m&quot;&gt;07&lt;/span&gt;:35:35.864034633 +0000
Modify: &lt;span class=&quot;m&quot;&gt;2015&lt;/span&gt;-06-28 &lt;span class=&quot;m&quot;&gt;07&lt;/span&gt;:35:35.864034633 +0000
Change: &lt;span class=&quot;m&quot;&gt;2015&lt;/span&gt;-06-28 &lt;span class=&quot;m&quot;&gt;07&lt;/span&gt;:35:35.864034633 +0000&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It’s a file (not a symlink or a directory) and it takes up 8 blocks of space, using a total of 3084 bytes. Alright then, let’s read it and figure out what’s inside.&lt;/p&gt;

&lt;h2 id=&quot;finding-the-magic-on-your-computer&quot;&gt;Finding the magic on your computer&lt;/h2&gt;
&lt;p&gt;When I first learned how this worked &lt;a href=&quot;https://twitter.com/3ameam&quot;&gt;the person&lt;/a&gt; showing me the ropes asked “Do you want to see where the magic is?” and I was utterly confused. Then he ran &lt;code&gt;man file&lt;/code&gt; and pointed out that the process of determining what’s inside a file from individual heuristics is, in fact, known as magic.&lt;/p&gt;

&lt;p&gt;Or, or more specifically:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;&amp;gt; $ man file &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; tr &lt;span class=&quot;s1&quot;&gt;&amp;#39; &amp;#39;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;\n&amp;quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; grep /magic  &lt;span class=&quot;c1&quot;&gt;# this tr will swap spaces for newlines&lt;/span&gt;
/etc/magic
/etc/magic,
/usr/share/misc/magic
/usr/share/misc/magic.mgc
/usr/share/misc/magic.mgc,&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Before we look inside one of these files by hand let’s practice using &lt;code&gt;file&lt;/code&gt; itself:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;&amp;gt; $ file /usr/share/misc/magic.mgc
/usr/share/misc/magic: symbolic link to &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;../file/magic.mgc&lt;span class=&quot;err&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Oh, that didn’t even inspect the contents of the file – it stopped at the &lt;code&gt;stat&lt;/code&gt; step. What did it see there?&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;&amp;gt; $ stat /usr/share/misc/magic.mgc
  File: ‘/usr/share/misc/magic.mgc’ -&amp;gt; ‘../file/magic.mgc’
  Size: &lt;span class=&quot;m&quot;&gt;17&lt;/span&gt;              Blocks: &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;          IO Block: &lt;span class=&quot;m&quot;&gt;4096&lt;/span&gt;   symbolic link
Device: ca01h/51713d    Inode: &lt;span class=&quot;m&quot;&gt;2023&lt;/span&gt;        Links: &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;
Access: &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0777&lt;/span&gt;/lrwxrwxrwx&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;  Uid: &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;    &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;/    root&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;   Gid: &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;    &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;/    root&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
Access: &lt;span class=&quot;m&quot;&gt;2015&lt;/span&gt;-06-28 &lt;span class=&quot;m&quot;&gt;08&lt;/span&gt;:12:44.599057183 +0000
Modify: &lt;span class=&quot;m&quot;&gt;2014&lt;/span&gt;-07-10 &lt;span class=&quot;m&quot;&gt;17&lt;/span&gt;:48:04.000000000 +0000
Change: &lt;span class=&quot;m&quot;&gt;2014&lt;/span&gt;-12-15 &lt;span class=&quot;m&quot;&gt;08&lt;/span&gt;:35:19.791057183 +0000
 Birth: -&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Yeah, I see the words ‘symbolic link’ there for sure. Now let’s follow the symlink and see what’s really inside it:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;&amp;gt; $ readlink -f /usr/share/misc/magic.mgc
/usr/share/file/magic.mgc  &lt;span class=&quot;c1&quot;&gt;# The following is identical to:&lt;/span&gt;
&amp;gt; $ file &lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;readlink -f !$&lt;span class=&quot;k&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# &amp;quot;file /usr/share/file/magic.mgc&amp;quot;&lt;/span&gt;
/usr/share/file/magic.mgc: magic binary file
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; file&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; cmd &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;version &lt;span class=&quot;m&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;little endian&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is great. It knows this file so well that it knows it’s its own magic file-detection file. So what’s inside it?&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;&amp;gt; $ less /usr/share/file/magic.mgc
BINARY DATA STUFF&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Yech. How about one of the others?&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;&amp;gt; $ head -n &lt;span class=&quot;m&quot;&gt;15&lt;/span&gt; /usr/share/file/magic
&lt;span class=&quot;c1&quot;&gt;##------------------------------------------------------------------------------&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;## $File: acorn,v 1.5 2009/09/19 16:28:07 christos Exp $&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;## acorn:  file(1) magic for files found on Acorn systems&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;##&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;## RISC OS Chunk File Format&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;## From RISC OS Programmer&amp;#39;s Reference Manual, Appendix D&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;## We guess the file type from the type of the first chunk.&lt;/span&gt;
&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;       lelong          0xc3cbc6c5      RISC OS Chunk data
&amp;gt;12     string          OBJ_            &lt;span class=&quot;se&quot;&gt;\b&lt;/span&gt;, AOF object
&amp;gt;12     string          LIB_            &lt;span class=&quot;se&quot;&gt;\b&lt;/span&gt;, ALF library

&lt;span class=&quot;c1&quot;&gt;# RISC OS AIF, contains &amp;quot;SWI OS_Exit&amp;quot; at offset 16.&lt;/span&gt;
&lt;span class=&quot;m&quot;&gt;16&lt;/span&gt;      lelong          0xef000011      RISC OS AIF executable&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now we’re talking. This format is a series of specific checks for byte values in a file. The first couple examples are kinda hard to make sense of so I’ll skip down to a simpler one:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;       string          &lt;span class=&quot;se&quot;&gt;\x&lt;/span&gt;89PNG&lt;span class=&quot;se&quot;&gt;\x&lt;/span&gt;0d&lt;span class=&quot;se&quot;&gt;\x&lt;/span&gt;0a&lt;span class=&quot;se&quot;&gt;\x&lt;/span&gt;1a&lt;span class=&quot;se&quot;&gt;\x&lt;/span&gt;0a         PNG image data
!:mime  image/png
&amp;gt;16     belong          x               &lt;span class=&quot;se&quot;&gt;\b&lt;/span&gt;, %ld x
&amp;gt;20     belong          x               %ld,
&amp;gt;24     byte            x               %d-bit
&amp;gt;25     byte            &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;               grayscale,
&amp;gt;25     byte            &lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;               &lt;span class=&quot;se&quot;&gt;\b&lt;/span&gt;/color RGB,
&amp;gt;25     byte            &lt;span class=&quot;m&quot;&gt;3&lt;/span&gt;               colormap,
&amp;gt;25     byte            &lt;span class=&quot;m&quot;&gt;4&lt;/span&gt;               gray+alpha,
&amp;gt;25     byte            &lt;span class=&quot;m&quot;&gt;6&lt;/span&gt;               &lt;span class=&quot;se&quot;&gt;\b&lt;/span&gt;/color RGBA,
&lt;span class=&quot;c1&quot;&gt;#&amp;gt;26    byte            0               deflate/32K,&lt;/span&gt;
&amp;gt;28     byte            &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;               non-interlaced
&amp;gt;28     byte            &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;               interlaced&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This means “If the string of bytes starting at position 0 are as follows then it’s a ‘PNG image data’”. Each of the lines starting with &lt;code&gt;&amp;gt;&lt;/code&gt; can refine the result, adding more data to it. Apparently it’s part of the PNG format that if the 25th byte is a 4 then this is a gracscale image with an alpha channel. Cool.&lt;/p&gt;

&lt;p&gt;Hey, we can detect Photoshop files, too!&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;       string          8BPS Adobe Photoshop Image
!:mime  image/vnd.adobe.photoshop
&amp;gt;4   beshort &lt;span class=&quot;m&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;PSB&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&amp;gt;18  belong  x &lt;span class=&quot;se&quot;&gt;\b&lt;/span&gt;, %d x
&amp;gt;14  belong  x %d,
&amp;gt;24  beshort &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; bitmap
&amp;gt;24  beshort &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt; grayscale
&amp;gt;&amp;gt;12 beshort &lt;span class=&quot;m&quot;&gt;2&lt;/span&gt; with alpha
&amp;gt;24  beshort &lt;span class=&quot;m&quot;&gt;2&lt;/span&gt; indexed
&amp;gt;24  beshort &lt;span class=&quot;m&quot;&gt;3&lt;/span&gt; RGB
&amp;gt;&amp;gt;12 beshort &lt;span class=&quot;m&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\b&lt;/span&gt;A
&amp;gt;24  beshort &lt;span class=&quot;m&quot;&gt;4&lt;/span&gt; CMYK
&amp;gt;&amp;gt;12 beshort &lt;span class=&quot;m&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\b&lt;/span&gt;A
&amp;gt;24  beshort &lt;span class=&quot;m&quot;&gt;7&lt;/span&gt; multichannel
&amp;gt;24  beshort &lt;span class=&quot;m&quot;&gt;8&lt;/span&gt; duotone
&amp;gt;24  beshort &lt;span class=&quot;m&quot;&gt;9&lt;/span&gt; lab
&amp;gt;12  beshort &amp;gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;
&amp;gt;&amp;gt;12  beshort x &lt;span class=&quot;se&quot;&gt;\b&lt;/span&gt;, %dx
&amp;gt;12  beshort &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\b&lt;/span&gt;,
&amp;gt;22  beshort x %d-bit channel
&amp;gt;12  beshort &amp;gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\b&lt;/span&gt;s&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;There are some 500 known formats in here (&lt;code&gt;egrep -c &apos;^# .* file&apos; /usr/share/misc/magic&lt;/code&gt;) detecting all kinds of things. How correct is this set of heuristics, though? Since it’s just looking for key data and ignoring most other bytes is it possible to fool it?&lt;/p&gt;

&lt;p&gt;To generate fake data we’re going to read from &lt;code&gt;/dev/urandom&lt;/code&gt; and write it straight to standard out (i.e. your screen).  we’ll do this 512 bytes at a time and pipe it straight to &lt;code&gt;file&lt;/code&gt; as a special (&lt;code&gt;-s&lt;/code&gt;) file:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;&amp;gt; $ dd &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/dev/urandom &lt;span class=&quot;nv&quot;&gt;bs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;512&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; file -s -
/dev/stdin: data&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Okay, not much. It’s “data”. Great. But if we try that in a bash loop…&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;&amp;gt; $ &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; _ &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;..20&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; dd &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/dev/urandom &lt;span class=&quot;nv&quot;&gt;bs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;512&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; file -s -&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;done&lt;/span&gt;
/dev/stdin: data
/dev/stdin: data
/dev/stdin: data
/dev/stdin: data
/dev/stdin: data
/dev/stdin: data
/dev/stdin: data
/dev/stdin: data
/dev/stdin: data
/dev/stdin: data
/dev/stdin: data
/dev/stdin: data
/dev/stdin: data
/dev/stdin: data
/dev/stdin: MPEG ADTS, layer III, v1,  &lt;span class=&quot;m&quot;&gt;40&lt;/span&gt; kbps, &lt;span class=&quot;m&quot;&gt;48&lt;/span&gt; kHz, Monaural
/dev/stdin: data
/dev/stdin: data
/dev/stdin: data
/dev/stdin: data
/dev/stdin: data
/dev/stdin: data&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Wait. What? What’s an MPEG ADTS file? Doesn’t matter, we generated data that fit the profile of it with just a few bytes in the right place.&lt;/p&gt;

&lt;p&gt;And if we run this in a loop and ignore the misses we see way more interesting stuff.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;&amp;gt; $ &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; :&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; dd &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/dev/urandom &lt;span class=&quot;nv&quot;&gt;bs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;512&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; file -s - &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; grep -v &lt;span class=&quot;s1&quot;&gt;&amp;#39;: data&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;done&lt;/span&gt;
/dev/stdin: Sendmail frozen configuration  - &lt;span class=&quot;nv&quot;&gt;version&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\2&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;36&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\2&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;07&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\0&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;21&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\0&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;33&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\3&lt;/span&gt;16h&lt;span class=&quot;se&quot;&gt;\3&lt;/span&gt;12d&lt;span class=&quot;se&quot;&gt;\2&lt;/span&gt;36i&lt;span class=&quot;se&quot;&gt;\3&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;26&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\0&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;33&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\2&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;36&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\3&lt;/span&gt;50C&lt;span class=&quot;se&quot;&gt;\2&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;34&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\3&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;73&lt;/span&gt;
/dev/stdin: &lt;span class=&quot;m&quot;&gt;8086&lt;/span&gt; relocatable &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;Microsoft&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
/dev/stdin: hp200 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;68010&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; BSD
/dev/stdin: Sendmail frozen configuration  - version &lt;span class=&quot;se&quot;&gt;\3&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\3&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;17&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\0&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;22&lt;/span&gt;?&lt;span class=&quot;se&quot;&gt;\3&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\2&lt;/span&gt;72s+^&lt;span class=&quot;se&quot;&gt;\0&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;21&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\0&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\2&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\2&lt;/span&gt;34Q&lt;span class=&quot;se&quot;&gt;\3&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;41&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\3&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;26&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\3&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;20&lt;/span&gt;
/dev/stdin: SysEx File - Fujitsu
/dev/stdin: DBase &lt;span class=&quot;m&quot;&gt;3&lt;/span&gt; data file
/dev/stdin: DBase &lt;span class=&quot;m&quot;&gt;3&lt;/span&gt; data file &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;899713281&lt;/span&gt; records&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
/dev/stdin: MPEG-4 LOAS, single stream
/dev/stdin: DBase &lt;span class=&quot;m&quot;&gt;3&lt;/span&gt; data file with memo&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;s&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1054998150&lt;/span&gt; records&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
/dev/stdin: Dyalog APL version &lt;span class=&quot;m&quot;&gt;219&lt;/span&gt; .105&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This really is magic, then, in the sense that this isn’t predictable and isn’t super reliable. But it’s still more effective than trying to cat it to your screen and look at the bytes yourself.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Essential terminal commands for new engineers</title>
   <link href="http://6brand.com/essential-terminal-commands-for-new-engineers.html"/>
   <updated>2015-02-04T00:00:00-08:00</updated>
   <id>http://6brand.com/essential-terminal-commands-for-new-engineers.html</id>
   <content type="html">&lt;p&gt;These are often called “bash shortcuts” or “bash tips” but, really, these apply to multiple different shell programs. Bash, ZSH (“zee shell”), etc. and any program that uses a library called ‘readline’ in it all work with (most) of the stuff on this page.&lt;/p&gt;

&lt;p&gt;There are literally thousands of these kinds of shortcuts that you could adopt as part of your daily workflow but I’m deliberately presenting just the most commonly useful ones that are truly worth your time. My promise to you: learn these by heart and you’ll move twice as fast in the terminal for the rest of your career.&lt;/p&gt;

&lt;h2 id=&quot;reusing-parts-of-previous-commands&quot;&gt;Reusing parts of previous commands&lt;/h2&gt;

&lt;h3 id=&quot;the--shortcut&quot;&gt;The !$ shortcut&lt;/h3&gt;

&lt;p&gt;Most of the commands you type look something like this:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code&gt;$ command_name --some --arguments filename
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The file that you’re working with is the most important part of this because you’re probably not just going to do one thing with that file. More likely you’ll call &lt;code&gt;less filename&lt;/code&gt; on it to take a look inside or &lt;code&gt;python filename&lt;/code&gt; to run it or &lt;code&gt;vim filename&lt;/code&gt; to edit it or &lt;code&gt;cat filename&lt;/code&gt; to pipe it to some program or maybe &lt;code&gt;grep filename&lt;/code&gt; to check if there’s a specific word or phrase inside it.&lt;/p&gt;

&lt;p&gt;Because the filename is the last argument it’s worth practicing the terminal shortcut for inserting the last argument of the previous command into your current one. Try this out in your terminal right now to see what I mean:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code&gt;# Making a file, examining it, giving it an extension, and making sure it has what we need
$ echo &quot;My name is&quot; &amp;gt;&amp;gt; somefile
$ echo &quot;Jack Danger&quot; &amp;gt;&amp;gt; somefile
$ less somefile
$ mv somefile somefile.text
$ ls -lAG somefile.text
$ grep &quot;Jack Danger&quot; somefile.text
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;How many times did you just type “somefile”? Now try typing out this one:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code&gt;$ echo &quot;My name is&quot; &amp;gt;&amp;gt; somefile
$ echo &quot;Jack Danger&quot; &amp;gt;&amp;gt; !$
$ less !$
$ mv !$ !$.text
$ ls -lAG !$
$ grep &quot;Jack Danger&quot; !$
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;!$&lt;/code&gt; shortcut means “the last argument of the last command I ran”. I use this all day every day. It’s worth teaching your fingers to type those two characters in quick succession because this muscle memory will help you stay in a state of flow and not fall out just because of the tedium of typing and trying to get filenames right. Particularly if instead of &lt;code&gt;somefile&lt;/code&gt; you’re working with &lt;code&gt;apache-http-webserver-nightly-2015011223.tgz&lt;/code&gt;&lt;/p&gt;

&lt;h3 id=&quot;the--shortcut-1&quot;&gt;The !! shortcut&lt;/h3&gt;
&lt;p&gt;This one is slightly less commonly used but is really handy &lt;a href=&quot;http://xkcd.com/149/&quot;&gt;in a specific situation&lt;/a&gt;. When you’ve typed a command and you needed to run it with &lt;code&gt;sudo&lt;/code&gt; you can either do this:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code&gt;$ rm file_that_I_hate
&amp;gt; rm: Permission denied
$ sudo rm file_that_I_hate
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Sure, that’s fine. But to save yourself some typing and, more importantly so you don’t mess up the actual command typing it by hand again, this is better:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code&gt;$ rm file_that_I_hate
&amp;gt; rm: Permission denied
$ sudo !!
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;!!&lt;/code&gt; is a fill-in for the entire previous command.&lt;/p&gt;

&lt;h2 id=&quot;text-manipulation&quot;&gt;Text Manipulation&lt;/h2&gt;

&lt;h3 id=&quot;finding-text-in-a-file&quot;&gt;Finding text in a file&lt;/h3&gt;
&lt;p&gt;Grep is your best friend. There are other, faster versions of this program (hint: &lt;code&gt;brew install ag &amp;amp;&amp;amp; ag --help&lt;/code&gt;) but &lt;code&gt;grep&lt;/code&gt; is installed on every unix box everywhere and it’s good enough. The primary way you’ll use &lt;code&gt;grep&lt;/code&gt; is to see which files have what you need:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code&gt;$ grep &quot;Error:&quot; /var/log/*.log
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If you have a regular expression you’d like to use you can just run &lt;code&gt;egrep&lt;/code&gt; instead of &lt;code&gt;grep&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code&gt;$ egrep &quot;Error:|http&quot; /var/log/*.log
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And, while there are many flags you can use to customize how you use &lt;code&gt;grep&lt;/code&gt;, the one I recommend getting familiar with right away is &lt;code&gt;-C&lt;/code&gt; (C for “context”). It will print out lines above and below the match for what you’re searching for. So&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code&gt;$ grep -C 1 &quot;Error:&quot; /var/log/*.log
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Will show you not just the lines with “Error:” but will show you one line before and after so you can maybe figure out what’s causing the error.&lt;/p&gt;

&lt;h3 id=&quot;printing-columns-of-data&quot;&gt;Printing columns of data&lt;/h3&gt;
&lt;p&gt;This one is deceptively useful and only requires a little bit of arcane syntax (which you can hide away if you want). You’re often going to have data printed to your screen like this:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code&gt;$ grep &quot;Error:&quot; my.log
&amp;gt; [error] 2015-01-05 12:31:40 Error: SadComputer - [log level: 1]
&amp;gt; [error] 2015-01-05 12:31:41 Error: BrokeComputer - [log level: 1]
&amp;gt; [error] 2015-01-05 12:31:43 Error: NoFunAtAll - [log level: 1]
&amp;gt; [error] 2015-01-05 12:31:48 Error: ThingsAreTwistedAllUp - [log level: 1]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Maybe all you want is the actual error message here. No problem! There’s a program called &lt;code&gt;awk&lt;/code&gt; that’s perfect for this. It does a lot of fancy stuff but without anything special it’s really good at splitting input up into columns and letting you pick which ones you want.&lt;/p&gt;

&lt;p&gt;The “SadComputer” message in the first line is the 5th column of text (each column is any contiguous set of characters separated by whitespace). Here’s how we just print that column:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code&gt;$ grep &quot;Error:&quot; my.log | awk &apos;{print $5}&apos;
&amp;gt; SadComputer
&amp;gt; BrokeComputer
&amp;gt; NoFunAtAll
&amp;gt; ThingsAreTwistedAllUp
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That syntax (a &lt;code&gt;print $5&lt;/code&gt; inside curly braces inside quotes) is worth memorizing. But if you dont want to you can always throw this into your &lt;code&gt;~/.bash_profile&lt;/code&gt; and you can make yourself a shortcut:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code&gt;awkc () {
  awk &quot;{print \$$1 }&quot;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That defines a new function that formats a call to &lt;code&gt;awk&lt;/code&gt; for you. You’d use it like this:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code&gt;$ grep &quot;Error:&quot; my.log | awkc 5
&amp;gt; SadComputer
&amp;gt; BrokeComputer
&amp;gt; NoFunAtAll
&amp;gt; ThingsAreTwistedAllUp
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id=&quot;navigating&quot;&gt;Navigating&lt;/h2&gt;

&lt;h3 id=&quot;try-the-tab-key&quot;&gt;Try the tab key&lt;/h3&gt;
&lt;p&gt;I first started using Linux even before I knew how to program because I couldn’t afford a very powerful computer when I was in college. I remember copying and pasting commands out of web pages to try to install programs. Then, inevitably, I’d be typing some filename that was 60+ characters long and a typo was nearly guaranteed. Nobody told me that you could hit the tab key and your shell will automatically complete filenames for you. Not only that, but depending on the context it may even complete long command invocations for you. When in doubt - hit the tab key.&lt;/p&gt;

&lt;h3 id=&quot;go-back-to-the-directory-you-were-just-in&quot;&gt;Go back to the directory you were just in&lt;/h3&gt;
&lt;p&gt;Running &lt;code&gt;cd -&lt;/code&gt; will go back to the directory you were in last and typing it again will return you to where you are now. Super useful if you’re switching mostly between just two places.&lt;br /&gt;
&lt;code&gt;git checkout -&lt;/code&gt; does the exact same thing but with two git branches.&lt;/p&gt;

&lt;h3 id=&quot;finding-files&quot;&gt;Finding files&lt;/h3&gt;
&lt;p&gt;There’s a program called &lt;code&gt;find&lt;/code&gt; that is kind of user-unfriendly. You find files like this:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code&gt;$ find /some/directory -name filename.text
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And the filename has to be exactly &lt;code&gt;filename.text&lt;/code&gt;. If you want a fuzzy match you have to add asterisks and quotes:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code&gt;$ find /some/directory -name &quot;*filename*&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Personally, I find all this to be cumbersome because I’m often just want to type part of the filename and I usually intend to find it just in the current directory. So I use this shell function as a wrapper (again, you can just put this in your &lt;code&gt;~/.bash_profile&lt;/code&gt;) and it’ll get picked up:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code&gt;name () {
  # If the second argument ($2) is not an empty string
  if [[ -n $2 ]]; then
     dir=$2 # You typed a second argument, it&apos;s a directory to search in
  else
     dir=. # No second argument given, let&apos;s use the current directory
  fi
  find $dir -name &quot;*$1*&quot;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then you can look for files by name like this:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code&gt;$ name fonts
# finds anything named &quot;*fonts*&quot; in the current directory
$ name fonts /var/log
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;There are so many variations of these commands you can play with but, like learning any skill or exploring any new system, I recommend taking things one step at a time. When you find you use one of these commands really frequently in the same way feel free to add more to your &lt;code&gt;~/.bash_profile&lt;/code&gt; so you can save yourself some typing (and typos).&lt;/p&gt;

&lt;p&gt;And please do copy freely from &lt;a href=&quot;https://github.com/JackDanger/dotfiles&quot;&gt;my ‘dotfiles’ repo on Github&lt;/a&gt;.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Making two ActiveRecord models look like one</title>
   <link href="http://6brand.com/an-activerecord-model-backed-by-two-datastores.html"/>
   <updated>2014-12-16T00:00:00-08:00</updated>
   <id>http://6brand.com/an-activerecord-model-backed-by-two-datastores.html</id>
   <content type="html">&lt;p&gt;I recently encountered a MySQL table backing an ActiveRecord model that grew so unexpectedly fast that it ran out of space. Our engineering team did what anybody would do in an emergency: moved all the existing data somewhere with more space and created a new, empty table so we wouldn’t lose new writes.&lt;/p&gt;

&lt;p&gt;Due to the nature of this data and the code that references it we couldn’t immediately move all queries to just use the new storage location. We had to keep both datasets for a while and we needed existing references to the ActiveRecord model to just keep working.&lt;/p&gt;

&lt;p&gt;Note: Our “fix” was purely temporary. What I’m about to describe is a gross hack that got us through the immediate crisis but we immediately began work to properly collapse these two datasets into one with a better runway for future growth. It’s a useful example of Ruby’s flexibility but please don’t put what follows into production unless you absolutely have to.&lt;/p&gt;

&lt;p&gt;What we did was swap out the ActiveRecord model for a bare class that simply delegates all the messages an instance receives to both of the MySQL datastores to present a unified view of two totally different tables on two different hosts.&lt;/p&gt;

&lt;p&gt;Here’s how we did it.&lt;/p&gt;

&lt;h2 id=&quot;delegating-everything&quot;&gt;Delegating everything&lt;/h2&gt;

&lt;p&gt;All of our code was referencing &lt;code&gt;TheModel&lt;/code&gt; and expecting it to behave like ActiveRecord. So the first step was to hide the actual model as inner class of a BasicObject (which is an object that has almost no methods defined). Then we created a second inner class that referenced the new dataset. Then we took all the existing, shared behavior from the original model and put it in a module to be included by both.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;TheModel&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;BasicObject&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;ExistingBehavior&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# methods that used to be inside TheModel&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;included&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;class_eval&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# method calls that used to be in the class&lt;/span&gt;
                           &lt;span class=&quot;c1&quot;&gt;# e.g. `belongs_to :user`&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;New&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;ActiveRecord&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;establish_connection&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;original_datastore&amp;quot;&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Connect to the right db&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;table_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:records&lt;/span&gt;
    &lt;span class=&quot;kp&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ExistingBehavior&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Old&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;ActiveRecord&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;
    &lt;span class=&quot;kp&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ExistingBehavior&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;establish_connection&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;other_datastore&amp;quot;&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Connect to the right db&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;table_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:records_other&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Reading from two places&lt;br /&gt;
What we’ll need is a way to turn calls for &lt;code&gt;TheModel.all&lt;/code&gt; or &lt;code&gt;TheModel.where(some_condition).all&lt;/code&gt; actually reads from two different datastores. It’s not too hard to proxy to just one datastore because all we need to do is delegate a few calls on the TheModel class to the inner model:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;TheModel&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;BasicObject&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;delegate&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
             &lt;span class=&quot;ss&quot;&gt;:where&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# This isn&amp;#39;t a complete list,&lt;/span&gt;
             &lt;span class=&quot;ss&quot;&gt;:first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# of creation methods but&lt;/span&gt;
             &lt;span class=&quot;ss&quot;&gt;:last&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;c1&quot;&gt;# it&amp;#39;ll do for now&lt;/span&gt;
             &lt;span class=&quot;ss&quot;&gt;:new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
             &lt;span class=&quot;ss&quot;&gt;:create&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
             &lt;span class=&quot;ss&quot;&gt;:create!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
             &lt;span class=&quot;ss&quot;&gt;:to&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:&amp;#39;TheModel::New&amp;#39;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;New&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ActiveRecord&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now if you run TheModel.all you’re actually calling TheModel::New.all. And any chained messages you add on to the result of that call will go to the right place.&lt;/p&gt;

&lt;p&gt;But what we really want is to have TheModel.all return TheModel::New.all + TheModel::Old.all. Let’s start with a naive approach:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;TheModel&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;BasicObject&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;                            &lt;span class=&quot;c1&quot;&gt;# Keep delegating constructor methods&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;delegate&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:create&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:create!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;# to the new dataset&lt;/span&gt;
           &lt;span class=&quot;ss&quot;&gt;:to&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:&amp;#39;TheModel::New&amp;#39;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;method_missing&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;method_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# all other calls get sent to&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;New&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;method_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;             &lt;span class=&quot;c1&quot;&gt;# both models and joined&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;Old&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;method_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;But that assumes that all of our operations will be immediately concatenating two values. That’s not true, sometimes we want to chain up successive &lt;code&gt;where&lt;/code&gt; calls. To make this possible we need some kind of intermediate object that holds state before we’re ready to concatenate the results:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;TheModel&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;BasicObject&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;method_missing&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;method_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;FindInTwoPlaces&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;New&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Old&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;method_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;FindInTwoPlaces&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initialize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new_dataset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;old_dataset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;vi&quot;&gt;@new_dataset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@old_dataset&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;new_dataset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;old_dataset&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;all&lt;/span&gt;
      &lt;span class=&quot;vi&quot;&gt;@new_dataset&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;all&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@old_dataset&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;all&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;method_missing&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;method_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;no&quot;&gt;FindInTwoPlaces&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;                                    &lt;span class=&quot;c1&quot;&gt;# All calls except `all`&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@new_dataset&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;method_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;# just create a new instance&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@old_dataset&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;method_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
   &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This &lt;code&gt;FindInTwoPlaces&lt;/code&gt; class is initialized with two datastores. Initially that’s just the bare models representing the complete datastores. But as we chain messages each datastore object gets further refined. If you call &lt;code&gt;TheModel.where(&quot;id=1&quot;)&lt;/code&gt; you get a &lt;code&gt;FindInTwoPlaces&lt;/code&gt; instances that contains &lt;code&gt;TheModel::New.where(&quot;id=1&quot;)&lt;/code&gt; and &lt;code&gt;TheModel::Old.where(&quot;id=1&quot;)&lt;/code&gt;. When you then call &lt;code&gt;.all&lt;/code&gt; on that object they get concatenated together.&lt;/p&gt;

&lt;p&gt;So far so good, but we’re getting a lot of complexity for just the &lt;code&gt;.all&lt;/code&gt; class method. We can do better by defining all of the final methods that we will want to use and proxying all other messages to a new intermediate object. For now let’s just implement &lt;code&gt;all&lt;/code&gt;, &lt;code&gt;count&lt;/code&gt;, and &lt;code&gt;to_a&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;TheModel&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;BasicObject&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;method_missing&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;method_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;FindInTwoPlaces&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;New&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Old&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;method_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;FindInTwoPlaces&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initialize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new_dataset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;old_dataset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;vi&quot;&gt;@new_dataset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@old_dataset&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;new_dataset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;old_dataset&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;all&lt;/span&gt;
      &lt;span class=&quot;vi&quot;&gt;@new_dataset&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;all&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@old_dataset&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;all&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;count&lt;/span&gt;
      &lt;span class=&quot;vi&quot;&gt;@new_dataset&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;count&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@old_dataset&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;to_a&lt;/span&gt;
      &lt;span class=&quot;vi&quot;&gt;@new_dataset&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;all&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@old_dataset&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;all&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;method_missing&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;method_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;no&quot;&gt;FindInTwoPlaces&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@new_dataset&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;method_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@old_dataset&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;method_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
   &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now &lt;code&gt;TheModel.where(&quot;id=1&quot;).order(&quot;created_at DESC&quot;).limit(2).all&lt;/code&gt; works as expected. It’ll return all records from both datasets that match those conditions. However, if you call &lt;code&gt;.first&lt;/code&gt; at the end instead of &lt;code&gt;.all&lt;/code&gt; it’ll totally fail to work. Let’s fix that.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;TheModel&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;BasicObject&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;method_missing&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;method_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;FindInTwoPlaces&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;New&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Old&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;method_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;FindInTwoPlaces&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initialize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new_dataset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;old_dataset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;vi&quot;&gt;@new_dataset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@old_dataset&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;new_dataset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;old_dataset&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;first&lt;/span&gt;
      &lt;span class=&quot;vi&quot;&gt;@new_dataset&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@old_dataset&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;all&lt;/span&gt;
      &lt;span class=&quot;vi&quot;&gt;@new_dataset&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;all&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@old_dataset&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;all&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;count&lt;/span&gt;
      &lt;span class=&quot;vi&quot;&gt;@new_dataset&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;count&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@old_dataset&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;to_a&lt;/span&gt;
      &lt;span class=&quot;vi&quot;&gt;@new_dataset&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;all&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@old_dataset&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;all&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;method_missing&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;method_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;no&quot;&gt;FindInTwoPlaces&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@new_dataset&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;method_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@old_dataset&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;method_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here we’ve introduced our first application-specific decision. It may be that you want one dataset prioritized over another. For my case here I need the newer one if it exists. We’ve also introduced our first operation that isn’t concatenative. If we implement all possible final methods we’ll have to be careful to use &lt;code&gt;+&lt;/code&gt; or &lt;code&gt;||&lt;/code&gt; or other operators as is appropriate.&lt;/p&gt;

&lt;p&gt;Let’s implement all of the rest of the methods that might appear as the final part of an ActiveRecord query chain. And to save on some typing I’m going to go ahead and refactor them into lists of method names grouped by operator. I’ll also be fixing a bug that exists in the above implementations by ensuring that all arguments to these methods get properly forwarded to the internal datastore objects.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;TheModel&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;BasicObject&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;method_missing&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;method_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;FindInTwoPlaces&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;New&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Old&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;method_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;FindInTwoPlaces&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Struct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:new_dataset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:old_dataset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Making this a struct lets us skip&lt;/span&gt;
    &lt;span class=&quot;sx&quot;&gt;%w{all count to_a pluck}&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;                     &lt;span class=&quot;c1&quot;&gt;# writing an initializer and it&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;define_method&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;                     &lt;span class=&quot;c1&quot;&gt;# gives us accessors for free&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;new_dataset&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;old_dataset&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

    &lt;span class=&quot;sx&quot;&gt;%w{first last}&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;define_method&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;new_dataset&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;old_dataset&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;empty?&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;new_store&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;empty?&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;old_store&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;empty?&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;method_missing&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;method_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;no&quot;&gt;FindInTwoPlaces&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;new_dataset&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;method_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;old_dataset&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;method_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
   &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You may notice I haven’t implemented the entire API of an ActiveRecord model. That’s because the full API includes a ton more methods including both &lt;code&gt;.forty_two&lt;/code&gt; and &lt;code&gt;.forty_two!&lt;/code&gt;. &lt;br /&gt;
If we needed all of those operations we’d probably have deeper problems because the objects in an application need to communicate over the narrowest API possible to keep the app simple. However, blindly passing them off to method_missing will have indeterminate results. So we should explicitly disallow their use.&lt;/p&gt;

&lt;p&gt;Here, then is the final version of our wacky meta-model. It presents two totally separate ActiveRecord datastores (possibly on different hosts or even using different database technology) as a single, unified datastore:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;TheModel&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;BasicObject&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;delegate&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:create&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:create!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:to&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:&amp;#39;TheModel::New&amp;#39;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;method_missing&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;method_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;FindInTwoPlaces&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;New&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Old&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;method_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;ExistingBehavior&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;included&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;class_eval&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;New&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;ActiveRecord&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;establish_connection&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;original_datastore&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;table_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:records&lt;/span&gt;
    &lt;span class=&quot;kp&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ExistingBehavior&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Old&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;ActiveRecord&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;
    &lt;span class=&quot;kp&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ExistingBehavior&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;establish_connection&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;other_datastore&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;table_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:records_other&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;no&quot;&gt;FindInTwoPlaces&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Struct&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:new_dataset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:old_dataset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;## Concatenating operations&lt;/span&gt;
    &lt;span class=&quot;sx&quot;&gt;%w{&lt;/span&gt;
&lt;span class=&quot;sx&quot;&gt;      all&lt;/span&gt;
&lt;span class=&quot;sx&quot;&gt;      count&lt;/span&gt;
&lt;span class=&quot;sx&quot;&gt;      delete_all&lt;/span&gt;
&lt;span class=&quot;sx&quot;&gt;      destroy_all&lt;/span&gt;
&lt;span class=&quot;sx&quot;&gt;      explain&lt;/span&gt;
&lt;span class=&quot;sx&quot;&gt;      ids&lt;/span&gt;
&lt;span class=&quot;sx&quot;&gt;      pluck&lt;/span&gt;
&lt;span class=&quot;sx&quot;&gt;      sum&lt;/span&gt;
&lt;span class=&quot;sx&quot;&gt;      to_a&lt;/span&gt;
&lt;span class=&quot;sx&quot;&gt;      update_all&lt;/span&gt;
&lt;span class=&quot;sx&quot;&gt;    }&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;define_method&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;new_dataset&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;old_dataset&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;## Selecting a value from one or the other&lt;/span&gt;
    &lt;span class=&quot;sx&quot;&gt;%w{&lt;/span&gt;
&lt;span class=&quot;sx&quot;&gt;      any&lt;/span&gt;
&lt;span class=&quot;sx&quot;&gt;      first&lt;/span&gt;
&lt;span class=&quot;sx&quot;&gt;      include&lt;/span&gt;
&lt;span class=&quot;sx&quot;&gt;      last&lt;/span&gt;
&lt;span class=&quot;sx&quot;&gt;      many?&lt;/span&gt;
&lt;span class=&quot;sx&quot;&gt;    }&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;define_method&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;new_dataset&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;old_dataset&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;## Impossible operations&lt;/span&gt;
    &lt;span class=&quot;sx&quot;&gt;%w{&lt;/span&gt;
&lt;span class=&quot;sx&quot;&gt;      average&lt;/span&gt;
&lt;span class=&quot;sx&quot;&gt;      calculate&lt;/span&gt;
&lt;span class=&quot;sx&quot;&gt;      create&lt;/span&gt;
&lt;span class=&quot;sx&quot;&gt;      create_with&lt;/span&gt;
&lt;span class=&quot;sx&quot;&gt;      delete&lt;/span&gt;
&lt;span class=&quot;sx&quot;&gt;      destroy&lt;/span&gt;
&lt;span class=&quot;sx&quot;&gt;      exec_explain&lt;/span&gt;
&lt;span class=&quot;sx&quot;&gt;      exists&lt;/span&gt;
&lt;span class=&quot;sx&quot;&gt;      fifth&lt;/span&gt;
&lt;span class=&quot;sx&quot;&gt;      find&lt;/span&gt;
&lt;span class=&quot;sx&quot;&gt;      find_by&lt;/span&gt;
&lt;span class=&quot;sx&quot;&gt;      find_each&lt;/span&gt;
&lt;span class=&quot;sx&quot;&gt;      find_in_batches&lt;/span&gt;
&lt;span class=&quot;sx&quot;&gt;      find_or_create_by&lt;/span&gt;
&lt;span class=&quot;sx&quot;&gt;      find_or_initialize_by&lt;/span&gt;
&lt;span class=&quot;sx&quot;&gt;      first&lt;/span&gt;
&lt;span class=&quot;sx&quot;&gt;      first_or_create&lt;/span&gt;
&lt;span class=&quot;sx&quot;&gt;      first_or_initialize&lt;/span&gt;
&lt;span class=&quot;sx&quot;&gt;      forty_two&lt;/span&gt;
&lt;span class=&quot;sx&quot;&gt;      fourth&lt;/span&gt;
&lt;span class=&quot;sx&quot;&gt;      fourth!&lt;/span&gt;
&lt;span class=&quot;sx&quot;&gt;      last&lt;/span&gt;
&lt;span class=&quot;sx&quot;&gt;      lock&lt;/span&gt;
&lt;span class=&quot;sx&quot;&gt;      maximum&lt;/span&gt;
&lt;span class=&quot;sx&quot;&gt;      minimum&lt;/span&gt;
&lt;span class=&quot;sx&quot;&gt;      readonly&lt;/span&gt;
&lt;span class=&quot;sx&quot;&gt;      second&lt;/span&gt;
&lt;span class=&quot;sx&quot;&gt;      take&lt;/span&gt;
&lt;span class=&quot;sx&quot;&gt;      third&lt;/span&gt;
&lt;span class=&quot;sx&quot;&gt;      update&lt;/span&gt;
&lt;span class=&quot;sx&quot;&gt;    }&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;define_method&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;raise&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Sorry, &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; isn&amp;#39;t possible via FindInTwoPlaces, do it by hand&amp;quot;&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;method_missing&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;method_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;new_dataset&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;method_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;old_dataset&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;method_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Again, please don’t use this in production unless you absolutely have to.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Build a Web Crawler in Go</title>
   <link href="http://6brand.com/build-a-web-crawler-in-go.html"/>
   <updated>2014-05-07T00:00:00-07:00</updated>
   <id>http://6brand.com/build-a-web-crawler-in-go.html</id>
   <content type="html">&lt;p&gt;One of the basic tests I use to try out a new programming language is building a web&lt;br /&gt;
crawler. I stole the idea from my colleague &lt;a href=&quot;https://twitter.com/MikeLewis&quot;&gt;Mike Lewis&lt;/a&gt; and&lt;br /&gt;
I love it because it uses all the principles necessary in internet engineering: A web&lt;br /&gt;
crawler needs to parse semi-structured text, rely on 3rd-party APIs, manage its internal&lt;br /&gt;
state, and perform some basic concurrency.&lt;/p&gt;

&lt;h2 id=&quot;starting-a-new-project-with-go&quot;&gt;Starting a new project with Go&lt;/h2&gt;

&lt;p&gt;This is a tutorial that is accessible for complete beginners to the Go programming&lt;br /&gt;
language or to web programming. All the commands you need to run are provided and all&lt;br /&gt;
the code you need to type into the &lt;code&gt;.go&lt;/code&gt; source code files is shown to you a piece at a&lt;br /&gt;
time. Each time I introduce a new concept you’ll need to edit the same file, slowly&lt;br /&gt;
building up functionality. When you run each version of the code Go will give you an&lt;br /&gt;
exact error message with a line number so you’ll be able to fix any mistakes you make.&lt;br /&gt;
If you get totally lost you can just copy straight out of the page into a new file and&lt;br /&gt;
pick back up. If you’re new to Go I &lt;em&gt;highly&lt;/em&gt; recommend reading the excellent &lt;a href=&quot;http://golang.org/doc/&quot;&gt;Go&lt;br /&gt;
documentation&lt;/a&gt; to help you make sense of what’s on this page.&lt;/p&gt;

&lt;p&gt;Since this example requires the Go programming language you should start by installing&lt;br /&gt;
Go:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo apt-get install golang  &lt;span class=&quot;c1&quot;&gt;# (if you&amp;#39;re on Linux)&lt;/span&gt;
brew install go  &lt;span class=&quot;c1&quot;&gt;# (if you&amp;#39;re on a Mac)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id=&quot;creating-the-main-function&quot;&gt;Creating the ‘main’ function&lt;/h2&gt;

&lt;p&gt;Go is so fast that it’s practically a scripting language. All you need to run it&lt;br /&gt;
is a ‘main’ package and a ‘main’ function. On my machine the following tiny program&lt;br /&gt;
takes only 0.04 seconds to compile. Let’s create a new file and try it out:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;&lt;span class=&quot;c1&quot;&gt;//// Put this in a new file &amp;#39;crawl.go&amp;#39;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;main&lt;/span&gt;     &lt;span class=&quot;c1&quot;&gt;// This is technically a perfectly&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;// valid Go program, even if a bit boring&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now you’re a Go programmer. Hooray! Let’s make it just slightly more interesting by&lt;br /&gt;
turning this into a Hello World program.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;&lt;span class=&quot;c1&quot;&gt;//// file: crawl.go&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;main&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;// package will always be &amp;#39;main&amp;#39; for our app.&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;// the &amp;#39;import&amp;#39; section is where you specify all&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&amp;quot;fmt&amp;quot;&lt;/span&gt;         &lt;span class=&quot;c1&quot;&gt;// dependencies and &amp;#39;fmt&amp;#39; is the package used for&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;               &lt;span class=&quot;c1&quot;&gt;// printing to the screen.&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;                   &lt;span class=&quot;c1&quot;&gt;// The &amp;#39;main&amp;#39; function is always the one that starts&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;I&amp;#39;m a gopher!&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// your program&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And now let’s run it:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;go run crawl.go  &lt;span class=&quot;c1&quot;&gt;# run this in your terminal in whatever directory you created the file.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You could have executed &lt;code&gt;go build crawl.go&lt;/code&gt; instead of &lt;code&gt;go run crawl.go&lt;/code&gt; and it would&lt;br /&gt;
have just compiled the file for you. The “run” command both compiles and executes it so&lt;br /&gt;
you’ll find it turns Go into a usable scripting language (indeed, it’s faster than a lot&lt;br /&gt;
of Ruby or Python projects).&lt;/p&gt;

&lt;h2 id=&quot;whats-a-web-crawler&quot;&gt;What’s a web crawler?&lt;/h2&gt;

&lt;p&gt;A web crawler is the portion of a search engine that scans web pages looking for links&lt;br /&gt;
and then follows them. It would normally store the data it finds into some database&lt;br /&gt;
where it can be useful but our version is just going to print the URLs to the screen and&lt;br /&gt;
move along.&lt;/p&gt;

&lt;p&gt;While not quite enterprise grade this’ll let us play with all the same concepts and see&lt;br /&gt;
some really satisfying output as our little script wanders the web.&lt;/p&gt;

&lt;h2 id=&quot;step-1-starting-from-a-specific-page&quot;&gt;Step 1. Starting from a specific page&lt;/h2&gt;

&lt;p&gt;You’ve got to start crawling from somewhere and in our program we’ll let the person who&lt;br /&gt;
executes the crawler specify what starting page to use. This involves reading a command&lt;br /&gt;
line argument which, in most programming languages, will be stored in a variable named&lt;br /&gt;
something like &lt;code&gt;ARGV&lt;/code&gt; and Go is no exception.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;&lt;span class=&quot;c1&quot;&gt;//// file: crawl.go&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;main&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&amp;quot;fmt&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&amp;quot;flag&amp;quot;&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;// &amp;#39;flag&amp;#39; helps you parse command line arguments&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&amp;quot;os&amp;quot;&lt;/span&gt;          &lt;span class=&quot;c1&quot;&gt;// &amp;#39;os&amp;#39; gives you access to system calls&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;flag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;         &lt;span class=&quot;c1&quot;&gt;// This stuff with &amp;#39;flag&amp;#39; converts the command line&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;args&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;flag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// arguments to a new variable named &amp;#39;args&amp;#39;&lt;/span&gt;
                       &lt;span class=&quot;c1&quot;&gt;// The &amp;#39;:=&amp;#39; form means &amp;quot;this is a brand new variable&amp;quot; and&lt;/span&gt;
                       &lt;span class=&quot;c1&quot;&gt;// a &amp;#39;=&amp;#39; here would throw an error.&lt;/span&gt;
                       &lt;span class=&quot;c1&quot;&gt;// At this point &amp;#39;args&amp;#39; will be either an empty list&lt;/span&gt;
                       &lt;span class=&quot;c1&quot;&gt;// (if no command line arguments were provided) or it&amp;#39;ll&lt;/span&gt;
                       &lt;span class=&quot;c1&quot;&gt;// contain some string values.&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;   
    &lt;span class=&quot;nx&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;Please specify start page&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// if a starting page wasn&amp;#39;t provided as an argument&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Exit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;                                &lt;span class=&quot;c1&quot;&gt;// show a message and exit.&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;                                           &lt;span class=&quot;c1&quot;&gt;// Note that &amp;#39;main&amp;#39; doesn&amp;#39;t return anything.&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now run this file by typing &lt;code&gt;go run crawl.go&lt;/code&gt; and see that it yells at you because you&lt;br /&gt;
didn’t specify a starting web page. Then try running it with an argument provided (&lt;code&gt;go
run crawl.go http://news.google.com&lt;/code&gt;) and it won’t show that message anymore.&lt;/p&gt;

&lt;h2 id=&quot;step-2-retrieving-a-page-from-the-internet&quot;&gt;Step 2. Retrieving a page from the internet&lt;/h2&gt;

&lt;p&gt;The next thing you need is to download the page your starting URL represents so you can&lt;br /&gt;
scan it for links. In Go there is a great http package right in the standard library.&lt;br /&gt;
You can use the primitives Go gives you to turn your URL string into a string&lt;br /&gt;
representing the page body.&lt;/p&gt;

&lt;p&gt;First I’ll show you what this looks like in isolation, then we can incorporate it into our crawler. Put the following in retrieve.go:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;&lt;span class=&quot;c1&quot;&gt;//// file: retrieve.go&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;main&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;// Note: this is a new temporary file, not our crawl.go&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&amp;quot;fmt&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&amp;quot;net/http&amp;quot;&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;// this is the &amp;#39;http&amp;#39; package we&amp;#39;ll be using to retrieve a page&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&amp;quot;io/ioutil&amp;quot;&lt;/span&gt;   &lt;span class=&quot;c1&quot;&gt;// we&amp;#39;ll only use &amp;#39;ioutil&amp;#39; to maek reading and printing&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;               &lt;span class=&quot;c1&quot;&gt;// the html page a little easier in this example.&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;resp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;http://6brand.com.com&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// See how we assign two variables at once here?&lt;/span&gt;
                                                  &lt;span class=&quot;c1&quot;&gt;// That destructuring is really common&lt;/span&gt;
                                                  &lt;span class=&quot;c1&quot;&gt;// in Go. The way you handle errors in&lt;/span&gt;
                                                  &lt;span class=&quot;c1&quot;&gt;// Go is to expect that functions you&lt;/span&gt;
                                                  &lt;span class=&quot;c1&quot;&gt;// call will return two things and the&lt;/span&gt;
                                                  &lt;span class=&quot;c1&quot;&gt;// second one will be an error. If the&lt;/span&gt;
                                                  &lt;span class=&quot;c1&quot;&gt;// error is nil then you can continue&lt;/span&gt;
                                                  &lt;span class=&quot;c1&quot;&gt;// but if it&amp;#39;s not you need to handle it.&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;http transport error is:&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ioutil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ReadAll&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// resp.Body isn&amp;#39;t a string, it&amp;#39;s more like a reference&lt;/span&gt;
                                          &lt;span class=&quot;c1&quot;&gt;// to a stream of data. So we use the &amp;#39;ioutil&amp;#39;&lt;/span&gt;
                                          &lt;span class=&quot;c1&quot;&gt;// package to read it into memory for us.&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;read error is:&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;   &lt;span class=&quot;c1&quot;&gt;// We cast the html body to a string because&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;                             &lt;span class=&quot;c1&quot;&gt;// Go hands it to us as a byte array&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And run it with &lt;code&gt;go run retrieve.go&lt;/code&gt;. You should see the body of&lt;br /&gt;
&lt;a href=&quot;http://6brand.com&quot;&gt;6brand.com&lt;/a&gt; printed to your screen. And if you scroll up to the top you’ll see that there were no errors (literally, err was nil) in either the transporting or reading of your http call. Yay, go you.&lt;/p&gt;

&lt;p&gt;Let’s copy the new pieces of this code into our &lt;code&gt;crawl.go&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;&lt;span class=&quot;c1&quot;&gt;//// file: crawl.go&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;main&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&amp;quot;flag&amp;quot;&lt;/span&gt;          &lt;span class=&quot;c1&quot;&gt;// &amp;#39;flag&amp;#39;, &amp;#39;fmt&amp;#39; and &amp;#39;os&amp;#39; we&amp;#39;ll keep around&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&amp;quot;fmt&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&amp;quot;net/http&amp;quot;&lt;/span&gt;      &lt;span class=&quot;c1&quot;&gt;// &amp;#39;http&amp;#39; will retrieve pages for us&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&amp;quot;io/ioutil&amp;quot;&lt;/span&gt;     &lt;span class=&quot;c1&quot;&gt;// &amp;#39;ioutil&amp;#39; will help us print pages to the screen&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&amp;quot;os&amp;quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;flag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;args&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;flag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;Please specify start page&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Exit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;retrieve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// The reason we can call &amp;#39;retrieve&amp;#39; is because&lt;/span&gt;
                     &lt;span class=&quot;c1&quot;&gt;// it&amp;#39;s defined in the same package as the calling function.&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;retrieve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;uri&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// This func(tion) takes a parameter and the&lt;/span&gt;
                             &lt;span class=&quot;c1&quot;&gt;// format for a function parameter definition is&lt;/span&gt;
                             &lt;span class=&quot;c1&quot;&gt;// to say what the name of the parameter is and then&lt;/span&gt;
                             &lt;span class=&quot;c1&quot;&gt;// the type.&lt;/span&gt;
                             &lt;span class=&quot;c1&quot;&gt;// So here we&amp;#39;re expecting to be given a&lt;/span&gt;
                             &lt;span class=&quot;c1&quot;&gt;// string that we&amp;#39;ll refer to as &amp;#39;uri&amp;#39;&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;resp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;            &lt;span class=&quot;c1&quot;&gt;// This is the way error handling typically works in Go.&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;                   &lt;span class=&quot;c1&quot;&gt;// It&amp;#39;s a bit verbose but it works.&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;defer&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;resp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// Important: we need to close the resource we opened&lt;/span&gt;
                           &lt;span class=&quot;c1&quot;&gt;// (the TCP connection to some web server and our reference&lt;/span&gt;
                           &lt;span class=&quot;c1&quot;&gt;// to the stream of data it sends us).&lt;/span&gt;
                           &lt;span class=&quot;c1&quot;&gt;// `defer` delays an operation until the function ends.&lt;/span&gt;
                           &lt;span class=&quot;c1&quot;&gt;// It&amp;#39;s basically the same as if you&amp;#39;d moved the code&lt;/span&gt;
                           &lt;span class=&quot;c1&quot;&gt;// you&amp;#39;re deferring to the very last line of the func.&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ioutil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ReadAll&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// I&amp;#39;m assigning the err to _ &amp;#39;cause&lt;/span&gt;
                                        &lt;span class=&quot;c1&quot;&gt;// I don&amp;#39;t care about it but Go will whine&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;             &lt;span class=&quot;c1&quot;&gt;// if I name it and don&amp;#39;t use it&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;What we’ve got now is an excellent start to a web crawler. It’s able to boot, parse the&lt;br /&gt;
URL you’ve given it, open a connection to the right remote host, and retrieve the html&lt;br /&gt;
content.&lt;/p&gt;

&lt;h2 id=&quot;step-3-parsing-hyperlinks-from-html&quot;&gt;Step 3. Parsing hyperlinks from HTML&lt;/h2&gt;

&lt;p&gt;If you have a page of HTML you may want to use a regular expression to extract the&lt;br /&gt;
links. Don’t. Like, &lt;a href=&quot;http://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags/1732454#1732454&quot;&gt;really&lt;br /&gt;
don’t&lt;/a&gt;.&lt;br /&gt;
Regular expressions are not a good tool for that. The best way is, sadly, to walk&lt;br /&gt;
through the tree structure of the page finding anchor tags and extracting &lt;code&gt;href&lt;/code&gt;&lt;br /&gt;
attributes from them. In most languages this is no fun but in Go’s standard library it’s&lt;br /&gt;
extra not fun (though not nearly as painful as Java) and I won’t subject you to it here.&lt;br /&gt;
I’ve encapsulated the act of pulling links from a large HTML string in &lt;a href=&quot;https://github.com/jackdanger/collectlinks&quot;&gt;this&lt;br /&gt;
project&lt;/a&gt; and you’re welcome to check out the&lt;br /&gt;
code if you’re interested.&lt;/p&gt;

&lt;p&gt;Now let’s modify our code to extract links from whatever page is provided and print&lt;br /&gt;
those links to the screen:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;&lt;span class=&quot;c1&quot;&gt;//// file: crawl.go&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;main&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&amp;quot;flag&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&amp;quot;fmt&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&amp;quot;github.com/jackdanger/collectlinks&amp;quot;&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// This is the little library I made for &lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&amp;quot;net/http&amp;quot;&lt;/span&gt;                            &lt;span class=&quot;c1&quot;&gt;// parsing links. Go natively allows sourcing&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&amp;quot;os&amp;quot;&lt;/span&gt;                                  &lt;span class=&quot;c1&quot;&gt;// Github projects as dependencies. They&amp;#39;ll be&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;                                       &lt;span class=&quot;c1&quot;&gt;// downloaded to $GOPATH/src/github.com/... on your&lt;/span&gt;
                                        &lt;span class=&quot;c1&quot;&gt;// filesystem but you don&amp;#39;t have to worry about that.&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;flag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;args&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;flag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;Please specify start page&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Exit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;resp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;defer&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;resp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
  
  &lt;span class=&quot;nx&quot;&gt;links&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;collectlinks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;All&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// Here we use the collectlinks package&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;link&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;links&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// &amp;#39;for&amp;#39; + &amp;#39;range&amp;#39; in Go is like .each in Ruby or&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;link&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;            &lt;span class=&quot;c1&quot;&gt;// an iterator in many other languages.&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;                              &lt;span class=&quot;c1&quot;&gt;// When we call range() on a list each iteration of the&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;                                &lt;span class=&quot;c1&quot;&gt;// contents will set two variables: the index and the value.&lt;/span&gt;
                                 &lt;span class=&quot;c1&quot;&gt;// Here we don&amp;#39;t care about the index so we set it to &amp;#39;_&amp;#39;&lt;/span&gt;
                                 &lt;span class=&quot;c1&quot;&gt;// because if we write &amp;#39;for index, link := range(links)&amp;#39;&lt;/span&gt;
                                 &lt;span class=&quot;c1&quot;&gt;// Go would point out that we left &amp;#39;index&amp;#39; unused.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If you run this against a simple website this’ll work fine:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;go run crawl.go http://6brand.com&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;But if you try to run it against an https-secured site it may error out because it&lt;br /&gt;
can’t validate the SSL cert. We don’t care about security in this toy app so let’s&lt;br /&gt;
disable the SSL verification.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;&lt;span class=&quot;c1&quot;&gt;//// file: crawl.go&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;main&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&amp;quot;crypto/tls&amp;quot;&lt;/span&gt;   &lt;span class=&quot;c1&quot;&gt;// we&amp;#39;ll import this package to get access to some&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&amp;quot;flag&amp;quot;&lt;/span&gt;         &lt;span class=&quot;c1&quot;&gt;// low-level transport customizations&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&amp;quot;fmt&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&amp;quot;github.com/jackdanger/collectlinks&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&amp;quot;net/http&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&amp;quot;os&amp;quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;flag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;args&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;flag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;Please specify start page&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Exit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;tlsConfig&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;tls&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;                 &lt;span class=&quot;c1&quot;&gt;// The &amp;amp;thing{a: b} syntax is equivalent to&lt;/span&gt;
                 &lt;span class=&quot;nx&quot;&gt;InsecureSkipVerify&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// new(thing(a: b)) in other languages.&lt;/span&gt;
               &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;                            &lt;span class=&quot;c1&quot;&gt;// It gives you a new &amp;#39;thing&amp;#39; object (in this&lt;/span&gt;
                                            &lt;span class=&quot;c1&quot;&gt;// case a new &amp;#39;tls.Config&amp;#39; object) and sets the&lt;/span&gt;
                                            &lt;span class=&quot;c1&quot;&gt;// &amp;#39;a&amp;#39; attribute to a value of &amp;#39;b&amp;#39;.&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;transport&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Transport&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;// And we take that tlsConfig object we instantiated&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;TLSClientConfig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;tlsConfig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;// and use it as the value for another new object&amp;#39;s&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;                                &lt;span class=&quot;c1&quot;&gt;// &amp;#39;TLSClientConfig&amp;#39; attribute.&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;client&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Transport&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;transport&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// Go typicaly gives you sane defaults (like &amp;#39;http.Get&amp;#39;)&lt;/span&gt;
                                               &lt;span class=&quot;c1&quot;&gt;// and also provides a way to override them.&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;resp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// this line is basically the same as before, only&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;                   &lt;span class=&quot;c1&quot;&gt;// we&amp;#39;re calling &amp;#39;Get&amp;#39; on a customized client rather&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;                          &lt;span class=&quot;c1&quot;&gt;// than the &amp;#39;http&amp;#39; package directly.&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;defer&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;resp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
  
  &lt;span class=&quot;nx&quot;&gt;links&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;collectlinks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;All&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;link&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;links&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;link&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id=&quot;step-4-concurrency&quot;&gt;Step 4. Concurrency&lt;/h2&gt;

&lt;p&gt;I’ve asked programming questions that required work similar to what we’re doing here in&lt;br /&gt;
programming interviews and the step that candidates need the most help with is building&lt;br /&gt;
some kind of queue. If you were to crawl the internet without queueing up the links you&lt;br /&gt;
found you’d just visit the top link of every page and rapidly, in a depth-first search&lt;br /&gt;
across the whole web, exhaust your resources without ever visiting the second link on&lt;br /&gt;
the first page. To avoid that we need to keep some kind of queue where we put links we&lt;br /&gt;
find in the back of it and we visit pages that we pull off the front of the queue.&lt;/p&gt;

&lt;p&gt;In C# we’d using a &lt;code&gt;ConsumingQueue&lt;/code&gt;, in Ruby we’d probably require the stdlib’s &lt;code&gt;Queue&lt;/code&gt;,&lt;br /&gt;
and in Java we’d use a &lt;code&gt;ConcurrentLinkedQueue&lt;/code&gt; or something. Go gives us a great&lt;br /&gt;
alternative: a channel. It’s kinda like a lightweight thread that abstracts away some&lt;br /&gt;
concurrency primitives for you and functions much like a queue.&lt;/p&gt;

&lt;p&gt;We’ll create a channel when we start the program and we’ll put our starting URL into it.&lt;br /&gt;
Then we’ll begin to read URLs from the channel and whenever we find new URLs we’ll write&lt;br /&gt;
them to the channel, effectively putting them into the back of our queue.&lt;/p&gt;

&lt;p&gt;The queue will grow continuously over time because we’re putting things in faster than&lt;br /&gt;
we take them out but we just don’t care.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;&lt;span class=&quot;c1&quot;&gt;//// file: crawl.go&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;main&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&amp;quot;crypto/tls&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&amp;quot;flag&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&amp;quot;fmt&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&amp;quot;github.com/jackdanger/collectlinks&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&amp;quot;net/http&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&amp;quot;os&amp;quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;flag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;args&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;flag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;Please specify start page&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Exit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;queue&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;make&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;chan&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;         &lt;span class=&quot;c1&quot;&gt;// This gives you a new channel that&lt;/span&gt;
                                     &lt;span class=&quot;c1&quot;&gt;// receives and delivers strings. There&amp;#39;s nothing&lt;/span&gt;
                                     &lt;span class=&quot;c1&quot;&gt;// more you need to do to set it up – it&amp;#39;s&lt;/span&gt;
                                     &lt;span class=&quot;c1&quot;&gt;// all ready to have data fed into it.&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;            &lt;span class=&quot;c1&quot;&gt;// saying &amp;quot;go someFunction()&amp;quot; means&lt;/span&gt;
                         &lt;span class=&quot;c1&quot;&gt;// &amp;quot;run someFunction() asynchronously&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;queue&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;     &lt;span class=&quot;c1&quot;&gt;// This means &amp;quot;put args[0] into the channel&amp;quot;.&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}()&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;uri&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;range&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;queue&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;     &lt;span class=&quot;c1&quot;&gt;// &amp;#39;range&amp;#39; is such an effective iterator keyword&lt;/span&gt;
                               &lt;span class=&quot;c1&quot;&gt;// that if you ask for the range of a channel it&amp;#39;ll&lt;/span&gt;
                               &lt;span class=&quot;c1&quot;&gt;// do an efficient, continuous blocking read of&lt;/span&gt;
                               &lt;span class=&quot;c1&quot;&gt;// all the channel contents.&lt;/span&gt;

    &lt;span class=&quot;nx&quot;&gt;enqueue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;queue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// we pass each URL we find off to be read &amp;amp; enqueued&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;enqueue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;uri&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;queue&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;chan&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;fetching&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;tlsConfig&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;tls&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;InsecureSkipVerify&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;transport&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Transport&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;TLSClientConfig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;tlsConfig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;client&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Transport&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;transport&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;resp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;defer&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;resp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;links&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;collectlinks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;All&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;link&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;range&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;links&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;queue&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;link&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}()&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// We asynchronously enqueue what we&amp;#39;ve found&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The flow now is that &lt;code&gt;main&lt;/code&gt; has a &lt;code&gt;for&lt;/code&gt; loop reading from the channel called &lt;code&gt;queue&lt;/code&gt;&lt;br /&gt;
and &lt;code&gt;enqueue&lt;/code&gt; does the HTTP retrieval and link parsing, putting the discovered&lt;br /&gt;
links into the same queue used by &lt;code&gt;main&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you try running our code so far it’ll work but you’ll immediately discover two&lt;br /&gt;
things: The World Wide Web is a messy place full of invalid links and most pages link to&lt;br /&gt;
themselves.&lt;/p&gt;

&lt;p&gt;So let’s add some sanity to our code.&lt;/p&gt;

&lt;h2 id=&quot;step-5-data-sanitization&quot;&gt;Step 5. Data sanitization&lt;/h2&gt;

&lt;p&gt;To properly explore the web let’s turn all of the relative links we find into absolute&lt;br /&gt;
links.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;&lt;span class=&quot;kn&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;main&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&amp;quot;crypto/tls&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&amp;quot;flag&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&amp;quot;fmt&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&amp;quot;github.com/jackdanger/collectlinks&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&amp;quot;net/http&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&amp;quot;net/url&amp;quot;&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// We&amp;#39;re going to use the standard library&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&amp;quot;os&amp;quot;&lt;/span&gt;       &lt;span class=&quot;c1&quot;&gt;// to fix our URLs&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;flag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;args&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;flag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;Please specify start page&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Exit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;queue&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;make&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;chan&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;queue&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}()&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;uri&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;range&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;queue&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;enqueue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;queue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;enqueue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;uri&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;queue&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;chan&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;fetching&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;transport&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Transport&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;TLSClientConfig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;tls&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;InsecureSkipVerify&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;client&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Transport&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;transport&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;resp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;defer&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;resp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;links&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;collectlinks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;All&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; 

  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;link&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;range&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;links&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;absolute&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fixUrl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;link&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;      &lt;span class=&quot;c1&quot;&gt;// Don&amp;#39;t enqueue the raw thing we find,&lt;/span&gt;
                                       &lt;span class=&quot;c1&quot;&gt;// fix it first.&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;uri&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;                     &lt;span class=&quot;c1&quot;&gt;// We&amp;#39;ll set invalid URLs to blank strings&lt;/span&gt;
                                       &lt;span class=&quot;c1&quot;&gt;// so let&amp;#39;s never send those to the channel. &lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;queue&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;absolute&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fixUrl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;base&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// given a relative link and the page on&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;              &lt;span class=&quot;c1&quot;&gt;// which it&amp;#39;s found we can parse them&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;                          &lt;span class=&quot;c1&quot;&gt;// both and use the url package&amp;#39;s&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;                              &lt;span class=&quot;c1&quot;&gt;// ResolveReference function to figure&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;                                        &lt;span class=&quot;c1&quot;&gt;// out where the link really points.&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;baseUrl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;          &lt;span class=&quot;c1&quot;&gt;// If it&amp;#39;s not a relative link this&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;                          &lt;span class=&quot;c1&quot;&gt;// is a no-op.&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;uri&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;baseUrl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ResolveReference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;                      &lt;span class=&quot;c1&quot;&gt;// We work with parsed url objects in this&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;                                          &lt;span class=&quot;c1&quot;&gt;// func but we return a plain string.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now you’re cookin’. This program will now pretty reliably walk around the web&lt;br /&gt;
downloading and parsing pages. However, there’s still one thing we lack.&lt;/p&gt;

&lt;h2 id=&quot;step-6-avoiding-loops&quot;&gt;Step 6. Avoiding Loops&lt;/h2&gt;

&lt;p&gt;Nothing so far prevents us from visiting a page that has one link pointing to itself and&lt;br /&gt;
just looping on that single page forever. That’s dumb, let’s not fetch any page more&lt;br /&gt;
than once.&lt;/p&gt;

&lt;p&gt;The right data structure for keeping track of the presence or absense of things is a&lt;br /&gt;
set. Go, like Javascript, doesn’t have a native way of doing sets so we need to use a&lt;br /&gt;
map (a.k.a a hash or hashmap or a dictionary) with urls as keys to keep track of which&lt;br /&gt;
pages we’ve visited.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;&lt;span class=&quot;kn&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;main&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&amp;quot;crypto/tls&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&amp;quot;flag&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&amp;quot;fmt&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&amp;quot;github.com/jackdanger/collectlinks&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&amp;quot;net/http&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&amp;quot;net/url&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&amp;quot;os&amp;quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

                                     &lt;span class=&quot;c1&quot;&gt;// Putting a variable outside a function is Go&amp;#39;s&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;visited&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;make&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// version of a global variable.&lt;/span&gt;
                                     &lt;span class=&quot;c1&quot;&gt;// This is a map of string -&amp;gt; bool, so&lt;/span&gt;
                                     &lt;span class=&quot;c1&quot;&gt;// visited[&amp;quot;hi&amp;quot;] works but visited[6] doesn&amp;#39;t.&lt;/span&gt;
                                     &lt;span class=&quot;c1&quot;&gt;// Setting a value in a map is a simple as:&lt;/span&gt;
                                     &lt;span class=&quot;c1&quot;&gt;//   visited[&amp;quot;google.com&amp;quot;] = true&lt;/span&gt;
                                     &lt;span class=&quot;c1&quot;&gt;// and reading is equally so:&lt;/span&gt;
                                     &lt;span class=&quot;c1&quot;&gt;//   visited[&amp;quot;google.com&amp;quot;] &lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;flag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;args&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;flag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;Please specify start page&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Exit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;queue&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;make&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;chan&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;queue&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}()&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;uri&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;range&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;queue&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;enqueue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;queue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;enqueue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;uri&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;queue&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;chan&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;fetching&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;visited&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;                        &lt;span class=&quot;c1&quot;&gt;// Record that we&amp;#39;re going to visit this page&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;transport&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Transport&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;TLSClientConfig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;tls&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;InsecureSkipVerify&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;client&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Transport&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;transport&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;resp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;defer&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;resp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;links&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;collectlinks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;All&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; 

  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;link&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;range&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;links&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;absolute&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fixUrl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;link&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;uri&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;visited&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;absolute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;          &lt;span class=&quot;c1&quot;&gt;// Don&amp;#39;t enqueue a page twice!&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;queue&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;absolute&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}()&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fixUrl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;base&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;baseUrl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;uri&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;baseUrl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ResolveReference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And now you can start at any html page you like and slowly explore the entire world wide&lt;br /&gt;
web.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;go run crawl.go http://6brand.com&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Full source code is available &lt;a href=&quot;https://github.com/JackDanger/gocrawler&quot;&gt;on GitHub&lt;/a&gt; as well.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>How do you break up a Rails monolith?</title>
   <link href="http://6brand.com/how-do-you-break-up-a-rails-monolith.html"/>
   <updated>2013-12-22T00:00:00-08:00</updated>
   <id>http://6brand.com/how-do-you-break-up-a-rails-monolith.html</id>
   <content type="html">&lt;p&gt;This was originally posted &lt;a href=&quot;http://www.quora.com/Ruby-on-Rails/What-steps-have-software-developers-taken-at-startups-with-a-Monorail-a-large-monolithic-Ruby-on-Rails-app-to-successfully-break-it-into-services?share=1&quot;&gt;on Quora&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;part-1-why-a-monolith-is-hard&quot;&gt;Part 1: Why a monolith is hard&lt;/h2&gt;

&lt;h3 id=&quot;number-of-contributors&quot;&gt;Number of contributors&lt;/h3&gt;
&lt;p&gt;Your application probably made a lot of sense when fewer than a dozen developers contributed to it. As your headcount scales so does the desire of individual engineers to work outside the globally-shared assumptions of a single codebase.&lt;/p&gt;

&lt;h3 id=&quot;lines-of-code&quot;&gt;Lines of code&lt;/h3&gt;
&lt;p&gt;Every additional file makes the percentage of the project that an individual engineer understands smaller. We don’t like to work on things we don’t understand, so unless we built the whole thing a large project just feels wrong.&lt;/p&gt;

&lt;h3 id=&quot;data-growth&quot;&gt;Data growth&lt;/h3&gt;
&lt;p&gt;If your application assumes that every piece of data can be relationally joined to any other piece of data then you’re limited to storing only as much data as fits on a single hard drive. At the time of writing the very largest, fastest drive you can get is a 6TB drive from Fusion-IO. It is not cheap. Once you outgrow that you have to split your data up into parts and it may be easier to break up your application than teach your application to connect to multiple datastores.&lt;/p&gt;

&lt;h3 id=&quot;speed&quot;&gt;Speed&lt;/h3&gt;
&lt;p&gt;Any large application will have some helpful code that is commonly-enough used that it becomes part of the framework. This may be that every web request looks up the user’s physical location via geo-ip or decrypts encrypted cookies, etc. When you have a feature that has to be super-fast you’ll wish it were on its own so all of the main app’s assumptions didn’t apply to it.&lt;/p&gt;

&lt;h3 id=&quot;upgrading-dependencies&quot;&gt;Upgrading dependencies&lt;/h3&gt;
&lt;p&gt;In a huge, well-aged app it’s a giant pain to upgrade the dependencies (like moving to a more modern Rails release). Smaller systems can be more easily upgraded as there are fewer lines of code to modify and fewer changes will be made by other engineers concurrently. This is a bit of a lie, however, because a well-designed monolith has dependencies abstracted away such that the upgrading difficulty is the same.&lt;/p&gt;

&lt;h3 id=&quot;the-underlying-problem&quot;&gt;The underlying problem&lt;/h3&gt;
&lt;p&gt;Behind the above 4 things is the real problem: tech debt scales poorly. You can get away with crappy code when your application is 99% the Rails framework and 1% your code. Once it’s 15-25% your code then you own the bugs and the poor design. And, unless you have no engineers contributing to or users using the application, there’s inertia behind the current poor design.&lt;/p&gt;

&lt;h2 id=&quot;part-2-how-to-break-up-your-monolith&quot;&gt;Part 2: How to break up your monolith&lt;/h2&gt;

&lt;h4 id=&quot;extract-the-most-important-thing&quot;&gt;Extract the most important thing&lt;/h4&gt;
&lt;p&gt;At AirB&amp;amp;B, Yammer, and Square the first parts extracted from the monolith were the high-performance or high-critical parts. Whatever behavior your app has to do fast, correctly, and constantly that is directly related to your competitive advantage as a business is the first thing you extract. This allows you to rebuild this feature properly and it lightens the stress on the monolith. Once you have, say, credit card payments not running straight through your monolith you can breathe a little easier.&lt;/p&gt;

&lt;p&gt;Chances are, though, that after this first extraction there is more code in your monolith because now you’re coordinating the data between the two applications. There are still features in the monolith that depend on data in the extracted service (or vice versa) so you have to bridge them somehow. This has not solved your problem.&lt;/p&gt;

&lt;h3 id=&quot;extract-more-things&quot;&gt;Extract more things&lt;/h3&gt;
&lt;p&gt;Especially if data growth is your problem you can probably buy yourself some runway by finding any data that looks or smells like a log of activity and move it out into a proper logging or analytics service. This still doesn’t solve your problem, however.&lt;/p&gt;

&lt;h3 id=&quot;build-new-features-in-new-services&quot;&gt;Build new features in new services&lt;/h3&gt;
&lt;p&gt;You’ve reached a tipping point when you have the platform support to create a new service for new features rather than having to build the features first in the monolith. This’ll slow the growth of the monolith by giving you an outlet for new development. It’ll also mean that you have a small team dedicated full-time to coordinating services and building synchronous and batch interfaces between them. This has actually made your problem slightly worse.&lt;/p&gt;

&lt;p&gt;If you follow this path long enough and with enough engineers you no longer have a monolith. You have several. There’s the old one (now slightly tamed) and probably at least one new one that, if you were publish the source, would cause people to gawk at its size and sprawl.&lt;/p&gt;

&lt;h2 id=&quot;part-2-for-real-how-to-actually-break-up-your-monolith&quot;&gt;Part 2 for real: How to actually break up your monolith&lt;/h2&gt;

&lt;h3 id=&quot;you-need-to-design-your-systems&quot;&gt;You need to design your systems.&lt;/h3&gt;
&lt;p&gt;When your startup is tiny and your biggest threat is that you’ll shut down before anybody hears of you then you’re just building whatever works. You’re probably writing good code but you are likely not writing good systems. This is okay in the beginning but once you’re surviving and trying to hire many more engineers you’ll need to rethink how you organize everything.&lt;/p&gt;

&lt;h3 id=&quot;start-with-data&quot;&gt;Start with data&lt;/h3&gt;
&lt;p&gt;The most important thing in your company is your data, not your code. So build a system that caters to the size and shape of your data. If you do financial work does the schema of your database use domain concepts that a CPA would recognize? What secondary datastore will you need to analyze your data (to avoid ruining the schema and scalability of the db where it was created)? Is there a natural way to shard your customers? What parts of your data are derivable from others? What can be eventually consistent and what needs to be consistent at all times?&lt;/p&gt;

&lt;p&gt;One mistake I’ve often made is to try to centralize data about a single entity in a single place. In fact, as long as every entity (e.g. a user) has a unique token generated for it then each service and application can and should keep it’s own private data about the entity and communicate to each other using the unique token. You can always generate a complete synthesis of data by pulling information from multiple services. You don’t need to centralize most data any more than you need to centralize most code.&lt;/p&gt;

&lt;h3 id=&quot;think-about-the-usage-profile-of-your-services&quot;&gt;Think about the usage profile of your services&lt;/h3&gt;
&lt;p&gt;Once you extract your first service you might be stunned to notice that, now that you have users, some parts of your system have orders of magnitude more usage than others. People might be favoriting/sharing things 10,000 times per second but you’re only seeing signups happen 5 times per second. If this is the case then you can optimize the signup code to be friendly to your designers and ensure a development experience there that’s optimized for rapid iteration and A/B testing at the low cost of a few extra servers. And maybe you need to rewrite your favoriting/sharing service in Clojure from the ground up just to eek out every bit of performance.&lt;/p&gt;

&lt;p&gt;There will be parts of your system that require speed, others that require ultra-high-availability, and others that are mere test features where the important quality is that you can ship them and scrap them fast. Each of this requires a different application design and, frankly, probably different programming languages.&lt;/p&gt;

&lt;h3 id=&quot;get-your-interfaces-right&quot;&gt;Get your interfaces right&lt;/h3&gt;
&lt;p&gt;When all your code is in one app you know that you’re using other code correctly because you’ll get an ArgumentError if you improperly invoke a method or a NoMethodError if you try to call a method with a typo’d name. This doesn’t work across service boundaries.&lt;/p&gt;

&lt;p&gt;You have two choices for inter-service communication:&amp;lt;/ br&amp;gt;&lt;br /&gt;
Write documentation for humans to read and a build a CURL-able API into every services so that they can verify they did things properly. Pray the service and clients never miss an API update.&lt;br /&gt;
Use some machine-parseable contract of the API between client and server. Your options here are Thrift, JSON-schema, Google protobuffers, msgpack, capnproto, Blink and probably a few others. These will allow you to ship your API definition to any client and let them validate the schema of any inter-service message before they send it.&lt;/p&gt;

&lt;h3 id=&quot;delete-everything-you-can&quot;&gt;Delete everything you can&lt;/h3&gt;
&lt;p&gt;If you’ve made it this far then you probably have 20+ services and there are diminishing returns to adding any new service – the system isn’t getting any simpler. So the next step in splitting out your monolith into services is bold: delete old features and code. At some point every company needs to carefully review all the features they’ve written to see if they can be deleted or replaced with something simpler. For example, my team recently deleted 16 large, complex files that operated a flaky batch processing job because the service we were sending batch files to had built a better API in the last two years.&lt;/p&gt;

&lt;p&gt;Really, anything to lower the amount of code and/or data going through your system (in any service) will mitigate the pain you felt when you started breaking up this monolith.&lt;/p&gt;

&lt;h2 id=&quot;part-3-doing-this-with-a-rails-application&quot;&gt;Part 3: Doing this with a Rails application&lt;/h2&gt;

&lt;p&gt;First the good news: Ruby on Rails apps have a standardized organizational structure and years of community best practices that help you keep things in place while you grow. This means that a Monorail (Rails monolith) can grow immensely larger than an application in most languages and still continue to function. As long as you have good tests your 200-controller Rails/ActiveRecord app will be far more pleasant to work with than a 200-controller Java/Hibernate app.&lt;/p&gt;

&lt;p&gt;Now, the bad news: Ruby has very poor tooling for in-process dependencies. You are allowed to require anything in the load path at any time and circular dependencies are totally normal as long as you’re willing to do some kind of delayed initialization. This means your Monorail’s class-level dependencies would not, if displayed in a graph, be a tree structure – they’d be a cyclic non-directed graph. This pattern is also called the “big ball of mud” software pattern.&lt;/p&gt;

&lt;p&gt;So unless you’re SUPER lucky and your developers read Sandi Metz’ book (search for ‘POODR’) they won’t have added explicit ‘require’ statements at the top of source code files and will instead just assume that everything gets loaded into memory all the time.&lt;/p&gt;

&lt;p&gt;So your biggest challenge dissecting a Monorail is straightening out the dependencies such that you know what’s referring to what. Once you know that feature X can live in a separate database (or service) and nothing will try to join its SQL queries across feature X’s tables then the extraction is relatively straightforward. But getting there is hard because there’s currently no tool that I know of to analyze the kinds of queries you make in production and develop a dependency graph of models. Please build this and I’ll totally use it.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>The Upside-Down Org Chart</title>
   <link href="http://6brand.com/the-upside-down-org-chart.html"/>
   <updated>2013-12-01T00:00:00-08:00</updated>
   <id>http://6brand.com/the-upside-down-org-chart.html</id>
   <content type="html">&lt;p&gt;A corporate organizational chart is drawn as a tree. It’s got a CEO at the root and then splits out to executives and then keeps branching further until you get to the people doing the actual work. Weirdly, this tree is drawn with the root up in the sky and individual contributors (often drawn very small) at the bottom. We use words like “managing up” and “climbing the corporate ladder” and “the decision came from above” as a reflection of this mental image – CEO on top, people on bottom. The up/down contrast is important because in this structure the people on top have more power to make decisions, more interesting labor to perform, and higher compensation. Those at the top communicate commands and desires down to people at the bottom. The top jobs are in every way better.&lt;/p&gt;

&lt;p class=&quot;photo&quot;&gt;&lt;img src=&quot;/images/orgchart.patriarchal.jpg&quot; width=&quot;600&quot; /&gt;&lt;span class=&quot;caption&quot;&gt;&quot;Working at BigCo&amp;reg; is so much fun!&quot;&lt;br /&gt;&amp;mdash; BigCo&amp;reg; CEO&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;This structure is very old. It’s basically &lt;a href=&quot;http://en.wikipedia.org/wiki/Patriarchy&quot;&gt;patriarchy&lt;/a&gt; and appears in armies, farms, and governments almost as far back as we have historical records&lt;a href=&quot;#links&quot; name=&quot;cite-1&quot; class=&quot;cite&quot;&gt;[1]&lt;/a&gt;. This structure is traditionally quite static - wherever you start is where you stay. Nobody wants to give up a higher spot to someone else and certainly nobody wants to move down. Napoleon’s &lt;a href=&quot;http://en.wikipedia.org/wiki/Grande_Arm%C3%A9e#Ranks_of_the_Grande_Arm.C3.A9e&quot;&gt;Grande Armèe&lt;/a&gt; was one of the first organizations to attempt promotion based on merit and not class and we’ve adopted that compromise in modern corporations. But both in the Napoleon’s case and ours “merit” is so vague as to be indistinguishable from class.&lt;/p&gt;

&lt;p&gt;I know hundreds of developers who refuse to work at a large company because of this structure. Nobody wants their work to be compromised by constantly having to “manage up” and certainly nobody wants to hand the benefits of their work to somebody else. There’s a saying I keep hearing that goes “Nobody quits their job, they &lt;a href=&quot;http://businesspaths.net/Articles/12/people-quit-their-boss-not-their-job&quot;&gt;quit their boss&lt;/a&gt;.” And there are plenty of bad managers in tech – often a result of “promoting” a veteran engineer to people management as a retention strategy.&lt;/p&gt;

&lt;p&gt;Unions try to solve the problem of bad managers and top-down negative pressure by pushing upwards through collective bargaining. Elon Musk famously claimed you don’t need unions if you just &lt;a href=&quot;http://www.wired.com/business/2009/06/elon-musk-on-the-inevitability-of-the-ev-running-detroit-and-firing-a-certain-someone/&quot;&gt;fire the assholes&lt;/a&gt;. But if you’ve got nice managers &lt;a href=&quot;http://psycnet.apa.org/journals/rev/110/2/265/&quot;&gt;exerting negative pressure downwards&lt;/a&gt;&lt;a href=&quot;#links&quot; name=&quot;cite-2&quot; class=&quot;cite&quot;&gt;[2]&lt;/a&gt; because of the very structure of the organization, then firing just the jerks won’t save you.&lt;/p&gt;

&lt;p&gt;Some companies are experimenting with a flat management structure to solve this problem. GitHub, Stripe and Valve are famously self-organized. &lt;a href=&quot;http://morningstarco.com/index.cgi?Page=Self-Management&quot;&gt;Morning Star&lt;/a&gt; is a non-tech company that has succeeded with the non-managerial approach as well. The theory is that if there are fewer people above you on the org chart then there is less negative pressure on you and you’ll be able to produce at the same high potential as if you were entirely self-directed. A self-managed company accepts increased chaos and takes a risk of potential non-productivity and in return gets the value of actually highly increased individual productivity. It’s as if every employee were the CEO of their own little company.&lt;/p&gt;

&lt;p class=&quot;photo&quot;&gt;&lt;a href=&quot;https://twitter.com/wycats/statuses/368752712894017536&quot;&gt;&lt;img src=&quot;/images/yehuda-mgmt.jpg&quot; width=&quot;600&quot; /&gt;&lt;/a&gt;&lt;span class=&quot;caption&quot;&gt;Yehuda isn&apos;t a fan of the flat-structure approach.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Removing managers rescues us from TPS reports and micro-managing but we still need to form into teams to accomplish anything of note. We can let these teams occur organically but then we suffer from the realities of &lt;a href=&quot;http://en.wikipedia.org/wiki/Emergence#Spontaneous_order&quot;&gt;emergent behavior&lt;/a&gt;: Left alone long enough every self-organizing bay area software team will accidentally build a bartending quad-copter running Node. There will never emerge a QuickBooks replacement that’s tax-compliant in all 50 states and Puerto Rico. You’re going to get a product that meets the immediate, bodily-felt needs of its creators because there’s no structure in place to acquire information from customers, verify the accuracy of this information, and provide it in a usable form to the engineers.&lt;/p&gt;

&lt;p&gt;There is a solution to bad managers that doesn’t require a flat company structure: good managers. And I don’t mean good people as managers (most bad managers are very friendly); I mean people who believe their job is to empower those they serve and make it easier for the individuals to function as a group. A good manager directs and augments the energies of a team without adding resistance to that energy. A good manager thinks their team is their boss. And a good manager expects the same support from their manager.&lt;/p&gt;

&lt;p&gt;To get leaders like this you don’t just need to hire well, you need to reorganize your structure to illustrate the roles. If we want managers to be empowering we need to fix our org charts to be a proper tree: root on bottom, branches above, leaves on top.&lt;/p&gt;

&lt;p&gt;This inverted&lt;a href=&quot;#links&quot; name=&quot;cite-3&quot; class=&quot;cite&quot;&gt;[3]&lt;/a&gt; org chart effectively evens out the broken power dynamics of the patriarchal model. The language itself is fixed: “I rely on my manager.” “I support my team.” “Because we’re way up here the CEO needs us to tell them what we see.” “I’m not sure I want to take on the weight of another team – that’s a lot to support.”&lt;/p&gt;

&lt;p class=&quot;photo&quot;&gt;&lt;img src=&quot;/images/orgchart.inverted.jpg&quot; width=&quot;600&quot; /&gt;&lt;span class=&quot;caption&quot;&gt;There are no &quot;promotions&quot; here; you can move to positions with less organizational responsibility and more task responsibility or vice versa.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;This also helps us fix compensation because if there’s a sense that someone near the root is actually holding up more of the company (and the people they serve feel that support) then it doesn’t feel unjust to pay them more.&lt;/p&gt;

&lt;p&gt;For a tech company to describe their structure this way requires some humility from the leadership. It requires accepting that senior positions must be evaluated based on the support given to individuals on the team rather than the support given to the CEO or executives. But it makes the structure one in which nothing is extracted from the laborers – indeed it provides help that an individual could not find working alone.&lt;/p&gt;

&lt;p&gt;If you want an engineer to work as slowly and sadly as possible, place them at a BigCo® where all the power is top-down (CEO-down) and tell them what to do. If you want them to produce something amazing, then place them in a team of people with all the resources of a supporting manager, a supporting corporate team, and total freedom to do their best work in the way they best see fit. You need only communicate the needs of the end customer clearly and then the work will get done.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;links&quot;&gt; &lt;/a&gt;&lt;br /&gt;
Links:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;a href=&quot;#cite-1&quot;&gt; ^&lt;/a&gt; Patriarchy only goes back about 3,000 years and seems to have originated as a survival mechanism during times of trouble. &lt;a href=&quot;http://en.wikipedia.org/wiki/Patriarchy#cite_ref-18&quot;&gt;http://en.wikipedia.org/wiki/Patriarchy#cite_ref-18&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#cite-2&quot;&gt; ^&lt;/a&gt; This study asked 3 people to write a paper and put one person nominally in charge. When the group was given 5 cookies the ‘boss’ would eat 2 cookies, not just 1, and would typically do it sloppily with their mouth open and getting crumbs on their shirt: &lt;a href=&quot;http://psycnet.apa.org/journals/rev/110/2/265/&quot;&gt;http://psycnet.apa.org/journals/rev/110/2/265/&lt;/a&gt;. So the very nature of ‘boss’ causes good people to have a negative effect on those they boss.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#cite-3&quot;&gt; ^&lt;/a&gt; Let’s be real, this &lt;a href=&quot;http://www.biblegateway.com/passage/?search=Luke%2022:26&quot;&gt;isn’t a new idea&lt;/a&gt;. It’s ancient, well-loved, and just very rarely used in human organizations.  Or, if you prefer, &lt;a href=&quot;http://silentvoicesbible.com/voices/42-luke-022.html#026&quot;&gt;http://silentvoicesbible.com/voices/42-luke-022.html#026&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</content>
 </entry>
 
 <entry>
   <title>Skinny Models – the DAO pattern for Ruby persistence</title>
   <link href="http://6brand.com/skinny-models-the-dao-pattern-for-ruby-persistence.html"/>
   <updated>2013-07-20T00:00:00-07:00</updated>
   <id>http://6brand.com/skinny-models-the-dao-pattern-for-ruby-persistence.html</id>
   <content type="html">&lt;p&gt;For those used to ActiveRecord-style&lt;br /&gt;
development the following might not seem all that bad:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ActiveRecord&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;belongs_to&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:account&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;has_many&lt;/span&gt;   &lt;span class=&quot;ss&quot;&gt;:posts&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;validates_format_of&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:with&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;/@/&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;after_create&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:deliver_welcome_email&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;after_create&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:mark_pending&lt;/span&gt;

  &lt;span class=&quot;kp&quot;&gt;private&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;mark_pending&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;update_attributes!&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:state&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;pending&amp;#39;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;deliver_welcome_email&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;ApplicationMailer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;deliver&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:welcome_email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;email&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If you’ve read &lt;a href=&quot;http://www.poodr.info/&quot;&gt;Sandi Metz’ book&lt;/a&gt; (or have an OO&lt;br /&gt;
background) you’ll notice something about this conventional Rails code.&lt;br /&gt;
Not only is it a huge mess of dependencies, it violates damn near every&lt;br /&gt;
part of&lt;br /&gt;
[SOLID](http://en.wikipedia.org/wiki/SOLID_(object-oriented_design)&lt;br /&gt;
object-oriented design that we practice as a means of keeping our code&lt;br /&gt;
nimble.&lt;/p&gt;

&lt;p&gt;So what’s the alternative?. The &lt;a href=&quot;http://en.wikipedia.org/wiki/Data_access_object&quot;&gt;Data Access&lt;br /&gt;
Object&lt;/a&gt; pattern uses an&lt;br /&gt;
object to manage persistence and doesn’t let that object do anything&lt;br /&gt;
else. Effectively, it makes the above class look like this:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ActiveRecord&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;belongs_to&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:account&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;has_many&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:posts&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Or, if you want to get religious:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ActiveRecord&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;(Personally, I think associations are the thing ActiveRecord does right&lt;br /&gt;
so I’m fine leaving those in.)&lt;/p&gt;

&lt;p&gt;We just took a lot of code out of the &lt;code&gt;User&lt;/code&gt; class and it has to go&lt;br /&gt;
somewhere else. Where? Well, that depends on what it does. Consider this&lt;br /&gt;
reorganization:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ActiveRecord&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;belongs_to&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:account&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;has_many&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:posts&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Validator&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Invalid&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;StandardError&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
                                   
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;validate!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;email&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=~&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;/@/&lt;/span&gt;   
      &lt;span class=&quot;k&quot;&gt;raise&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Invalid&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Email&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;welcome&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;## Handle email delivery&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;StateMachine&lt;/span&gt;

  &lt;span class=&quot;kp&quot;&gt;attr_reader&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:record&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initialize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# I&amp;#39;m making the StateMachine instantiable because&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@record&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;record&lt;/span&gt;      &lt;span class=&quot;c1&quot;&gt;# the &amp;#39;record&amp;#39; object feels like internal state and&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;                     &lt;span class=&quot;c1&quot;&gt;# there may be actions we want to perform on that&lt;/span&gt;
                          &lt;span class=&quot;c1&quot;&gt;# object during a state transition&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;pending!&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;state&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;pending&amp;#39;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;save!&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Signup&lt;/span&gt;
                                   &lt;span class=&quot;c1&quot;&gt;# You now have to use this to tell Signup&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;persistence=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;db_model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# what object is in charge of database&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@persistence&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;db_model&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;# persistence. This is where you pass in&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;                              &lt;span class=&quot;c1&quot;&gt;# your DAO or, in tests, your stub object&lt;/span&gt;
                                 
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;complete!&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;              &lt;span class=&quot;c1&quot;&gt;# I&amp;#39;m not bothering to make Signup an instantiable&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;record&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@persistence&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# class at this point because we don&amp;#39;t need it yet.&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;Validator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;validate!&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;record&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;save!&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;StateMachine&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pending!&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;Email&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;welcome&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:email&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We now have many more lines of code and many more objects so it might&lt;br /&gt;
look like we just added complexity but in fact we’ve reduced it. If&lt;br /&gt;
complexity is the entanglement of concepts, then we’ve removed nearly all&lt;br /&gt;
complexity from this application. Let’s walk through the changes bit by bit.&lt;/p&gt;

&lt;h3 id=&quot;removing-callbacks&quot;&gt;Removing callbacks&lt;/h3&gt;

&lt;p&gt;We turned a couple &lt;code&gt;after_create&lt;/code&gt; callbacks into&lt;br /&gt;
direct code execution.  You now know exactly when the email address will&lt;br /&gt;
be validated and when the welcome message will be sent. You also know&lt;br /&gt;
how to stub out the objects that perform those functions in your tests.&lt;/p&gt;

&lt;h3 id=&quot;introducing-a-proper-state-machine&quot;&gt;Introducing a proper state machine&lt;/h3&gt;

&lt;p&gt;This is my favorite. There’s a Rails application at work that&lt;br /&gt;
moves a lot of money around and needs to handle many intermediate states&lt;br /&gt;
with very precise rules about when things are purchased, paid for,&lt;br /&gt;
approved, rejected, returned, refunded, etc. If we were to try to&lt;br /&gt;
implement this logic inside an ActiveRecord class we’d be fighting&lt;br /&gt;
against the weight of Rails every time we extended the state graph.&lt;/p&gt;

&lt;p&gt;Most Rails applications I’ve worked on have eventually had some kind of&lt;br /&gt;
state machine in them. I’ve tried &lt;code&gt;acts_as_state_machine&lt;/code&gt;, two gems both&lt;br /&gt;
called &lt;code&gt;state_machine&lt;/code&gt; and I’ve built several terrible and bug-prone&lt;br /&gt;
versions myself. Nothing has worked as well as pulling all the logic out&lt;br /&gt;
into a new class and being very explicit about what kind of state&lt;br /&gt;
transitions your application allows. You’ll notice the interface to the&lt;br /&gt;
persistence object is only two methods large. As long as the object you&lt;br /&gt;
pass in responds to &lt;code&gt;state=&lt;/code&gt; and &lt;code&gt;save!&lt;/code&gt; the &lt;code&gt;StateMachine&lt;/code&gt; class will&lt;br /&gt;
work. Which means you do NOT need to pass in an &lt;code&gt;ActiveRecord&lt;/code&gt; instance in&lt;br /&gt;
your tests – any simple mock will do.&lt;/p&gt;

&lt;h3 id=&quot;adding-sane-validations&quot;&gt;Adding sane validations&lt;/h3&gt;

&lt;p&gt;Two months ago I was in the middle of a Rails2-&amp;gt;Rails3 upgrade and I&lt;br /&gt;
found myself in a &lt;a href=&quot;http://rubygems.org/gems/pry&quot;&gt;pry&lt;/a&gt; console staring at the insides of a&lt;br /&gt;
&lt;code&gt;validates_each&lt;/code&gt; block deep inside Rails. For trivial validations and/or&lt;br /&gt;
trivial applications the Rails way of adding data validation is just&lt;br /&gt;
fine. But when you write the validations yourself you get all the&lt;br /&gt;
following benefits:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;test your validations without simultaneously testing that&lt;br /&gt;
&lt;code&gt;ActiveRecord#save&lt;/code&gt; still works&lt;/li&gt;
  &lt;li&gt;test the edge cases of your validations because you actually control&lt;br /&gt;
how they’re defined and when they fire&lt;/li&gt;
  &lt;li&gt;easily debug your validations because you implemented them in a&lt;br /&gt;
well-factored class&lt;/li&gt;
  &lt;li&gt;write hundreds of validation tests if you want because they’ll all run in&lt;br /&gt;
less than a second.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;separating-application-level-features-from-database-objects&quot;&gt;Separating application-level features from database objects&lt;/h3&gt;

&lt;p&gt;The conventional path would have you type &lt;code&gt;User.create! params[:user]&lt;/code&gt;&lt;br /&gt;
in your controller. This is only good if you’re &lt;em&gt;certain&lt;/em&gt; that creating&lt;br /&gt;
a new User record is the action you’re trying to complete. But more&lt;br /&gt;
likely what you want is to complete a user signup. So&lt;br /&gt;
&lt;code&gt;Signup.complete! params[:user]&lt;/code&gt; is much more descriptive of what you&lt;br /&gt;
want. Maybe you want to create a User record. Maybe you want to create a&lt;br /&gt;
&lt;code&gt;Business&lt;/code&gt; record. Maybe it’s such an important action that you’ll be&lt;br /&gt;
generating &lt;code&gt;Account&lt;/code&gt;, &lt;code&gt;Business&lt;/code&gt;, &lt;code&gt;User&lt;/code&gt;, and &lt;code&gt;Product&lt;/code&gt; records all at&lt;br /&gt;
once. By keeping the controller-level semantics high-level you won’t&lt;br /&gt;
have to change them to keep up with an evolving implementation.&lt;/p&gt;

&lt;h3 id=&quot;and-then-your-tests-go-zoom&quot;&gt;And then your tests go zoom&lt;/h3&gt;

&lt;p&gt;This post isn’t called ‘how to make your Rails tests faster’ but it&lt;br /&gt;
might as well be. The reason your tests are slow is &lt;code&gt;ActiveRecord&lt;/code&gt; and&lt;br /&gt;
&lt;code&gt;ActionController&lt;/code&gt;. Your code (and Ruby) is actually blazing fast but&lt;br /&gt;
it’s organized in such a way that you have to test each object’s&lt;br /&gt;
dependencies if you want to test the object itself.&lt;/p&gt;

&lt;h2 id=&quot;the-tests&quot;&gt;The tests&lt;/h2&gt;

&lt;p&gt;Let’s take a look at what these tests would look like before and after&lt;br /&gt;
the above reorganization. First, the conventional Rails way:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;## file:spec/models/user_spec.rb&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;config/environment&amp;#39;&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# This loads all of Rails and autoloads&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;              &lt;span class=&quot;c1&quot;&gt;# every object automatically&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;creating&amp;#39;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;subject&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;create!&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;params&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;m@rvelo.us&amp;#39;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Marvelous&amp;#39;&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;ss&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;  &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;with invalid email&amp;quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;whoops&amp;#39;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;doesn&amp;#39;t create a new record&amp;quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;expect&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;subject&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;change&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;count&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;with valid params&amp;quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;creates a new record&amp;quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;expect&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;subject&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;change&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;count&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;by&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;sends a welcome email&amp;quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
        &lt;span class=&quot;no&quot;&gt;ActionMailer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;should_receive&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:deliver&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:welcome&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;subject&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;sets the &amp;#39;state&amp;#39; column to &amp;#39;pending&amp;#39;&amp;quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;subject&lt;/span&gt;
        &lt;span class=&quot;no&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;last&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;pending&amp;#39;&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That’s a respectable spec. It’s reasonably clean, tests most of the&lt;br /&gt;
important stuff, and doesn’t go off track testing unnecessary edge cases&lt;br /&gt;
or the implementation of the code (other than the ActionMailer bit).&lt;/p&gt;

&lt;p&gt;However, every example in that snippet booted all of &lt;code&gt;ActiveRecord&lt;/code&gt; and&lt;br /&gt;
tested the full forest of callbacks, validations, database connection&lt;br /&gt;
mechanisms, and relational associations inside ActiveRecord. Rails has&lt;br /&gt;
its own tests so there’s no point in me or you re-testing the Rails&lt;br /&gt;
internals. That just turns our app into a Seti@Home that’s guaranteed&lt;br /&gt;
not to find anything.&lt;/p&gt;

&lt;p&gt;Let’s rewrite that to test only what we care about.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;## file:spec/unit/services/signup_spec.rb&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;app/services/signup&amp;#39;&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# We only require the thing we care about&lt;/span&gt;
                               &lt;span class=&quot;c1&quot;&gt;# and we trust that _it_ will require any&lt;/span&gt;
                               &lt;span class=&quot;c1&quot;&gt;# require any dependencies that it needs.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;FakeDAO&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;ostruct&amp;#39;&lt;/span&gt;               &lt;span class=&quot;c1&quot;&gt;# We don&amp;#39;t want to go saving to the actual&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;instance&lt;/span&gt;               &lt;span class=&quot;c1&quot;&gt;# database all the time, we&amp;#39;ll just assume that&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@instance&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;OpenStruct&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# ActiveRecord still works.&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;attrs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;attrs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;instance&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;send&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;instance&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;send&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;save!=&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;instance&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Signup&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;before&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Signup&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;persistence&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;FakeDAO&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# This is where we inject the dependency&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;subject&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Signup&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;complete!&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;m@rvelo.us&amp;#39;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Marvelous&amp;#39;&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;ss&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;  &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;with invalid email&amp;quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;whoops&amp;#39;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;doesn&amp;#39;t create a new record&amp;quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;expect&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;subject&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;raise_error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Validator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Invalid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;with valid data&amp;quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;creates a new record&amp;quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
      &lt;span class=&quot;no&quot;&gt;FakeDAO&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;instance&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;should_receive&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:save!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;at_least&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;times&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;subject&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;sends a welcome email&amp;quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
      &lt;span class=&quot;no&quot;&gt;Email&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;should_receive&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:welcome&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;subject&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;sets the &amp;#39;state&amp;#39; column to &amp;#39;pending&amp;#39;&amp;quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;subject&lt;/span&gt;
      &lt;span class=&quot;no&quot;&gt;FakeDAO&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;instance&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;pending&amp;#39;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That’s about the same size code as the previous example but it runs in&lt;br /&gt;
less than a hundredth of a millisecond. It also explicitly tests only&lt;br /&gt;
&lt;code&gt;Signup&lt;/code&gt; – the object under test.&lt;/p&gt;

&lt;p&gt;We then get to add individual tests for the other components we’ve&lt;br /&gt;
extracted. Each of those will be focused and obvious.&lt;/p&gt;

&lt;h2 id=&quot;youre-stubbing-things-what-if-a-bug-slips-through-the-cracks&quot;&gt;You’re stubbing things. What if a bug slips through the cracks?&lt;/h2&gt;

&lt;p&gt;It’s only okay to stub the dependencies of an object if two conditions&lt;br /&gt;
hold: You’re stubbing in such a way that you’re unlikely to change the&lt;br /&gt;
core behavior of the object under test and you still have high-level&lt;br /&gt;
integration tests that test the whole suite.&lt;/p&gt;

&lt;p&gt;So if you’re reasonably sane about what you choose to stub and you still&lt;br /&gt;
write a basic high-level test that only tests for the primary cases (not&lt;br /&gt;
edge cases) you can get away with this approach.&lt;/p&gt;

&lt;p&gt;We’ve had enough success with this pattern at work that&lt;br /&gt;
&lt;a href=&quot;http://twitter.com/xshay&quot;&gt;Xavier&lt;/a&gt; added the following to our&lt;br /&gt;
&lt;code&gt;spec/unit_helper.rb&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;RSpec&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;configure&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;before&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:suite&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;const_defined?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Rails&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;const_defined?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;ActiveRecord&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;raise&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;The Rails environment should not be loaded for unit tests.&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That’s right, we throw an error if you’ve required any part of Rails in&lt;br /&gt;
your code. This enforces that you’ve written loosely-coupled,&lt;br /&gt;
dependency-injected, DAO-style persistence-oriented classes whether you&lt;br /&gt;
are familiar with those terms or not. I can’t recommend this snippet of&lt;br /&gt;
code highly enough.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Electricity: the parts I couldn't understand</title>
   <link href="http://6brand.com/electricity-explained-by-a-software-engineer.html"/>
   <updated>2013-05-18T00:00:00-07:00</updated>
   <id>http://6brand.com/electricity-explained-by-a-software-engineer.html</id>
   <content type="html">&lt;p&gt;I want to make robots. Not just a simulation running on a computer but&lt;br /&gt;
real-life Actual® Stuff® with moving parts. The problem is that I’m a&lt;br /&gt;
software engineer and hardware has a steep learning curve. One of the&lt;br /&gt;
biggest surprises is that apparently I never understood electricity at&lt;br /&gt;
all.&lt;/p&gt;

&lt;p&gt;Sometimes it’s helpful to learn from a person who’s just one step ahead of you&lt;br /&gt;
rather than a veteran. To that end I’ll do my best to explain a few concepts&lt;br /&gt;
that didn’t make sense to me when taught the traditional way and what I’ve&lt;br /&gt;
learned as a total amateur. I want to write this all down before I forget what&lt;br /&gt;
was so hard about it.&lt;/p&gt;

&lt;h2 id=&quot;current&quot;&gt;Current&lt;/h2&gt;

&lt;p&gt;Electrons flow from negatively-charged stuff to positively-charged&lt;br /&gt;
stuff. Electricity is the flow of electrons in a current. Sure, thanks.&lt;br /&gt;
Let’s rephrase it: stuff that has too many electrons pushes those&lt;br /&gt;
electrons away toward stuff with too few electrons. There’s going to be&lt;br /&gt;
‘current’ as those electrons get pushed away.&lt;/p&gt;

&lt;p&gt;Here’s what I wish I’d somebody had mentioned to me: &lt;strong&gt;Electrical diagrams are all written backwards&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;They&lt;img class=&quot;inline&quot; alt=&quot;Traffic Beijing&quot; src=&quot;/images/traffic_jam.jpg&quot; original=&quot;http://upload.wikimedia.org/wikipedia/commons/5/50/Changan_avenue_in_Beijing.jpg&quot; /&gt; describe current flowing from positive to negative (red to&lt;br /&gt;
black). Even though electrons are going in the opposite direction. This&lt;br /&gt;
has confused me.  Badly. I once exploded a car battery in high school&lt;br /&gt;
because I knew enough chemistry to understand electron flow but didn’t&lt;br /&gt;
know that ‘ground’ meant ‘where the electrons come from’. Ever since&lt;br /&gt;
then I’ve struggled to get this straight.  Here’s how I now think of it:&lt;br /&gt;
electrical current is like the wave of movement in a traffic jam. The&lt;br /&gt;
cars are all pointing forward but that’s not the direction of the&lt;br /&gt;
current. Whenever the front-most car sees a gap it moves forward, then&lt;br /&gt;
the one behind it takes its place, etc. From an outside observer it&lt;br /&gt;
appears that there is a wave of open space moving backward. The&lt;br /&gt;
electrons are the cars, the wave is the ‘current’.&lt;/p&gt;

&lt;p&gt;So if you see an arrow on a circuit diagram it represents the wave&lt;br /&gt;
moving backwards on a freeway – not the cars themselves.&lt;/p&gt;

&lt;h2 id=&quot;circuits&quot;&gt;Circuits&lt;/h2&gt;

&lt;p&gt;A circuit is a loop in which electrons can flow. They won’t move&lt;br /&gt;
unless you connect a power source to the circuit because the whole point of a&lt;br /&gt;
power source is to continuously push too many electrons into a circuit so they&lt;br /&gt;
all have to move.&lt;/p&gt;

&lt;h2 id=&quot;resistance&quot;&gt;Resistance&lt;/h2&gt;

&lt;p&gt;One&lt;img class=&quot;inline&quot; alt=&quot;This resistor dims the LED&quot; src=&quot;/images/resistor.jpg&quot; original=&quot;http://www.flickr.com/photos/lovelihood/6932789786/&quot; /&gt; of the most basic ways to modify an electrical circuit is to add resistance&lt;br /&gt;
to one part. Here it helps to think of a water pipe that is narrow in the&lt;br /&gt;
middle. The water will be able to move fast or slow depending on how much&lt;br /&gt;
resistance it feels traveling through the middle. There’ll be higher water&lt;br /&gt;
pressure one whichever side the water is coming from but the water will always&lt;br /&gt;
move at the same speed on both ends of the pipe. The pressure is irrelevant –&lt;br /&gt;
the more you constrain the middle the slower the whole pipe will be able to&lt;br /&gt;
move water.  It’s like this with an electrical circuit. If you add a resistor&lt;br /&gt;
to one part the whole circuit will appear to slow down. You can plug&lt;br /&gt;
in a lightbulb to the circuit on either side of the resistor and it will&lt;br /&gt;
receive the same (diminished, thanks to the resistor) current. So a resistor&lt;br /&gt;
doesn’t just resist current at the point where it’s installed – &lt;br /&gt;
it slows the whole circuit down.&lt;/p&gt;

&lt;h2 id=&quot;induction&quot;&gt;Induction&lt;/h2&gt;

&lt;p&gt;Induction is where magnetism connects one flow of electricity to another.&lt;br /&gt;
Induction is useful when you have two circuits that you don’t want physically&lt;br /&gt;
touching but you need the current in one to affect the other.  Induction motors&lt;br /&gt;
work this way; you provide current to the fixed part of the motor and that&lt;br /&gt;
current (sharing a magnetic field with the rotating part of the motor) controls&lt;br /&gt;
the rotation.  The principle behind this is that an inductor resists changes in&lt;br /&gt;
current. Said another way: It’s hard to increase the current of a circuit that&lt;br /&gt;
contains a inductor and it’s also hard to decrease it afterward. This&lt;br /&gt;
resistance to change comes from a sort of magnetic turbulence in the inductor&lt;br /&gt;
whenever the current isn’t steady.&lt;/p&gt;

&lt;h2 id=&quot;capacitance&quot;&gt;Capacitance&lt;/h2&gt;

&lt;p&gt;A capacitor is basically just a really short-term battery.&lt;br /&gt;
Electrons pile up on one side of a capacitor and they’re much-needed on the&lt;br /&gt;
other side – but they can’t cross because there’s a small gap. When a&lt;br /&gt;
connection is made across the gap then the electrons all flow instantly from&lt;br /&gt;
one side to the other (and through the rest of the circuit). This is how camera&lt;br /&gt;
flashes work – they store up electricity for a few seconds and then let it all&lt;br /&gt;
out at once.  Note: I do &lt;em&gt;not&lt;/em&gt; understand how capacitors are discharged. There&lt;br /&gt;
are two terminals on a capacitor that you can hook up to your circuit but how&lt;br /&gt;
do you trigger the discharge? If somebody can explain that to me I’ll update&lt;br /&gt;
this page.&lt;/p&gt;

&lt;p&gt;I could write about LEDs, motors, batteries, etc. but those all roughly made&lt;br /&gt;
sense when I tried studying them. It’s the foundational stuff that confused me&lt;br /&gt;
and I hope my perspective on these concepts might help you out too.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>The King Cannot Be Removed From the Board</title>
   <link href="http://6brand.com/the-king-cannot-be-removed-from-the-board.html"/>
   <updated>2013-05-05T00:00:00-07:00</updated>
   <id>http://6brand.com/the-king-cannot-be-removed-from-the-board.html</id>
   <content type="html">&lt;p&gt;My&lt;a href=&quot;http://www.flickr.com/photos/little_sadie/4595278936/&quot;&gt;&lt;img alt=&quot;Bishops kick ass&quot; src=&quot;/images/chess_bishop.jpg&quot; height=&quot;265&quot; width=&quot;320&quot; class=&quot;inline&quot; /&gt;&lt;/a&gt; grandmother taught me to play chess&lt;br /&gt;
with a special set of pieces that had their&lt;br /&gt;
names printed on them. If you picked them up they had words on&lt;br /&gt;
the bottom that described their legal moves. “Bishop: can go diagonally&lt;br /&gt;
as far as he wants”, “Knight: can go over 2 and diagonally 1, or over 1&lt;br /&gt;
and diagonally 2”&lt;br /&gt;
Most of the rules were simple and just required memorization to retain&lt;br /&gt;
but one rule confused me: The King cannot be removed from the board.&lt;/p&gt;

&lt;p&gt;I asked my grandmother what happens when&lt;br /&gt;
the king is captured. “The King cannot be captured”. No, see, I can&lt;br /&gt;
capture him with even a pawn if it’s&lt;br /&gt;
in the right position. “No, you can be about to capture him, but the&lt;br /&gt;
game ends right before you do.”&lt;/p&gt;

&lt;p&gt;This seemed pretty weird to me. Why not let the king be captured and&lt;br /&gt;
immediately after call the game for the winner? Why stop one step&lt;br /&gt;
before?&lt;/p&gt;

&lt;p&gt;The &lt;a href=&quot;http://www.flickr.com/photos/midgley/4658051902/&quot;&gt;&lt;img alt=&quot;I _am_ the game.&quot; src=&quot;/images/chess_king.jpg&quot; height=&quot;500&quot; width=&quot;309&quot; class=&quot;inline&quot; /&gt;&lt;/a&gt; best book I’ve read on domestic violence is &lt;a href=&quot;http://www.amazon.com/Why-Does-He-That-Controlling/dp/0425191656&quot;&gt;Why does he do&lt;br /&gt;
that?&lt;/a&gt;.&lt;br /&gt;
It breaks apart so many myths about domestic abusers: That they’re&lt;br /&gt;
always physically violent, that they can’t control their emotions, that&lt;br /&gt;
they’re crazy, that the woman “just needs to leave him”, and many more.&lt;br /&gt;
Most of all this book on the psychology of abusers reveals the nature of&lt;br /&gt;
patriarchy. Patriarchy is not a system that prefers men to women, it’s a&lt;br /&gt;
system designed to meet the needs of specific men at the expense of&lt;br /&gt;
the needs of all other men, women, boys, and girls. These men are always&lt;br /&gt;
at the top of a clear hierarchy. It’s the father in a family, the CEO in&lt;br /&gt;
a company, the king in a nation, the pastor in a church. Other people&lt;br /&gt;
can have their needs met – but only after his are satisfied.&lt;/p&gt;

&lt;p&gt;Many pieces on a chess board are important. Sure, the pawns are&lt;br /&gt;
obviously worthless but the bishops and rooks get to throw their weight&lt;br /&gt;
around. Even more, the most powerful piece is the queen! Surely this&lt;br /&gt;
game is progressive if the female character can do whatever she likes in&lt;br /&gt;
whatever direction. But in testing a social system it’s not enough to&lt;br /&gt;
ask “who has power?” You have to go one step further and ask “whose&lt;br /&gt;
needs are being served?” Is the queen powerful? Oh yes. When she dies&lt;br /&gt;
does the game continue uninterrupted? Yes, in fact most end-game&lt;br /&gt;
scenarios assume she’s  gone. But not so with the king. When the king is&lt;br /&gt;
about to be captured the rules suddenly change.&lt;/p&gt;

&lt;p&gt;One common habit of an abuser is that when they are threatened they&lt;br /&gt;
manage to change the rules of the game. When the woman has a bad day she&lt;br /&gt;
has to deal with it. But when he has a bad day it’s the whole house’s&lt;br /&gt;
problem to fix it. When she gets injured the vacation still continues as&lt;br /&gt;
planned but when he sprains an ankle the whole world gets rearranged to&lt;br /&gt;
deal with his new situation. An abuser will even attempt to change&lt;br /&gt;
reality itself to suit his needs. If he’s winning an argument against&lt;br /&gt;
his woman  but then she is able to score a point then he can switch&lt;br /&gt;
positions in the argument and try to make the woman think she’s stupid&lt;br /&gt;
and crazy if she notices the change.&lt;/p&gt;

&lt;p&gt;When the king is threatened on a chess board the rules change. Suddenly&lt;br /&gt;
the fighting isn’t worth it anymore and a new strategy appears. The king&lt;br /&gt;
cannot be captured in a struggle for the kingdom because the purpose of&lt;br /&gt;
the kingdom is to support the king. This is what I didn’t understand&lt;br /&gt;
when my grandmother taught me the game. I didn’t get that the king isn’t&lt;br /&gt;
just a piece; the king is the game. The game is played through the eyes&lt;br /&gt;
of the king pieces.&lt;/p&gt;

&lt;p&gt;This &lt;a href=&quot;http://en.wikipedia.org/wiki/Bechdel_test&quot;&gt;same pattern exists&lt;/a&gt; in&lt;br /&gt;
every Hollywood movie and most TV shows.  When the action moves away&lt;br /&gt;
from the man the camera does not follow. When the man is removed from&lt;br /&gt;
the story the story ends. When a chess king knows that he has lost then&lt;br /&gt;
the game ends. &lt;em&gt;You&lt;/em&gt; must stop playing because &lt;em&gt;his&lt;/em&gt; role is finished&lt;br /&gt;
and he sees no point in letting you continue the script.&lt;/p&gt;

&lt;p&gt;I’m glad my grandmother taught me this game (and bought me such&lt;br /&gt;
beginner-friendly pieces). But I wish she’d helped me to better&lt;br /&gt;
understand the pattern encoded inside the rules. She’s also the one who&lt;br /&gt;
introduced me to James Bond films and she set the expectations perfectly&lt;br /&gt;
for that: She told me “They’re just movies about sex and death but boy&lt;br /&gt;
are they fun.” One day if I have the privilege of teaching a child or&lt;br /&gt;
grandchild the ancient game of chess I’ll jump at the chance but I’ll&lt;br /&gt;
clarify the rules a bit. I’ll say “This game has one character that&lt;br /&gt;
doesn’t pull his weight. The King pretends to be weak and makes&lt;br /&gt;
everybody else do his work for him. Some people do this in real life and&lt;br /&gt;
you should watch out for them. And don’t be like this yourself or you’ll&lt;br /&gt;
hurt people. Okay, you’re white so you go first.”&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Calculating Factorials in Ruby</title>
   <link href="http://6brand.com/calculating-factorials-in-ruby.html"/>
   <updated>2013-01-20T00:00:00-08:00</updated>
   <id>http://6brand.com/calculating-factorials-in-ruby.html</id>
   <content type="html">&lt;p&gt;The factorial of a number is itself multiplied by itself-1 multiplied&lt;br /&gt;
by itself-2, etc. all the way down until you multiply it by 1. By then&lt;br /&gt;
it’s a giant number. In mathematics the denotation for this would be&lt;br /&gt;
&lt;code&gt;n!&lt;/code&gt; or, if n were 12, &lt;code&gt;12!&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But there’s no way in Ruby to make this mathy syntax work:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;  &lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# that&amp;#39;s &amp;quot;twelve factorial&amp;quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is because the &lt;strong&gt;!&lt;/strong&gt; operator (pronounced “bang operator”) is picked up by&lt;br /&gt;
the parser and merely negates the next term. If you type the above into&lt;br /&gt;
IRB you’ll find that your REPL hangs because it’s waiting for more&lt;br /&gt;
input.&lt;/p&gt;

&lt;p&gt;One way to calculate a factorial in Ruby is the following&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;total&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;downto&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;total&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That’ll give you the correct answer (479,001,600). But… gross. There’s&lt;br /&gt;
a local variable defined outside the block unnecessarily. A cleaner way&lt;br /&gt;
would be:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;&lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;downto&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That gives the same answer. Let’s unpack that a bit. The &lt;code&gt;12.downto(1)&lt;/code&gt;&lt;br /&gt;
would normally be something you’d give a block to, like in the first&lt;br /&gt;
example. But in this case we’re not passing a block, we’re calling&lt;br /&gt;
&lt;code&gt;.reduce&lt;/code&gt; on the return value of &lt;code&gt;.downto&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This works because &lt;code&gt;downto&lt;/code&gt; returns an&lt;br /&gt;
&lt;a href=&quot;http://www.ruby-doc.org/core-1.9.3/Enumerator.html&quot;&gt;Enumerator&lt;/a&gt;&lt;br /&gt;
instance.  This is something that you can perform virtually any&lt;br /&gt;
Enumerable method on. In this case we’ll call &lt;code&gt;reduce&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you’re not familiar with &lt;code&gt;reduce&lt;/code&gt;, it’s the latter half of the&lt;br /&gt;
famous “&lt;a href=&quot;http://en.wikipedia.org/wiki/MapReduce&quot;&gt;map/reduce&lt;/a&gt;” pair. A reduce function is given to each element in a&lt;br /&gt;
list in turn and keeps track of the result from the previous time it was&lt;br /&gt;
run. It might be a little clearer to see an example:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;reduce&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;lambda&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;last_result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;element&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Here we&amp;#39;re creating a lambda (think &amp;quot;function&amp;quot;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;last_result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;last_result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;element&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# that is named reduce that takes a thing and&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;                                        &lt;span class=&quot;c1&quot;&gt;# a new thing and adds them.&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;elements&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;                       &lt;span class=&quot;c1&quot;&gt;# Here&amp;#39;s a collection that we can reduce.&lt;/span&gt;

                                         &lt;span class=&quot;c1&quot;&gt;# We start with an initial value. This is because&lt;/span&gt;
                                         &lt;span class=&quot;c1&quot;&gt;# the reduce function&amp;#39;s first argument is the result&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;                               &lt;span class=&quot;c1&quot;&gt;# of the previous call and to begin with &lt;/span&gt;
                                         &lt;span class=&quot;c1&quot;&gt;# that value needs to be created by hand.&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;elements&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;element&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;                 &lt;span class=&quot;c1&quot;&gt;# Now we call the reduce function we created&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;element&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# once for each element.  Importantly: we remember&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;                                        &lt;span class=&quot;c1&quot;&gt;# the result each time and feed it back in&lt;/span&gt;
                                         &lt;span class=&quot;c1&quot;&gt;# When we&amp;#39;re done the `result` has the value we want&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;## =&amp;gt; 6&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is a useful pattern because it allows us to separate our data from&lt;br /&gt;
the functions we perform on it. Check out how easy it is to make the&lt;br /&gt;
above code work on a list of strings instead of numbers:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;elements&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;fee&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;fi&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;fo&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;          &lt;span class=&quot;c1&quot;&gt;# Strings also respond to the &amp;#39;+&amp;#39; method&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;                             &lt;span class=&quot;c1&quot;&gt;# We have to initialize the result differently&lt;/span&gt;
                                        &lt;span class=&quot;c1&quot;&gt;# now that we are using strings.&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;elements&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;element&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;                &lt;span class=&quot;c1&quot;&gt;# Everything else is the same!&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;element&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;## =&amp;gt; &amp;quot;feefifo&amp;quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;There are still a couple clunky bits here, however. We have to&lt;br /&gt;
initialize the result each time and we are doing a fair bit of plumbing&lt;br /&gt;
still. Luckily, all good &lt;code&gt;reduce&lt;/code&gt; methods smooth out these rough edges.&lt;br /&gt;
Here’s the API to the &lt;code&gt;reduce&lt;/code&gt; method as implemented in Ruby’s&lt;br /&gt;
Enumerable module:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:+&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; 45                    # Sum some numbers&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inject&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sum&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;            &lt;span class=&quot;c1&quot;&gt;# Same using a block and inject&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;                         &lt;span class=&quot;c1&quot;&gt;# Multiply some numbers&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;               &lt;span class=&quot;c1&quot;&gt;# Same using a block&lt;/span&gt;
&lt;span class=&quot;sx&quot;&gt;%w{ cat sheep bear }&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inject&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;memo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;word&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# find the longest word&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;memo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;word&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;memo&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;word&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;##=&amp;gt; &amp;quot;sheep&amp;quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;reduce&lt;/code&gt; method is aliased to &lt;code&gt;inject&lt;/code&gt; in Ruby so you may&lt;br /&gt;
have already used it in your own code.&lt;/p&gt;

&lt;p&gt;So the reason this factorial snippet works is that &lt;code&gt;reduce&lt;/code&gt; is smart&lt;br /&gt;
enough to take the first value from the list if you didn’t give it an&lt;br /&gt;
initial value. It’s also smart enough to infer if you give it a proc&lt;br /&gt;
object (which is what &lt;code&gt;:*&lt;/code&gt; is here — &lt;code&gt;(:*).to_proc == {|a,b| a * b }&lt;/code&gt;)&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Graph Traversal: solving the 8-puzzle with basic A.I.</title>
   <link href="http://6brand.com/solving-8-puzzle-with-artificial-intelligence.html"/>
   <updated>2013-01-02T00:00:00-08:00</updated>
   <id>http://6brand.com/solving-8-puzzle-with-artificial-intelligence.html</id>
   <content type="html">&lt;p&gt;I’ve been working through Peter Norvig and Stuart Russel’s &lt;a href=&quot;https://www.google.com/shopping/product/15504409301906575446?q=artificial+intelligence+a+modern+approach&amp;amp;oq=artificial+intelligence+&amp;amp;aqs=chrome.1.57j0l3j62l2.6157&amp;amp;sourceid=chrome&amp;amp;ie=UTF-8&amp;amp;sa=X&amp;amp;ei=a4viUMLAK6rSiwLk1YC4Cw&amp;amp;ved=0CKUBEMQf&quot;&gt;Artificial&lt;br /&gt;
Intelligence, A Modern&lt;br /&gt;
Approach&lt;/a&gt; (thanks to the &lt;a href=&quot;https://squareup.com/careers&quot;&gt;Square engineering library&lt;/a&gt;) and one of the most helpful chapters involved methodically demonstrating basic graph traversal algorithms for problem solving. If that sounds heady, it’s not — I think you’ll enjoy it.&lt;/p&gt;

&lt;p&gt;First,&lt;img alt=&quot;binary tree on Wikipedia&quot; src=&quot;http://upload.wikimedia.org/wikipedia/commons/f/f7/Binary_tree.svg&quot; class=&quot;inline&quot; /&gt;&lt;br /&gt;
let’s talk about graphs. A graph is any set of points (nodes) and the&lt;br /&gt;
lines (edges) between those points. A simple kind of graph is a tree&lt;br /&gt;
structure. This is where there’s a single ‘root’ which has 1 or more&lt;br /&gt;
branches that then have their own branches, etc. Many things in computer&lt;br /&gt;
science can be expressed using some kind of tree structure graph.&lt;/p&gt;

&lt;p&gt;Here’s how this relates to AI: the root node (the one at the top of&lt;br /&gt;
the tree) is the state the world is in right now. Each other node&lt;br /&gt;
represents a different state of the world that’s reachable across an&lt;br /&gt;
edge by the node immediately above it. The line between them is some&lt;br /&gt;
kind of action. Moving a car’s wheels, turning on a servo, whatever. The&lt;br /&gt;
A.I. just needs to know that if you start at node A and do action X&lt;br /&gt;
you’ll get to node B. Your software will appear to be intelligent if it&lt;br /&gt;
can start at the root node and find its way to a better state of the&lt;br /&gt;
world through a series of actions.&lt;/p&gt;

&lt;h2 id=&quot;a-world-where-you-try-to-get-a-big-number&quot;&gt;A world where you try to get a big number&lt;/h2&gt;

&lt;p&gt;Let’s reuse the above image as an example. Imagine it’s a complete map&lt;br /&gt;
of all possible states of the world. The only actions that are&lt;br /&gt;
available to you are “go left” and “go right” (‘cause you’re always&lt;br /&gt;
starting at the root (top) node and heading downward). Imagine,&lt;br /&gt;
additionally, that the value of the number of a node is how much we like&lt;br /&gt;
that node. From a glance you can easily tell that one of the nodes has a&lt;br /&gt;
value of &lt;strong&gt;11&lt;/strong&gt; and is therefore the “best” node in the graph; it’s the&lt;br /&gt;
“best” state of the world that we could possibly get to. If our software&lt;br /&gt;
is intelligent it should start at the root node and find the &lt;strong&gt;11&lt;/strong&gt; node&lt;br /&gt;
as it’s destination.&lt;/p&gt;

&lt;p&gt;Since we can easily see where the &lt;strong&gt;11&lt;/strong&gt; node is the right answer is “go&lt;br /&gt;
left, then right, then right again.” But how do we teach our code to&lt;br /&gt;
find the best node?&lt;/p&gt;

&lt;h2 id=&quot;recursive-depth-first-search&quot;&gt;Recursive Depth-first search&lt;/h2&gt;

&lt;p&gt;Here’s the simplest way we can find the right node on the given tree.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;best&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;walk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;best&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;node&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;best&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nil?&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;node&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;best&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;children&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;child&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;walk&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;child&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;walk&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;root&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here we “walk” down each branch of the tree all the way to the end using&lt;br /&gt;
recursion. This is known as recursive &lt;a href=&quot;http://en.wikipedia.org/wiki/Depth-first_search&quot;&gt;&lt;code&gt;depth first
search&lt;/code&gt;&lt;/a&gt; and is a great&lt;br /&gt;
tool when you think that any path might have a good node really far down&lt;br /&gt;
so you just want to get really deep really fast. It’s also the least&lt;br /&gt;
code possible to find a solution to our problem.  Unfortunately, the&lt;br /&gt;
simple implementation of depth-first involves recursion which means&lt;br /&gt;
we’re limited to only traversing graphs that have a total depth less&lt;br /&gt;
than our runtime stack frame limit. If you’ve ever seen a “stack&lt;br /&gt;
overflow error” it’s because there was so much recursion in your program&lt;br /&gt;
that the computer assumed you were caught in an infinite loop and gave&lt;br /&gt;
up. To demonstrate this try running this simple program in &lt;code&gt;irb&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;go&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# On my machine the last thing printed was 8247 and then I saw:&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;     &lt;span class=&quot;c1&quot;&gt;#   SystemStackError: stack level too deep&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;   &lt;span class=&quot;c1&quot;&gt;# which means Ruby let me use 8,247 stack frames&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;          &lt;span class=&quot;c1&quot;&gt;# before giving up. If I were to try going 9,000 nodes deep&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;         &lt;span class=&quot;c1&quot;&gt;# in a graph I&amp;#39;d get this error.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, if you wanted to do a depth-first search without recursion you can&lt;br /&gt;
but it’s no longer the simplest code so I’ll skip it here. Suffice to&lt;br /&gt;
say that it would mean you’ll have to manually keep track of which nodes&lt;br /&gt;
to visit in which order rather than letting your programming language do&lt;br /&gt;
it for you.&lt;/p&gt;

&lt;h2 id=&quot;breadth-first-search-in-a-loop&quot;&gt;Breadth-first search in a loop&lt;/h2&gt;

&lt;p&gt;Another simple way to traverse the graph is to look at the nodes from&lt;br /&gt;
left to right on each level rather than going all the way down one&lt;br /&gt;
branch and then all the way down another branch. This is called&lt;br /&gt;
&lt;a href=&quot;http://en.wikipedia.org/wiki/Breadth-first_search&quot;&gt;&lt;code&gt;breadth-first
search&lt;/code&gt;&lt;/a&gt; and is&lt;br /&gt;
better if you think there’s a good node close to the root.&lt;/p&gt;

&lt;p&gt;This is also a very simple bit of code &lt;em&gt;and&lt;/em&gt; it frees us&lt;br /&gt;
from having to rely on our runtime’s call stack. Rather than recursing&lt;br /&gt;
through methods and letting Ruby keep track of our work (as in the above&lt;br /&gt;
example) we’ll just run in a loop and store our work in an array. The&lt;br /&gt;
advantage here is you can put more than 9,000 items in an array —&lt;br /&gt;
it’s only bounded by how much memory is on your machine.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;queue&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;best&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;begin&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;current&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;queue&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shift&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;best&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;current&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;best&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;current&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;children&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;child&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;queue&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;push&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;child&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;until&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;queue&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;empty?&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The name “breadth-first” comes from the fact that it’ll look at all the&lt;br /&gt;
nodes at each level from side to side before proceeding down to the next&lt;br /&gt;
level. Notice that the array variable is named &lt;code&gt;queue&lt;/code&gt;. This is because&lt;br /&gt;
in a depth-first implementation you’re always going to have a list that&lt;br /&gt;
you put newly-discovered nodes onto the end of and pull nodes to explore&lt;br /&gt;
off of the front.&lt;/p&gt;

&lt;p&gt;Breadth-first search is easy to reason about, you won’t run out of stack&lt;br /&gt;
space like when you used recursion (although it’s possible you’ll run&lt;br /&gt;
out of memory), and if your environment supports concurrency primitives&lt;br /&gt;
you might be able to run it in parallel quite easily. C# has a &lt;code&gt;Consumer
Queue&lt;/code&gt; that can help with this and Clojure has multiple ways to iterate&lt;br /&gt;
through a list in parallel. Ruby requires you to do more work&lt;br /&gt;
synchronizing when threads get to append their newly-discovered nodes to&lt;br /&gt;
the end of the queue but otherwise you get the parallelism cheaply.&lt;/p&gt;

&lt;h2 id=&quot;solving-the-sliding-block-puzzle&quot;&gt;Solving the sliding-block puzzle&lt;/h2&gt;

&lt;p&gt;We&lt;img alt=&quot;15 puzzle&quot; src=&quot;/images/15-puzzle.svg&quot; class=&quot;inline&quot; /&gt; walk&lt;br /&gt;
along the edges of a graph from the starting node to a better&lt;br /&gt;
node. With me so far? If this graph represents a set of world states&lt;br /&gt;
that are reachable from each other via actions then searching the graph&lt;br /&gt;
is the same thing as figuring out what to do.&lt;/p&gt;

&lt;p&gt;Let’s use this technique to try to solve a problem that has a clear&lt;br /&gt;
starting state and a clear ending state with many (possibly &lt;em&gt;very&lt;/em&gt; many)&lt;br /&gt;
intermediate states. The sliding-block puzzle (often called an 8-puzzle&lt;br /&gt;
or, in it’s larger variant, a 15-puzzle) is a great case for us to&lt;br /&gt;
tackle.&lt;/p&gt;

&lt;p&gt;In an 8-puzzle you’ve got a bunch of tiles in the wrong places and just&lt;br /&gt;
one empty space that you can move around until the tiles are in the&lt;br /&gt;
right order. How do you know which move to make first? How do you know&lt;br /&gt;
when you’re on the right track? How do you know if you’ve going in&lt;br /&gt;
loops?&lt;/p&gt;

&lt;p&gt;If we model each possible action as edges in a graph and each potential puzzle&lt;br /&gt;
state as a node then we just start at the beginning and begin exploring&lt;br /&gt;
the graph. We’ll stop once we’ve found the solution (or, if we built our&lt;br /&gt;
code poorly, we’ll stop when we run out of memory or time).&lt;/p&gt;

&lt;p&gt;Now, there are two ways we can set up our data for this problem. One is&lt;br /&gt;
to generate all possible states (nodes) that the puzzle can have and to&lt;br /&gt;
then connect the adjacent states. We would then have a complete graph we&lt;br /&gt;
could traverse and we’d even be able to mark the solution ahead of time&lt;br /&gt;
and know where it was located in the graph. Unfortunately, the number of&lt;br /&gt;
states is 9-factorial or about 360,000. Generating that many puzzle&lt;br /&gt;
slide orientations and then iterating through each one would take, at&lt;br /&gt;
best, &lt;code&gt;(9!)(9!-1)/2&lt;/code&gt; node-comparison operations (the formula for how&lt;br /&gt;
many edges can exist between nodes in a graph is &lt;code&gt;(n * n-1)/2&lt;/code&gt;)&lt;/p&gt;

&lt;p&gt;So let’s not do that. Rather, let’s start at the root node (the starting&lt;br /&gt;
state) and then create branches from each node as we go. We’ll stop&lt;br /&gt;
when we discover our solution — hopefully long before we examine 360,000&lt;br /&gt;
states.&lt;/p&gt;

&lt;h2 id=&quot;defining-a-puzzle-class&quot;&gt;Defining a puzzle class&lt;/h2&gt;

&lt;p&gt;We’re going to need a few tools. First, let’s put together a way to&lt;br /&gt;
represent a puzzle board with tiles in a particular position:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Puzzle&lt;/span&gt;
  &lt;span class=&quot;no&quot;&gt;Solution&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;              &lt;span class=&quot;c1&quot;&gt;# Let&amp;#39;s put all the tiles in ascending order&lt;/span&gt;
              &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;              &lt;span class=&quot;c1&quot;&gt;# the same way you&amp;#39;d see them on a phone keypad.&lt;/span&gt;
              &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;              &lt;span class=&quot;c1&quot;&gt;# We use a &amp;#39;0&amp;#39; for the blank cell because&lt;/span&gt;
                                    &lt;span class=&quot;c1&quot;&gt;# `nil` doesn&amp;#39;t play well with others.&lt;/span&gt;
  &lt;span class=&quot;kp&quot;&gt;attr_reader&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:cells&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initialize&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cells&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@cells&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cells&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;solution?&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;Solution&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@cells&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;What did we just do there? That is a &lt;code&gt;Puzzle&lt;/code&gt; class where each instance&lt;br /&gt;
knows whether it’s a solution. The cells/tiles of the puzzle are kept in&lt;br /&gt;
a list.&lt;/p&gt;

&lt;p&gt;Now let’s construct a way to represent a state (a node on the&lt;br /&gt;
solution graph). A state isn’t just a representation of puzzle tile&lt;br /&gt;
position but &lt;em&gt;also&lt;/em&gt; the history of how that puzzle arrangement was&lt;br /&gt;
reached from the starting point. This is key: if we don’t keep track of&lt;br /&gt;
how we got to a solution node on the graph then we’ll never be able to&lt;br /&gt;
report how to solve the puzzle. So we need to keep a list as we go of&lt;br /&gt;
which actions we’ve taken to arrive at the current node.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Puzzle&lt;/span&gt;                                          &lt;span class=&quot;c1&quot;&gt;# We&amp;#39;re extending the Puzzle class.&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;zero_position&lt;/span&gt;                                   &lt;span class=&quot;c1&quot;&gt;# `zero_position` tells us which cell has&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@cells&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;                &lt;span class=&quot;c1&quot;&gt;# the &amp;#39;0&amp;#39;.&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;swap&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;swap_index&lt;/span&gt;                                 &lt;span class=&quot;c1&quot;&gt;# `swap` tells the puzzle:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;new_cells&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@cells&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;clone&lt;/span&gt;                          &lt;span class=&quot;c1&quot;&gt;# &amp;quot;give me you, but with the &amp;#39;0&amp;#39; cell&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;new_cells&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;zero_position&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;new_cells&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;swap_index&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# replaced by the cell at some other&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;new_cells&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;swap_index&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;                         &lt;span class=&quot;c1&quot;&gt;# location of my choice.&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;Puzzle&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;new_cells&lt;/span&gt;                              &lt;span class=&quot;c1&quot;&gt;# This is how we&amp;#39;ll simulate moving a tile.&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;State&lt;/span&gt;                                           &lt;span class=&quot;c1&quot;&gt;# Each `State` instance represents a node&lt;/span&gt;
  &lt;span class=&quot;no&quot;&gt;Directions&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:up&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:down&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;            &lt;span class=&quot;c1&quot;&gt;# in our solution graph. It keeps track of&lt;/span&gt;
                                                      &lt;span class=&quot;c1&quot;&gt;# both a puzzle and the list of actions&lt;/span&gt;
                                                      &lt;span class=&quot;c1&quot;&gt;# required to arrive at there from the&lt;/span&gt;
  &lt;span class=&quot;kp&quot;&gt;attr_reader&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:puzzle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:path&lt;/span&gt;                          &lt;span class=&quot;c1&quot;&gt;# starting node.&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initialize&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;puzzle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt;                     
    &lt;span class=&quot;vi&quot;&gt;@puzzle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@path&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;puzzle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;                     &lt;span class=&quot;c1&quot;&gt;# The `path` is a list of actions&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;                                                 &lt;span class=&quot;c1&quot;&gt;# like &amp;#39;up&amp;#39;, &amp;#39;down&amp;#39;, &amp;#39;right&amp;#39;, right&amp;#39;&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;solution?&lt;/span&gt;                                       &lt;span class=&quot;c1&quot;&gt;# Each node in our graph should&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;puzzle&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;solution?&lt;/span&gt;                                  &lt;span class=&quot;c1&quot;&gt;# know if it&amp;#39;s a solution.&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;branches&lt;/span&gt;                                        &lt;span class=&quot;c1&quot;&gt;# Returns all adjacent possible states&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;Directions&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dir&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;                           &lt;span class=&quot;c1&quot;&gt;# including steps needed to get there.&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;branch_toward&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dir&lt;/span&gt;                               &lt;span class=&quot;c1&quot;&gt;# Most nodes will have 2-4 branches based&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compact&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shuffle&lt;/span&gt;                               &lt;span class=&quot;c1&quot;&gt;# on how many directions the blank tile&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;                                                 &lt;span class=&quot;c1&quot;&gt;# can try to go.&lt;/span&gt;

  &lt;span class=&quot;kp&quot;&gt;private&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;branch_toward&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;direction&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;blank_position&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;puzzle&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;zero_position&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;blankx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;blank_position&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;blanky&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;blank_position&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_i&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;cell&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;direction&lt;/span&gt;                      &lt;span class=&quot;c1&quot;&gt;# The only reason this method is so long&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:left&lt;/span&gt;                                 &lt;span class=&quot;c1&quot;&gt;# is because sometimes the blank tile is already&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;blank_position&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;blankx&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# at a wall and that direction isn&amp;#39;t possible&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:right&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;blank_position&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;blankx&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:up&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;blank_position&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;blanky&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:down&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;blank_position&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;blanky&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;State&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;puzzle&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;swap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cell&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@path&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;direction&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cell&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This State class knows about one particular arrangement of the puzzle&lt;br /&gt;
and is able to determine next steps. When we call State#branches we get&lt;br /&gt;
a list of adjacent puzzle arrangements (anything reachable by moving the&lt;br /&gt;
empty space over by 1 square) and each of these new states include the&lt;br /&gt;
full list of steps necessary to reach them.&lt;/p&gt;

&lt;p&gt;That’s the setup. Now that we have some problem-specific helpers we can&lt;br /&gt;
use our breadth-first algorithm from up above to start tackling this.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;search&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;state&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;branches&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reject&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;branch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;# Important: don&amp;#39;t revisit puzzles&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@visited&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;include?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;branch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;puzzle&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cells&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# you&amp;#39;ve already seen!&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;branch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;                     &lt;span class=&quot;c1&quot;&gt;# The list of places we need to search&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@frontier&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;branch&lt;/span&gt;                    &lt;span class=&quot;c1&quot;&gt;# is known as the &amp;#39;frontier&amp;#39;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;set&amp;#39;&lt;/span&gt;                           &lt;span class=&quot;c1&quot;&gt;# We&amp;#39;ll remember what we&amp;#39;ve seen in a set, it has&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;solve&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;puzzle&lt;/span&gt;                        &lt;span class=&quot;c1&quot;&gt;# way better lookup times than an array.&lt;/span&gt;
  &lt;span class=&quot;vi&quot;&gt;@visited&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;
  &lt;span class=&quot;vi&quot;&gt;@frontier&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;state&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;State&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;puzzle&lt;/span&gt;
  &lt;span class=&quot;kp&quot;&gt;loop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@visited&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;puzzle&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cells&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;solution?&lt;/span&gt;            &lt;span class=&quot;c1&quot;&gt;# This is the `base` or end condition&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;search&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;state&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;state&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@frontier&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shift&lt;/span&gt;             &lt;span class=&quot;c1&quot;&gt;# Pull another off the list, keep chugging along&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;state&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If we feed in a solveable puzzle we can see that this code works. Let’s&lt;br /&gt;
try one where the empty tile was moved right and then down. The solution&lt;br /&gt;
should be to move it up and then left:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;solve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Puzzle&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;         &lt;span class=&quot;c1&quot;&gt;# `solve` is going to return a State&lt;/span&gt;
                    &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;         &lt;span class=&quot;c1&quot;&gt;# instance. We care about it&amp;#39;s #path&lt;/span&gt;
                    &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;## =&amp;gt; [:up, :left]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;So… it works, but it’s just kinda wandering around until it finds a&lt;br /&gt;
solution. We gave it a problem that was only 2 steps from a solution so&lt;br /&gt;
if we gave it something harder would it ever finish? And how long would the&lt;br /&gt;
solution path be?&lt;/p&gt;

&lt;p&gt;Here’s our code running with a puzzle who’s optimal solution is 20 steps&lt;br /&gt;
away:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;solve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Puzzle&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;       &lt;span class=&quot;c1&quot;&gt;# I generated this by creating a solution state and&lt;/span&gt;
                    &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;       &lt;span class=&quot;c1&quot;&gt;# running `state = state.branches.sample` in a big loop.&lt;/span&gt;
                    &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;## =&amp;gt; [:up, :up, :right, :down, :right, :down, :left, :left,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;##     :up, :up, :right, :down, :down, :right, :up, :left,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;##     :down, :left, :up, :up]&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;## Time: 27 seconds&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It works! Eventually. But 27 seconds is a bit slow. What if we were&lt;br /&gt;
tackling the 15-puzzle instead? Rather than the 9! (360K) options we&lt;br /&gt;
would be searching through 16! (20 trillion) options. That would take&lt;br /&gt;
almost literally forever.&lt;/p&gt;

&lt;h2 id=&quot;uniform-cost-search&quot;&gt;Uniform-cost search&lt;/h2&gt;

&lt;p&gt;As we walk the graph we’re keeping a &lt;code&gt;frontier&lt;/code&gt; — a list of states&lt;br /&gt;
we’re hoping to explore in the future. Since we always add to the back&lt;br /&gt;
of the list and take (&lt;code&gt;shift&lt;/code&gt;) from the front it’s technically a &lt;abbr title=&quot;First In, First Out&quot;&gt;FIFO&lt;/abbr&gt; queue rather than just a list.&lt;/p&gt;

&lt;p&gt;What if, rather than picking the next element from the queue to explore&lt;br /&gt;
we tried to pick the &lt;em&gt;best&lt;/em&gt; one? Then we wouldn’t have to explore quite&lt;br /&gt;
so many trillions of nodes in our state graph.&lt;/p&gt;

&lt;p&gt;Uniform-cost search entails keeping track of the how far any given node&lt;br /&gt;
is from the root node and using that as its &lt;code&gt;cost&lt;/code&gt;. For our puzzle&lt;br /&gt;
example that means that however many steps &lt;code&gt;n&lt;/code&gt; it takes to get to state&lt;br /&gt;
&lt;code&gt;s&lt;/code&gt; then &lt;code&gt;s&lt;/code&gt; has a cost of &lt;code&gt;n&lt;/code&gt;. In code: &lt;code&gt;s.cost =
steps_to_reach_from_start(s)&lt;/code&gt;. A variant of this is called &lt;a href=&quot;http://en.wikipedia.org/wiki/Dijkstra&apos;s_algorithm&quot;&gt;Dijkstra’s&lt;br /&gt;
Algorithm&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There’s one missing piece here though: we don’t want to examine every&lt;br /&gt;
item in the entire &lt;code&gt;frontier&lt;/code&gt; queue every time we want to pick the&lt;br /&gt;
next lowest-cost element. What we need is a priority queue that&lt;br /&gt;
automatically sorts its members by some value so looking up an element&lt;br /&gt;
by cost is cheap and doesn’t slow down the rest of what we’re trying to&lt;br /&gt;
do.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;PriorityQueue&lt;/span&gt;            &lt;span class=&quot;c1&quot;&gt;# This is a terrible implementation of a&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initialize&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;comparator&lt;/span&gt;   &lt;span class=&quot;c1&quot;&gt;# priority queue. The `#sort!` method iterates&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@comparator&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;comparator&lt;/span&gt;   &lt;span class=&quot;c1&quot;&gt;# through every item every time.&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@elements&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt;             &lt;span class=&quot;c1&quot;&gt;# What you want is a priority queue backed by a heap data structure.&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;                          &lt;span class=&quot;c1&quot;&gt;# In Ruby you should use the `PriorityQueue` gem&lt;/span&gt;
                               &lt;span class=&quot;c1&quot;&gt;# and on the JVM there&amp;#39;s a good Java implementation.&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;element&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@elements&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;element&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;sort!&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;pop&lt;/span&gt;                      &lt;span class=&quot;c1&quot;&gt;# `pop` is the typical queue-polling nomenclature.&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@elements&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shift&lt;/span&gt;            &lt;span class=&quot;c1&quot;&gt;# Your implementation may call it something else.&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;kp&quot;&gt;private&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;sort!&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@elements&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@elements&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sort_by&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@comparator&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# This line is why this implementation &lt;/span&gt;
                                                &lt;span class=&quot;c1&quot;&gt;# sucks. Don&amp;#39;t use this IRL.&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;State&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;cost&lt;/span&gt;                           &lt;span class=&quot;c1&quot;&gt;# The cost is pretty simple to calculate here.&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;                        &lt;span class=&quot;c1&quot;&gt;# The path contains all the steps, in order that we&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;                                &lt;span class=&quot;c1&quot;&gt;# used to arrive at this state. So the cost&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;                                  &lt;span class=&quot;c1&quot;&gt;# is just the number of steps.&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;set&amp;#39;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;solve&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;puzzle&lt;/span&gt;
  &lt;span class=&quot;vi&quot;&gt;@visited&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;
  &lt;span class=&quot;vi&quot;&gt;@frontier&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;PriorityQueue&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cost&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;state&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;State&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;puzzle&lt;/span&gt;
  &lt;span class=&quot;kp&quot;&gt;loop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@visited&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;puzzle&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cells&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;solution?&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;search&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;state&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;state&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@frontier&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pop&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;state&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Sidebar:&lt;/strong&gt; you may be wondering why this gains us any advantage? Sure,&lt;br /&gt;
we’re now picking the the best node from the queue rather than whichever&lt;br /&gt;
one was added first but we still have to explore all of them, right?&lt;br /&gt;
Actually, no. Because we’re sorting by the ‘cost’ of the nodes we can be&lt;br /&gt;
guaranteed that whenever we find a solution it’s the best one.  There&lt;br /&gt;
may be other paths to solutions in our graph but they are all guaranteed&lt;br /&gt;
to be of higher cost. So this Uniform-cost search lets us leave a vast&lt;br /&gt;
section of the queue unexplored.&lt;/p&gt;

&lt;p&gt;What does that do to our performance? Well, if we re-run our above&lt;br /&gt;
20-step puzzle the time will drop considerably from 27 seconds to 10&lt;br /&gt;
seconds (on my machine).&lt;/p&gt;

&lt;p&gt;This is a big speedup and, for larger problems, can shave days off the&lt;br /&gt;
calculation time. But there’s much more we can do.&lt;/p&gt;

&lt;h2 id=&quot;a-search&quot;&gt;A* Search&lt;/h2&gt;

&lt;p&gt;The uniform-cost search picks the best next state from the frontier.&lt;br /&gt;
Let’s enhance the code’s understanding of what makes something&lt;br /&gt;
“best” by calculating not only the distance from the start to where we&lt;br /&gt;
are but the distance from where we are to the goal.&lt;/p&gt;

&lt;p&gt;Old cost function: &lt;code&gt;steps_to_get_to(s)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;New cost function: &lt;code&gt;steps_to_get_to(s) + steps_to_goal_from(s)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;But, uh, how do we know how far we are from the solution? If we knew how&lt;br /&gt;
far away the solution was we’d probably already have found it, right?&lt;br /&gt;
Right. So rather than being exact, let’s just pick a healthy estimate of&lt;br /&gt;
how far we are from a solution. One approximation would be “how many&lt;br /&gt;
tiles are out of place?” That would at least differentiate&lt;br /&gt;
almost-solution nodes from not-even-close ones. But we’d like to be a&lt;br /&gt;
bit more precise.&lt;/p&gt;

&lt;p&gt;So let’s say that the distance cost between a given node and the&lt;br /&gt;
solution node is the number of tile-movements that would be required if&lt;br /&gt;
tiles could move through each other and go straight to their goal&lt;br /&gt;
positions. So a near-solution node might have a distance cost of 3 and a&lt;br /&gt;
not-even-close node might have a distance cost of 26. That should give&lt;br /&gt;
us decent precision while also being fair. It’s important that our&lt;br /&gt;
cost-to-get-to-goal function doesn’t accidentaly deprioritize good&lt;br /&gt;
near-solution states.&lt;/p&gt;

&lt;p&gt;To help us we’ll calculate the &lt;a href=&quot;http://en.wikipedia.org/wiki/Taxicab_geometry&quot;&gt;Manhattan&lt;br /&gt;
Distance&lt;/a&gt; between each&lt;br /&gt;
tile and where it’s supposed to be. Manhattan Distance is the distance&lt;br /&gt;
between two places if you have to travel along city blocks.&lt;br /&gt;
Essentially, you’re adding up the short sides of a right triangle rather&lt;br /&gt;
than shortcutting across the hypotenuse. The formula is pretty simple:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Puzzle&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;distance_to_goal&lt;/span&gt;                               &lt;span class=&quot;c1&quot;&gt;# Here we `zip` the current puzzle with the solution&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@cells&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;zip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Solution&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# and total up the distances between each cell&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;sum&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;manhattan_distance&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# and where that cell should be.&lt;/span&gt;
                                &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_i&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# This % and / stuff is just turning an integer&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;                                              &lt;span class=&quot;c1&quot;&gt;# into puzzle x,y coordinates&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;kp&quot;&gt;private&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;manhattan_distance&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y2&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# The manhattan distance of something is just&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;abs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;abs&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;# the distance between x coordinates&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;                                    &lt;span class=&quot;c1&quot;&gt;# plus the distance between y coordinates&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;State&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;cost&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;steps_from_start&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;steps_to_goal&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# Now we have a more informed cost method&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;                                   &lt;span class=&quot;c1&quot;&gt;# so our priority queue should be giving&lt;/span&gt;
                                        &lt;span class=&quot;c1&quot;&gt;# us better results.&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;steps_from_start&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;steps_to_goal&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;puzzle&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;distance_to_goal&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;set&amp;#39;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;solve&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;puzzle&lt;/span&gt;
  &lt;span class=&quot;vi&quot;&gt;@visited&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;
  &lt;span class=&quot;vi&quot;&gt;@frontier&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;PriorityQueue&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cost&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;state&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;State&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;puzzle&lt;/span&gt;
  &lt;span class=&quot;kp&quot;&gt;loop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;solution?&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;search&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;state&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;state&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@frontier&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pop&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;state&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If you’re following along at home (and using a real priority queue) you&lt;br /&gt;
might think the code is broken because it exited so fast. With a proper&lt;br /&gt;
priority queue implementation this latest search took 0.07 seconds.&lt;/p&gt;

&lt;p&gt;This &lt;a href=&quot;http://en.wikipedia.org/wiki/A*_search_algorithm&quot;&gt;A* search&lt;/a&gt; is&lt;br /&gt;
able to quickly pick the best candidate to explore in&lt;br /&gt;
any situation where the distance from the current state to the goal&lt;br /&gt;
state is knowable. In real-world pathfinding, e.g., you can use the geospatial&lt;br /&gt;
distance between two points. It doesn’t work at all, however, in&lt;br /&gt;
situations where you know the goal when you see it but can’t determine&lt;br /&gt;
how close you are. A robot trying to find a door in unexplored&lt;br /&gt;
territory would not be able to use this, it would have to just keep&lt;br /&gt;
bumbling around.&lt;/p&gt;

&lt;p&gt;The full reference code for this is &lt;a href=&quot;https://github.com/JackDanger/eight-puzzle/blob/master/eight-puzzle.rb&quot;&gt;on&lt;br /&gt;
GitHub&lt;/a&gt;&lt;br /&gt;
including a full &lt;a href=&quot;https://github.com/JackDanger/eight-puzzle/blob/master/src/puzzle/eight_puzzle.clj&quot;&gt;implentation in&lt;br /&gt;
Clojure&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Huge thanks to my reviewer &lt;a href=&quot;https://twitter.com/tundal45&quot;&gt;Ashish Dixit&lt;/a&gt;&lt;br /&gt;
without whom this post would have been a typo-filled mess of&lt;br /&gt;
half-conveyed ideas.&lt;/p&gt;

&lt;p&gt;A quick recap of the relative time and memory costs for these search&lt;br /&gt;
algorithms:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code&gt;uninformed depth-first:               {stack overflow error}
breadth-first w/o tracking `visited`: {out of memory error}
uninformed breadth-first:             27 seconds, 47,892 explored states
uniform-cost (Dijkstra&apos;s):            10 seconds, 51,963 explored states
A* search:                            0.07 seconds, 736 explored states
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
</content>
 </entry>
 
</feed>


