<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Matt Farmer]]></title><description><![CDATA[A software engineer writing about whatever comes to mind.]]></description><link>https://farmdawgnation.com/</link><image><url>https://farmdawgnation.com/favicon.png</url><title>Matt Farmer</title><link>https://farmdawgnation.com/</link></image><generator>Ghost 2.37</generator><lastBuildDate>Fri, 15 Nov 2019 18:31:27 GMT</lastBuildDate><atom:link href="https://farmdawgnation.com/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[On DigitalOcean Kubernetes, Part 3: Simplified Helm Tooling]]></title><description><![CDATA[If you're anything like me, you want very little typing to deploy K8S Helm charts. This post is about some simple tooling I created to achieve that.]]></description><link>https://farmdawgnation.com/on-digitalocean-kubernetes-part-3/</link><guid isPermaLink="false">5c56553ef4f6c3002baad8cb</guid><category><![CDATA[Operations]]></category><category><![CDATA[On Digital Ocean Kubernetes (Series)]]></category><dc:creator><![CDATA[Matt Farmer]]></dc:creator><pubDate>Sat, 13 Apr 2019 20:34:00 GMT</pubDate><media:content url="https://fdn-assets.sfo2.cdn.digitaloceanspaces.com/2019/02/jeremy-bishop-136677-unsplash.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://fdn-assets.sfo2.cdn.digitaloceanspaces.com/2019/02/jeremy-bishop-136677-unsplash.jpg" alt="On DigitalOcean Kubernetes, Part 3: Simplified Helm Tooling"><p>Deploying packages with Helm can require a lot of ceremony on the command line. It's not senseless ceremony: there are use cases where the flexibility of Helm is helpful. Yet, if you're anything like me, you want as little typing as possible when you're ready to throw a thing at Kubernetes. This post is about some simple tooling I created to achieve that.</p><p><em>This post is part 3 in my series about running my own Kubernetes deployment using Digital Ocean managed Kubernetes. If you're interested in what else is involved in my setup, be sure to check out <a href="https://farmdawgnation.com/2019/01/31/on-digitalocean-kubernetes-part-1/">part 1</a> and part 2.</em></p><p>Deploying something to my cluster using Helm loosely involves a Helm invocation that looks something like this:</p><!--kg-card-begin: code--><pre><code>helm upgrade deployment_name \
  chart_name \
  -f override_values.yaml \
  --tls \ # if you don't have the env var set
  --install \
  --namespace target_namespace</code></pre><!--kg-card-end: code--><p>This is fine until you've got to keep everything straight for more than two deployments or if you're not doing deployments frequently. At work, we built out a good amount of tooling to manage Helm for us. Honestly, though, I didn't need anything near that complex for my personal cluster. I settled down one evening not long ago, stretched my bash muscles, and came up with something "good enough" for me.</p><h2 id="matt-s-k8s-specs-repo">Matt's k8s-specs repo</h2><p>I have a git repository that I've imaginatively named k8s-specs. The structure is pretty straightforward:</p><!--kg-card-begin: code--><pre><code>k8s-specs/
├── deploy.sh
├── fdn
│   ├── CHART_NAME
│   ├── dependencies.yaml
│   └── values.yaml
├── ghost-test
│   ├── CHART_NAME
│   ├── dependencies.yaml
│   └── values.yaml
├── mysql
│   ├── CHART_NAME
│   ├── dependencies.yaml
│   └── values.yaml
├── nfs
│   ├── CHART_NAME
│   └── values.yaml
└── traefik
    ├── CHART_NAME
    └── values.yaml</code></pre><!--kg-card-end: code--><p>Under k8s-specs, each folder is a thing I want to deploy. The name that's used for the deployment name in Helm is the same as the folder name. Each folder has up to three items in it:</p><ol><li>The <code>CHART_NAME</code> file that is a valid reference to the Helm chart I want to use. This is the only file that's required.</li><li>The <code>dependencies.yaml</code> file containing any Kubernetes resources that must be added <em>before </em>the Helm chart is run. I typically use this to deploy secrets or something similar.</li><li>The <code>values.yaml</code> file that overrides the default settings for the Chart for my deployment.</li></ol><p>This turns out to be a pretty excellent setup. It can even support a chart actually living in one of these folders, if needed.</p><p>The <code>deploy.sh</code> script is a few lines of bash that does the required legwork to make things happen in the Kubernetes cluster. It takes up to two arguments: the first is name of the folder you want to deploy, the second is the namespace in Kubernetes you want to deploy it in. The second argument is optional and only matters for initial deployments. Subsequent deployments of a chart will always go to the namespace the initial deployment targeted.</p><p>The source of my deploy script is:</p><!--kg-card-begin: code--><pre><code>#!/bin/bash

NAME=$1
CHART_NAME=$(cat $NAME/CHART_NAME)
NAMESPACE=${2:-default}

echo "Name:" $NAME
echo "Chart:" $CHART_NAME
echo "Namespace: " $NAMESPACE

echo "Ensuring dependencies are installed..."

if [[ -f "$NAME/dependencies.yaml" ]]; then
  echo "Applying dependencies..."
  kubectl apply -f $NAME/dependencies.yaml
else
  echo "No dependencies to apply."
fi

