<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://brandonvin.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://brandonvin.github.io/" rel="alternate" type="text/html" /><updated>2026-04-21T04:27:27+00:00</updated><id>https://brandonvin.github.io/feed.xml</id><title type="html">Mind map</title><subtitle>Map of my mind: what seeds are growing, what trees are bearing fruit?</subtitle><author><name>Brandon Vincent</name></author><entry><title type="html">Migrations considered helpful! And the tale of the Matryoshka Migration</title><link href="https://brandonvin.github.io/2026/04/08/matryoshka-migrations.html" rel="alternate" type="text/html" title="Migrations considered helpful! And the tale of the Matryoshka Migration" /><published>2026-04-08T00:00:00+00:00</published><updated>2026-04-08T00:00:00+00:00</updated><id>https://brandonvin.github.io/2026/04/08/matryoshka-migrations</id><content type="html" xml:base="https://brandonvin.github.io/2026/04/08/matryoshka-migrations.html"><![CDATA[<p><img src="/img/matryoshki-ye-olde-curiosity-shop.png" alt="Seven Matryoshki" /></p>

<p><em>Seven Matryoshki. Source: Ye Olde Curiosity Shop, Seattle, WA</em></p>

<p>Migrations are an art, not a science. A migration is a juggling act between
breaking glass, keeping the lights on, and opening new doors.</p>

<p>Migrations are the evolution of a system through incremental changes.</p>

<p>Migrations are not limited to infrastructure; customer/product changes can be
migrations too.</p>

<p>The difference between a single commit and a migration is that a migration is a
long series of commits. Also, migrations generally affect a lot more than one
person.</p>

<p>Migrations require updating docs, people’s brains, and muscle memory.</p>

<p>Done well, migrations reduce complexity and accelerate product development.</p>

<p>Done poorly, migrations increase complexity and slow product development.</p>

<h1 id="why-did-i-write-this">Why did I write this?</h1>

<p>Circa November 2024, some seasoned engineers, a few newer folks, and I, had a passionate discussion:</p>

<blockquote>
  <p>We’ve increasingly moved our product towards being <strong>easy</strong> – wizards, fast
onboarding – at the cost of <strong>simplicity</strong> – removing non-essential
complexity. Does that resonate with anyone else? The easy things become quite
hard to manage in the medium-to-long term.</p>
</blockquote>

<p>From what I heard, yes. It resonated, resoundingly.</p>

<blockquote>
  <p>How do we think about the tradeoff between <strong>simple</strong> and <strong>easy</strong> in a longer view? If we
build something easy today, how do we think about incremental architectural
changes to reduce our complexity? Likely easier said than done, but how have we
thought about it in the past, vs. now?</p>

  <p>What are the biggest sources of pain and complexity right now in the platform,
and are there ways to reduce that complexity over time, balancing it with
product roadmap, new features, etc.?</p>
</blockquote>

<p>These are great questions!</p>

<p>This conversation happened in November 2024, when I had just completed a 3-year migration project
of my own. So I was already in a headspace of reflecting on the past 5 years and what wisdom
can be gleaned from it.</p>

<h1 id="so-whats-the-goal">So what’s the goal?</h1>

<p>At Amperity, the word “migration” carries a lot of historical baggage.
Let’s sit with the baggage, process it, and accept it.</p>

<p>Let’s:</p>

<ul>
  <li>Share examples of good outcomes of migrations.</li>
  <li>Share examples of troubled migrations and how they turned successful.</li>
  <li>Share common themes from the above.</li>
</ul>

<h1 id="how-do-big-migrations-start">How do big migrations start?</h1>

<p>Usually, but not always, a design-and-architecture or staff engineering group
gets together and studies a big problem. A design doc, or series of design docs
get written. It may be very long, 20+ pages. Usually, an engineer is chosen as
the Directly Responsible Individual (DRI) to start and navigate the project.</p>

<h1 id="examples-of-successful-big-migrations">Examples of successful big migrations</h1>

<p>We did it! Yay, us! This is in no particular order, and I’m obviously forgetting some as I write this:</p>

