<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Justin Howard</title>
    <description>Justin Howard's Software Engineering Thoughts
</description>
    <link>http://justinhoward.org/</link>
    <atom:link href="http://justinhoward.org/feed.xml" rel="self" type="application/rss+xml" />
    <pubDate>Fri, 04 Jun 2021 23:50:00 +0000</pubDate>
    <lastBuildDate>Fri, 04 Jun 2021 23:50:00 +0000</lastBuildDate>
    <generator>Jekyll v3.9.0</generator>
    
      <item>
        <title>A Dependency Checklist</title>
        <description>&lt;p&gt;Unless you’re working for a large corporation with strict security guidelines,
you may not think too much about adding a new third-party dependency to your
project. However, even if you’re the sole developer or working on a small team,
choosing dependencies should not be taken lightly.&lt;/p&gt;

&lt;p&gt;This checklist explains what I consider when considering adding a dependency
like a third-party library.&lt;/p&gt;

&lt;h2 id=&quot;activity&quot;&gt;Activity&lt;/h2&gt;

&lt;p&gt;Is this software actively maintained? How friendly is the author to outside
contributions? Are there many outstanding bugs? What was the last time a bug
was fixed? If the project has dependencies of its own, is it compatible with the
latest versions of those?&lt;/p&gt;

&lt;p&gt;I typically will not add a dependency unless I’m confident that issues that I
discover can be fixed. I don’t mind fixing it myself, as long as my time isn’t
wasted on a pull request that will never be reviewed.&lt;/p&gt;

&lt;h2 id=&quot;license&quot;&gt;License&lt;/h2&gt;

&lt;p&gt;For the most part, I look for open-source dependencies with few exceptions. I
prefer simple, permissive licenses like MIT, BSD-3, ISC, and Apache 2.0.
Depending on the project, GPL may also be acceptable. A project with a missing
license is a no-go.&lt;/p&gt;

&lt;h2 id=&quot;maturity&quot;&gt;Maturity&lt;/h2&gt;

&lt;p&gt;For the most part, maturity comes down to how long a project has been used in
production. I consider overall age, but also things like performance,
configurability, and stability.&lt;/p&gt;

&lt;p&gt;A newer project is less likely to stand up to heavy production use where its
limits are tested. I prefer not to be a beta tester in these cases.&lt;/p&gt;

&lt;h2 id=&quot;documentation&quot;&gt;Documentation&lt;/h2&gt;

&lt;p&gt;A piece of code can be the most revolutionary, perfect piece of software ever
written, but it’s worth very little without good documentation. This comes in
the form of guides, API docs, and release notes.&lt;/p&gt;

&lt;p&gt;Guides are intended to address the most common use-cases for a piece of
software, things like setup and configuration. API docs should dig deep into the
full public API for a library and document the details of each class or
function. The release notes, or changelog should document all significant
changes in each version and specifically call out breaking changes.&lt;/p&gt;

&lt;h2 id=&quot;reputation&quot;&gt;Reputation&lt;/h2&gt;

&lt;p&gt;Who is the maintainer or maintainers of the project? Is it backed by a company,
or an individual? If it is an individual, are they known in the community? Can
they be trusted? Are they vulnerable to coercion by a malicious party? How
likely is it that the project will be abandoned?&lt;/p&gt;

&lt;p&gt;Without knowing the reputation of the maintainers, it is very risky to use their
code in your application.&lt;/p&gt;

&lt;h2 id=&quot;code-quality&quot;&gt;Code Quality&lt;/h2&gt;

&lt;p&gt;When I scan the code, does it have a consistent, readable style? Would I feel
comfortable writing a patch for it? Does it have good test coverage? What kind
of bugs are in the issue tracker, and do those demonstrate commitment to
quality?&lt;/p&gt;

&lt;p&gt;Code quality can be an indicator of stability and usability, but it’s also
important for maintenance. Code that is a spaghetti mess is likely to become
difficult to maintain or have unfixable bugs.&lt;/p&gt;

&lt;h2 id=&quot;popularity&quot;&gt;Popularity&lt;/h2&gt;

&lt;p&gt;How many other users are there of this software? Although popularity isn’t
critical, it does make it more likely that the project will continue to be
maintained. Especially if the project has a permissive license, a popular
project is likely to be maintained even after the current maintainers abandon
it.&lt;/p&gt;

&lt;p&gt;Popularity also makes it more likely that common bugs will have already been
found and fixed.&lt;/p&gt;

&lt;h2 id=&quot;transitive-dependencies&quot;&gt;Transitive Dependencies&lt;/h2&gt;

&lt;p&gt;Don’t forget to check the dependencies that the project itself has. Transitive
dependencies are just dependencies of your dependencies. You depend on these
just as much as your direct dependencies, so it’s important to apply the same
rigor to them.&lt;/p&gt;

&lt;h2 id=&quot;overall-risk&quot;&gt;Overall Risk&lt;/h2&gt;

&lt;p&gt;Considering all the other points, what is the risk of introducing this
dependency? How easy will it be to replace in my application if necessary? What
would be the impact of a bug or security vulnerability if there was one?&lt;/p&gt;

&lt;p&gt;Adding third party code to your application is risky, but almost always
necessary. Make sure to do your due diligence.&lt;/p&gt;
</description>
        <pubDate>Sun, 25 Apr 2021 00:00:00 +0000</pubDate>
        <link>http://justinhoward.org/a-dependency-checklist</link>
        <guid isPermaLink="true">http://justinhoward.org/a-dependency-checklist</guid>
        
        
      </item>
    
      <item>
        <title>Avoid Ruby Hash Defaults</title>
        <description>&lt;p&gt;In Ruby, like most languages the default value for a hash is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nil&lt;/code&gt; or empty. You
can override this behavior with your own default. Here are some reasons to avoid
using this feature.&lt;/p&gt;

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