echo "Running helm"
helm upgrade $NAME $CHART_NAME -f $NAME/values.yaml --tls --install --namespace $NAMESPACE</code></pre><!--kg-card-end: code--><p>Now whenever I have changes I want to deploy to the blog, I just drop into my k8s-specs repository on my terminal and type <code>./deploy.sh fdn</code> to get rolling.</p><p>I've been using this setup for many weeks now and have found it to age pretty well so far. This is more than I can say for a lot of Chef cookbooks I've written in a prior life.</p>]]></content:encoded></item><item><title><![CDATA[On DigitalOcean Kubernetes, Part 2: Core Services]]></title><description><![CDATA[After you've got your initial Kubernetes cluster up and running the next step is to decide what core cluster services you want to install. I'll walk through what I've deployed in my DigitalOcean cluster.]]></description><link>https://farmdawgnation.com/on-digitalocean-kubernetes-part-2/</link><guid isPermaLink="false">5c55c198f4f6c3002baad824</guid><category><![CDATA[Operations]]></category><dc:creator><![CDATA[Matt Farmer]]></dc:creator><pubDate>Thu, 14 Feb 2019 01:53:48 GMT</pubDate><media:content url="https://fdn-assets.sfo2.cdn.digitaloceanspaces.com/2019/02/yannis-papanastasopoulos-340526-unsplash.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://fdn-assets.sfo2.cdn.digitaloceanspaces.com/2019/02/yannis-papanastasopoulos-340526-unsplash.jpg" alt="On DigitalOcean Kubernetes, Part 2: Core Services"><p>After you've got your initial Kubernetes cluster up and running the next step is to decide what core cluster services you want to install. I'll walk through what I've deployed in my DigitalOcean cluster. This post is Part 2 of my experience running a personal Kubernetes Cluster on DigitalOcean's managed Kubernetes platform. If you missed part 1, you can <a href="https://farmdawgnation.com/2019/01/31/on-digitalocean-kubernetes-part-1/">find it here</a>.</p><p>The core services I chose to deploy to my Kubernetes cluster are:</p><ul><li><strong>Sealed Secrets</strong> — A secure secret implementation for Kubernetes.</li><li><strong>Tiller</strong> — The server-side component for the Helm package manager.</li><li><strong>Traefik</strong> — An HTTP server that serves as my edge proxy.</li></ul><p>Below I'm going to walk through what each of these do in detail and some specifics about how I use each of them.</p><h2 id="sealed-secrets">Sealed Secrets</h2><p>Kubernetes ships with a <a href="https://kubernetes.io/docs/concepts/configuration/secret/">Secrets API</a> that gives cluster users the hooks to protect credentials and other sensitive information. Secrets themselves, however, don't provide any kind of encryption on the data provided to them. The Kubernetes default "Opaque" secrets are just bags of keys with base64-encoded values. A base64-encoded secret isn't something you'd want to put into, say, GitHub. Cluster users essentially have two options for secure secret storage.</p><p>The first is to manage secrets totally apart from version control. The second option is to deploy tooling that handles the encryption and decryption of secrets into their base64-encoded counterparts for Kubernetes.</p><p>I chose to use <a href="https://github.com/bitnami-labs/sealed-secrets">Bitnami's Sealed Secrets Controller</a>.</p><p>When you deploy the controller to your cluster it generates a public and private key pair for encryption and decryption, respectively. It also defines a new resource type, <code>sealedsecret</code> that can be used from <code>kubectl</code> and other tooling. A sealed secret is encrypted using the public key the controller generates. When you push a new <code>sealedsecret</code> resource to your cluster, the controller decrypts it using its private key and creates a corresponding Kubernetes <code>secret</code> that can be mounted into a Pod.</p><p>The YAML file for the sealed secret is safe to check into GitHub alongside your other Kubernetes resources because it can only be decrypted with the private key in your cluster. If it were to fall into the hands of an unsavory foe, it wouldn't do them much good unless they are the NSA.</p><p>If you are deploying the Sealed Secrets Controller on a cluster with many users, I recommend using <a href="https://kubernetes.io/docs/reference/access-authn-authz/rbac/">role-based access control</a> to block individual users from interacting with the <code>secret</code> resource from <code>kubectl</code>. This will prevent users from being able to access the base64 encoded versions of secrets. It will also serve as a useful reminder that folks should be using <code>sealedsecret</code> in your production cluster (because they won't be able to directly create the less secure <code>secret</code> object).</p><h3 id="installing-sealed-secrets">Installing Sealed Secrets</h3><p>The repository for the Sealed Secrets Controller has great <a href="https://github.com/bitnami-labs/sealed-secrets#installation">installation instructions</a>. Just a few simple kubectl commands stand between you and the ability to create sealed secrets to your heart's content.</p><p>You'll also want to install <code>kubeseal</code> on your local machine to create sealed secrets. You can download the latest binary for Linux and macOS from their <a href="https://github.com/bitnami-labs/sealed-secrets/releases">releases page on GitHub</a> or install it using Homebrew:</p><pre><code>$ brew install kubeseal</code></pre><h3 id="creating-your-first-sealed-secret">Creating your first sealed secret</h3><p>Creating a sealed secret is a two-step process:</p><ol><li>Locally create a Kubernetes Opaque secret that you would like to seal (but don't push it to the cluster)</li><li>Run that secret through <code>kubeseal</code> to do the encryption, and output it to YAML so you can store it somewhere. (You could also output it to JSON, but meh.)</li></ol><p>In Bash that process looks like so:</p><pre><code>kubectl create secret generic \
  --dry-run \
  my-secret-name \
  --from-literal KEY1=VALUE1 \
  --from-literal KEY2=VALUE2 \
  -o json | kubeseal --format yaml</code></pre><p>To make this a bit easier, I've written a shell script that lives on my path that I've named <code>ezseal</code>:</p><pre><code>#!/bin/bash

set -e

kubectl create secret generic \
  --dry-run \
  "$@" \
  -o json | kubeseal --format yaml</code></pre><p>This allows me to get the same result by running:</p><pre><code>$ ezseal my-secret --from-literal KEY1=VALUE1 --from-literal KEY2=VALUE2</code></pre><p>The resulting YAML can be pushed as a <code>sealedsecret</code> resource to your cluster. Once the controller picks up that the sealed secret is there, a corresponding <code>secret</code> resource will appear in your cluster with the decrypted values.</p><h2 id="tiller-and-helm">Tiller and Helm</h2><p><a href="https://helm.sh">Helm</a> is a popular way to distribute applications that can be deployed to a Kubernetes cluster. Tiller is the cluster-side component that the <code>helm</code> command line tool requires. To use <code>helm</code>, you need Tiller.</p><p>One option for deploying Tiller is to deploy it on your local machine and configure it to talk to a remote Kubernetes cluster. This option is viable because Tiller persists everything it needs in the cluster itself. It's a perfectly fine option if you don't want to run Tiller remotely. I decided to run Tiller in my cluster for little other reason than I wanted to.</p><blockquote><strong>Note: </strong>The default Tiller configuration does not enforce TLS on Tiller's API endpoint. Any multi-user, production deployment of Kubernetes should take care to enable TLS on Tiller.</blockquote><p><a href="https://docs.helm.sh/">Helm's Documentation</a> is pretty comprehensive. I won't waste my effort talking about how to install Tiller and the <code>helm</code> client. I will, however, share a few things I've done for configuring my <code>helm</code> client locally.</p><h3 id="setting-up-tiller-s-key-infrastructure">Setting up Tiller's Key Infrastructure</h3><p>Helm's documentation walks you through setting up Tiller's TLS using the raw openssl commands to create a Certificate Authority and sign the certificate. Each user should have their own client certificate they use to authenticate to Tiller, so you can get into a situation where whoever administrates these keys does a lot of key signing.</p><p>You have a few options here to make this easier with out-of-the-box tools.</p><p>The first is to use <a href="https://github.com/FiloSottile/mkcert">mkcert</a>. The mkcert utility was designed for local development certificates, but it also makes running a public key infrastructure for something like Tiller a lot easier because it can issue and sign certificates from a CA with a single command. If you're going to have mostly one person managing certificates for a Tiller install, you might want to consider this option.</p><p>The second is to look at deploying something like <a href="https://www.vaultproject.io/">Vault</a> to manage the PKI for Tiller and other services. The deployment of Vault is not a small undertaking. However, at a certain scale it is a preferable way to manage these certificates.</p><h3 id="defaulting-helm-to-tls-locally">Defaulting Helm to TLS locally</h3><p>The <code>helm</code> client does not default to using TLS. If you attempt to use <code>helm</code> against a Tiller setup that has TLS turned on without providing the <code>--tls</code> flag, you will get an opaque error message.</p><p>I fixed my forgetfulness by adding the following environment variable to my shell profile:</p><pre><code>export HELM_TLS_ENABLE=true</code></pre><p>Now my local <code>helm</code> client will default to using TLS when it connects to Tiller.</p><h2 id="traefik">Traefik</h2><p>Kubernetes cluster admins can choose to deploy an Ingress Controller that's capable of processing <a href="https://kubernetes.io/docs/concepts/services-networking/ingress/">Kubernetes ingress definitions</a> and routing incoming requests that match that definition to the proper backend. At the end of the day, an ingress controller is a reverse proxy with some wiring that permits it to update its configuration when new ingress definitions are added to Kubernetes.</p><p>My proxy of choice is <a href="https://traefik.io/">Traefik</a>. (Apparently, pronounced "traffic" because letters don't mean anything.)</p><p>A few things about Traefik make it my go-to solution for an edge proxy:</p><ul><li>The simplicity of its configuration is second to none.</li><li>It has built-in support for Let's Encrypt.</li><li>It has built-in support for integrating with Kubernetes.</li><li>It also can be employed as a service mesh proxy</li><li>It has a built-in dashboard and a slew of useful metrics</li></ul><p>I used the <a href="https://github.com/helm/charts/tree/master/stable/traefik">official Helm chart to deploy Traefik</a> to my cluster. The README there does a good job of laying out the various options for the deployment.</p><h2 id="conclusion">Conclusion</h2><p>My cluster is a pretty simple one. A full deployment at a multi-person organization could be much, much more complex. But for one dude running a blog that occasionally gets some readers these cluster services work pretty well.</p>]]></content:encoded></item><item><title><![CDATA[On DigitalOcean Kubernetes, Part 1]]></title><description><![CDATA[ Until recently I was running my blog on Linode using Docker Swarm. This week I migrated over to Kubernetes on DigitalOcean.]]></description><link>https://farmdawgnation.com/on-digitalocean-kubernetes-part-1/</link><guid isPermaLink="false">5c51ae27810c70002a64f316</guid><category><![CDATA[Operations]]></category><category><![CDATA[Personal]]></category><category><![CDATA[On Digital Ocean Kubernetes (Series)]]></category><dc:creator><![CDATA[Matt Farmer]]></dc:creator><pubDate>Fri, 01 Feb 2019 03:42:15 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1511804472014-fa7b871cd6a9?ixlib=rb-1.2.1&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1511804472014-fa7b871cd6a9?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&ixid=eyJhcHBfaWQiOjExNzczfQ" alt="On DigitalOcean Kubernetes, Part 1"><p> Until recently I was running my blog on Linode using Docker Swarm. This week I migrated over to Kubernetes on DigitalOcean.</p><p>After doing a comparison between running Kubernetes and Swarm a few years back, I decided in favor of the latter. Swarm is incredibly lightweight and, at the time, it was different enough from what I was doing day to day to be interesting. Further, I'm cheap. I could effectively run my blog, its database, and a few other apps on a $5/mo Linode instance. There weren't good options, besides GKE, for managed Kubernetes at the time, either. I didn't want to manage a Kube control plane.</p><p>Fast forward a few years: we're in a very different situation. When DigitalOcean announced their <a href="https://www.digitalocean.com/products/kubernetes/">Kubernetes offering</a>, I decided to take it out for a spin. I decided that, even though it's more expensive, there's more learning value in running my blog on Kube than there is in running it on Docker Swarm. Let's be honest, I'm not writing this blog because I expect to get famous. Running this site is <em>all </em>about learning value for me. This is part one of what I've learned so far.</p><h2 id="pricing-your-expectations">Pricing Your Expectations</h2><p>I don't use Amazon Web Services or Google Cloud for my personal projects. The utility pricing those providers have is great for micro-usage or companies that have the budget to write big checks. I, however, am always going to strongly favor predictability. Even though I am probably spending more on DigitalOcean than I would at Amazon or Google, it would take <strong>a lot</strong> to cause that dollar amount to increase.</p><p>I never expect to end up on the front page of <a href="https://news.ycombinator.com">Hacker News</a>, but it's nice to know that if I do I don't have to be too concerned with what the impact on my wallet is going to be.</p><p>When configuring a Kubernetes cluster on DigitalOcean you configure what are called Node pools.</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://fdn-assets.sfo2.cdn.digitaloceanspaces.com/2019/01/Screen-Shot-2019-01-30-at-9.22.58-AM.png" class="kg-image" alt="On DigitalOcean Kubernetes, Part 1"><figcaption>Node pool selection in DigitalOcean's Cluster creation wizard</figcaption></figure><p>For my personal cluster I opted for the two of the Flexible Nodes. My selection was $15/month for 2vCPU and 2GB of memory for each node.</p><p>In addition to this, you pay a per GB cost for each Volume you create on DigitalOcean. When you deploy a Kubernetes cluster on DigitalOcean, this is all abstracted behind the Kubernetes concept of <code>PersistentVolumeClaim</code>s.</p><p>When you create a new <code>PersistentVolumeClaim</code> in Kubernetes with the class <code>do-block-storage</code> - DigitalOcean will create a Volume on the backend. These volumes ensure that data outlives any individual node if that node gets destroyed. At $0.10 per GB reserved, my usage adds about $1 per month to my bill. (<strong>Note:</strong> You pay for GB reserved, not GB used. So if you reserve 10 GB, that's what you pay for.)</p><p>I also have a <code>LoadBalancer</code> service declared in Kubernetes for Traefik - the service responsible for routing incoming requests to the right backend running in the cluster. On DigitalOcean Kube, this creates a DigitalOcean Load Balancer, which costs $10/month. You could save this cost by using a Floating IP and host ports in Kubernetes, but Floating IPs don't automatically move when a node goes down.</p><p>Finally, I've subscribed to DigitalOcean Spaces for $5/month. I'm using Spaces to host image assets for the blog. Previously, image assets were loaded from the blog's server directly. Unfortunately, there was a performance hit to doing this. Images are many times larger than the text that you transfer from my server. Using Spaces I can offload that work to DigitalOcean and, bonus, I can utilize their Content Delivery Network (CDN) to get the images to load really quickly no matter how far away you are from my actual servers.</p><p>Totaling everything up:</p><ul><li>Compute Nodes — $30/month</li><li>Load Balancer — $10/month</li><li>Volumes — $1/month</li><li>Spaces — $5/month</li></ul><p>Total cost: $46/month.</p><figure class="kg-card kg-image-card"><img src="https://images.unsplash.com/photo-1470645792662-dd18394f8c97?ixlib=rb-1.2.1&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ" class="kg-image" alt="On DigitalOcean Kubernetes, Part 1"><figcaption>Kubernetes Take the Wheel</figcaption></figure><p>That's a pretty sharp increase from the $5/month that I was paying for my Swarm node. But this is all about the learning experience for me.</p><p>I've been learning a lot more from running on Kubernetes than I learned from running on Docker Swarm.</p>]]></content:encoded></item><item><title><![CDATA[Tried to Switch to Fastmail]]></title><description><![CDATA[<p>I made the attempt this weekend to switch to <a href="https://www.fastmail.com">FastMail</a> from Google for my custom domain. It lasted less than an hour. Here's why.</p>
<p>By way of (brief) introduction, FastMail is a direct competitor to Google GSuite. It is great for folks who are privacy concious. Their plans are affordable,</p>]]></description><link>https://farmdawgnation.com/the-bonds-of-big-google/</link><guid isPermaLink="false">5c468fd705ce900013ec758f</guid><category><![CDATA[Personal]]></category><dc:creator><![CDATA[Matt Farmer]]></dc:creator><pubDate>Sun, 06 May 2018 20:10:39 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1473797874090-4f768ae28470?ixlib=rb-0.3.5&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ&amp;s=b0dc8b5369f1346c3b31442b83eaff34" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1473797874090-4f768ae28470?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&ixid=eyJhcHBfaWQiOjExNzczfQ&s=b0dc8b5369f1346c3b31442b83eaff34" alt="Tried to Switch to Fastmail"><p>I made the attempt this weekend to switch to <a href="https://www.fastmail.com">FastMail</a> from Google for my custom domain. It lasted less than an hour. Here's why.</p>
<p>By way of (brief) introduction, FastMail is a direct competitor to Google GSuite. It is great for folks who are privacy concious. Their plans are affordable, and their UI is slick. Included is an importer tool that will allow you to move all of your email from any IMAP-capable account (which includes Google) into your new FastMail account.</p>
<p>I came <em>incredibly</em> close to making the migration. I had MX records on my primary domain switched over, did some initial tests, and was beginning to switch over some of my secondary domains before I was stopped by an incoming email. This was an email that I wanted to save for later, but alas: I could not. Unlike Google Inbox and the &quot;new&quot; Gmail, I cannot snooze emails in FastMail and have them reappear in my inbox later on. My only options were to leave the email in my inbox or to send it to the archive. This single feature was my dealbreaker.</p>
<p>A few months back I attempted to switch away from Google's interface and toward a desktop email client. I tried to use Airmail and Apple Mail. I realized pretty quickly that snoozing emails and having them reliably reappear in my inbox was an essential workflow for me. Without this work flow a lot of things get missed when I inevitably declare inbox bankrupcy. Both Apple Mail and Airmail offer or can be extended to offer that feature, but they didn't work effectively unless the application was actively running on my machine. Given the frequency with which I would snooze something on my computer and need to see it on my phone later on, I couldn't tolerate that limitation.</p>
<p>Therefore, for the moment, I'm locked into the Google life. However, the limited time I spent tinkering with FastMail looked interesting. There are other apps that provide the functionality I'm looking for (e.g. <a href="https://newtonhq.com">Newton</a>), but the idea of a service that proxies my email through their servers makes me a bit leery... it doesn't feel like that should be required to get the effect I'm looking for. Also, if I have to go through their servers to get an experience that makes sense, have I really gained much by not being in the Google ecosystem? (Especially given I'll be paying an annual fee for the pleasure?)</p>
]]></content:encoded></item><item><title><![CDATA[Snipper: Better YAML Templating]]></title><description><![CDATA[<p>I got an itch a few days ago to try out an idea. This was, in part, motivated by a few conversations about <a href="https://helm.sh">Helm templates</a> for Kubernetes. Helm Charts rely on weaving templating into your Kubernetes object definitions. The templating that Helm uses hails from the same tradition as ERB</p>]]></description><link>https://farmdawgnation.com/introducing-snipper/</link><guid isPermaLink="false">5c468fd705ce900013ec758e</guid><category><![CDATA[Personal]]></category><dc:creator><![CDATA[Matt Farmer]]></dc:creator><pubDate>Sun, 15 Apr 2018 02:31:45 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1520083554676-53cce5922b07?ixlib=rb-0.3.5&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ&amp;s=54822779ec71fc6fbfee9eb55250a6fa" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1520083554676-53cce5922b07?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&ixid=eyJhcHBfaWQiOjExNzczfQ&s=54822779ec71fc6fbfee9eb55250a6fa" alt="Snipper: Better YAML Templating"><p>I got an itch a few days ago to try out an idea. This was, in part, motivated by a few conversations about <a href="https://helm.sh">Helm templates</a> for Kubernetes. Helm Charts rely on weaving templating into your Kubernetes object definitions. The templating that Helm uses hails from the same tradition as ERB templates, mixed PHP/HTML pages, etc.</p>
<p>I started thinking on what it would be like if I could template Kubernetes definitions using something resembling <a href="https://liftweb.net">Lift</a> snippets - where the template and the instructions that lead to the final result are totally separated. And, since I'm working on getting a bit more familiar with Go - I decided to build it using Go. What I ended up with is <strong>Snipper</strong>.</p>
<h2 id="gettingsnipper">Getting Snipper</h2>
<p>I'll start by saying that Snipper is very much a <strong>proof of concept.</strong></p>
<p>Snipper is available on <a href="https://github.com/farmdawgnation/snipper">GitHub</a>. Pre-built binaries are available on the releases page, or you can get it using <code>go install</code> if you have a Go development environment set up.</p>
<p>Once it's installed you can use it by providing a template YAML file - which is just a regular old YAML file. You can then invoke snipper with the template and any number of transformers like so:</p>
<pre><code>$ snipper template.yaml transformer1.yaml transformer2.yaml...
</code></pre>
<p>The resulting YAML will get sent to standard out.</p>
<h2 id="example">Example</h2>
<p>Let's say that I've got this Pod definition pulled mercilessly from the Kubernetes documentation.</p>
<pre><code>apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
  labels:
    app: myapp