<table>
  <thead>
    <tr>
      <th style="text-align: left">Before</th>
      <th style="text-align: left">After</th>
      <th style="text-align: left">Big unlocks (non-exhaustive)</th>
      <th style="text-align: left">Est. finish date</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left">Workflow System V0, built on Apache Airflow</td>
      <td style="text-align: left">Workflow System V1</td>
      <td style="text-align: left">Customers can own Workflows – Reliable Workflows – Customer vs. Platform Attribution of Failures</td>
      <td style="text-align: left">2024</td>
    </tr>
    <tr>
      <td style="text-align: left">Finagle/Thrift Service Framework</td>
      <td style="text-align: left">Prodigal Service Framework</td>
      <td style="text-align: left">Developer Efficiency</td>
      <td style="text-align: left">2022</td>
    </tr>
    <tr>
      <td style="text-align: left">Self-Running Apache Kafka on VMs in the cloud</td>
      <td style="text-align: left">Purchase Confluent Kafka-as-a-Service Kafka Topics Managed in Infrastructure as Code in a CD pipeline</td>
      <td style="text-align: left">Developer Efficiency – Infra Cost Efficiency</td>
      <td style="text-align: left">2022</td>
    </tr>
    <tr>
      <td style="text-align: left">Cloud Storage Spaghetti</td>
      <td style="text-align: left">Storage Service and APIs</td>
      <td style="text-align: left">Bridge / Delta Sharing – Strong security posture – Bring Your Own Storage</td>
      <td style="text-align: left">2024</td>
    </tr>
    <tr>
      <td style="text-align: left">Jobs Inputs/Outputs in Cloud Storage</td>
      <td style="text-align: left">Job Inputs/Outputs in Redis</td>
      <td style="text-align: left">Developer Efficiency</td>
      <td style="text-align: left">2022</td>
    </tr>
    <tr>
      <td style="text-align: left">API Framework V0</td>
      <td style="text-align: left">API Framework V1</td>
      <td style="text-align: left">Developer Efficiency</td>
      <td style="text-align: left">2022</td>
    </tr>
    <tr>
      <td style="text-align: left">ADLS Gen 1</td>
      <td style="text-align: left">ADLS Gen 2</td>
      <td style="text-align: left">Infra Cost Efficiency – Platform Reliability – Security Posture – Developer Efficiency</td>
      <td style="text-align: left">2021</td>
    </tr>
    <tr>
      <td style="text-align: left">Loggly for structured logs + Honeycomb for traces</td>
      <td style="text-align: left">Honeycomb for traces and structured logs</td>
      <td style="text-align: left">Infra Cost Efficiency – Developer Efficiency – Security Posture</td>
      <td style="text-align: left">2023</td>
    </tr>
    <tr>
      <td style="text-align: left">Plain Text Logging</td>
      <td style="text-align: left">Structured Logging and Tracing</td>
      <td style="text-align: left">Speed to debug/resolve incidents – Developer Efficiency</td>
      <td style="text-align: left">2021</td>
    </tr>
    <tr>
      <td style="text-align: left">Deprecated Azure Public IP</td>
      <td style="text-align: left">Modern Azure Public IP</td>
      <td style="text-align: left">BFD: Connections to customer systems won’t break when Azure retires their old infra – Developer Efficiency</td>
      <td style="text-align: left">2024</td>
    </tr>
    <tr>
      <td style="text-align: left">Loading Dock</td>
      <td style="text-align: left">Not Loading Dock</td>
      <td style="text-align: left">Security Developer Efficiency</td>
      <td style="text-align: left">2024</td>
    </tr>
    <tr>
      <td style="text-align: left">Tables In Accumulo + HDFS</td>
      <td style="text-align: left">Files in Cloud Storage, removal of Accumulo/HDFS</td>
      <td style="text-align: left">Infra Cost Efficiency – Developer Efficiency</td>
      <td style="text-align: left">2020</td>
    </tr>
    <tr>
      <td style="text-align: left">HDFS</td>
      <td style="text-align: left">Cloud Storage, full removal of HDFS</td>
      <td style="text-align: left">Infra Cost Efficiency – Developer Efficiency</td>
      <td style="text-align: left">idk</td>
    </tr>
    <tr>
      <td style="text-align: left">Product Configuration in Spaghetti/Accumulo</td>
      <td style="text-align: left">Unified Product Configuration</td>
      <td style="text-align: left">Sandboxes – Developer Efficiency</td>
      <td style="text-align: left">idk</td>
    </tr>
    <tr>
      <td style="text-align: left">Service Data in Spaghetti/Accumulo</td>
      <td style="text-align: left">Service Data in PostgreSQL</td>
      <td style="text-align: left">Sandboxes – Developer Efficiency</td>
      <td style="text-align: left">idk</td>
    </tr>
    <tr>
      <td style="text-align: left">Something I’m Forgetting</td>
      <td style="text-align: left">Something I’m Forgetting</td>
      <td style="text-align: left"> </td>
      <td style="text-align: left">idk</td>
    </tr>
  </tbody>
</table>

<p><strong>TODO:</strong><br />
I’ve worked on backend/infra most of my time at Amperity, so I’m probably missing some of the more direct customer-facing migrations. Feel free to email me if I missed anything! I will update this post, if so.</p>

<h1 id="whats-in-a-successful-big-migration">What’s in a successful big migration?</h1>

<p>Usually:</p>