&lt;p&gt;You can create a ruby Hash with the literal &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{}&lt;/code&gt; syntax, or with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Hash.new&lt;/code&gt;.
If you use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Hash.new&lt;/code&gt;, you can specify a default with an argument&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;no&quot;&gt;Hash&lt;/span&gt;&lt;span class=&quot;p&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;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now, any time you access a key that is not present on the hash, it will return
your custom default instead of the stored value.&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Hash&lt;/span&gt;&lt;span class=&quot;p&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;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; 0&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; {}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Already, we see some potential traps. Here’s a example:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Hash&lt;/span&gt;&lt;span class=&quot;p&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;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:a&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;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; {}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here, the author makes the mistake of assuming that the default of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;h&lt;/code&gt; is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nil&lt;/code&gt;,
but it’s actually &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0&lt;/code&gt;, so we can’t check for presence with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;if/unless&lt;/code&gt; like we
usually can. Okay, we can probably handle that and just make sure to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;key?&lt;/code&gt;
when we want to check key presence, so let’s look at some more complex and
dangerous examples.&lt;/p&gt;

&lt;h2 id=&quot;with-mutable-objects&quot;&gt;With Mutable Objects&lt;/h2&gt;

&lt;p&gt;Probably the most common use of hash defaults is to make the default another
hash or array.&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Hash&lt;/span&gt;&lt;span class=&quot;p&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;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'foo'&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; ['foo']&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; {}&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; ['foo']&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Wait, what happened? Where did &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;'foo'&lt;/code&gt; go, and why is it in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:b&lt;/code&gt;? Well you
probably guessed it. When we mutate with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;&amp;lt;&lt;/code&gt;, we actually mutated the default
array. Not only did we not add the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:a&lt;/code&gt; key, but we also changed the value we
get when we request an unset key.&lt;/p&gt;

&lt;p&gt;We can solve this problem by using a block to create a new array whenever we
request a default. This solves a problem and creates new ones.&lt;/p&gt;

&lt;h2 id=&quot;with-dynamic-default&quot;&gt;With Dynamic Default&lt;/h2&gt;

&lt;p&gt;We can pass a block (Ruby’s closures) to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Hash.new&lt;/code&gt; that will get called every
time we need the default value. Let’s see how that works.&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Hash&lt;/span&gt;&lt;span class=&quot;p&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;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'foo'&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; ['foo']&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; {}&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; []&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Okay, so that didn’t fix it. We’re no longer mutating the default array, but our
changes still aren’t sticking. Let’s look at the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;&amp;lt;&lt;/code&gt; line and break it down
into its components.&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# Equivalent of h[:a] &amp;lt;&amp;lt; 'foo'&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# First get the default value, so our block is called and returns []&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# and we store it in a&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;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# Now we append 'foo' to our new array&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'foo'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You can see that our array with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;'foo'&lt;/code&gt; in it never gets assigned back to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;h&lt;/code&gt;.
Let’s try to solve that problem.&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Hash&lt;/span&gt;&lt;span class=&quot;p&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;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&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;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'foo'&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; ['foo']&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; { a: ['foo'] }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Nice! We solved all our problems. Or did we? There are still a couple more
pitfalls because we now assign hash keys whenever they are accessed.&lt;/p&gt;

&lt;h2 id=&quot;access-as-assignment&quot;&gt;Access as Assignment&lt;/h2&gt;

&lt;p&gt;Let’s look at how you might use our solution so far in your application. We’ll
see how it can cause issues.&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;RequestHeader&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;vi&quot;&gt;@fields&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Hash&lt;/span&gt;&lt;span class=&quot;p&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;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&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;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;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@fields&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field&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;nf&quot;&gt;content_type&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;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@fields&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:content_type&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;value&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;add_cookie&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cookie&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@fields&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:cookie&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;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@fields&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;key?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:cookie&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@fields&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:cookie&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cookie&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;/div&gt;

&lt;p&gt;We created a class to store request headers, and added a helper method to add
cookies individually. Did you spot the error? Let’s look closer.&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;header&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;RequestHeader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;header&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;add_cookie&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'cookie'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;header&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:cookie&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; ['cookie']&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Looks fine so far, let’s look at how this breaks.&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;header&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;RequestHeader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;header&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:cookie&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; {}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Oops, we expected an array, but it returned us a hash. This is a contrived
example, but a very similar bug caused a major issue in production for an app
that I worked on. Let’s look at one more trap before wrapping up.&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Hash&lt;/span&gt;&lt;span class=&quot;p&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;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&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;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:a&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;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'foo'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; []&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; { a: [] }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;i-avoid-hash-defaults&quot;&gt;I Avoid Hash Defaults&lt;/h2&gt;

&lt;p&gt;Did you catch all these mistakes? If you did, good job, you’re a very
knowledgeable Ruby developer. However, I’d prefer to just avoid these issues
altogether. Imagine if you initialize a hash in one file, and pass it somewhere
else in the application. It would be a nightmare to anticipate or track down
this type of bug.&lt;/p&gt;

&lt;p&gt;In general, I now completely avoid overriding Hash defaults, and I suggest you
carefully consider your own uses of them.&lt;/p&gt;
</description>
        <pubDate>Thu, 22 Apr 2021 00:00:00 +0000</pubDate>
        <link>http://justinhoward.org/avoid-ruby-hash-defaults</link>
        <guid isPermaLink="true">http://justinhoward.org/avoid-ruby-hash-defaults</guid>
        
        
      </item>
    
      <item>
        <title>Why I Love Code Comments (Now)</title>
        <description>&lt;p&gt;Should I add comments to my code? It turns out this is a controversial topic
that has much more nuance than you’d think at first glance. Here are the various
approaches I’ve used and why I now write a lot of comments.&lt;/p&gt;

&lt;h2 id=&quot;a-beginner-approach&quot;&gt;A Beginner Approach&lt;/h2&gt;