spec:
  containers:
  - name: myapp-container
    image: busybox
    command:
    - 'sh'
    - '-c'
    - 'echo The app is running! &amp;&amp; sleep 3600'
</code></pre>
<p>I can use snipper to modify this pod to my heart's content. Let's say that I would like to add a <code>team</code> label to the container. I might define this in the transformer YAML file like so:</p>
<pre><code>'metadata:labels:team': Farmdawg Nation
</code></pre>
<p>Transformer YAML files follow some special conventions. Specifically:</p>
<ul>
<li>The top-level keys are all in &quot;selector format&quot;
<ul>
<li><code>:</code> separates selectors. <code>metadata</code> selects the metadata node at the root. <code>metadata:labels</code> selects the labels under <code>metadata</code>, but would not select the labels under <code>spec</code> if there were one.</li>
<li>Ending a sector with <code>+</code> causes snipper to append a value to a string or a list instead of replacing the value</li>
<li>Using <code>[]</code> as a selector selects all array members at the level you're selecting at. <code>spec:containers:[]:command:[]</code> would select all components of the command array for all of the containers above.</li>
</ul>
</li>
<li>Selectors are only parsed at the top level of keys. Anything nested inside the selectors are assumed to be values that you would like to drop into your template.</li>
</ul>
<p>These rules are still heavily in flux. They will likely change, but let's take a few more examples of things we can do.</p>
<p>We could suffix the pod name with the number 2:</p>
<pre><code>'metadata:name+': 2
</code></pre>
<p>We could change the image to <code>alpine</code>:</p>
<pre><code>'spec:containers:[]:image`: alpine
</code></pre>
<p>We could add an additional container:</p>
<pre><code>'spec:containers+':
- name: myapp-hello
  image: hello-world
</code></pre>
<p>And of course, a single transformer file can have multiple rules:</p>
<pre><code>'metadata:labels:team': Farmdawg Nation
'metadata:labels:alerting': enabled
'spec:containers+':
- name: myapp-hello
  image: hello-world