<ul>
  <li>A <strong>Directly-Responsible Individual (DRI)</strong> who is also a direct contributor to the code (or holds enough sway with engineers who <em>are</em> direct contributors)</li>
  <li>A central <strong>Design Doc,</strong> kept up to date. A Google Doc works well.</li>
  <li>Maintain <strong>buy-in</strong> from engineering and product
    <ul>
      <li>You will be asked, “What?” and “Why?”. <strong>Do Repeat Yourself</strong>, and link to the <strong>Design Doc</strong>.</li>
    </ul>
  </li>
  <li><strong>Small focused team</strong>: Team-to-team handoffs and trying to coordinate across teams is the path of pain.
    <ul>
      <li>This may include <strong>embedding</strong>: bringing together SMEs from different teams (e.g. a product domain SME with a cloud infrastructure SME) into a “tiger team” or “v(irtual) team”</li>
      <li>Observe the Churn Rule: take the initiative on updating callers, in backward-compatible fashion. Avoid imposing work on teams who are likely busy and far from the migration details
        <ul>
          <li>Friction in the migration strategy directly feeds back into accelerating the migration (e.g. they may start with a runbook, then feel the repetitive parts, and then automate them)</li>
        </ul>
      </li>
    </ul>
  </li>
  <li><strong>Ratcheting:</strong> when the new pattern is ready and in use, prevent new usages of the old pattern from being added - usages of the old pattern monotonically decrease.
    <ul>
      <li>See also: <a href="https://martinfowler.com/bliki/StranglerFigApplication.html">Strangler Fig Pattern</a></li>
      <li>See also: <a href="https://sirupsen.com/shitlists">Shitlists</a> (CI tests that fail when old pattern is re-introduced)</li>
      <li>Examples at Amperity:
        <ul>
          <li><code>mulch</code> is a homegrown Shitlist for Clojure code. It blocks new usages of deprecated functions in our Clojure and ClojureScript code.</li>
          <li>After we migrated a few services from Finagle/Thrift to Prodigal, we produced a runbook to migrate services and made Prodigal the officially blessed path for new services.</li>
          <li>After we migrated a few services from Aurora to K8s, we produced a repeatable migration runbook. We updated the “add a new service” tools/docs/guidance to target K8s. Soon after, 5 new services needed to be added, and they were stood up directly on K8s.</li>
        </ul>
      </li>
    </ul>
  </li>
  <li>They are finished and <strong>recognized as finished</strong>. How?
    <ul>
      <li>Written and shared definition of done</li>
      <li>Announcement that it’s done</li>
    </ul>
  </li>
  <li>Deliver an early win and/or other incremental wins
    <ul>
      <li>Caveat: Avoid starting with the easiest parts
        <ul>
          <li>Up front research to find the riskiest, hardest parts and derisk them</li>
          <li>Sequence work so that the hard parts get easier
            <ul>
              <li>Example: we don’t know how to use K8s, and have no K8s tooling, which is a big operational risk we need to solve before using it widely in production → Let’s start by using K8s in a lesser-used part of the product to build expertise and foundational tooling</li>
            </ul>
          </li>
          <li>Or, start with the riskiest part to prove the migration strategy
            <ul>
              <li>Example: in both the Prodigal and K8s migration, one of the first services we tackled was Tenant Service, which is a high-traffic, core service that could bring the whole app down</li>
            </ul>
          </li>
          <li>Sometimes migrations stall because they dive head-first into the easy parts, and then the harder parts lead to re-considering earlier design decisions.</li>
        </ul>
      </li>
      <li><strong>Also, Scenic Routes</strong>: take a little detour to get obvious wins for customers, which are clearly beneficial to the migration
        <ul>
          <li>WARNING: when Scenic Routes keep getting pulled into the critical path, and they grow in scope, this can lead to a Matryoshka Migration</li>
        </ul>
      </li>
    </ul>
  </li>
  <li>Learn from Incidents
    <ul>
      <li>We run AARs and incorporate the learnings into the <strong>Design Doc</strong></li>
    </ul>
  </li>
  <li>Delete the dead code!
    <ul>
      <li>If the only dead stuff is code, it’s often easiest to delete it all at once, when we’re confident it’s unused. Big red line PRs are tasty!</li>
    </ul>
  </li>
  <li>Shut down the dead infra!
    <ul>
      <li>In infra migrations targeting cost efficiency (e.g. shutdown of Accumulo/HDFS), slowly scaling down the old system helps deliver incremental wins.</li>
    </ul>
  </li>
</ul>

<h2 id="how-do-big-migrations-struggle">How do big migrations struggle?</h2>

<h3 id="pattern-matryoshka-migration">Pattern: Matryoshka Migration</h3>

<p>Commonly, migrations turn into <strong>Matryoshka Migrations</strong>. <a href="https://en.wikipedia.org/wiki/Matryoshka_doll">Matryoshka</a> is the Russian nesting doll. 🪆Migrations nested in migrations.</p>

<p>A Matryoshka Migration is one that has diverged a bit too far from its original goals.</p>

<p>This migration has gone on so long that we started other migrations that affect the same parts of the system.</p>

<p>The critical path of the migration has gotten longer and more complicated, rather than shorter and simpler.</p>

<p>You can smell it:</p>

<ul>
  <li>A migration started</li>
  <li>It has been <em>almost done</em> for a really long time: months, or years.</li>
  <li>Though it’s done with good intentions (e.g. <strong>Scenic Routes</strong> motivated by product/customers), the migration keeps going… and going… and going… or pausing inexplicably.</li>
</ul>

<h3 id="pattern-drained-dri">Pattern: Drained DRI</h3>

<p>For example, a migration was started 1 year ago. Then, re-orgs and staffing changes (e.g. hiring, attrition, reduction in force) happened.<br />
All the teams, code ownership, and managers have shuffled around.<br />
Company strategy can change, too.</p>