&lt;p&gt;As a junior developer I wrote code without a good understanding of how it would
be maintained or how it would stand up to continual changes. Then as my
experience grew, that code went from an unreadable mess to organized and (for
the most part) clear. At this point I rarely used code comments and I didn’t see
the need for them.&lt;/p&gt;

&lt;p&gt;As my skills improved, my team was able to understand &lt;em&gt;how&lt;/em&gt; my code worked. This
was a big improvement, but it’s not nearly enough.&lt;/p&gt;

&lt;h2 id=&quot;code-as-documentation&quot;&gt;Code as Documentation&lt;/h2&gt;

&lt;p&gt;As I became an intermediate developer, I came across some blog posts that
described “self-documenting” code. The concept is that if you write clear enough
code, and name your variables and functions well, comments are unnecessary. They
often claim that if you need comments, your code needs to be fixed.&lt;/p&gt;

&lt;p&gt;Here is an example in Ruby&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;user_is_valid?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&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;kp&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;full_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;nil?&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;nil?&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;^&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;phone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;nil?&lt;/span&gt;
  &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The line with email and phone is not readable at first glance since we’re
abusing the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;^&lt;/code&gt; operator to be XOR (one or the other but not both). We could add
a comment, or we could just extract a method to document that.&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;user_is_valid?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&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;kp&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;full_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;nil?&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user_has_email_xor_phone?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&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;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;user_has_email_xor_phone?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;nil?&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;^&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;phone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;nil?&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This is much more readable. I started following this approach, fanatically
refactoring all my functions into self-documenting bits. Today I take a slightly
more pragmatic approach, but I still use similar strategies.&lt;/p&gt;

&lt;p&gt;However, even this is not enough. A reader can easily understand that we’re
validating that a user has an email XOR phone, but why? Why can’t our user have
both?&lt;/p&gt;

&lt;h2 id=&quot;communicating-intent&quot;&gt;Communicating Intent&lt;/h2&gt;

&lt;p&gt;The next step of documentation is communicating intent. Intent expresses not
only &lt;em&gt;how&lt;/em&gt; your code works, but &lt;em&gt;why&lt;/em&gt; it is designed that way. All applications
are designed to work a specific way, but unless you document intent, that design
can be lost.&lt;/p&gt;

&lt;p&gt;Let’s say the product manager wants to add support for both email and phone on
user accounts. As a developer of this application, I would encounter the
validation rule above. I would wonder whether it’s safe to remove this. Is
anything downstream depending on this rule? Will the front-end UI behave
correctly?&lt;/p&gt;

&lt;p&gt;Let’s add clarifying intent comments to our example above.&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# The given user has an email or phone but not both&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# A user must have at least one way to contact them. That can be either email&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# or phone. However, users cannot have both an email and phone because that&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# would break the NotificationSender module which currently does not support&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# users with both contact methods. If we fix NotificationSender to support both,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# this validation rule can be removed.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;user_has_email_xor_phone?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;nil?&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;^&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;phone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;nil?&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We now know &lt;em&gt;why&lt;/em&gt; this validation rule was created. Later if we want to remove
this rule, we have better information and can approach change with the full
history in mind.&lt;/p&gt;

&lt;p&gt;Much of the code I write now has comments like this. Especially as application
logic becomes more complex, intent documentation is invaluable.&lt;/p&gt;
</description>
        <pubDate>Wed, 14 Apr 2021 00:00:00 +0000</pubDate>
        <link>http://justinhoward.org/why-i-love-code-comments-now</link>
        <guid isPermaLink="true">http://justinhoward.org/why-i-love-code-comments-now</guid>
        
        
      </item>
    
      <item>
        <title>Start Thinking About Connection Timeouts</title>
        <description>&lt;p&gt;When an application makes an HTTP request to another service, the application
surrenders control of its performance to that external service. If it takes 10
seconds to respond, the application waits for 10 seconds. To stay healthy the
application needs to set appropriate timeouts to limit the impact of flaky
external services.&lt;/p&gt;

&lt;h2 id=&quot;why-bother-with-timeouts&quot;&gt;Why Bother With Timeouts?&lt;/h2&gt;

&lt;p&gt;Timeouts are an often overlooked setting when making network requests. We’ll be
talking in terms of HTTP in this post, but timeouts apply to all network
requests. But why should we care about setting timeout values?&lt;/p&gt;

&lt;p&gt;Consider an application that makes an API call to an external service to translate
some text. When a user clicks a translate button, the client does an AJAX
request to our server, and our server calls the translation service. The API
call takes an average of 200ms to return, so we’re able to return translated
text to the user within around 400ms total.&lt;/p&gt;

&lt;p&gt;Suddenly, the translation service performance degrades, and starts taking 5
seconds to return instead of 200ms. Requests to our AJAX endpoint start piling
up, and now our web server starts to run out of available connections. Now our
users start to see errors that the site is down! We can quickly try to restart
servers, but the requests keep piling up because the translation service keeps
taking our available connections.&lt;/p&gt;

&lt;p&gt;How do we avoid this nightmare scenario? The first step is to set timeouts on
all your HTTP requests. Yes, in this scenario, that means that users would see
an error when they click the translate button, but the whole site wouldn’t
crash.&lt;/p&gt;

&lt;h2 id=&quot;how-do-http-clients-handle-timeouts&quot;&gt;How do HTTP clients handle timeouts?&lt;/h2&gt;