</code></pre>
<p>All of these instructions remain separate from the actual template itself. You no longer have to litter a single file with the template <em>and</em> what needs to happen to it. With Snipper, these concepts are separate.</p>
<h3 id="butwhataboutlogic">But what about logic?</h3>
<p>You'll notice that there aren't any logic constructs. That's actually an intentional decision. Snipper by itself isn't a total replacement for a templating engine. However, when combined with an orchestration layer that conditionally applies transforms, you wouldn't be far off. I have not (yet) written such an orchestration layer, but I could imagine a tool that defines, say, a:</p>
<ul>
<li>pod_template.yaml</li>
<li>local.yaml (transforms for local deployment)</li>
<li>staging.yaml (transforms for staging cluster deployment)</li>
<li>prod.yaml (transforms for production cluster deployment)</li>
</ul>
<h2 id="whatsnext">What's next?</h2>
<p>I'm not sure. Part of this was scratching an itch. Part of it was wanting to develop some better informed opinions about Go. What I do next with this project will depend heavily on whether or not folks find it useful / interesting. So, if <strong>you</strong> find it useful / interesting please <a href="https://github.com/farmdawgnation/snipper">star it on GitHub</a>, file bugs and feature requests, or share with your friends.</p>
]]></content:encoded></item><item><title><![CDATA[On Net Neutrality]]></title><description><![CDATA[<p>In December of 2010 I wrote a piece titled &quot;<a href="https://farmdawgnation.com/2010/12/21/what-net-neutrality-means-for-you/">What Net Neutrality Means For You</a>&quot; shortly after the FCC took its initial action on Net Neutrality. In light of the recent FCC ruling to scrap the subsequent 2015 rule that permitted the FCC to enforce Net Neutrality principles,</p>]]></description><link>https://farmdawgnation.com/on-net-neutrality/</link><guid isPermaLink="false">5c468fd705ce900013ec758c</guid><category><![CDATA[net-neutrality]]></category><dc:creator><![CDATA[Matt Farmer]]></dc:creator><pubDate>Sun, 17 Dec 2017 03:58:57 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1451187580459-43490279c0fa?ixlib=rb-0.3.5&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;s=90369b1af3c31e8d54930b1eab8adc35" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1451187580459-43490279c0fa?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&s=90369b1af3c31e8d54930b1eab8adc35" alt="On Net Neutrality"><p>In December of 2010 I wrote a piece titled &quot;<a href="https://farmdawgnation.com/2010/12/21/what-net-neutrality-means-for-you/">What Net Neutrality Means For You</a>&quot; shortly after the FCC took its initial action on Net Neutrality. In light of the recent FCC ruling to scrap the subsequent 2015 rule that permitted the FCC to enforce Net Neutrality principles, I thought it would be fitting to revisit that topic with some thoughts from this past week.</p>
<h2 id="aboutdiscouraginginvestment">About discouraging investment</h2>
<p>On Thursday the FCC voted to roll back the rules that were enacted under the Obama Administration. The Associated Press summarizes what the expected impact will be in the short and long term <a href="https://www.nytimes.com/aponline/2017/12/15/us/ap-us-net-neutrality.html?_r=0">in this article</a>. Additionally, the AP outlines the central objection of the telecommunications companies:</p>
<blockquote>
<p>The big telecommunications companies had lobbied hard to overturn the rules, contending they are heavy-handed and discourage investment in broadband networks.</p>
</blockquote>
<p>Wired <a href="https://www.wired.com/story/the-fcc-says-net-neutrality-cripples-investment-thats-not-true/">poked some holes</a> in this argument. The study cited in the FCC proposal to roll back the rules was industry funded, and asserted that there's a correlation of decreased spending after the rules were enacted. Setting aside the <a href="https://en.wikipedia.org/wiki/Post_hoc_ergo_propter_hoc">post hoc ergo propter hoc</a> nature of that argument, Wired illustrated that the reality is a mixed bag at best. For example:</p>
<ul>
<li>Comcast made statements to their shareholders that the Title II classification was not negatively impacting their business, but they did have to delay a streaming service (sounds like that rubbed them the wrong way)</li>
<li>AT&amp;T has been working to lean on software for improved performance, decreasing their hardware investment accordingly</li>
<li>Sprint has been cutting spending since before the rules were passed, but the then-CTO admitted that the Title II classification wouldn't impact them</li>
<li>Charter has consistently been increasing spending since 2014 to increase speed</li>
</ul>
<p>... and the list goes on.</p>
<p>From my vantage point I've actually seen a surprising amount of investment in infrastructure in the Atlanta area. Comcast and AT&amp;T have both launched residential gigabit services within months of Google Fiber announcing their intent to move in. Comcast has also increased data caps for residential customers over the last year or two without me noticing.</p>
<p>It sure doesn't feel like investment has been hindered since 2015.</p>
<h2 id="aboutthatlighttouchapproach">About that light-touch approach</h2>
<p>Ajit Pai, the FCC chairman, seems quite proud of his work. From the AP article linked above:</p>
<blockquote>
<p>&quot;What is the FCC doing today?&quot; asked FCC chairman Ajit Pai, a Republican. &quot;Quite simply, we are restoring the light-touch framework that has governed the internet for most of its existence.&quot;</p>
</blockquote>
<p>Let's briefly discuss some other things that have been true for most of the internet's existence.</p>
<p>Pai conveniently neglects to mention here that for most of the internet's existence there has been a strong delineation between <em>content providers</em> and <em>internet service providers</em>. He also doesn't mention that for most of the internet's existence it's been mostly irrelevant in Presidential elections. He doesn't mention that for most of the internet's existence citizens have not used it to access social or government services, educate themselves, or exercise their First Amendment rights.</p>
<p>Did you know that in 2014 the country of Estonia launched an <a href="https://en.wikipedia.org/wiki/E-residency_of_Estonia">E-Residency program</a>? While primarily designed for businesses who wish to have an EU presence, the program in Estonia is certainly a forbearer of what is to come as governments look for ways to become more accessible and efficient.</p>
<p>The internet has become very much like the streets through which we travel to do the important business of life. All signs indicate that it will become even more so in the years to come. This has not been true for most of the internet's existence. As that happens, having good rules for how the companies that own the pavement can behave is ultimately required for a successful society to continue to build on top of it.</p>
<p>Chairman Pai is either laughably ignorant that the reality around him has changed, or he's willingly ignoring it for political convenience. Either option should disqualify him from having a voice in the matter.</p>
<h2 id="thiswaybedragons">This way be dragons</h2>
<p>Now, as in 2010, there are very good reasons for the FCC, or some other entity, to monitor and referee how privately-held monopolies riddled with conflicts of interest steward the foundation of our digital society.</p>
<p>Though internet providers have claimed they are not interested in blocking the services we value, the AP rightly notes:</p>
<blockquote>
<p>But such things have happened before. The Associated Press in 2007 found Comcast was blocking some file-sharing services. AT&amp;T blocked Skype and other internet calling services — which competed with its voice-call business — from the iPhone until 2009.</p>
</blockquote>
<p>The astute reader would rightly observe that there's a razor thin difference between censoring a competing service and censoring a competing opinion.</p>
<h2 id="apathforward">A path forward</h2>
<p>There are proven strategies for managing the ever-increasing network demand that an ever-increasing population with an ever-increasing variety of content will produce. There are proven strategies for dealing with monopolies that misbehave. There are proven strategies for dealing with conflicts of interest.</p>
<p>We need only use them.</p>
]]></content:encoded></item><item><title><![CDATA[The Conscience of the Ethical Engineer]]></title><description><![CDATA[<p>It's being widely reported this weekend that a former engineer involved in the Volkswagen diesel scandal, James Liang, has been sentenced to a 40-month prison term. I've seen a bit of shock and outrage on Twitter over this, including a quickness to conclude that Liang was sent to prison for</p>]]></description><link>https://farmdawgnation.com/the-conscience-of-the-ethical-engineer/</link><guid isPermaLink="false">5c468fd705ce900013ec758a</guid><category><![CDATA[Culture]]></category><dc:creator><![CDATA[Matt Farmer]]></dc:creator><pubDate>Mon, 28 Aug 2017 03:27:06 GMT</pubDate><media:content url="https://fdn-assets.sfo2.cdn.digitaloceanspaces.com/2017/08/auto-vw-vw-bus-vehicle-163711.jpeg" medium="image"/><content:encoded><![CDATA[<img src="https://fdn-assets.sfo2.cdn.digitaloceanspaces.com/2017/08/auto-vw-vw-bus-vehicle-163711.jpeg" alt="The Conscience of the Ethical Engineer"><p>It's being widely reported this weekend that a former engineer involved in the Volkswagen diesel scandal, James Liang, has been sentenced to a 40-month prison term. I've seen a bit of shock and outrage on Twitter over this, including a quickness to conclude that Liang was sent to prison for just doing something his boss told him to do. It seemed to me that there are some out there that have bought into the school of thought that if you're ordered to do something, your butt should be totally covered. As a software engineer, this is a belief I would like to speak against and dispel for the good of myself and my craft.</p>
<h2 id="background">Background</h2>
<p>If you've been living under a rock, or just aren't quite sure what the emissions scandal was about, this summary from the Car and Driver Blog<sup><a href="#fn1">1</a></sup> does a good job of summarizing what happened:</p>
<blockquote>
<p>Volkswagen installed emissions software on more than a half-million diesel cars in the U.S.—and roughly 10.5 million more worldwide—that allows them to sense the unique parameters of an emissions drive cycle set by the Environmental Protection Agency. [...] [T]hese so-called “defeat devices” detect steering, throttle, and other inputs used in the test to switch between two distinct operating modes.</p>
</blockquote>
<blockquote>
<p>In the test mode, the cars are fully compliant with all federal emissions levels. But when driving normally, the computer switches to a separate mode—significantly changing the fuel pressure, injection timing, exhaust-gas recirculation, and, in models with AdBlue, the amount of urea fluid sprayed into the exhaust. While this mode likely delivers higher mileage and power, it also permits heavier nitrogen-oxide emissions (NOx)—a smog-forming pollutant linked to lung cancer—up to 40 times higher than the federal limit.</p>
</blockquote>
<p>To elaborate slightly: This means there was a group of people at Volkswagen that installed software specifically designed to lie to the test devices. The result of this lie is that there were (and probably still are) cars on the road that emit an excess of a chemical linked to lung cancer.</p>
<p>The one qualm that I have with Car and Driver's depiction is their use of the word &quot;installed.&quot; Please excuse me if I'm giving the average reader of my blog too little credit, but I want to make it clear to everyone that installing this kind of software isn't anywhere near the same thing as installing Microsoft Office on your PC. You'd be hard pressed to find pre-written emissions defeat software anywhere online, much less software that just happens to work with the new car engine you're designing.</p>
<p>I actually searched for &quot;emissions defeat software&quot; while writing this blog post. The results are best summarized by this screen shot from GitHub's project search screen:</p>
<p><img src="https://static.farmdawgnation.com/blog_assets/2017/08/26/emissions-github-search.png" alt="The Conscience of the Ethical Engineer"></p>
<p>Why does this matter?</p>
<p>To install this software in their cars, it means that Volkswagen had to <em>design</em> the software first. Liang's own admissions<sup><a href="#fn2">2</a></sup> corroborate this (empahsis mine):</p>
<blockquote>
<p>According to Liang’s admissions, when he and his co-conspirators realized that they could not design a diesel engine that would meet the stricter U.S. emissions standards, they <strong>designed and implemented</strong> software to recognize whether a vehicle was undergoing standard U.S. emissions testing on a dynamometer or being driven on the road under normal driving conditions (the defeat device), in order to cheat the emissions tests.</p>
</blockquote>
<p>The design element of this scandal is the element I find most troubling. It means that there was an ongoing, intentional, directed effort to subvert U.S. law by the leadership and engineering teams at VW. There were likely planning meetings, task tracking of some sort,<sup><a href="#fn3">3</a></sup> deadlines, and concrete deliverables that these teams agreed on in advance. Throughout this process, there was no voice that prevailed that said &quot;Hey, perhaps this isn't okay.&quot;</p>
<h2 id="justanengineer">Just an &quot;Engineer&quot;</h2>
<p>The piece that I've seen circulating the most is a piece from Reuters that characterizes Mr. Liang as a &quot;former engineer.&quot;<sup><a href="#fn4">4</a></sup> The reaction I saw is nicely summarized by the Tweet below:</p>
<blockquote class="twitter-tweet" data-lang="en"><p lang="en" dir="ltr">Every. Single. Software developer. Must. Take. Note.<br><br>YOU can go to jail for the code YOUR BOSS tells you to write. <a href="https://t.co/3MZGHqI4dy">https://t.co/3MZGHqI4dy</a></p>&mdash; Ted Neward (@tedneward) <a href="https://twitter.com/tedneward/status/901135785969074177">August 25, 2017</a></blockquote> <script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
<p>I saw a few retweets and other takes that had about the same flavor to them. This will be news to nobody, but &quot;Oh man, that could be me&quot; is a visceral fear that's hard to combat. If I had to guess, I'd say this fear is motivating many of the reactions I've personally seen.</p>
<p>However, based on my reading of the Reuters article, the relevant Justice Department press release, and some well-educated guesses informed by my professional experience, I think the tweet above is largely a false equivalence. It paints the picture that Liang was convicted for <em>just</em> writing some code.</p>
<p>It's unlikely that every single software engineer at Volkswagen had the level of involvement it seems Liang exercised over Volkswagen's diesel (non-)compliance. Indeed, the Justice Department release from 2016<sup><a href="#fn2">2</a></sup> states: &quot;Liang admitted that during some of these meetings [with regulators], which he personally attended, his co-conspirators misrepresented that VW diesel vehicles complied with U.S. emissions standards and hid the existence of the defeat device from U.S. regulators.&quot; Liang here is <strong>directly complicit</strong> in misleading U.S. regulators. At the risk of over-generalizing my own experience, I'll state that folks who are front-line engineers are rarely in the room with regulators.</p>
<p>Yet, I want to set aside that false equivalence and discuss something more important. Even if Liang himself is not a member of the population Ted Neward's tweet above appeals to, the front-line software engineers, do we really believe they should be totally free from responsibility in this scandal?</p>
<h2 id="theethicsofengineering">The Ethics of Engineering</h2>
<p>I, like many of my contemporaries, strongly prefer the job title of &quot;Software Engineer&quot; to describe myself over the practically interchangeable term &quot;Software Developer.&quot; I don't see my job as developing software. My job is to solve problems, and I will most often use or develop software to do so.<sup><a href="#fn5">5</a></sup></p>
<p>I cannot know what happened in the back rooms at VW. Perhaps ethical concerns were raised. Perhaps jobs were threated by management. Perhaps every front-line engineer involved had defendable reasons why they couldn't resign their position on ethical grounds and ultimately helped create the deception that lead to the sentencing of Mr. Liang and others.</p>
<p>I would not fault someone for doing the wrong thing for the right reasons. I likewise do not think that the front-line software engineers at VW should be held legally responsible in this specific case. In spite of that, however, I doubt the ethical intelligence of anyone who would suggest, without further exonerating evidence, that those individuals bear no moral responsibility for the deception and health risk they helped create.</p>
<p>In our roles as problem solvers, whether or not someone is paying us for the work we're doing, we are ultimately responsible for whether or not our solution to the problem at hand will make the world a better place. This conviction is what drives the conscience of the ethical engineer - software or otherwise - and it plays out in our decisions big and small.</p>
<p>This conviction is simultaniously burdensome and empowering.</p>
<p>It is burdensome when we're at odds with whatever organization we're currently employed by and we're asked to do things that go against our ethical code. It is burdensome when we're told doing the right thing is too expensive and we should just do the cheap thing and be happy. It is burdensome when our peers or bosses reply, &quot;But everyone else is doing X, so you should just get over your objections and implement X!&quot; Or, worse still, when those in power threaten to fire us if we do not captiulate.</p>
<p>Yet even in burdensome organizations, this conscience is empowering when it motivates us to do even the smallest things to make the world better. It empowers us to speak up in the meeting and say, &quot;I disagree with this.&quot; It empowers us to work to ensure that the new app we're building is accessible to someone using a screen reader. It empowers us to help customer support execute more informed, coordinated responses when things go wrong. It empowers us to go to the extra effort of making our code easier to understand for the next engineer who comes along. It empowers us to work to protect end-user user information of our own accord instead of waiting for a security event to force our hand.</p>
<p>We all have the choice of whether or not to live in line with this conscience as we go about our problem solving. I have good days and bad when it comes to listening to my own convictions about the right thing to do. Even still, the truth is that we're uniquely empowered to make the world a better place every day, by a thousand paper cuts if we're so forced. On those occasions when we're lucky to work with an organization that backs ethical efforts, the possibilities for improving the world we're in are <em>endless</em>.</p>
<p>But this is not the work of those happy to punch a clock and write off ownership of what they've done. We have to first take up our mantle of responsibility as engineers, or else we will squander our unique, individual opportunity to make the world better by ethically doing what we do well.</p>
<h4 id="footnotes">Footnotes</h4>
<ol>
<li><a name="fn1"></a>You can find that blog post here <a href="http://blog.caranddriver.com/everything-you-need-to-know-about-the-vw-diesel-emissions-scandal/">here</a>.</li>
<li><a name="fn2"></a><a href="https://www.justice.gov/opa/pr/volkswagen-engineer-pleads-guilty-his-role-conspiracy-cheat-us-emissions-tests">Justice Department Press Release, 9/2016</a></li>
<li><a name="fn3"></a>I find myself idly wondering if they were using JIRA, though I kind of doubt it. It would just be really amusing to me if they were because it seems like everyone uses JIRA. I also find myself idly wondering if the people who could reason their way to committing fraud like this may understand JIRA better than I do. Really, I just find myself confused at JIRA a lot these days and I wanted to vent about that a little.</li>
<li><a name="fn4"></a>Reuters article <a href="https://www.reuters.com/article/us-volkswagen-emissions-sentencing-idUSKCN1B51YP">here</a></li>
<li><a name="fn5"></a>When I'm really lucky I'll solve problems by deleting software. Those are good days.</li>
</ol>
]]></content:encoded></item><item><title><![CDATA[Just Be Nice]]></title><description><![CDATA[<p>I've been giving a lot of thought to online communities as of late. I've been a bit discouraged at some behavior I've seen in the Scala ecosystem recently. Enough so that I felt the need to subtweet about it.</p>
<blockquote class="twitter-tweet" data-lang="en"><p lang="en" dir="ltr">I’m always really disappointed when really prominent folks in the</p></blockquote>]]></description><link>https://farmdawgnation.com/just-be-nice/</link><guid isPermaLink="false">5c468fd705ce900013ec7589</guid><category><![CDATA[Culture]]></category><dc:creator><![CDATA[Matt Farmer]]></dc:creator><pubDate>Sat, 22 Jul 2017 14:00:00 GMT</pubDate><media:content url="https://fdn-assets.sfo2.cdn.digitaloceanspaces.com/2017/07/people-coffee-tea-meeting.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://fdn-assets.sfo2.cdn.digitaloceanspaces.com/2017/07/people-coffee-tea-meeting.jpg" alt="Just Be Nice"><p>I've been giving a lot of thought to online communities as of late. I've been a bit discouraged at some behavior I've seen in the Scala ecosystem recently. Enough so that I felt the need to subtweet about it.</p>
<blockquote class="twitter-tweet" data-lang="en"><p lang="en" dir="ltr">I’m always really disappointed when really prominent folks in the Scala community are mean to people.</p>&mdash; Matt Farmer (@farmdawgnation) <a href="https://twitter.com/farmdawgnation/status/880507279174504448">June 29, 2017</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
<p>I <em>truly</em> believe that open source software is an essential, important piece of maintaining innovation velocity in the technology industry. I've advocated heavily for this idea everywhere I've worked, and even <a href="http://www.elemica.com/technology/open-source-at-elemica/">written about it for prior employers</a> on occasion. I volunteer my time to help maintain open source software that I've benefited from in the past. And yet, as much as I love and support open source development, I have to admit that the biggest risk to the continued health of the open source ecosystem is the behavior of the people involved in open source development.</p>
<p>Nothing that I witnessed on these most recent occasions was particularly egregious, but after reflecting on my frustrations for a few weeks I wanted to share some thoughts for constructive community interactions within technical communities. The individuals who triggered these thoughts will probably never read them, and probably wouldn't care if they did. But perhaps someone else will find them useful. If nothing else, writing them down should be cathartic.</p>
<p>Without further ado:</p>
<ol>
<li><strong>Assume you're not the smartest person in the room.</strong> Odds are, you probably aren't.</li>
<li><strong>Assume the other person means well and has put thought into their point of view.</strong> Being belittling, especially when people are volunteering their free time to participate, ultimately discourages people from participating in your community or using your software. Over time this kills open source projects.</li>
<li><strong>Disagreement isn't the end of the world.</strong> Agreeing to disagree is totally fine. Your open source contributions aren't life or death. Don't be overly dramatic when something happens that you disagree with, because it'll probably be fine. This, too, kills projects over time.</li>
<li><strong>Be patient with new community members.</strong> New community members that don't understand what is going on are a good sign. It means your project is gaining visibility and getting new blood.</li>
<li><strong>Decide what's accepted behavior and what's not, and enforce that norm.</strong> GitHub has rightly started allowing maintainers to <a href="https://help.github.com/articles/adding-a-code-of-conduct-to-your-project/">add codes of conduct</a> to their projects. Create one. And enforce it. Lift has been doing this for a while (though we haven't yet taken advantage of the new GitHub feature). I plan to do the same for my other major projects.</li>
</ol>
<p>TL;DR: Just be nice, and encourage other participants in your community to do the same. At the end of the day you can have the most well thought out, perfect software out there. Yet it won't matter if nobody uses it because they don't want to deal with you.</p>
<p>End of song.</p>
]]></content:encoded></item><item><title><![CDATA[Karma No More]]></title><description><![CDATA[<p>As I write this I'm burning off the last of the data I purchased from <a href="https://yourkarma.com/wifi/">Karma</a> earlier this year. For <a href="https://blog.karmawifi.com/karma-refuel-grandfather-program-faq-46de32b5b1ba">reasons that are understandable</a> they've decided to discontinue their Refuel plan and, instead, favor plans that charge a monthly fee or a monthly fee <em>plus</em> the cost of data used.</p>]]></description><link>https://farmdawgnation.com/karma-no-more/</link><guid isPermaLink="false">5c468fd705ce900013ec7588</guid><category><![CDATA[Personal]]></category><dc:creator><![CDATA[Matt Farmer]]></dc:creator><pubDate>Sun, 02 Jul 2017 16:45:00 GMT</pubDate><media:content url="https://fdn-assets.sfo2.cdn.digitaloceanspaces.com/2017/07/Karma_Wi-fi_Hotspot_-15021293548---1-.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://fdn-assets.sfo2.cdn.digitaloceanspaces.com/2017/07/Karma_Wi-fi_Hotspot_-15021293548---1-.jpg" alt="Karma No More"><p>As I write this I'm burning off the last of the data I purchased from <a href="https://yourkarma.com/wifi/">Karma</a> earlier this year. For <a href="https://blog.karmawifi.com/karma-refuel-grandfather-program-faq-46de32b5b1ba">reasons that are understandable</a> they've decided to discontinue their Refuel plan and, instead, favor plans that charge a monthly fee or a monthly fee <em>plus</em> the cost of data used.</p>
<p>While I understand that Karma needs to stop paying for customers that are never using their devices, it still seems like the underlying problem with their data arrangement is the &quot;Never Expires&quot; bit. I'm  confused as to why the answer to this problem <em>wasn't</em> to change the &quot;Never Expires&quot; policy and leave the rest of the structure in place.</p>
<p>Perhaps I am a strange customer, but I would be willing to pay for data that expires in a certain amount of time than to accept a $3 monthly fee plus automatically incurring $10 per GB as I use data. The fact that the total cost of my data expenditure was known <strong>up front</strong> without billing me monthly was <strong>the</strong> killer feature of the Karma platform for me.</p>
<p>Under the current offerings there isn't much that distinguishes Karma from the data service I can get through a cell provider. Furthermore, the resurgence of &quot;Unlimited&quot; data plans on many of the major cell networks and new offerings like Verizon's <a href="https://www.verizonwireless.com/plans/hotspots/">Pop Data</a> make a Karma subscription even harder to justify. If I were to use Pop Data, I can work for an entire day on my LTE connection for $24, likely have better coverage, and still have my standard LTE data pool to fall back on afterward. If I were to use Karma's Drift program, I could easily end up using 3GB (or more) over the course of the day (Docker images can be large) and spend $30+ <em>after</em> the monthly subscription fee.</p>
<p>I wish Karma well, but I'm not sure they've made the right move here. As a small company in the ocean with big fish like Verizon, Sprint, AT&amp;T, and T-Mobile, you've got to distinguish yourself to win out.  Karma's old pricing structure put the service in a class of its own while the new structure just seems like a small spin on the same thing every other company in the space is doing. Furthermore, no matter what plans Karma offers, they're never really going to replace any of the cell providers. I'll still need to buy data from them for my phone. Karma is always an extra on top of my cell plan whereas if I need to only use a few hundred MB to do a quick errand I can easily slot that into my existing data allowance with tethering.</p>
<p>Perhaps they'll still manage to find a productive, profitable niche with these new plan structures. However, based on what I know today that niche won't include me.</p>
<p><em>Image above is used under the terms of CC Attribution 2.0 Generic. Source is <a href="https://commons.wikimedia.org/wiki/File:Karma_Wi-fi_Hotspot_(15021293548).jpg">here</a>.</em></p>
]]></content:encoded></item><item><title><![CDATA[New JSON Array Extraction for Lift]]></title><description><![CDATA[<p>JSON is everywhere. That means that properly supporting all of JSON's flexibility is an important priority for any web framework in 2017. For a typed language, like Scala, this type of problem can get interesting because JSON can do a few things that aren't quite as intuitive to do in</p>]]></description><link>https://farmdawgnation.com/tuple-array-extraction-for-lift/</link><guid isPermaLink="false">5c468fd705ce900013ec7587</guid><category><![CDATA[Development]]></category><category><![CDATA[lift]]></category><dc:creator><![CDATA[Matt Farmer]]></dc:creator><pubDate>Wed, 03 May 2017 02:14:54 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1524686788093-aa1f9c0f7c4f?ixlib=rb-0.3.5&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ&amp;s=034a1404b22cae9dbee680655bcc3432" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1524686788093-aa1f9c0f7c4f?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&ixid=eyJhcHBfaWQiOjExNzczfQ&s=034a1404b22cae9dbee680655bcc3432" alt="New JSON Array Extraction for Lift"><p>JSON is everywhere. That means that properly supporting all of JSON's flexibility is an important priority for any web framework in 2017. For a typed language, like Scala, this type of problem can get interesting because JSON can do a few things that aren't quite as intuitive to do in an actual Scala application. One of those is supporting collections with many diverse types.</p>
<p>In JSON, like many other data formats, you can have arrays that help store collections of information. Such as a list of my favorite dishes to eat:</p>
<pre><code>[&quot;spaghetti&quot;, &quot;pizza&quot;, &quot;pb&amp;j&quot;, &quot;pimento cheese sandwich&quot;]
</code></pre>
<p>As you can tell, I make sure that all of the major food groups are covered in my diet. I could also create a tabular data structure and describe a health rating of 0-10 of each of these foods:</p>
<pre><code>[
  [&quot;spaghetti&quot;, 6],
  [&quot;pizza&quot;, 4],
  [&quot;pb&amp;j&quot;, 7],
  [&quot;pimento cheese sandwich&quot;, 8]
]
</code></pre>
<p>This is a totally valid JSON data structure. The inner data structure here is called a <strong>heterogenous array</strong> because the types of the different positions are different. However, it's one that's a bit challenging to represent in Scala without additional libraries. <em>Unless you use a <code>Tuple</code>.</em></p>
<p>The data structure above can easily be modeled in Scala using a <code>Seq[(String, Int)]</code>, but until recently Lift-Json couldn't interpret this data structure without a custom serializer and deserializer defined by the developer.</p>
<p>We recently merged <a href="https://github.com/lift/framework/pull/1768">a pull request</a> that changes that by implementing a feature we're calling <strong>Array Tuple Extraction</strong>. This feature will ship with Lift 3.1.0-M3 and will be disabled by default for backwards-compatibility reasons. This blog post will walk through what has changed, the limitations of our new Tuple extraction, and how to use it.</p>
<h3 id="currenttuplesupport">Current Tuple Support</h3>
<p>Lift-Json has always supported tuples in one form or another, but it has not, until now, supported heterogenous arrays. In Lift 3.1.0-M2 and earlier, a <code>Seq[(String, Int)]</code> would be decomposed and serialized into the following JSON data structure:</p>
<pre><code>[
  {&quot;_1&quot;: &quot;spaghetti&quot;, &quot;_2&quot;: 6},
  {&quot;_1&quot;: &quot;pizza&quot;, &quot;_2&quot;: 4},
  {&quot;_1&quot;: &quot;pb&amp;j&quot;, &quot;_2&quot;: 7},
  {&quot;_1&quot;: &quot;pimento cheese sandwich&quot;, &quot;_2&quot;: 8}
]
</code></pre>
<p>If those <code>_1</code> and <code>_2</code> members in the object look familiar to you, it's because they come from the constructor for the [<code>Tuple2</code>](<a href="http://www.scala-lang.org/api/current/scala/Tuple2.html#">http://www.scala-lang.org/api/current/scala/Tuple2.html#</a><init>(_1:T1,_2:T2):(T1,T2)) class that Scala would use to model this at runtime.</init></p>
<p>One of Lift-Json's strengths is that its method of looking at the declaration of a class when figuring out how to serialize it means it can do a lot of things automatically without intervention. The above data structure will correctly serialize and deserialize through Lift-Json with no extra work from the developer using the library.</p>
<p>Unfortunately, this isn't super semantically correct with regards to how JSON thinks about arrays. Many REST JSON APIs require you to submit a heterogenous array as a part of a payload for certain requests. Until recently, this is a need that Lift-Json users would need to manually craft the AST representation of the data structure or write a custom serializer/deserializer for this data.</p>
<h3 id="arraytupleextraction">Array Tuple Extraction</h3>
<p>The new Array Tuple Extraction functionality allows developers using Lift-Json to correctly represent Heterogenous Arrays as mixed-type <code>Tuple</code>s in Scala without any additional serializer/deserializer work.</p>
<p>As with many changes you might want to make to Lift-Json's extractor, all you need to do is provide a <code>Formats</code> instance as an <code>implicit val</code> that turns the feature on. You can do this, for example, by declaring the following at the top of a class:</p>
<pre><code>val formats = new DefaultFormats {
  override val tuplesAsArrays = true
}
</code></pre>
<p>This will activate the new tuple extractor and decomposer that will represent a <code>Tuple</code> of <code>(Thing1, Thing2)</code> as a JSON array of <code>[Thing1, Thing2]</code>.</p>
<p>There are, however, a few caveats with this functionality:</p>
<ul>
<li><strong>Scala primitives don't yet work reliably.</strong> If you're going to serialize/deserialize Tuples with your application using the array extractor you should ensure you're using Java's boxed types (<code>java.lang.Integer</code>, <code>java.lang.Boolean</code>, etc). This has something to do with the limitations of JVM reflection on Scala primitive types, but we haven't determined the best solution.</li>
<li><strong>Back-compat support is provided, but not two-way.</strong> The array extractor can correctly interpret Tuples that were serialized in the old format, but if you want to write Tuples in that format again, you'll need to change your <code>Formats</code> to disable the feature first.</li>
<li><strong>The implementation is a bit... dodgy.</strong> The Lift-Json extraction code is the code that takes actual, factual Scala datatypes and turns them into an AST for translation into JSON. This is the point at which we start handling Tuples differently. Unfortunately, the extractor is quite old at this point and challenging to reason about. I've started <a href="https://github.com/farmdawgnation/lift-json-extractor-ng">a speculative rewrite of the extractor</a> using Scala runtime reflection, but don't expect to see feature parity with the main extractor for awhile.</li>
</ul>
<h3 id="finalnotes">Final Notes</h3>
<p>My hope is that this feature turns out to be really useful to folks using the Lift Framework and Lift-Json to push JSON over a wire. If you have any questions, find some bugs, or just want to tell us what you think: drop us a line on <a href="https://groups.google.com/forum/#!forum/liftweb">the Lift Mailing List</a>.</p>
]]></content:encoded></item><item><title><![CDATA[Chimpin' Like Whoa]]></title><description><![CDATA[<p>Last week was my first week at <a href="https://mailchimp.com">MailChimp</a>. I want to share a few specific, unorganized thoughts coming out of that week about my experience as a first-week employee of the company.</p>
<ul>
<li>
<p>The on boarding experience at MailChimp was intentionally thought out. This is a big difference from my past</p></li></ul>]]></description><link>https://farmdawgnation.com/chimpin-like-whoa/</link><guid isPermaLink="false">5c468fd705ce900013ec7586</guid><category><![CDATA[Personal]]></category><dc:creator><![CDATA[Matt Farmer]]></dc:creator><pubDate>Mon, 23 Jan 2017 02:50:28 GMT</pubDate><media:content url="https://fdn-assets.sfo2.cdn.digitaloceanspaces.com/2018/05/IMG_2153.JPG" medium="image"/><content:encoded><![CDATA[<img src="https://fdn-assets.sfo2.cdn.digitaloceanspaces.com/2018/05/IMG_2153.JPG" alt="Chimpin' Like Whoa"><p>Last week was my first week at <a href="https://mailchimp.com">MailChimp</a>. I want to share a few specific, unorganized thoughts coming out of that week about my experience as a first-week employee of the company.</p>
<ul>
<li>
<p>The on boarding experience at MailChimp was intentionally thought out. This is a big difference from my past positions where on boarding was more ad-hoc. Historically, I've felt like a burden as a new employee. MailChimp's approach goes a long way toward making me feel valued from Day 1, which is a much better emotional foot to start off on.</p>
</li>
<li>
<p>Humility is one of the core values of the company, and it shows in my interactions with the coworkers I met last week. Throughout the week members of every department sat with the new hires and answered our questions about their share of what we do. They spent time actually getting to know <em>us</em> and asking what departments we were in and what we'd be doing. Furthermore, that includes IT and legal, departments that in my past experiences tended to be a bit more aloof from the rest of the company.</p>
</li>
<li>
<p>Intentional discussion about how we each communicate is a part of the orientation process. MailChimp uses <a href="https://birkman.com/">Birkman</a> assessments to get a sense of how each of the new hires communicates. The company also does regular sessions with teams to help ensure that people are communicating effectively.</p>
</li>
<li>
<p>I didn't have any time in my first week to write code. This isn't a one size fits all thing — MailChimp is larger than most other organizations I've worked with, but after experiencing the intentional learning time and discussion up front, I think I'm going to be less of an advocate for &quot;first pull request on the first day&quot; than I have been in the past. A week long series of sessions certainly wouldn't make sense for a small start up, but in reflecting on my past experiences I think that my first few months at my previous jobs would have been less anxiety filled with some intentional time to listen and learn.</p>
</li>
<li>
<p>This is the first company I've worked for that handles security so well. I won't go into details for Obvious Reasons™ — but the security policies established are sensible for our threat level without being overbearing. IT has also done a great job of making security accessible to the less technical members of the organization. I don't fall into that category, obviously, but I still noticed how smooth the process was and how well written the documentation is. Should both of those fail, the IT folks are also super easy to reach and willing to answer questions.</p>
</li>
<li>
<p>This is the most diverse company I've ever worked for. I'm not qualified to speak on how we got to the point we're at now, but technology companies have a really lousy track record with diversity and I'm really proud to work for one that is taking it seriously. A pastor friend of mine once shared this quote with me: &quot;The best criticism of the bad is the practice of the better.&quot; I can't recall the original author, but it rings true in this situation.</p>
</li>
</ul>
<p>TL;DR: I'm really excited for week two, and that's a fantastic feeling. It's also been about three weeks since I've touched any code in any significant capacity — so I'm starting to get that old itch to fire up my editor again and get into the weeds on something challenging.</p>
]]></content:encoded></item><item><title><![CDATA[A Rant on Technical Debt]]></title><description><![CDATA[<p>I've been thinking a lot about technical debt lately. It's something that every codebase has, but also something that we still fail to fully consider the cost of. As such, I thought it would be appropriate to walk through some of the ways technical debt has affected my life in</p>]]></description><link>https://farmdawgnation.com/a-rant-on-technical-debt/</link><guid isPermaLink="false">5c468fd705ce900013ec7585</guid><category><![CDATA[Development]]></category><dc:creator><![CDATA[Matt Farmer]]></dc:creator><pubDate>Wed, 07 Dec 2016 03:17:01 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1515524738708-327f6b0037a7?ixlib=rb-0.3.5&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ&amp;s=33dc33ce5706917521381c7d810b42c2" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1515524738708-327f6b0037a7?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&ixid=eyJhcHBfaWQiOjExNzczfQ&s=33dc33ce5706917521381c7d810b42c2" alt="A Rant on Technical Debt"><p>I've been thinking a lot about technical debt lately. It's something that every codebase has, but also something that we still fail to fully consider the cost of. As such, I thought it would be appropriate to walk through some of the ways technical debt has affected my life in the last 24 hours.</p>
<h3 id="vmfilesharing">VM File sharing</h3>
<p>This is something that always comes with a lot of promises, but never seems to deliver. And, to boot, when it fails it always fails in really interesting ways.</p>
<p>Today, the file sharing in Parallels failed me. At Domino we recently added LevelDB as a dependency. I've been largely working on another project so it had been a minute since I had compiled the main application and tried to get it working. Things didn't go so well.</p>
<p>It seems that if you attempt to use LevelDB over a Parallels file share you'll get an error that things can't be set up correctly. All of that will boil down to:</p>
<pre><code>IOException: Invalid argument
</code></pre>
<p>Let me count the ways in which this is a frustrating condition to find yourself in:</p>
<ol>
<li>What the hell kind of error message is &quot;Invalid argument.&quot;</li>
<li>What the hell kind of error message is &quot;Invalid argument.&quot;</li>
<li>VMW file systems are typically supposed to be a substitute, and ideally something that performs better than, some network file share like NFS or SMB. In all cases that I tried, <em>except</em> Parallels, they have abysmal performance (but that's probably an entirely different blog post).</li>
<li>What the hell kind of error message is &quot;Invalid argument.&quot;</li>
</ol>
<h3 id="x11xquartzremoting">X11 / XQuartz / Remoting</h3>
<p>After this experience I decided a more conventional Linux experience might serve me better. As a result, today I tried (yet again) to get X11 remoting working. I had tried this on a company issued Lenovo earlier. After failing to use Linux as a primary OS I reverted to using Windows - because my experience with Linux reached a point where that seemed like a more reasonable option. (Perhaps that's <em>a different</em> blog post.)</p>
<p>Anyway, we arrive at today where I attempt to redo the same experience on my Mac box using XQuartz. I got XQuartz installed, I got Atom installed on my VM, and then I ssh'd into the Ubuntu VM from the XQuartz session and started Atom.</p>
<p>Performance was abysmal, but not intolerable. So I decided to give typing in a new document a try.</p>
<pre><code>This is a st ofybord
</code></pre>
<p>Hm. That doesn't seem right. If you're looking at this and you think &quot;Whoa the 'e' key got mapped to backspace&quot; then you're a cleverer person than I, because it took me a little bit to figure out what was going on.</p>
<p>After much Googling, tinkering around inspecting X events, trying to figure out ways to work around this, attempting to connect to the X server without a wrapping session, I then proceeded to give up.</p>
<p>I don't quite know what the underlying cause of the technical debt here is. I don't know if it's in X11, ssh, XQuartz, or something else. It's <em>not</em> something that happens in the xterm terminal, so I'm inclined to think that it's some weird X11 interaction with Atom.</p>
<p>I don't quite know how I would classify this technical debt. However, I feel confident in attributing it <em>as</em> technical debt in spite of my lack of knowledge with X11. (Or maybe perhaps because of what I do know of X11?)</p>
<h3 id="installingkubuntuonparallels">Installing kubuntu on Parallels</h3>
<p>After the above failed, I attempted to install Kubuntu in a Parallels VM and start emulating an entire Linux environment with KDE as my preferred alternative to the mainline Ubuntu Unity.</p>
<p>The installer crashed before it even got started. So, there's that.</p>
<h3 id="conclusion">Conclusion</h3>
<p>My day has the distinct flavor of a lot of shit that should just not be possible. It has the distinct flavor, in my mind, of technical debt.</p>
<p>So, next time you're trying to figure out how to weigh trade offs in your project please imagine that your project will be wildly successful. And then imagine that there's going to be someone like me. Staring at his screen. Asking his software to just please finally work.</p>
]]></content:encoded></item><item><title><![CDATA[The Pluggable Dependency Pattern]]></title><description><![CDATA[<p>I do not love <a href="https://en.wikipedia.org/wiki/Transitive_dependency">transitive dependencies</a>. However, they seem almost unavoidable. Consider <a href="https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol">HTTP</a> libraries. The odds are that if you're writing software in 2016, there's a decent chance you're writing software that will want to talk to some other software on the Internet. Furthermore, there's also a decent chance you'll</p>]]></description><link>https://farmdawgnation.com/the-pluggable-dependency-pattern/</link><guid isPermaLink="false">5c468fd705ce900013ec7584</guid><category><![CDATA[Development]]></category><dc:creator><![CDATA[Matt Farmer]]></dc:creator><pubDate>Thu, 20 Oct 2016 17:10:44 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1517320069935-381614f8c1e5?ixlib=rb-0.3.5&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ&amp;s=1de9b490cd7dc0d05c709f184aad093c" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1517320069935-381614f8c1e5?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&ixid=eyJhcHBfaWQiOjExNzczfQ&s=1de9b490cd7dc0d05c709f184aad093c" alt="The Pluggable Dependency Pattern"><p>I do not love <a href="https://en.wikipedia.org/wiki/Transitive_dependency">transitive dependencies</a>. However, they seem almost unavoidable. Consider <a href="https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol">HTTP</a> libraries. The odds are that if you're writing software in 2016, there's a decent chance you're writing software that will want to talk to some other software on the Internet. Furthermore, there's also a decent chance you'll use HTTP to talk to that other software.</p>
<p>The good news here is that you don't have to keep re-inventing the wheel. You have plenty of reusable libraries to choose from in order to accomplish this communication. Pull them in to your Super Cool Open Source Project™, and your project then can speak HTTP with relatively little effort from you! Being able to re-use code in this manner is one of the major strengths of today's software world. It's also a significant weakness.</p>
<p>I've spent some of my free time lately developing a project I've named <a href="https://github.com/farmdawgnation/giterrific">Giterrific</a>. As a part of that project I've had to wrestle with some of the problems inherent in transitive dependencies and, in the process, have developed a solution I'm calling the <strong>Pluggable Dependency Pattern</strong> that I believe more open source projects should consider adopting. This blog post will outline the issues we ran into attempting to integrate Giterrific into a proof of concept project at Domino, my employer, and how I used this pattern to overcome those issues.</p>
<p>This pattern may not in fact be new to you. I've seen it appear sporadically in other projects. Yet in implementing it myself I learned some useful guidelines for integrating it into my projects, and became convinced this is something other projects should be discussing.</p>
<h2 id="transitivity">Transitivity</h2>
<p>To set up the story that I'm about to tell you, it's helpful to ensure we all start with an understanding of transitive dependencies.</p>
<p>A transitive dependency is a dependency that exists because of transitivity. If you're writing project A, and project A depends on project B. In turn, project B depends on project C. Therefore, C is a transitive dependency of A.</p>
<p>If this sounds fimiliar to transitivity from a Mathematics class, then you're thinking of the right thing. It works the same way!</p>
<h2 id="dumpsterfiresthemotherofinvention">Dumpster Fires, the Mother of Invention</h2>
<p>Giterrific aims to do one thing well: expose information about private Git repositories in a simple, straightforward JSON API. Further, it also aims to make that easy to integrate with your existing code. To that end, I've provided a library named giterrific-client that provides Scala API bindings for calling out to the Giterrific server.</p>
<p>The abstraction here is pretty simple. You make a call to a function I've defined that is designed to retrieve commit information for a particular git branch. Behind the scenes, giterrific-client will make an HTTP request to your installation of Giterrific and return the result. To accomplish this, I used my favorite HTTP abstraction: <a href="http://dispatch.databinder.net/Dispatch.html">Databinder Dispatch</a>. This was a simple 48 hour project over a weekend. The following week I handed this off to a coworker who I thought could find use of this at Domino.</p>
<p>Can you guess what happened?</p>
<p><img src="https://i.giphy.com/26FPy3QZQqGtDcrja.gif" alt="The Pluggable Dependency Pattern"></p>
<p>If you guessed <strong>dumpster fire</strong>, then you guessed correctly.</p>
<p>At Domino, we're using the Play Framework for a lot of our development work - much like a <em>lot</em> of other Scala shops. The Play Framework version we're using depends on a library called &quot;Async HTTP Client.&quot; It's a Java library that makes speaking HTTP easier.</p>
<p>For giterrific-client, I used Databinder Dispatch to help me speak HTTP easier. Dispatch in turn uses Async HTTP Client, also. The problem: Dispatch uses a <em>different version</em> of Async HTTP Client than Play. Moreover, it uses a <em>totally incompatible version</em>. This meant that with the way I'd architected giterrific-client, there's no way that any relatively recent Play application could use it.</p>
<p>This is why transitive dependencies are so obnoxious. It's really trivial on any project to create a situation where you have conflicting dependencies. To explain another way consider the following example:</p>
<ul>
<li>Your project <strong>A1</strong> depends on <strong>B1</strong> and <strong>C1</strong>.</li>
<li><strong>B1</strong> depends on <strong>X1</strong>.</li>
<li><strong>C1</strong> depends on <strong>X2</strong>.</li>
<li><strong>A1</strong> therefore depends on <strong>X1</strong> and <strong>X2</strong>.</li>
<li><strong>X1</strong> and <strong>X2</strong> will attempt to occupy the exact same space, and conflict. As a result either <strong>B1</strong> or <strong>C1</strong> will not behave as they were intended to.</li>
</ul>
<p>So what do we do to fix this problem? Well, typically in this scenario project <strong>A1</strong> would get no say in what <strong>B1</strong> or <strong>C1</strong> pull in transitively. However, if it could, it could easliy tell <strong>B1</strong> &quot;Hey, I want you to use <strong>X2</strong> instead of <strong>X1</strong> - and here's how you talk to it.&quot;</p>
<h2 id="enterhttpdriver">Enter HttpDriver</h2>
<p>To resolve the issue, I tweaked the architecture of Giterrific to use what I'm calling <strong>The Pluggable Dependency Pattern</strong>.</p>
<p>I created an interface I've named <code>HttpDriver</code>. Previously, Giterrific's client code would talk directly to Dispatch when it wanted to make an HTTP request. Now, it'll talk to an <code>HttpDriver</code>. By default, this will still talk to Dispatch under the hood, but it can be configured to talk to whatever HTTP library you'd prefer to use.</p>
<p>For <a href="https://github.com/farmdawgnation/giterrific/releases/tag/v0.2.0">Giterrific 0.2.0</a>, I ship four different pre-built drivers: the default Dispatch driver, a driver for Play 2.4, a driver for Play 2.5, and a driver for Finagle HTTP. If one of them doesn't work for you, it's quite trivial to swap out which driver is being used <em>or</em> implement your own <code>HttpDriver</code> from scratch. Since I've done this, we've successfully been able to implement a Giterrific POC in our Play application at Domino with minimal fuss.</p>
<p>The caveat here is that the underlying HTTP libraries are no longer declared as transitive dependencies. The project that wants to use Giterrific has to pull in Dispatch, Finagle, or Play themselves.</p>
<h2 id="fromtransitivitytopluggability">From Transitivity to Pluggability</h2>
<p>Surely, making <em>everything</em> pluggable on <em>every</em> open source project would become very annoying. Transitive dependencies are a huge convenience until they blow up in some unexpected way. Arguably, this is an avoidable problem by using a microservice architecture instead of a monolith architecture. However, I think in spite of that there's space for reasonable people to disagree when it comes to &quot;the best fit&quot; for a certain underlying service.</p>
<p>Some folks make heavy use of some core Finagle features throughout their architecture, for example. If they get a benefit from that <em>and</em> want to use Giterrific, why should my personal preference for Databinder Dispatch handicap them?</p>
<p>Pluggability, I think, has a few specific cases that it will work very well for. Specifically, cases where:</p>
<ol>
<li>The task you're trying to accomplish is fairly common with a lot of angles.</li>
<li>The task you're trying to accomplish is sufficiently complex to warrant concern over what transitive dependencies you'll pull in.</li>
</ol>
<p>There are two examples of areas ripe for pluggability. Specifically, HTTP interaction and JSON serailization/deserialization. Both of these tend to be pretty common tasks with different angles to them (which socket library gets used, which reflection method does the serialization algorithm use) and both can require some complex dependencies in their own right to accomplish their end goal.</p>
<p>Furthermore, I think that it's important that the project which wishes to be pluggable should have its abstraction for pluggability self-contained. So, for example, I think it's unlikely (based on my current thinking) that I'll ever make <code>HttpDriver</code> its own library. Doing so would just move the transitive dependency risk to a different link in the chain. Therefore, each project I implement this pattern in shall have it's own <code>HttpDriver</code> that will define the minimum interface that project needs in order to speak HTTP.</p>
<h2 id="finalthoughts">Final Thoughts</h2>
<p>This was a useful pattern for me to fix a real probem I ran into. As always, your mileage may vary. Either way, I would love to hear your thoughts on this. Reach out to me on Twitter at <a href="https://twitter.com/farmdawgnation">@farmdawgnation</a> and let me know your thoughts. I'll update this post with any interesting exchanges that result.</p>
]]></content:encoded></item><item><title><![CDATA[Riding the Ghost Train]]></title><description><![CDATA[<p>I've officially made the switch to a self-hosted <a href="http://ghost.org">Ghost</a> install on my blog.</p>
<p>It's still <em>something</em> of a work in progress. The layout and design are far from final and I don't currently have any kind of comment support. (I actually haven't decided whether or not I'm going to support</p>]]></description><link>https://farmdawgnation.com/riding-the-ghost-train/</link><guid isPermaLink="false">5c468fd705ce900013ec7583</guid><category><![CDATA[Personal]]></category><dc:creator><![CDATA[Matt Farmer]]></dc:creator><pubDate>Thu, 16 Jun 2016 02:47:03 GMT</pubDate><content:encoded><![CDATA[<p>I've officially made the switch to a self-hosted <a href="http://ghost.org">Ghost</a> install on my blog.</p>
<p>It's still <em>something</em> of a work in progress. The layout and design are far from final and I don't currently have any kind of comment support. (I actually haven't decided whether or not I'm going to support comments at all.) In spite of that, I wanted to give you all a view into my decision making process for this switch.</p>
<p>This blog post is part 1 of 2. I am going to walk through some of the things that I also evaluated and why I decided to settle on Ghost. This post will be largely the <em>what</em> and the <em>why</em> of this little migration. If you're interested in the <em>how</em>, that will come in part 2.</p>
<h2 id="pricing">Pricing</h2>
<p>The catalyst for this migration came first in the form of pricing. I realized that my Squarespace subscription was about to be renewed. The cost breaks down to roughly $8/month, which is a really good value. Yet, I still made the determination that there are more effective ways for <em>me</em>, being the highly technical user that I am, to spend that money.</p>
<p>I decided to rent server space from <a href="https://delimiter.com">Delimiter</a>. They give me a decently sized box for $6/mo, which is $2 cheaper than Squarespace. I just had to decide what to put on it.</p>
<h2 id="bloggingshowdown">Blogging Showdown</h2>
<p>There were three front-runners in my mind:</p>
<ul>
<li><a href="https://wordpress.org">WordPress</a> - I may dislike it because I've had to write plugins for it before, but it's kind of the &quot;Old Faithful&quot; of website platforms at this point.</li>
<li><a href="https://jekyllrb.com/">Jekyll</a> - I've used this for a number of low-maintenance sites in the past. I actually used it to build the wedding website for Katie and myself.</li>
<li><a href="https://ghost.org">Ghost</a> - The new-er kid on the block. It's a very minimalistic blogging platform designed to be lightweight and portable.</li>
</ul>
<p>In the end I made the call that there were three priorities:</p>
<ol>
<li>The ability to write my posts in Markdown.</li>
<li>Something that was lightweight with a simple template system.</li>
<li>The ability to use and interact with my blog from a mobile device.</li>
</ol>
<p>I briefly evaluated the options that I had in front of me in light of those priorities.</p>
<h3 id="markdown">Markdown</h3>
<p>Every option I evaluated except WordPress included native support for Markdown. Sure, sure, I'm sure that WordPress supports it by way of plugin. But I'd rather have first-class support for my preferred editing language. While first-class support itself isn't really a guarantee that editing will be enjoyable, it still instills a decent amount of confidence in me.</p>
<p>Jekyll expects you to use whatever editor you use for editing normal text documents. So, I had a pretty good idea of what that experience would feel like. That left Ghost for evaluation.</p>
<p>After tinkering around with Ghost on a test setup I can say that I found the Markdown editing and preview in Ghost smooth and enjoyable. It secures a small edge because it doesn't require me to deal with my editor. I love my editor, but I also feel like I'm working when I'm using it.</p>
<h3 id="lightweight">Lightweight</h3>
<p>This ends up being a really short comparison because, once again, the winner here is pretty much everything except WordPress.</p>
<p>Jekyll and Ghost use <a href="https://github.com/Shopify/liquid/wiki">Liquid</a> and <a href="http://handlebarsjs.com/">Handlebars</a>, respectively. Both are very similar, slim template languages that are very bare-bones. Overall this means that customizing either publishing system is a pretty quick and easy process. Additionally, the plugin support in both platforms is well designed and minimal. There are relatively few variables to concern yourself with when customizing either.</p>
<p>WordPress, however, is the opposite of lightweight. Its templates are not well separated from the actual implementation of the backend, it's designed to support everything from corporate sites to personal blogs, and I generally find managing all the moving parts to be unwieldy. When you write a template for WordPress you not only have to think about how your template will look and behave with your blog posts. You have to think about how your template will look and behave with every plugin you need to install to get all the functionality you need.</p>
<p>Of course, one man's bloat is another's value. I know a lot of smart people who will swear by WordPress. More power to them.</p>
<h3 id="mobile">Mobile</h3>
<p>This is the one category where a clear winner emerged. Ghost is the only option out of the non-WordPress list that would enable me to compose from my iPad or iPhone. I suspect Jekyll can be made to support it, but it's not quite as pleasant.</p>
<h3 id="conclusion">Conclusion</h3>
<p>It seems part of this post went missing somehow. Let's hope that's not a trend. In the end the mobile experience pushed me over the edge. We'll see if I end up stepping into a world of snafu's of disappearing posts! ;)</p>
]]></content:encoded></item><item><title><![CDATA[Dockerizing Development at Domino, Part II]]></title><description><![CDATA[<p>If you’ve been following my blog for awhile, you probably saw my post on using Docker Compose to improve <a href="http://www.dominodatalab.com">Domino Data Lab</a>‘s development environment (titled <a href="http://farmdawgnation.com/blog/2016/2/20/docker-composing-for-fun-and-profit">“Docker Composing for Fun and Profit”</a>). This post is the sequel.</p>
<p>Over the last few weeks we prioritized closing the loop on these</p>]]></description><link>https://farmdawgnation.com/dockerizing-development-at-domino-part-ii/</link><guid isPermaLink="false">5c468fd705ce900013ec7581</guid><category><![CDATA[Development]]></category><category><![CDATA[Operations]]></category><dc:creator><![CDATA[Matt Farmer]]></dc:creator><pubDate>Sun, 01 May 2016 15:37:09 GMT</pubDate><content:encoded><![CDATA[<p>If you’ve been following my blog for awhile, you probably saw my post on using Docker Compose to improve <a href="http://www.dominodatalab.com">Domino Data Lab</a>‘s development environment (titled <a href="http://farmdawgnation.com/blog/2016/2/20/docker-composing-for-fun-and-profit">“Docker Composing for Fun and Profit”</a>). This post is the sequel.</p>
<p>Over the last few weeks we prioritized closing the loop on these development environment improvements because we had three new developers joining the fray. Historically our machine bootstrapping process has been a disaster. Getting my machine fully up and running when I joined last year took two days, if my memory serves me correctly.. The good news is that it seems like we’ve successfully tamed the beast.</p>
<p>Domino now has a working, containerized development environment and a simple python-based bootstrap script for OS X and Ubuntu to help facilitate setting a new environment up. Together these tools significantly reduce the time it takes to get a working environment down to a few hours or less. Yesterday I actually took these both out for a spin on an AWS server I was setting up “just to see.” Using them I got to a working environment in right at an hour.</p>
<p>Today I want to share a few things with you about what we’re doing to make this successful. But first let’s review where we started and then proceed to where we’re going.</p>
<p>The setup I described in my last post had roughly this structure:</p>
<ul>
<li>Container for database, other services.</li>
<li>Container for holding the application under development.</li>
<li>On Linux mount the AUD directly. On OS X use rsync to push changes into the Docker VM on your machine.</li>
<li>Use docker-compose to orchestrate all of these containers.</li>
</ul>
<p>If you need more detail than that feel free to go through the previous post. ? Now a bit about where we are today.</p>
<h3 id="osxvolumemountingwithspeed">OS X Volume Mounting with Speed!</h3>
<p>I made some pretty important changes to the way I set things up in OS X from my first post. In particular, you may note that in my first post I recommended using rsync to move changes from my host system (OS X) into the VirtualBox container. This hack needed to exist because of the horrible performance of VirtualBox’s own file sharing system.</p>
<p>Since then I found a much easier setup in the form of <a href="https://github.com/codekitchen/dinghy">Dinghy</a>. Dinghy is a wrapper around docker-machine that sets up NFS sharing of the /Users folder between OS X and the VM that Docker is actually running in. NFS is much, much more performant than VirtualBox’s file sharing, and enough so that we can mount our source directly into the container without issue. So things now worked a bit closer to how they did on Linux based systems, modulo one, important issue: some of our containers expected to be able to chown and chmod things as root. Dinghy’s default settings prevent this over NFS.</p>
<p>For most folks these default settings are fine, but occasionally people like us need an escape hatch in order to do what we want to do. I proposed <a href="https://github.com/codekitchen/dinghy/pull/170">codekitchen/dinghy#170</a> (which is merged but not yet released) to provide just such an escape hatch and permit overriding the default file sharing settings provided by Dinghy. With that change in place things are <strong>mostly</strong> smooth in the file sharing department.</p>
<p><strong>That said,</strong> as a word of advice: be aware that NFS has some weird things about it. Some applications (such as pip) will blow up if the wrong folder is actually an NFS share. (In our case we had one container where /tmp was mounted from the host. Boom!)</p>
<h3 id="baremetalissometimesbest">Bare Metal is Sometimes Best</h3>
<p>The most important thing we learned was that the container for the Application Under Development was a bad idea for our system.</p>
<p>In our case, our AUD has to do a good bit of I/O on the file system and cares a lot about file ownership and permissions for security reasons. These reasons largely only apply in the production system, but minimizing differences between production and development is a priority for us. It’s also not uncommon for sbt to do some I/O on our behalf that an IDE like IntelliJ will want to inspect in order to provide helpful features like autocompletion.</p>
<p>Anyone who has done a little bit of work in Docker will tell you that user id and group id management between docker containers and the host system is a little bit of a dumpster fire. After a long, winding adventure in trying to make the UIDs/GIDs automatically line up regardless of your actual host system, we took a step back and re-evaluated the consistency (or sanity) of trying to do this in the first place. We landed on the conclusion that, although Docker was really useful for ensuring that the services we needed were set up and configured correctly, the cost of trying to figure out how to get all of the moving pieces we wanted to use (IDEA, various other editors, sbt, tools, etc) working consistently wasn’t worth the benefit. Linux and OS X systems both experienced a good deal of pain around trying to do that.</p>
<p>We concluded that bare metal is sometimes best. With the number of metaphorical coconuts in the air that depend on proper UID/GID/permissions it just made more sense for us to keep the actual application we are building on the host system and use containers for the services it needs.</p>
<h3 id="bootstrapscriptsfeelpainfulbutdowork">Bootstrap Scripts Feel Painful, but Do Work</h3>
<p>Another part of this project of ours was the bootstrap script for OS X and Ubuntu machines. I don’t have a lot to say about this except that, as the author, it felt like a really burdensome thing to write. I was convinced at various moments that this wouldn’t be worth the time I was spending on it.</p>
<p>Yesterday I set up a brand new Ubuntu environment using that script. It was worth it.</p>
<h3 id="lookingforward">Looking Forward</h3>
<p>We’ve come a long way since my first blog post, and we’re continuing to improve.</p>
<p>Since my initial work with Dinghy, I’ve started participating in the <a href="https://blog.docker.com/2016/03/docker-for-mac-windows-beta/">Docker for Mac Beta</a>, which is based on <a href="https://github.com/mist64/xhyve">xhyve</a> virtualization and a custom file sharing layer that is both a) performant and b) not subject to some of the peculiarities of NFS. I think that once this is released to the general public it’ll be a much better experience than what we have today.</p>
<p>As always, I would love feedback on what you thought of this post! Positive feedback is what convinces me to write more frequently, so if you enjoyed this let me know!</p>
]]></content:encoded></item></channel></rss>