<p>However, the friction that motivated the migration, and the friction of unfinished migrations, usually rear their ugly head again.<br />
It’s hard work for the DRI to re-establish buy-in and kickstart the migration. Sometimes they have to do this multiple times.</p>

<p>What can help:</p>

<ul>
  <li>Design Doc</li>
  <li>Switch DRI</li>
  <li>Embedding, re-establishing a focus team</li>
  <li>Let the DRI take a break</li>
</ul>

<h2 id="turn-this-matryoshka-around">Turn this Matryoshka around!</h2>

<p>Some of the successful migrations became Matryoshka Migrations and then turned around. How?</p>

<ul>
  <li>Recognize that it’s a Matryoshka Migration.
    <ul>
      <li>Compare the original goals/timeline with the current timeline. A smell is that the original timeline hasn’t been re-evaluated.</li>
    </ul>
  </li>
  <li>Re-evaluate the cost of complexity inherent in having multiple, large in-progress migrations.</li>
  <li>Re-focus on the original goals. Telling the customer value, and buy-in of those goals.</li>
  <li>Re-evaluate what’s really in the critical path, and focus on it.</li>
  <li>Re-establish a small focused team with a “mandate”, free up their time to focus on it.</li>
</ul>

<h1 id="own-up-to-blocked-and-stalled-big-migrations">Own up to blocked and stalled big migrations</h1>

<p>Let’s be leaders: communicate, and have empathy.</p>

<p>Yes, it is <strong>okay</strong>, and sometimes <strong>better for the company</strong> to wait to start, pause, or stop a migration.</p>

<p>There’s a negative outcome we’ve seen sometimes at Amperity. Example:</p>

<ol>
  <li>Engineers or customers feel pain from a problem that exists <strong>today</strong></li>
  <li>Engineers have designed a solution, socialized it with engineers, and feel that they have clear buy-in.</li>
  <li>Engineers feel blocked from starting or continuing work that they believe would solve the problem.</li>
  <li>This blockage lacks a clear explanation: nameless leaders withhold their buy-in</li>
  <li><strong>Outcome:</strong> a tenured, high-value engineer is demoralized.</li>
</ol>

<p><strong>If we decide to block, pause, or cancel a migration, let’s communicate clearly and honestly why.</strong></p>

<h1 id="reflect-on-finished-big-migrations">Reflect on finished big migrations</h1>

<p>When a migration finishes, we can run retrospectives to gather and share what we learned. <strong>Consider this post a “Meta-Retrospective” of 5 years of migrations at Amperity.</strong></p>

<p>One example retrospective is the <code>Spark 2-to-3 Retrospective</code>.</p>

<h1 id="so-what-should-we-do">So… what should we <em>do</em>?</h1>

<p>It’s a fact. We have a complex product and complex infrastructure.<br />
What are the biggest sources of complexity right now?<br />
Are there ways to reduce that complexity over time, balancing it with product roadmap, new features, etc.?</p>

<p>Yes!</p>

<p>We’ll do all the migrations, all at the same time, all as fast as possible. No - sorry, that’s a joke. <strong>Today, we can’t do all of them at full speed.</strong></p>

<ul>
  <li>As engineering leaders (e.g. staff-eng community), let’s catalog and <strong>prioritize</strong> all our major migrations that are executing and proposed.</li>
  <li>If some migrations are entering Matryoshka status, and still valuable, let’s focus on finishing them.</li>
  <li>We should decide which ones to pause, and which ones to hold off on starting, with <strong>empathy</strong>.
    <ul>
      <li>Note that pausing may mean some progress may still happen - it just will be in the background with gradual progress, likely not on any team’s Jira board. Perhaps interspersed among new feature commits, written on quiet Wednesday and Friday afternoons. (See below: Tidy as we go)</li>
    </ul>
  </li>
</ul>

<p>We’ve done a lot of the hard thinking on ways to simplify that complexity, but we haven’t started or implemented them fully.</p>

<p>Examples:</p>

<ul>
  <li>Datasets: groups of named tables. Tables are tables!</li>
  <li>Amperity’s internal library, <code>comp-graph</code> for forming Computation Graphs of complex layered transformations. (Credit to Kevin Litwack)</li>
  <li>Amperity Sandboxes: a massive enabler for testing, sharing changes. I think this is done from a product standpoint – what is left from the engineering perspective?</li>
  <li>Coordinated Changes</li>
  <li>Explicit vs. implicit configuration / semantic action-at-a-distance</li>
  <li>Workbench for exploring Datasets (state)</li>
  <li>Drafts</li>
</ul>

<h2 id="tidy-as-we-go">Tidy as we go</h2>

<p>We can pragmatically “Tidy as we go”. <a href="https://www.oreilly.com/library/view/tidy-first/9781098151232/">Tidy First?</a>  is a nice 2-hour read on this topic.</p>

<p>Quick summary:</p>

<ul>
  <li>“Tidying” is at the level of individual commits, a conversation among engineers and the code; it’s not called out as a “migration project”.</li>
  <li>Tidying means effectively carrying out a “low-urgency migration” bit-by-bit, interspersed with new-feature commits. In other words, gradual refactoring towards a higher quality, lower-friction codebase.</li>
  <li>Tidying requires trust and good judgment.</li>