&lt;p&gt;Here are the default timeouts for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Net::HTTP&lt;/code&gt;, Ruby’s standard library HTTP
client.&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;vi&quot;&gt;@open_timeout&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;60&lt;/span&gt;
&lt;span class=&quot;vi&quot;&gt;@read_timeout&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;60&lt;/span&gt;
&lt;span class=&quot;vi&quot;&gt;@write_timeout&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;60&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p class=&quot;caption&quot;&gt;(&lt;a href=&quot;https://github.com/ruby/ruby/blob/b2d96abb42abbe2e01f010ffc9ac51f0f9a50002/lib/net/http.rb#L688-L690&quot;&gt;source&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;The default for each of these is 60 seconds! Imagine if one of your third-party
integrations started taking 60 seconds for each call. How would that affect your
application? Notice that there are three timeouts here.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Open timeout: The maximum time allowed to open a TCP connection to the host&lt;/li&gt;
  &lt;li&gt;Read timeout: The maximum time to wait for an HTTP response&lt;/li&gt;
  &lt;li&gt;Write timeout: The maximum time to send your HTTP request&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At a low level, this is how timeouts are implemented for most HTTP client
libraries. For example, here is OkHttp for Java/Kotlin, whose timeouts default
to 10 seconds.&lt;/p&gt;

&lt;div class=&quot;language-kotlin highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;internal&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;connectTimeout&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10_000&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;internal&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;readTimeout&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10_000&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;internal&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;writeTimeout&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10_000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p class=&quot;caption&quot;&gt;(&lt;a href=&quot;https://github.com/square/okhttp/blob/cd722373281202492043f4294fccfe6f691ddc01/okhttp/src/main/kotlin/okhttp3/OkHttpClient.kt#L494-L496&quot;&gt;source&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Regardless of the defaults for your HTTP client, they will likely not match the
usage pattern for your request. You need to be aware of each of these and adjust
them appropriately.&lt;/p&gt;

&lt;h2 id=&quot;be-explicit&quot;&gt;Be Explicit&lt;/h2&gt;

&lt;p&gt;Whether you expect an HTTP request to take a long or short time, you should be
explicit about that expectation. Set your timeouts to match your usage.&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;res&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Net&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;HTTP&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;open_timeout: &lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;1.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;read_timeout: &lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;2.5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;write_timeout: &lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;1.5&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Some HTTP clients try to abstract away the complexity of the three different
timeouts. For example, here is &lt;a href=&quot;https://github.com/jnunemaker/httparty&quot;&gt;HTTParty&lt;/a&gt;
for Ruby.&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;add_timeout?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:timeout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;open_timeout&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:timeout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;read_timeout&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:timeout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;from_ruby_version&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'2.6.0'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;option: :write_timeout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;warn: &lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;false&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;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;write_timeout&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:timeout&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;/div&gt;

&lt;p class=&quot;caption&quot;&gt;(&lt;a href=&quot;https://github.com/jnunemaker/httparty/blob/b9a54d8f73a9a94863bf83a1ba559b557c68b4c8/lib/httparty/connection_adapter.rb#L117-L124&quot;&gt;source&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;It lets you write this&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;no&quot;&gt;HTTParty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;timeout: &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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;But this is a deceptive API and easily causes mistakes. When reading this, you’d
expect that the whole request can take up to 3 seconds. However, the actual
effect is that each individual timeout is set to 3 seconds, adding up to a
worst-case request time of 9 seconds (there’s actually more that contributes to
total request time).&lt;/p&gt;

&lt;h2 id=&quot;base-your-timeouts-on-data&quot;&gt;Base Your Timeouts on Data&lt;/h2&gt;

&lt;p&gt;At &lt;a href=&quot;https://www.parentsquare.com&quot;&gt;ParentSquare&lt;/a&gt;, we use Datadog’s APM product to
trace applications. Tools like this or NewRelic’s APM product provide samples
of each outgoing HTTP request along with the total request time. We can use this
data as a baseline for choosing timeout values.&lt;/p&gt;

&lt;p&gt;For example, if we know that the average request time for a certain endpoint is
100ms, and the max known request time is 300ms, we might choose 600ms for each
of the connect, read, and write timeout values to give us plenty of buffer.
It’s a good idea to build in some buffer in case the service quality of the
endpoint degrades. However, you don’t want too much buffer since that could
start to cause cascading failures in your application.&lt;/p&gt;

&lt;p&gt;As you might have noticed, this requires some amount of educated guessing, since
so far, we have no data that tells us how much of the request is taken by
connect/reads/writes. Can we do a better job of choosing more accurate values?&lt;/p&gt;

&lt;p&gt;While I’m certainly not an expert at this, I found this feature of cURL
described by Joseph Scott in “&lt;a href=&quot;https://blog.josephscott.org/2011/10/14/timing-details-with-curl/&quot;&gt;Timing Details With cURL&lt;/a&gt;”.&lt;/p&gt;

&lt;p&gt;First create a format file we’ll call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;curl-format.txt&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-plain&quot;&gt;time_namelookup: %{time_namelookup}\n
time_connect: %{time_connect}\n
time_appconnect: %{time_appconnect}\n
time_pretransfer: %{time_pretransfer}\n
time_redirect: %{time_redirect}\n
time_starttransfer: %{time_starttransfer}\n
———\n
time_total: %{time_total}\n
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then run cURL with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-w&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--write-out&lt;/code&gt; option, passing in our format
file. Let’s just run it on the ParentSquare home page.&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;curl &lt;span class=&quot;nt&quot;&gt;-L&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-w&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;@curl-format.txt&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; /dev/null &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt;  https://parentsquare.com

time_namelookup: 0.004379
time_connect: 0.072605
time_appconnect: 0.223555
time_pretransfer: 0.223701
time_redirect: 0.291480
time_starttransfer: 0.294933
———
time_total: 0.821796
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This actually gives us a pretty good idea of the timings. The
&lt;a href=&quot;https://curl.se/docs/manpage.html&quot;&gt;cURL manpage&lt;/a&gt; gives us a good description of
each of these values:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;time_namelookup&lt;/strong&gt; The time, in seconds, it took from the start until the
name resolving was completed.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Name resolution took 4ms, so we know that the DNS lookup portion of this request
was negligible.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;time_connect&lt;/strong&gt; The time, in seconds, it took from the start until the TCP
connect to the remote host (or proxy) was completed.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It took 72ms to complete the TCP connection. This would be included in
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;open_timeout&lt;/code&gt; in our Ruby example above.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;time_appconnect&lt;/strong&gt; The time, in seconds, it took from the start until the
SSL/SSH/etc connect/handshake to the remote host was completed. (Added in
7.19.0)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It took 223ms to open a TCP connection and complete the SSL/TLS handshake.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;time_pretransfer&lt;/strong&gt; The time, in seconds, it took from the start until the
file transfer was just about to begin. This includes all pre-transfer commands
and negotiations that are specific to the particular protocol(s) involved.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In this test the request took 223ms before starting any data transfer. So far
we’ve just opened a TCP connection and completed the TLS handshake. We haven’t
sent our HTTP request yet.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;time_redirect&lt;/strong&gt; The time, in seconds, it took for all redirection steps
including name lookup, connect, pretransfer and transfer before the final
transaction was started. time_redirect shows the complete execution time for
multiple redirections. (Added in 7.12.3)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In this case, we did follow a redirect, and so far, after negotiating the
redirect, 291ms have elapsed in total&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;time_starttransfer&lt;/strong&gt; The time, in seconds, it took from the start until the
first byte was just about to be transferred. This includes time_pretransfer
and also the time the server needed to calculate the result.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;At the 294ms point, we’re starting to transfer our first byte. After that, the
rest of the time is spend writing our request and reading the response. As far
as I know, cURL has no way to differentiate between those times.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;time_total&lt;/strong&gt; The total time, in seconds, that the full operation lasted.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The total time for this request was 821ms after we received our response.&lt;/p&gt;

&lt;p&gt;What does all this tell us? If we strip away the extra information, we see that
we can get the information we need from cURL with two metrics,
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;time_pretransfer&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;time_total&lt;/code&gt;, so let’s rerun the command. We don’t even
need the format file now.&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;curl &lt;span class=&quot;nt&quot;&gt;-L&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-w&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Pre: %{time_pretransfer}&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Total: %{time_total}&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; /dev/null &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt;  https://parentsquare.com

Pre: 0.223701
Total: 0.821796
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now we can make better educated guesses about our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;open_timeout&lt;/code&gt;,
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;read_timeout&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;write_timeout&lt;/code&gt; values.&lt;/p&gt;

&lt;h3 id=&quot;open-timeout&quot;&gt;Open Timeout&lt;/h3&gt;

&lt;p&gt;Our test data shows 223ms, so an open timeout of 1 second should give the
endpoint more than enough room to occasionally respond slowly without timing
out. Depending on your use-case, you may want to be more or less strict with
this.&lt;/p&gt;

&lt;h3 id=&quot;read-timeout&quot;&gt;Read Timeout&lt;/h3&gt;

&lt;p&gt;If we subtract our pretransfer time from the total, we get 598ms. This includes
both write and read time. In most real-world use-cases, your read time is going
to take the most time, since it includes the entire time from when the server
receives your request, to when you receive a response back. This will include
time for the remote server to process your request and send the response. So we
can assume that most of this 598ms was included in the read wait time. If you
know of a better way of measuring this, let me know.&lt;/p&gt;

&lt;h3 id=&quot;write-timeout&quot;&gt;Write Timeout&lt;/h3&gt;

&lt;p&gt;In this case, we can set this to a fairly low value, since we’re assuming that
most of the request time is taken by the read. However, in cases where you’re
writing a lot of data (for example file uploads), you’ll need to allow time for
that data to be transferred.&lt;/p&gt;

&lt;h2 id=&quot;experiment&quot;&gt;Experiment&lt;/h2&gt;

&lt;p&gt;Ultimately, the performance of your external dependencies may vary, and you
might need to do what amounts to “guess and check” to tune in the right timeout
values. Your application should be able to tolerate some timeouts without
causing usability issues for your users. If it can’t, you will also need to add
other forms of fault-tolerance (like retries) to make sure that your application
can recover from a temporary service interruption in its dependencies.&lt;/p&gt;

&lt;h2 id=&quot;going-further&quot;&gt;Going Further&lt;/h2&gt;

&lt;p&gt;Even with our timeouts, we still might worry about cascading failures. Consider
if we’re processing a job 10,000 times a minute, and each of those makes an HTTP
request. That request normally takes 300ms, and we have our timeouts set around
1 second. If that request starts timing out, suddenly that job is taking 3 times
longer than normal! This application likely won’t behave well if that happens.&lt;/p&gt;

&lt;p&gt;To solve this problem, we need something like circuit breakers, as described by
Michael T. Nygard in his book “Release It!: Design and Deploy Production-Ready
Software”. I highly recommend reading it for great examples of catastrophic
software failures and ways to avoid them.&lt;/p&gt;

&lt;p&gt;I also wrote a library called &lt;a href=&quot;https://github.com/parentsquare/faulty&quot;&gt;Faulty&lt;/a&gt;
that implements circuit breakers for Ruby.&lt;/p&gt;

&lt;p&gt;Timeouts are an important first step to ensure your application is safe from
failing HTTP endpoints. They are often overlooked by even seasoned developers.
Make sure you think about them before it causes a problem.&lt;/p&gt;
</description>
        <pubDate>Sun, 22 Nov 2020 00:00:00 +0000</pubDate>
        <link>http://justinhoward.org/start-thinking-about-connection-timeouts</link>
        <guid isPermaLink="true">http://justinhoward.org/start-thinking-about-connection-timeouts</guid>
        
        
      </item>
    
      <item>
        <title>A Portable Shell Script Template</title>
        <description>&lt;p&gt;Often write small utility scripts to perform repetitive tasks. More
often than not, throw-away scripts become tools I come back to over and over.
I’ve decided to spend a bit more time on polish so that when I use the script
again, it is documented and easy to use.&lt;/p&gt;

&lt;p&gt;Most of my scripts are written in portable shell code. I’ve found that shell
scripts are best for writing small workflow tools. I always start with the same
basic structure.&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#!/usr/bin/env sh&lt;/span&gt;

usage&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&amp;amp;2 &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;EOF&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;
Usage: example-script [OPTIONS] ARG1 ARG2...
Perform an example function

OPTIONS
-h       Help - Show this help message
-m VAL   My flag - Do something fun!
-n       Dry run - Print debug messaging instead of performing the function
-v       Verbose - Print verbose messaging
&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;EOF
&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# msg(message...)&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Print a message to stderr&lt;/span&gt;
msg&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;printf&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'%s\n'&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$*&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&amp;amp;2
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# verbose(message...)&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Print a message only in verbose mode&lt;/span&gt;
verbose&lt;span class=&quot;o&quot;&gt;()&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;nt&quot;&gt;-n&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$verbose&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; msg &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$@&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# error_exit(message...)&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Print an error, then exit&lt;/span&gt;
error_exit&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  msg &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$@&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;exit &lt;/span&gt;1
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# usage_error(message...)&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Print an error and usage information, then exit&lt;/span&gt;
usage_error&lt;span class=&quot;o&quot;&gt;()&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;&quot;$#&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-gt&lt;/span&gt; 0 &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;printf&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'%s\n\n'&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$*&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&amp;amp;2
  usage
  &lt;span class=&quot;nb&quot;&gt;exit &lt;/span&gt;1
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;while &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;getopts&lt;/span&gt; :hm:nv opt&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do
  case&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$opt&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in
    &lt;/span&gt;h&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; usage &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;exit&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
    m&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;my_flag&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$OPTARG&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
    n&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;dry_run&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;1 &lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
    v&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;verbose&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;1 &lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
    &lt;span class=&quot;se&quot;&gt;\?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; usage_error &lt;span class=&quot;s2&quot;&gt;&quot;Invalid option -&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;OPTARG&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
    :&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; usage_error &lt;span class=&quot;s2&quot;&gt;&quot;Missing value for option -&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;OPTARG&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;esac&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;done
&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;shift&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;$((&lt;/span&gt;OPTIND &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;k&quot;&gt;))&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;$#&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-ge&lt;/span&gt; 2 &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; usage_error &lt;span class=&quot;s1&quot;&gt;'At least 2 arguments are required'&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Main script here&lt;/span&gt;

verbose &lt;span class=&quot;s1&quot;&gt;'Prints a message only in verbose mode'&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-z&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$dry_run&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&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;k&quot;&gt;then
  &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'This will not run if dry run is set'&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;step-by-step&quot;&gt;Step by Step&lt;/h2&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#!/usr/bin/env sh&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This is the “shebang”. It tells the operating system to run the script with the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sh&lt;/code&gt; command. I use POSIX compatible sh rather than bash for
portability, although I sometimes prefer bash for some features (like arrays).&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;usage&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&amp;amp;2 &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;EOF&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;
Usage: example-script [OPTIONS] ARG1 ARG2...
Perform an example function

OPTIONS
-h       Help - Show this help message
-n       Dry run - Print debug messaging instead of performing the function
-v       Verbose - Print verbose messaging
&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;EOF
&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This function just prints a block of help text. I’ve learned not to skip this.
Even for scripts I only use myself, I reference this help block constantly.&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# msg(message...)&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Print a message to stderr&lt;/span&gt;
msg&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;printf&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'%s\n'&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$*&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&amp;amp;2
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This function is basically just echo, but it prints to stderr instead of stdout.
It’s always a good idea to print messaging to stderr. This allows the real
output to be parsed by another script if necessary.&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# verbose(message...)&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Print a message only in verbose mode&lt;/span&gt;
verbose&lt;span class=&quot;o&quot;&gt;()&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;nt&quot;&gt;-n&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$verbose&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; msg &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$@&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This function is just like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;msg&lt;/code&gt; except it only prints if the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-v&lt;/code&gt; verbose flag
is set. I don’t always use this, but it’s good for situations where you
sometimes want debug output.&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# error_exit(message...)&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Print an error, then exit&lt;/span&gt;
error_exit&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  msg &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$@&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;exit &lt;/span&gt;1
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# usage_error(message...)&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Print an error and usage information, then exit&lt;/span&gt;
usage_error&lt;span class=&quot;o&quot;&gt;()&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;&quot;$#&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-gt&lt;/span&gt; 0 &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;printf&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'%s\n\n'&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$*&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&amp;amp;2
  usage
  &lt;span class=&quot;nb&quot;&gt;exit &lt;/span&gt;1
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;These are just shortcuts for printing an error message and exiting. I use
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;error_exit&lt;/code&gt; when encountering a runtime error, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;usage_error&lt;/code&gt; when the user
inputs invalid information.&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;while &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;getopts&lt;/span&gt; :hm:nv opt&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do
  case&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$opt&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in
    &lt;/span&gt;h&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; usage &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;exit&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
    n&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;dry_run&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;1 &lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
    m&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;my_flag&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$OPTARG&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
    v&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;verbose&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;1 &lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
    &lt;span class=&quot;se&quot;&gt;\?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; usage_error &lt;span class=&quot;s2&quot;&gt;&quot;Invalid option -&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;OPTARG&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
    :&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; usage_error &lt;span class=&quot;s2&quot;&gt;&quot;Missing value for option -&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;OPTARG&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;esac&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;done
&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;shift&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;$((&lt;/span&gt;OPTIND &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;k&quot;&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This part collects option flags (like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-n&lt;/code&gt;). For more information see &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;man
getopts&lt;/code&gt;. You can add or remove flags in this section.&lt;/p&gt;

&lt;p&gt;The first line defines a loop over every flag. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getopts&lt;/code&gt; is a utility that gets
the next flag on each call. The first argument sets the expected flags, and the
second is the variable name to store each flag in.&lt;/p&gt;

&lt;p&gt;The string &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:hm:nv&lt;/code&gt; defines the flags. If the string begins with a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:&lt;/code&gt;,
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getopts&lt;/code&gt; runs in quiet mode, meaning it won’t output any text. Each letter
after that is an option. If the option is followed by a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:&lt;/code&gt;, it accepts an
argument. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-m&lt;/code&gt; option here accepts an argument.&lt;/p&gt;

&lt;p&gt;The case statement processes each flag and sets variables if the flag is
encountered. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$opt&lt;/code&gt; variable is the flag letter and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$OPTARG&lt;/code&gt; variable
is the argument if one is set. A &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;?&lt;/code&gt; is given if an invalid option is
encountered. A &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:&lt;/code&gt; is given if a flag expected an argument but it was missing.&lt;/p&gt;

&lt;p&gt;The last line &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;shift $((OPTIND - 1))&lt;/code&gt; removes the option flags from the argument
list so that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$1&lt;/code&gt; - &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$9&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$@&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$*&lt;/code&gt; are set to the remaining arguments.&lt;/p&gt;

&lt;p&gt;Now to write some scripts!&lt;/p&gt;
</description>
        <pubDate>Mon, 31 Jul 2017 00:00:00 +0000</pubDate>
        <link>http://justinhoward.org/a-portable-shell-script-template</link>
        <guid isPermaLink="true">http://justinhoward.org/a-portable-shell-script-template</guid>
        
        
      </item>
    
      <item>
        <title>How to Fail Better</title>
        <description>&lt;p&gt;Software development is like an art. Every project starts with a concept, an
idea that organically unfolds into something beautiful. That is the creative
process that makes my work worthwhile. However, for every masterpiece there are
a thousand failures. How should software developers deal with failure?&lt;/p&gt;

&lt;h2 id=&quot;fail-early&quot;&gt;Fail Early&lt;/h2&gt;

&lt;p&gt;Failures are unavoidable. Rather than fighting against failure, software
developers should embrace them as a useful part of the craft. In order to profit
from failure, it needs to be expected.&lt;/p&gt;

&lt;p&gt;This last week I was building a JavaScript library for managing data in a single
page application. I began the project with the goal of keeping it simple. It
turned out anything but simple. As the week went by I would come across a
problem and solve it by adding a bit to the scope of my library. By Tuesday, the
library had a dependency graph of all the tracked entities, and was managing
object relationships. I was building an &lt;a href=&quot;http://en.wikipedia.org/wiki/Object-relational_mapping&quot;&gt;ORM&lt;/a&gt;. I recognized the warning
signs, but I was committed. I had already spent two days working on it. By
Thursday, it became obvious that my project had long ago missed my goal of
simplicity and was headed nowhere. I had failed.&lt;/p&gt;

&lt;p&gt;Why did I wait so long before admitting failure? I don’t think it was pride or
fear. It just caught me off guard. I wasn’t expecting to fail. This blind spot
is a dangerous one. This mistake cost my company four days of work. It could
have been much more. Had I been watching for failure and heeded the warning
signs, I could have caught my mistake much earlier.&lt;/p&gt;

&lt;p&gt;In order to fail profitably, mistakes need to be caught early. The later they
happen, the more they cost. There are two ways to do that. First, continually
evaluate your work. Have benchmarks for success and failure. Are you meeting
your original goals? Are you fulfilling user requirements with your work?
Second, be accountable to someone. Often we cannot see our own blind spots. Be
completely transparent about what you are working on with your co-workers. If
you are self-employed, have a mentor or partner that you can share your work
with.&lt;/p&gt;

&lt;h2 id=&quot;dont-feed-a-failure&quot;&gt;Don’t Feed a Failure&lt;/h2&gt;

&lt;p&gt;In economics, &lt;a href=&quot;http://en.wikipedia.org/wiki/Sunk_costs&quot;&gt;sunk costs&lt;/a&gt; are costs that are already incurred. The
time you have already spent on a project is a sunk cost. You cannot get that
time back. The sunk cost fallacy is making a choice based on what you have
already paid rather than objectively evaluating the current situation. When I
saw the warning signs that my JavaScript project was not working, I rationalized
it by saying that “I had already spent two days working on it”. That is a
fallacy. Instead, I should have objectively evaluated my project and seen that
it was not worth spending any more time on. Instead, I spent two &lt;em&gt;more&lt;/em&gt; days on
it before conceding. If a project or task has failed, kill it immediately and
spend your time on a better solution.&lt;/p&gt;

&lt;h2 id=&quot;dont-repeat-yourself&quot;&gt;Don’t Repeat Yourself&lt;/h2&gt;

&lt;p&gt;Failures are rich with useful information that often goes to waste. &lt;a href=&quot;http://en.wikipedia.org/wiki/Don't_repeat_yourself&quot;&gt;DRY&lt;/a&gt;
(Don’t Repeat Yourself) is a principle used in software development to minimize
duplicated code and redundant systems, but it can be extended even further to
the development process. When I make a mistake, I evaluate it, find out why it
happened, then take steps to prevent it.&lt;/p&gt;

&lt;p&gt;After recovering from the failure of my project this week, I identified two
reasons for the failure. I didn’t identify the problem soon enough, and my
original design was too complex. To solve the early identification problem, I am
using daily stand up meetings and more frequent code reviews to be as
transparent as possible about my work. To improve my designs, I plan to
collaborate more with co-workers during design stage.&lt;/p&gt;

&lt;p&gt;No one enjoys their failures, but when we harness their power, failures can
become a useful tool in the software developer’s toolbox. We use them to improve
ourselves. If software development is an art, then our failures are just the
road to creating a masterpiece.&lt;/p&gt;

</description>
        <pubDate>Sat, 08 Nov 2014 10:00:00 +0000</pubDate>
        <link>http://justinhoward.org/how-to-fail-better</link>
        <guid isPermaLink="true">http://justinhoward.org/how-to-fail-better</guid>
        
        
      </item>
    
      <item>
        <title>How I Set Up GitHub Pages</title>
        <description>&lt;p&gt;I was suffering from analysis paralysis trying to choose a platform for this
blog. Out of the hundreds of options, &lt;a href=&quot;https://pages.github.com/&quot;&gt;GitHub Pages&lt;/a&gt; and
&lt;a href=&quot;http://jekyllrb.com&quot;&gt;Jekyll&lt;/a&gt; provided the right balance power and simplicity. I’ll explain
why, and how to get started.&lt;/p&gt;

&lt;h2 id=&quot;what-is-github-pages&quot;&gt;What Is GitHub Pages?&lt;/h2&gt;

&lt;p&gt;GitHub Pages is a static web host integrated with GitHub so that you can deploy
a website simply by pushing to your git repository. You can see the source code
of this site at its &lt;a href=&quot;https://github.com/justinhoward/justinhoward.github.io&quot;&gt;GitHub repo&lt;/a&gt;. This post is written in markdown
and its HTML was generated by &lt;a href=&quot;http://jekyllrb.com&quot;&gt;Jekyll&lt;/a&gt;. GitHub has Jekyll built in, so
as soon as I push a new post, the site is immediately regenerated.&lt;/p&gt;

&lt;h2 id=&quot;setting-up-the-repository&quot;&gt;Setting Up The Repository&lt;/h2&gt;

&lt;p&gt;First you need to create a &lt;a href=&quot;https://github.com/new&quot;&gt;new github repository&lt;/a&gt; with the name
&lt;em&gt;username&lt;/em&gt;.github.io. Replace &lt;em&gt;username&lt;/em&gt; with your GitHub username. Don’t
add a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;README&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.gitignore&lt;/code&gt;, or license yet.&lt;/p&gt;

&lt;p&gt;Now clone the repository on your machine with&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git clone git@github.com:username/username.github.io.git
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now we’re going to set up Jekyll. You will need to have &lt;a href=&quot;https://www.ruby-lang.org/en/installation/&quot;&gt;ruby installed&lt;/a&gt;.&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;gem &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;jekyll

&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;username.github.io
jekyll new &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
jekyll serve &lt;span class=&quot;nt&quot;&gt;--watch&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Jekyll is now running your site! Go to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;localhost:4000&lt;/code&gt; in your browser to see
the basic template that was created. If you make changes to any of the content
files you will see the changes reflected in the generated site. Take a look at
the &lt;a href=&quot;http://jekyllrb.com/docs/home/&quot;&gt;Jekyll Documentation&lt;/a&gt; for more information on configuring and
building your site.&lt;/p&gt;

&lt;p&gt;After you have your site configured and you added your content, push it to
GitHub.&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git push
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;After your first push, it will take a while for your site to show up. For me it
took about 15 minutes. Once it is created, you can see it at
&lt;em&gt;username&lt;/em&gt;.github.io.&lt;/p&gt;

&lt;h2 id=&quot;setting-up-your-domain-name&quot;&gt;Setting Up Your Domain Name&lt;/h2&gt;

&lt;p&gt;GitHub fully supports pointing your own domain name at a GitHub pages site. They
go into detail in the &lt;a href=&quot;https://help.github.com/articles/setting-up-a-custom-domain-with-github-pages/&quot;&gt;help doc&lt;/a&gt; on the subject. I’ll
explain how &lt;em&gt;justinhoward.org&lt;/em&gt; is set up.&lt;/p&gt;

&lt;p&gt;There are two components to setting up &lt;em&gt;justinhoward.org&lt;/em&gt; to point to
&lt;em&gt;justinhoward.github.io&lt;/em&gt;. First, I need to set up my DNS records, then I need
to set up a file called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CNAME&lt;/code&gt; in the repository.&lt;/p&gt;

&lt;p&gt;My DNS records look like this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-plain&quot;&gt;@    A        192.30.252.153
@    A        192.30.252.154
www  CNAME    justinhoward.github.io.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;em&gt;@&lt;/em&gt; records represent the apex domain &lt;em&gt;justinhoward.org&lt;/em&gt;. Apex domains
cannot be aliased with CNAME. We need to use A records for those. Make sure you
are using the latest IPs from the GitHub documentation. If you are only using
subdomains, you can ignore those records. The subdomain &lt;em&gt;www&lt;/em&gt; is pointed
directly at &lt;em&gt;justinhoward.github.io&lt;/em&gt; with a CNAME (alias) record.&lt;/p&gt;

&lt;p&gt;Now &lt;em&gt;justinhoward.org&lt;/em&gt; and &lt;em&gt;www.justinhoward.org&lt;/em&gt; will both go to the GitHub
Pages site. However, GitHub doesn’t know which domain to prefer. Try typing
&lt;em&gt;justinhoward.org&lt;/em&gt; into your browser. You’ll see it gets redirected to
&lt;em&gt;www.justinhoward.org&lt;/em&gt;. To do that, you need to have a CNAME file in the root of
your repository.&lt;/p&gt;

&lt;p&gt;The file should contain the domain you want as your primary domain.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-plain&quot;&gt;www.justinhoward.org
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;next-steps&quot;&gt;Next Steps&lt;/h2&gt;

&lt;p&gt;You can now set up a blog with GitHub Pages. What next? How about adding some
comments? You’ll see that the comments on this site are powered by
&lt;a href=&quot;https://disqus.com/&quot;&gt;Disqus&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You’ll also want to customize your template. At the time of this writing, I’m
still running the default Jekyll template. I’m planning to personalize it soon.
Keep an eye out for that.&lt;/p&gt;

</description>
        <pubDate>Wed, 05 Nov 2014 21:00:00 +0000</pubDate>
        <link>http://justinhoward.org/how-i-set-up-github-pages</link>
        <guid isPermaLink="true">http://justinhoward.org/how-i-set-up-github-pages</guid>
        
        
      </item>
    
  </channel>
</rss>