</ul>

<p>Example at Amperity:</p>

<ul>
  <li>UI Code Modernization: Reframe Spaghetti → React/Helix</li>
</ul>

<h1 id="sources-and-inspiration">Sources and inspiration</h1>

<p>This post is a synthesis of my own experience and several other people’s great ideas.</p>

<pre><code>(iterate inc @amperity-engineering)
</code></pre>

<p>I’ve chatted about this topic with these people at Amperity <em>(please note, I took 5 seconds on this list, it is not exhaustive, and in no particular order)</em>:</p>

<ul>
  <li>… many others!</li>
  <li>John Rush</li>
  <li>Jeff Stokes</li>
  <li>Greg Look</li>
  <li>Stephen Meyles</li>
  <li>Hemanth Srinivas</li>
  <li>Aria Haghighi</li>
  <li>Bryce Covert</li>
  <li>Brandon Vincent</li>
  <li>Ace Levenberg</li>
  <li>Drew Inglis</li>
  <li>Graeme Roche</li>
  <li>Kevin Litwack</li>
  <li>Cary Lee</li>
  <li>Joe Christianson</li>
  <li>… many others!</li>
</ul>

<p>In general, thanks to Amperity’s <code>#staff-engineering</code> discussions.</p>

<p>… and in the public domain:</p>

<ul>
  <li><a href="https://www.oreilly.com/library/view/tidy-first/9781098151232/">Kent Beck – “Tidy First?”</a></li>
  <li><a href="https://blog.danielna.com/talks/pushing-through-friction/">Dan Na – “Pushing Through Friction”</a>
    <ul>
      <li>What is <strong>friction</strong>? It is resistance; when things feel harder than they ought to be.</li>
      <li><strong>Friction</strong> in engineering demotivates otherwise smart and highly-motivated engineers.</li>
      <li><strong>Friction</strong> in a product turns customers away.</li>
      <li>“<strong>WTF Factor</strong>” and “<strong>Normalization of Deviance</strong>”: The harms when tech debt, stalled migrations, or struggling migrations “swept under the rug” become normalized in an organization.</li>
      <li>“<strong>Pushing Through Friction Is The Job</strong> <em>[of a tech lead or staff+ engineer].</em>”</li>
    </ul>
  </li>
  <li><a href="https://www.oreilly.com/library/view/the-staff-engineers/9781098118723/">Tanya Reilly – “The Staff Engineer’s Path”</a>
    <ul>
      <li>Chapter: Leading big projects</li>
      <li>Section: Why have we stopped?</li>
    </ul>
  </li>
  <li>Will Larson’s astute articles
    <ul>
      <li><a href="https://lethain.com/migrations/">Migrations: the sole scalable fix to tech debt.</a></li>
      <li><a href="https://lethain.com/migration-isnt-failing-due-to-lack-of-staffing/">Your migration probably isn’t failing due to insufficient staffing.</a></li>
    </ul>
  </li>
  <li><a href="https://betterprogramming.pub/you-will-always-have-more-problems-than-engineers-aafff94a4623">Matt Schellhas – “You will always have more problems than engineers”</a></li>
  <li>While we were pretty proud of “coining” the term Matryoshka Migration, it
turns out we aren’t really that original. Except when it comes to naming
things. Check out this travelling blog: <a href="https://migratingmatryoshka.com/">Migrating Matryoshka</a></li>
</ul>]]></content><author><name>Brandon Vincent</name></author><category term="Other" /><summary type="html"><![CDATA[]]></summary></entry><entry><title type="html">Force multiplication</title><link href="https://brandonvin.github.io/2026/03/12/force-multiplication.html" rel="alternate" type="text/html" title="Force multiplication" /><published>2026-03-12T00:00:00+00:00</published><updated>2026-03-12T00:00:00+00:00</updated><id>https://brandonvin.github.io/2026/03/12/force-multiplication</id><content type="html" xml:base="https://brandonvin.github.io/2026/03/12/force-multiplication.html"><![CDATA[<p>Two short stories of how <em>getting things done</em> can happen, when it’s not doing
the things myself.</p>

<h2 id="the-first-one">The first one</h2>

<p>A server needed to be created and configured. This is a special snowflake
server. It’s owned by team B.</p>

<p>My team provisions servers all the time. I understood the scope of changes: I
could’ve done it myself, or elected an engineer on my team.</p>

<p>Instead, I reached out to the team’s manager, and asked something like:</p>

<blockquote>
  <p>Hey, this is nominally in your team’s area of ownership. You all have a full
plate, and don’t do server config often. It could be a learning opportunity
for your team, but we could also just do it. What do you think?</p>
</blockquote>

<p>She said yes, there’s interest on the team in a learning opportunity and a cross-team win, so let’s have an engineer on her team take it on. Nice!</p>

<p>Later, I reached out to the engineer and asked:</p>

<blockquote>
  <p>Hey, have you provisioned or configured a server before?</p>
</blockquote>

<p>No, she hadn’t. All good, just checking, I said, and asked if it’d be helpful
to have a call where we go through the tooling and typical workflows. We had
that call, and it went great – she was over-prepared by reading some of our
docs ahead of time. I asked lots of socratic questions and she engaged with
them and asked her own questions too.</p>

<p>It got done! She showed her work to the engineering department.</p>

<h2 id="the-second-one">The second one</h2>

<p>With a different team and a different engineer, I “gave” them a task in a
similar way: reached out to their manager, etc. They reached out to me with
maybe one or two questions total. I reached out to them with a question,
basically “hey, how can we fix this error?” and they replied with a “yep I can
fix it <em>nod</em>”.</p>

<p>Basically, they did not engage with the socratic question, so I
did not ask more.</p>

<p>It got done-done-done! They showed their work to the engineering department.</p>

<p>I had reached out to their manager – like in the first one – and the task
getting done happened about 2 months later.</p>

<h2 id="the-learning">The learning</h2>

<p>Patience pays off for everyone.</p>

<p>Both of these stories happened in the context of a multi-month project
which I was leading.</p>

<p>As a result of choosing this path instead of the “do it all ourselves” path, we have
strengthened the organization. The skills to provision and configure servers, and
provision cloud resources, are not frequently <em>needed</em> by other teams, but when they are needed
it is often a late discovery in a project that already has a lot of momentum.</p>

<p>In the grand scheme of the software-shipping machine, it is better for these
skills and familiarity to be distributed in pockets around the organization.</p>

<p>That’s an example of <em>force multiplication</em>.</p>]]></content><author><name>Brandon Vincent</name></author><category term="Other" /><summary type="html"><![CDATA[Two short stories of how getting things done can happen, when it’s not doing the things myself.]]></summary></entry><entry><title type="html">Heaps of work</title><link href="https://brandonvin.github.io/2026/03/06/shifting-my-priorities.html" rel="alternate" type="text/html" title="Heaps of work" /><published>2026-03-06T00:00:00+00:00</published><updated>2026-03-06T00:00:00+00:00</updated><id>https://brandonvin.github.io/2026/03/06/shifting-my-priorities</id><content type="html" xml:base="https://brandonvin.github.io/2026/03/06/shifting-my-priorities.html"><![CDATA[<blockquote>
  <p>noun</p>

  <p>(colloquial) A lot, a large amount</p>

  <blockquote>
    <p>Thanks a heap!</p>
  </blockquote>
</blockquote>

<p>– <a href="https://en.wiktionary.org/wiki/heap">Wiktionary</a></p>

<p>Right, if we do <em>heaps</em> of work, we’ll get <a href="https://www.youtube.com/watch?v=ULeDlxa3gyc&amp;list=RDULeDlxa3gyc&amp;start_radio=1">loads of money!</a></p>

<p>Serve pizza on plastic throwaway plates. It’s <a href="https://kinggizzard.bandcamp.com/track/astroturf">better for business!</a></p>

<p><img src="/img/loads-of-money.png" alt="Loads of money!" /></p>

<h2 id="okay-wut">Okay, wut?</h2>

<p>To stay motivated and engaged, I’ve started thinking about what
kind of work I should be doing in my current role and team.</p>

<p>A helpful motto I’ve learned is: any time a task comes onto your radar, you can:</p>

<blockquote>
  <ol>
    <li>Do it now</li>
    <li>Drop it now</li>
    <li>Delegate it</li>
    <li>Do it later</li>
  </ol>
</blockquote>

<p>Some people talk about <em>stacks</em> and <em>queues</em> of work. That’s pretty helpful.
It makes a lot of sense, when every task is of equal priority.
But time is finite. Not everything can be of equal priority!</p>

<p>As time and priority become more important factors in my personal algorithm,
<a href="https://en.wikipedia.org/wiki/Heap_(data_structure)">heaps</a> – also known as <a href="https://docs.oracle.com/javase/8/docs/api/java/util/PriorityQueue.html"><code>PriorityQueue</code> in Java</a>, possibly a
a <a href="https://docs.python.org/3/library/collections.html#deque-objects"><code>deque</code> in Python</a>, and possibly a <code>PersistentQueue</code> in Clojure
– is the analogy I’ve landed on. I don’t even know if it’s original, but it’s useful.</p>

<p>But also, big projects should not be rapidly moving on to and off of the heap.
They have external commitments (stakeholders around the business, and maybe deadlines) that need to be
kept in alignment. And context switching between big projects is <em>expensive</em>.</p>

<p>So, what’s on that heap?</p>

<h2 id="snacks">Snacks</h2>

<p>At any moment, there’s likely a <em>real, important</em> project that I could be working on,
but so many ideas and potential things to work on come up every day.</p>

<p>An idea that stuck with me is the clever label for work that is enticing and
easy, but not a great use of one’s time: snacking.</p>

<p>All the credit to <a href="https://www.noidea.dog/staff">The Staff Engineer’s Path</a> and <a href="https://staffeng.com/guides/work-on-what-matters/">Staff Engineer</a> for the clever analogy of <em>snacking</em>.</p>

<ul>
  <li>Big projects are on a queue-ish and stack-ish system.</li>
  <li><em>Snacks</em> stay on the heap.</li>
</ul>

<h2 id="whats-worth-my-time">What’s worth my time?</h2>

<p>Besides the <em>real, important</em> projects, what’s worth my time?</p>

<p>A few ideas that seem obviously worth my time are:</p>

<ul>
  <li>Org-wide sources of friction</li>
  <li>Org-wide drags on velocity</li>
  <li>Preventing the next incident we haven’t thought of yet</li>
</ul>

<p>When I’m on-call, maybe a little different:</p>

<ul>
  <li>In incident response, fill the gaps</li>
  <li>Fixing <em>recurring</em> sources of incidents in the system <em>and</em> on-call lives</li>
  <li>Fixing <em>recurring</em> sources of on-call friction and cognitive load</li>
</ul>

<h2 id="what-should-i-do-with-snacks">What should I do with snacks?</h2>

<p>It’s okay to snack from time to time. It breaks up the monotony of the week.
When I’m in the middle of large projects, it’s good to have a small
quick thing that I can just ship and get validation on.</p>

<p>Instead of snacking all the time, I can:</p>

<ul>
  <li>Delegate them</li>
  <li>Keep a list of snacks</li>
  <li>Block out an hour or two a week to have a snack</li>
</ul>

<h2 id="might-look-like-a-snack-but-actually-important-work">Might look like a snack, but actually important work</h2>

<p>There’s a class of work that is actually important <em>for future success</em>
but feels like a snack in the moment: researching big ideas that
could become org-wide improvements.</p>

<p>To nurture these ideas, I can:</p>

<ul>
  <li>Keep a list of pie-in-the-sky ideas</li>
  <li>Use an hour or two every week to continue the research and prototyping</li>
  <li>Sneakily <a href="https://hyperbo.la/w/nemawashi/">build consensus</a>. Get people sold on the idea, before it’s even working</li>
</ul>]]></content><author><name>Brandon Vincent</name></author><category term="Other" /><summary type="html"><![CDATA[noun (colloquial) A lot, a large amount Thanks a heap!]]></summary></entry><entry><title type="html">Ten years of deploying to production</title><link href="https://brandonvin.github.io/2026/03/04/ten-years-of-deploying-to-production.html" rel="alternate" type="text/html" title="Ten years of deploying to production" /><published>2026-03-04T00:00:00+00:00</published><updated>2026-03-04T00:00:00+00:00</updated><id>https://brandonvin.github.io/2026/03/04/ten-years-of-deploying-to-production</id><content type="html" xml:base="https://brandonvin.github.io/2026/03/04/ten-years-of-deploying-to-production.html"><![CDATA[<p>Back in 2018, where I worked there was an operations team. “Ops”, we called them.
In that decade, this company was behind the curve, but not far from typical.
We were just starting to <em>think about</em> AWS. At the tail end of my time there, we were just starting to adopt AWS for some internal-only systems.
But from what I’ve heard from friends who worked at more mature companies, it wasn’t uncommon in that era to have <em>an operations team</em> that owned production.</p>

<p>Funny thing: the ops team literally sat in a corner of the office, in their own room. That’s where ops is, in that little room. It sounds like a meme.</p>

<p>The ops team had a nice tool to spin up a VM inside the company’s infrastructure. I appreciated that – my whole team used it all the time. I needed to train <a href="https://en.wikipedia.org/wiki/Long_short-term_memory">recurrent neural networks</a> using GPUs and 20+ gigabytes of RAM. No way that was going to run on my laptop, so this workflow was invaluable to my work.</p>

<p>Here’s the big catch: production deployments happened once every two weeks. Full stop.</p>

<p>If something went wrong, the deployment had to wait another two weeks.
Unless you were lucky: if the current ops on the weekly rotation was particularly nice, and not dealing with evening plans, and if you were online to respond to their questions, you could push through and fix that random error that only happens in production.</p>

<p>From time to time, I would wander into the ops corner and chat with people about strange issues my team saw in the production database, in our latest attempt to deploy to production, and so on.</p>

<h2 id="the-production-deployment-challenge">The production deployment challenge</h2>
<p>My team was fundamentally a data science team.
We were training ML models, building and running data pipelines to collect training data and train models on the latest data.
All Python code. That’s all fine.</p>

<p>There was a big problem: the models in production were misbehaving, and customers were noticing:</p>
<blockquote>
  <p>Your API returned this classifier result. That makes no sense. Why?</p>
</blockquote>

<p>It would get sent to our team of analysts, and eventually my team to figure out. After a long back-and-forth, we’d conclude there’s probably a deficiency in the training data, the model, or business logic wrapping the model.</p>

<blockquote>
  <p>Okay, how do we fix this?
We need to fix the model, or update the business logic wrapping the model.
And then what?
We can test it and deploy it to production.
Okay, but we can’t deploy to production because only engineers and ops can do that.
What? How do they … deploy to production?
Go talk to them.</p>
</blockquote>

<p>This became my problem to solve, perhaps heroically.</p>

<p>To give you a picture of where we were at, reviewing PRs was… simply not a thing.
We worked out of GitHub repositories that were largely just snapshots of the current code. That’s great - it’s a backup of our code.
In the ideal case, we’d push to <code>master</code>, <code>ssh</code> to an internal VM, pull the code, and run it.
In the normal case, we’d <code>ssh</code> to the VM and edit things there, rerun the models, copy the code from the VM into the GitHub repository if we remember.</p>

<p>How do we build a new model and deploy it to production? Who knows. Maybe <a href="https://skamille.medium.com/opp-other-peoples-problems-d7eb174724ee">other people’s problem</a>, but that wasn’t a term I knew back then.</p>

<h2 id="the-production-deployment-solution">The production deployment solution</h2>
<p>This post isn’t about my heroism, so to keep it brief, I leaned hard into what I understood as “DevOps”:</p>
<ul>
  <li>Went and talked to the engineering teams and the ops team. Figured out how everything fits together.</li>
  <li>Learned what the heck <a href="https://www.chef.io/">Chef</a> is.</li>
  <li>Wrote and deployed an internal <a href="https://packaging.python.org/en/latest/guides/hosting-your-own-index/">PyPi repository</a> that used git tags as versions, and resolved dependencies using our internal GitHub repositories. With the support of a partner in the ops team. Not a ton of code - maybe 100 lines of Python - but deeply embedded and tough to test and deploy on my own.</li>
  <li>Established a pattern of not just pushing to <code>master</code>, but also tagging versions to release, and sometimes reviewing code in PRs before merging to <code>master</code></li>
  <li>Created a Chef recipe template for Python apps</li>
  <li>Created a Chef recipe for our Python app</li>
  <li>Deployed the thing to production, and fixed the customer’s concerns!</li>
</ul>

<h2 id="since-then">Since then</h2>
<p>Since then, I’ve spent <em>most</em> of my time the other side of the table, so to speak. Not to mention in a completely different company with different values, and a more flexible organization.</p>

<p>I’ve reflected a bit on what makes 2018 different from 2026.</p>

<h2 id="2018-production-operations-team">2018: Production Operations Team</h2>
<blockquote>
  <p>We are the production operations team.
Our mission is to protect production.</p>
</blockquote>

<p>If a developer wants a change in production, it should be possible, but we need to cover our butts.
There’s going to be a handoff from the developers to us. Make a full paper trail with tickets.</p>

<p>If production is too hard to change for a regular developer - well, that sucks, but it kind of works in our favor.
Any deviation from what’s in that ticket is - by default - a liability for us.
Nobody has time for debugging a random issue that happens “only in production”. We have lives outside of work!</p>

<p>From time to time, a hero might <a href="https://blog.danielna.com/talks/pushing-through-friction">push through the friction</a> and make a self-service path. But again, that’s a hero, and heroes are few and far between. They also might quickly move on to another company where change is easier.</p>

<h2 id="2026-platform-engineering-team">2026: Platform Engineering Team</h2>
<blockquote>
  <p>Our mission is to accelerate development and make production resilient.</p>
</blockquote>

<p>Developer experience has to be smooth.
CI/CD has to be quick.
If a developer is ever waiting for CI or CD, treat that as a mini-incident.</p>

<p>When a problem is discovered in production, it should be obvious what the problem was, and the internal signals <em>for developers</em> should make it easy to diagnose and fix.</p>

<p>It still feels early to be prescriptive on the <em>how</em> and <em>what</em>, so it’s worth another post in the future.</p>]]></content><author><name>Brandon Vincent</name></author><category term="Other" /><summary type="html"><![CDATA[Back in 2018, where I worked there was an operations team. “Ops”, we called them. In that decade, this company was behind the curve, but not far from typical. We were just starting to think about AWS. At the tail end of my time there, we were just starting to adopt AWS for some internal-only systems. But from what I’ve heard from friends who worked at more mature companies, it wasn’t uncommon in that era to have an operations team that owned production.]]></summary></entry><entry><title type="html">Thank you, Chad Baldwin!</title><link href="https://brandonvin.github.io/2024/10/27/thank-you-chad.html" rel="alternate" type="text/html" title="Thank you, Chad Baldwin!" /><published>2024-10-27T00:00:00+00:00</published><updated>2024-10-27T00:00:00+00:00</updated><id>https://brandonvin.github.io/2024/10/27/thank-you-chad</id><content type="html" xml:base="https://brandonvin.github.io/2024/10/27/thank-you-chad.html"><![CDATA[<p>Chad Baldwin made an excellent
<a href="https://chadbaldwin.net/2021/03/14/how-to-build-a-sql-blog.html">blog post</a>
about how to start a blog using GitHub pages.</p>

<p>I stumbled upon that today and thought dang, that looks
like something I can try in about 15 minutes… let me go make a cup of tea.
And here it is!</p>

<p>Thank you, Chad.</p>

<p>More coming soon.</p>]]></content><author><name>Brandon Vincent</name></author><category term="Other" /><summary type="html"><![CDATA[Chad Baldwin made an excellent blog post about how to start a blog using GitHub pages.]]></summary></entry></feed>