<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
    <channel>
      <title>Chris Dickinson</title>
      <link>https://www.neversaw.us</link>
      <description></description>
      <generator>Zola</generator>
      <language>en</language>
      <atom:link href="https://www.neversaw.us/rss.xml" rel="self" type="application/rss+xml"/>
      <lastBuildDate>Thu, 26 Mar 2026 00:00:00 +0000</lastBuildDate>
      <item>
          <title>you have to know what to wish for</title>
          <pubDate>Thu, 26 Mar 2026 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://www.neversaw.us/2026/03/26/you-have-to-know-what-to-wish-for/</link>
          <guid>https://www.neversaw.us/2026/03/26/you-have-to-know-what-to-wish-for/</guid>
          <description xml:base="https://www.neversaw.us/2026/03/26/you-have-to-know-what-to-wish-for/">&lt;h1 id=&quot;you-have-to-know-what-to-wish-for&quot;&gt;you have to know what to wish for&lt;&#x2F;h1&gt;
&lt;p&gt;Last month, someone high up at &lt;code&gt;$dayjob&lt;&#x2F;code&gt; said that we should treat any line of
code written by hand as a failure.&lt;&#x2F;p&gt;
&lt;p&gt;This hit me like a ton of bricks, to be honest. What does it mean to be a
software engineer without writing code? Is this the end of software engineering?&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Let’s define terms.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pages.cs.wisc.edu&#x2F;~remzi&#x2F;Naur.pdf&quot;&gt;&lt;strong&gt;Programming&lt;&#x2F;strong&gt; is theory building&lt;&#x2F;a&gt;, as Peter Naur remarked. The job of
the programmer is to build and maintain a mental model of the problem space the
system they develop is written against. There’s a feedback loop there in the
small: the programmer writes a program to solve a problem, and learns more about
the program and its environment when they run the program&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Change, edit, crash, swear, learn, repeat.&lt;&#x2F;p&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;1&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;Excelsior! Chris wrote a bit about tests as feedback loops for
interrogating systems in the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.neversaw.us&#x2F;2026&#x2F;02&#x2F;20&#x2F;testing-one-two&#x2F;&quot;&gt;last post&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;With luck, eventually the program does what the programmer intended. The
programmer walks away changed from the experience. They know avenues not to
explore, patterns to match on that let them skip steps, maybe something
interesting about their tools. Writing the code changed their mental model of
the program.&lt;&#x2F;p&gt;
&lt;p&gt;This understanding, not the code, is the thing of value.&lt;&#x2F;p&gt;
&lt;p&gt;The programmer could write documentation about the program, but their exact
understanding at that moment &lt;em&gt;cannot be captured in full&lt;&#x2F;em&gt;. This is what Naur is
talking about: the programmer has a theory of the system, developed in concert
with that system. That theory is a mental model, a map of the system, problem
space, and how it might react to changes in the future.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Software Engineering&lt;&#x2F;strong&gt; is the act of building a socio-technical system that
promulgates that theory to a group of people – &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;research.swtch.com&#x2F;vgo-eng&quot;&gt;“engineering is programming
integrated over time”&lt;&#x2F;a&gt; &lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#2&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;. This is to say, the goal of software
engineering as an organizational capability is to model the problem domain and
current solution, keep &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;agilemanifesto.org&#x2F;principles.html&quot;&gt;multiple people&lt;&#x2F;a&gt; &lt;em&gt;in alignment&lt;&#x2F;em&gt; on that
definition, and use that understanding to integrate changes from the business.&lt;&#x2F;p&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;2&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;2&lt;&#x2F;sup&gt;
&lt;p&gt;Quoting Russ Cox quoting Titus Winters. Programming is also learning to
dereference references!&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;Just as programmers anneal their theory of the system by changing programs to
understand the effect of their changes; software engineering manages concurrent
theories of the program held by everyone involved in changing, building, and
shipping the software: product managers, engineering managers, executives,
marketing, sales, etc., in addition to the engineers themselves. The goal is to
align all of these different ways of understanding the system.&lt;&#x2F;p&gt;
&lt;p&gt;This is, of course, impossible&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#3&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;. But trying matters:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;EVERY GOOD REGULATOR OF A SYSTEM MUST BE A MODEL OF THAT SYSTEM&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pespmc1.vub.ac.be&#x2F;books&#x2F;Conant_Ashby.pdf&quot;&gt;Roger C. Conant&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;This comes to us from the field of cybernetics. Here, a “regulator of a system”
is an entity which, given a set of inputs into a closed system which may produce
a number of outputs, a subset of which are desirable, takes action to steer the
system towards desirable output. The theorem says that a good regulator is a
model of the system under regulation – a homomorphism, potentially lacking the
detail of the full system. Air traffic control models planes into the airspace
around an airport for the purposes of routing and sequencing, but lacks the full
detail of the airport being modeled: what is the temperature inside the gate? Is
the nearby river hosting migratory geese? What is the status of the airport
Chili’s (TM)?&lt;&#x2F;p&gt;
&lt;p&gt;Bad regulation increases the entropy of the system, destabilizing it: if air
traffic control doesn’t model the geese, they might not be able to account for
bird strikes.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Organizations which design systems (in the broad sense used here) are
constrained to produce designs which are copies of the communication
structures of these organizations.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.melconway.com&#x2F;Home&#x2F;Committees_Paper.html&quot;&gt;Melvin E. Conway&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Systems reflect the communication structure of their respective organizations
because of the positive pressure of the good regulator theorem. Systems which
don’t reflect their organizations tend not to be stable, even over a short run.
Either the system produces incentive to align the organization around it, or the
system fails spectacularly.&lt;&#x2F;p&gt;
&lt;p&gt;In either case: software engineering is the capability to translate the desired
state of a product system into reality, integrating it with the current theory
of that system. Information doesn’t flow one-way: engineering and product
management are always in productive conflict, pushing each other back and forth
on the effect of changes to the system. And in the middle is the theory of the
program: this conflict is only ever as productive as their models of the system
are accurate.&lt;&#x2F;p&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;3&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;3&lt;&#x2F;sup&gt;
&lt;p&gt;I say alignment is impossible, but take this in the sense that
there’s no such thing as perfect communication. A listener always receives
something different than what a speaker has in their head: the act of communicating
quantizes the information to be transferred.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;I want to note that, as humans, we live and die by our ability to abstract. We
cannot hold perfect models of the world. We are always navigating through
assumptions and missing information. “Making a mental model” doesn’t mean making a
perfect model. We’re constantly updating those models as we find out new
information (or as we find out we don’t need to &lt;em&gt;remember&lt;&#x2F;em&gt; specifics.)&lt;&#x2F;p&gt;
&lt;p&gt;And this is true of how we think about other organizational roles: we hold a
cartooned, simplified version of other jobs in our head. A manager’s job is to
manage, but what does that look like from the point of view of an engineer&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#4&quot;&gt;4&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;? A
product manager works to define what the product needs. A designer builds how
the product feels – visually, primarily, but on other axes as well. These are
tiny definitions for whole careers worth of details!&lt;&#x2F;p&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;4&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;4&lt;&#x2F;sup&gt;
&lt;p&gt;As an engineer who has bounced through management: it looks like a
completely different set of (complementary) skills, and a lot less control
over specific outcomes than you’d think.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;Every role carries its own frame with respect to the system the organization
manages. The frame the role carries determines the problems and opportunities it
can see – what is &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.bitsaboutmoney.com&#x2F;archive&#x2F;seeing-like-a-bank&#x2F;&quot;&gt;legible&lt;&#x2F;a&gt; to it.&lt;&#x2F;p&gt;
&lt;p&gt;And so, when I say that product and engineering have a productive conflict: it
is because engineering can see things that product can’t, and product can see
things that engineering can’t. And there is a &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;blog.ceejbot.com&#x2F;posts&#x2F;future-shock&#x2F;&quot;&gt;career’s worth&lt;&#x2F;a&gt; of details
involved in building either of those frames.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Software engineering is the function of an organization that assimilates change
into the existing software system. Historically, it’s been the function
responsible for translating that change into specifics, and communicating out
the cost of those specifics.&lt;&#x2F;p&gt;
&lt;p&gt;But we’re &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.thoughtworks.com&#x2F;content&#x2F;dam&#x2F;thoughtworks&#x2F;documents&#x2F;report&#x2F;tw_future%20_of_software_development_retreat_%20key_takeaways.pdf&quot;&gt;in a mechanized world&lt;&#x2F;a&gt; now. Roles are &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;claude.com&#x2F;blog&#x2F;product-management-on-the-ai-exponential&quot;&gt;bleeding
over&lt;&#x2F;a&gt;. The cost of bespoke, one-off software has dropped to zero. The
genie is here to grant your wishes.&lt;&#x2F;p&gt;
&lt;p&gt;The genie warps the cost of everything in software engineering. It’s as if
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=rC2VQ-oyDG0&quot;&gt;space-time itself&lt;&#x2F;a&gt; has warped. Think of a map: there is a coffee
shop 20 minutes away by foot. Now imagine the genie installs a pneumatic tube
that transports you 100 miles away to another coffee shop and back in 10
minutes. That 100-mile-distant coffee shop is now &lt;em&gt;closer&lt;&#x2F;em&gt; to you, temporally,
than the one down the block.&lt;&#x2F;p&gt;
&lt;p&gt;What’s more, everyone gets a lamp. Anyone can generate a program now. Bespoke
software is commoditized. Generating or re-generating an entire working program
is as simple as prompting. The less you care about the implementation – or
keeping that implementation working in the face of change – the broader you can
be about the prompt.&lt;&#x2F;p&gt;
&lt;p&gt;That said, what you say to the genie matters. A lot. If you don’t know to avoid
certain problems, the genie will not tell you that you should think about
including a solution for them. The genie uses your frame, for better or worse.&lt;&#x2F;p&gt;
&lt;p&gt;And the genie understands the world anew every time you wish. It reads
documentation it left behind, sure, but as we established, that is not the same
thing as the theory of the program. So it’s still on the person who rubbed the
lamp to understand the implications of their wishes; even more so on the
compounding results of those wishes.&lt;&#x2F;p&gt;
&lt;p&gt;So the problem remains, but the means have changed.&lt;&#x2F;p&gt;
&lt;p&gt;Programming is no longer the foundational practice of software engineering.&lt;&#x2F;p&gt;
&lt;p&gt;That is: the work of software engineering has fled from the act of programming
both to the left side of the process – definitional work (“how do we define
this problem and how do we wish to solve it”) – and to the right
side – verification work and risk assessment (“is this implementation correct and
what will happen if we’re wrong?”)&lt;&#x2F;p&gt;
&lt;p&gt;The middle of the problem is where a lot of us engineers have spent most of our
careers. It’s where we developed our understanding of software systems in the
first place and where we hone our ability to change them. Former colleague
Laurie Voss calls this kind of engineer a &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.linkedin.com&#x2F;posts&#x2F;seldo_i-have-always-been-the-kind-of-developer-activity-7438760039143878656-NW0C?utm_source=share&amp;amp;utm_medium=member_desktop&amp;amp;rcm=ACoAAAMWH5wB1wjOC8gdjp4mQOOfiF-SzzR9YTU&quot;&gt;“craftsperson”&lt;&#x2F;a&gt;: focused on
the means instead of the outcome.&lt;&#x2F;p&gt;
&lt;p&gt;I think of this work-in-the-middle in terms of “feedback from the medium”: I
understand programs better by changing them; I find seams in them that suggest
future changes, lines along which to cut, and the process of getting my
fingerprints on a codebase makes it more real to me&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#6&quot;&gt;5&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;6&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;5&lt;&#x2F;sup&gt;
&lt;p&gt;It is &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.neversaw.us&#x2F;2022&#x2F;01&#x2F;30&#x2F;the-canvas-cares-not&#x2F;#finding-one-s-voice&quot;&gt;practice&lt;&#x2F;a&gt;, in other words.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;I would venture a guess that my “craftspeople” feel similarly. Being asked to
change or understand a program &lt;em&gt;without programming it&lt;&#x2F;em&gt; feels like removing
one’s proprioception: like floating in a sensory deprivation tank. The
impressions you get of the codebase are unmoored. You have to build up a new set
of reflexes to grasp the bottom of the pool.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;But it is possible to build up that sense again. It feels different. The details
still matter, but how you come to understand those details changes. I spend a
lot more time walking the codebase with Claude and testing my assumptions there.
Being able to communicate &lt;em&gt;how&lt;&#x2F;em&gt; to visualize code becomes way more important: I
ask the genie for maps of the system from different angles, rendered in
graphviz. Claude can put things that were tedious bookkeeping (git blame
histories) more directly at hand&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#7&quot;&gt;6&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;7&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;6&lt;&#x2F;sup&gt;
&lt;p&gt;And Claude can steer my editor while I walk this path, which is possible
because I knew that neovim supports a socket interface and that Claude can
self-discover how to control it to write a skill. This is trivia!)&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;So the details still matter. In fact, the &lt;em&gt;trivia&lt;&#x2F;em&gt; is more powerful, because the
genie only grants wishes as well as you’re able to frame the wish. If you can
think of novel ways to combine existing concepts, you’re getting a different
value from the genie than someone else would.&lt;&#x2F;p&gt;
&lt;p&gt;From a language perspective, it’s a lot of fun to hack with: I’ve noticed that
my plans are executed more successfully when I run them through a &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;grugbrain.dev&#x2F;&quot;&gt;grug&lt;&#x2F;a&gt; style
filter, for example&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#8&quot;&gt;7&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;8&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;7&lt;&#x2F;sup&gt;
&lt;p&gt;Semantic quantization, probably: “I dislike ternaries” becomes “grug hate
ternaries. hit with club”.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;But this is a manic “the sky is falling” sort of fun. I return to the question.
Is software engineering a viable career if you take out the programming?&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;em&gt;frame&lt;&#x2F;em&gt; you spent years developing is more valuable than ever: you are
capable of regulating these tools safely because &lt;strong&gt;you are a model of how they
operate&lt;&#x2F;strong&gt;. The new software engineering looks a lot like the old. It values most
of the same things in the large: exploration, trivia, model-building. It
amplifies your ability to build the theory of the program.&lt;&#x2F;p&gt;
&lt;p&gt;So, does hand-written code represent a failure? &lt;em&gt;Well, …&lt;&#x2F;em&gt; no. At least, I
wouldn’t call it a failure. But treating it as such is a useful forcing
function. It’s just not &lt;em&gt;required&lt;&#x2F;em&gt; anymore. Where it helps you develop a better
model of the program, it’s arguably more worthwhile than ever.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;small&gt;
&lt;p&gt;Thanks to &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;mastodon.social&#x2F;@ceejbot&quot;&gt;@ceejbot&lt;&#x2F;a&gt; for reviewing a draft of this post!&lt;&#x2F;p&gt;
&lt;&#x2F;small&gt;
</description>
      </item>
      <item>
          <title>testing, one two</title>
          <pubDate>Fri, 20 Feb 2026 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://www.neversaw.us/2026/02/20/testing-one-two/</link>
          <guid>https://www.neversaw.us/2026/02/20/testing-one-two/</guid>
          <description xml:base="https://www.neversaw.us/2026/02/20/testing-one-two/">&lt;h1 id=&quot;testing-your-patience&quot;&gt;testing your patience&lt;&#x2F;h1&gt;
&lt;p&gt;Welcome back to the last blog at the end of software engineering. Pull up a
stool. I’m here to give you my take on testing.&lt;&#x2F;p&gt;
&lt;p&gt;Wait, wait, don’t go. I promise, it’s worth reading. I typed these words by
hand.&lt;&#x2F;p&gt;
&lt;p&gt;Why would testing be an important topic now, of all times, especially
considering how many of us are likely using tools to &lt;em&gt;generate&lt;&#x2F;em&gt; our test suites
and those same tools to &lt;em&gt;generate&lt;&#x2F;em&gt; fixes to said test suites?&lt;&#x2F;p&gt;
&lt;p&gt;Well, strawperson, I would argue that tests are more important now than they
have been for a long time.&lt;&#x2F;p&gt;
&lt;p&gt;You have two feedback loops available to you. You can get feedback from your
users: they can tell you your program is broken explicitly, if you’re lucky. If
you’re unlucky, they’ll tell you this implicitly by not using your product.&lt;&#x2F;p&gt;
&lt;p&gt;Tests are your other feedback loop. They’re the cheap one. Good tests will tell
you something about your system as it changes. They give you confidence that a
change to one part of your system won’t set the other parts on fire. Tests keep
your generative coding tools on track.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Let’s back up for a second to talk about what a test suite actually &lt;em&gt;is&lt;&#x2F;em&gt;: I find
that most developers I talk to think of a test suite as an ancillary component
of their program. Tests are a property of the important code in the code base:
you might talk about “a module &lt;em&gt;and its tests&lt;&#x2F;em&gt;”. The codebase is mostly about
their shipped program, application, or service. Tests say whether that program
is “Of Kwalitee”. I mean, “Of Quality”.&lt;&#x2F;p&gt;
&lt;p&gt;To which I say: look again! Each test case you build &lt;em&gt;is a program&lt;&#x2F;em&gt; unto itself!&lt;&#x2F;p&gt;
&lt;p&gt;This is less apparent in VM languages like Python, Ruby, JS, or Java. Compiled
languages make this explicit: Rust and C++ tests are compiled into their own
binaries and run via a harness. So you’re not shipping one program, you’re
shipping (potentially) hundreds of programs. And the codebase really contains a
system whose internal interfaces can be used to assemble these programs, one of
which actually happens to be your production application.&lt;&#x2F;p&gt;
&lt;p&gt;The goal of the other 100 programs is to tell you what happens as a result of
your changes to another part of that system before a user tells you. If this is
designed well, failures in your test suite help you track down &lt;em&gt;which&lt;&#x2F;em&gt; invariant
your changes violated. When designed poorly, test suites tell you only that
&lt;em&gt;something in your system changed&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;You usually see this when the tests &lt;em&gt;over-specify&lt;&#x2F;em&gt; behavior based on internal
interfaces. This falls out of treating tests as an afterthought: new components
each get a suite of tests. As new components are added suites of tests for new
components overlap the old: in order to pass both sets of tests the components
must behave &lt;em&gt;exactly&lt;&#x2F;em&gt; as originally implemented, including their &lt;em&gt;internal
structure&lt;&#x2F;em&gt;. The overlap violates modularity, in other words.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Instead…&lt;&#x2F;p&gt;
&lt;p&gt;Think of your implemented system as a directed graph. A step abstracted from a
control flow graph, but more concrete than a UML diagram. The nodes represent
some business logic happening, and the edges between those nodes are interfaces
for calling and returning values. Something like this:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;www.neversaw.us&#x2F;static&#x2F;img&#x2F;00-graph.png&quot; alt=&quot;A directed graph of an API system showing a system of objects; with multiple entry points defined by HTTP REST endpoints passing through an auth middleware on to a layer of user and item services, and then on to database, permissions, and an external catalog.&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;When you test, you pick some entry and exit interfaces to test, and in doing so
you end up executing a sub-graph of the system under test. I am going to refer
to this sub-graph as the “gamut” of your test, in its sense of “complete range
or scope of a thing.”&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;www.neversaw.us&#x2F;static&#x2F;img&#x2F;01-highlighted.png&quot; alt=&quot;The same graph now shows the middleware as a dominator node, with the mock boundary at an external Catalog API&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Writing an effective test suite means thinking about how the gamut of each test
relates to those around it.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Write tests. Not too many. Mostly integration.&lt;&#x2F;p&gt;
&lt;p&gt;~ &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Heartbreaking:_The_Worst_Person_You_Know_Just_Made_a_Great_Point&quot;&gt;Guillermo
Rauch&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;You might be accustomed to thinking of tests that have a narrow gamut as “unit
tests”, and those with a wider gamut as “integration tests.” To this, I’d say:
“yes, and!”&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Yes, and&lt;&#x2F;em&gt; these specific terms imply a frame of reference. From the frame of
reference of your system, you might be running a unit test of a single free
function. But if your system is a Python application, from the perspective of
the Python interpreter, you’re running a pretty broad &lt;em&gt;integration&lt;&#x2F;em&gt; test of the
language runtime. (I don’t love these terms for this reason: the definition of
“unit” depends on whose ruler you’re using.)&lt;&#x2F;p&gt;
&lt;p&gt;That being said.&lt;&#x2F;p&gt;
&lt;p&gt;When designing tests, you’re looking to identify interfaces which are &lt;em&gt;unlikely
to change frequently&lt;&#x2F;em&gt; and which cover meaningful swaths of application
behavior.&lt;&#x2F;p&gt;
&lt;p&gt;Dominance in a graph describes the property of “flow” through a node with
respect to an entry point&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;. If all paths from an entry point node &lt;em&gt;must pass&lt;&#x2F;em&gt;
through a given node to reach downstream nodes, that node is said to &lt;em&gt;dominate&lt;&#x2F;em&gt;
the downstream nodes.&lt;&#x2F;p&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;1&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;Dominance originated in a paper on the analysis of &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;dl.acm.org&#x2F;doi&#x2F;epdf&#x2F;10.1145&#x2F;1460299.1460314&quot;&gt;flow diagrams&lt;&#x2F;a&gt;.
It has been a useful concept in compiler research, in particular &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.cs.wustl.edu&#x2F;~cytron&#x2F;cs531&#x2F;Resources&#x2F;Papers&#x2F;valnum.pdf&quot;&gt;static single
assignment&lt;&#x2F;a&gt; form.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;This is the property you are looking to build tests around. This lets you
“cover” many internal interfaces while starting all of your tests at the same
point. If you’re building a REST API, you’ll usually see this along the
HTTP endpoints you define. If you’re building a React app, you’ll find this
along pages and in &lt;em&gt;commonly used components&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;These dominators help design your test suite: you can take that and walk from
the smallest sub-graph with the most overlap – like authentication in an API –
out to tests that depend on larger swaths of the system working in concert. My
druthers is to number these, like I’m building a proof of the system: if
&lt;code&gt;01-authentication&lt;&#x2F;code&gt; fails, I know I can safely ignore errors from
&lt;code&gt;08-frobnicate&lt;&#x2F;code&gt; until I’ve resolved them.&lt;&#x2F;p&gt;
&lt;p&gt;I’ve talked about picking which interface to &lt;em&gt;start&lt;&#x2F;em&gt; a test’s gamut. Mocks are a
complementary, inverse tool for determining a test’s gamut. They artificially
&lt;em&gt;limit&lt;&#x2F;em&gt; the test’s gamut. Mocks &lt;em&gt;require&lt;&#x2F;em&gt; knowledge of the internal interfaces.&lt;&#x2F;p&gt;
&lt;p&gt;This can be fine: mocking implies knowledge external to the program about
whether the interface is likely to change: you might know that the interface to
an external API you’re using will not change. You might know that contract-based
tests are in place. You might know where the person providing that interface
sits in the office and you might be within throwing distance of them.&lt;&#x2F;p&gt;
&lt;p&gt;But you’ve got to be careful: the goal of picking complementary dominators and
testing them in order is to build a proof of the system that avoids leaning on
internal interfaces. The act of using mocks pins internal interfaces.&lt;&#x2F;p&gt;
&lt;p&gt;Be deliberate about the interfaces you pick to use in your test suite. It’s
worth sweating the details. You will produce a crisp definition of what it means
for the system under test to fail. These failures will have better context: why
is the failure important, what does it affect, and where did it happen first,
&lt;em&gt;approximately&lt;&#x2F;em&gt;? And more context will help your agent to avoid spinning itself
in circles trying to fix over-specified tests: you can trust that it won’t
resolve the issue by rewriting the test.&lt;&#x2F;p&gt;
&lt;p&gt;And that’s the end of my spiel. Aren’t you glad you sat down to read this while
your agent finished writing your tests? Go tell them to pull up a stool and read
this article, too.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>&quot;The Economics of Programming Languages - Evan Czaplicki&quot;</title>
          <pubDate>Mon, 09 Oct 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://www.neversaw.us/links/the-economics-of-programming-languages-evan-czaplicki/</link>
          <guid>https://www.neversaw.us/links/the-economics-of-programming-languages-evan-czaplicki/</guid>
          <description xml:base="https://www.neversaw.us/links/the-economics-of-programming-languages-evan-czaplicki/">&lt;p&gt;Evan Czaplicki, creator of Elm, lays out a compelling explanation for the
economics of programming languages: what work goes into creating a new language
and ecosystem? How is that paid for? By whom and for what purposes?&lt;&#x2F;p&gt;
&lt;p&gt;You should watch it.&lt;&#x2F;p&gt;
&lt;p&gt;I want to add something about the corporate languages he lists under “rewarding talent.” In particular, Evan
points out both Dart and Golang as the result of rewarding engineering effort.
While I there’s some truth in Evan’s conclusion that the engineers behind these
languages were rewarded for their contributions, I don’t think that’s the whole
picture.&lt;&#x2F;p&gt;
&lt;p&gt;Google was (and maybe still is!) deeply invested in the Java ecosystem. Oracle
acquired Sun in 2010 and filed suit against Google shortly after, but the
writing was on the wall for Sun years earlier. I suspect Golang was a hedge
against Java use at Google. Google needed a language which could fill a similar
niche as Java: similar (or better) performance characteristics, garbage
collected, and straightforward to deploy. It also needed to be easy to teach &amp;amp;
relatively opinionated: it would be a shift from the Java taught at
universities (and from where Google sources a lot of its incoming talent), so
it needed to scale well to newcomers. Google announced Golang in 2009, a year
ahead of the Oracle Sun acquisition and subsequent lawsuit. Rob Pike was a
known quantity who had, as Evan points out, already meaningfully contributed to
the bottom line of the company and had proven language design and documentation
chops.&lt;&#x2F;p&gt;
&lt;p&gt;Less obvious, I think, is where Dart fits into all of this. I still wonder at
it myself a little bit! In 2011, it looked as if Google had put together an
all-star team to speed up JavaScript and — once they had accomplished
that goal — turned around and &lt;em&gt;gave up&lt;&#x2F;em&gt; on JS. However, backing up from
that: Dart made sense as a hedged bet against JS, whose spec had only &lt;em&gt;just&lt;&#x2F;em&gt;
started progressing in 2009 after ten years of stagnation. While Node.js had
introduced a working module system for the language in 2010, bundlers that
utilized that module format wouldn’t arrive until 2011 with Browserify.
Finally, as part of the Sun acquisition, Oracle had &lt;em&gt;also&lt;&#x2F;em&gt; acquired the
JavaScript trademark. During the time Dart was developed, it was by no means
certain that JavaScript would rise to its contemporary adoption levels.&lt;&#x2F;p&gt;
&lt;p&gt;All of that is to say: while there was an element of “reward” behind both Golang
and Dart, both language efforts &lt;em&gt;also&lt;&#x2F;em&gt; made strategic sense for Google.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Understanding Wasm, Part 3: You Are Here</title>
          <pubDate>Mon, 04 Sep 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://www.neversaw.us/2023/09/04/understanding-wasm/part3/you-are-here/</link>
          <guid>https://www.neversaw.us/2023/09/04/understanding-wasm/part3/you-are-here/</guid>
          <description xml:base="https://www.neversaw.us/2023/09/04/understanding-wasm/part3/you-are-here/">&lt;h1 id=&quot;understanding-wasm&quot;&gt;Understanding Wasm&lt;&#x2F;h1&gt;
&lt;h2 id=&quot;part-3-you-are-here&quot;&gt;Part 3: You Are Here&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;em&gt;(This is part 3 of a series. See &lt;a href=&quot;https:&#x2F;&#x2F;www.neversaw.us&#x2F;2023&#x2F;05&#x2F;10&#x2F;understanding-wasm&#x2F;part1&#x2F;virtualization&#x2F;&quot;&gt;part 1, “Virtualization”&lt;&#x2F;a&gt; and &lt;a href=&quot;https:&#x2F;&#x2F;www.neversaw.us&#x2F;2023&#x2F;06&#x2F;30&#x2F;understanding-wasm&#x2F;part2&#x2F;whence-wasm&#x2F;&quot;&gt;part 2, “Whence Wasm”&lt;&#x2F;a&gt;.)&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;If WASM+WASI existed in 2008, we wouldn’t have needed to create Docker.
That’s how important it is. WebAssembly on the server is the future of
computing. A standardized system interface was the missing link. Let’s hope
WASI is up to the task!&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Solomon Hykes via &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;solomonstre&#x2F;status&#x2F;1111004913222324225?lang=en&quot;&gt;twitter&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;When we left off last time, we were just about to dig into what &lt;strong&gt;“Operating
System Support”&lt;&#x2F;strong&gt; might mean for a virtual instruction set architecture. Solomon
Hykes claimed that if WASI —the WebAssembly System Interface— had
existed in 2008, he and his companions at dotCloud&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#docker-ref&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; wouldn’t have had
to invent Docker. Given the accomplishments of Docker over the last decade,
that’s pretty wild!&lt;&#x2F;p&gt;
&lt;p&gt;To understand what a “standardized system interface” might do for us, I wanted
to first understand &lt;em&gt;system interfaces&lt;&#x2F;em&gt;— how we virtualize them, how they
came to be, and how they help us work together.&lt;&#x2F;p&gt;
&lt;p&gt;Does WASI represent a bridge to the future for existing applications, or a
destination?&lt;&#x2F;p&gt;
&lt;p&gt;To understand the future of computing, let’s look at its past.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;processes-and-virtual-machines&quot;&gt;Processes and Virtual Machines&lt;&#x2F;h2&gt;
&lt;p&gt;Processes are a universal abstraction in modern operating systems. They
comprise three capabilities:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;A continuous view of processing resources&lt;&#x2F;strong&gt; that initially includes a
single advancing program state with the ability to spawn additional,
concurrent states against the same program within the process
(&lt;strong&gt;“threads”&lt;&#x2F;strong&gt;.)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;A contiguous address namespace&lt;&#x2F;strong&gt;, into which memory may be allocated by
the operating system upon request. This initially contains the program
instructions (or &lt;strong&gt;“text”&lt;&#x2F;strong&gt;), environment variables and arguments, read-only
(or &lt;strong&gt;“static”&lt;&#x2F;strong&gt;) data, space reserved for structures to be initialized at
startup (“block starting symbol”, or &lt;strong&gt;“bss”&lt;&#x2F;strong&gt;&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#bss&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;), and
room for a “stack” of activation frames. A number of system libraries may
also be loaded by the operating system into this address space.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;A system interface&lt;&#x2F;strong&gt;, made available through a set of supervisory calls
(&lt;strong&gt;“system calls”&lt;&#x2F;strong&gt;.) Typically this is implemented through use of dedicated
&lt;code&gt;syscall&lt;&#x2F;code&gt; or system interrupt instructions (e.g., &lt;code&gt;int 0x80&lt;&#x2F;code&gt;, in x86 assembly)
available through the instruction set architecture. The use of supervisory
calls is dictated through calling conventions, including what registers must
be saved, where parameters to the syscall are placed—in memory or on registers— and how results are
retrieved after control returns to the process thread. These conventions
describe an “application binary interface”, or &lt;strong&gt;“ABI”&lt;&#x2F;strong&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;This is a &lt;em&gt;virtual&lt;&#x2F;em&gt; view of the physical machine’s resources: an “extended
machine”&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#hey&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;. The operating system is responsible for enforcing the illusion
that each process operates with independent, full access to the system’s
resources. This illusion is constructed through the operating system’s careful
orchestration of the machine’s processor features — the
processor’s memory mapping hardware, interrupts and traps, mode and protection
rings, and use of privileged instructions.&lt;&#x2F;p&gt;
&lt;p&gt;As widespread as the concept of a process is today, it wasn’t always so:
processes and operating systems emerged &lt;em&gt;alongside&lt;&#x2F;em&gt; virtual machines in the
’60s.&lt;&#x2F;p&gt;
&lt;p&gt;Hardware and software design were, at the start of the 1960s, intertwined. It
was common practice to design parallel computers —those with a number of
processors— by assigning a program to each processor, along with a range
of physical memory to be accessed &lt;em&gt;by&lt;&#x2F;em&gt; that processor. If, during development,
programmers discovered that &lt;em&gt;one&lt;&#x2F;em&gt; process on the system needed additional
space, all other processes had to be reprogrammed to accommodate the new memory
partitions. Similarly, if one process went idle, no other processes could make
use of that idle processor hardware. Programs had to be submitted in batches in
order to maximize utilization of the hardware. Time-sharing systems would
change that.&lt;&#x2F;p&gt;
&lt;iframe width=&quot;640&quot; height=&quot;480&quot;
src=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;embed&#x2F;Q07PhW5sCEk?si=LAZO7ozHwlvegUlr&quot;
title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay;
clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot;
allowfullscreen&gt;&lt;&#x2F;iframe&gt;
&lt;p&gt;In 1961, DARPA, newly flush with cash&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#gagarin&quot;&gt;4&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;, funded research on time-sharing operating
systems through “Project MAC”&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#mac&quot;&gt;5&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;. MIT, a participating member, brought their
“Compatible Time Sharing System” (&lt;strong&gt;“CTSS”&lt;&#x2F;strong&gt;&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#its&quot;&gt;6&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;) with them, and along with
Bell Laboratories and General Electric, began work on a successor system called
“MULTICS”.&lt;&#x2F;p&gt;
&lt;p&gt;That term we introduced earlier, “extended machine”, originated from this work.
It described a machine that was “easier to program” than the underlying
physical machine. The role of a “monitor” (or “nucleus”, or “kernel”) was to
support these extended machines by using the “bare machine interface”, or
hardware, directly. The monitor scheduled user programs to minimize costly idle
time.&lt;&#x2F;p&gt;
&lt;p&gt;The extended machine typically supported virtual memory, supervisory calls, and
protection rings. Virtual memory was developed so that programs could be
written in isolation, without advance knowledge of other programs running on
the system.&lt;&#x2F;p&gt;
&lt;p&gt;This was accomplished by introducing indirection: the address namespace of a
program no longer mapped directly to the physical address space of memory.
Three techniques were used to accomplish this indirection: paging,
segmentation, or the combination of the two.&lt;&#x2F;p&gt;
&lt;details&gt;
&lt;summary&gt;Expand for more on virtual memory&amp;hellip;&lt;&#x2F;summary&gt;
&lt;p&gt;With paging, both the process and physical address space are subdivided into
“pages” of memory. Each page represented several hundred “words” of
memory&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#words&quot;&gt;7&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;. Accesses to “non-resident” pages in process address space
trigger hardware faults. The kernel sets traps for those faults: the fault
transfers control to the kernel, which takes action to load the missing page
into physical memory to complete the mapping. Control transfers back to the
process at this point&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#tricks&quot;&gt;8&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.neversaw.us&#x2F;img&#x2F;virtual-memory-paging.png&quot;&gt;&lt;img width=&quot;640&quot; src=&quot;https:&#x2F;&#x2F;www.neversaw.us&#x2F;img&#x2F;virtual-memory-paging.png&quot; alt=&quot;Illustration from &amp;quot;Segmentation and the Design of Multiprogrammed Systems&amp;quot;, Jack B. Dennis, 1965&quot; &#x2F;&gt;&lt;&#x2F;a&gt;
&lt;sup&gt;Illustration from &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;dl.acm.org&#x2F;doi&#x2F;pdf&#x2F;10.1145&#x2F;321296.321310&quot;&gt;“Segmentation and the Design of Multiprogrammed Systems”&lt;&#x2F;a&gt;, Jack B. Dennis, 1965. “N” represents the process address namespace, “M” the physical namespace. Note how the contiguous “N” namespace maps to a discontiguous namespace in “M”.&lt;&#x2F;sup&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Memory segmentation was also used to support virtual memory. Segmentation has
the advantage of allowing larger address namespaces than the native computer
word size would otherwise be capable of representing. Consider that a 16-bit
word can only represent values from 0 to 65535. One popular segmentation scheme
addresses 20-bit values. It accomplishes this by holding another 16-bit value
in a “segment register”, shifting it left by 4 bits (multiplying it by 16) and
adding the resulting value to the base offset held in the operand register.
This allows addressing up to 1MiB of memory. When the segment register changes,
the entire segment of memory is made resident at once — which could be a
single word of memory or a significant subset of physical memory. Some hardware
supports transferring control to the kernel when the segment register changes,
which allows the implementation of virtual memory purely through segmentation.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.neversaw.us&#x2F;img&#x2F;virtual-memory-segmentation.png&quot;&gt;&lt;img width=&quot;640&quot; src=&quot;https:&#x2F;&#x2F;www.neversaw.us&#x2F;img&#x2F;virtual-memory-segmentation.png&quot; alt=&quot;Illustration from &amp;quot;Segmentation and the Design of Multiprogrammed Systems&amp;quot;, Jack B. Dennis, 1965&quot; &#x2F;&gt;&lt;&#x2F;a&gt;
&lt;sup&gt;Illustration from &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;dl.acm.org&#x2F;doi&#x2F;pdf&#x2F;10.1145&#x2F;321296.321310&quot;&gt;“Segmentation and the Design of Multiprogrammed Systems”&lt;&#x2F;a&gt;, Jack B. Dennis, 1965. The left diagram illustrates using a word address to index into the segment. The right diagram illustrates the namespace of segments.&lt;&#x2F;sup&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The variable size of segments could lead to conflict —or thrash—
between processes if the two segments happened to overlap. Given the much
expanded range available to them, desktop 64-bit processors tend to use paging
by itself to implement virtual memory. Processors of the era we’re discussing
used both techniques in conjunction to combine the advantages of paging with the
ability to increase the addressable memory space.&lt;&#x2F;p&gt;
&lt;p&gt;Finally, protection rings change the instruction set architecture available to
the program, trapping or disallowing use of privileged instructions having to
do with memory mapping, input&#x2F;output (&lt;strong&gt;“I&#x2F;O”&lt;&#x2F;strong&gt;) devices, or the manipulation
of software timer interrupts. The operating system runs in a protection ring
with higher privileges. Processes run in a lower ring. Processes may request
services from the operating system, like memory allocation or I&#x2F;O, by making
supervisory calls. System requests are implemented using interrupt instructions
or dedicated &lt;code&gt;syscall&lt;&#x2F;code&gt; instructions available in the instruction set
architecture of the processor.&lt;&#x2F;p&gt;
&lt;&#x2F;details&gt;
&lt;p&gt;&lt;em&gt;(For more on all of this, check out &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;cpu.land&#x2F;&quot;&gt;cpu.land&lt;&#x2F;a&gt; and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;os.phil-opp.com&#x2F;paging-introduction&#x2F;&quot;&gt;Phil Opp’s “Writing an OS in Rust” series&lt;&#x2F;a&gt;)&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Project MAC’s contemporaries included Project GENIE at UC Berkeley and the IBM
System&#x2F;360 and 370. These technologies were built in competition with MULTICS;
IBM found that they their university bids were being out-competed by
time-sharing systems spun out from Project MAC. This led them to develop early
whole-machine virtualization software.&lt;&#x2F;p&gt;
&lt;p&gt;While extended machines made it possible to safely create and run relocatable
programs, much research revolved around the development of new operating
systems. This was more difficult than developing a program for an extended
machine, as only a single kernel could run at a time. This lead to the
development of “pseudo-machines” or “virtual machine monitors”, which used the
bare machine interface to provide many copies of that &lt;em&gt;same&lt;&#x2F;em&gt; bare machine
interface for the purposes of kernel development. Further, these virtual
machine monitors could be &lt;em&gt;nested&lt;&#x2F;em&gt;, so long as the appropriate resource
mappings were set up in hardware ahead of time. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;dl.acm.org&#x2F;doi&#x2F;pdf&#x2F;10.1145&#x2F;800122.803946&quot;&gt;There was some
debate&lt;&#x2F;a&gt; around “pure” virtual
machine monitors as opposed to “impure” VMMs at this time! “Impure” VMMs
presented an extended bare machine interface to the guest; the guest machine
was aware of the virtualization.&lt;&#x2F;p&gt;
&lt;p&gt;IBM implemented virtual machine monitors on the System&#x2F;370 using a feature of
the processors’ protection rings. Whenever a non-privileged program performed a
privileged operation, the processor hardware would fault. The VMM trapped these
privilege faults; mapping incoming requests for resources and operations to
appropriate backing resources without the knowledge of the guest operating
system. In his July 1974 article &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;web.eecs.umich.edu&#x2F;~prabal&#x2F;teaching&#x2F;eecs582-w11&#x2F;readings&#x2F;Gol74.pdf&quot;&gt;“A Survey of Virtual Machine
Research”&lt;&#x2F;a&gt;, Robert P. Goldberg noted that the primary
difficulty in implementing efficient virtualization of machines lies in the
lack of comprehensive hardware support for trapping “privilege-sensitive”
instructions. Indeed, the month prior, he and Gerald J. Popek proposed a
definition for “virtualizable architecture” in &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;dl.acm.org&#x2F;doi&#x2F;pdf&#x2F;10.1145&#x2F;361011.361073&quot;&gt;“Formal Requirements for
Virtualizable Third Generation Architectures”&lt;&#x2F;a&gt;&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#third-gen&quot;&gt;9&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.neversaw.us&#x2F;img&#x2F;virtual-machine-organization.png&quot;&gt;&lt;img width=&quot;640&quot; src=&quot;https:&#x2F;&#x2F;www.neversaw.us&#x2F;img&#x2F;virtual-machine-organization.png&quot; alt=&quot;Survey of Virtual Machine Research: Robert P. Goldberg, COMPUTER magazine June 1974&quot; &#x2F;&gt;&lt;&#x2F;a&gt;
&lt;sup&gt;Illustration of VMM, extended machine, and interfaces from &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;web.eecs.umich.edu&#x2F;~prabal&#x2F;teaching&#x2F;eecs582-w11&#x2F;readings&#x2F;Gol74.pdf&quot;&gt;“Survey of Virtual Machine Research”&lt;&#x2F;a&gt;, Robert P. Goldberg, COMPUTE June 1974&lt;&#x2F;sup&gt;&lt;&#x2F;p&gt;
&lt;p&gt;So why did virtual machine monitor research halt for so many years?&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;the-modern-operating-system&quot;&gt;The Modern Operating System&lt;&#x2F;h2&gt;
&lt;p&gt;The Mansfield amendments, passed 1969 and 1973, narrowed the scope of
Department of Defense funds to projects with direct military applications. This
cut public funding for operating systems research. The General Electric 635
used to build MULTICS at MIT cost as much as a passenger jet. MULTICS had been
over-budget and behind schedule for years; Bell Labs pulled out of the MULTICS
project in 1969. The aftermath of the OS research era left many useful ideas
floating in the ether, while virtual machine monitor research would freeze
until the late 1990s&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#ibm&quot;&gt;10&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Many researchers from the Project MAC days joined up at Xerox PARC. There they
developed the Xerox Alto and Smalltalk, which prefigured the modern personal
computer. By the late 1970s, commercial personal computers were available to
consumers: the Apple II, Tandy TRS-80, and others. The IBM PC launched in 1981,
the Apple Lisa in 1983, and the Macintosh in 1984. The earliest versions of
these computers only ran a single program at a time, typically in conjunction
with a disk operating system (&lt;strong&gt;“DOS”&lt;&#x2F;strong&gt;); later they would run many processes
cooperatively. There was only one user and thus, no need to worry about
time-sharing — these systems could be written to assume cooperation
between all programs running on the machine&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#that-said&quot;&gt;11&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;. In 1982, Intel
released the first commercial chips capable of protected mode operation &amp;amp;
on-die memory mapping in the form of the 80286 processor&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#gates-brain-dead&quot;&gt;12&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.
Microsoft, Intel, and IBM’s personal computers rapidly chipped away at the
market for time-shared minicomputers from the consumer side, while
high-performance workstations made inroads on the commercial side.&lt;&#x2F;p&gt;
&lt;p&gt;For the most part, those workstations ran a variant of UNIX.&lt;&#x2F;p&gt;
&lt;p&gt;Dennis Ritchie, Ken Thompson, Douglas McIlroy, and Joe Ossanna developed UNIX
at Bell Laboratories in the aftermath of Bell’s strategic retreat from the
MULTICS project. UNIX benefited from its circumstances: a small
team&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#small&quot;&gt;13&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; with little supervision working on a comparatively cheap computer
(the PDP-7) proved able to incorporate the best ideas in operating systems
research rapidly. UNIX did not start out as a time-sharing system, nor was it a
preemptive operating system. It wasn’t much more than a filesystem supporting a
game &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.bell-labs.com&#x2F;usr&#x2F;dmr&#x2F;www&#x2F;hist.html&quot;&gt;at first&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Back around 1970-71, Unix on the PDP-11&#x2F;20 ran on hardware that not only did
not support virtual memory, but didn’t support any kind of hardware memory
mapping or protection, for example against writing over the kernel. This was
a pain, because we were using the machine for multiple users. When anyone
was working on a program, it was considered a courtesy to yell “A.OUT?”
before trying it, to warn others to save whatever they were editing.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.bell-labs.com&#x2F;usr&#x2F;dmr&#x2F;www&#x2F;odd.html&quot;&gt;“A hardware story”&lt;&#x2F;a&gt;, Dennis Ritchie, 2002&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;The initial system was multiprogrammed — that is, there were two, time-shared
shell processes running, one for each terminal connected to the machine. When
the shell executed another program, it would read the file in over the top of
the shell code and start executing it. The &lt;code&gt;exit()&lt;&#x2F;code&gt; syscall would reload the
shell program over the top of the shell and restart execution. Support for a
&lt;em&gt;tree&lt;&#x2F;em&gt; of processes was added rapidly, however.&lt;&#x2F;p&gt;
&lt;p&gt;UNIX inherited &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;dl.acm.org&#x2F;doi&#x2F;pdf&#x2F;10.1145&#x2F;1463822.1463838&quot;&gt;Conway’s &lt;code&gt;fork&#x2F;join&lt;&#x2F;code&gt; semantics&lt;&#x2F;a&gt; from Project GENIE
as &lt;code&gt;fork&#x2F;exec&lt;&#x2F;code&gt;: one command to make a duplicate of the current process as a
child of the forking process, and a second command run in that child process to
replace the duplicate with the target code. This model of copying processes
using prototypal inheritance directly enabled the container models we’ll talk
about shortly.&lt;&#x2F;p&gt;
&lt;p&gt;By 1977 work was underway to port UNIX from the PDP-11 to the Interdata 8&#x2F;32,
as we noted way back in &lt;a href=&quot;https:&#x2F;&#x2F;www.neversaw.us&#x2F;2023&#x2F;05&#x2F;10&#x2F;understanding-wasm&#x2F;part1&#x2F;virtualization&#x2F;&quot;&gt;the first post in this series&lt;&#x2F;a&gt;. (The work had
been validated by porting a copy of UNIX to an IBM System&#x2F;370 virtual machine.)
With the support of Sun Microsystems, IBM, HP, and others, UNIX and C had swept
through the industry by the late eighties. Consumer operating systems were
converging on preemptive, protected time-sharing, buoyed by advances in Intel’s
commercial hardware. Hardware virtualization features, if supported, primarily
existed to support older DOS programs. Entering the 90’s, “virtual machine”
came to refer primarily to language virtual machines, like Smalltalk and
Erlang.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;the-internet&quot;&gt;The Internet&lt;&#x2F;h2&gt;
&lt;p&gt;The internet changed things (he said, blandly.)&lt;&#x2F;p&gt;
&lt;p&gt;The internet meant unbound connectivity, which meant servers had to support
unprecedented numbers: of processes, of users, of connections. The added
pressure was not tenable with contemporary operating systems approaches, which
were too rigid. Both scaling and consolidation were difficult and relocating
processes was nearly impossible.&lt;&#x2F;p&gt;
&lt;p&gt;Going into the 90’s, the ever-problematic, ever-popular x86 ISA was thought
impossible to virtualize efficiently, but pressure was building behind that
cork.&lt;&#x2F;p&gt;
&lt;p&gt;These problems spurred a renaissance of virtualization research.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;modern-virtual-machines&quot;&gt;Modern Virtual Machines&lt;&#x2F;h2&gt;
&lt;p&gt;Scaling a website to meet traffic demands meant procuring and provisioning
hardware. This could not be done quickly. Internet companies were required to
expend considerable money well in advance of expected traffic and were largely
unable to recoup costs if that traffic did not materialize. The industry needed
a way to commoditize hardware.&lt;&#x2F;p&gt;
&lt;p&gt;x86 was the most popular processor architecture with the best economies of
scale and broadest software support. However, it could not be virtualized
directly: privileged instructions and memory operations would silently fail
without triggering traps.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Unfortunately, many current architectures are not strictly virtualizeable.
This may be because either their instructions are non-virtualizeable, or they
have segmented architectures that are non-virtualizeable, or both.&lt;&#x2F;p&gt;
&lt;p&gt;Unfortunately, the all-but-ubiquitous Intel x86 processor family has both of
these problematic properties, that is, both non-virtualizeable instructions
and non-reversible segmentation. Consequently, no [Virtual Machine Monitor]
based exclusively on direct execution can completely virtualize the x86
architecture.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;patents.google.com&#x2F;patent&#x2F;US6397242B1&#x2F;en&quot;&gt;“Virtualization System Including a Virtual Machine Monitor For a Computer
With Segmented Architecture”&lt;&#x2F;a&gt;, United States Patent #6,397,232&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;The late 90’s saw a growing interest in direct binary translation (&lt;strong&gt;“DBT”&lt;&#x2F;strong&gt;.)
The hegemony of the x86 processor was predicted to crumble. Efforts such as
DAISY and Transmeta’s Crusoe bet against the continued popularity of x86.
Meanwhile, in the language virtual machine space, just-in-time compilation
research blossomed. VMWare was founded in this context, submitting a
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;patents.google.com&#x2F;patent&#x2F;US6397242B1&#x2F;en&quot;&gt;patent&lt;&#x2F;a&gt; early on for a direct-binary-translation method of implementing
virtual machine monitors for the x86 architecture.&lt;&#x2F;p&gt;
&lt;p&gt;VMWare’s virtual machine monitor triggered a translator whenever control
entered or exited a protection ring. This translator monitored for execution of
untrapped privileged instructions in order to inject manual VMM trap calls. This
enabled virtualization but added overhead to every system call.&lt;&#x2F;p&gt;
&lt;p&gt;Because DBT added uneven overhead to kernel execution, it was difficult to
associate system use with virtual machine execution. This prevented accurate
billing systems from being constructed around such virtual machines.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.cl.cam.ac.uk&#x2F;research&#x2F;srg&#x2F;netos&#x2F;papers&#x2F;2003-xensosp.pdf&quot;&gt;“Xen and the Art of Virtualization”&lt;&#x2F;a&gt; changed all of that.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;By allowing 100 operating systems to run on a single server, we reduce the
associated costs by two orders of magnitude. Furthermore, by turning the
setup and configuration of each OS into a software concern, we facilitate
much smaller-granularity timescales of hosting.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.cl.cam.ac.uk&#x2F;research&#x2F;srg&#x2F;netos&#x2F;papers&#x2F;2003-xensosp.pdf&quot;&gt;“Xen and the Art of Virtualization”&lt;&#x2F;a&gt;, 2003&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Xen achieved this through paravirtualization: instead of pure virtualization,
it achieved “impure”, cooperative virtualization by modifying the guest operating
systems. In particular, Xen moved the operating system &lt;em&gt;out&lt;&#x2F;em&gt; of the most
protected ring of the processor: from ring 0 to ring 1. Processes continued to
run in ring 3. This gave the operating system its own “extended machine”: while
it lost access to privilege instructions, it gained access to its own
supervisory call system (“hypervisor calls”.)&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.neversaw.us&#x2F;img&#x2F;xen-perf.png&quot;&gt;&lt;img width=&quot;640&quot; src=&quot;https:&#x2F;&#x2F;www.neversaw.us&#x2F;img&#x2F;xen-perf.png&quot; alt=&quot;Xen and the Art of Virtualization: Comparison of native Linux, Xen, VMWare Workstation, and User-mode Linux&quot; &#x2F;&gt;&lt;&#x2F;a&gt;
&lt;sup&gt;Comparison of native Linux, Xen, VMWare Workstation, and User-mode Linux on various benchmarks, from &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.cl.cam.ac.uk&#x2F;research&#x2F;srg&#x2F;netos&#x2F;papers&#x2F;2003-xensosp.pdf&quot;&gt;“Xen and the Art of Virtualization”&lt;&#x2F;a&gt;. Note that OLTP represents relational database workloads and WEB99 represents web-serving.&lt;&#x2F;sup&gt;&lt;&#x2F;p&gt;
&lt;p&gt;In particular, Xen’s performance on web application workloads was a breakthrough.&lt;&#x2F;p&gt;
&lt;p&gt;Cloud virtual machines commoditized hardware, severing the connection between
“procuring and provisioning hardware” and “scaling a web service.”&lt;&#x2F;p&gt;
&lt;p&gt;As with memory mapping and protection rings in the 80s, consumer hardware
lagged behind the market’s needs. AMD and Intel introduced hardware support
for virtualization of x86(_64) architectures in 2005 through SVM and VT-X,
respectively. ARM added hardware virtualization support in Cortex-A in 2011&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#popek&quot;&gt;14&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Hardware is really just software crystallized early. It is there to make
program schemes run as efficiently as possible. But far too often the
hardware has been presented as a given and it is up to software designers to
make it appear reasonable. […]&lt;&#x2F;p&gt;
&lt;p&gt;As Bob Barton used to say: “Systems programmers are high priests of a low
cult.”&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;worrydream.com&#x2F;EarlyHistoryOfSmalltalk&#x2F;&quot;&gt;“An Early History of Smalltalk”&lt;&#x2F;a&gt;, Alan Kay&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Hardware virtualization support allowed operating systems to integrate
hypervisor capabilities: Windows Server added Hyper-V (2008); Linux, Kernel
Virtual Machines (“KVM”, 2006); and macOS, Hypervisor.framework (2020). (EC2
started moving from Xen to KVM-based “Nitro” virtual machines in 2017. Brendan
Gregg wrote more about the path from the first version of Xen to Nitro
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.brendangregg.com&#x2F;blog&#x2F;2017-11-29&#x2F;aws-ec2-virtualization-2017.html&quot;&gt;here&lt;&#x2F;a&gt;.) In lieu of running Xen or VMWare, consumer operating systems
themselves became capable of running guest operating systems, accelerating the
development of new hypervisor software.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;A few notes on timing: by 2003, the dotcom bubble had burst. The servers that
internet startups had loaded up on flooded the market with cheap used hardware,
causing Sun Microsystems to hemorrhage money. At Amazon, &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;blog.b3k.us&#x2F;2009&#x2F;01&#x2F;25&#x2F;ec2-origins.html&quot;&gt;Benjamin
Black&lt;&#x2F;a&gt; circulated a document describing a standardized
infrastructure; Bezos tasked Chris Pinkham with developing this in 2004. EC2
launched publicly in 2006, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;aws.amazon.com&#x2F;blogs&#x2F;aws&#x2F;amazon_ec2_beta&#x2F;&quot;&gt;powered by Xen&lt;&#x2F;a&gt;. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;courses.cs.washington.edu&#x2F;courses&#x2F;cse452&#x2F;23wi&#x2F;papers&#x2F;yegge-platform-rant.html&quot;&gt;According to Steve
Yegge&lt;&#x2F;a&gt;, sometime in 2002-2003 or so, Bezos issued his famous “services
edict”, stipulating that all Amazon engineering teams deliver their work in the
form of networked services. By 2009, Netflix had moved their video encoding
operations to AWS. Netflix finished transitioning to the cloud in 2011. And
Docker launched in 2013.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;docker&quot;&gt;Docker&lt;&#x2F;h2&gt;
&lt;p&gt;The high-level metaphor of Docker is that of &lt;strong&gt;shipping containers&lt;&#x2F;strong&gt;.
Standardized containers revolutionized the shipping industry: a standard form
factor meant a standard way to load, unload, and transport material. The
technology made shipping &lt;em&gt;everything&lt;&#x2F;em&gt; faster, cheaper, and more reliable. This
is Docker’s raison d’être: to do for computer applications and operations teams
what standard containers did for the shipping industry.&lt;&#x2F;p&gt;
&lt;p&gt;The metaphor is pretty durable: the concrete problem that Docker solved was
that of shared resources. Consider: given a large company, two developers may
develop two different web serving applications (&lt;strong&gt;“services”&lt;&#x2F;strong&gt;) that expect to
listen on the same network port&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#port&quot;&gt;15&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;. Before containers, these two developers
would have to sync up: who gets to listen on port 80? They’d have to agree,
up-front, before being able to deploy their software. Worse, if they couldn’t
come to agreement about the use of resources, they’d have to involve a
third-party — someone from the operations department — who might
solve the problem by introducing a &lt;em&gt;third&lt;&#x2F;em&gt; server, a reverse proxy layer, to
resolve the conflict.&lt;&#x2F;p&gt;
&lt;p&gt;Docker solves this by giving each service a &lt;strong&gt;virtualized&lt;&#x2F;strong&gt; view of the
operating system and its resources. Both developers may remain agnostic of each
other AND the operations team. The operations team can map network ports as
necessary – or rely on orchestration software, like Nomad or Kubernetes, to do
this for them. Standard containers yield standard tools.&lt;&#x2F;p&gt;
&lt;p&gt;Docker achieves&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#docker-how&quot;&gt;16&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; virtualization through a combination of abstract
programming interfaces (&lt;strong&gt;“APIs”&lt;&#x2F;strong&gt;) supported by the kernel of the host
operating system: secure computing mode (&lt;strong&gt;“seccomp”&lt;&#x2F;strong&gt;), namespaces, and
control groups — on which, more later. Each of these APIs must be
properly configured to make durable the illusion that the process is running on
a virtualized system.&lt;&#x2F;p&gt;
&lt;p&gt;Windows supports containers natively through a &lt;code&gt;hcsshim&lt;&#x2F;code&gt; runtime that provides
namespace and cgroup support through Windows’ native Host Compute Service.
Apple’s macOS, however, runs docker containers by spinning up a virtualized
Linux host to run a Docker daemon and container processes.&lt;&#x2F;p&gt;
&lt;p&gt;While the Docker&#x2F;OCI&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#oci&quot;&gt;17&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; container model is ubiquitous today, the
capabilities underpinning it have their origins in the virtual machine
renaissance of the late 90s.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Let’s walk back towards the year 2000.&lt;&#x2F;p&gt;
&lt;p&gt;Docker was originally implemented using an earlier container model called “LXC”
(“Linux Containers”), introduced in 2008. LXC, like many of its contemporary
container models, was built to act like a virtual machine. Rather than Docker’s
model of taking a single process and giving it a virtual system environment,
LXC containers typically virtualized an &lt;code&gt;init&lt;&#x2F;code&gt; process (like &lt;code&gt;systemd&lt;&#x2F;code&gt;,
&lt;code&gt;upstart&lt;&#x2F;code&gt;, or SysV &lt;code&gt;init&lt;&#x2F;code&gt;&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#init&quot;&gt;18&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.) This made them “feel” much more like a
virtual machine, with their own long-lived daemons, periodic tasks, and system
logs. But, akin to Docker, LXC was built from &lt;code&gt;cgroups&lt;&#x2F;code&gt; and namespaces.&lt;&#x2F;p&gt;
&lt;p&gt;Google contributed &lt;code&gt;cgroups&lt;&#x2F;code&gt; (or “control groups”) to the Linux kernel in 2007.
Control groups allowed userland to communicate resource quotas for process
subtrees to the kernel: effectively allowing container runtimes to dictate the
maximum CPU time, parallelism, network, memory, and disk usage a set of
sub-processes should be able to use. This doesn’t affect the ability of those
processes to &lt;em&gt;see&lt;&#x2F;em&gt; certain subsystems: control groups don’t affect what the
process has access to, only the available quality of service for that
access&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#borg&quot;&gt;19&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;I consulted the local gurus about the security of a &lt;code&gt;chroot&lt;&#x2F;code&gt; environment. Their
conclusion: it is not perfectly secure, but if compilers and certain programs
are missing, it is very difficult to escape.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.cheswick.com&#x2F;ches&#x2F;papers&#x2F;berferd.pdf&quot;&gt;“An Evening with Berferd”&lt;&#x2F;a&gt;, Bill Cheswick, 1990&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Namespaces are related to earlier &lt;code&gt;jail&lt;&#x2F;code&gt; and &lt;code&gt;chroot&lt;&#x2F;code&gt; capabilities&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#when-jail&quot;&gt;20&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.
This family of APIs control what operating system subresources are visible to
jailed processes. Linux began adding namespace support in 2002. The mount
namespace for filesystems came first, inspired by Plan 9&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#java-killed&quot;&gt;21&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;. Eric W.
Biederman enumerated the necessary support in &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.kernel.org&#x2F;doc&#x2F;ols&#x2F;2006&#x2F;ols2006v1-pages-101-112.pdf&quot;&gt;“Multiple Instances of
the Global Linux Namespaces”&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;mnt&lt;&#x2F;code&gt;: The filesystem namespace.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;uts&lt;&#x2F;code&gt;: The UNIX Time-sharing namespace (controlling what hostname is visible to the process.)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;ipc&lt;&#x2F;code&gt;: Inter-process communication namespace.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;net&lt;&#x2F;code&gt;: The network namespace.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;pid&lt;&#x2F;code&gt;: The process identifier namespace.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;user&lt;&#x2F;code&gt;: The user and group namespace.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;time&lt;&#x2F;code&gt;: The time namespace.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Linux added the &lt;code&gt;user&lt;&#x2F;code&gt; namespace in 2013 — the same year Docker was first
released publicly. (This was later followed up with the &lt;code&gt;cgroup&lt;&#x2F;code&gt; namespace in
2016.)&lt;&#x2F;p&gt;
&lt;p&gt;Namespaces and cgroups form the basis of what we think of as containers
today&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#openvz&quot;&gt;22&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; — and they exist to work around the lack of virtualization
support in turn-of-the-century processors.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;From the hardware perspective, processes and guest operating systems look
nearly the same. Virtualizing the system at the process layer means sharing
more code between the virtualized systems with a finer granularity of
abstractions, but has the advantage of being achievable purely through
software: hardware can’t really tell the difference between a container and any
other process.&lt;&#x2F;p&gt;
&lt;p&gt;Because virtualizing the system at the hardware interface layer is more
coarse-grained with less shared code, VMMs are generally considered safer
targets for multi-tenancy —that is, running untrusted code from third
parties collocated on the same hardware&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#meltdown-spectre&quot;&gt;23&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;. On the other hand,
VMMs introduce more startup overhead. However, in recent years, containers
and VMMs have converged: Kata containers, AWS’ Firecracker, and others use the
container user interface but run the containers inside lightweight virtual
machines, achieving remarkable performance, security, and
density&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#comparisons&quot;&gt;24&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;density&quot;&gt;Density&lt;&#x2F;h2&gt;
&lt;p&gt;The more efficiently tasks can be collocated, the better the margins on
equipment; this is a competitive edge for a hosting company. Processes, whether
virtual machines or containers, have overhead. Switching between processes
takes time and memory; Tyler McMullen, CTO of Fastly, noted that were limits on
the number of processes running on a single box in his 2018 &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;vimeo.com&#x2F;291584445&quot;&gt;“Software Fault
Isolation”&lt;&#x2F;a&gt;. This was a natural place to look for improvements, and
so content delivery networks — which handle some of the highest volume of
traffic on the internet — started digging into the problem. Fastly and
Cloudflare both landed on web technologies, launching products in 2018.&lt;&#x2F;p&gt;
&lt;p&gt;Cloudflare launched Workers, which co-locates many user tasks in a single
process using V8 isolates. V8 is, as we discussed previously, the JIT
JavaScript engine open-sourced by Google as part of their Chrome browser.
Workers customers upload JavaScript applications that implement the
ServiceWorker spec; Cloudflare deploys the application to their edge network, with points
of presence across the globe. As a bonus, since WebAssembly support is
available through the web platform API, users that really needed to could
target Wasm. (Though they’d be responsible for writing their own bindings to
the ServiceWorker API.)&lt;&#x2F;p&gt;
&lt;p&gt;Fastly launched Compute@Edge, skipping JavaScript in favor of WebAssembly. But
this posed a problem. While JS could rely on the Web platform as a system
interface, Wasm does not automatically provide one. In order to hook Wasm up to
their edge compute, Fastly had to &lt;em&gt;define&lt;&#x2F;em&gt; an interface: one that was stable
and versioned.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;wasi&quot;&gt;WASI&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;em&gt;(Finally.)&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Fastly, Intel, and Mozilla teamed up in 2019 to form the Bytecode Alliance.
Their goal was to define a specification for a standard system interface for
WebAssembly&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#and-cranelift-and-wasmtime-but&quot;&gt;25&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The WebAssembly ISA allows imports and exports: functions that the host can
pass &lt;em&gt;in&lt;&#x2F;em&gt; to the Wasm module for internal use, and functions that the Wasm
module can hand back to the host to be called &lt;em&gt;by&lt;&#x2F;em&gt; the host on demand. The host
may also provide a chunk of memory for the Wasm module to operate on. Imported
and exported functions may only take primitive values — integer and floating
point values of various widths. The host and module may cooperate to transfer
more complicated types. For example, the host and module might agree that a string
is represented as an integer pointer into the module’s memory along with an
integer length.&lt;&#x2F;p&gt;
&lt;p&gt;This is a &lt;em&gt;lot&lt;&#x2F;em&gt; like the sort of &lt;strong&gt;ABI&lt;&#x2F;strong&gt; a process &lt;strong&gt;System Interface&lt;&#x2F;strong&gt; uses.&lt;&#x2F;p&gt;
&lt;p&gt;Tools like emscripten and wasm-bindgen treat the interface between the host and
Wasm module as an internal detail. Those tools were designed to take an
existing application and get it running in a browser with minimal changes,
generating both Wasm, HTML, and the JavaScript to integrate the Wasm with the
Web Platform. If one were to recompile an application with a newer version of
emscripten and try to drop the Wasm onto an older version of the HTML and JS,
it may not work. Likewise, the Wasm from an application compiled with
wasm-bindgen could not be dropped onto emscripten HTML and JS or vice versa.
They are not &lt;strong&gt;ABI&lt;&#x2F;strong&gt; compatible.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;The first preview of WASI launched in 2019. For the most part, it closely
resembles POSIX with some light editorialization: for example, POSIX APIs whose
behavior changed based on parameters, like &lt;code&gt;unlink&lt;&#x2F;code&gt;, were split into separate
functions. However, WASI preview 1 deferred implementation of several key
capabilities: C++ stack unwinding&#x2F;exception support, full network socket
support, and &lt;code&gt;fork&lt;&#x2F;code&gt;&#x2F;&lt;code&gt;exec&lt;&#x2F;code&gt; were omitted.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;fork&lt;&#x2F;code&gt; and &lt;code&gt;exec&lt;&#x2F;code&gt; form the bedrock of the POSIX process model. Their
descendants, &lt;code&gt;clone&lt;&#x2F;code&gt; and &lt;code&gt;unshare&lt;&#x2F;code&gt;, form the basis for working with Linux
cgroups and namespaces. In short, it is hard to support &lt;code&gt;fork&lt;&#x2F;code&gt; without also
taking the traditional process model on board. And WebAssembly &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.microsoft.com&#x2F;en-us&#x2F;research&#x2F;uploads&#x2F;prod&#x2F;2019&#x2F;04&#x2F;fork-hotos19.pdf&quot;&gt;may not want to
do that&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;System interface ABIs don’t just define the boundary between a process and the
kernel. They’re also used to enable software &lt;em&gt;linking&lt;&#x2F;em&gt; — the reuse of
compiled artifacts: shared objects (&lt;code&gt;.dylib&lt;&#x2F;code&gt;, &lt;code&gt;.so&lt;&#x2F;code&gt;, or &lt;code&gt;.dll&lt;&#x2F;code&gt;.) Linking can be
performed at compile time (static linking) or at process start (dynamic
linking.) While shared object linking wasn’t defined as part of the first WASI
preview&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#reactors-commands&quot;&gt;26&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;, neither did the specifiers wish to preclude it in
future versions of the specification.&lt;&#x2F;p&gt;
&lt;p&gt;The standard approach to sockets would have exposed too much power between
linked modules. Sockets are typically represented as a “descriptor” or “handle”
in the form of an integer the operating system hands to the process on request.
Operations on the socket are performed by making a system call referencing that
integer, and all linked modules are assumed to have access to the same system
interface. This model is difficult to secure: malicious linked modules can
“guess at” active descriptors by picking random integers&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#forging&quot;&gt;27&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;. The system
can’t differentiate between linked modules and the core application logic when
receiving calls referencing the descriptors.&lt;&#x2F;p&gt;
&lt;p&gt;The problem with the POSIX model is that the system interface forms a
monolithic wall between the kernel and the user process, leaving
undifferentiated space on either side. The ABI emphasizes the importance of the
system interface &lt;em&gt;over&lt;&#x2F;em&gt; the importance of the interface between modules.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;a-component-model&quot;&gt;A Component Model&lt;&#x2F;h2&gt;
&lt;p&gt;Through the &lt;strong&gt;Wasm Component Model&lt;&#x2F;strong&gt;, WASI preview 2 fundamentally rethinks the
process model.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;One of WebAssembly’s unique attributes is the ability to run sandboxed without
relying on OS process boundaries. Requiring a 1-to-1 correspondence between
wasm instances and heavyweight OS processes would take away this key advantage
for many use cases. Fork&#x2F;exec are the obvious example of an API that’s
difficult to implement well if you don’t have POSIX-style processes, but a lot
of other things in POSIX are tied to processes too. So it isn’t a simple matter
to take POSIX, or even a simple subset of it, to WebAssembly.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;bytecodealliance&#x2F;wasmtime&#x2F;blob&#x2F;main&#x2F;docs&#x2F;WASI-rationale.md#why-not-a-more-traditional-set-of-posix-like-syscalls&quot;&gt;“Why not a more traditional set of POSIX-like syscalls?”, WASI Rationale&lt;&#x2F;a&gt; - Dan Gohman&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;The &lt;strong&gt;Wasm Component Model&lt;&#x2F;strong&gt; defines a static linking approach for combining
many Wasm core modules into a single file, a “component”. The &lt;strong&gt;Component
Model&lt;&#x2F;strong&gt; also a new, modular interface definition language called “WebAssembly
Interface Types” (&lt;strong&gt;“WIT”&lt;&#x2F;strong&gt;.) WIT allows for the definition of named functions,
groups of functions, and high-level types like strings and structs. WIT also
allows for groupings-of-groupings with requirements around exports and imports,
called “worlds”. WIT worlds can be used to generate host code or as a target
for compiling shared code — it is a language for defining contracts
between modules.&lt;&#x2F;p&gt;
&lt;p&gt;Instead of one monolithic wall of functions representing all system services,
the Wasm Component Model proposes a system of smaller fences placed between
every module. Each interface only specifies the functionality it needs, and may
be fulfilled by any other module — or the host. Instead of exposing
entire namespaces of functionality, like &lt;code&gt;mnt&lt;&#x2F;code&gt;, &lt;code&gt;uts&lt;&#x2F;code&gt;, or &lt;code&gt;net&lt;&#x2F;code&gt;, the interface
can be described in a fine-grained way: “module A requires a function for
reading input data.”&lt;&#x2F;p&gt;
&lt;p&gt;This allows sockets to be represented as higher level objects whose full
capabilities aren’t transferred between linked modules, as opposed to an
integer descriptor tracked by the host. (See Dan Gohman’s excellent &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;blog.sunfishcode.online&#x2F;no-ghosts&#x2F;&quot;&gt;“No
Ghosts!”&lt;&#x2F;a&gt; for more on this.)&lt;&#x2F;p&gt;
&lt;p&gt;WASI preview 2 aims to stabilize &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;WebAssembly&#x2F;wasi-cli&quot;&gt;&lt;code&gt;wasi-cli&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; and
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;WebAssembly&#x2F;wasi-http&#x2F;blob&#x2F;main&#x2F;proxy.md&quot;&gt;&lt;code&gt;wasi-http-proxy&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; worlds first. However, at the time of writing the
Component Model proposal is only in &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;WebAssembly&#x2F;meetings&#x2F;blob&#x2F;main&#x2F;process&#x2F;phases.md#1-feature-proposal-community-group&quot;&gt;stage 1&lt;&#x2F;a&gt;, so many popular tools
and runtimes do not support Wasm components or WASI preview 2. And many
platform-as-a-service (&lt;strong&gt;“PaaS”&lt;&#x2F;strong&gt;) startups have appeared since Solomon Hyke’s
tweet.&lt;&#x2F;p&gt;
&lt;p&gt;Companies have proposed alternative system interfaces.&lt;&#x2F;p&gt;
&lt;p&gt;Deis labs introduced WAGI in 2020. WAGI sidesteps the issue of missing POSIX
support by using WASI preview 1’s standard input and output instead of sockets.
This is reminiscent of the venerable “common gateway interface” (&lt;strong&gt;“CGI”&lt;&#x2F;strong&gt;)
from the 1990s. Fermyon, a Wasm PaaS company, supports WAGI through its Spin
framework.&lt;&#x2F;p&gt;
&lt;p&gt;In 2023, Wasmer introduced WASIX. WASIX, a superset of WASI, aims to target
more of the POSIX API, including support for &lt;code&gt;fork&lt;&#x2F;code&gt;. This is akin to an
Emscripten for server applications, with the goal of lowering the barrier
between existing web services and PaaS Wasm companies. Like Emscripten, WASIX
values easy portability of existing applications. As a result, it doesn’t
editorialize too much on the POSIX API. However, at the time of writing, WASIX
doesn’t support shared object linking. While WASIX doesn’t preclude linking
shared objects in the future, it seems likely that it would follow the existing
linking model, whether for good or for ill.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Every technology we’ve talked about made it easier for developers to
collaborate by reducing their need to coordinate ahead of time. Interfaces are
a contract, a minimum viable agreement, between two parties. Interfaces build
two-sided network effects: implementing the contract lets your program work
with an unbound number of other programs which consume the contract and vice
versa. Interfaces are living systems: they have internal motion. Inertia.&lt;&#x2F;p&gt;
&lt;p&gt;The inertia of an interface may even overcome deep flaws with that interface.&lt;&#x2F;p&gt;
&lt;p&gt;In this series, we’ve talked about how the inertia of the x86 ISA spurred an
unexpected breakthrough in hardware design — despite the bet that we’d
all be using VLIW RISC processors today. How the inertia of JavaScript, through
the web platform, precluded competing web technologies, like Java, PNaCL, and
Dart, and eventually gave rise to WebAssembly. This is the heart of &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.dreamsongs.com&#x2F;RiseOfWorseIsBetter.html&quot;&gt;“Worse is
Better”&lt;&#x2F;a&gt; &lt;strong&gt;and&lt;&#x2F;strong&gt; &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;John_Gall_(author)#Gall&amp;#x27;s_law&quot;&gt;Gall’s Law&lt;&#x2F;a&gt;: &lt;em&gt;“A complex system that
works is invariably found to have evolved from a simple system that worked.”&lt;&#x2F;em&gt;
It’s the human side of computing: it is better to be in a room full of people
gathered around the warmth of an imperfectly useful interface than it is to be
out, alone in the cold, with a perfect interface.&lt;&#x2F;p&gt;
&lt;p&gt;Good interfaces are grown, not invented: coaxed out of usefully-bad interfaces
by redirecting some of their inertia. Borrowing the energy of the inertia to
achieve a new orbit, so to speak.&lt;&#x2F;p&gt;
&lt;p&gt;Processes and virtual machines are some of our oldest, most widely-used
usefully-bad interfaces. Their use at scale — and our ability to reason
about their capabilities — have begun to fail us, but they are the mass
around which all of modern computing orbits. This is what’s interesting about
WASI and the WebAssembly Component model: it is a moonshot. The initial
trajectory won’t get WASI to the moon: WASI preview 2, if successful, still
looks like embedded Wasm in web proxies and command lines. But that might be a high
enough apogee to slingshot to a new, higher orbit.&lt;&#x2F;p&gt;
&lt;p&gt;On the other hand, moonshots are not a sure thing: like Java before it, WASI
doesn’t represent a bridge, but a destination. That is the fundamental difference
between the component approach and the WASIX approach.&lt;&#x2F;p&gt;
&lt;p&gt;For my part, I think this WASI moonshot warrants energy: Docker succeeded, in
part, because it described a vision of the future that anyone could take part
in building. Through npm, JavaScript had a similar trajectory. I think we’re on the
cusp of the same moment with WebAssembly.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;epilogue&quot;&gt;Epilogue&lt;&#x2F;h2&gt;
&lt;p&gt;So, whew. That’s a lot.&lt;&#x2F;p&gt;
&lt;p&gt;I’m excited to announce that I’ll be joining &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;dylibso.com&#x2F;&quot;&gt;Dylibso&lt;&#x2F;a&gt; as of this
month to work on Wasm materials, tools, and smooth out friction in the
ecosystem wherever I find it.&lt;&#x2F;p&gt;
&lt;p&gt;Working on these posts has been hugely educational for me on a number of
levels, and I’d like to thank everyone who reviewed these posts (C J Silverio,
Eric Sampson, and Aria Stewart), advised and helped source research (Ron Gee,
Dan Gohman) and encouraged me. In particular I’d like to thank my family for
their support: my wife, Krysten, and my parents, Mark and Sue. They dealt with
an entire summer of me talking non-stop about Wasm, writing, and computing
history.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;bibliography-and-timeline&quot;&gt;Bibliography and Timeline&lt;&#x2F;h2&gt;
&lt;p&gt;So many PDFs this time around!&lt;&#x2F;p&gt;
&lt;p&gt;I’d like to call out &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;dl.acm.org&#x2F;doi&#x2F;fullHtml&#x2F;10.1145&#x2F;3365199&quot;&gt;“The Ideal Versus the Real: Revisiting the History of
Virtual Machines and Containers”&lt;&#x2F;a&gt; by Allison Randal, which dives
more deeply into the history and interrelations between these technologies than
my effort here. Give it a read!&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;1961. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.andrew.cmu.edu&#x2F;course&#x2F;15-440&#x2F;assets&#x2F;READINGS&#x2F;fotheringham1961.pdf&quot;&gt;“Dynamic Storage Allocation in the Atlas Computer”&lt;&#x2F;a&gt;, John Fotheringham,&lt;&#x2F;li&gt;
&lt;li&gt;1961. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.dcs.gla.ac.uk&#x2F;~wpc&#x2F;grcs&#x2F;kilburn.pdf&quot;&gt;“One-level storage system”&lt;&#x2F;a&gt;, Kilburn, Edwards, Lanigan, Sumner&lt;&#x2F;li&gt;
&lt;li&gt;1961. Compatible Time-Sharing System first operational&lt;&#x2F;li&gt;
&lt;li&gt;1962. Atlas Computer operational&lt;&#x2F;li&gt;
&lt;li&gt;1963. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;dl.acm.org&#x2F;doi&#x2F;10.1145&#x2F;1463822.1463838&quot;&gt;“A multiprocessor system design”&lt;&#x2F;a&gt;, Melvin E. Conway&lt;&#x2F;li&gt;
&lt;li&gt;1964. Compatible Time-Sharing System in operational use&lt;&#x2F;li&gt;
&lt;li&gt;1964. IBM System&#x2F;360&lt;&#x2F;li&gt;
&lt;li&gt;1965. GE 645 hardware simulated at MIT for MULTICS&lt;&#x2F;li&gt;
&lt;li&gt;1965. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;dl.acm.org&#x2F;doi&#x2F;pdf&#x2F;10.1145&#x2F;321296.321310&quot;&gt;“Segmentation and the Design of Multiprogrammed Computer Systems”&lt;&#x2F;a&gt; - Jack B. Dennis
&lt;ul&gt;
&lt;li&gt;cites 1961 “one-level storage system”&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;1966. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;dl.acm.org&#x2F;doi&#x2F;10.1145&#x2F;365230.365252&quot;&gt;“Programming Semantics for Multiprogrammed Computations”&lt;&#x2F;a&gt; - Jack B. Dennis, Earl C. Van Horn
&lt;ul&gt;
&lt;li&gt;cites 1963 “A multiprocessor system design”&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;1967. GE 645 hardware received at MIT&lt;&#x2F;li&gt;
&lt;li&gt;1968. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;dl.acm.org&#x2F;doi&#x2F;pdf&#x2F;10.1145&#x2F;363095.363139&quot;&gt;“Virtual Memory, Processes,and Sharing in MULTICS”&lt;&#x2F;a&gt; - Robert C. Daley, Jack B. Dennis&lt;&#x2F;li&gt;
&lt;li&gt;1969. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.bell-labs.com&#x2F;usr&#x2F;dmr&#x2F;www&#x2F;hist.html&quot;&gt;UNIX v1 running on a pdp-7&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;1969. MULTICS replaces GECOS on GE 645&lt;&#x2F;li&gt;
&lt;li&gt;1970. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;dl.acm.org&#x2F;doi&#x2F;pdf&#x2F;10.1145&#x2F;356571.356573&quot;&gt;“Virtual Memory”&lt;&#x2F;a&gt;, Peter Denning
&lt;ul&gt;
&lt;li&gt;cites 1961 “one-level storage”&lt;&#x2F;li&gt;
&lt;li&gt;cites 1961 “dynamic storage allocation”&lt;&#x2F;li&gt;
&lt;li&gt;cites 1966 “Programming Semantics for Multiprogrammed Computations” Jack B. Dennis, Earl C. Van Horn&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;1970. IBM System&#x2F;370 released&lt;&#x2F;li&gt;
&lt;li&gt;1971. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.bell-labs.com&#x2F;usr&#x2F;dmr&#x2F;www&#x2F;1stEdman.html&quot;&gt;UNIX moved to the PDP-11&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;1973. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;dl.acm.org&#x2F;doi&#x2F;pdf&#x2F;10.1145&#x2F;800122.803946&quot;&gt;“Virtual machine or virtual operating system”&lt;&#x2F;a&gt;, Bellino, J, C Hans
&lt;ul&gt;
&lt;li&gt;this seems a LOT like paravirtualization and&#x2F;or containers — could not achieve full performance
virtualizing an entire IBM 360 machine, so the VMM provided “higher level” primitives&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;1974. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;web.eecs.umich.edu&#x2F;~prabal&#x2F;teaching&#x2F;eecs582-w11&#x2F;readings&#x2F;Gol74.pdf&quot;&gt;“Survey of Virtual Machine Research”&lt;&#x2F;a&gt;, Robert P. Goldberg
&lt;ul&gt;
&lt;li&gt;cites bellino&#x2F;hans 1973 re: “pure” vs “impure” virtual machines&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;1979. UNIX v7, introduction of &lt;code&gt;chroot&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;1979. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;dl.acm.org&#x2F;doi&#x2F;pdf&#x2F;10.5555&#x2F;800091.802915&quot;&gt;“Software Engineering in 1968”&lt;&#x2F;a&gt; - B. Randell&lt;&#x2F;li&gt;
&lt;li&gt;1981. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pages.cs.wisc.edu&#x2F;~stjones&#x2F;proj&#x2F;vm_reading&#x2F;ibmrd2505M.pdf&quot;&gt;“The Origin of the VM&#x2F;370 Time-Sharing System”&lt;&#x2F;a&gt; - R. J. Creasy&lt;&#x2F;li&gt;
&lt;li&gt;1982. &lt;code&gt;chroot&lt;&#x2F;code&gt; added to BSD&lt;&#x2F;li&gt;
&lt;li&gt;1998. immunix apparmor introduced&lt;&#x2F;li&gt;
&lt;li&gt;1998. VMWare x86&lt;&#x2F;li&gt;
&lt;li&gt;1999. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.usenix.org&#x2F;legacy&#x2F;publications&#x2F;library&#x2F;proceedings&#x2F;osdi99&#x2F;full_papers&#x2F;banga&#x2F;banga.pdf&quot;&gt;Resource Containers&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;2000. &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.watson.org&#x2F;~robert&#x2F;freebsd&#x2F;sane2000-jail.pdf&quot;&gt;FreeBSD jails&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;2000. SELinux first released OSS&lt;&#x2F;li&gt;
&lt;li&gt;2001. linux vserver&lt;&#x2F;li&gt;
&lt;li&gt;2001. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20060827064533&#x2F;http:&#x2F;&#x2F;www.vmware.com&#x2F;news&#x2F;releases&#x2F;gsx_win_release.html&quot;&gt;VMWare releases gsx&lt;&#x2F;a&gt;, first x86 server virtualization product&lt;&#x2F;li&gt;
&lt;li&gt;2002. VMWare patent - &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;patents.google.com&#x2F;patent&#x2F;US6397242B1&#x2F;en&quot;&gt;“Virtualization System Including a Virtual Machine Monitor For a Computer With Segmented Architecture”&lt;&#x2F;a&gt;, United States Patent #6,397,232&lt;&#x2F;li&gt;
&lt;li&gt;2002. linux namespaces (2.4.19); mount namespace&lt;&#x2F;li&gt;
&lt;li&gt;2002. linux security modules&lt;&#x2F;li&gt;
&lt;li&gt;2003. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.cl.cam.ac.uk&#x2F;research&#x2F;srg&#x2F;netos&#x2F;papers&#x2F;2003-xensosp.pdf&quot;&gt;“Xen and the Art of Virtualization”&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;2003. SELinux merged into linux kernel (2.6.0-test3)&lt;&#x2F;li&gt;
&lt;li&gt;2003. &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;blog.b3k.us&#x2F;2009&#x2F;01&#x2F;25&#x2F;ec2-origins.html&quot;&gt;Work on AWS EC2 kicks off&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;2004. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.usenix.org&#x2F;legacy&#x2F;publications&#x2F;library&#x2F;proceedings&#x2F;lisa04&#x2F;tech&#x2F;full_papers&#x2F;price&#x2F;price.pdf&quot;&gt;Solaris Zones&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;2005. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;wiki.openvz.org&#x2F;History&quot;&gt;OpenVZ (open virtuzzo)&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;2005. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.brendangregg.com&#x2F;blog&#x2F;2017-11-29&#x2F;aws-ec2-virtualization-2017.html&quot;&gt;intel vt-x, amd-v&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;2006. Slicehost launched&lt;&#x2F;li&gt;
&lt;li&gt;2006. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.kernel.org&#x2F;doc&#x2F;ols&#x2F;2006&#x2F;ols2006v1-pages-101-112.pdf&quot;&gt;“Multiple instances of the global linux namespaces”&lt;&#x2F;a&gt; - Eric W. Biederman&lt;&#x2F;li&gt;
&lt;li&gt;2006. AWS EC2 first released - built on xen virtualization&lt;&#x2F;li&gt;
&lt;li&gt;2006. &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;kir.sacred.ru&#x2F;lj&#x2F;openvz-intro.pdf&quot;&gt;“Virtualization in Linux”&lt;&#x2F;a&gt; - Kirill Kolyshkin&lt;&#x2F;li&gt;
&lt;li&gt;2007. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.kernel.org&#x2F;doc&#x2F;ols&#x2F;2007&#x2F;ols2007v2-pages-45-58.pdf&quot;&gt;“Adding Generic Process Containers to the Linux Kernel”&lt;&#x2F;a&gt; - Paul B. Menage, Google&lt;&#x2F;li&gt;
&lt;li&gt;2007. cgroups lands in linux kernel (2.6.24); final form of google process containers&lt;&#x2F;li&gt;
&lt;li&gt;2007. KVM lands in the linux kernel (forked QEMU added KVM support)&lt;&#x2F;li&gt;
&lt;li&gt;2008. LXC released&lt;&#x2F;li&gt;
&lt;li&gt;2008. Microsoft launches Hyper-V for windows server&lt;&#x2F;li&gt;
&lt;li&gt;2009. AWS VPC launch, ELB, Autoscaling, Cloudwatch&lt;&#x2F;li&gt;
&lt;li&gt;2009. Netflix moves movie encoding to the cloud&lt;&#x2F;li&gt;
&lt;li&gt;2009. Canonical adopts apparmor&lt;&#x2F;li&gt;
&lt;li&gt;2010. Netflix moves account signup, etc to the cloud&lt;&#x2F;li&gt;
&lt;li&gt;2010. Hyper-V support &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;past.date-conference.com&#x2F;proceedings-archive&#x2F;2010&#x2F;DATE10&#x2F;PDFFILES&#x2F;05.6_3.PDF&quot;&gt;merged into libvirt&lt;&#x2F;a&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;blockquote&gt;
&lt;p&gt;In 2010, Bolte et al. incorporated support for Hyper-V into
libvirt, so it could be managed through a standardized interface,
together with Xen, QEMU+KVM, and VMware ESX.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;2011. Netflix’s entire operation is on the cloud&lt;&#x2F;li&gt;
&lt;li&gt;2012. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;lists.gnu.org&#x2F;archive&#x2F;html&#x2F;qemu-devel&#x2F;2012-12&#x2F;msg00123.html&quot;&gt;KVM support merged into mainline QEMU&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;2013. user namespaces land in the linux kernel (3.8); this completes support for containers.&lt;&#x2F;li&gt;
&lt;li&gt;2013. Docker released (based on LXC)&lt;&#x2F;li&gt;
&lt;li&gt;2013. LMCTFY (“Let me contain that for you”)&lt;&#x2F;li&gt;
&lt;li&gt;2014. Kubernetes released&lt;&#x2F;li&gt;
&lt;li&gt;2014. Docker Swarm released&lt;&#x2F;li&gt;
&lt;li&gt;2014. docker-compose v1&lt;&#x2F;li&gt;
&lt;li&gt;2014. Docker replaces LXC with &lt;code&gt;libcontainer&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;2014. Canonical begins work on &lt;code&gt;lxd&lt;&#x2F;code&gt;, orchestration for LXC containers&lt;&#x2F;li&gt;
&lt;li&gt;2015. Terraform released&lt;&#x2F;li&gt;
&lt;li&gt;2015. Consul released&lt;&#x2F;li&gt;
&lt;li&gt;2015. Hashicorp releases first version of vault, nomad&lt;&#x2F;li&gt;
&lt;li&gt;2015. Docker spins &lt;code&gt;runc&lt;&#x2F;code&gt; out of its container runtime&lt;&#x2F;li&gt;
&lt;li&gt;2016. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;blog.paranoidsoftware.com&#x2F;dirty-cow-cve-2016-5195-docker-container-escape&#x2F;&quot;&gt;dirty cow container CVE&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;2016. CRI-O launched&lt;&#x2F;li&gt;
&lt;li&gt;2016. docker-compose v2&lt;&#x2F;li&gt;
&lt;li&gt;2016. LXD released&lt;&#x2F;li&gt;
&lt;li&gt;2016. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=4OLlKGT7aVQ&quot;&gt;“AWS re:Invent 2016: Netflix: Container Scheduling, Execution, and Integration with AWS (CON313)”&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;2017. docker-compose v3&lt;&#x2F;li&gt;
&lt;li&gt;2017. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;netflixtechblog.com&#x2F;the-evolution-of-container-usage-at-netflix-3abfc096781b&quot;&gt;“The Evolution of Container Usage at Netflix”&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;2018. Kata, gVisor, Nabla&lt;&#x2F;li&gt;
&lt;li&gt;2018. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;vimeo.com&#x2F;291584445&quot;&gt;“Software Fault Isolation and Edge Computing | Altitude San Francisco 2018”&lt;&#x2F;a&gt; - Tyler McMullen&lt;&#x2F;li&gt;
&lt;li&gt;2019. CRI-O handed over to cncf&lt;&#x2F;li&gt;
&lt;li&gt;2019. Docker Swarm start of 2-year EOL&lt;&#x2F;li&gt;
&lt;li&gt;2019. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.microsoft.com&#x2F;en-us&#x2F;research&#x2F;uploads&#x2F;prod&#x2F;2019&#x2F;04&#x2F;fork-hotos19.pdf&quot;&gt;“A fork() in the road”&lt;&#x2F;a&gt; - Andrew Baumann, Jonathan Appavoo, Orran Krieger, and Timothy Roscoe&lt;&#x2F;li&gt;
&lt;li&gt;2020. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;dl.acm.org&#x2F;doi&#x2F;fullHtml&#x2F;10.1145&#x2F;3365199&quot;&gt;“The Ideal Versus the Real: Revisiting the History of Virtual Machines and Containers”&lt;&#x2F;a&gt; - Allison Randal&lt;&#x2F;li&gt;
&lt;li&gt;2023. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;dylibso.com&#x2F;blog&#x2F;wasi-command-reactor&#x2F;&quot;&gt;“WASI Command and Reactor Modules”&lt;&#x2F;a&gt; - Rob Wong, Zach Shipko, Gavin Hayes&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;docker-ref&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;Which would later be rebranded as “Docker”, after their most famous
product.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;bss&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;2&lt;&#x2F;sup&gt;
&lt;p&gt;“BSS” is also known as “better save space”.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;hey&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;3&lt;&#x2F;sup&gt;
&lt;p&gt;Hey, there’s that “machine” word again.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;gagarin&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;4&lt;&#x2F;sup&gt;
&lt;p&gt;Which had &lt;em&gt;nothing at all&lt;&#x2F;em&gt; to do with Yuri Gagarin’s recent orbital trip, I’m &lt;em&gt;sure&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;mac&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;5&lt;&#x2F;sup&gt;
&lt;p&gt;“MAC” expanded to “Mathematics and Computation” early on, later
expanding to “Multiple Access Computer”, “Machine Aided Cognitions”, and
“Man and Computer”. It also funded the MIT AI lab.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;its&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;6&lt;&#x2F;sup&gt;
&lt;p&gt;MIT also originated the “Incompatible Time Sharing”, which would give
us EMACS.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;words&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;7&lt;&#x2F;sup&gt;
&lt;p&gt;A “word” in this case refers to the number of bits the hardware was optimized to process.
You’re probably reading this on a device with a native word size of 64-bits, but in the past 32-
and 16-bit word sizes were common. In the distant past, you might see 36-bit words!&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;tricks&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;8&lt;&#x2F;sup&gt;
&lt;p&gt;There are are all sorts of neat tricks that paging enables, including “copy on
write” pages – mapping the same memory to different places in the same
address space, and only creating copies of them when they’re mutated.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;third-gen&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;9&lt;&#x2F;sup&gt;
&lt;p&gt;“Third Generation Architecture” refers to the generation of
computers designed in the 1960’s using early integrated circuits; these are
typically called “minicomputers”. They were succeeded by fourth generation
architecture in the early 1970’s which began to use microprocessors.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;Even today, virtualizable architectures can be set to meet “Popek and Goldberg
virtualization requirements.”&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;ibm&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;10&lt;&#x2F;sup&gt;
&lt;p&gt;IBM continued to ship virtual machine monitor systems throughout this
period. However, they were primarily focused on virtualizing earlier
technologies, like mainframes and minicomputers, on top of newer hardware.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;that-said&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;11&lt;&#x2F;sup&gt;
&lt;p&gt;Now, that said, that assumption was frequently (and spectacularly) invalidated.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;gates-brain-dead&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;12&lt;&#x2F;sup&gt;
&lt;p&gt;Gates called these processors “brain dead”. At the time,
IBM and Microsoft were co-developing OS&#x2F;2 for the IBM PC, and IBM wanted to
target the 286. However, the protection modes of the 286 were “one-way” –
once the processor entered protected mode, re-entering real mode required
restarting the system.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;small&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;13&lt;&#x2F;sup&gt;
&lt;p&gt;The benefits of a small team are made evident through this quote, which
is a prime example of &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Conway%27s_law&quot;&gt;Conway’s Law&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;blockquote&gt;
&lt;p&gt;Where under Unix one might say&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D3C6AA; background-color: #2D353B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ls &amp;gt;xx&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;to get a listing of the names of one’s files in xx, on Multics the notation was&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D3C6AA; background-color: #2D353B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;iocall attach user_output file xx&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;list&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;iocall attach user_output syn user_i&#x2F;o&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Even though this very clumsy sequence was used often during the Multics days,
and would have been utterly straightforward to integrate into the Multics
shell, the idea did not occur to us or anyone else at the time. I speculate
that the reason it did not was the sheer size of the Multics project: the
implementors of the IO system were at Bell Labs in Murray Hill, while the
shell was done at MIT. We didn’t consider making changes to the shell (it was
their program); correspondingly, the keepers of the shell may not even have
known of the usefulness, albeit clumsiness, of iocall. […]&lt;&#x2F;p&gt;
&lt;p&gt;Because both the Unix IO system and its shell were under the
exclusive control of Thompson, when the right idea finally surfaced, it was a
matter of an hour or so to implement it.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.bell-labs.com&#x2F;usr&#x2F;dmr&#x2F;www&#x2F;hist.html&quot;&gt;“The Evolution of the Unix Time-sharing System”&lt;&#x2F;a&gt;, Dennis M. Ritchie, 1996&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;popek&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;14&lt;&#x2F;sup&gt;
&lt;p&gt;Indeed, ARM Cortex’s virtualization support is specifically marketed as
meeting “Goldberg and Popek virtualizability requirements”!&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;port&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;15&lt;&#x2F;sup&gt;
&lt;p&gt;A port is a numbered resource, managed by an operating system,
representing a stream of incoming or outgoing network requests.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;docker-how&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;16&lt;&#x2F;sup&gt;
&lt;p&gt;Docker comprises a long-lived process (or “daemon”, in this case
called &lt;code&gt;containerd&lt;&#x2F;code&gt;) for running these virtualized containers (via &lt;code&gt;runc&lt;&#x2F;code&gt;
or &lt;code&gt;crun&lt;&#x2F;code&gt;), a user interface for &lt;em&gt;controlling&lt;&#x2F;em&gt; those containers, a registry
protocol for &lt;em&gt;sharing&lt;&#x2F;em&gt; container images, and a file format describing how
to &lt;em&gt;build&lt;&#x2F;em&gt; those container images. The file format for building docker
images, a &lt;code&gt;Dockerfile&lt;&#x2F;code&gt;, specifies a series of commands that construct a
container image; each command forms a distinct, content-addressable
“layer”. &lt;code&gt;Dockerfile&lt;&#x2F;code&gt;s may source other &lt;code&gt;Dockerfile&lt;&#x2F;code&gt;s during the build
process, common layers are reused between builds.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;oci&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;17&lt;&#x2F;sup&gt;
&lt;p&gt;In 2013, dotCloud rebranded themselves as Docker in an attempt to
capture some of the value of this ecosystem. To ensure trust that the
ecosystem would outlive the company, Docker and CoreOS formed the “Open
Container Initiative” in 2015. As a result, there are alternative
OCI&#x2F;Docker runtimes: &lt;code&gt;crio&lt;&#x2F;code&gt; and &lt;code&gt;podman&lt;&#x2F;code&gt;, for example.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;init&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;18&lt;&#x2F;sup&gt;
&lt;p&gt;Init processes are responsible for setting up the userland system:
they are the root of the tree of userland processes; setting up daemons for
resolving DNS, networking, devices, filesystem mounts, and more.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;borg&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;19&lt;&#x2F;sup&gt;
&lt;p&gt;This control allowed Google to more efficiently allocate shared
resources using their internal orchestration software, AKA &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;research.google&#x2F;pubs&#x2F;pub43438&#x2F;&quot;&gt;“Borg”&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;when-jail&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;20&lt;&#x2F;sup&gt;
&lt;p&gt;The earliest jail-like capability, &lt;code&gt;chroot&lt;&#x2F;code&gt;, was added to AT&amp;amp;T
Unix in 1979. It was also added to the Berkeley Software Distribution
(“&lt;strong&gt;BSD&lt;&#x2F;strong&gt;”&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#bsd&quot;&gt;28&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;) in 1982.  &lt;code&gt;chroot&lt;&#x2F;code&gt; allowed a process to “pivot” the root
directory to a subdirectory, effectively hiding parent directories from a
process. This offered &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20080113162832&#x2F;http:&#x2F;&#x2F;www.bpfh.net&#x2F;simes&#x2F;computing&#x2F;chroot-break.html&quot;&gt;incomplete protection&lt;&#x2F;a&gt;, thus BSD
introduced the &lt;code&gt;jail&lt;&#x2F;code&gt; system call in 2000.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;blockquote&gt;
&lt;p&gt;In the case of the &lt;code&gt;chroot(2)&lt;&#x2F;code&gt; call, a process’s visibility of the file
system name-space is limited to a single subtree. However, the
compartmentalisation does not extend to the process or networking spaces and
therefore both observation of and interference with processes outside their
compartment is possible.&lt;&#x2F;p&gt;
&lt;p&gt;To this end, we describe the new FreeBSD ‘Jail’ facility, which provides a
strong partitioning solution, leveraging existing mechanisms, such as
&lt;code&gt;chroot(2)&lt;&#x2F;code&gt;, to what &lt;em&gt;effectively amounts to a virtual machine environment&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.watson.org&#x2F;~robert&#x2F;freebsd&#x2F;sane2000-jail.pdf&quot;&gt;“Jails: Confining the omnipotent root.”&lt;&#x2F;a&gt;, Poul-Henning Kamp, Robert N. M. Watson, 2000&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Jails did not address resource management or scheduling concerns. Sun addressed
this in 2004 with Solaris’s “Zones”, which provided an Docker-like experience
years in advance. However, as we mentioned, Sun fell on hard times during the
2000’s, eventually meeting its demise in 2010 after being acquired by Oracle.
As a result, Solaris didn’t experience the widespread adoption that various
Linux distributions enjoyed during this time.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;We have been gratified when casual users mistake the technology for a virtual machine.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.usenix.org&#x2F;legacy&#x2F;publications&#x2F;library&#x2F;proceedings&#x2F;lisa04&#x2F;tech&#x2F;full_papers&#x2F;price&#x2F;price.pdf&quot;&gt;“Solaris Zones: Operating System Support for Consolidating Commercial Workloads”&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;blockquote&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;java-killed&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;21&lt;&#x2F;sup&gt;
&lt;p&gt;Plan 9! Which, as you’ll recall from the last article, Java
killed! In the 80s and 90s, “virtual machine” in the sense of “system
emulation” had withered so far as to be supplanted by “virtual machine”
meaning “language model runtime.”&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;openvz&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;22&lt;&#x2F;sup&gt;
&lt;p&gt;Ok, I’m adding this one as a footnote because this is a long post
already. I’m only going to gesture at linux-vserver, which was focused on scaling
webservers through containerized networking. However, Virtuozzo (and its successor project,
OpenVZ) approached containers for an entirely different reason: to enable
checkpoint&#x2F;restore of work on high-performance batch clusters. This would allow
relocation of processes between computers (“nodes”) in a cluster by namespacing
all of their system resources. This required maintaining patches against the linux
kernel at the time, so as far as I can tell it never really took off, but it did
spawn the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;criu.org&#x2F;Main_Page&quot;&gt;“Checkpoint and Restore in Userspace” (&lt;strong&gt;“CRIU”&lt;&#x2F;strong&gt;) project&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;meltdown-spectre&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;23&lt;&#x2F;sup&gt;
&lt;p&gt;This is notwithstanding the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;meltdownattack.com&#x2F;&quot;&gt;Meltdown and Spectre&lt;&#x2F;a&gt; vulnerabilities.
Meltdown exploits a race condition between memory access and privilege checking and affects operating
systems and hypervisors. Exploits allow processes and VMs to read memory across security boundaries,
effectively breaking the illusion of virtual memory. Spectre exploits speculative execution —
a property of modern superscalar processors. Speculative execution executes every code path leading
out from a branch point, throwing away the results from the paths not taken. However, this speculative
execution can affect caches, so the path not taken may be observed by measuring operation timings after
the fact.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;comparisons&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;24&lt;&#x2F;sup&gt;
&lt;p&gt;For an in-depth look at how container and virtualization
approaches compare in terms of performance on various axes, check out &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;dl.acm.org&#x2F;doi&#x2F;pdf&#x2F;10.1145&#x2F;3464298.3493404&quot;&gt;“A
Fresh Look at the Architecture and Performance of Contemporary Isolation
Platforms”&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;and-cranelift-and-wasmtime-but&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;25&lt;&#x2F;sup&gt;
&lt;p&gt;And to develop the Cranelift, Wasmtime, and Wasm Micro
Runtime (&lt;strong&gt;“WAMR”&lt;&#x2F;strong&gt;) projects.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;reactors-commands&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;26&lt;&#x2F;sup&gt;
&lt;p&gt;WASI preview 1 instead classes modules as “reactors” or
“commands”. You can read more on this &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;dylibso.com&#x2F;blog&#x2F;wasi-command-reactor&#x2F;&quot;&gt;on Dylibso’s blog&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;forging&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;27&lt;&#x2F;sup&gt;
&lt;p&gt;This is known as “forging” a descriptor.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;bsd&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;28&lt;&#x2F;sup&gt;
&lt;p&gt;It’s out of scope for this post, but suffice it to say that UNIX
split in the 80’s and 90’s: roughly, Linux, BSD, and SysV. Linux provides
the kernel of popular distributions like Redhat, CentOS, Ubuntu, Debian,
and Android. BSD provides a specification for a kernel for operating
systems: most conspicuously, Apple’s modern operating systems and SunOS.
SunOS’s successor, Solaris, was based on AT&amp;amp;T’s UNIX System V, along with
HP’s HP-UX and IBM’s AIX.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;hr &#x2F;&gt;
</description>
      </item>
      <item>
          <title>Understanding Wasm, Part 3: A System Interface</title>
          <pubDate>Thu, 31 Aug 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://www.neversaw.us/drafts/understanding-wasm-pt-3/</link>
          <guid>https://www.neversaw.us/drafts/understanding-wasm-pt-3/</guid>
          <description xml:base="https://www.neversaw.us/drafts/understanding-wasm-pt-3/">&lt;h1 id=&quot;understanding-wasm&quot;&gt;Understanding WASM&lt;&#x2F;h1&gt;
&lt;h2 id=&quot;part-3-a-virtual-system&quot;&gt;Part 3: A Virtual System&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;em&gt;(This is part 3 of a series. See &lt;a href=&quot;https:&#x2F;&#x2F;www.neversaw.us&#x2F;2023&#x2F;05&#x2F;10&#x2F;understanding-wasm&#x2F;part1&#x2F;virtualization&#x2F;&quot;&gt;part 1, “Virtualization”&lt;&#x2F;a&gt; and &lt;a href=&quot;https:&#x2F;&#x2F;www.neversaw.us&#x2F;2023&#x2F;06&#x2F;30&#x2F;understanding-wasm&#x2F;part2&#x2F;whence-wasm&#x2F;&quot;&gt;part 2, “Whence WASM”&lt;&#x2F;a&gt;.)&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;It’s not enough for a virtual architecture, like WebAssembly, to be portable
across physical processors: after all, if that’s all it could do we’d be
limited to calculating numbers. Chris Lattner’s &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;llvm.org&#x2F;pubs&#x2F;2003-10-01-LLVA.pdf&quot;&gt;“Low-level Virtual
Architecture”&lt;&#x2F;a&gt; established a handy rubric that we’ve been using to judge
WebAssembly as a Virtual Instruction Set Architecture. WebAssembly has:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;✅ &lt;strong&gt;Simple, low-level operations.&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;✅ &lt;strong&gt;No execution-oriented features.&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;✅ &lt;strong&gt;Portability across processor designs.&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;✅ &lt;strong&gt;High-level information to support optimization.&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;✅ &lt;strong&gt;Language independence.&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;❓ &lt;strong&gt;Operating system support.&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Solomon Hykes claimed that if WASI had existed in 2008, he and his companions
at dotCloud&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#docker&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; wouldn’t have had to invent Docker. This is a pretty bold
claim! Docker not only solved a lot of issues for developers over the course of
the last decade, it changed the course of the “platform as a service” market.&lt;&#x2F;p&gt;
&lt;p&gt;This quote sets up WebAssembly (and WASI) as an alternative to Docker; not only
than that, it might be &lt;em&gt;better&lt;&#x2F;em&gt; than Docker. So, uh, what gives? What is WASI?
What is Docker? What does “the future of computing” even mean in this context?&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;contain-your-enthusiasm&quot;&gt;Contain your Enthusiasm&lt;&#x2F;h2&gt;
&lt;p&gt;Let’s start with Docker. Docker was launched in 2013 by dotCloud. The
high-level metaphor of Docker is that of &lt;strong&gt;shipping containers&lt;&#x2F;strong&gt;. Standardized
containers revolutionized the shipping industry: a standard form factor meant a
standard way to load, unload, and transport material. The technology made
shipping &lt;em&gt;everything&lt;&#x2F;em&gt; faster, cheaper, and more reliable. This is Docker’s
raison d’être: to do for computer applications and operations teams what
standard containers did for the shipping industry.&lt;&#x2F;p&gt;
&lt;p&gt;The metaphor is pretty durable: the concrete problem that Docker solved was
that of shared resources. Consider: given a large company, two developers may
develop two different web serving applications (&lt;strong&gt;“services”&lt;&#x2F;strong&gt;) that expect to
listen on the same network port&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#port&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;. Before containerization, these two
developers would have to sync up: who gets to listen on port 80? They’d have to
agree, up-front, before being able to deploy their software. Worse, if they
couldn’t come to agreement about the use of resources, they’d have to involve a
third-party — someone from the operations department — who might solve the
problem by introducing a &lt;em&gt;third&lt;&#x2F;em&gt; server, a reverse proxy layer, to resolve
the conflict.&lt;&#x2F;p&gt;
&lt;p&gt;Docker solves this by giving each service a &lt;strong&gt;virtualized&lt;&#x2F;strong&gt; view of the
operating system’s resources. Both developers may remain agnostic of each other
AND the operations team. The operations team can map network ports as necessary
– or rely on orchestration software, like Nomad or Kubernetes, to do this for
them. Standard containers yield standard tools.&lt;&#x2F;p&gt;
&lt;p&gt;So far, so good. So what &lt;em&gt;is&lt;&#x2F;em&gt; Docker?&lt;&#x2F;p&gt;
&lt;p&gt;Docker is a virtualization technology, just like all of the other
virtualization technologies we’ve talked about in previous posts. However, it
achieves virtualization through a combination of technologies supported by the
kernel of the host operating system: seccomp, namespaces, and control groups.
Namespaces allow for partitioning of operating system concepts across
processes. Seccomp (“secure computing”) allows or disallows the set of system
requests a process may make. Control groups partition use of hardware
resources: the amount of CPU time, number of processors, and amount of memory
processes in the group can use. Each namespace, control group, and seccomp
profile has to be layered properly to make durable the illusion that the
process is running on a virtualized system.&lt;&#x2F;p&gt;
&lt;p&gt;Docker comprises a long-lived process (or “daemon”, in this case called
&lt;code&gt;containerd&lt;&#x2F;code&gt;) for running these virtualized containers (via &lt;code&gt;runc&lt;&#x2F;code&gt; or &lt;code&gt;crun&lt;&#x2F;code&gt;),
a user interface for &lt;em&gt;controlling&lt;&#x2F;em&gt; those containers, a registry protocol for
&lt;em&gt;sharing&lt;&#x2F;em&gt; container images, and a file format describing how to &lt;em&gt;build&lt;&#x2F;em&gt; those
container images. The long-lived process, container builder, and registry
protocol is usually called the “runtime”, while the user interface for
starting, stopping, and managing container state is called a “frontend”. The
file format for building docker images, a &lt;code&gt;Dockerfile&lt;&#x2F;code&gt;, specifies a series of
commands that construct a container image; each command forms a distinct,
content-addressable “layer”. &lt;code&gt;Dockerfile&lt;&#x2F;code&gt;s may source other &lt;code&gt;Dockerfile&lt;&#x2F;code&gt;s
during the build process, common layers are reused between builds.&lt;&#x2F;p&gt;
&lt;p&gt;dotCloud rebranded themselves as Docker in an attempt to capture some of the
value of this ecosystem in 2013; to ensure trust that the ecosystem would
outlive the company the “Open Container Initiative” was formed in 2015. As a
result, there are alternative runtimes (&lt;code&gt;crio&lt;&#x2F;code&gt; from Redhat), frontends
(Rancher), or combinations of the two (&lt;code&gt;podman&lt;&#x2F;code&gt;.)&lt;&#x2F;p&gt;
&lt;p&gt;Containers rely on kernel support: on operating systems that don’t support
namespaces and cgroups containers are typically run in a virtual machine
process. Windows supports containers natively through a &lt;code&gt;hcsshim&lt;&#x2F;code&gt; runtime that
provides namespace and cgroup support through Window’s native Host Compute
Service. Apple’s macOS, however, runs docker containers by spinning up a
virtualized Linux host to run a Docker daemon and container processes.&lt;&#x2F;p&gt;
&lt;p&gt;While the Docker&#x2F;OCI containerization model is ubiquitous today, the
capabilities underpinning it have a much longer history.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;blockquote&gt;
&lt;p&gt;I never intended to use these tools to simulate a system in real-time. I wanted
to watch the cracker’s keystrokes, to trace him, learn his techniques, and warn
his victims. The best solution was to lure him to a sacrificial machine and tap
the connection. The Ethernet is easy to tap, and modified tcpdump software can
separate and store the sessions. But I didn’t have a spare machine handy, so I
took the software route. (Steve Bellovin did construct such a machine. We never
managed to lure anyone interesting to it.)&lt;&#x2F;p&gt;
&lt;p&gt;I consulted the local gurus about the security of a &lt;code&gt;chroot&lt;&#x2F;code&gt; environment. Their
conclusion: it is not perfectly secure, but if compilers and certain programs
are missing, it is very difficult to escape.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.cheswick.com&#x2F;ches&#x2F;papers&#x2F;berferd.pdf&quot;&gt;“An Evening with Berferd”&lt;&#x2F;a&gt;, Bill Cheswick, 1990&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;The need to consolidate servers, decouple hardware provisioning from service
scaling, and migrate batch processes between high performance compute nodes
created a renaissance of virtualization technologies in the late 90’s and early
2000’s. The rapid adoption of the internet drove these use cases, thawing a
nearly twenty year long freeze in virtual machine research.&lt;&#x2F;p&gt;
&lt;p&gt;Let’s walk backwards through time for a second.&lt;&#x2F;p&gt;
&lt;p&gt;Docker was originally implemented using an earlier containerization model
called “LXC” (“Linux Containers”), introduced in 2008. LXC, like many of its
contemporary containerization models, was built on the model of a virtual
machine. Rather than Docker’s model of taking a single process and giving it a
virtual system environment, LXC containers typically virtualized an &lt;code&gt;init&lt;&#x2F;code&gt;
process (like &lt;code&gt;systemd&lt;&#x2F;code&gt;, &lt;code&gt;upstart&lt;&#x2F;code&gt;, or SysV &lt;code&gt;init&lt;&#x2F;code&gt;&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#init&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.) This made them
“feel” much more like a virtual machine, with their own long-lived daemons,
periodic tasks, and system logs.&lt;&#x2F;p&gt;
&lt;p&gt;Linux Containers were made possible in part by Google’s contribution of control
groups (&lt;code&gt;cgroups&lt;&#x2F;code&gt;) to the Linux kernel in 2007. Control groups allowed userland
to communicate resource quotas for process subtrees to the kernel: effectively
allowing container runtimes to dictate the maximum CPU time, parallelism,
network, memory, and disk usage a set of sub-processes should be able to use.
This doesn’t affect the ability of those processes to &lt;em&gt;see&lt;&#x2F;em&gt; certain subsystems:
control groups don’t affect what the process has access to, only the available
quality of service for that access. This control allowed Google to more
efficiently allocate shared resources using their internal orchestration
software&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#borg&quot;&gt;4&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Namespaces are related to earlier &lt;code&gt;jail&lt;&#x2F;code&gt; capabilities. They control what
operating system subresources are visible to jailed processes. The earliest
jail-like capability, &lt;code&gt;chroot&lt;&#x2F;code&gt;, was added to AT&amp;amp;T Unix in 1979. It was also
added to the Berkeley Software Distribution (“&lt;strong&gt;BSD&lt;&#x2F;strong&gt;”&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#bsd&quot;&gt;5&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;) in 1982. &lt;code&gt;chroot&lt;&#x2F;code&gt;
allowed a process to “pivot” the root directory to a subdirectory, effectively
hiding parent directories from a process. This offered &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20080113162832&#x2F;http:&#x2F;&#x2F;www.bpfh.net&#x2F;simes&#x2F;computing&#x2F;chroot-break.html&quot;&gt;incomplete
protection&lt;&#x2F;a&gt;, thus BSD introduced the &lt;code&gt;jail&lt;&#x2F;code&gt; system call in 2000.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;In the case of the &lt;code&gt;chroot(2)&lt;&#x2F;code&gt; call, a process’s visibility of the file
system name-space is limited to a single subtree. However, the
compartmentalisation does not extend to the process or networking spaces and
therefore both observation of and interference with processes outside their
compartment is possible.&lt;&#x2F;p&gt;
&lt;p&gt;To this end, we describe the new FreeBSD ‘Jail’ facility, which provides a
strong partitioning solution, leveraging existing mechanisms, such as
&lt;code&gt;chroot(2)&lt;&#x2F;code&gt;, to what &lt;em&gt;effectively amounts to a virtual machine environment&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.watson.org&#x2F;~robert&#x2F;freebsd&#x2F;sane2000-jail.pdf&quot;&gt;“Jails: Confining the omnipotent root.”&lt;&#x2F;a&gt;, Poul-Henning Kamp, Robert N. M. Watson, 2000&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Jails were effective but did not address resource management or scheduling
concerns. Sun addressed this in 2004 with Solaris’s “Zones”, which provided an
LXC- or Docker-like experience. However, Sun fell on hard times during the
2000’s, eventually meeting its demise in 2010 after being acquired by Oracle.
As a result, Solaris didn’t experience the widespread adoption that various
Linux distributions enjoyed during this time. (We’ll touch on the source of
Sun’s woes a little later.)&lt;&#x2F;p&gt;
&lt;p&gt;Starting in 2002, Linux began adding namespace support. The mount namespace for
filesystems came first, inspired by Plan 9&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#java-killed&quot;&gt;6&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;. Eric W. Biederman
outlined the necessary namespace support in &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.kernel.org&#x2F;doc&#x2F;ols&#x2F;2006&#x2F;ols2006v1-pages-101-112.pdf&quot;&gt;“Multiple Instances of the
Global Linux Namespaces”&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;mnt&lt;&#x2F;code&gt;: The filesystem namespace.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;uts&lt;&#x2F;code&gt;: The UNIX Time-sharing namespace (controlling what hostname is visible to the process.)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;ipc&lt;&#x2F;code&gt;: Inter-process communication namespace.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;net&lt;&#x2F;code&gt;: The network namespace.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;pid&lt;&#x2F;code&gt;: The process identifier namespace.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;user&lt;&#x2F;code&gt;: The user and group namespace.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;time&lt;&#x2F;code&gt;: The time namespace.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Linux added the &lt;code&gt;user&lt;&#x2F;code&gt; namespace in 2013 — the same year Docker was first
released publicly. (This was later followed up with the &lt;code&gt;cgroup&lt;&#x2F;code&gt; namespace in
2016.) Namespaces and cgroups form the basis of what we think of as containers
today&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#openvz&quot;&gt;7&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;As we noted previously, virtualizing the system at the process&#x2F;system interface
required careful virtualization of each &lt;em&gt;kind&lt;&#x2F;em&gt; of system resource visible to
processes, both in terms of which subresources are visible (files, other
processes, users, etc) &lt;em&gt;and&lt;&#x2F;em&gt; in terms of their quality of service (available
memory or bandwidth.) Each of these resources can be virtualized &lt;em&gt;separately&lt;&#x2F;em&gt;,
but the Docker containerization model generally virtualizes them
together&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#selinux&quot;&gt;8&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;We have been gratified when casual users mistake the technology for a virtual machine.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.usenix.org&#x2F;legacy&#x2F;publications&#x2F;library&#x2F;proceedings&#x2F;lisa04&#x2F;tech&#x2F;full_papers&#x2F;price&#x2F;price.pdf&quot;&gt;“Solaris Zones: Operating System Support for Consolidating Commercial Workloads”&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;There’s a fork in the road, here. It is important to understand both paths: why
they diverged, how they’re starting to merge once again, and what that means
for WebAssembly. Containerized processes virtualize at the system interface;
virtual machines virtualize at the hardware interface. However, processes and
virtual machines are two expressions of the same concept: &lt;strong&gt;time-sharing&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;processes&quot;&gt;Processes&lt;&#x2F;h2&gt;
&lt;p&gt;Processes are a near-universal concept in modern operating systems. They
comprise three capabilities:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;A continuous view of processing resources&lt;&#x2F;strong&gt; that initially includes a
single advancing program state with the ability to spawn additional,
concurrent states against the same program within the process
(&lt;strong&gt;“threads”&lt;&#x2F;strong&gt;.)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;A contiguous address namespace&lt;&#x2F;strong&gt;, into which memory may be allocated by
the operating system upon request. This initially contains the program
instructions (or &lt;strong&gt;“text”&lt;&#x2F;strong&gt;), environment variables and arguments, read-only
(or &lt;strong&gt;“static”&lt;&#x2F;strong&gt;) data, space reserved for structures to be initialized at
startup (“block starting symbol”, or &lt;strong&gt;“bss”&lt;&#x2F;strong&gt;&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#bss&quot;&gt;9&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;), and
room for a “stack” of activation frames. A number of system libraries may
also be loaded by the operating system into this address space.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;A system interface&lt;&#x2F;strong&gt;, made available through a set of supervisory calls
(&lt;strong&gt;“system calls”&lt;&#x2F;strong&gt;.) Typically this is implemented through use of dedicated
&lt;code&gt;syscall&lt;&#x2F;code&gt; or system interrupt instructions (e.g., &lt;code&gt;int 0x80&lt;&#x2F;code&gt;, in x86 assembly)
available through the instruction set architecture. The use of supervisory
calls is dictated through calling conventions, including what registers must
be saved, where parameters to the syscall are placed—in memory or on registers— and how results are
retrieved after control returns to the process thread. These conventions
describe an “application binary interface”, or &lt;strong&gt;“ABI”&lt;&#x2F;strong&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;This is a &lt;em&gt;virtual&lt;&#x2F;em&gt; view of the physical machine’s resources: an “extended
machine”&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#hey&quot;&gt;10&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;. The operating system is responsible for enforcing the illusion
that each process operates with independent, full access to the system’s
resources. This illusion is constructed through the operating system’s careful
orchestration of the machine’s processor features — the
processor’s memory mapping hardware, interrupts and traps, mode and protection
rings, and use of privileged instructions.&lt;&#x2F;p&gt;
&lt;p&gt;As widespread as the concept of a process is today, it wasn’t always so:
processes and operating systems emerged &lt;em&gt;alongside&lt;&#x2F;em&gt; virtual machines in the
’60s.&lt;&#x2F;p&gt;
&lt;p&gt;Hardware and software design were, at the start of the 1960s, intertwined. It
was common practice to design parallel computers —those with a number of
processors— by assigning a program to each processor, along with a range
of physical memory to be accessed &lt;em&gt;by&lt;&#x2F;em&gt; that processor. If, during development,
programmers discovered that &lt;em&gt;one&lt;&#x2F;em&gt; process on the system needed additional
space, all other processes had to be reprogrammed to accommodate the new memory
partitions. Similarly, if one process went idle, no other processes could make
use of that idle processor hardware. Programs had to be submitted in batches in
order to maximize utilization of the hardware. Time-sharing systems would
change that.&lt;&#x2F;p&gt;
&lt;iframe width=&quot;640&quot; height=&quot;480&quot;
src=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;embed&#x2F;Q07PhW5sCEk?si=LAZO7ozHwlvegUlr&quot;
title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay;
clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot;
allowfullscreen&gt;&lt;&#x2F;iframe&gt;
&lt;p&gt;In 1961, DARPA, newly flush with cash&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#yuri&quot;&gt;11&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;, funded research on time-sharing operating
systems through “Project MAC”&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#mac&quot;&gt;12&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;. MIT, a participating member, brought their
“Compatible Time Sharing System” (&lt;strong&gt;“CTSS”&lt;&#x2F;strong&gt;&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#its&quot;&gt;13&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;) with them, and along with
Bell Laboratories and General Electric, began work on a successor system called
“MULTICS”. Several teams coordinated on it.&lt;&#x2F;p&gt;
&lt;p&gt;That term we introduced earlier, “extended machine”, originated from this era.
It described a machine that was “easier to program” than the underlying
physical machine. The role of a “monitor” (or “nucleus”, or “kernel”) was to
support these extended machines by using the “bare machine interface”, or
hardware, directly. The monitor scheduled user programs to minimize costly idle
time.&lt;&#x2F;p&gt;
&lt;p&gt;The extended machine typically supported virtual memory, supervisory calls, and
protection rings. Virtual memory was developed so that programs could be
written without advance knowledge of other programs running on the system.&lt;&#x2F;p&gt;
&lt;p&gt;This was accomplished by introducing indirection: the address namespace of a
program no longer mapped directly to the physical address space of memory.
Three techniques were used to accomplish this indirection: paging,
segmentation, or the combination of the two.&lt;&#x2F;p&gt;
&lt;p&gt;With paging, both the process and physical address space are subdivided into
“pages” of memory. Each page represented several hundred “words” of
memory&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#words&quot;&gt;14&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;. Accesses to “non-resident” pages in process address space
trigger hardware faults. The kernel sets traps for those faults: the fault
transfers control to the kernel, which takes action to load the
missing page into physical memory to complete the mapping. Control transfer
back to the process at this point&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#tricks&quot;&gt;15&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.neversaw.us&#x2F;img&#x2F;virtual-memory-paging.png&quot;&gt;&lt;img width=&quot;640&quot; src=&quot;https:&#x2F;&#x2F;www.neversaw.us&#x2F;img&#x2F;virtual-memory-paging.png&quot; alt=&quot;Illustration from &amp;quot;Segmentation and the Design of Multiprogrammed Systems&amp;quot;, Jack B. Dennis, 1965&quot; &#x2F;&gt;&lt;&#x2F;a&gt;
&lt;sup&gt;Illustration from &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;dl.acm.org&#x2F;doi&#x2F;pdf&#x2F;10.1145&#x2F;321296.321310&quot;&gt;“Segmentation and the Design of Multiprogrammed Systems”&lt;&#x2F;a&gt;, Jack B. Dennis, 1965. “N” represents the process address namespace, “M” the physical namespace. Note how the contiguous “N” namespace maps to a discontiguous namespace in “M”.&lt;&#x2F;sup&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Memory segmentation was also used to support virtual memory. Segmentation has
the advantage of allowing larger address namespaces than the native computer
word size would otherwise be capable of representing. Consider that a 16-bit
word can only represent values from 0 to 65535. One popular segmentation scheme
addresses 20-bit values. It accomplishes this by holding another 16-bit value
in a “segment register”, shifting it left by 4 bits (multiplying it by 16) and
adding the resulting value to the base offset held in the operand register.
This allows addressing up to 1MiB of memory. When the segment register changes,
the entire segment of memory is made resident at once — which could be a
single word of memory or a significant subset of physical memory. Some hardware
supports transferring control to the kernel when the segment register changes,
which allows the implementation of virtual memory purely through segmentation.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.neversaw.us&#x2F;img&#x2F;virtual-memory-segmentation.png&quot;&gt;&lt;img width=&quot;640&quot; src=&quot;https:&#x2F;&#x2F;www.neversaw.us&#x2F;img&#x2F;virtual-memory-segmentation.png&quot; alt=&quot;Illustration from &amp;quot;Segmentation and the Design of Multiprogrammed Systems&amp;quot;, Jack B. Dennis, 1965&quot; &#x2F;&gt;&lt;&#x2F;a&gt;
&lt;sup&gt;Illustration from &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;dl.acm.org&#x2F;doi&#x2F;pdf&#x2F;10.1145&#x2F;321296.321310&quot;&gt;“Segmentation and the Design of Multiprogrammed Systems”&lt;&#x2F;a&gt;, Jack B. Dennis, 1965. The left diagram illustrates using a word address to index into the segment. The right diagram illustrates the namespace of segments.&lt;&#x2F;sup&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The variable size of segments could lead to conflict —or thrash—
between processes if the two segments happened to overlap. Given the much
expanded range available to them, desktop 64-bit processors tend to use paging
by itself to implement virtual memory. Processors of the era we’re discussing
used both techniques in conjunction to combine the advantages of paging with the
ability to increase the addressable memory space.&lt;&#x2F;p&gt;
&lt;p&gt;Finally, protection rings change the instruction set architecture available to
the program, trapping or disallowing use of privileged instructions having to
do with memory mapping, input&#x2F;output (&lt;strong&gt;“I&#x2F;O”&lt;&#x2F;strong&gt;) devices, or the manipulation
of software timer interrupts. The operating system runs in a protection ring
with higher privileges. Processes run in a lower ring. Processes may request
services from the operating system, like memory allocation or I&#x2F;O, by making
supervisory calls. System requests are implemented using interrupt instructions
or dedicated &lt;code&gt;syscall&lt;&#x2F;code&gt; instructions available in the instruction set
architecture of the processor.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;(For more on all of this, check out &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;cpu.land&#x2F;&quot;&gt;cpu.land&lt;&#x2F;a&gt; and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;os.phil-opp.com&#x2F;paging-introduction&#x2F;&quot;&gt;Phil Opp’s “Writing an OS in Rust” series&lt;&#x2F;a&gt;)&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Project MAC’s contemporaries included Project GENIE at UC Berkeley and the IBM
System&#x2F;360 and 370. These technologies were built in competition with MULTICS;
IBM found that they their university bids were being out-competed by
time-sharing systems spun out from Project MAC. This led them to develop early
whole-machine virtualization software.&lt;&#x2F;p&gt;
&lt;p&gt;While extended machines made it possible to safely create and run relocatable
programs, much research revolved around the development of new operating
systems. This was more difficult than developing a program for an extended
machine, as only a single kernel could run at a time. This lead to the
development of “pseudo-machines” or “virtual machine monitors”, which used the
bare machine interface to provide many copies of that &lt;em&gt;same&lt;&#x2F;em&gt; bare machine
interface for the purposes of kernel development. Further, these virtual
machine monitors could be &lt;em&gt;nested&lt;&#x2F;em&gt;, so long as the appropriate resource
mappings were set up in hardware ahead of time. There was some debate around
“pure” virtual machine monitors as opposed to “impure” VMMs at this time!
“Impure” VMMs presented an extended bare machine interface to the guest; the
guest machine was aware of the virtualization.&lt;&#x2F;p&gt;
&lt;p&gt;IBM implemented virtual machine monitors on the System&#x2F;370 using a feature of
the processors’ protection rings. Whenever a non-privileged program performed a
privileged operation, the processor hardware would fault. The VMM trapped these
privilege faults; mapping incoming requests for resources and operations to
appropriate backing resources without the knowledge of the guest operating
system. In his July 1974 article &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;web.eecs.umich.edu&#x2F;~prabal&#x2F;teaching&#x2F;eecs582-w11&#x2F;readings&#x2F;Gol74.pdf&quot;&gt;“A Survey of Virtual Machine
Research”&lt;&#x2F;a&gt;, Robert P. Goldberg noted that the primary
difficulty in implementing efficient virtualization of machines lies in the
lack of comprehensive hardware support for trapping “privilege-sensitive”
instructions. Indeed, the month prior, he and Gerald J. Popek proposed a
definition for “virtualizable architecture” in &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;dl.acm.org&#x2F;doi&#x2F;pdf&#x2F;10.1145&#x2F;361011.361073&quot;&gt;“Formal Requirements for
Virtualizable Third Generation Architectures”&lt;&#x2F;a&gt;.
Even today, virtualizable architectures can be set to meet “Popek and Goldberg
virtualization requirements”&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#third-gen&quot;&gt;16&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.neversaw.us&#x2F;img&#x2F;virtual-machine-organization.png&quot;&gt;&lt;img width=&quot;640&quot; src=&quot;https:&#x2F;&#x2F;www.neversaw.us&#x2F;img&#x2F;virtual-machine-organization.png&quot; alt=&quot;Survey of Virtual Machine Research: Robert P. Goldberg, COMPUTER magazine June 1974&quot; &#x2F;&gt;&lt;&#x2F;a&gt;
&lt;sup&gt;Illustration of VMM, extended machine, and interfaces from &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;web.eecs.umich.edu&#x2F;~prabal&#x2F;teaching&#x2F;eecs582-w11&#x2F;readings&#x2F;Gol74.pdf&quot;&gt;“Survey of Virtual Machine Research”&lt;&#x2F;a&gt;, Robert P. Goldberg, COMPUTE June 1974&lt;&#x2F;sup&gt;&lt;&#x2F;p&gt;
&lt;p&gt;So why did virtual machine monitor research halt for so many years?&lt;&#x2F;p&gt;
&lt;p&gt;The Mansfield amendments, passed 1969 and 1973, narrowed the scope of
Department of Defense funds to projects with direct military applications. This
cut public funding for operating systems research. The General Electric 635
used to build MULTICS at MIT cost as much as a passenger jet. MULTICS had been
over-budget and behind schedule for years; Bell Labs pulled out of the MULTICS
project in 1969. The aftermath of the OS research era left many useful ideas
floating in the ether, while virtual machine monitor research would freeze
until the late 1990s&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#ibm&quot;&gt;17&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;iframe src=&quot;https:&#x2F;&#x2F;archive.org&#x2F;embed&#x2F;byte-magazine-1984-11&#x2F;page&#x2F;n229&#x2F;&quot; width=&quot;640&quot; height=&quot;480&quot; frameborder=&quot;0&quot; webkitallowfullscreen=&quot;true&quot; mozallowfullscreen=&quot;true&quot; allowfullscreen&gt;&lt;&#x2F;iframe&gt;
[](https:&#x2F;&#x2F;archive.org&#x2F;details&#x2F;byte-magazine-1984-11&#x2F;page&#x2F;n229&#x2F;mode&#x2F;2up)
&lt;p&gt;Many researchers from the Project MAC days joined up at Xerox PARC. There they
developed the Xerox Alto and Smalltalk, which prefigured the modern personal
computer. By the late 1970s, commercial personal computers were available to
consumers: the Apple II, Tandy TRS-80, and others. The IBM PC launched in 1981,
the Apple Lisa in 1983, and the Macintosh in 1984. The earliest versions of
these computers only ran a single program at a time, typically in conjunction
with a disk operating system (&lt;strong&gt;“DOS”&lt;&#x2F;strong&gt;); later they would run many processes
cooperatively. There was only one user and thus, no need to worry about
time-sharing — these systems could be written to assume cooperation between
all programs running on the machine&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#that-said&quot;&gt;18&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;. In 1982, Intel released the first
commercial chips capable of protected mode operation &amp;amp; on-die memory mapping in
the form of the 80286 processor&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#gates-brain-dead&quot;&gt;19&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;. Taken together with the
rise of high-performance workstations, Microsoft, Intel, and IBM’s PC rapidly
chipped away at the market for time-shared minicomputers.&lt;&#x2F;p&gt;
&lt;p&gt;For the most part, those workstations ran a variant of UNIX.&lt;&#x2F;p&gt;
&lt;p&gt;Dennis Ritchie, Ken Thompson, Douglas McIlroy, and Joe Ossanna developed UNIX
at Bell Laboratories in the aftermath of Bell’s strategic retreat from the
MULTICS project. UNIX benefited from its circumstances: a small
team&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#small&quot;&gt;20&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; with little supervision working on a comparatively cheap computer
(the PDP-7) proved able to iterate on the best ideas in operating systems
research rapidly. Douglas McIlroy managed the department. Douglas was
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.cs.dartmouth.edu&#x2F;~doug&#x2F;components.txt&quot;&gt;particularly animated&lt;&#x2F;a&gt; by the possibilities code reuse
unlocked. UNIX did not start out as a time-sharing system, nor was it a
preemptive operating system. It wasn’t much more than a filesystem supporting a
game &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.bell-labs.com&#x2F;usr&#x2F;dmr&#x2F;www&#x2F;hist.html&quot;&gt;at first&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Back around 1970-71, Unix on the PDP-11&#x2F;20 ran on hardware that not only did
not support virtual memory, but didn’t support any kind of hardware memory
mapping or protection, for example against writing over the kernel. This was
a pain, because we were using the machine for multiple users. When anyone
was working on a program, it was considered a courtesy to yell “A.OUT?”
before trying it, to warn others to save whatever they were editing.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.bell-labs.com&#x2F;usr&#x2F;dmr&#x2F;www&#x2F;odd.html&quot;&gt;“A hardware story”&lt;&#x2F;a&gt;, Dennis Ritchie, 2002&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;The initial system was multiprogrammed — that is, there were two, time-shared
shell processes running, one for each terminal connected to the machine. When
the shell executed another program, it would read the file in over the top of
the shell code and start executing it. The &lt;code&gt;exit()&lt;&#x2F;code&gt; syscall would reload the
shell program over the top of the shell and restart execution. Support for a
&lt;em&gt;tree&lt;&#x2F;em&gt; of processes was added rapidly, however. UNIX inherited &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;dl.acm.org&#x2F;doi&#x2F;pdf&#x2F;10.1145&#x2F;1463822.1463838&quot;&gt;Conway’s
&lt;code&gt;fork&#x2F;join&lt;&#x2F;code&gt; semantics&lt;&#x2F;a&gt; from Project GENIE as &lt;code&gt;fork&#x2F;exec&lt;&#x2F;code&gt;: one
command to make a duplicate of the current process as a child of the forking
process, and a second command run in that child process to replace the
duplicate with the target code. This model of copying processes using
prototypal inheritance directly enabled the containerization models we talked
about earlier (Linux eventually grew &lt;code&gt;clone&lt;&#x2F;code&gt; and &lt;code&gt;unshare&lt;&#x2F;code&gt; to handle removing
privilege from new processes early.)&lt;&#x2F;p&gt;
&lt;p&gt;By 1977 work was underway to port UNIX from the PDP-11 to the Interdata 8&#x2F;32,
as we noted way back in &lt;a href=&quot;https:&#x2F;&#x2F;www.neversaw.us&#x2F;2023&#x2F;05&#x2F;10&#x2F;understanding-wasm&#x2F;part1&#x2F;virtualization&#x2F;&quot;&gt;the first post in this series&lt;&#x2F;a&gt;. (The work had
been validated by porting a copy of UNIX to an IBM System&#x2F;370 virtual machine.)
With the support of Sun Microsystems, IBM, HP, and others, UNIX and C had swept
through the industry by the late eighties. Entering the 90’s, “virtual machine”
came to refer primarily to language virtual machines, like Smalltalk and
Erlang. Consumer operating systems were converging on preemptive, protected
time-sharing, buoyed by advances in Intel’s commercial hardware. Hardware
virtualization features, if supported, primarily existed to support older DOS
programs.&lt;&#x2F;p&gt;
&lt;p&gt;First and foremost, UNIX succeeded as &lt;strong&gt;a user interface&lt;&#x2F;strong&gt;. Not necessarily in the
traditional sense, but rather as a programmer’s work bench. The system put
forward a comparatively simple, unified model of programming. UNIX inherited
code sharing and linking from MULTICS. This code sharing and linking was
powerful, but ultimately subordinate to the system’s user interface. Code
linked into a program shared that program’s resources, capabilities, and access
to the system interface.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;return-to-the-fork-in-the-road&quot;&gt;Return to the fork in the road&lt;&#x2F;h2&gt;
&lt;p&gt;The rapid growth of the internet in the mid-90’s rekindled virtualization
research. Scaling a website meant procuring and provisioning hardware. This
could not be done quickly. Internet companies were required to expend
considerable money well in advance of expected traffic and were largely unable
to recoup costs if that traffic did not materialize. The industry was looking
for a way to commoditize hardware.&lt;&#x2F;p&gt;
&lt;p&gt;x86 was the most popular processor architecture with the best economies of
scale and broadest software support. However, it could not be virtualized
directly: privileged instructions and memory operations would silently fail
without triggering traps.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Unfortunately, many current architectures are not strictly virtualizeable.
This may be because either their instructions are non-virtualizeable, or they
have segmented architectures that are non-virtualizeable, or both.&lt;&#x2F;p&gt;
&lt;p&gt;Unfortunately, the all-but-ubiquitous Intel x86 processor family has both of
these problematic properties, that is, both non-virtualizeable instructions
and non-reversible segmentation. Consequently, no [Virtual Machine Monitor]
based exclusively on direct execution can completely virtualize the x86
architecture.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;patents.google.com&#x2F;patent&#x2F;US6397242B1&#x2F;en&quot;&gt;“Virtualization System Including a Virtual Machine Monitor For a Computer
With Segmented Architecture”&lt;&#x2F;a&gt;, United States Patent #6,397,232&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;The late 90’s saw a growing interest in direct binary translation (&lt;strong&gt;“DBT”&lt;&#x2F;strong&gt;.)
The hegemony of the x86 processor was predicted to crumble. Efforts such as
DAISY and Transmeta’s Crusoe bet against the continued popularity of x86.
Meanwhile, in the language virtual machine space, just-in-time compilation
research blossomed. VMWare was founded in this context, submitting a
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;patents.google.com&#x2F;patent&#x2F;US6397242B1&#x2F;en&quot;&gt;patent&lt;&#x2F;a&gt; early on for a direct-binary-translation method of implementing
virtual machine monitors for the x86 architecture.&lt;&#x2F;p&gt;
&lt;p&gt;VMWare’s virtual machine monitor worked thusly: entering or exiting a
protection ring triggered the translator, which monitored for execution of
untrapped privileged instructions and inject manual VMM trap calls. This
enabled virtualization but added overhead to every system call.&lt;&#x2F;p&gt;
&lt;p&gt;Because DBT added uneven overhead to kernel execution, it was difficult to
associate system use with virtual machine execution. This prevented accurate
billing systems from being constructed around such virtual machines.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.cl.cam.ac.uk&#x2F;research&#x2F;srg&#x2F;netos&#x2F;papers&#x2F;2003-xensosp.pdf&quot;&gt;“Xen and the Art of Virtualization”&lt;&#x2F;a&gt; changed all of that.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;By allowing 100 operating systems to run on a single server, we reduce the
associated costs by two orders of magnitude. Furthermore, by turning the
setup and configuration of each OS into a software concern, we facilitate
much smaller-granularity timescales of hosting.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.cl.cam.ac.uk&#x2F;research&#x2F;srg&#x2F;netos&#x2F;papers&#x2F;2003-xensosp.pdf&quot;&gt;“Xen and the Art of Virtualization”&lt;&#x2F;a&gt;, 2003&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Xen achieved this through paravirtualization: instead of pure virtualization,
it achieved “impure”, cooperative virtualization by modifying the guest operating
systems. In particular, Xen moved the operating system &lt;em&gt;out&lt;&#x2F;em&gt; of the most
protected ring of the processor: from ring 0 to ring 1. Processes continued to
run in ring 3. This gave the operating system its own “extended machine”: while
it lost access to privilege instructions, it gained access to its own
supervisory call system (“hypervisor calls”.)&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.neversaw.us&#x2F;img&#x2F;xen-perf.png&quot;&gt;&lt;img width=&quot;640&quot; src=&quot;https:&#x2F;&#x2F;www.neversaw.us&#x2F;img&#x2F;xen-perf.png&quot; alt=&quot;Xen and the Art of Virtualization: Comparison of native Linux, Xen, VMWare Workstation, and User-mode Linux&quot; &#x2F;&gt;&lt;&#x2F;a&gt;
&lt;sup&gt;Comparison of native Linux, Xen, VMWare Workstation, and User-mode Linux on various benchmarks, from &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.cl.cam.ac.uk&#x2F;research&#x2F;srg&#x2F;netos&#x2F;papers&#x2F;2003-xensosp.pdf&quot;&gt;“Xen and the Art of Virtualization”&lt;&#x2F;a&gt;. Note that OLTP represents relational database workloads and WEB99 represents web-serving.&lt;&#x2F;sup&gt;&lt;&#x2F;p&gt;
&lt;p&gt;In particular, Xen’s performance on web application workloads was a breakthrough.&lt;&#x2F;p&gt;
&lt;p&gt;A few notes on timing: by 2003, the dotcom bubble had burst. The servers that
internet startups had loaded up on flooded the market with cheap used hardware,
causing Sun Microsystems to hemorrhage money. At Amazon, &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;blog.b3k.us&#x2F;2009&#x2F;01&#x2F;25&#x2F;ec2-origins.html&quot;&gt;Benjamin
Black&lt;&#x2F;a&gt; circulated a document describing a standardized
infrastructure; Bezos tasked Chris Pinkham with developing this in 2004. EC2
launched publicly in 2006, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;aws.amazon.com&#x2F;blogs&#x2F;aws&#x2F;amazon_ec2_beta&#x2F;&quot;&gt;powered by Xen&lt;&#x2F;a&gt;. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;courses.cs.washington.edu&#x2F;courses&#x2F;cse452&#x2F;23wi&#x2F;papers&#x2F;yegge-platform-rant.html&quot;&gt;According to Steve
Yegge&lt;&#x2F;a&gt;, sometime in 2002-2003 or so, Bezos issued his famous “services
edict”, stipulating that all Amazon engineering teams deliver their work in the
form of networked services. By 2009, Netflix had moved their video encoding
operations to AWS. Netflix finished transitioning to the cloud in 2011. And
again, just as a reminder, Docker launched in 2013.&lt;&#x2F;p&gt;
&lt;p&gt;Service oriented architectures —composed from hundreds of tiny web
microservices making tiny remote procedure calls to one another over
HTTP— roamed the earth. You might have wondered earlier why two engineers
would come into conflict over a network port on a single machine.&lt;&#x2F;p&gt;
&lt;p&gt;Well, now you know why!&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;blockquote&gt;
&lt;p&gt;Hardware is really just software crystallized early. It is there to make
program schemes run as efficiently as possible. But far too often the
hardware has been presented as a given and it is up to software designers to
make it appear reasonable. […]&lt;&#x2F;p&gt;
&lt;p&gt;As Bob Barton used to say: “Systems programmers are high priests of a low
cult.”&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;worrydream.com&#x2F;EarlyHistoryOfSmalltalk&#x2F;&quot;&gt;“An Early History of Smalltalk”&lt;&#x2F;a&gt;, Alan Kay&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Cloud virtual machines commoditized hardware, severing the connection between
“procuring and provisioning hardware” and “scaling a web service.”&lt;&#x2F;p&gt;
&lt;p&gt;As with memory mapping and protection rings in the 80s, consumer hardware
lagged behind the market’s needs. AMD and Intel introduced hardware support
for virtualization of x86(_64) architectures in 2005 through SVM and VT-X,
respectively. ARM added hardware virtualization support in Cortex-A in 2011&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#popek&quot;&gt;21&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Hardware virtualization support allowed operating systems to integrate
hypervisor capabilities: Windows Server added Hyper-V (2008); Linux, Kernel
Virtual Machines (“KVM”, 2006); and macOS, Hypervisor.framework (2020). (EC2
started moving from Xen to KVM-based “Nitro” virtual machines in 2017. Brendan
Gregg wrote more about the path from the first version of Xen to Nitro
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.brendangregg.com&#x2F;blog&#x2F;2017-11-29&#x2F;aws-ec2-virtualization-2017.html&quot;&gt;here&lt;&#x2F;a&gt;.) In lieu of running Xen or VMWare, consumer operating systems
themselves became capable of running guest operating systems, accelerating the
development of new hypervisor software.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;The core innovation of Docker is not the underlying containerization
technology. As we’ve established: the underpinnings of the OCI format predate
Docker by many years. Docker’s innovation is in its user interface around
authoring, sharing, and running container images. This reusability led to the
creation of standardized orchestration software; virtual machine images have
yet to catch up to this level of popular reusability.&lt;&#x2F;p&gt;
&lt;p&gt;From the hardware perspective, processes and guest operating systems look
nearly the same. Virtualizing the system at the process layer means sharing
more code between the virtualized systems with a finer granularity of
abstractions, but has the advantage of being achievable purely through
software: hardware can’t really tell the difference between a container and any
other process.&lt;&#x2F;p&gt;
&lt;p&gt;Because virtualizing the system at the hardware interface layer is more
coarse-grained with less shared code, VMMs are generally considered safer
targets for multi-tenancy —that is, running untrusted code from third parties
collocated on the same hardware&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#meltdown-spectre&quot;&gt;22&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;. On the other hand, VMMs are
generally perceived as introducing more startup overhead. However, in recent
years, containers and VMMs have converged: Kata containers, AWS’ Firecracker,
and others use the container user interface but run the containers inside
lightweight virtual machines, achieving remarkable performance, security, and
density&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#comparisons&quot;&gt;23&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;The more efficiently tasks can be collocated, the better the margins on
equipment; this is a competitive edge for a hosting company. Processes,
whether virtual machines or containers, have overhead. Switching between
processes takes time and memory; density experiments as of TKTK 202X have shown 10K
containers running on a single host. This was a natural place to look for
improvements, and so content delivery networks — which handle some of the
highest volume of traffic on the internet — started digging into the problem.
Fastly and Cloudflare both landed on web technologies, launching products
in 2018.&lt;&#x2F;p&gt;
&lt;p&gt;Cloudflare launched Workers, which co-locates many user tasks in a single
process using V8 isolates. V8 is, as we discussed previously, the JIT
JavaScript engine open-sourced by Google as part of their Chrome browser.
Workers customers upload JavaScript applications that implement the
ServiceWorker spec; Cloudflare deploys the application to their edge network, with points
of presence across the globe. As a bonus, since WebAssembly support is
available through the web platform API, users that really needed to could
target WASM. (Though they’d be responsible for writing their own bindings to
the ServiceWorker API.)&lt;&#x2F;p&gt;
&lt;p&gt;Fastly launched Compute@Edge, skipping JavaScript in favor of WebAssembly. But
this posed a problem. While JS could rely on the Web platform as a system
interface, WASM does not automatically provide one. In order to hook WASM up to
their edge compute, Fastly had to &lt;em&gt;define&lt;&#x2F;em&gt; an interface: one that was stable
and versioned.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;enter-wasi-finally&quot;&gt;Enter WASI (finally)&lt;&#x2F;h2&gt;
&lt;p&gt;Fastly, Intel, and Mozilla teamed up in 2019 to form the Bytecode Alliance.
Their goal was to define a specification for a standard system interface for
WebAssembly&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#and-cranelift-and-wasmtime-but&quot;&gt;24&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The WebAssembly ISA allows imports and exports: functions that the host can
pass &lt;em&gt;in&lt;&#x2F;em&gt; to the WASM module for internal use, and functions that the WASM
module can hand back to the host to be called &lt;em&gt;by&lt;&#x2F;em&gt; the host on demand. The host
may also provide a chunk of memory for the WASM module to operate on. Imported
and exported functions may only take primitive values — integer and floating
point values of various widths. The host and module may cooperate to transfer
more complicated types. For example, the host and module might agree that a string
is represented as an integer pointer into the module’s memory along with an
integer length.&lt;&#x2F;p&gt;
&lt;p&gt;This is a &lt;em&gt;lot&lt;&#x2F;em&gt; like the sort of &lt;strong&gt;ABI&lt;&#x2F;strong&gt; a process &lt;strong&gt;System Interface&lt;&#x2F;strong&gt; uses.&lt;&#x2F;p&gt;
&lt;p&gt;In fact, the first preview release of WASI explicitly mimicked the POSIX system
interface — roughly speaking, the system interface common to all variations of
UNIX systems. This differed from contemporary tools, like emscripten and
wasm-bindgen, which treat the interface between the host and WASM module as an
internal detail. Those tools were designed to take an existing application and
get it running in a browser with minimal changes, generating both WASM, HTML,
and the JavaScript to integrate the WASM with the Web Platform. If one were to
recompile an application with a newer version of emscripten and try to drop the
WASM onto an older version of the HTML and JS, it may not work. Likewise, the
WASM from an application compiled with wasm-bindgen could not be dropped onto
emscripten HTML and JS or vice versa. They are not &lt;strong&gt;ABI&lt;&#x2F;strong&gt; compatible.&lt;&#x2F;p&gt;
&lt;p&gt;WASI existed to enable multiple compilers and hosts. It would be a [thin
waist][thin-waist] for WebAssembly&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#triple&quot;&gt;25&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;The first preview of WASI launched in 2019. While it included many POSIX
concepts, it omitted full support for network sockets and process forking.
These features are key to supporting high-performance network servers. The
omission was intentional: system interface ABIs don’t just define the boundary
between a process and kernel. They’re also used to enable software &lt;em&gt;linking&lt;&#x2F;em&gt; –
the reuse of compiled artifacts: shared objects (&lt;code&gt;.dylib&lt;&#x2F;code&gt;, &lt;code&gt;.so&lt;&#x2F;code&gt;, or &lt;code&gt;.dll&lt;&#x2F;code&gt;.)
Linking can be performed at compile time (static linking) or at process start
(dynamic linking.) While shared object linking wasn’t defined as part of the
first WASI preview, neither did the specifiers wish to preclude it in future
versions of the specification.&lt;&#x2F;p&gt;
&lt;p&gt;The standard approach to sockets would have exposed too much power between
linked modules. Sockets are typically represented as a “descriptor” or “handle”
in the form of an integer the operating system hands to the process on request.
Operations on the socket are performed by making a system call referencing that
integer, and all linked modules are assumed to have access to the same system
interface. This model is difficult to secure: malicious linked modules can
“sniff” for active descriptors. The system can’t differentiate between linked
modules and the core application logic when receiving calls referencing the
descriptors.&lt;&#x2F;p&gt;
&lt;p&gt;The problem with the POSIX model is that the system interface forms a
monolithic wall between the kernel and the user process, leaving
undifferentiated space on either side. The ABI emphasizes the importance of the
system interface &lt;em&gt;over&lt;&#x2F;em&gt; the importance of the interface between libraries.&lt;&#x2F;p&gt;
&lt;p&gt;Finding a solution to this problem took time.&lt;&#x2F;p&gt;
&lt;p&gt;The second preview of WASI proposes a solution: the WASM component model. This
defines a static linking approach for combining many WASM core modules in a
single file. This proposal is in stage 1, which means that many popular WASM
tools and runtimes do not yet implement it. Despite this, WASI preview 2 hinges
on this proposal, which defines a new interface definition language called
“WebAssembly interface types” (“WIT”.) WIT allows for the definition of named
functions, groups of functions, and high-level types like strings and structs.
WIT also allows for groupings-of-groupings with requirements around exports and
imports, called “worlds”. WIT worlds can be used to generate host code or as a
target for compiling shared code.&lt;&#x2F;p&gt;
&lt;p&gt;This allows sockets to be represented as higher level objects whose full
capabilities aren’t transferred between linked modules, as opposed to an
integer descriptor tracked by the host. (See Dan Gohman’s excellent &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;blog.sunfishcode.online&#x2F;no-ghosts&#x2F;&quot;&gt;“No
Ghosts!”&lt;&#x2F;a&gt; for more on this.)&lt;&#x2F;p&gt;
&lt;p&gt;WASI preview 2 appears to be targeting a release this year. At the time of
writing the component model proposal is only in stage 1, so many popular tools
and runtimes do not support WASM components (or WASI preview 2.) And many
platform-as-a-service (&lt;strong&gt;“PaaS”&lt;&#x2F;strong&gt;) startups have appeared since Solomon Hyke’s tweet.&lt;&#x2F;p&gt;
&lt;p&gt;In the meantime, companies have proposed alternative system interfaces: Deis
labs introduced WAGI in 2020. WAGI sidesteps the issue of missing POSIX support
by using WASI preview 1’s standard input and output instead of sockets. This is
reminiscent of the venerable “common gateway interface” (&lt;strong&gt;“CGI”&lt;&#x2F;strong&gt;) from the
1990s. Fermyon, a WASM PaaS company, supports WAGI through its Spin framework.&lt;&#x2F;p&gt;
&lt;p&gt;In 2023, Wasmer introduced WASIX. WASIX, a superset of WASI, aims to target
more of the POSIX API. This is akin to an Emscripten for server applications,
with the goal of lowering the barrier between existing web services and PaaS
WASM companies. Like Emscripten, WASIX values easy portability of existing
applications. As a result, it doesn’t editorialize too much on the POSIX API.
At the time of writing, WASIX doesn’t support shared object linking. While WASIX
doesn’t preclude linking shared objects in the future, it seems likely that it
would follow the existing linking model, for good or ill&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#ba-wasix&quot;&gt;26&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;The common thread through every technology we’ve talked about is that they were
all created to make it easier for people to work together. To lower the barrier
of cooperation. Processes made it possible to write programs separately,
containers made it possible to use OS resources without up-front coordination,
VMMs made it possible to decouple infrastructure scaling from procuring
hardware. Each of these take a direct conversation between two components and
move it to a third party, an interface. They form a minimal agreement — the
smallest contract that one must agree to in order to work seamlessly with any
other party that also agrees.&lt;&#x2F;p&gt;
&lt;p&gt;WASI, through the web component model, revises the UNIX system interface,
narrowing it from a programmer’s workbench to a secure computing environment.
Taken to the extreme, the WASM component model reinvents the operating system
process model to take modern needs into account. It promises secure
multi-tenancy at runtime while lowering the barrier to cooperation between
library authors and application programmers. From my (maybe optimistic?)
perspective, it’s on the cusp of a Docker moment. The technologies that
underpin Docker predated Docker by years. Docker bundled them together and made
it easy to share one’s work with others. What does WASM’s moment look like?&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;epilogue&quot;&gt;Epilogue&lt;&#x2F;h2&gt;
&lt;p&gt;I’m excited to announce that I’ll be joining Dylibso as of this month to work
on WASM materials, tools, and smooth out friction in the ecosystem wherever I
find it.&lt;&#x2F;p&gt;
&lt;p&gt;Working on these posts has been hugely educational for me on a number of
levels, and I’d like to thank everyone who reviewed these posts — C J
Silverio, Eric Sampson, and Aria Stewart — helped source research — Ron Gee,
– and encouraged me. In particular I’d like to thank my family: my wife,
Krysten, and my parents, Mark and Sue, for dealing with an entire summer of me
talking non-stop about writing these posts and reviewed the most radioactive,
unfit-for-human-consumption drafts of these posts (“WASM good? why?”)&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;bibliography-and-timeline&quot;&gt;Bibliography and Timeline&lt;&#x2F;h2&gt;
&lt;p&gt;So many PDFs this time around!&lt;&#x2F;p&gt;
&lt;p&gt;I’d like to call out &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;dl.acm.org&#x2F;doi&#x2F;fullHtml&#x2F;10.1145&#x2F;3365199&quot;&gt;“The Ideal Versus the Real: Revisiting the History of
Virtual Machines and Containers”&lt;&#x2F;a&gt; by Allison Randal, which dives
more deeply into the history and interrelations between these technologies than
my effort here. Give it a read!&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;1961. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.andrew.cmu.edu&#x2F;course&#x2F;15-440&#x2F;assets&#x2F;READINGS&#x2F;fotheringham1961.pdf&quot;&gt;“Dynamic Storage Allocation in the Atlas Computer”&lt;&#x2F;a&gt;, John Fotheringham,&lt;&#x2F;li&gt;
&lt;li&gt;1961. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.dcs.gla.ac.uk&#x2F;~wpc&#x2F;grcs&#x2F;kilburn.pdf&quot;&gt;“One-level storage system”&lt;&#x2F;a&gt;, Kilburn, Edwards, Lanigan, Sumner&lt;&#x2F;li&gt;
&lt;li&gt;1961. Compatible Time-Sharing System first operational&lt;&#x2F;li&gt;
&lt;li&gt;1962. Atlas Computer operational&lt;&#x2F;li&gt;
&lt;li&gt;1963. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;dl.acm.org&#x2F;doi&#x2F;10.1145&#x2F;1463822.1463838&quot;&gt;“A multiprocessor system design”&lt;&#x2F;a&gt;, Melvin E. Conway&lt;&#x2F;li&gt;
&lt;li&gt;1964. Compatible Time-Sharing System in operational use&lt;&#x2F;li&gt;
&lt;li&gt;1964. IBM System&#x2F;360&lt;&#x2F;li&gt;
&lt;li&gt;1965. GE 645 hardware simulated at MIT for MULTICS&lt;&#x2F;li&gt;
&lt;li&gt;1965. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;dl.acm.org&#x2F;doi&#x2F;pdf&#x2F;10.1145&#x2F;321296.321310&quot;&gt;“Segmentation and the Design of Multiprogrammed Computer Systems”&lt;&#x2F;a&gt; - Jack B. Dennis
&lt;ul&gt;
&lt;li&gt;cites 1961 “one-level storage system”&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;1966. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;dl.acm.org&#x2F;doi&#x2F;10.1145&#x2F;365230.365252&quot;&gt;“Programming Semantics for Multiprogrammed Computations”&lt;&#x2F;a&gt; - Jack B. Dennis, Earl C. Van Horn
&lt;ul&gt;
&lt;li&gt;cites 1963 “A multiprocessor system design”&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;1967. GE 645 hardware received at MIT&lt;&#x2F;li&gt;
&lt;li&gt;1968. [“Virtual Memory, Processes,and Sharing in MULTICS”][multics-virtual-memory] - Robert C. Daley, Jack B. Dennis&lt;&#x2F;li&gt;
&lt;li&gt;1969. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.bell-labs.com&#x2F;usr&#x2F;dmr&#x2F;www&#x2F;hist.html&quot;&gt;UNIX v1 running on a pdp-7&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;1969. MULTICS replaces GECOS on GE 645&lt;&#x2F;li&gt;
&lt;li&gt;1970. “Virtual Memory”, Peter Denning
&lt;ul&gt;
&lt;li&gt;cites 1961 “one-level storage”&lt;&#x2F;li&gt;
&lt;li&gt;cites 1961 “dynamic storage allocation”&lt;&#x2F;li&gt;
&lt;li&gt;cites 1966 “Programming Semantics for Multiprogrammed Computations” Jack B. Dennis, Earl C. Van Horn&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;1970. IBM System&#x2F;370 released&lt;&#x2F;li&gt;
&lt;li&gt;1971. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.bell-labs.com&#x2F;usr&#x2F;dmr&#x2F;www&#x2F;1stEdman.html&quot;&gt;UNIX moved to the PDP-11&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;1973. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;dl.acm.org&#x2F;doi&#x2F;pdf&#x2F;10.1145&#x2F;800122.803946&quot;&gt;“Virtual machine or virtual operating system”&lt;&#x2F;a&gt;, Bellino, J, C Hans
&lt;ul&gt;
&lt;li&gt;this seems a LOT like paravirtualization and&#x2F;or containers — could not achieve full performance
virtualizing an entire IBM 360 machine, so the VMM provided “higher level” primitives&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;1974. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;web.eecs.umich.edu&#x2F;~prabal&#x2F;teaching&#x2F;eecs582-w11&#x2F;readings&#x2F;Gol74.pdf&quot;&gt;“Survey of Virtual Machine Research”&lt;&#x2F;a&gt;, Robert P. Goldberg
&lt;ul&gt;
&lt;li&gt;cites bellino&#x2F;hans 1973 re: “pure” vs “impure” virtual machines&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;1979. UNIX v7, introduction of &lt;code&gt;chroot&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;1979. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;dl.acm.org&#x2F;doi&#x2F;pdf&#x2F;10.5555&#x2F;800091.802915&quot;&gt;“Software Engineering in 1968”&lt;&#x2F;a&gt; - B. Randell&lt;&#x2F;li&gt;
&lt;li&gt;1981. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pages.cs.wisc.edu&#x2F;~stjones&#x2F;proj&#x2F;vm_reading&#x2F;ibmrd2505M.pdf&quot;&gt;“The Origin of the VM&#x2F;370 Time-Sharing System”&lt;&#x2F;a&gt; - R. J. Creasy&lt;&#x2F;li&gt;
&lt;li&gt;1982. &lt;code&gt;chroot&lt;&#x2F;code&gt; added to BSD&lt;&#x2F;li&gt;
&lt;li&gt;1998. immunix apparmor introduced&lt;&#x2F;li&gt;
&lt;li&gt;1998. VMWare x86&lt;&#x2F;li&gt;
&lt;li&gt;1999. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.usenix.org&#x2F;legacy&#x2F;publications&#x2F;library&#x2F;proceedings&#x2F;osdi99&#x2F;full_papers&#x2F;banga&#x2F;banga.pdf&quot;&gt;Resource Containers&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;2000. &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.watson.org&#x2F;~robert&#x2F;freebsd&#x2F;sane2000-jail.pdf&quot;&gt;FreeBSD jails&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;2000. SELinux first released OSS&lt;&#x2F;li&gt;
&lt;li&gt;2001. linux vserver&lt;&#x2F;li&gt;
&lt;li&gt;2001. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20060827064533&#x2F;http:&#x2F;&#x2F;www.vmware.com&#x2F;news&#x2F;releases&#x2F;gsx_win_release.html&quot;&gt;VMWare releases gsx&lt;&#x2F;a&gt;, first x86 server virtualization product&lt;&#x2F;li&gt;
&lt;li&gt;2002. VMWare patent - &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;patents.google.com&#x2F;patent&#x2F;US6397242B1&#x2F;en&quot;&gt;“Virtualization System Including a Virtual Machine Monitor For a Computer With Segmented Architecture”&lt;&#x2F;a&gt;, United States Patent #6,397,232&lt;&#x2F;li&gt;
&lt;li&gt;2002. linux namespaces (2.4.19); mount namespace&lt;&#x2F;li&gt;
&lt;li&gt;2002. linux security modules&lt;&#x2F;li&gt;
&lt;li&gt;2003. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.cl.cam.ac.uk&#x2F;research&#x2F;srg&#x2F;netos&#x2F;papers&#x2F;2003-xensosp.pdf&quot;&gt;“Xen and the Art of Virtualization”&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;2003. SELinux merged into linux kernel (2.6.0-test3)&lt;&#x2F;li&gt;
&lt;li&gt;2003. &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;blog.b3k.us&#x2F;2009&#x2F;01&#x2F;25&#x2F;ec2-origins.html&quot;&gt;Work on AWS EC2 kicks off&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;2004. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.usenix.org&#x2F;legacy&#x2F;publications&#x2F;library&#x2F;proceedings&#x2F;lisa04&#x2F;tech&#x2F;full_papers&#x2F;price&#x2F;price.pdf&quot;&gt;Solaris Zones&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;2005. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;wiki.openvz.org&#x2F;History&quot;&gt;OpenVZ (open virtuzzo)&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;2005. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.brendangregg.com&#x2F;blog&#x2F;2017-11-29&#x2F;aws-ec2-virtualization-2017.html&quot;&gt;intel vt-x, amd-v&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;2006. Slicehost launched&lt;&#x2F;li&gt;
&lt;li&gt;2006. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.kernel.org&#x2F;doc&#x2F;ols&#x2F;2006&#x2F;ols2006v1-pages-101-112.pdf&quot;&gt;“Multiple instances of the global linux namespaces”&lt;&#x2F;a&gt; - Eric W. Biederman&lt;&#x2F;li&gt;
&lt;li&gt;2006. AWS EC2 first released - built on xen virtualization&lt;&#x2F;li&gt;
&lt;li&gt;2007. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.kernel.org&#x2F;doc&#x2F;ols&#x2F;2007&#x2F;ols2007v2-pages-45-58.pdf&quot;&gt;“Adding Generic Process Containers to the Linux Kernel”&lt;&#x2F;a&gt; - Paul B. Menage, Google&lt;&#x2F;li&gt;
&lt;li&gt;2007. cgroups lands in linux kernel (2.6.24); final form of google process containers&lt;&#x2F;li&gt;
&lt;li&gt;2007. KVM lands in the linux kernel (forked QEMU added KVM support)&lt;&#x2F;li&gt;
&lt;li&gt;2008. LXC released&lt;&#x2F;li&gt;
&lt;li&gt;2008. Microsoft launches Hyper-V for windows server&lt;&#x2F;li&gt;
&lt;li&gt;2009. AWS VPC launch, ELB, Autoscaling, Cloudwatch&lt;&#x2F;li&gt;
&lt;li&gt;2009. Netflix moves movie encoding to the cloud&lt;&#x2F;li&gt;
&lt;li&gt;2009. Canonical adopts apparmor&lt;&#x2F;li&gt;
&lt;li&gt;2010. Netflix moves account signup, etc to the cloud&lt;&#x2F;li&gt;
&lt;li&gt;2010. Hyper-V support &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;past.date-conference.com&#x2F;proceedings-archive&#x2F;2010&#x2F;DATE10&#x2F;PDFFILES&#x2F;05.6_3.PDF&quot;&gt;merged into libvirt&lt;&#x2F;a&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;blockquote&gt;
&lt;p&gt;In 2010, Bolte et al. incorporated support for Hyper-V into
libvirt, so it could be managed through a standardized interface,
together with Xen, QEMU+KVM, and VMware ESX.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;2011. Netflix’s entire operation is on the cloud&lt;&#x2F;li&gt;
&lt;li&gt;2012. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;lists.gnu.org&#x2F;archive&#x2F;html&#x2F;qemu-devel&#x2F;2012-12&#x2F;msg00123.html&quot;&gt;KVM support merged into mainline QEMU&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;2013. user namespaces land in the linux kernel (3.8); this completes support for containers [1]&lt;&#x2F;li&gt;
&lt;li&gt;2013. Docker released (based on LXC)&lt;&#x2F;li&gt;
&lt;li&gt;2013. LMCTFY (“Let me contain that for you”)&lt;&#x2F;li&gt;
&lt;li&gt;2014. Kubernetes released&lt;&#x2F;li&gt;
&lt;li&gt;2014. Docker Swarm released&lt;&#x2F;li&gt;
&lt;li&gt;2014. docker-compose v1&lt;&#x2F;li&gt;
&lt;li&gt;2014. Docker replaces LXC with &lt;code&gt;libcontainer&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;2014. Canonical begins work on &lt;code&gt;lxd&lt;&#x2F;code&gt;, orchestration for LXC containers&lt;&#x2F;li&gt;
&lt;li&gt;2015. Terraform released&lt;&#x2F;li&gt;
&lt;li&gt;2015. Consul released&lt;&#x2F;li&gt;
&lt;li&gt;2015. Hashicorp releases first version of vault, nomad&lt;&#x2F;li&gt;
&lt;li&gt;2015. Docker spins &lt;code&gt;runc&lt;&#x2F;code&gt; out of its container runtime&lt;&#x2F;li&gt;
&lt;li&gt;2016. dirty cow container CVE (https:&#x2F;&#x2F;blog.paranoidsoftware.com&#x2F;dirty-cow-cve-2016-5195-docker-container-escape&#x2F;)&lt;&#x2F;li&gt;
&lt;li&gt;2016. CRI-O launched&lt;&#x2F;li&gt;
&lt;li&gt;2016. docker-compose v2&lt;&#x2F;li&gt;
&lt;li&gt;2016. LXD released&lt;&#x2F;li&gt;
&lt;li&gt;2017. docker-compose v3&lt;&#x2F;li&gt;
&lt;li&gt;2018. Kata, gVisor, Nabla&lt;&#x2F;li&gt;
&lt;li&gt;2019. CRI-O handed over to cncf&lt;&#x2F;li&gt;
&lt;li&gt;2019. Docker Swarm start of 2-year EOL&lt;&#x2F;li&gt;
&lt;li&gt;2020. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;dl.acm.org&#x2F;doi&#x2F;fullHtml&#x2F;10.1145&#x2F;3365199&quot;&gt;“The Ideal Versus the Real: Revisiting the History of Virtual Machines and Containers”&lt;&#x2F;a&gt; - Allison Randal&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;docker&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;Which would later be rebranded as “Docker”, after their most famous
product.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;port&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;2&lt;&#x2F;sup&gt;
&lt;p&gt;A port is a numbered resource, managed by an operating system,
representing a stream of incoming or outgoing network requests.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;init&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;3&lt;&#x2F;sup&gt;
&lt;p&gt;Init processes are responsible for setting up the userland system:
they are the root of the tree of userland processes; setting up daemons for
resolving DNS, networking, devices, filesystem mounts, and more.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;borg&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;4&lt;&#x2F;sup&gt;
&lt;p&gt;AKA &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;research.google&#x2F;pubs&#x2F;pub43438&#x2F;&quot;&gt;“Borg”&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;bsd&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;5&lt;&#x2F;sup&gt;
&lt;p&gt;It’s out of scope for this post, but suffice it to say that UNIX
split in the 80’s and 90’s: roughly, Linux, BSD, and SysV. Linux provides
the kernel of popular distributions like Redhat, CentOS, Ubuntu, Debian,
and Android. BSD provides a specification for a kernel for operating
systems: most conspicuously, Apple’s modern operating systems and SunOS.
SunOS’s successor, Solaris, was based on AT&amp;amp;T’s UNIX System V, along with
HP’s HP-UX and IBM’s AIX.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;java-killed&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;6&lt;&#x2F;sup&gt;
&lt;p&gt;Plan 9! Which, as you’ll recall from the last article, Java
killed! In the 80s and 90s, “virtual machine” in the sense of “system
emulation” had withered so far as to be supplanted by “virtual machine”
meaning “language model runtime.”&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;openvz&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;7&lt;&#x2F;sup&gt;
&lt;p&gt;Ok, I’m adding this one as a footnote because this is a long post
already. I’m only going to gesture at linux-vserver, which was focused on scaling
webservers through containerized networking. However, Virtuozzo (and its successor project,
OpenVZ) approached containerization for an entirely different reason: to enable
checkpoint&#x2F;restore of work on high-performance batch clusters. This would allow
relocation of processes between computers (“nodes”) in a cluster by namespacing
all of their system resources. This required maintaining patches against the linux
kernel at the time, so as far as I can tell it never really took off, but it did
spawn the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;criu.org&#x2F;Main_Page&quot;&gt;“Checkpoint and Restore in Userspace” (&lt;strong&gt;“CRIU”&lt;&#x2F;strong&gt;) project&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;selinux&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;8&lt;&#x2F;sup&gt;
&lt;p&gt;And I didn’t touch on SELinux, which the NSA contributed to the Linux kernel
for, um, &lt;em&gt;reasons&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;bss&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;9&lt;&#x2F;sup&gt;
&lt;p&gt;“BSS” is also known as “better save space”.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;hey&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;10&lt;&#x2F;sup&gt;
&lt;p&gt;Hey, there’s that “machine” word again.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;yuri&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;11&lt;&#x2F;sup&gt;
&lt;p&gt;Which had &lt;em&gt;nothing at all&lt;&#x2F;em&gt; to do with Yuri Gagarin’s recent orbital trip, I’m &lt;em&gt;sure&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;mac&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;12&lt;&#x2F;sup&gt;
&lt;p&gt;“MAC” expanded to “Mathematics and Computation” early on, later
expanding to “Multiple Access Computer”, “Machine Aided Cognitions”, and
“Man and Computer”. It also funded the MIT AI lab.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;its&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;13&lt;&#x2F;sup&gt;
&lt;p&gt;MIT also originated the “Incompatible Time Sharing”, which would give
us EMACS.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;words&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;14&lt;&#x2F;sup&gt;
&lt;p&gt;A “word” in this case refers to the number of bits the hardware was optimized to process.
You’re probably reading this on a device with a native word size of 64-bits, but in the past 32-
and 16-bit word sizes were common. In the distant past, you might see 36-bit words!&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;tricks&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;15&lt;&#x2F;sup&gt;
&lt;p&gt;There are are all sorts of neat tricks that paging enables, including “copy on
write” pages — mapping the same memory to different places in the same
address space, and only creating copies of them when they’re mutated.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;third-gen&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;16&lt;&#x2F;sup&gt;
&lt;p&gt;“Third Generation Architecture” refers to the generation of
computers designed in the 1960’s using early integrated circuits; these are
typically called “minicomputers”. They were succeeded by fourth generation
architecture in the early 1970’s which began to use microprocessors.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;ibm&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;17&lt;&#x2F;sup&gt;
&lt;p&gt;IBM continued to ship virtual machine monitor systems throughout this
period. However, they were primarily focused on virtualizing earlier
technologies, like mainframes and minicomputers, on top of newer hardware.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;that-said&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;18&lt;&#x2F;sup&gt;
&lt;p&gt;Now, that said, that assumption was frequently (and spectacularly) invalidated.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;gates-brain-dead&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;19&lt;&#x2F;sup&gt;
&lt;p&gt;Gates called these processors “brain dead”. At the time,
IBM and Microsoft were co-developing OS&#x2F;2 for the IBM PC, and IBM wanted to
target the 286. However, the protection modes of the 286 were “one-way” –
once the processor entered protected mode, re-entering real mode required
restarting the system.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;small&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;20&lt;&#x2F;sup&gt;
&lt;p&gt;The benefits of a small team are made evident through this quote, which
is a prime example of [Conway’s Law][conway]:&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;blockquote&gt;
&lt;p&gt;Where under Unix one might say&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D3C6AA; background-color: #2D353B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ls &amp;gt;xx&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;to get a listing of the names of one’s files in xx, on Multics the notation was&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D3C6AA; background-color: #2D353B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;iocall attach user_output file xx&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;list&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;iocall attach user_output syn user_i&#x2F;o&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Even though this very clumsy sequence was used often during the Multics days,
and would have been utterly straightforward to integrate into the Multics
shell, the idea did not occur to us or anyone else at the time. I speculate
that the reason it did not was the sheer size of the Multics project: the
implementors of the IO system were at Bell Labs in Murray Hill, while the
shell was done at MIT. We didn’t consider making changes to the shell (it was
their program); correspondingly, the keepers of the shell may not even have
known of the usefulness, albeit clumsiness, of iocall. […]&lt;&#x2F;p&gt;
&lt;p&gt;Because both the Unix IO system and its shell were under the
exclusive control of Thompson, when the right idea finally surfaced, it was a
matter of an hour or so to implement it.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.bell-labs.com&#x2F;usr&#x2F;dmr&#x2F;www&#x2F;hist.html&quot;&gt;“The Evolution of the Unix Time-sharing System”&lt;&#x2F;a&gt;, Dennis M. Ritchie, 1996&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;popek&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;21&lt;&#x2F;sup&gt;
&lt;p&gt;Indeed, ARM Cortex’s virtualization support is specifically marketed as
meeting “Goldberg and Popek virtualizability requirements”!&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;meltdown-spectre&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;22&lt;&#x2F;sup&gt;
&lt;p&gt;This is notwithstanding the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;meltdownattack.com&#x2F;&quot;&gt;Meltdown and Spectre&lt;&#x2F;a&gt; vulnerabilities.
Meltdown exploits a race condition between memory access and privilege checking and affects operating
systems and hypervisors. Exploits allow processes and VMs to read memory across security boundaries,
effectively breaking the illusion of virtual memory. Spectre exploits speculative execution —
a property of modern superscalar processors. Speculative execution executes every code path leading
out from a branch point, throwing away the results from the paths not taken. However, this speculative
execution can affect caches, so the path not taken may be observed by measuring operation timings after
the fact.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;comparisons&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;23&lt;&#x2F;sup&gt;
&lt;p&gt;For an in-depth look at how containerization and virtualization
approaches compare in terms of performance on various axes, check out &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;dl.acm.org&#x2F;doi&#x2F;pdf&#x2F;10.1145&#x2F;3464298.3493404&quot;&gt;“A
Fresh Look at the Architecture and Performance of Contemporary Isolation
Platforms”&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;and-cranelift-and-wasmtime-but&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;24&lt;&#x2F;sup&gt;
&lt;p&gt;And to develop the Cranelift, Wasmtime, and WASM Micro
Runtime (&lt;strong&gt;“WAMR”&lt;&#x2F;strong&gt;) projects.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;triple&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;25&lt;&#x2F;sup&gt;
&lt;p&gt;This is where we get the &lt;code&gt;wasm32-wasi&lt;&#x2F;code&gt; target triple (and why it’s
different from &lt;code&gt;wasm32-unknown-unknown&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;ba-wasix&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;26&lt;&#x2F;sup&gt;
&lt;p&gt;The Bytecode Alliance has taken a &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.infoworld.com&#x2F;article&#x2F;3700569&#x2F;wasix-undermines-webassembly-system-interface-spec-bytecode-alliance-says.html&quot;&gt;dim view&lt;&#x2F;a&gt; of WASIX.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;hr &#x2F;&gt;
</description>
      </item>
      <item>
          <title>Understanding Wasm, Part 2: Whence Wasm</title>
          <pubDate>Fri, 30 Jun 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://www.neversaw.us/2023/06/30/understanding-wasm/part2/whence-wasm/</link>
          <guid>https://www.neversaw.us/2023/06/30/understanding-wasm/part2/whence-wasm/</guid>
          <description xml:base="https://www.neversaw.us/2023/06/30/understanding-wasm/part2/whence-wasm/">&lt;h1 id=&quot;understanding-wasm&quot;&gt;Understanding Wasm&lt;&#x2F;h1&gt;
&lt;h2 id=&quot;part-2-whence-wasm&quot;&gt;Part 2: Whence Wasm&lt;&#x2F;h2&gt;
&lt;p&gt;“Write once, run anywhere” is a great sales pitch. It grabs your attention.
It’s pithy! It invites the reader to fill in the blanks of “who is writing
what, where is it going, and how does it get there” with the answer that most
appeals to them. This was Java’s sales pitch. WebAssembly seems to have the
same goal. Given that Java still exists, why do we need WebAssembly? What makes
them different?&lt;&#x2F;p&gt;</description>
      </item>
      <item>
          <title>GUARDA COME DONDOLO &#x2F; Edouardo Vianello</title>
          <pubDate>Fri, 30 Jun 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://www.neversaw.us/links/guarda-come-dondolo-edouardo-vianello/</link>
          <guid>https://www.neversaw.us/links/guarda-come-dondolo-edouardo-vianello/</guid>
          <description xml:base="https://www.neversaw.us/links/guarda-come-dondolo-edouardo-vianello/">&lt;p&gt;A little 1960’s Italian pop music to kick off the weekend.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>understanding wasm pt 2: whence wasm</title>
          <pubDate>Thu, 29 Jun 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://www.neversaw.us/drafts/understanding-wasm-pt-2/</link>
          <guid>https://www.neversaw.us/drafts/understanding-wasm-pt-2/</guid>
          <description xml:base="https://www.neversaw.us/drafts/understanding-wasm-pt-2/">&lt;h1 id=&quot;understanding-wasm&quot;&gt;understanding wasm&lt;&#x2F;h1&gt;
&lt;h2 id=&quot;part-2-whence-wasm&quot;&gt;part 2: whence wasm&lt;&#x2F;h2&gt;
&lt;p&gt;“Write once, run anywhere” is a great sales pitch. It grabs your attention.
It’s pithy! It invites the reader to fill in the blanks of “who is writing
what, where is it going, and how does it get there” with the answer that most
appeals to them. This was Java’s sales pitch. WebAssembly seems to have the
same goal. Given that Java still exists, why do we need WebAssembly? What makes
them different?&lt;&#x2F;p&gt;</description>
      </item>
      <item>
          <title>Anxiety Groove | Louie Zong</title>
          <pubDate>Fri, 23 Jun 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://www.neversaw.us/links/anxiety-groove-louie-zong/</link>
          <guid>https://www.neversaw.us/links/anxiety-groove-louie-zong/</guid>
          <description xml:base="https://www.neversaw.us/links/anxiety-groove-louie-zong/">&lt;p&gt;Louie Zong is a heckin’ treasure.
There’s a huge list of his stuff I want to link you to but I’m going
to hold off on that.
He makes music, cartoons, 3d art, videos, teaching content, the list
goes on.
Having just got back from being social for several days in a row,
including a (lovely) wedding reception near Mt. Hood, it perfectly
captures how I feel. “Glad you guys are having fun! I’m gonna
bounce!” Thankfully, I have a relatively quiet weekend coming up. But
I did find myself scooting around town singing along to this on
repeat.
OK, I lied about holding off because I &lt;em&gt;have to link&lt;&#x2F;em&gt; to his &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=KBYvH3myqyg&quot;&gt;Mario
italodisco album&lt;&#x2F;a&gt;. I
can’t not!&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Plain Text Journaling · peppe.rs</title>
          <pubDate>Tue, 20 Jun 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://www.neversaw.us/links/plain-text-journaling-peppe-rs/</link>
          <guid>https://www.neversaw.us/links/plain-text-journaling-peppe-rs/</guid>
          <description xml:base="https://www.neversaw.us/links/plain-text-journaling-peppe-rs/">&lt;p&gt;This is really quite similar to my &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.neversaw.us&#x2F;2021&#x2F;04&#x2F;27&#x2F;my-notetaking-setup&#x2F;&quot;&gt;neovim notetaking setup&lt;&#x2F;a&gt;, with
a bit more structure.
I particularly enjoyed their vim-specific improvements, like using &lt;code&gt;iabbrev&lt;&#x2F;code&gt; to shorten common words (like &lt;code&gt;todo&lt;&#x2F;code&gt; and &lt;code&gt;done&lt;&#x2F;code&gt; to
&lt;code&gt;·&lt;&#x2F;code&gt; and &lt;code&gt;×&lt;&#x2F;code&gt;, respectively) and &lt;code&gt;formatprg&lt;&#x2F;code&gt; for automatic todo sorting. And using syntax highlighting was a beautiful detail.
(I’m filing these away as todo list items for myself, to be honest.)
The post also comes with a &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.neversaw.us&#x2F;tags&#x2F;nix&quot;&gt;&lt;strong&gt;#nix&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt; flake too. As an aside, I intend to start gathering info about nix,
since it looks quite promising as a system setup tool. I’ve never &lt;em&gt;quite&lt;&#x2F;em&gt; been happy with ansible for those purposes, especially when it comes
to local dev.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Understanding Wasm, Part 1: Virtualization</title>
          <pubDate>Wed, 10 May 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://www.neversaw.us/2023/05/10/understanding-wasm/part1/virtualization/</link>
          <guid>https://www.neversaw.us/2023/05/10/understanding-wasm/part1/virtualization/</guid>
          <description xml:base="https://www.neversaw.us/2023/05/10/understanding-wasm/part1/virtualization/">&lt;h1 id=&quot;understanding-wasm&quot;&gt;Understanding Wasm&lt;&#x2F;h1&gt;
&lt;h2 id=&quot;part-1-virtualization&quot;&gt;Part 1: Virtualization&lt;&#x2F;h2&gt;
&lt;p&gt;So, this all started when I tried to answer a colleague’s question about “what
makes WebAssembly (Wasm) different from the Java Virtual Machine (JVM)?” They
were particularly interested in parsing out Wasm’s goals as they overlapped and
differed from the historical goals of the JVM (&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Write_once,_run_anywhere&quot;&gt;“write once, run
anywhere”&lt;&#x2F;a&gt;). Further, they were curious about the differences in approach
that lead folks to believe Wasm might succeed at achieving these goals. You
might say:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Wasm is a Web platform technology, developed and supported in the open
by multiple vendors. The JVM was primarily driven by a single vendor.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;This happens to be perfectly correct! But still. There was something there that
itched at the back of my mind: I &lt;em&gt;knew&lt;&#x2F;em&gt; these things were different, but I
wasn’t able to articulate my mental framework to &lt;em&gt;explain&lt;&#x2F;em&gt; those differences.
There’s a lot going on in that pat answer that bears unpacking:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Where did Wasm come from – what problems was it created to solve?&lt;&#x2F;li&gt;
&lt;li&gt;How did Wasm come to be developed and supported by multiple vendors, while
the JVM remained single-vendor?&lt;&#x2F;li&gt;
&lt;li&gt;Are Wasm and the JVM really the same type of thing?&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;What does “virtual machine” &lt;em&gt;mean&lt;&#x2F;em&gt;?&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;In particular, when I went to talk about Wasm – which bills itself as a
“virtual instruction set architecture” &lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#v-isa&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; in specification – I found
that I had a shallow understanding of the word “virtual”. I knew the term for
its effect, by example, but not &lt;em&gt;deeply&lt;&#x2F;em&gt;. So. Having found myself with some
time on my hands recently, I split this post in three (at least, to start
with.) Today, we’re going to talk about virtualization, instruction set
architectures, and machines. This post isn’t meant to get into &lt;em&gt;all&lt;&#x2F;em&gt; of the
details, but should give you a good mental framework with which to place these
concepts, and serve as a nice jumping-off point for further research.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Let’s start by forming some rough categories using examples.&lt;&#x2F;p&gt;
&lt;p&gt;There’s the “virtual machines” that Amazon or Google are happy to sell us:
virtualized computers running on their hardware in the cloud. Alternatively:
VMWare, VirtualBox, and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.qemu.org&#x2F;&quot;&gt;QEMU&lt;&#x2F;a&gt; let me run virtualized computers on &lt;em&gt;my&lt;&#x2F;em&gt;
hardware. So, that’s one definition of “virtual machine”: “software simulating
hardware.” (You might even lump “video game emulators” into this category!)&lt;&#x2F;p&gt;
&lt;p&gt;On the other hand, we have “virtual machines” in the “JVM” sense: things like
the .NET Common Language Runtime (“CLR”), Erlang’s BEAM, JavaScript’s
SpiderMonkey or V8 engines, or even Python’s interpreter. These are all
programs running on an operating system for the purposes of taking an input
language and executing it. They do this by translating the input language into
the input language of the current computer. The Python virtual machine consumes
a Python operation code (opcode) and reacts to it by executing some number of
native machine operations. Let’s call this “software evaluating a language” for
now.&lt;&#x2F;p&gt;
&lt;p&gt;On the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wiktionary.org&#x2F;wiki&#x2F;on_the_gripping_hand&quot;&gt;gripping&lt;&#x2F;a&gt; hand: the Low Level Virtual Machine. I’m calling this one out
separately because it’s not really “software simulating hardware”, nor is it
“software evaluating a language”: it’s something else entirely. It’s a
waystation for languages on their way toward native machine code. C, C++, Rust,
and other languages can be translated from their source to this intermediate
representation, on which a number of optimizations can be made by the LLVM
toolchain. LLVM is a “machine which abstracts over other machines”, an
“abstract machine.”&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;There are three things that these three rough piles have in common:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;They all accept some sort of &lt;em&gt;input language&lt;&#x2F;em&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;They all refer to the term “virtual.”&lt;&#x2F;li&gt;
&lt;li&gt;They all refer to the term “machine.”&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Let’s approach these concepts in reverse order.&lt;&#x2F;p&gt;
&lt;p&gt;You might already be familiar with the term “Turing machine” or the phrase
“Turing complete”, but in case you’re not: a Turing machine is a mathematical
model of computation for which some useful properties hold. It describes an
abstract machine – hey, there’s that term again! – that operates on a finite
set of symbols printed on an infinite spool of tape. The classic Turing machine
uses a “head” to write to a cell to a discrete cell on that tape, shifting the
tape left or right based on its current state. Turing &lt;em&gt;completeness&lt;&#x2F;em&gt; describes
a property of a language, expressed as a discrete syntax: a Turing complete
language can express any task that can be accomplished by computers.&lt;&#x2F;p&gt;
&lt;p&gt;There’s an interesting relationship between “input language” and
“machine”. A sufficiently detailed description of a language also describes a
machine for processing that language, at least in the abstract. Much like how
an IKEA instruction manual describes the ideal Billy bookshelf. Many Billy
bookshelves can be assembled based on one instruction manual; all in various
degrees of “conversation” with the physical constraints encountered during
assembly.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;So what does it mean to “virtualize” a machine?&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;A good way to distinguish virtual and transparent is this: Virtual means it’s
not there but you can see it; transparent means that it is there but you
can’t see it.&lt;&#x2F;p&gt;
&lt;p&gt;Peter J. Denning - &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;ieeexplore.ieee.org&#x2F;stamp&#x2F;stamp.jsp?arnumber=948908&quot;&gt;IEEE Annals of Computing History&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;“Virtual” comes to computer science by way of the field of optics, where it
describes the perceived image of an object reflected by a mirror. There are two
frames of reference: an observer and the mirror. The observer sees a virtual
world behind the plane of the mirror. The mirror only “sees” the world in front
of it.&lt;&#x2F;p&gt;
&lt;p&gt;So, abstract machines are the platonic idea of a machine capable of processing
a given language. Virtual machines are one of two ways to realize these
machines: by writing them as programs to be executed &lt;em&gt;by another machine&lt;&#x2F;em&gt;. A
virtual machine acts like a mirror for the input language: the language “sees”
a machine designed just for it, but cannot see any of the implementation
details. For all the input language knows, it might be running directly on
hardware!&lt;&#x2F;p&gt;
&lt;p&gt;(Our vocabulary gets a little muddled in practice: the “AM” in Erlang’s “BEAM”
runtime stands for “abstract machine” &lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#beam&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;, while the “VM” in both the JVM
spec &lt;em&gt;and&lt;&#x2F;em&gt; in LLVM’s name stand for “virtual machine.” In other words, the
boundary between “abstract” and “virtual” is a little blurry. Note also:
specific &lt;em&gt;aspects&lt;&#x2F;em&gt; of a machine might be virtualized while others are left
transparent. For example, most programs assume a single contiguous view of
memory, which may exceed the actual memory available to the system. The
operating system &lt;em&gt;virtualizes&lt;&#x2F;em&gt; this view for processes, working behind the
scenes to maintain the illusion.)&lt;&#x2F;p&gt;
&lt;p&gt;The other way to realize an abstract machine is to reify it in hardware: to
build a processor to carry out the physical task of computing. A processor
doesn’t have to be electronic, that just happens to be the most common and
efficient computing substrate available to us today. You could, in theory, act
as a processor with a pencil, eraser, and a notebook if you wanted to –
assuming you followed some strict set of rules that described what you &lt;em&gt;do&lt;&#x2F;em&gt;
with those items. That is, a processor still requires an input language with
rules. This input language takes the form of a contract between processor and
program: an &lt;strong&gt;instruction set architecture&lt;&#x2F;strong&gt; (“ISA”.) Examples of ISAs include
&lt;code&gt;x86_64&lt;&#x2F;code&gt; and &lt;code&gt;arm64&lt;&#x2F;code&gt; – it’s frequently abbreviated as &lt;code&gt;arch&lt;&#x2F;code&gt;, or
“architecture” &lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#compiler-triple&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The ISA acts as a “&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.oilshell.org&#x2F;blog&#x2F;2022&#x2F;02&#x2F;diagrams.html&quot;&gt;narrow waist&lt;&#x2F;a&gt;” (as in an hourglass): it contains &lt;em&gt;just
enough&lt;&#x2F;em&gt; specification that many approaches to implementation are valid on both
sides of the contract. Software may expect that &lt;code&gt;ADD&lt;&#x2F;code&gt; or &lt;code&gt;JNE&lt;&#x2F;code&gt; exhibits the
expected behavior across implementations, while hardware is free to implement
that behavior as it sees fit. (AMD and Intel &lt;em&gt;both&lt;&#x2F;em&gt; implement the &lt;code&gt;x86_64&lt;&#x2F;code&gt;
ISA!) This is all, of course, subject to physical constraints – speed, power
draw, and thermal envelopes all come into play when &lt;em&gt;implementing&lt;&#x2F;em&gt; an ISA &lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#ciscs-riscs&quot;&gt;4&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.
So, while it’s possible to define an ISA that cannot be efficiently implemented
as hardware, people generally don’t do so &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.tomshardware.com&#x2F;news&#x2F;last-itanium-shipment&quot;&gt;on purpose&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Now, “Air Bud” &lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#air-bud&quot;&gt;5&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; rules apply here: software running against an ISA doesn’t know
what implements that ISA. It’s perfectly possible to &lt;em&gt;virtualize&lt;&#x2F;em&gt; an ISA such
that the hardware is simulated by software &lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#hw-hw&quot;&gt;6&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;. Software running on
virtualized hardware doesn’t &lt;em&gt;know&lt;&#x2F;em&gt; the hardware has been virtualized: it can’t
see the mirror. This is how we get those shiny cloud VMs, VirtualBox, VMWare,
and QEMU “virtual machines”! Because we don’t make any promises about the
implementation, the virtualizer might take a number of different approaches. It might:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;interpret machine code as bytecode in software (&lt;strong&gt;“emulation”&lt;&#x2F;strong&gt;),&lt;&#x2F;li&gt;
&lt;li&gt;pipe it directly through to its underlying ISA if those two happen to match
(&lt;strong&gt;“hardware virtualization”&lt;&#x2F;strong&gt;),&lt;&#x2F;li&gt;
&lt;li&gt;or recompile the ISA at runtime if it doesn’t (&lt;strong&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Binary_translation#Dynamic_binary_translation&quot;&gt;“dynamic binary
translation”&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt; or &lt;strong&gt;“just in time” &#x2F; “JIT”&lt;&#x2F;strong&gt; compilation)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Emulation is the most resource-intensive approach &lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#super-nt-fpgas&quot;&gt;7&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;, but is the
most flexible, theoretically: you can emulate a &lt;code&gt;powerpc&lt;&#x2F;code&gt; architecture on top
of your &lt;code&gt;x86_64&lt;&#x2F;code&gt; processor in software. This comes at a cost! Emulation
introduces a relatively low performance ceiling compared to the hardware running
the emulator.&lt;&#x2F;p&gt;
&lt;p&gt;Hardware virtualization is less flexible but more efficient: these are
processor instructions that aid in the creation of hypervisor software.
Hypervisors typically &lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#type-1-type-2&quot;&gt;8&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; run in a &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Protection_ring#Hypervisor_mode&quot;&gt;lower protection
mode&lt;&#x2F;a&gt; than operating systems; they can be thought of as an operating
system for operating systems. Hypervisor software provides (near-)transparent
processor access for virtualized operating systems, while virtualizing other
system resources (like persistent disks, memory, and peripherals.) On &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;X86_virtualization#AMD_virtualization_(AMD-V)&quot;&gt;x86
platforms&lt;&#x2F;a&gt;, this is provided by AMD’s AMD-V (AKA “Secure Virtual
Machine” or “SVM”) and Intel’s VT-x (AKA “VMX”), ARM has &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;developer.arm.com&#x2F;documentation&#x2F;100942&#x2F;0100&#x2F;AArch64-virtualization&quot;&gt;an
equivalent&lt;&#x2F;a&gt;. AWS, GCP, VMWare, the Windows Subsystem for Linux &lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#wsl2&quot;&gt;9&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;, Apple’s
Hypervisor framework: all of these use hardware virtualization. As mentioned,
this is &lt;em&gt;generally&lt;&#x2F;em&gt; less flexible than other ISA virtualization strategies, in
that the ISA of the system virtualized must match the host ISA&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#v-wii&quot;&gt;10&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; – you can’t
virtualize an ARM machine on top of a physical x86 machine.&lt;&#x2F;p&gt;
&lt;p&gt;That is, unless you’re running a dynamic binary translator (“DBT”) of some
sort. The most widely-deployed DBT ISA VM that I’m aware of is Apple’s Rosetta.
Rosetta 1 &lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#quicktransit&quot;&gt;11&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; eased the transition from PowerPC architecture to
Intel&#x2F;x86 before its removal in OSX Lion, and Rosetta 2 is doing the same for
the Intel&#x2F;x86 transition to Apple’s own ARM-architecture hardware. Notable
mentions include Intel’s &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;IA-32_Execution_Layer&quot;&gt;IA-32 Execution Layer&lt;&#x2F;a&gt;, the Dolphin emulator’s JIT
recompilation of Gamecube&#x2F;Wii PowerPC code to x86&#x2F;ARM &lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#dolphin&quot;&gt;12&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;, and, of
course, the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Transmeta_Crusoe&quot;&gt;Transmeta Crusoe&lt;&#x2F;a&gt;. There are caveats with this approach: some
virtual instructions may have no hardware equivalent, and so must use (much
slower!) emulation in software. Most importantly, this is the most complex
solution to program: it requires a working &lt;em&gt;emulator&lt;&#x2F;em&gt; to fall back on for
virtualized operations that have no native equivalent.&lt;&#x2F;p&gt;
&lt;p&gt;DBTs are probably the most expensive virtualization technology to develop –
they are JIT VMs, which we’ll talk about again soon. Companies turn to them
when both the language to be virtualized and the target platform are fixed
points: IBM &lt;em&gt;had&lt;&#x2F;em&gt; to support Power architecture, e.g. However, because the
addressable base of x86 machines is much larger, individual developers weren’t
likely to compile their software specially for IBM – there’s little incentive
for them to do so.&lt;&#x2F;p&gt;
&lt;p&gt;Whew, okay, let’s take a breath and recap briefly. A “machine” is any
Turing-capable computer. An “abstract machine” is the conceptual definition of
such a machine over an input language. An instruction set architecture is a
contract language between the hardware of a machine and the input language of
that machine – software. To “virtualize” a system means to present an
interface to that system “as if” it existed using some mechanism. The more
transparent that mechanism is, the less performance will be lost in
virtualizing: that is, hardware virtualization support makes the processor
partially “transparent” to guest operating systems. On the opposite side of the
gradient: software emulation is fully virtual, straightforward to implement,
but slow compared to native execution. In the middle we have Dynamic Binary
Translation: translating a binary in one format “just in time” to execute it as
a native format. DBT JITs are expensive to write but potentially very
effective!&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Now, finally, input languages. Let’s revisit that “language virtual machine”
category of virtual machines we piled up earlier.&lt;&#x2F;p&gt;
&lt;p&gt;As you might suspect, hardware only gets &lt;em&gt;one&lt;&#x2F;em&gt; input language – an ISA
&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#transmeta-crusoe-again&quot;&gt;13&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;. However, approximately &lt;em&gt;no one&lt;&#x2F;em&gt; wants to write &lt;em&gt;all
of their software&lt;&#x2F;em&gt; directly &lt;em&gt;in&lt;&#x2F;em&gt; that one input language. For one, it’s a pain,
but more importantly, it’s intimately tied to the hardware. If, say, you have
to support another ISA, that means a ground-up rewrite (or hinging your
software’s value proposition squarely in the hands of a system virtual machine
vendor. Is your software really worth making your users simulate an entire
other machine and operating system just to run it? For my part, no
&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#but-games&quot;&gt;14&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.) Leaving that aside, domain specific languages are powerful for a
reason: they help us model the problem space of our software more directly.&lt;&#x2F;p&gt;
&lt;p&gt;So, we invented programming languages &lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#glib&quot;&gt;15&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;. Each programming language
defines an abstract machine whether explicitly as part of a specification, or
implicitly as part of an implementation. That abstract machine can be implemented
in (roughly) one of three ways.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;INCOMING &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Wikipedia:Emerson_and_Wilde_on_consistency&quot;&gt;FOOLISH CONSISTENCY&lt;&#x2F;a&gt;. BRACE FOR IMPACT.&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;These three methods correspond to what we’ve &lt;em&gt;already talked about&lt;&#x2F;em&gt; above: we
can emulate the language abstract machine in software, we can attempt to
translate it to native code at runtime, or we can map the input language
transparently to the underlying hardware. In other words: we can write an
interpreter (like Ruby, Python; an “emulator”), a JIT VM (like the JVM or
popular JavaScript engines; a “dynamic binary translator” of sorts), or an
ahead-of-time (“AOT”) compiler (as we have for C, C++, Rust, and others;
“hardware virtualization,” after a fashion, possible because the two machines
are so similar.) Interpreters are generally slow but portable and flexible, JIT
VMs are complex, potentially efficient, and generally require an interpreter to
fall back to, and compilers produce efficient translations at the cost of
flexibility.&lt;&#x2F;p&gt;
&lt;p&gt;They are &lt;em&gt;all&lt;&#x2F;em&gt; ways to virtualize a machine.&lt;&#x2F;p&gt;
&lt;p&gt;If you’re like me, you’re probably accustomed to thinking of Erlang, C#, or
JavaScript as running atop a virtual machine. You &lt;em&gt;might&lt;&#x2F;em&gt; even think “yeah,
Python’s interpreter constitutes a virtual machine.&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#interpreters&quot;&gt;16&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;” But Go? C?
C++? Rust? Compiled languages run on &lt;em&gt;the&lt;&#x2F;em&gt; machine, not on a virtual machine,
right?&lt;&#x2F;p&gt;
&lt;p&gt;Well, sorta. C’s specification, in fact, specifies an abstract
machine&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#c-abstract-machine&quot;&gt;17&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;. It is the job of compiler software to statically
map operations in that abstract machine to the corresponding operations in the
hardware – the machine as defined by the ISA, in other words. Rust, Go, Java,
and C# work similarly, in this fashion: a compiler rephrases the input language
into a form that can be easily translated to a target machine
(&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;rustc-dev-guide.rust-lang.org&#x2F;backend&#x2F;lowering-mir.html&quot;&gt;“lowering”&lt;&#x2F;a&gt; it). (In C# and Java’s cases, the target machine
happens to be a virtual machine: the CLR&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#unpacked&quot;&gt;18&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; in the former case, and the
JVM in the latter.)&lt;&#x2F;p&gt;
&lt;p&gt;This is where that last category of examples comes in: LLVM and friends. These
“VMs” are &lt;em&gt;intermediate&lt;&#x2F;em&gt; languages (or “intermediate representations”, or
“IR”), meant to facilitate the translation of one abstract language machine
into another. Rust itself has two (&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;blog.rust-lang.org&#x2F;2016&#x2F;04&#x2F;19&#x2F;MIR.html&quot;&gt;HIR and MIR&lt;&#x2F;a&gt;), many JS
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;firefox-source-docs.mozilla.org&#x2F;js&#x2F;MIR-optimizations&#x2F;index.html&quot;&gt;engines&lt;&#x2F;a&gt; have &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.google.com&#x2F;presentation&#x2F;d&#x2F;1Z9iIHojKDrXvZ27gRX51UxHD-bKf1QcPzSijntpMJBM&#x2F;edit#slide=id.p&quot;&gt;their&lt;&#x2F;a&gt; own &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;webkit.org&#x2F;docs&#x2F;b3&#x2F;intermediate-representation.html&quot;&gt;internal&lt;&#x2F;a&gt; IRs, and the JVM
bytecode specification is itself an IR. IRs narrow semantics, provide a place
to collect extra information about the program, and act as a single point at
which to apply useful optimizations &lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#ssa&quot;&gt;19&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;. AOT compiled languages, like C, Go,
or Rust, contain sufficient information to be “lowered” to low level
intermediate languages, which themselves can be compiled to an ISA after
optimizations have been applied. Interpreted languages can be JIT compiled,
assuming the runtime can collect sufficient information to generate native code
&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#jit&quot;&gt;20&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;I’m going to turn now to a paper from 1978 that I definitely &lt;em&gt;did not read&lt;&#x2F;em&gt;
ahead of drafting this post:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Thus a language definition implies a model of the machine on which programs
in the language will run. If a real machine conforms well to the model, then
an implementation on that machine is likely to be
efficient and easily written; if not, the implementation will be painful to
provide and costly to use.&lt;&#x2F;p&gt;
&lt;p&gt;Via &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.bell-labs.com&#x2F;usr&#x2F;dmr&#x2F;www&#x2F;portpap.html&quot;&gt;“Portability of C Programs and the Unix System”&lt;&#x2F;a&gt;, S.C. Johnson and D.M. Ritchie&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;I urge you to read this paper in full. When I read it, I spun around in my
office chair, arms raised in celebration for a full minute.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Ahem.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;It’s a story about porting C &amp;amp; UNIX from the PDP-11 to the Interdata 8&#x2F;32. I’ll
briefly summarize it here: it includes early automated regression testing, the
first tool called “lint”, the origin of &lt;em&gt;several&lt;&#x2F;em&gt; concepts in C (including
unsigned integers, before which folks just had to type pun &lt;code&gt;char*&lt;&#x2F;code&gt; pointers
because they &lt;em&gt;happened to behave the same way&lt;&#x2F;em&gt; on the PDP-11), the above quote,
early virtualization, a description of using an intermediate language in a
compiler toolchain to port &lt;em&gt;Fortran&lt;&#x2F;em&gt; to new machines in addition to C, and a
whole lot of new working systems spun up from &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;John_Gall_(author)#Gall&amp;#x27;s_law&quot;&gt;existing, simpler working
systems&lt;&#x2F;a&gt;. It is just &lt;em&gt;so&lt;&#x2F;em&gt; good.&lt;&#x2F;p&gt;
&lt;p&gt;But the bit of it that is germane to this post is this: C started with an
implicit abstract machine, that mapped nearly 1:1 with the PDP-11. They
&lt;em&gt;specifically picked&lt;&#x2F;em&gt; the Interdata 8&#x2F;32 because it &lt;em&gt;was&lt;&#x2F;em&gt; so different from the
PDP-11. In porting C, they modified the definition of C, using the large corpus
of existing software to validate the port and their changes. They built an
intermediate representation (though they didn’t call it that) and an abstract
model of the machine that the C language represented by &lt;em&gt;extracting&lt;&#x2F;em&gt; them from
existing, working systems.&lt;&#x2F;p&gt;
&lt;p&gt;It wasn’t &lt;em&gt;just&lt;&#x2F;em&gt; luck that C’s machine model mapped so closely to the machines
they were trying to straddle: the authors explicitly call out that they had
previous experience porting languages between machines with C’s predecessor, B,
and the large software project, Altran (a Fortran library.) In other words, they
made good bets and were willing to coax the language the rest of the way. And in
shaving off those rough edges, they made an eventual port to a third machine that
much easier: C’s abstract machine became a self-reinforcing system.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;It is true that moving a program from one machine to another does not
guarantee that it can be moved to a third. There are many issues in
portability about which we worried in a theoretical way without having to
face them in fact. […] Nevertheless, moving UNIX
to a third new machine, or a fourth, will be easier than it was to the
second. The operating system and the software have been carefully
parameterized, and this will not have to be done again. We have also learned
a great deal about the critical issues (the “hard parts”).&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;That is: because C was so portable and had so much software already available
for it, ISAs were incentivized to map closely to C’s abstract machine. Because
hardware based on those ISAs kept advancing, there was more incentive to write
C (or languages that targeted C’s abstract machine.) ISA’s and C’s abstract
machine evolved symbiotically.&lt;&#x2F;p&gt;
&lt;p&gt;And that draws me to the close of this post. We spent a lot of time defining
terms here: what a machine is, what it means to virtualize it, what an
instruction set architecture is, the differences and similarities between
virtualizing a system versus a language, implementation approaches and their
costs, and finally how to use a set of existing machines to create and refine
an abstract machine. WebAssembly, a self-billed “virtual ISA”, is following in
C’s footsteps here: extracting a reusable abstract machine from a set of
existing virtual machines. Next time, we’ll talk about the context Wasm was
developed in and how it aims to achieve Java’s goal of “Write once, run
anywhere.”&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;em&gt;(Thanks to &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.evntdrvn.com&#x2F;&quot;&gt;Eric Sampson&lt;&#x2F;a&gt; for reviewing drafts of this blog post.)&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;v-isa&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;See “scope” under &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.w3.org&#x2F;TR&#x2F;wasm-core-2&#x2F;intro&#x2F;introduction.html#scope&quot;&gt;the w3 Wasm specification&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;beam&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;2&lt;&#x2F;sup&gt;
&lt;p&gt;BEAM was a replacement for the original Erlang Abstract Machine:
“&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.cs.tufts.edu&#x2F;~nr&#x2F;cs257&#x2F;archive&#x2F;joe-armstrong&#x2F;erlang-jam.pdf&quot;&gt;JAM&lt;&#x2F;a&gt;”, or “&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Joe_Armstrong_(programmer)&quot;&gt;Joe’s&lt;&#x2F;a&gt; Abstract Machine”.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;ciscs-riscs&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;4&lt;&#x2F;sup&gt;
&lt;p&gt;You might have heard of “complete instruction set computers”
(“CISC”) and “reduced instruction set computers” before
(&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=EklmUZF6lm0&amp;amp;t=470s&quot;&gt;“RISC”&lt;&#x2F;a&gt;): this refers
to the approach taken in defining the ISA. Reduced instruction set computers
generally specify &lt;em&gt;fewer&lt;&#x2F;em&gt;, more popular instruction codes in a more regular
fashion. For example, as opposed to a CISC architecture, a RISC machine may
not be able to combine memory access and computation in a single instruction.
The idea is that the reduced set of instructions narrows the focus of the
implementation, potentially making it faster. These days, ARM is considered a
RISC machine, while x86 is considered a CISC machine. In practice, ISAs
implementers may decompose operations into microcode invisible to software,
so the line is a little blurry. For an interesting read on the subject
from one of the folks behind the Transmeta Crusoe, see &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;people.eecs.berkeley.edu&#x2F;~krste&#x2F;papers&#x2F;EECS-2014-146.pdf&quot;&gt;this paper&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;compiler-triple&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;3&lt;&#x2F;sup&gt;
&lt;p&gt;You might have seen “arch” in various software releases
before, in the form &lt;code&gt;x86_64-pc-win32&lt;&#x2F;code&gt; or &lt;code&gt;arm-apple-darwin-eabi&lt;&#x2F;code&gt;. This is
known as a “&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;wiki.osdev.org&#x2F;Target_Triplet&quot;&gt;target triple&lt;&#x2F;a&gt;” and is meant to communicate the
target processor, hardware vendor, and operating system.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;air-bud&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;5&lt;&#x2F;sup&gt;
&lt;p&gt;“There’s no rule that says dogs can’t play basketball!”&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;hw-hw&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;6&lt;&#x2F;sup&gt;
&lt;p&gt;Or indeed, using hardware to virtualize other hardware: these days the
x86 ISA is implemented as a frontend for other, vendor-specific processor microcode.
See &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;queue.acm.org&#x2F;detail.cfm?id=3212479&quot;&gt;“C Is Not A Low Level Language”&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;super-nt-fpgas&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;7&lt;&#x2F;sup&gt;
&lt;p&gt;Analogue’s &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.analogue.co&#x2F;super-nt&quot;&gt;Super nt&lt;&#x2F;a&gt; famously turned to Field Programmable Gate Arrays
(FPGAs) in order to fully replicate the behavior of the Super Nintendo
Entertainment System. There was a video that interviewed the person who implemented all of that
FPGA work, but it is sadly lost to me. Happily, you can find out more about the technical capabilities
over on the Digital Foundry &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=LOSQgBEf5ac&quot;&gt;video&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;type-1-type-2&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;8&lt;&#x2F;sup&gt;
&lt;p&gt;Type 1 hypervisors (“native”) run on the hardware beneath all
other operating systems: Oracle VM, VMWare’s &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;VMware_ESXi&quot;&gt;ESXi&lt;&#x2F;a&gt;, Microsoft’s &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;learn.microsoft.com&#x2F;en-us&#x2F;virtualization&#x2F;hyper-v-on-windows&#x2F;about&#x2F;&quot;&gt;Hyper-V&lt;&#x2F;a&gt;,
and Amazon’s &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.aws.amazon.com&#x2F;whitepapers&#x2F;latest&#x2F;security-design-of-aws-nitro-system&#x2F;the-components-of-the-nitro-system.html&quot;&gt;AWS Nitro&lt;&#x2F;a&gt;. Type 2 (“hosted”) hypervisors run as a process on
top of an operating system. Type 2 includes VMWare, Virtualbox, and Virtual
PC. It’s not clear to me at the time of writing whether Apple’s
Hypervisor.framework is a Type 1 or Type 2 hypervisor. I get the sense that
user-oriented operating systems are beginning to embed type 1 hypervisors
(e.g., Microsoft supports WSL on Windows using a subset of Hyper-V), exposing
the functionality out to the main guest OS as a framework.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;wsl2&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;9&lt;&#x2F;sup&gt;
&lt;p&gt;&lt;em&gt;WSL2&lt;&#x2F;em&gt; uses hardware virtualization. &lt;em&gt;WSL1&lt;&#x2F;em&gt; was implemented entirely
differently, and we’ll talk more about that approach in a coming post.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;v-wii&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;10&lt;&#x2F;sup&gt;
&lt;p&gt;For a really fun example of the inflexibility of hardware virtualization,
see the Wii U’s &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.copetti.org&#x2F;writings&#x2F;consoles&#x2F;wiiu&#x2F;#becoming-a-wii&quot;&gt;virtual Wii&lt;&#x2F;a&gt;
mode. It works because the Wii U is (roughly speaking) three Wii processors in a trenchcoat;
so to become a Wii, it hides two of those processors and a bunch of RAM.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;quicktransit&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;11&lt;&#x2F;sup&gt;
&lt;p&gt;Rosetta 1, at least, is an implementation of Transitive
Corporation’s &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;QuickTransit&quot;&gt;QuickTransit&lt;&#x2F;a&gt;
software, which Apple licensed. IBM acquired the company in 2009.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;dolphin&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;12&lt;&#x2F;sup&gt;
&lt;p&gt;Seriously. The Dolphin dev blog is a treasure trove of interesting
posts about various ISA JITs. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;dolphin-emu.org&#x2F;blog&#x2F;2021&#x2F;05&#x2F;24&#x2F;temptation-of-the-apple-dolphin-on-macos-m1&#x2F;&quot;&gt;See this one&lt;&#x2F;a&gt;
on adding an M1 backend to their JIT!&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;transmeta-crusoe-again&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;13&lt;&#x2F;sup&gt;
&lt;p&gt;Yes, yes, even if the hardware is the Transmeta
Crusoe. It has one input language, which happens to be a “very large
instruction word” (“VLIW”) set that can handle the union of a &lt;em&gt;couple&lt;&#x2F;em&gt; of
other hardware ISAs. If you’re interested in this processor, read more about
it &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;tedium.co&#x2F;2023&#x2F;04&#x2F;26&#x2F;transmeta-crusoe-processor-history&#x2F;&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;but-games&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;14&lt;&#x2F;sup&gt;
&lt;p&gt;Video games being the BIG exception to this. And even then, that
took some pretty anticompetitive practices to put in place.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;glib&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;15&lt;&#x2F;sup&gt;
&lt;p&gt;I’m being &lt;em&gt;exceptionally&lt;&#x2F;em&gt; glib about this. The history of programming languages
is large and fascinating. It has a &lt;em&gt;lot&lt;&#x2F;em&gt; to do with linguistics but &lt;em&gt;very little&lt;&#x2F;em&gt;
to do with the point of this (increasingly long) post.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;interpreters&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;16&lt;&#x2F;sup&gt;
&lt;p&gt;See &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Comparison_of_application_virtualization_software&quot;&gt;this wiki page&lt;&#x2F;a&gt; for an overview of
“ways to implement a language virtual machine.” Also, go read &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;craftinginterpreters.com&#x2F;&quot;&gt;“Crafting
Interpreters”&lt;&#x2F;a&gt;!&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;unpacked&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;18&lt;&#x2F;sup&gt;
&lt;p&gt;The “CLR” referred to here is Microsoft’s “Common Language
Runtime”, which implements the “Common Language Infrastructure” (“CLI”)
abstract machine. “CLI” is miserable to search for, though, so I’m committing
the sin of &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Metonymy&quot;&gt;metonomy&lt;&#x2F;a&gt; by referring to the abstract machine language by its
implementation.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;ssa&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;19&lt;&#x2F;sup&gt;
&lt;p&gt;I’m probably so out of date at this point, but see &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;darksi.de&#x2F;d.sea-of-nodes&#x2F;&quot;&gt;Sea of Nodes&lt;&#x2F;a&gt;,
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Static_single-assignment_form&quot;&gt;“Static Single Assignment” (“SSA”)&lt;&#x2F;a&gt;, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.cs.cmu.edu&#x2F;afs&#x2F;cs&#x2F;academic&#x2F;class&#x2F;15745-s19&#x2F;www&#x2F;lectures&#x2F;L9-LICM.pdf&quot;&gt;“Loop Invariant Code Motion” (“LICM”)&lt;&#x2F;a&gt;,
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Inline_expansion&quot;&gt;inline expansion&lt;&#x2F;a&gt;, and the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Optimizing_compiler&quot;&gt;“optimizing compiler”&lt;&#x2F;a&gt; page on wikipedia. It’s a
very interesting space!&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;jit&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;20&lt;&#x2F;sup&gt;
&lt;p&gt;I’m leaving a lot out here, but to gesture at it: at least for
JavaScript, the job of a JIT VM is to run the language in multiple stages. In
the initial stage, it’s running as an interpreter, collecting type
signatures; if a function is called frequently enough, with consistent enough
type information, the interpreter code replaces that function with one in the
native machine’s ISA. This compiled code includes type checks that can cause
the function to “bail out” if unexpected types are encountered at runtime,
falling back to the interpreter. As I understand it, the JVM and CLR operate
in a similar fashion, though with more initial type information available.
The creation of JIT VMs owes a lot to the Smalltalk &amp;amp; Self lineage of
languages; Strongtalk, in particular, informed &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.strongtalk.org&#x2F;history.html&quot;&gt;the design&lt;&#x2F;a&gt; of &lt;em&gt;many&lt;&#x2F;em&gt; vms.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;hypervisor&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;21&lt;&#x2F;sup&gt;
&lt;p&gt;Hardware virtualization involves the use of a program called a
“control program”, “hypervisor”, or “virtual machine manager” (“VMM”),
usually running in a &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Protection_ring#Hypervisor_mode&quot;&gt;lower protection
mode&lt;&#x2F;a&gt;
than the kernel itself.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;vms&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;22&lt;&#x2F;sup&gt;
&lt;p&gt;An aside here. I’ve just described two &lt;em&gt;more&lt;&#x2F;em&gt; subtypes of VMs here:
&lt;em&gt;process&lt;&#x2F;em&gt; VMs and &lt;em&gt;system&lt;&#x2F;em&gt; VMs. System VMs run outside of the context of an
operating system: a hypervisor, loaded as part of the hardware boot process.
Process VMs, however, include QEMU, VMWare, Python, V8, SpiderMonkey: any VM
that runs as a process managed by an operating system.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;art&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;23&lt;&#x2F;sup&gt;
&lt;p&gt;See &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Abstract_machine&quot;&gt;“Abstract Machines”&lt;&#x2F;a&gt; on
Wikipedia. Also, go read &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;dr-knz.net&#x2F;abstract-machine-models.html&quot;&gt;“Abstract Machine Models”&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;what-no-spec&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;24&lt;&#x2F;sup&gt;
&lt;p&gt;Languages without specifications &lt;em&gt;still&lt;&#x2F;em&gt; have abstract
machines, but they’re not written down anywhere: they live in the heads of
the maintainers of the canonical implementation. The Ruby and Python machines
are “that feeling you get when you read the entire codebase”, the wind in
your hair on a pleasant Spring day.
Of course, that means accurate, alternate implementations are that much more
difficult to write.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;c-abstract-machine&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;17&lt;&#x2F;sup&gt;
&lt;p&gt;See the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20181230041359if_&#x2F;http:&#x2F;&#x2F;www.open-std.org&#x2F;jtc1&#x2F;sc22&#x2F;wg14&#x2F;www&#x2F;abq&#x2F;c17_updated_proposed_fdis.pdf&quot;&gt;freely available
copy&lt;&#x2F;a&gt;
of the C standard, §5.1.2.3, which states:
“The semantic descriptions in this International Standard describe the
behavior of an abstract machine in which issues of optimization are irrelevant.”&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;pdp11&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;25&lt;&#x2F;sup&gt;
&lt;p&gt;Via &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;queue.acm.org&#x2F;detail.cfm?id=3212479&quot;&gt;“C Is Not a Low-level Language”&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
</description>
      </item>
      <item>
          <title>A Mirror for Rust: Compile-Time Reflection Report - Shepherd&#x27;s Oasis</title>
          <pubDate>Mon, 08 May 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://www.neversaw.us/links/a-mirror-for-rust-compile-time-reflection-report-shepherd-s-oasis/</link>
          <guid>https://www.neversaw.us/links/a-mirror-for-rust-compile-time-reflection-report-shepherd-s-oasis/</guid>
          <description xml:base="https://www.neversaw.us/links/a-mirror-for-rust-compile-time-reflection-report-shepherd-s-oasis/">&lt;p&gt;A long read, but a good read. Covers the use of &lt;code&gt;syn&lt;&#x2F;code&gt; and &lt;code&gt;reflect&lt;&#x2F;code&gt; in the Rust ecosystem,
what those tools are in reaction to, and the limits of that pattern. Proposes a compile-time
reflection system with low- and mid-level APIs that would (in theory) allow Rust to get away
from the widespread peer dependency on &lt;code&gt;serde&lt;&#x2F;code&gt;.
Linked terms include:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.cppreference.com&#x2F;w&#x2F;cpp&#x2F;language&#x2F;sfinae&quot;&gt;SFINAE&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;dtolnay&#x2F;reflect&quot;&gt;dtolnay’s &lt;code&gt;reflect&lt;&#x2F;code&gt; crate&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;dtolnay&#x2F;syn&quot;&gt;dtolnay’s &lt;code&gt;syn&lt;&#x2F;code&gt; crate&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.rs&#x2F;bevy_reflect&#x2F;latest&#x2F;bevy_reflect&#x2F;&quot;&gt;bevy’s &lt;code&gt;bevy_reflect&lt;&#x2F;code&gt; crate&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;C’s &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gitlab.inria.fr&#x2F;gustedt&#x2F;p99&quot;&gt;P99 macro library&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;the Rust &lt;code&gt;offset_of!&lt;&#x2F;code&gt; macro &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rust-lang&#x2F;rust&#x2F;pull&#x2F;106934&quot;&gt;PR&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>In defense of blub studies | benkuhn.net</title>
          <pubDate>Mon, 08 May 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://www.neversaw.us/links/in-defense-of-blub-studies-benkuhn-net/</link>
          <guid>https://www.neversaw.us/links/in-defense-of-blub-studies-benkuhn-net/</guid>
          <description xml:base="https://www.neversaw.us/links/in-defense-of-blub-studies-benkuhn-net/">&lt;p&gt;This post talks about the importance of schlepping through the details of the tools you’re working with. As you can probably
guess, I love it. It really rings true for me: the times I have learned the most as a programmer are the times I explicitly
said “heck it, I’m going to write my own ORM &#x2F; template language &#x2F; implementation of the deflate algorithm.” Or “I’m going to
learn how Django works by &lt;em&gt;reading the source&lt;&#x2F;em&gt; for the area I’m interested in.”
It’s important on multiple levels – “blub studies” make you engage deeply with your tools and build a theory of how they work,
which inspire you to build new tools, save you time debugging (as the author notes) or help you put the tool in context.
This link comes to me via &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.simplermachines.com&#x2F;&quot;&gt;simplermachines&lt;&#x2F;a&gt;, which is another great blog I urge you to follow.
Linked terms include:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;“Blub”, via &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.paulgraham.com&#x2F;avg.html&quot;&gt;“Beating the Averages”&lt;&#x2F;a&gt;, a Paul Graham essay. (So, uh, take that for what it’s worth.)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;intronetworks.cs.luc.edu&#x2F;&quot;&gt;“An Introduction to Computer Networks”&lt;&#x2F;a&gt;, which might be &lt;strong&gt;just the thing&lt;&#x2F;strong&gt; I’ve been looking for, re: network engineering.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>6.6</title>
          <pubDate>Fri, 16 Dec 2022 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://www.neversaw.us/links/6-6/</link>
          <guid>https://www.neversaw.us/links/6-6/</guid>
          <description xml:base="https://www.neversaw.us/links/6-6/">&lt;p&gt;This used to be my go-to “I am entirely burnt out and I give up”
song. (It’s maybe alarming that I had a “go-to” song for that? Hm,
hm.)
I’m happy to report that I play it a LOT LESS these days than I used
to, but whoo.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Dead 80&#x27;s | Mrs. Magician</title>
          <pubDate>Fri, 16 Dec 2022 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://www.neversaw.us/links/dead-80-s-mrs-magician/</link>
          <guid>https://www.neversaw.us/links/dead-80-s-mrs-magician/</guid>
          <description xml:base="https://www.neversaw.us/links/dead-80-s-mrs-magician/">&lt;p&gt;“On new year’s eve, I met a girl &#x2F; she scared all my friends and then she showed me a whole new world”
Love this track just for that line. Oh, and the easy nihilism and jangly guitars.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Don&#x27;t Try | Radioactivity | Dirtnap Records</title>
          <pubDate>Fri, 16 Dec 2022 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://www.neversaw.us/links/don-t-try-radioactivity-dirtnap-records/</link>
          <guid>https://www.neversaw.us/links/don-t-try-radioactivity-dirtnap-records/</guid>
          <description xml:base="https://www.neversaw.us/links/don-t-try-radioactivity-dirtnap-records/">&lt;p&gt;I didn’t come by this track honestly! This popped up on Shanti (or
Kevin?)’s Spotify playlist while they were driving Krysten and I
around Palm Springs in a rental car. I’ve been in a strange state of
mind for a while: I’m starting to physically feel older, my job (at
the time) wasn’t really working out, and, to be frank, folks: my
brain just no good no more. Years of pandemic and years of being
glued to Twitter waiting to see what new outrage Trump would drum up
and years of working from home and being separated from friends and
family have done a number on my good brain juice.
But this song popped me right out of that torpor by collecting all of
the melancholy-angst that had been building up inside of me and just
wailing it out. I leaned to read the name of the song and artist from
the back seat and mumbled it to myself until I could get home so I could
write it down in some kind of computer. And now I’m writing it into this
computer!&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>JAPANTHER - FIRST OF ALL | JAPANTHER | Seayou Records</title>
          <pubDate>Fri, 16 Dec 2022 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://www.neversaw.us/links/japanther-first-of-all-japanther-seayou-records/</link>
          <guid>https://www.neversaw.us/links/japanther-first-of-all-japanther-seayou-records/</guid>
          <description xml:base="https://www.neversaw.us/links/japanther-first-of-all-japanther-seayou-records/">&lt;p&gt;Man. What a great “I’m incredibly frustrated” song. And at the same time,
I wish it wasn’t on repeat for me? At least it dispaced &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=zKq-P4wSy8U&quot;&gt;6.6&lt;&#x2F;a&gt; for me.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Never Again | Thin Lips</title>
          <pubDate>Fri, 16 Dec 2022 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://www.neversaw.us/links/never-again-thin-lips/</link>
          <guid>https://www.neversaw.us/links/never-again-thin-lips/</guid>
          <description xml:base="https://www.neversaw.us/links/never-again-thin-lips/">&lt;p&gt;“Raw and powerful”, unrequited love, alliteration. It just sounds
like being in your early twenties. At least, it sounds like being in
&lt;em&gt;my&lt;&#x2F;em&gt; early twenties. Or how I &lt;em&gt;wanted&lt;&#x2F;em&gt; my early twenties to sound
when I was in my early twenties? I don’t know. I’m in my late
thirties as I write this. I can barely believe I used to stay out
past midnight.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Nostalgia of Island | Tatsuro Yamashita</title>
          <pubDate>Fri, 16 Dec 2022 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://www.neversaw.us/links/nostalgia-of-island-tatsuro-yamashita/</link>
          <guid>https://www.neversaw.us/links/nostalgia-of-island-tatsuro-yamashita/</guid>
          <description xml:base="https://www.neversaw.us/links/nostalgia-of-island-tatsuro-yamashita/">&lt;p&gt;Got this from one action button video or another. I feel like I should have more
to say about this, but… yanno, some music just takes you somewhere. I’m happy
I went on this trip.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Simulation Swarm | Big Thief</title>
          <pubDate>Fri, 16 Dec 2022 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://www.neversaw.us/links/simulation-swarm-big-thief/</link>
          <guid>https://www.neversaw.us/links/simulation-swarm-big-thief/</guid>
          <description xml:base="https://www.neversaw.us/links/simulation-swarm-big-thief/">&lt;p&gt;What a big, warm, sad sound.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Something About Lemons | Chumped</title>
          <pubDate>Fri, 16 Dec 2022 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://www.neversaw.us/links/something-about-lemons-chumped/</link>
          <guid>https://www.neversaw.us/links/something-about-lemons-chumped/</guid>
          <description xml:base="https://www.neversaw.us/links/something-about-lemons-chumped/">&lt;p&gt;I am an ABSOLUTE SUCKER for any song about it being hard to get out of
a town that folks stay in. I think about Lawrence KS in those terms a lot,
though in practice most folks I know had already moved out of there before
me.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>x-post: LARPing a Gossip Protocol about Reality</title>
          <pubDate>Fri, 04 Nov 2022 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://www.neversaw.us/2022/11/04/larping-a-gossip-protocol/</link>
          <guid>https://www.neversaw.us/2022/11/04/larping-a-gossip-protocol/</guid>
          <description xml:base="https://www.neversaw.us/2022/11/04/larping-a-gossip-protocol/">&lt;p&gt;&lt;em&gt;This was originally posted &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;cohost.org&#x2F;isntitvacant&#x2F;post&#x2F;192013-lar-ping-a-gossip-pro&quot;&gt;on my Cohost account&lt;&#x2F;a&gt;; I’ve reposted it here
for posterity.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;h1 id=&quot;larping-a-gossip-protocol-about-reality&quot;&gt;LARPing a Gossip Protocol about Reality&lt;&#x2F;h1&gt;
&lt;small&gt;
&lt;p&gt;I’ve edited and re-edited this and I don’t feel super comfortable sharing it
but I need it out of my head sooner rather than later. I need that brain space
back. And besides, I want to move on to post things that &lt;em&gt;aren’t&lt;&#x2F;em&gt; about other
social network platforms on this social network platform. So. Here goes.&lt;&#x2F;p&gt;
&lt;&#x2F;small&gt;
&lt;p&gt;Twitter changed how I write, for certain. Twitter also changed how I think.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;I spent more than a decade squeezing every stray thought into Twitter. Every
evening, morning, and spare moment scrolling to see what folks were talking
about. Minutes in the shower thinking about &lt;em&gt;my&lt;&#x2F;em&gt; position on the topic of the
day, then how best to cram that into 140, then 280 characters. “Hold on a
moment,” I’d say to myself mid-anything-at-all-really, “Has anyone made
the ‘Node dot michael jackson’ joke yet?” &lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;p&gt;
&lt;p&gt;For a decade we talked to each other in tabloid headlines. It was a place to
make dumb jokes, then watch likes pour in. To make even dumber jokes, and then
watch nothing at all happen. To collectively gawk at the news of the day. To
stay up late at night in fear of a war with North Korea. Twitter was the place
I went to &lt;em&gt;feel&lt;&#x2F;em&gt; social without having to actually &lt;em&gt;be social&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Twitter made me realize that hundreds if not &lt;em&gt;thousands&lt;&#x2F;em&gt; of people would,
given the same relative prompts, produce the same dumb joke. Myself included.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;You know what was new to me in the early-to-mid 00’s?&lt;&#x2F;p&gt;
&lt;p&gt;The idea that I could &lt;em&gt;quantify&lt;&#x2F;em&gt; the approval of my peers. Used to be, you’d
write something, put it out on the internet, and you might never even know if
anyone cared about what you made. Sure, you could stare at Google Analytics,
but all that told you was that “they” &lt;em&gt;saw&lt;&#x2F;em&gt; it. And who are “they”, anyway? I
had no way to know. You might get a comment or two on a link aggregator site,
but largely… nothing.&lt;&#x2F;p&gt;
&lt;p&gt;I graduated into the 2008 recession. At that same time, I lost my first
programming job. I was unemployed for the first time in my life (for what would
be, to date, the longest stretch of time in my life.)&lt;&#x2F;p&gt;
&lt;p&gt;I was &lt;em&gt;scared&lt;&#x2F;em&gt;. I watched the savings I had put together to move to Portland
dwindle perilously close to empty. This stretch of unemployment was a formative
experience (even despite the number of safety nets available to me!)&lt;&#x2F;p&gt;
&lt;p&gt;The ability to quantify approval came to serve a completely new purpose for me
at this point, one apart from feeding an annoyingly deep-seated personal need
for external validation. I began thinking that “the more people know and
approve of my work online, the less likely I am to be unemployed in the
future.” This wasn’t a unique thought, really, lots of other people who had
similar context came to the same conclusion. But Twitter hadn’t risen to
popularity yet, so how was I to know?&lt;&#x2F;p&gt;
&lt;p&gt;I resolved to try to do a lot more of my work in public, and in particular, to
make things for platforms where I could &lt;em&gt;measure the return on my effort&lt;&#x2F;em&gt;. This
former was a conscious decision, the latter, less so.&lt;&#x2F;p&gt;
&lt;p&gt;At the time, it generally seemed like the things I wanted to do anyway were the
sorts of things that were getting approval online. I wasn’t concerned with the
thought that I would end up tailoring my creative output to fit any particular
platform. The internet was still pretty weird in the mid-to-late 00’s! (It
continues to be  weird now, but, like, in the sense that you might see Arby’s
flirt with Steak’ums.)&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;When I joined Twitter in 2009-ish, it was the &lt;strong&gt;exact opposite&lt;&#x2F;strong&gt; of compelling:
it felt like being able to group text people I could &lt;em&gt;already group text&lt;&#x2F;em&gt;. My
digital social network perfectly overlapped my real, physical social network.
It felt forced; a parody of a social network, good only for dodging phone
carrier SMS fees.&lt;&#x2F;p&gt;
&lt;p&gt;More to the point, it felt like a fad. At one point, my boss at the two (2!)
person local startup I had mercifully landed at introduced a twitter-alike
microblog system to work – so we could micro-post our current working status.
Our desks literally faced each other in an office the size of a closet. Such
was the power of the fad at the time: we dutifully microblogged status updates
we could have literally just said out loud to each other, face to face. We
didn’t just work on the cutting edge – we &lt;em&gt;lived&lt;&#x2F;em&gt; on the cutting edge. And it
&lt;em&gt;hurt&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;We eventually ditched that microblog. There wasn’t enough of a social network
on that social network. And so it was with Twitter at the time.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;The inflection point came shortly after I moved to Portland in 2012. I still
remember: buoyed by a digital social network I had grown around Node.js via
IRC, I started to weigh in on the then-nascent ECMAScript modules debate on
Twitter. Not only that, I was weighing in on it from karaoke. Over a &lt;em&gt;beer&lt;&#x2F;em&gt;.
And I was getting responses from the guy who &lt;em&gt;designed JavaScript&lt;&#x2F;em&gt; &lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#2&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;. And
another guy, whose code I &lt;em&gt;idolized&lt;&#x2F;em&gt;. And he &lt;em&gt;liked my tweets&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Reader. Let me tell you. Through a combination of this ill-conceived platform
and the mundane ignorance of the privilege I benefit from as a straight white
cis guy, I had gained entry to a conversation I had &lt;em&gt;absolutely&lt;&#x2F;em&gt; not paid the
table stakes to participate in.&lt;&#x2F;p&gt;
&lt;p&gt;I was &lt;em&gt;hooked&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Twitter was a free copy editor: the constraint of 140 characters encouraged
pithiness, impact, and comedic pacing. I stop short of saying it made me a
better, more thoughtful writer, but the medium &lt;em&gt;certainly&lt;&#x2F;em&gt; shaped the messages
I wrote.&lt;&#x2F;p&gt;
&lt;p&gt;This helpful editing advice wasn’t &lt;em&gt;free&lt;&#x2F;em&gt;, to be clear: Twitter got something
out of it. The constraints made it easier for people to create content; they
also put an upper limit on wordiness which made it easier to feel okay with
posting something &lt;em&gt;short&lt;&#x2F;em&gt;. The medium itself helped create an environment where
content flowed infinitely; it helped us build our own skinner box. More tweets,
more news, more jokes, more opportunities for validation.&lt;&#x2F;p&gt;
&lt;p&gt;I (and others) often complained about conversations on Twitter losing “nuance.”
Why were we all so okay sacrificing nuance so readily? Well, nuance doesn’t
count for much if you don’t feel like you can be heard in the first place, so.&lt;&#x2F;p&gt;
&lt;p&gt;To be honest, it felt &lt;em&gt;good&lt;&#x2F;em&gt; to tweet through it, sometimes. It was cathartic.
But it also frequently felt less like interacting with other &lt;em&gt;people&lt;&#x2F;em&gt; and more
like feeding a machine: a machine hungry for attention, eyeballs, tweets,
retweets, stories, feelings, &lt;em&gt;hot takes&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;I often found myself editing my thoughts down to tweet size so I could convey
them on Twitter. The medium became the measure of my thoughts. I’d find myself
thinking something insipid about the tactical branding of men’s soap while
shopping at Target (now with Mil-Spec (TM) paracord soap holder) and think,
“I’d like to tweet about that later.”&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Goodhart%27s_law&quot;&gt;When a measure becomes a target, it ceases to be a good measure.&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;small&gt;
&lt;p&gt;I don’t &lt;em&gt;actually&lt;&#x2F;em&gt; want to tweet about that later. I don’t think I want
to tweet anymore, at all. I’d like some of my brain back, please.&lt;&#x2F;p&gt;
&lt;&#x2F;small&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Four things.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;One:&lt;&#x2F;strong&gt; Twitter’s best feature was its biggest liability. Anyone can talk to
anyone at any time about anything. Anything you say has the potential to reach
audiences both friendly and unfriendly at any point over time. You are close to
everyone at the same time that you are speaking to no one in particular. You
get to choose the sound bite, but you can never give it context. You are
LARPing a gossip protocol about reality. Most of the time this is fine. Some of
the time this is fun.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Two:&lt;&#x2F;strong&gt; Some of the time, this is dangerous. There are people who know this and
want to exploit split brain situations on purpose. Or create them. Who looked
at a thousand people making the same joke and thought “okay, how do we control
the punchline?”&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Three:&lt;&#x2F;strong&gt; worryingly, there’s &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.pnas.org&#x2F;doi&#x2F;10.1073&#x2F;pnas.2207159119&quot;&gt;some
evidence&lt;&#x2F;a&gt; that nonlocal
interactions, rather than echo chambers, increase polarization and violent
partisanship. Being able to quantify validation doesn’t just apply to artists
and writers, it applies to people who crave violence against “the other”. It
gives them a mechanism to receive encouragement and a built-in, captive
audience of targets to lash out at.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Four:&lt;&#x2F;strong&gt; ad-funded social network platforms optimize for engagement. Content that
prompts anger draws shares and eyeballs faster than anything else. Thus,
platforms are incentivized to optimize for as little moderation as possible
while still being able to sell ads. Meanwhile, trolls optimize for creating as
much anger as they can while dodging the (scant) moderation in place.&lt;&#x2F;p&gt;
&lt;p&gt;Twitter doesn’t bear the nickname “hellsite” for nothing. Over time, the format
and the incentives of the platform make it a factory for fascism.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;small&gt;And if you couldn’t help but insert “nothing wrong with me” after
reading each number in the prior paragraphs, a la Drowning Pool’s “Let the
Bodies Hit the Floor”: condolences, we think alike.&lt;&#x2F;small&gt;&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;And yet. Something’s got to give, now.&lt;&#x2F;p&gt;
&lt;p&gt;Twitter was a digital &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Third_place&quot;&gt;third place&lt;&#x2F;a&gt;.
I am sad at the propsect of seeing it fade into the digital entropy that
consumed IRC, Digg, Xanga, Livejournal, Starsiege: Tribes, and Tripod before
it.&lt;&#x2F;p&gt;
&lt;p&gt;At its height, I could go to Twitter to ask questions, look for jobs &lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#3&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;, goof
around, expand my worldview, find out about trends in my profession, find
interesting artists, find new indie games, and keep up to date with world news
(through perspectives completely different than mine!) And, yanno, read dril
tweets.&lt;&#x2F;p&gt;
&lt;p&gt;But it really wasn’t &lt;em&gt;healthy&lt;&#x2F;em&gt;, at least not for me. And I don’t know if I want
to rush to replace it with something similar.&lt;&#x2F;p&gt;
&lt;small&gt;
&lt;p&gt;Thanks to &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.jefflembeck.com&#x2F;&quot;&gt;Jeff Lembeck&lt;&#x2F;a&gt; and Krysten for reviewing this&lt;&#x2F;p&gt;
&lt;&#x2F;small&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;1&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;because ES modules were getting node support and they were going to
change the file extension for those modules to “.mjs”, get it, and oh my
god what have I done with the last ten years of my free time&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;2&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;2&lt;&#x2F;sup&gt;
&lt;p&gt;who would later be revealed to be a bit of a turd&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;3&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;3&lt;&#x2F;sup&gt;
&lt;p&gt;isn’t it strange how much better Twitter was at this than LinkedIn?&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
</description>
      </item>
      <item>
          <title>&quot;The UNIX Programming Environment&quot;, reviewed</title>
          <pubDate>Sun, 21 Aug 2022 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://www.neversaw.us/2022/08/21/the-unix-programming-environment/</link>
          <guid>https://www.neversaw.us/2022/08/21/the-unix-programming-environment/</guid>
          <description xml:base="https://www.neversaw.us/2022/08/21/the-unix-programming-environment/">&lt;p&gt;Why should you read 1984’s &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;The_Unix_Programming_Environment&quot;&gt;“The UNIX Programming Environment”&lt;&#x2F;a&gt;
thirty-eight years after it was first published? Why did &lt;em&gt;I&lt;&#x2F;em&gt; read this book?
(Well, I am an unrepentant fan of bash.) Is it even relevant anymore? (Yes.)
Why should you read it?&lt;&#x2F;p&gt;
&lt;p&gt;In order to understand where we’re going as an art, it’s important to know
where we came from. It’s 2022 and I still SSH to boxes, edit files using vim,
and write bash scripts. To be honest, sometimes it feels like the only that’s
changed in the fifteen years is the amount of YAML I have to wrap my bash in.&lt;&#x2F;p&gt;
&lt;p&gt;So yeah, as the Palmolive commercial says, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=dzmTtusvjR4&quot;&gt;“You’re soaking in it!”&lt;&#x2F;a&gt;
This 1984 book remains relevant: most tools we use are either from this era,
reactions to these tools, or reactions to the reactions. Tools written outside
of this conversation exist and can be effective, but generally they feel
slightly off. They don’t integrate with other tools like they should.&lt;&#x2F;p&gt;
&lt;p&gt;Writing tools that coöperate fluently with each other gives you an opportunity
to leverage network effects; to make all existing tools more useful with your
tool.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;So. That all being said, let’s talk about the book itself. “The UNIX
Programming Environment” is short and sweet, clocking in at a little over 250
pages. Each chapter introduces a new topic, explores how it interacts with
topics from prior chapters, then raises issues for the next chapter to resolve.
The book starts with the key innovations of the UNIX operating system and
builds from there to illustrate a “blessed path” for program development:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;The filesystem&lt;&#x2F;li&gt;
&lt;li&gt;Using the shell&lt;&#x2F;li&gt;
&lt;li&gt;Filters&lt;&#x2F;li&gt;
&lt;li&gt;Shell programming&lt;&#x2F;li&gt;
&lt;li&gt;The process environment: using stdio&lt;&#x2F;li&gt;
&lt;li&gt;System calls&lt;&#x2F;li&gt;
&lt;li&gt;Program development&lt;&#x2F;li&gt;
&lt;li&gt;Document preparation&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Some chapters are more relevant to contemporary readers than others. In
particular, while the section on document preparation is interesting from a
historical perspective, unless you’re writing &lt;code&gt;man&lt;&#x2F;code&gt; pages by hand, you probably
won’t have occasion to use the tools described there.&lt;&#x2F;p&gt;
&lt;p&gt;It’s worth noting at this point that this book wasn’t written during the early
development of UNIX. Rather, this book was written 11-15 years later, when UNIX
had already escaped containment at Bell Labs and was rapidly growing in
popularity.&lt;&#x2F;p&gt;
&lt;p&gt;Quoth the book, in an example given in a late chaper:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;John Lions taught the 6th Edition UNIX kernel in an undergraduate OS course
at UNSW. In notes prepared for the class, he wrote, “the whole documentation
is not unreasonably transportable in a student’s briefcase.” (This has been
fixed in recent versions.)&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;(You can expect this level of self-effacing, dry humor throughout.)&lt;&#x2F;p&gt;
&lt;p&gt;The section on program development gleefully sings the praises of &lt;code&gt;yacc&lt;&#x2F;code&gt;,
sharing the fascination with parsing so common in texts from this era. The C
code listings are somewhat less directly applicable today than the shell
listings, but the progression from “using the shell” to “using filters” to
“programming the shell” to “writing the program in C with &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;System_call&quot;&gt;system calls&lt;&#x2F;a&gt;” does an
excellent job of illustrating the third point from the oft-quoted,
frequently-truncated UNIX philosophy. I include the full treatment of the
philosophy from the book itself:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;First, let the machine do the work. Use programs like grep and wc and
awk to mechanize tasks that you might do by hand on other systems.&lt;&#x2F;p&gt;
&lt;p&gt;Second, let other people do the work. Use programs that already exist as
building blocks in your programs, with the shell and the programmable filters
to glue them together. Write a small program to interface to an existing one
that does the real work, as we did with idiff. The UNIX environment is rich
in tools that can be combined in myriad ways; your job is often just to think of
the right combination.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Third, do the job in stages.&lt;&#x2F;strong&gt; Build the simplest thing that will be useful, and
let your experience with that determine what (if anything) is worth doing next.
Don’t add features and options until usage patterns tell you which ones are
needed.&lt;&#x2F;p&gt;
&lt;p&gt;Fourth, build tools. Write programs that mesh with the existing environ-
ment, enhancing it rather than merely adding to it. Built well, such programs
themselves become a part of everyone’s toolkit.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;I invite you, dear reader, to make a comparison to &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Unix_philosophy#Origin&quot;&gt;pithier, widely-known Doug
McIllroy version&lt;&#x2F;a&gt;. The book’s version of the philosophy resonates with my
experiences as a professional programmer for the last sixteen years. These are
words to live by!&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;My goal in writing this review —other than to defend an otherwise
indefensibly wanton habit of purchasing classic Computer Science textbooks from
my local used bookstore— is to &lt;em&gt;nudge&lt;&#x2F;em&gt; you, dear reader, into leafing
through this book, perhaps on a lazy day off. The UNIX Programming Environment
conveys the enthusiasm and laughing regret of folks who’ve worked within a
particular moment in computer science. It’s a great jumping-off point for
future research, while connecting the dots between many of the disparate tools
you use every day.&lt;&#x2F;p&gt;
&lt;p&gt;So, I leave you as the book does, with an aside about &lt;code&gt;ed&lt;&#x2F;code&gt;. One of the most
interesting things I learned from this book (aside from the fact that &lt;code&gt;stdin&lt;&#x2F;code&gt;
is the result of &lt;code&gt;open(&quot;&#x2F;dev&#x2F;tty&quot;)&lt;&#x2F;code&gt;, and &lt;code&gt;stdout&lt;&#x2F;code&gt; is the result of &lt;code&gt;dup(1)&lt;&#x2F;code&gt;, so
you can write output to stdin) is the relationship between &lt;code&gt;ed&lt;&#x2F;code&gt;, &lt;code&gt;grep&lt;&#x2F;code&gt;, and
&lt;code&gt;sed&lt;&#x2F;code&gt;. You may be aware, as I was, that &lt;code&gt;grep&lt;&#x2F;code&gt; was derived from &lt;code&gt;ed&lt;&#x2F;code&gt;; but I was
surprised to find that &lt;code&gt;grep&lt;&#x2F;code&gt; had wayward siblings: &lt;code&gt;gred&lt;&#x2F;code&gt; and &lt;code&gt;gres&lt;&#x2F;code&gt; – all
derived from the &lt;code&gt;ed&lt;&#x2F;code&gt; incantation, &lt;code&gt;g&#x2F;re&#x2F;*&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Eventually all of the variant commands were wrapped into a successor program,
&lt;code&gt;sed&lt;&#x2F;code&gt;. Where this becomes useful for me: my editor, &lt;code&gt;neovim&lt;&#x2F;code&gt;, descends from
&lt;code&gt;vim&lt;&#x2F;code&gt;, which descends from &lt;code&gt;vi&lt;&#x2F;code&gt;, which descends from &lt;code&gt;ex&lt;&#x2F;code&gt;, which descends from
&lt;code&gt;ed&lt;&#x2F;code&gt;. My muscle memory for my editor translates directly into using &lt;code&gt;sed&lt;&#x2F;code&gt;! And
likewise, everything I learn about &lt;code&gt;sed&lt;&#x2F;code&gt; carries back into my editor.&lt;&#x2F;p&gt;
&lt;p&gt;Network effects are powerful!&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>(2019) Keynote: The Path to Components - Luke Wagner, Distinguished Engineer, Fastly - YouTube</title>
          <pubDate>Tue, 02 Aug 2022 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://www.neversaw.us/links/2019-keynote-the-path-to-components-luke-wagner-distinguished-engineer-fastly-youtube/</link>
          <guid>https://www.neversaw.us/links/2019-keynote-the-path-to-components-luke-wagner-distinguished-engineer-fastly-youtube/</guid>
          <description xml:base="https://www.neversaw.us/links/2019-keynote-the-path-to-components-luke-wagner-distinguished-engineer-fastly-youtube/">&lt;p&gt;One of the best explainers on the state of WASI&#x2F;WIT&#x2F;WASM components I’ve seen.
This is part of an interesting trend: the industry is starting to revisit bedrock abstractions. Systemd started doing this
with single-machine process management, Kubernetes did it with cluster management, Aurae is starting to look into what it looks
like for larger clusters. At the same time that we’re having this renaissance in service orchestration, WASM components are relitigating
inter-process communications and resource sharing (“What if programs didn’t call each other by file system location, but instead by calling
directly into each other? What if they didn’t have to serialize state into text?”)
I am much more hopeful about the hypothetical future of orchestrated WASM binaries than I am about the container landscape, to be honest. Docker
left behind quite a crater.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>IPv6 Internet Is Broken</title>
          <pubDate>Tue, 02 Aug 2022 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://www.neversaw.us/links/ipv6-internet-is-broken/</link>
          <guid>https://www.neversaw.us/links/ipv6-internet-is-broken/</guid>
          <description xml:base="https://www.neversaw.us/links/ipv6-internet-is-broken/">&lt;p&gt;Fascinating stuff. I’ve spent half of this year picking up the rudiments of network engineering,
and it’s absolutely fascinating to me that IPv6 attempts to return to the “end to end” principle
we lost with IPv4 NAT. (Peering disputes around IPv6 are only tangentially related to this, of course,
but two neurons grazed past each other when I read this.)
Of note (for me) are the other links on this post – the “looking
glass” sites for those providers are new to me!
Also, the “cheap VPS” and “subnetting cheatsheets” seem handy.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Refactoring Is Not Just Clickbait - Kevlin Henney - NDC Oslo 2022</title>
          <pubDate>Tue, 02 Aug 2022 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://www.neversaw.us/links/refactoring-is-not-just-clickbait-kevlin-henney-ndc-oslo-2022/</link>
          <guid>https://www.neversaw.us/links/refactoring-is-not-just-clickbait-kevlin-henney-ndc-oslo-2022/</guid>
          <description xml:base="https://www.neversaw.us/links/refactoring-is-not-just-clickbait-kevlin-henney-ndc-oslo-2022/">&lt;p&gt;Great talk; I especially enjoyed his “three axes” approach to describing changes to programs.
He also mentions Herbert Simon, whose writing on systems I am now enjoying.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Running LXD Containers in Macpine</title>
          <pubDate>Tue, 02 Aug 2022 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://www.neversaw.us/links/running-lxd-containers-in-macpine/</link>
          <guid>https://www.neversaw.us/links/running-lxd-containers-in-macpine/</guid>
          <description xml:base="https://www.neversaw.us/links/running-lxd-containers-in-macpine/">&lt;p&gt;This is pretty rad.
I ended up wanting to &lt;code&gt;ssh&lt;&#x2F;code&gt; directly into my containers; in order to
do this I had to edit &lt;code&gt;&#x2F;etc&#x2F;ssh&#x2F;sshd_config&lt;&#x2F;code&gt; on the macpine box
(using &lt;code&gt;alpine ssh lxd&lt;&#x2F;code&gt;.)&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D3C6AA; background-color: #2D353B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;AllowTcpForwarding yes # change this from &amp;quot;no&amp;quot; to &amp;quot;yes&amp;quot; in &#x2F;etc&#x2F;ssh&#x2F;sshd_config&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After running &lt;code&gt;&#x2F;etc&#x2F;init.d&#x2F;ssh reload&lt;&#x2F;code&gt;, I was able to use the macpine LXD VM as
an ssh jumpbox (via ssh’s handy &lt;code&gt;-J&lt;&#x2F;code&gt; option.)&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>So you&#x27;re Staff+ ... now what?</title>
          <pubDate>Tue, 02 Aug 2022 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://www.neversaw.us/links/so-you-re-staff-now-what/</link>
          <guid>https://www.neversaw.us/links/so-you-re-staff-now-what/</guid>
          <description xml:base="https://www.neversaw.us/links/so-you-re-staff-now-what/">&lt;p&gt;This is one of the most useful talks I’ve seen. I acted as a principal
engineer at Eaze for a little over a year; early on I struggled with the
role because it wasn’t clear how involved I should get with the various
teams I floated between.
Sabrina Leandro outlines a great way to build accountability for yourself
that empowers you to work directly in different codebases while also giving
yourself headroom to do the planning, research, and coordination that come
with the role.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>The Continuity of Splines - YouTube</title>
          <pubDate>Tue, 02 Aug 2022 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://www.neversaw.us/links/the-continuity-of-splines-youtube/</link>
          <guid>https://www.neversaw.us/links/the-continuity-of-splines-youtube/</guid>
          <description xml:base="https://www.neversaw.us/links/the-continuity-of-splines-youtube/">&lt;p&gt;What a presentation! I only took calculus up to “engineering calc 2” level in college,
which leaves off approximately where this picks up – that is, calculus for parametric equations. That is to say, just when math starts
to get really interesting, if you’re into gamedev.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>The Rust Programming Language for Game Tooling</title>
          <pubDate>Tue, 02 Aug 2022 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://www.neversaw.us/links/the-rust-programming-language-for-game-tooling/</link>
          <guid>https://www.neversaw.us/links/the-rust-programming-language-for-game-tooling/</guid>
          <description xml:base="https://www.neversaw.us/links/the-rust-programming-language-for-game-tooling/">&lt;p&gt;It’s great to see Rust adoption at game studios. I appreciated the
link to &lt;code&gt;gimli&lt;&#x2F;code&gt; and &lt;code&gt;iced&lt;&#x2F;code&gt;. His recommendation to start building rust
in a contained fashion – in a corner of the codebase – matches my
experience at Eaze. I definitely did the same there: starting small,
nerd-sniping a colleague with a standalone CLI tool, then rolling it out
to more and more developers.
Also, he mentions that his favorite web framework is Tide! (I love to see
it, even if I’m not using Tide since Tokio won the async wars.)&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>toast - crates.io: Rust Package Registry</title>
          <pubDate>Tue, 02 Aug 2022 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://www.neversaw.us/links/toast-crates-io-rust-package-registry/</link>
          <guid>https://www.neversaw.us/links/toast-crates-io-rust-package-registry/</guid>
          <description xml:base="https://www.neversaw.us/links/toast-crates-io-rust-package-registry/">&lt;p&gt;Another super-useful tool from Kevin’s menagerie of good Rust links.
This allows easy cross-compilation using containers.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Watchexec</title>
          <pubDate>Tue, 02 Aug 2022 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://www.neversaw.us/links/watchexec/</link>
          <guid>https://www.neversaw.us/links/watchexec/</guid>
          <description xml:base="https://www.neversaw.us/links/watchexec/">&lt;p&gt;Wow, this is great. I’m using it already to power my link dump parser.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Color Studies</title>
          <pubDate>Sun, 20 Feb 2022 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://www.neversaw.us/2022/02/20/color-studies/</link>
          <guid>https://www.neversaw.us/2022/02/20/color-studies/</guid>
          <description xml:base="https://www.neversaw.us/2022/02/20/color-studies/">&lt;h1 id=&quot;color-studies&quot;&gt;Color Studies&lt;&#x2F;h1&gt;
&lt;p&gt;TKTK&lt;&#x2F;p&gt;
&lt;p&gt;After the last post, I want to back away from tech for a bit, so I’m writing about color palettes today.&lt;&#x2F;p&gt;
&lt;p&gt;I used &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;colormind.io&#x2F;image&#x2F;#&quot;&gt;Colormind&lt;&#x2F;a&gt; to derive palettes from images that
resonated with me.&lt;&#x2F;p&gt;
&lt;!-- using bin&#x2F;palettize, sic --&gt;
&lt;h2 id=&quot;sonic-cd-stardust-speedway-zone&quot;&gt;sonic cd: stardust speedway zone&lt;&#x2F;h2&gt;
&lt;div style=&quot;display: flex; flex-direction: row; width: 100%&quot;&gt;&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #CDB043&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #322143&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #6E49BF&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #529B56&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #465D2A&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #CC5541&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #071317&quot;&gt;&lt;&#x2F;div&gt;&lt;&#x2F;div&gt;
&lt;img style=&quot;max-width: 100%;&quot; src=&quot;https:&#x2F;&#x2F;www.neversaw.us&#x2F;palettes&#x2F;sonic-cd-stardust-speedway-zone.jpg&quot; &#x2F;&gt;
&lt;p&gt;I’m kicking things off with a bunch of 16-bit Sonic screenshots. It’s probably
no surprise that I love the art direction of this series; it’s one of the first
things I remember identifying as “futuristic” in the early nineties.&lt;&#x2F;p&gt;
&lt;p&gt;This shot, in particular, is from Sonic CD, a game on a console I only managed
to rent once. The color palette is doing a TON of work here: it feels frenetic
and cosmopolitan. Depictions like this really formed my perception of what a
modern metropolis should look like!&lt;&#x2F;p&gt;
&lt;p&gt;(It bears mentioning: I love a dark palette with pops of purple and green.)&lt;&#x2F;p&gt;
&lt;hr style=&quot;clear: both;&quot; &#x2F;&gt;
&lt;h2 id=&quot;sf-sunset&quot;&gt;sf sunset&lt;&#x2F;h2&gt;
&lt;div style=&quot;display: flex; flex-direction: row; width: 100%&quot;&gt;&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #7287AE&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #224464&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #75A922&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #885457&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #F99D41&quot;&gt;&lt;&#x2F;div&gt;&lt;&#x2F;div&gt;
&lt;img style=&quot;max-width: 100%;&quot; src=&quot;https:&#x2F;&#x2F;www.neversaw.us&#x2F;palettes&#x2F;sf-sunset.jpg&quot; &#x2F;&gt;
&lt;p&gt;I found this via &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;mobile.twitter.com&#x2F;vllry&#x2F;status&#x2F;1491584598370750466&quot;&gt;this tweet&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;A strong blue-orange composition, sticking towards the midtones!&lt;&#x2F;p&gt;
&lt;p&gt;I’m tickled that Colormind detected the yellow street sign and threw it into the
palette as a little burst of green.&lt;&#x2F;p&gt;
&lt;p&gt;I find these blue-orange palettes captivating: they can tilt warm or cold with
only a little nudge, melancholy or energetic, even futuristic (thinking back to
LEGO’s &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;LegoSpaceBot&#x2F;status&#x2F;1256945447286996993&quot;&gt;“Ice Planet
2002”&lt;&#x2F;a&gt; line from
the nineties.)&lt;&#x2F;p&gt;
&lt;hr style=&quot;clear: both;&quot; &#x2F;&gt;
&lt;h2 id=&quot;sonic-2-chemical-plant-zone-act-1&quot;&gt;sonic 2: chemical plant zone act 1&lt;&#x2F;h2&gt;
&lt;div style=&quot;display: flex; flex-direction: row; width: 100%&quot;&gt;&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #390F09&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #8E1708&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #9A4308&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #7A942D&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #E5C852&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #0C0ECA&quot;&gt;&lt;&#x2F;div&gt;&lt;&#x2F;div&gt;
&lt;img style=&quot;max-width: 100%;&quot; src=&quot;https:&#x2F;&#x2F;www.neversaw.us&#x2F;palettes&#x2F;sonic-2-chemical-plant-zone-act-1.jpg&quot; &#x2F;&gt;
&lt;p&gt;Increasingly displaced by blue-white LED lighting, sodium lamps used to throw
their golden hue lazily over city blocks. Chemical plant zone captures this;
it’s kind of an oddball arrangement with the warmer tones in the background
getting covered up by higher-energy bright colors, grays, and blues.&lt;&#x2F;p&gt;
&lt;p&gt;A near-black red sky is at once ominous and comforting.&lt;&#x2F;p&gt;
&lt;hr style=&quot;clear: both;&quot; &#x2F;&gt;
&lt;h2 id=&quot;sonic-2-chemical-plant-zone-act-2&quot;&gt;sonic 2: chemical plant zone act 2&lt;&#x2F;h2&gt;
&lt;div style=&quot;display: flex; flex-direction: row; width: 100%&quot;&gt;&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #A09D8A&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #E6C03A&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #0C0ECA&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #1A1525&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #7A942D&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #CB4CB0&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #824EB9&quot;&gt;&lt;&#x2F;div&gt;&lt;&#x2F;div&gt;
&lt;img style=&quot;max-width: 100%;&quot; src=&quot;https:&#x2F;&#x2F;www.neversaw.us&#x2F;palettes&#x2F;sonic-2-chemical-plant-zone-act-2.jpg&quot; &#x2F;&gt;
&lt;p&gt;As the aforementioned level plays forward, you end up getting closer to the
eponymous pink goo. The colors skew cooler here; even the pink tends a little
towards the blue side.&lt;&#x2F;p&gt;
&lt;hr style=&quot;clear: both;&quot; &#x2F;&gt;
&lt;h2 id=&quot;doom-eternal&quot;&gt;doom eternal&lt;&#x2F;h2&gt;
&lt;div style=&quot;display: flex; flex-direction: row; width: 100%&quot;&gt;&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #984D39&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #CA533A&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #D0999E&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #F1C986&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #7196CF&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #65678E&quot;&gt;&lt;&#x2F;div&gt;&lt;&#x2F;div&gt;
&lt;img style=&quot;max-width: 100%;&quot; src=&quot;https:&#x2F;&#x2F;www.neversaw.us&#x2F;palettes&#x2F;doom-eternal.jpg&quot; &#x2F;&gt;
&lt;p&gt;Another strong blue-orange composition; it’s fascinating how little one has to
lean towards the blues to drop the temperature sharply.&lt;&#x2F;p&gt;
&lt;hr style=&quot;clear: both;&quot; &#x2F;&gt;
&lt;h2 id=&quot;metroid-by-mostly-ghostly&quot;&gt;metroid by mostly ghostly&lt;&#x2F;h2&gt;
&lt;div style=&quot;display: flex; flex-direction: row; width: 100%&quot;&gt;&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #091F5E&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #0C61CD&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #0D55CB&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #12B9F2&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #2A6760&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #1CA363&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #D74A62&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #E56B54&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #E8428E&quot;&gt;&lt;&#x2F;div&gt;&lt;&#x2F;div&gt;
&lt;img style=&quot;max-width: 100%;&quot; src=&quot;https:&#x2F;&#x2F;www.neversaw.us&#x2F;palettes&#x2F;metroid-by-mostly-ghostly.jpg&quot; &#x2F;&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;mobile.twitter.com&#x2F;LowBudgetGhost&#x2F;status&#x2F;1465673162675392524&#x2F;photo&#x2F;1&quot;&gt;A great
illustration&lt;&#x2F;a&gt;
by LowBudgetGhost. (I love this illustrator’s work!) I picked this piece because it’s indicative
of their other work: strong mid-to-light tone colors vibrating against each other.&lt;&#x2F;p&gt;
&lt;p&gt;Go check out their work!&lt;&#x2F;p&gt;
&lt;hr style=&quot;clear: both;&quot; &#x2F;&gt;
&lt;h2 id=&quot;chicago-winter-storm-tweet&quot;&gt;chicago winter storm tweet&lt;&#x2F;h2&gt;
&lt;div style=&quot;display: flex; flex-direction: row; width: 100%&quot;&gt;&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #160B07&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #858B9E&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #7B7F93&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #A7A29C&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #D9C2A4&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #7B4D1C&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #4F75B1&quot;&gt;&lt;&#x2F;div&gt;&lt;&#x2F;div&gt;
&lt;img style=&quot;max-width: 100%;&quot; src=&quot;https:&#x2F;&#x2F;www.neversaw.us&#x2F;palettes&#x2F;chicago-winter-storm-tweet.jpg&quot; &#x2F;&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;mobile.twitter.com&#x2F;mandophotos&#x2F;status&#x2F;1494473003090034689&#x2F;photo&#x2F;1&quot;&gt;A really lovely
photo&lt;&#x2F;a&gt;
of a chicago winter storm.&lt;&#x2F;p&gt;
&lt;p&gt;This just popped across my feed and reminded me of an ill-fated winter visit to
Chicago from years past (one of many, to be honest!) In particular, I love how
this palette captures the juxtaposition of those snowy whites and grays against
the warm, again ominous sky.&lt;&#x2F;p&gt;
&lt;hr style=&quot;clear: both;&quot; &#x2F;&gt;
&lt;h2 id=&quot;lawrence-ks-sunset&quot;&gt;lawrence ks sunset&lt;&#x2F;h2&gt;
&lt;div style=&quot;display: flex; flex-direction: row; width: 100%&quot;&gt;&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #26334A&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #8B90A3&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #B4A99E&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #4F3B37&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #151716&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #7B7F9E&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #53424F&quot;&gt;&lt;&#x2F;div&gt;&lt;&#x2F;div&gt;
&lt;img style=&quot;max-width: 100%;&quot; src=&quot;https:&#x2F;&#x2F;www.neversaw.us&#x2F;palettes&#x2F;lawrence-ks-sunset.jpeg&quot; &#x2F;&gt;
&lt;p&gt;Home sweet home. Lawrence is a small Kansas college town where I lived from
2004-2012. This shot is from Summer 2009; a view from the hill, where the
college is located, down to the main street of the town.&lt;&#x2F;p&gt;
&lt;hr style=&quot;clear: both;&quot; &#x2F;&gt;
&lt;h2 id=&quot;lift-in-palm-springs&quot;&gt;lift in palm springs&lt;&#x2F;h2&gt;
&lt;div style=&quot;display: flex; flex-direction: row; width: 100%&quot;&gt;&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #1B2837&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #202D3D&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #527CAF&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #80A7D4&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #6C7A8F&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #DCE0E2&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #E1E5E7&quot;&gt;&lt;&#x2F;div&gt;&lt;&#x2F;div&gt;
&lt;img style=&quot;max-width: 100%;&quot; src=&quot;https:&#x2F;&#x2F;www.neversaw.us&#x2F;palettes&#x2F;lift-in-palm-springs.jpeg&quot; &#x2F;&gt;
&lt;hr style=&quot;clear: both;&quot; &#x2F;&gt;
&lt;h2 id=&quot;weeping-alaskan-close-up&quot;&gt;weeping alaskan close up&lt;&#x2F;h2&gt;
&lt;div style=&quot;display: flex; flex-direction: row; width: 100%&quot;&gt;&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #383F30&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #335537&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #63927D&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #5C9773&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #80CAAE&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #87BD9B&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #B1DEB9&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #C7E2D8&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #6F97A7&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #CEDDD5&quot;&gt;&lt;&#x2F;div&gt;&lt;&#x2F;div&gt;
&lt;img style=&quot;max-width: 100%;&quot; src=&quot;https:&#x2F;&#x2F;www.neversaw.us&#x2F;palettes&#x2F;weeping-alaskan-close-up.jpeg&quot; &#x2F;&gt;
&lt;hr style=&quot;clear: both;&quot; &#x2F;&gt;
&lt;h2 id=&quot;blue-sky&quot;&gt;blue sky&lt;&#x2F;h2&gt;
&lt;div style=&quot;display: flex; flex-direction: row; width: 100%&quot;&gt;&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #5C84BB&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #75A4E2&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #9DBAE6&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #929EC6&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #ADB0CF&quot;&gt;&lt;&#x2F;div&gt;&lt;&#x2F;div&gt;
&lt;img style=&quot;max-width: 100%;&quot; src=&quot;https:&#x2F;&#x2F;www.neversaw.us&#x2F;palettes&#x2F;blue-sky.jpeg&quot; &#x2F;&gt;
&lt;hr style=&quot;clear: both;&quot; &#x2F;&gt;
&lt;h2 id=&quot;halloween-jack-o-lantern&quot;&gt;halloween jack o lantern&lt;&#x2F;h2&gt;
&lt;div style=&quot;display: flex; flex-direction: row; width: 100%&quot;&gt;&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #CE3D3C&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #DE4426&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #B58A93&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #850CA2&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #871F44&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #1E0906&quot;&gt;&lt;&#x2F;div&gt;&lt;&#x2F;div&gt;
&lt;img style=&quot;max-width: 100%;&quot; src=&quot;https:&#x2F;&#x2F;www.neversaw.us&#x2F;palettes&#x2F;halloween-jack-o-lantern.jpeg&quot; &#x2F;&gt;
&lt;hr style=&quot;clear: both;&quot; &#x2F;&gt;
&lt;h2 id=&quot;neon-blinds&quot;&gt;neon blinds&lt;&#x2F;h2&gt;
&lt;div style=&quot;display: flex; flex-direction: row; width: 100%&quot;&gt;&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #020E36&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #0B3873&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #769C8C&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #6025D7&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #9B6ABC&quot;&gt;&lt;&#x2F;div&gt;&lt;&#x2F;div&gt;
&lt;img style=&quot;max-width: 100%;&quot; src=&quot;https:&#x2F;&#x2F;www.neversaw.us&#x2F;palettes&#x2F;neon-blinds.jpeg&quot; &#x2F;&gt;
&lt;hr style=&quot;clear: both;&quot; &#x2F;&gt;
&lt;h2 id=&quot;tampa&quot;&gt;Tampa&lt;&#x2F;h2&gt;
&lt;div style=&quot;display: flex; flex-direction: row; width: 100%&quot;&gt;&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #B4D9F8&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #5D8AB4&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #9DCEFC&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #608154&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #183133&quot;&gt;&lt;&#x2F;div&gt;&lt;&#x2F;div&gt;
&lt;img style=&quot;max-width: 100%;&quot; src=&quot;https:&#x2F;&#x2F;www.neversaw.us&#x2F;palettes&#x2F;tampa.jpeg&quot; &#x2F;&gt;
&lt;p&gt;Can I just say that I’m really chuffed that Colormind picked four beautiful
colors and “swamp green” for this picture?&lt;&#x2F;p&gt;
&lt;p&gt;(This picture actually got me back into liquid inks – mostly to play with
masqueing fluid!)&lt;&#x2F;p&gt;
&lt;hr style=&quot;clear: both;&quot; &#x2F;&gt;
&lt;h2 id=&quot;budapest-alley-at-night&quot;&gt;Budapest Alley, at Night&lt;&#x2F;h2&gt;
&lt;div style=&quot;display: flex; flex-direction: row; width: 100%&quot;&gt;&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #CAA571&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #A49442&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #917457&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #463B49&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #7768B0&quot;&gt;&lt;&#x2F;div&gt;&lt;&#x2F;div&gt;
&lt;img style=&quot;max-width: 100%;&quot; src=&quot;https:&#x2F;&#x2F;www.neversaw.us&#x2F;palettes&#x2F;budapest-alley-at-night.jpeg&quot; &#x2F;&gt;
&lt;p&gt;I took a trip to Budapest a few years back – my first overseas flight, with
Krysten and some friends – and took this photo looing down from the back of
our hotel on our first night.&lt;&#x2F;p&gt;
&lt;p&gt;This picture has a pretty sedate palette: purple and yellow bounce off each
other, but since they’re not super-saturated they end up feeling pretty chill.&lt;&#x2F;p&gt;
&lt;hr style=&quot;clear: both;&quot; &#x2F;&gt;
&lt;h2 id=&quot;budapest-sunset-one&quot;&gt;Budapest Sunset One&lt;&#x2F;h2&gt;
&lt;div style=&quot;display: flex; flex-direction: row; width: 100%&quot;&gt;&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #403429&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #717B7C&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #D2BCA9&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #7F624D&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #614531&quot;&gt;&lt;&#x2F;div&gt;&lt;&#x2F;div&gt;
&lt;img style=&quot;max-width: 100%;&quot; src=&quot;https:&#x2F;&#x2F;www.neversaw.us&#x2F;palettes&#x2F;budapest-sunset-one.jpeg&quot; &#x2F;&gt;
&lt;hr style=&quot;clear: both;&quot; &#x2F;&gt;
&lt;h2 id=&quot;budapest-sunset-two&quot;&gt;Budapest Sunset Two&lt;&#x2F;h2&gt;
&lt;div style=&quot;display: flex; flex-direction: row; width: 100%&quot;&gt;&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #242120&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #847993&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #D6ABB1&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #603829&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #986642&quot;&gt;&lt;&#x2F;div&gt;&lt;&#x2F;div&gt;
&lt;img style=&quot;max-width: 100%;&quot; src=&quot;https:&#x2F;&#x2F;www.neversaw.us&#x2F;palettes&#x2F;budapest-sunset-two.jpeg&quot; &#x2F;&gt;
&lt;hr style=&quot;clear: both;&quot; &#x2F;&gt;
&lt;h2 id=&quot;1208-room-markers&quot;&gt;1208 Room, Markers&lt;&#x2F;h2&gt;
&lt;div style=&quot;display: flex; flex-direction: row; width: 100%&quot;&gt;&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #C9ABBA&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #F2CC83&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #DF8D59&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #635040&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #A5975A&quot;&gt;&lt;&#x2F;div&gt;&lt;&#x2F;div&gt;
&lt;img style=&quot;max-width: 100%;&quot; src=&quot;https:&#x2F;&#x2F;www.neversaw.us&#x2F;palettes&#x2F;1208-room-markers.jpg&quot; &#x2F;&gt;
&lt;p&gt;An illustration I did of my old room from 2007. The room was a mess and I think
the colors faithfully reflect that. The room in question had a bright green
carpet set against burgundy walls, and the only source of light at night was a
cheap Target paper lamp, giving off warm incandescent light. As a result, you
get light purples, oranges, olives, and greens. The red of the wall isn’t
present, thankfully.&lt;&#x2F;p&gt;
&lt;p&gt;I particularly like the pastel-violet to mustard yellow transition.&lt;&#x2F;p&gt;
&lt;hr style=&quot;clear: both;&quot; &#x2F;&gt;
&lt;h2 id=&quot;captain-yajima-splash&quot;&gt;Captain Yajima Splash&lt;&#x2F;h2&gt;
&lt;div style=&quot;display: flex; flex-direction: row; width: 100%&quot;&gt;&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #EBE2E1&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #C46853&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #963E38&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #29221E&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #90AB1A&quot;&gt;&lt;&#x2F;div&gt;&lt;&#x2F;div&gt;
&lt;img style=&quot;max-width: 100%;&quot; src=&quot;https:&#x2F;&#x2F;www.neversaw.us&#x2F;palettes&#x2F;captain-yajima-splash.png&quot; &#x2F;&gt;
&lt;p&gt;From Worthikid’s &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=l-TJm7HkzkQ&quot;&gt;“Captain Yajima”&lt;&#x2F;a&gt; short animation.&lt;&#x2F;p&gt;
&lt;p&gt;Another pulp-comics-inspired palette. I love the poster colors – the red,
green, and eggshell white are out in front, grabbing your attention. The black is
tinged a sickly green, like the black ink on neon green you’d see for a band flier.&lt;&#x2F;p&gt;
&lt;p&gt;I like that this palette gives you three different ways to grab attention.&lt;&#x2F;p&gt;
&lt;hr style=&quot;clear: both;&quot; &#x2F;&gt;
&lt;h2 id=&quot;f-zero-big-blue&quot;&gt;F-Zero: Big Blue&lt;&#x2F;h2&gt;
&lt;div style=&quot;display: flex; flex-direction: row; width: 100%&quot;&gt;&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #F0E2E3&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #8E97D2&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #2E3FB8&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #852D73&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #D08F39&quot;&gt;&lt;&#x2F;div&gt;&lt;&#x2F;div&gt;
&lt;img style=&quot;max-width: 100%;&quot; src=&quot;https:&#x2F;&#x2F;www.neversaw.us&#x2F;palettes&#x2F;f-zero-big-blue.jpg&quot; &#x2F;&gt;
&lt;p&gt;The nineties aesthetic loves a beach. We hit a bunch of loud, hyper-saturated colors
here: deep blues, palm tree greens, and neon oranges. The rambunctious colors are grounded
by a staid, almost wine-like, magenta.&lt;&#x2F;p&gt;
&lt;hr style=&quot;clear: both;&quot; &#x2F;&gt;
&lt;h2 id=&quot;demon-s-crest-town&quot;&gt;Demon’s Crest Town&lt;&#x2F;h2&gt;
&lt;div style=&quot;display: flex; flex-direction: row; width: 100%&quot;&gt;&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #131124&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #3D2B98&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #273073&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #639A34&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #9FAB7F&quot;&gt;&lt;&#x2F;div&gt;&lt;&#x2F;div&gt;
&lt;img style=&quot;max-width: 100%;&quot; src=&quot;https:&#x2F;&#x2F;www.neversaw.us&#x2F;palettes&#x2F;demon-s-crest-town.png&quot; &#x2F;&gt;
&lt;p&gt;A game I really loved as a kid.&lt;&#x2F;p&gt;
&lt;p&gt;Demon’s Crest is a SNES Capcom game set in a strange, ruined medieval world
ruled by demons. The environment design is top-notch; it really shines in the
early game when you’re wandering through ruined towns and overgrown cemeteries.&lt;&#x2F;p&gt;
&lt;p&gt;Demon’s Crest strikes a balance between eeriness and melancholy. It’s probably
no surprise they’re using a saturated purple-green palette to play up the pulp
horror vibes.&lt;&#x2F;p&gt;
&lt;hr style=&quot;clear: both;&quot; &#x2F;&gt;
&lt;hr style=&quot;clear: both;&quot; &#x2F;&gt;
&lt;h2 id=&quot;portland-springtime-cherry-blossoms&quot;&gt;Portland Springtime Cherry Blossoms&lt;&#x2F;h2&gt;
&lt;div style=&quot;display: flex; flex-direction: row; width: 100%&quot;&gt;&lt;div style=&quot;flex: fit-content; width: -webkit-fit-content; width: fit-content; height: 200px; background: #987C92&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: -webkit-fit-content; width: fit-content; height: 200px; background: #A59DC6&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: -webkit-fit-content; width: fit-content; height: 200px; background: #A7CBE7&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: -webkit-fit-content; width: fit-content; height: 200px; background: #E7DDDC&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: -webkit-fit-content; width: fit-content; height: 200px; background: #486829&quot;&gt;&lt;&#x2F;div&gt;&lt;&#x2F;div&gt;
&lt;img style=&quot;max-width: 100%;&quot; src=&quot;https:&#x2F;&#x2F;www.neversaw.us&#x2F;palettes&#x2F;portland-springtime-cherry-blossoms.webp&quot; &#x2F;&gt;
&lt;p&gt;I found this via &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.reddit.com&#x2F;r&#x2F;Portland&#x2F;comments&#x2F;tistwr&#x2F;cherry_blossoms_at_the_waterfront_yesterday&#x2F;&quot;&gt;this Reddit post&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;hr style=&quot;clear: both;&quot; &#x2F;&gt;
&lt;h2 id=&quot;portland-springtime-cherry-blossoms-part-two&quot;&gt;Portland Springtime Cherry Blossoms Part Two&lt;&#x2F;h2&gt;
&lt;div style=&quot;display: flex; flex-direction: row; width: 100%&quot;&gt;&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #2B2A3E&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #6E97D1&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #85BDF5&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #A4676C&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content;  height: 200px; background: #CDA09C&quot;&gt;&lt;&#x2F;div&gt;&lt;&#x2F;div&gt;
&lt;img style=&quot;max-width: 100%;&quot; src=&quot;https:&#x2F;&#x2F;www.neversaw.us&#x2F;palettes&#x2F;portland-springtime-cherry-blossoms-part-two.webp&quot; &#x2F;&gt;
&lt;p&gt;Found via &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.reddit.com&#x2F;r&#x2F;Portland&#x2F;comments&#x2F;tof4vm&#x2F;last_weekend_of_full_cherry_blossoms&#x2F;&quot;&gt;this Reddit post&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;hr style=&quot;clear: both;&quot; &#x2F;&gt;
&lt;h2 id=&quot;deep-dream-rainbow&quot;&gt;Deep dream rainbow&lt;&#x2F;h2&gt;
&lt;div style=&quot;display: flex; flex-direction: row; width: 100%&quot;&gt;&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content;  height: 200px; background: #58C751&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #100B1A&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #D74F48&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #D57D34&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #45B97E&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #D9C748&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #4C3FA8&quot;&gt;&lt;&#x2F;div&gt;
&lt;div style=&quot;flex: fit-content; width: fit-content; flex-grow: 1; flex-shrink: 1; flex-basis: fit-content; height: 200px; background: #146992&quot;&gt;&lt;&#x2F;div&gt;&lt;&#x2F;div&gt;
&lt;img style=&quot;max-width: 100%;&quot; src=&quot;https:&#x2F;&#x2F;www.neversaw.us&#x2F;palettes&#x2F;deep-dream-rainbow.jpg&quot; &#x2F;&gt;
&lt;p&gt;Found via &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;mobile.twitter.com&#x2F;ParkerMolloy&#x2F;status&#x2F;1508165079598043139&#x2F;photo&#x2F;3&quot;&gt;this Tweet&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;hr style=&quot;clear: both;&quot; &#x2F;&gt;
</description>
      </item>
      <item>
          <title>The Canvas Cares Not</title>
          <pubDate>Sun, 30 Jan 2022 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://www.neversaw.us/2022/01/30/the-canvas-cares-not/</link>
          <guid>https://www.neversaw.us/2022/01/30/the-canvas-cares-not/</guid>
          <description xml:base="https://www.neversaw.us/2022/01/30/the-canvas-cares-not/">&lt;h1 id=&quot;the-canvas-cares-not&quot;&gt;The Canvas Cares Not&lt;&#x2F;h1&gt;
&lt;p&gt;Computers don’t care how programs are structured. Businesses don’t care how
systems are architected. The canvas does not care how paint is applied.
Software engineering is an art.&lt;&#x2F;p&gt;
&lt;p&gt;Software engineering is also a culture of artists; despite that, we recoil at
being called “artists.” Art has no right answers: a work of art means something
different to everyone who receives it. Software engineering denies that it is
an art form, which leads to a deep-seated intellectual insecurity. It
fetishizes science.&lt;&#x2F;p&gt;
&lt;p&gt;Until we come to terms with the reality of the profession, we delude ourselves.
Our output, our programs, our systems suffer for our deliberate
misunderstanding. What’s more, in our pursuit of the trappings of science, we
inflict suffering on one another needlessly.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;a-front-row-seat-at-the-best-art-awards&quot;&gt;A Front-Row Seat at the “Best Art” Awards&lt;&#x2F;h2&gt;
&lt;p&gt;First, art. Why do I say software engineering is art? Art is communication:
between people, between the artist’s past self and present self, between the
author and the audience. Music is art, prose is art, cooking is art,
architecture is art.&lt;&#x2F;p&gt;
&lt;p&gt;Art is forever imperfect. It leans on shared context. Art is always “in
reaction to” itself: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Infinite_regress&quot;&gt;an infinite regress&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Software engineering culturally focuses on the utilitarian byproducts of art:
the food the cooking produced, the building the people live in, the album the
musician pressed; we are obsessed with the utility produced while we ignore the
aesthetic involved.&lt;&#x2F;p&gt;
&lt;p&gt;Aesthetics are, broadly, the values we bring to art: they’re how we decide what
is “good art” and what is “bad art.” The concepts of “bad” and “good” are
personal, not universal: it is entirely reasonable for two people to disgree
about whether a book is bad, or whether an API is overengineered.&lt;&#x2F;p&gt;
&lt;p&gt;The art of software engineering is the voice of the engineers behind the code.
The communication of the history of the system, the decisions made and options
weighed. Every single engineer has different tastes, different aesthetic
values, a different voice.&lt;&#x2F;p&gt;
&lt;p&gt;Focusing solely on the utility that we produce ignores the fact that we &lt;em&gt;have&lt;&#x2F;em&gt;
tastes — that we have &lt;strong&gt;a voice&lt;&#x2F;strong&gt;. We are, in fact, explicitly in the
practice of pretending we &lt;em&gt;don’t&lt;&#x2F;em&gt;: we commonly defend our taste by lashing it
crudely to quantifiable, universal truths. It is not enough to simply dislike
leaving semicolons out of your JavaScript, it has to go hand in hand with the
claim that “automatic semicolon insertion leans on error-correction code in the
parser, and is thus a program that does not include semicolons is &lt;em&gt;less
technically correct&lt;&#x2F;em&gt; than a program that includes semicolons.” It’s a tenuous
conclusion; one that leaves no room for people who &lt;em&gt;don’t&lt;&#x2F;em&gt; like semicolons to
be right. And yet people of both tastes write programs successfully every day.&lt;&#x2F;p&gt;
&lt;p&gt;There is no such thing as a universal “best tool for the job” because our job
is &lt;em&gt;to communicate&lt;&#x2F;em&gt;. There exists no meaningful award for “best art” because,
as a form of communication, art is intrinsically subjective. So it is with
programming.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;a-zero-sum-game&quot;&gt;A Zero-Sum Game&lt;&#x2F;h2&gt;
&lt;p&gt;Software engineering is, as a culture, intellectually insecure.&lt;&#x2F;p&gt;
&lt;p&gt;We hold technologies in our periphery with some imagined faint praise or
damnation.&lt;&#x2F;p&gt;
&lt;p&gt;We hold technologies in our direct line of sight with some self-assessed
— but again, imagined — level of expertise, while we gloss over
their essential complexity.&lt;&#x2F;p&gt;
&lt;p&gt;We imagine that our grasp of complex systems and topics grants us universal
insight across all complex systems. We generalize prematurely. We pattern-match
like a cheese grater, dragging complex ideas across the plane of our
understanding until they come through the other side misshapen.&lt;&#x2F;p&gt;
&lt;p&gt;To some degree we do all of these things because we are human. But we make the
mistake of thinking that we are special humans. That we are on one end of the
“bell curve of intelligence”, as if such an abstract concept could ever
honestly be made concrete (don’t @ me about IQ tests, they’re bullshit.)&lt;&#x2F;p&gt;
&lt;p&gt;We’re told we are the smartest and the best and that we should seek to work
&lt;em&gt;only with&lt;&#x2F;em&gt; the smartest and the best, but:&lt;&#x2F;p&gt;
&lt;p&gt;We &lt;strong&gt;don’t&lt;&#x2F;strong&gt; know everything and we’re &lt;strong&gt;constantly&lt;&#x2F;strong&gt; reminded of just how
average we are; just how small our understanding is. And if our understanding
is small, then maybe we aren’t the smartest and best. And if we’re not the
smartest and best, then no one wants to work with us. If no one wants to work
with us, well, then, shelter and food are going to be a problem.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.goodreads.com&#x2F;quotes&#x2F;21810-it-is-difficult-to-get-a-man-to-understand-something&quot;&gt;It is far easier to react defensively to that insecurity than to embrace it.&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;What makes us so rigid? Who told us to be this way?&lt;&#x2F;p&gt;
&lt;p&gt;Software engineering is art, yes, but it’s also a job. The utility of our work
attracts capital, and capitalists have have found it useful to tell us how
great we are. Probably because it makes us turn a blind eye to the
externalities of the systems we produce.&lt;&#x2F;p&gt;
&lt;p&gt;Because the utility of the systems we produce is the sole focus of capital
— our sole value to business — we are systemically encouraged to
&lt;em&gt;avoid&lt;&#x2F;em&gt; thinking of ourselves as artists, to &lt;em&gt;recoil&lt;&#x2F;em&gt; from the thought of
having aesthetics.&lt;&#x2F;p&gt;
&lt;p&gt;Developers internalize this conflict: we have druthers, preferences, etc., but
we’re told that we shouldn’t. Because we shouldn’t have anything as silly as “a
preference about semicolons”, we try to rationalize it by picking some concrete
truth and lashing our foibles to it. We’re sandbagging our opinions both from
each other and ourselves.&lt;&#x2F;p&gt;
&lt;p&gt;And so, as a rule, we’re insecure.&lt;&#x2F;p&gt;
&lt;p&gt;As a result, we’re constantly fighting both for and against our aesthetics and
for and against the aesthetics of others. And our desire to continue drawing a
salary prevents us from embracing the simple fact that we even &lt;em&gt;have&lt;&#x2F;em&gt;
aesthetics in the first place. We seek to quantify our aesthetics, to ground
them in universal truth: “For my expression to be be valid, all alternatives
must be invalid.” A zero-sum game.&lt;&#x2F;p&gt;
&lt;p&gt;We get in our own way. We get in each other’s way.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;a-successful-hire&quot;&gt;A Successful Hire&lt;&#x2F;h2&gt;
&lt;p&gt;It’s no wonder that the state of technical interviews is so abysmal.&lt;&#x2F;p&gt;
&lt;p&gt;Technical interviews are a coarse values compatibility test between the
interviewee and representatives from the hiring team. Ideally, this catches
things like “does your preferred communication style match that of the team?”,
“how best do you learn and is the team suited to support that mode?”, among
similar questions.&lt;&#x2F;p&gt;
&lt;p&gt;However.&lt;&#x2F;p&gt;
&lt;p&gt;Because of the deep-seated insecurity of engineering at large, interviews are
often a form of &lt;strong&gt;earning cachet&lt;&#x2F;strong&gt; with the existing team. In the worst case,
this looks like answering “gotcha questions”, whiteboarding, and
regurgitating trivia. Hazing, in other words.&lt;&#x2F;p&gt;
&lt;p&gt;Why do I say “worst case” when it’s so widespread? Consider: it is common
practice for most engineering managers to have some amount of programming
background; thus those most frequently responsible for screening candidates
ahead of technical interviews &lt;em&gt;can already tell&lt;&#x2F;em&gt; if the candidate &lt;em&gt;knows how to
program or not&lt;&#x2F;em&gt;. Any discussion of “can the candidate program up to the quality
level of the organization” can be linked directly or thematically back to &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=wTgQ2PBiz-g&quot;&gt;“‘A’
players only want to work with ‘A’ players”&lt;&#x2F;a&gt;, which &lt;em&gt;is generally
misunderstood to mean&lt;&#x2F;em&gt; “this candidate shares my aesthetics.” A gentle thump on
the offending interviewer’s head may be dispensed by the hiring manager.&lt;&#x2F;p&gt;
&lt;p&gt;New hires bring in their own opinions, values, &amp;amp; aesthetics.&lt;&#x2F;p&gt;
&lt;p&gt;A successful hire &lt;strong&gt;always&lt;&#x2F;strong&gt; changes the values of the team that they join; and
in turn the team &lt;strong&gt;always&lt;&#x2F;strong&gt; changes the values of the person that they hire.&lt;&#x2F;p&gt;
&lt;p&gt;The weight of the change — whether it tilts in favor of the team or the
hire — depends on the experience of the hire and the role they are being
hired into, but it NEVER goes to zero on either side. (If either side remains
unchanged, it wasn’t a successful hire: they were most likely shuffled onto
another team or fired.)&lt;&#x2F;p&gt;
&lt;p&gt;Now, keep in mind: capital &lt;em&gt;wants&lt;&#x2F;em&gt; fungible engineers. They’re focused
solely on the utility we produce. From that frame, the conflict &amp;amp;
compromise of a team’s aesthetic values is a bug, not a feature. But they
couldn’t be more wrong: the primary value in hiring a new engineer is not
simply “increasing parallelism of work”, but “expanding the artistic scope of
the team.”&lt;&#x2F;p&gt;
&lt;p&gt;Invention happens because of unexpected connections; art is improved by
resolving constructive conflict and integrating feedback. But if you leave that
conflict unresolved — if our field is so stunted as to believe the conflict
&lt;em&gt;shouldn’t exist&lt;&#x2F;em&gt; — you merely end up with a team in discord.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;concede-the-point&quot;&gt;Concede the Point&lt;&#x2F;h2&gt;
&lt;p&gt;When aesthetic conflict can only be resolved by quantifiable arguments grounded
in utility or universal fact, the result is tenuous rationalization of
aesthetics. In other words, a team in this state &lt;em&gt;lacks the means&lt;&#x2F;em&gt; to resolve
the conflict constructively.&lt;&#x2F;p&gt;
&lt;p&gt;This gives rise to bad behaviors:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Argument to exhaustion: whoever argues the longest for their point wins.&lt;&#x2F;li&gt;
&lt;li&gt;Oil and water: different parts of the system are built based on increasingly
different aesthetic principles. The engineers involved “agree to disagree”,
so the conflict gets pushed into the interface between their two systems.&lt;&#x2F;li&gt;
&lt;li&gt;Disingenuous arguments (or sandbagging): coming up with a solution and
constructing arguments to support it instead of investigating a problem
space, eroding trust.&lt;&#x2F;li&gt;
&lt;li&gt;Appeal to the wisdom of the crowd: “everyone is using
&lt;code&gt;$FRAMEWORK_OR_PROCESS&lt;&#x2F;code&gt;, so it must be the right answer for us as well.” This
ignores the context of the team, who may not be in agreement with the
practice.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Teams in discord are not stable. Unresolved conflict will show up in the system
they produce. &lt;em&gt;Ignoring the aesthetic of the team threatens the utility they
produce.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The core of the problem is that, absent a means to talk about their personal
desires &amp;amp; values for the solution, engineers “argue to win”. The starting point
of the argument is disingenuous, &amp;amp; they do not feel they can admit to their
aesthetics because it would concede the point.&lt;&#x2F;p&gt;
&lt;p&gt;By way of comparison, a healthy team respects the tastes of its members, which
lets them talk about them openly when faced with a problem. Conflicts can be
resolved constructively by surfacing the values behind them.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;borrow-these-values&quot;&gt;Borrow These Values&lt;&#x2F;h2&gt;
&lt;p&gt;Art is, as previously established, always in reaction to itself. It is subject
to fads: a technique, thought process, or organizational principle sparks the
imagination of a large number of artists at once. The fad might propose a novel
solution to long-standing problems, reframe the art in a fresh way, or simply
resurface an old technique for a new generation. Fads create a vacuum, a new
space to explore in the art.&lt;&#x2F;p&gt;
&lt;p&gt;Invariably fads die out, either being subsumed into the practice completely or
being replaced by new trends. They become contextualized, contained,
understood. Penning them in extinguishes the initial enthusiasm that propelled
them to popularity. You don’t see a lot of art that centers pointillism these
days. The fad has been explored and it no longer captures the imagination.
There’s just no point in focusing on it anymore.&lt;&#x2F;p&gt;
&lt;p&gt;Much like visual media, software engineering experiences fads of execution and
fads of process. Fads of execution center a technique, a tool: for the web, the
2010’s were about JavaScript frameworks: React, Angular, Ember. Fads of
process, by contrast, center an organizing principle: “we should act as Site
Reliability Engineers!”&lt;&#x2F;p&gt;
&lt;p&gt;Fads are a good thing in moderation. They expand the borders of the art. Long
after their demise, the lessons learned still resonate and inform future
artists. Fads, however, can produce zealotry: it’s tempting to believe that
“we’ve finally figured out the art! It is the end of history!” The fad can live
forever, becoming synonymous with the art itself.&lt;&#x2F;p&gt;
&lt;p&gt;Software engineering is fertile ground for such zeal. Fads in this field live a
charmed life: we call them “best practices.” They’re dumped on teams, with the
expectation that the team’s output will improve. Agile, scrum, devops, SRE,
React, Node, matrix orgs, the Spotify model, Rails, Web 2.0! All fads.&lt;&#x2F;p&gt;
&lt;p&gt;When the team’s productivity is down and your back is to the wall, there’s a
pressure to find a magic bullet. A process or tool that worked for some other
team. Not your team – a famous team, a successful team. After all, engineers
ought to be fungible, right?&lt;&#x2F;p&gt;
&lt;p&gt;But all of these tools and processes are shaped by the aesthetic values of the
teams that originated them. You can borrow these values, but they’ll always fit
a little like hand-me-downs: a little uncomfortably. Your team is not Google.
You may not be able to afford Google’s values: Google has a money printer,
after all.&lt;&#x2F;p&gt;
&lt;p&gt;Your team needs to find its own voice. “Best practices” are the start of that
work, not the end.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;finding-one-s-voice&quot;&gt;Finding One’s Voice&lt;&#x2F;h2&gt;
&lt;p&gt;First, &lt;strong&gt;release the idea that it is possible to be right about software
engineering.&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Second, I am going to quote John Gardner’s “The Art of Fiction”, which is as
applicable to fabulists as it is to software engineers:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;[…] in order to achieve mastery [they] must &lt;strong&gt;read widely and deeply&lt;&#x2F;strong&gt; and must
write not just carefully but continually, thoughtfully assessing and
reassessing what [they] write, because practice, for the writer as for the
concert pianist, is &lt;strong&gt;the heart of the matter&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Practice, practice, practice. There are no silver bullets. Read lots of code,
write lots of code, try out different approaches, see what speaks to you.
Discard the rest.&lt;&#x2F;p&gt;
&lt;p&gt;Finally: I am going to give you the scariest bit of advice. In order to work
well with others, you &lt;em&gt;must be vulnerable&lt;&#x2F;em&gt;. Admit that your tastes are &lt;em&gt;your
tastes&lt;&#x2F;em&gt;. Concede the ground of universal truth; it was never yours to begin
with.&lt;&#x2F;p&gt;
&lt;p&gt;Read old code together; react honestly when you find code that violates your
values, but know that what you read &lt;em&gt;isn’t wrong&lt;&#x2F;em&gt;, it merely offends you. There
may be entirely valid reasons for it to be written the way it is! Build trust
with your colleagues by demonstrating that you are willing to give authors the
benefit of the doubt. Your colleagues can connect the dots: how you talk about
code when the author’s not around extends to how you talk about &lt;em&gt;their&lt;&#x2F;em&gt; code
when &lt;em&gt;they’re&lt;&#x2F;em&gt; not around.&lt;&#x2F;p&gt;
&lt;p&gt;Let your teammates see that you value &lt;em&gt;their&lt;&#x2F;em&gt; aesthetics. Invite them to
inspect and adjust your values when you start a project. If you accommodate
them, they are more likely to accommodate you. Expose your values and thinking
whenever you go to solve a problem. Accept feedback graciously, and make sure
you give credit when acting on it.&lt;&#x2F;p&gt;
&lt;p&gt;This profession doesn’t need to be a zero-sum game. Treat it like an art,
respect your colleagues as fellow artists, and practice it together.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h3 id=&quot;thanks&quot;&gt;Thanks!&lt;&#x2F;h3&gt;
&lt;p&gt;Thanks &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;ceejbot&#x2F;&quot;&gt;@ceejbot&lt;&#x2F;a&gt; and
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;jefflembeck&#x2F;&quot;&gt;@jefflembeck&lt;&#x2F;a&gt; for reviewing drafts of this
post.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>SSH to Cloud Managed Servers</title>
          <pubDate>Sat, 22 Jan 2022 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://www.neversaw.us/2022/01/22/ssh-proxycommand/</link>
          <guid>https://www.neversaw.us/2022/01/22/ssh-proxycommand/</guid>
          <description xml:base="https://www.neversaw.us/2022/01/22/ssh-proxycommand/">&lt;h1 id=&quot;using-proxycommand-to-ssh-to-cloud-managed-servers&quot;&gt;Using ProxyCommand to SSH to Cloud Managed Servers&lt;&#x2F;h1&gt;
&lt;h2 id=&quot;problem-statement&quot;&gt;Problem Statement&lt;&#x2F;h2&gt;
&lt;p&gt;Given:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;You have a series of server instances: something like an AWS Autoscaling Group (or “ASG”).&lt;&#x2F;li&gt;
&lt;li&gt;These groups are named in a regular pattern: &lt;code&gt;environment-service&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;You don’t necessarily have a stable set of IP addresses to SSH into.&lt;&#x2F;li&gt;
&lt;li&gt;Your instances are attached to a private network.&lt;&#x2F;li&gt;
&lt;li&gt;You have a well-known bastion server with SSH access.&lt;&#x2F;li&gt;
&lt;li&gt;You don’t want to use AWS Secure Session Manager, or their equivalent (for whatever reason!)&lt;&#x2F;li&gt;
&lt;li&gt;You have &lt;code&gt;jq&lt;&#x2F;code&gt; installed.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;You wish to be able to SSH to an ASG-managed instance without knowing the IP address ahead of time.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;solution&quot;&gt;Solution&lt;&#x2F;h2&gt;
&lt;p&gt;These steps enable you to run &lt;code&gt;ssh myuser@myhosts.environment.service&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;.ssh&#x2F;config&lt;&#x2F;code&gt; host aliases to capture an autoscaling group name.&lt;&#x2F;li&gt;
&lt;li&gt;Point that host alias at a &lt;code&gt;ProxyCommand&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;The &lt;code&gt;ProxyCommand&lt;&#x2F;code&gt; script receives two arguments: the user-specified host and the port (See Fig. 1)&lt;&#x2F;li&gt;
&lt;li&gt;The script removes the host alias prefix (&lt;code&gt;myhosts.&lt;&#x2F;code&gt;), extracts the environment, service name, and
(optional) instance index into variables (See Fig. 2, section 1)&lt;&#x2F;li&gt;
&lt;li&gt;The script uses a command line interface with your cloud provider to list instances for that
autoscaling group and select an instance by the requested index (See Fig. 2, section 2.)&lt;&#x2F;li&gt;
&lt;li&gt;Then the script retrieves private IP information for that instance. (See Fig. 2, section 3.)&lt;&#x2F;li&gt;
&lt;li&gt;Finally, we connect to the target instance through a jumpbox.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;figures&quot;&gt;Figures&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;strong&gt;Figure 1:&lt;&#x2F;strong&gt; An SSH config with &lt;code&gt;ProxyCommand&lt;&#x2F;code&gt; inserted:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D3C6AA; background-color: #2D353B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Host myhosts.*&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ProxyCommand &#x2F;path&#x2F;to&#x2F;proxy-command-script %h %p&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ForwardAgent yes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;Figure 2:&lt;&#x2F;strong&gt; An example proxy command:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D3C6AA; background-color: #2D353B;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #859289;font-style: italic;&quot;&gt;#!&#x2F;bin&#x2F;bash&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #859289;font-style: italic;&quot;&gt;# if necessary!&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DBBC7F;&quot;&gt;source path&#x2F;to&#x2F;some&#x2F;credentials&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #859289;font-style: italic;&quot;&gt;# Section 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;target&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E69875;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;${1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E69875;&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D699B6;&quot;&gt;myhosts&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt;\.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E69875;&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;environment&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E69875;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;$(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DBBC7F;&quot;&gt;echo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D699B6;&quot;&gt; $target&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E69875;&quot;&gt; |&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt; cut&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DBBC7F;&quot;&gt; -d&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt;&amp;#39;.&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DBBC7F;&quot;&gt; -f1&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;service&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E69875;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;$(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DBBC7F;&quot;&gt;echo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D699B6;&quot;&gt; $target&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E69875;&quot;&gt; |&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt; cut&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DBBC7F;&quot;&gt; -d&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt;&amp;#39;.&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DBBC7F;&quot;&gt; -f2&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;num&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E69875;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;$(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DBBC7F;&quot;&gt;echo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D699B6;&quot;&gt; $target&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E69875;&quot;&gt; |&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt; cut&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DBBC7F;&quot;&gt; -d&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt;&amp;#39;.&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DBBC7F;&quot;&gt; -f3&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;num&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E69875;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D699B6;&quot;&gt;${num&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E69875;&quot;&gt;:-&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D699B6;&quot;&gt;0}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #859289;font-style: italic;&quot;&gt;# Section 2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;autoScalingGroup&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E69875;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;$(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt;  aws&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DBBC7F;&quot;&gt; autoscaling describe-auto-scaling-groups --output json&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E69875;&quot;&gt; |&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt;  jq&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DBBC7F;&quot;&gt; -r&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt; &amp;#39;.AutoScalingGroups[] |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt;  select( .AutoScalingGroupName == &amp;quot;&amp;#39;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D699B6;&quot;&gt;${environment}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D699B6;&quot;&gt;${service}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt;&amp;quot;&amp;#39;&amp;quot; ) |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt;  .Instances[].InstanceId&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E69875;&quot;&gt; |&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt;  sort&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E67E80;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D699B6;&quot;&gt; ${&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E69875;&quot;&gt;#&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D699B6;&quot;&gt;autoScalingGroup}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E69875;&quot;&gt; -lt&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D699B6;&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span&gt; ];&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E67E80;&quot;&gt; then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E69875;&quot;&gt;  &amp;gt;&amp;amp;2&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DBBC7F;&quot;&gt; echo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt; &amp;quot;Autoscaling group \&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;$1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt;\&amp;quot; not found or empty&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DBBC7F;&quot;&gt;  exit&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D699B6;&quot;&gt; 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E67E80;&quot;&gt;fi&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;instance&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E69875;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;$(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DBBC7F;&quot;&gt;echo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D699B6;&quot;&gt; ${autoScalingGroup}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E69875;&quot;&gt; |&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt; head&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DBBC7F;&quot;&gt; -n&lt;&#x2F;span&gt;&lt;span&gt;$((&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt;num&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DBBC7F;&quot;&gt; +&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D699B6;&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span&gt;))&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E69875;&quot;&gt; |&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt; tail&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DBBC7F;&quot;&gt; -n1&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E67E80;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E69875;&quot;&gt; -z&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D699B6;&quot;&gt;$instance&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; ];&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E67E80;&quot;&gt; then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E69875;&quot;&gt;  &amp;gt;&amp;amp;2&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DBBC7F;&quot;&gt; echo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt; &amp;quot;Could not find server by index \&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D699B6;&quot;&gt;$num&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt;\&amp;quot;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DBBC7F;&quot;&gt;  exit&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D699B6;&quot;&gt; 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E67E80;&quot;&gt;fi&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #859289;font-style: italic;&quot;&gt;# Section 3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ip&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E69875;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;$(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt;  aws&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DBBC7F;&quot;&gt; ec2 describe-instances --instance-id&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D699B6;&quot;&gt;$instance&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DBBC7F;&quot;&gt; --output json&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E69875;&quot;&gt; |&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt;  jq&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DBBC7F;&quot;&gt; -r&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt; &amp;#39;.Reservations[].Instances[] | .PrivateIpAddress&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E67E80;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E69875;&quot;&gt; -z&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D699B6;&quot;&gt;$ip&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; ];&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E67E80;&quot;&gt; then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E69875;&quot;&gt;  &amp;gt;&amp;amp;2&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DBBC7F;&quot;&gt; echo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt; &amp;quot;Could not find ip of instance \&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D699B6;&quot;&gt;$instance&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt;\&amp;quot;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DBBC7F;&quot;&gt;  exit&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D699B6;&quot;&gt; 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E67E80;&quot;&gt;fi&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #859289;font-style: italic;&quot;&gt;# Section 4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt;ssh&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DBBC7F;&quot;&gt; -q ubuntu@jumpbox.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D699B6;&quot;&gt;$environment&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DBBC7F;&quot;&gt;.example.com -W&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D699B6;&quot;&gt; $ip&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DBBC7F;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt;$2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;</description>
      </item>
      <item>
          <title>My Note-Taking Setup</title>
          <pubDate>Tue, 27 Apr 2021 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://www.neversaw.us/2021/04/27/my-notetaking-setup/</link>
          <guid>https://www.neversaw.us/2021/04/27/my-notetaking-setup/</guid>
          <description xml:base="https://www.neversaw.us/2021/04/27/my-notetaking-setup/">&lt;h1 id=&quot;my-notetaking-setup&quot;&gt;My Notetaking Setup&lt;&#x2F;h1&gt;
&lt;p&gt;A quick update today because &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;mobile.twitter.com&#x2F;trevorbrindlejs&#x2F;status&#x2F;1387053209697460224&quot;&gt;this tweet&lt;&#x2F;a&gt; reminded me that I wanted
to talk briefly about my notetaking setup. I recently streamlined
my notetaking tools after living with them for about two years(!)&lt;&#x2F;p&gt;
&lt;p&gt;The problem statement I started from is:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;I primarily work in a terminal with a vim session inside,&lt;&#x2F;li&gt;
&lt;li&gt;I have two laptops across which I wish to share notes,&lt;&#x2F;li&gt;
&lt;li&gt;I experience process as friction (so &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;zettelkasten.de&#x2F;&quot;&gt;Zettelkasten&lt;&#x2F;a&gt; and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;bulletjournal.com&#x2F;&quot;&gt;Bullet
Journaling&lt;&#x2F;a&gt; are right out),&lt;&#x2F;li&gt;
&lt;li&gt;I find myself needing to refer back to notes via distant memory,&lt;&#x2F;li&gt;
&lt;li&gt;I write notes more often than I read them,&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;&lt;strong&gt;Given this, I want to keep searchable notes about work, life, and research
with as little friction as possible.&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The system I use is a slight refinement of a previously unregarded group of
behaviors! I used to take notes in an editor in any directory I happened to be
in. As a result, I had a pile of unordered, untitled notes files in my &lt;code&gt;$HOME&lt;&#x2F;code&gt;
directory. Whenever I switched computers, I’d lose all of my notes. Even on a
single computer, &lt;em&gt;finding&lt;&#x2F;em&gt; a note I had previously written was fairly
impossible.&lt;&#x2F;p&gt;
&lt;p&gt;It wasn’t all bad, though: the act of writing notes was valuable in and of
itself in helping me retain thoughts, and – maybe more importantly – it was
the &lt;em&gt;seed&lt;&#x2F;em&gt; of a habit which I could spin in a more useful direction. In a
sense, I had handled the first point of my problem statement already!&lt;&#x2F;p&gt;
&lt;p&gt;Two years ago, I collected all of my notes, meticulously adding titles and
modified times from the files themselves, then moved them into a &lt;code&gt;~&#x2F;notes&lt;&#x2F;code&gt;
directory. I symlinked this directory to DropBox on both of my laptops.
Success! I crossed off &lt;strong&gt;point 2&lt;&#x2F;strong&gt;. There was a little added process: note
filenames now started with a &lt;code&gt;YYYYMMDD-&lt;&#x2F;code&gt; timestamp to give them an unambiguous
sort order.&lt;&#x2F;p&gt;
&lt;p&gt;This, however, added process. The process was “look up the date, then run &lt;code&gt;vim ~&#x2F;notes&#x2F;20080808-chomp-womp.md&lt;&#x2F;code&gt;” to take a note. Even &lt;em&gt;that&lt;&#x2F;em&gt; amount of added
process itched, so a couple of weeks ago, I wrote a little &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;chrisdickinson&#x2F;06f4fbef686c1959de174758497a7b2a&quot;&gt;script&lt;&#x2F;a&gt; to take
notes. (I wrote it in Bash, &lt;a href=&quot;https:&#x2F;&#x2F;www.neversaw.us&#x2F;2021&#x2F;04&#x2F;02&#x2F;the-case-for-bash&#x2F;&quot;&gt;to no-one’s surprise&lt;&#x2F;a&gt;.) This crossed off
&lt;strong&gt;point 3&lt;&#x2F;strong&gt;. I integrated &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;junegunn&#x2F;fzf#readme&quot;&gt;&lt;code&gt;fzf&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ggreer&#x2F;the_silver_searcher#readme&quot;&gt;&lt;code&gt;ag&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; into the script so now I can run:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D3C6AA; background-color: #2D353B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ note search &amp;#39;some term&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;To bring up a fuzzyfinder window with just the matching notes. If only one note
matches, it’ll open in &lt;code&gt;$EDITOR&lt;&#x2F;code&gt; instead. Inside fuzzyfinder I can select
multiple notes to open in &lt;code&gt;vim&lt;&#x2F;code&gt; tabs.&lt;&#x2F;p&gt;
&lt;p&gt;I can also run &lt;code&gt;note last&lt;&#x2F;code&gt; to open up the last note I took. Finally, running
&lt;code&gt;note&lt;&#x2F;code&gt; with no arguments opens an &lt;code&gt;$EDITOR&lt;&#x2F;code&gt; window and lets me enter freeform
text. It takes the first line, slugifies it, and places it in the &lt;code&gt;~&#x2F;notes&lt;&#x2F;code&gt; dir
with an appropriate name. Combined, those features tackle &lt;strong&gt;points 4 and 5&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;I’ve been fairly happy with the results: I’ve taken more notes and been less
tempted to combine unrelated notes into a single document. The thing I’d want
you to take away from this is not that you should use &lt;em&gt;my&lt;&#x2F;em&gt; note-taking system,
but that having &lt;em&gt;any&lt;&#x2F;em&gt; note-taking system is useful. (Also, look for places in
your life where you’re experiencing friction and try to formulate a problem
statement! You’ll be happier with solutions that are tied to a tightly-defined
problem!)&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>the case for bash</title>
          <pubDate>Fri, 02 Apr 2021 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://www.neversaw.us/2021/04/02/the-case-for-bash/</link>
          <guid>https://www.neversaw.us/2021/04/02/the-case-for-bash/</guid>
          <description xml:base="https://www.neversaw.us/2021/04/02/the-case-for-bash/">&lt;h1 id=&quot;the-case-for-bash&quot;&gt;The Case For Bash&lt;&#x2F;h1&gt;
&lt;p&gt;&lt;small&gt;&lt;code&gt;esac&lt;&#x2F;code&gt;&lt;&#x2F;small&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Friends, coders, I come not to praise bash, but to contextualize
it.&lt;&#x2F;p&gt;
&lt;p&gt;Bash is oft-maligned: you hear it sneered at in sentences like “our continuous
integration pipeline is just a &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;mobile.twitter.com&#x2F;search?q=%22pile+of+bash+scripts%22&quot;&gt;pile of bash scripts&lt;&#x2F;a&gt;.” It is commonly
regarded as unintelligible and thus unmaintainable. The pile of bash scripts
are the toxic byproduct of an infrastructure team understaffed, pressed for
time, unwilling or unable to do it “the right way” in a blessed programming
language, such as Ruby, Python, or, uh, … YAML?&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;some problems with bash:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;It’s a weird &amp;amp; counterintuitive language&lt;&#x2F;li&gt;
&lt;li&gt;you probably don’t need to write it that often, so you don’t practice&lt;&#x2F;li&gt;
&lt;li&gt;the times you DO need to use it, it’s often because something important
(like a build) broke and it needs to be fixed RIGHT NOW&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;– Julia Evans, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;b0rk&quot;&gt;@b0rk&lt;&#x2F;a&gt;, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;b0rk&#x2F;status&#x2F;1337953874309754880&quot;&gt;via tweet&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Julia has a a &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;wizardzines.com&#x2F;zines&#x2F;bite-size-bash&#x2F;&quot;&gt;great zine&lt;&#x2F;a&gt; that will get you comfortable with Bash. I’m not
going to try to do that in this post! Instead, I’m going to try to convince you
why it’s &lt;em&gt;worth&lt;&#x2F;em&gt; learning Bash. To do that, I’m going to talk about the problem
space that Bash thrives in, and why other languages are a bad fit for that same
space.&lt;&#x2F;p&gt;
&lt;p&gt;So, about problem spaces and languages. You might be familiar with the idea
that any language with &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;wiki.c2.com&#x2F;?TuringEquivalent&quot;&gt;sufficient flow-control primitives&lt;&#x2F;a&gt; can express
the same algorithm that any other language of that class can express. In other
words, given access to the same system APIs, the same approach to solving a
problem could be expressed in Java, Ruby, or Bash. By comparison to art, if you
had to render an image of the inky blackness of outer space, you could
accomplish it with pen and ink or with a flat brush and paint. One approach
will save you a lot of time (and wrist problems!)&lt;&#x2F;p&gt;
&lt;p&gt;This is to state by example: certain tools are better adapted to certain
problems. You, as a programmer, are likely to run into a wide range of problems
requiring a corsucating variety of problem-solving approaches in your career.
The first, best tool that we can bring to bear on the problems before us is
&lt;strong&gt;language&lt;&#x2F;strong&gt;, and thankfully we have a variety from which to choose.&lt;&#x2F;p&gt;
&lt;p&gt;Languages lend themselves to solving a subset of the problems you’re likely to
encounter. When selecting a language to fill a particular niche in your
toolset, there are a number of considerations: performance, popularity,
ubiquity, familiarity, capability, amongst others. Languages will overlap
niches: C, C++, Java, Go, and Rust are good choices for problems where
performance is a primary concern. Python, JavaScript, and Ruby are excellent
multitools where performance isn’t a problem. All are popular languages with
active ecosystems. There is no universal correct answer, even amongst languages
with overlapping capabilities, because every language has different values that
suit different people.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;As a programmer, I think it behooves us to think about not just the values
that we hold, but the values of the people that use our software hold and, as
a programmer, you should use tools that align with your values.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;– &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.infoq.com&#x2F;presentations&#x2F;rust-tradeoffs&#x2F;&quot;&gt;“How Rust Views Tradeoffs”&lt;&#x2F;a&gt;, Steve Klabnik, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;steveklabnik&quot;&gt;@steveklabnik&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I haven’t talked about Bash yet.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;So, what does Bash value? One might be tempted to say “ubiquity”. Bash is
available nearly everywhere these days; but ubiquity is a quality that is
conferred from outside the language. Preserving ubiquity &lt;em&gt;can&lt;&#x2F;em&gt; be a value –
see JavaScript and backwards compatibility, or C and the PDP-11 – but it’s
difficult to positively &lt;em&gt;attain&lt;&#x2F;em&gt; ubiquity.&lt;&#x2F;p&gt;
&lt;p&gt;Instead, Bash values a &lt;em&gt;very&lt;&#x2F;em&gt; particular fitness for purpose: the management
and coordination of programs. This includes spawning processes, connecting
processes via pipelines, and parallelizing processes. The purpose of Bash is
&lt;em&gt;running other programs&lt;&#x2F;em&gt;. Consider the following:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D3C6AA; background-color: #2D353B;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt;tail&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DBBC7F;&quot;&gt; -q &#x2F;var&#x2F;log&#x2F;nginx&#x2F;access.log&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E69875;&quot;&gt; |&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt; awk &amp;#39;{print $7}&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E69875;&quot;&gt; |&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt; sort&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E69875;&quot;&gt; |&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt; uniq&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DBBC7F;&quot;&gt; -c&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E69875;&quot;&gt; |&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt; sort&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DBBC7F;&quot;&gt; -rn&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;“Follow the ngnix &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Common_Log_Format&quot;&gt;access log&lt;&#x2F;a&gt;; print the 7th word (the path); sort those
paths, count the number of unique instances, and then sort the results by
occurrence count.”&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D3C6AA; background-color: #2D353B;&quot;&gt;&lt;code data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E69875;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span&gt; { spawn }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E69875;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt; require&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DBBC7F;&quot;&gt;&amp;#39;child_process&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E69875;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span&gt; tail&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E69875;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt; spawn&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DBBC7F;&quot;&gt;&amp;#39;tail&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, [&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DBBC7F;&quot;&gt;&amp;#39;-q&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DBBC7F;&quot;&gt; &amp;#39;&#x2F;var&#x2F;log&#x2F;nginx&#x2F;access.log&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;])&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E69875;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span&gt; awk&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E69875;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt; spawn&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DBBC7F;&quot;&gt;&amp;#39;awk&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, [&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DBBC7F;&quot;&gt;&amp;#39;{print $7}&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;], {stdio&lt;&#x2F;span&gt;&lt;span style=&quot;color: #859289;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; [tail&lt;&#x2F;span&gt;&lt;span style=&quot;color: #859289;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;stdout,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DBBC7F;&quot;&gt; &amp;#39;inherit&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DBBC7F;&quot;&gt; &amp;#39;inherit&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;]})&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E69875;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span&gt; sort&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E69875;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt; spawn&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DBBC7F;&quot;&gt;&amp;#39;sort&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, [], {stdio&lt;&#x2F;span&gt;&lt;span style=&quot;color: #859289;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; [awk&lt;&#x2F;span&gt;&lt;span style=&quot;color: #859289;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;stdout,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DBBC7F;&quot;&gt; &amp;#39;inherit&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DBBC7F;&quot;&gt; &amp;#39;inherit&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;])&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #859289;font-style: italic;&quot;&gt;&#x2F;&#x2F; ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is a contrived example, but there’s a lot more &lt;em&gt;going on&lt;&#x2F;em&gt; in the Node
example than there is in the Bash one. The Python and Ruby versions would be
similar. The core data primitive of Bash is a &lt;em&gt;running process&lt;&#x2F;em&gt;. It has
distinct syntax for dealing with the input and output of those processes, for
capturing that output as a variable, and dealing with process exit conditions.
The boilerplate you’d type in another programming language is the &lt;em&gt;default&lt;&#x2F;em&gt; in
Bash.&lt;&#x2F;p&gt;
&lt;p&gt;It values running programs over assigning variables, over branching, over
everything. If you don’t believe me, consider that the common mode for &lt;code&gt;if&lt;&#x2F;code&gt;
statements in Bash is &lt;code&gt;if [ &amp;lt;test&amp;gt; ]; then &amp;lt;stmt&amp;gt;; fi&lt;&#x2F;code&gt;. Now go run &lt;code&gt;less &#x2F;bin&#x2F;[&lt;&#x2F;code&gt;. That’s right: &lt;code&gt;[&lt;&#x2F;code&gt; is a &lt;strong&gt;program&lt;&#x2F;strong&gt; being run by the &lt;code&gt;if&lt;&#x2F;code&gt; builtin.&lt;&#x2F;p&gt;
&lt;p&gt;Bash’s choices don’t make a lot of sense coming from other languages: &lt;code&gt;0&lt;&#x2F;code&gt; is
“true” or “success”, strings inside variables often need to be re-quoted on
use, the loop and conditional logic is off-the-wall; but it makes sense in
&lt;em&gt;context&lt;&#x2F;em&gt; of its values (and, well, history.)&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;It’s true that a lot of what I’ve said about Bash is equally true of other
shell scripting languages: Fish, Zsh, Powershell, and Nushell all value similar
things. It’s worth learning these languages! However, if you’re dealing with
Linux servers on a daily basis, it’s definitely worth learning Bash. Even if
you’re not, it’s worth learning just to understand what these other shell
scripting languages are reacting to. Bash’s &lt;code&gt;for&lt;&#x2F;code&gt; loops might be weird, but if
you can familiarize yourself with them, you can use that knowledge everywhere
from your personal laptop to a server running on AWS and back down to a shell
running on your local router.&lt;&#x2F;p&gt;
&lt;p&gt;You (can) use Bash every time you open a terminal session. This knowledge
compounds over time: you don’t have to learn the entire language to be more
efficient. You can layer in new concepts every few weeks and before you know
it, it’ll be muscle memory. Any time you’re presented with the need to write a
one-off program to accomplish a small task, take the opporunity to puzzle out
how to write it as a shell script. The difficulty of learning Bash is less in
learning the language itself, and more in identifying what programs you should
call to accomplish your goal. This is like any other language: finding the
right API and the right way to call it forms the bulk of day-to-day programming
effort. So, give it a whirl! Remember that there are &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;httpie.io&#x2F;&quot;&gt;alternatives&lt;&#x2F;a&gt; to tricky
APIs! If you do, you’ll have a valuable tool that fills a niche most other
popular programming languages struggle to address.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>context</title>
          <pubDate>Sat, 27 Mar 2021 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://www.neversaw.us/2021/03/27/context/</link>
          <guid>https://www.neversaw.us/2021/03/27/context/</guid>
          <description xml:base="https://www.neversaw.us/2021/03/27/context/">&lt;p&gt;I’ve heard it said that coding, as a skill, rewards those who have a high
tolerance for remembering lots of trivia.&lt;&#x2F;p&gt;
&lt;p&gt;Trivia, here, means “knowledge divorced from context”. That is, the sort of
thing you’d hear in a bar trivia game, such as “what year was Waterloo?” or
“what are the names of the active volcanoes around Portland?” The observation
is funny in a useful way: it subverts the image of programmers as magicians by
reframing it as a sort of stubborn tolerance for an unfortunate situation.
However, the important thing isn’t really the &lt;em&gt;volume&lt;&#x2F;em&gt; of trivia one can
memorize, but the desire to continually &lt;em&gt;contextualize&lt;&#x2F;em&gt; trivia both for oneself
and for others.&lt;&#x2F;p&gt;
&lt;p&gt;Contextualizing knowledge is tricky. We don’t help each other do it as much as
we should.&lt;&#x2F;p&gt;
&lt;p&gt;A professional StarCraft player, Sean Plott &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=TI9tUr-hiAs&amp;amp;t=930s&quot;&gt;said the following&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;I think one of the biggest things that irks me is when someone who’s trying
to teach me conflates the learning process with knowledge. Which is, “Sean,
in this situation, &lt;em&gt;you need to build X&lt;&#x2F;em&gt; because that counters their build.”&lt;&#x2F;p&gt;
&lt;p&gt;That is someone sharing a tidbit of knowledge, not considering &lt;em&gt;the sequence of
steps of learning that are necessary to even use that knowledge&lt;&#x2F;em&gt;, or what that
knowledge is sitting on top of.“&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Much of the craft of software engineering (&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;research.swtch.com&#x2F;vgo-eng#:~:Software%20engineering%20is%20what%20happens%20to%20programming&quot;&gt;AKA programming alongside other
programmers&lt;&#x2F;a&gt;) is about communicating knowledge &lt;em&gt;in
context&lt;&#x2F;em&gt; so that others may build a mental model of the program being developed.
The best programmers I’ve worked with recognize that &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pages.cs.wisc.edu&#x2F;~remzi&#x2F;Naur.pdf&quot;&gt;&lt;strong&gt;programming is theory
building&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt;, and so give great weight to leaving artifacts behind
that communicate meaningful context for their decisions. The aforelinked
author, Naur, makes a useful recommendation about what to communicate:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;That which helps the next programmer build an adequate theory of the
program&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Even so, it’s no small feat to identify all of the necessary context that
future readers might require, let alone to marshal it into natural language in
an easily understood fashion. As a profession, we’re terrifically bad at
sharing context. I care a lot about sharing adequate context! I know I’m
&lt;em&gt;still&lt;&#x2F;em&gt; bad at it, though. What can we do?&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Identify your audience. Are there gaps in your skills? A delta in your
experience levels? What might they not know that you are taking for granted? Be
gracious: you might misestimate them: apologize up front for retreading ground.
This is incredibly important when talking to folks early in their careers.&lt;&#x2F;p&gt;
&lt;p&gt;A brief aside: back in 2007, my first paying programming gig was maintaining a
college radio station website &amp;amp; DJ song log by myself. I was self-taught: a
feral &lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; programmer. I knew how to &lt;em&gt;program&lt;&#x2F;em&gt;, sure, but I didn’t know about
things you’d absolutely take for granted, like version control. As part of a
archival project, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;mobile.twitter.com&#x2F;rorypetty&quot;&gt;another programmer&lt;&#x2F;a&gt; came in to help digitize the station’s
vast CD and record collection &lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#2&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;. They had many suggestions that were, in
retrospect, incredibly insightful. At the time, though, I didn’t have the
necessary context to make that knowledge actionable. I pushed back on a lot of
it because I simply couldn’t understand it. I was &lt;em&gt;frustrated&lt;&#x2F;em&gt; and in turn I
was &lt;em&gt;frustrating&lt;&#x2F;em&gt;&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#3&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;I met up with that programmer a few years later, after I had some professional
programming experience under my belt. To my great surprise, so much of what
they said &lt;em&gt;made sense to me&lt;&#x2F;em&gt;. They had been clear this entire time: it wasn’t
them! &lt;em&gt;It was me!&lt;&#x2F;em&gt; Look out for these sorts of gaps. It’s not always so
pronounced: it might be that you’re talking to someone whose expertise is
simply in a different area.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;To some degree part of the problem particular to programming is that the solo
act involves considering many different courses of action and weighing their
outcomes.&lt;&#x2F;p&gt;
&lt;p&gt;That is, you spend time thinking about the problem before typing your
solution. One of the developmental stages commonly seen in programmers is to go
from working the solution out in the editor to thinking the problem through
before committing to typing it out. The more you practice simulating the
effects of edits ahead of making them, the more automatic it becomes! The more
automatic it becomes, the more efficient you become as a programmer. It’s a
virtuous cycle right up until another programmer joins you on the program.&lt;&#x2F;p&gt;
&lt;p&gt;In my experience, pair programming helps a ton here. Pairing forces both
programmers to verbalize the unconscious act of simulation [^4]. This can feel
like a terrible slog at first, but it’s useful on a number of levels:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;By talking through one’s thought process and deliberating on approaches in
tandem, the mental model is shared, reducing the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Bus_factor&quot;&gt;lottery factor&lt;&#x2F;a&gt; of the
program.&lt;&#x2F;li&gt;
&lt;li&gt;It’s a great way to share cognitive strategies &amp;amp; problem solving approaches
which are otherwise hard-won.&lt;&#x2F;li&gt;
&lt;li&gt;Verbalizing the process requires surfacing the unconscious process to conscious
examination. Flaws in thinking can be identified and fixed.&lt;&#x2F;li&gt;
&lt;li&gt;It builds rapport, which is key to maintaining a healthy social structure
around the program. Since the program will &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Conway%27s_law&quot;&gt;inevitably reflect&lt;&#x2F;a&gt; the structure
that built it this is is essential work.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Just remember: you and your pair now share context that the rest of the
organization may not have. Luckily, you’ve verbalized that context! It’s still
incumbent on you to record it for others. Even if you don’t combat this by
pairing, it’s helpful to consider that the act of conveying context is in
tension with the act of coding.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;There are no silver bullets here: communication is difficult. Practice
contextualizing what you’ve learned. Teach others. Find communication you
admire and emulate it. But most of all, don’t give up: continually seeking to
improve your communication skills is an excellent way to distinguish yourself
as a talented engineer. Giving up early – or worse, imagining that you have no
room to improve – is a surefire way to frustrate your peers.&lt;&#x2F;p&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;1&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;A phrase I borrow from &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;ceejbot&quot;&gt;ceejbot&lt;&#x2F;a&gt; who in turn received it from &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;goofbone&quot;&gt;goofbone&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;2&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;2&lt;&#x2F;sup&gt;
&lt;p&gt;Using python scripts to automate an 80-spindle CD player &amp;amp; associate the resulting FLAC and mp3 files with metadata from &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;musicbrainz.org&#x2F;&quot;&gt;musicbrainz&lt;&#x2F;a&gt;. Still a very cool project.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;3&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;3&lt;&#x2F;sup&gt;
&lt;p&gt;Probably.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
</description>
      </item>
      <item>
          <title>Deploying at Eaze</title>
          <pubDate>Sat, 19 Dec 2020 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://www.neversaw.us/2020/12/19/deploying-at-eaze/</link>
          <guid>https://www.neversaw.us/2020/12/19/deploying-at-eaze/</guid>
          <description xml:base="https://www.neversaw.us/2020/12/19/deploying-at-eaze/">&lt;h1 id=&quot;deploying-at-eaze&quot;&gt;Deploying at Eaze&lt;&#x2F;h1&gt;
&lt;p&gt;Late January 2020 &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;techcrunch.com&#x2F;2020&#x2F;01&#x2F;16&#x2F;eaze-out-of-cash-to-burn&#x2F;&quot;&gt;was a bummer&lt;&#x2F;a&gt;. In the wake of some &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.sfchronicle.com&#x2F;business&#x2F;article&#x2F;Pot-delivery-company-Eaze-lays-off-36-workers-14493533.php&quot;&gt;pretty&lt;&#x2F;a&gt; dire &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;techcrunch.com&#x2F;2020&#x2F;02&#x2F;25&#x2F;troubled-eaze-finally-closes-35m-funding-to-roll-out-a-new-vertical-model-selling-its-own-cannabis&#x2F;&quot;&gt;cuts&lt;&#x2F;a&gt;,
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;ceejbot&quot;&gt;ceejbot&lt;&#x2F;a&gt; and I found ourselves the sole custodians of Eaze’s
infrastructure. I remember looking at the scope
of problem ahead of us and asking myself “what am I &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.entropic.dev&#x2F;&quot;&gt;giving up doing now&lt;&#x2F;a&gt;
because I am taking on this work?”&lt;&#x2F;p&gt;
&lt;p&gt;Our first task: deploy a newly written identity verification service
for trust &amp;amp; safety. One small step.&lt;&#x2F;p&gt;
&lt;p&gt;Flash forward to the end of 2020. We built a new infrastructure team. Deploys
went from low-confidence, hourlong ordeals involving careful coordination of
shared resources to &lt;em&gt;blink-and-you’ll-miss-it&lt;&#x2F;em&gt;, safe operations against
&lt;em&gt;on-demand&lt;&#x2F;em&gt; development clusters. As a result of our work, our cloud provider
bill dropped by 66%. The work to get the system to move again was deliberate
and intense, but like the compounded effects of an ion engine’s paper-weight
pressure against a starship, we’ve achieved some incredible velocity over time.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Oh, and we put Rust in production!&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;So, what did we do? What did we learn?&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;starting-at-zero&quot;&gt;starting at zero&lt;&#x2F;h2&gt;
&lt;p&gt;For a long time, bright lines of responsibility existed between teams, ones
that could not be crossed: a backend engineer could not expect much access to
the AWS console, say. Likewise, it was frowned upon for frontend engineers to
cross into the backend. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Conway%27s_law&quot;&gt;Predictably&lt;&#x2F;a&gt;, this resulted in a system that
mistrusted itself. The code developed a Velcro-like consistency at the seams
where teams met, born out of defensiveness and mutual mistrust. These codebases
represented silos of knowledge. When you can’t cross team boundaries, you can’t
socialize knowledge about your corner of the system! Over time, maintainers of
the system went on to new opportunities, unintentionally leaving huge knowledge
gaps in their wake.&lt;&#x2F;p&gt;
&lt;p&gt;The technical debt was holding us back and the company realized this. Thus,
over the fall and summer of 2019 I was tasked with working across teams to
build a next-generation infrastructure for Eaze. However, the company had
not yet come to grips with the organizational debt it accrued, so this
project was doomed: because of the mistrust between teams, it was built in
a corner without interacting with the other systems. This insulated the
decision-making of the next generation project at the expense of making
sure those decisions were ultimately noncommittal; they could not affect the
working system or the existing team structure maintaining it.&lt;&#x2F;p&gt;
&lt;p&gt;The next generation project was to be built using Kubernetes and Golang, the
former as a means to placate management and the latter as a means of resolving
a long-standing conflict between C# and Node developers in the company. Within
a week of landing at the company in the summer of 2019 I bounced off of Go.
This is not to say it is a bad language, but it and I do not share the same
values, and I was hesitant to hand it to the team.&lt;&#x2F;p&gt;
&lt;p&gt;In particular, I was spoiled by my experience with the Rust compiler; I was
disappointed to find that Go’s compiler was not nearly as helpful or respectful
of my time. Thus began my campaign to get Rust into production at Eaze. I
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;xkcd.com&#x2F;356&#x2F;&quot;&gt;nerdsniped&lt;&#x2F;a&gt; ceej into writing small Rust CLI tools as glue for the nextgen
project with me. She had prior experience with Rust’s 2015 edition; ergonomic
improvements in the 2018 edition made the sale easy. Ultimately, Rust was the
only lasting contribution of this failed nextgen project.&lt;&#x2F;p&gt;
&lt;p&gt;The important point here is that we were working to tame a &lt;strong&gt;feral&lt;&#x2F;strong&gt; system, one
whose maintainers had long since left, and about which documentation was sparse
or non-existent. There was a small mountain of existing infrastructure managed
by a variety of homegrown tools, all of the knowledge of which had just been
lost from the company. On hand, we had pieces of a next-gen,
Docker-and-Kubernetes approach, written to avoid ruffling feathers. We
looked at what we had and said: “no.”&lt;&#x2F;p&gt;
&lt;h2 id=&quot;shoe-string-service-mesh&quot;&gt;shoe-string service mesh&lt;&#x2F;h2&gt;
&lt;p&gt;To be frank, Kubernetes and Docker were overkill for our problems and team
scale.&lt;&#x2F;p&gt;
&lt;p&gt;We needed something fast, correct, and ready yesterday. ceej and I had
previous, shared context for such a system: we wanted something similar to the
deploy system at NPM. This was ceej’s second time implementing such a system,
as she was the primary author of NPM’s deploy system; I previously put
together something similar for my personal infrastructure having found great joy
using that system at NPM.&lt;&#x2F;p&gt;
&lt;p&gt;Our goals and values were:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Developers should feel safe to deploy at any time of day, any day of the
week, limited only by their sense of the impact of their changes &amp;amp; their
commitment to work&#x2F;life balance.&lt;&#x2F;li&gt;
&lt;li&gt;We should start with a simple working system for a single service, then
add features as needed to support subsequent services.&lt;&#x2F;li&gt;
&lt;li&gt;What we build should be able to be operated by any engineer: we should
not hide important infrastructure tooling from them. (We want people to walk
away with experience with Terraform, not “eaze’s
bin&#x2F;apply-changes-somehow.sh script.”)&lt;&#x2F;li&gt;
&lt;li&gt;When in doubt about a decision, consider that we want our work to generalize
to multiple clusters.&lt;&#x2F;li&gt;
&lt;li&gt;We intend to use this new infrastructure to tame our existing feral services,
to make them malleable so we can take them back under control &amp;amp; begin making
necessary changes to our system.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;The gist of where we landed is: services run directly on EC2 instances.
Services run 4 processes, load-balanced by a single colocated reverse proxy.
When a deploy starts, we take each service process out of rotation, update the
code &amp;amp; configuration, roll the process, wait for success from a ping endpoint,
then add it back into rotation. Rinse and repeat until all service
processes are back up. Report progress into a special slack channel.&lt;&#x2F;p&gt;
&lt;p&gt;These EC2 instances are managed by an autoscaling group, and (at least initially)
each service had an application load balancer proxying to the nginx on each box.
(We later moved to single ALBs with multiple listener rules, thanks to &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;mobile.twitter.com&#x2F;maciejmalecki&quot;&gt;maciej&lt;&#x2F;a&gt;.)&lt;&#x2F;p&gt;
&lt;p&gt;Configuration and deploy event information comes from a watchable key-value
store. Service configuration combines keys of the form
&lt;code&gt;&amp;lt;servicename&amp;gt;&#x2F;ENV_VAR_NAME&lt;&#x2F;code&gt; with a &lt;code&gt;global&#x2F;ENV_VAR_NAME&lt;&#x2F;code&gt; namespace to produce
a single environment file suitable for feeding to systemd. Since the key-value
store is watchable, there’s a special &lt;code&gt;deploys&#x2F;&amp;lt;servicename&amp;gt;&lt;&#x2F;code&gt; key containing a
JSON blob with the S3 URL of a tarball containing the service executable, &amp;amp;
other deploy metadata. Whenever this changes, a deploy is triggered.
Configuration changes, on the other hand, aren’t watched &amp;amp; can be triggered
out-of-band.&lt;&#x2F;p&gt;
&lt;p&gt;This service deploy key is managed by a lambda listening for S3 bucket event
changes. Whenever an object lands in the bucket, the S3 metadata from that
object is turned into JSON along with the object’s location in the bucket. That
JSON is written to the appropriate consul deploy key.&lt;&#x2F;p&gt;
&lt;p&gt;The S3 object is provided by a GitHub action, which builds &amp;amp; zips up the
service on a push to a &lt;code&gt;deploy&#x2F;$cluster&lt;&#x2F;code&gt; branch and drops the result into S3.
(We eventually wrote a GitHub workflow to synchronize service GitHub deploy
workflows, but that’s a story for another time.)&lt;&#x2F;p&gt;
&lt;p&gt;We tracked Honeycomb trace IDs in our build metadata, so we could show the
fruits of our effort in concrete manner.&lt;&#x2F;p&gt;
&lt;a href=&quot;https:&#x2F;&#x2F;www.neversaw.us&#x2F;images&#x2F;honeycomb.png&quot; target=&quot;_blank&quot;&gt;
  &lt;img alt=&quot;Honeycomb UI showing service deploy in 35 seconds&quot; width=&quot;100%&quot; src=&quot;https:&#x2F;&#x2F;www.neversaw.us&#x2F;images&#x2F;honeycomb.png&quot; &#x2F;&gt;
&lt;&#x2F;a&gt;
&lt;p&gt;More important than the particulars of &lt;em&gt;what&lt;&#x2F;em&gt; we built are &lt;em&gt;how&lt;&#x2F;em&gt; we built it
and what we learned along the way.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;thesis-antithesis-and-synthesis&quot;&gt;thesis, antithesis, and synthesis&lt;&#x2F;h2&gt;
&lt;p&gt;With the exception of a few months in 2018 and 2019, Ceej and I have worked
together for the last five years. We have a lot of shared context and values –
whether that’s as a result of working together so long or why we’ve worked well
together, it’s unclear; probably a little of column A and a little of column B.&lt;&#x2F;p&gt;
&lt;p&gt;We approached rewriting Eaze’s infrastructure stack with a lot of
opinions about &lt;em&gt;how&lt;&#x2F;em&gt; we should work together. Most usefully: having gleefully
worked each other into burnout in the past, we understood which behavioral patterns
were most likely to burn us out.&lt;&#x2F;p&gt;
&lt;p&gt;As a result, the rule was that we only worked on the infrastructure together in
pairing sessions, and never let our enthusiasm for the work spill out into
evenings or weekends. Any time there was some bit of code we felt particularly
passionate about writing, we’d confer and make sure we both got a chance to
work on it during work hours. In order to get some quiet programming time
apart, we would take the time to define some self-contained tasks: writing a
CLI tool with well-known inputs and outputs to be plugged in to a bash script
written separately, for example.&lt;&#x2F;p&gt;
&lt;p&gt;We pair programmed on all of this work over Zoom. The day to day work took on a
morning&#x2F;afternoon cadence – a few hours before lunch, followed by a longer
pairing session in the afternoon. At the end of the work day, one or both of us
would summarize the work in a public Slack channel, both to communicate
progress out as well as to help us get started the next day. We both monitored
each other’s stress levels and would regularly make sure to trade off driving
duties at least every other day. We’d switch off more often for particularly
tricky tasks. (In mid-spring I took to working outside to get some sunshine.
Little things helped a lot with my morale, since this was around the outset
of the pandemic)&lt;&#x2F;p&gt;
&lt;p&gt;More important than the act of driving or navigating was the decision-making
cadence. When we needed to make a tactical decision with strategic
ramifications, we’d compare the outcomes against our values going in. Often
multiple solutions would present themselves. We’d then converse about the
solutions, often adopting a thesis&#x2F;antithesis pattern: “If we do X, Y gets
easier”, “ah, but if Z is important, we should reconsider because X makes it
more difficult.” If we got too far into a rabbit hole, we’d back out and
re-examine the larger problem.&lt;&#x2F;p&gt;
&lt;p&gt;We continue these practices even today!&lt;&#x2F;p&gt;
&lt;p&gt;This might not seem especially relevant in a technical context, but in my
opinion, this is the meat and potatoes of programming in a team context. There
always must be a balance of interests, a drive to share knowledge, and respect
for boundaries. Successful engineering has lot more to do with working well in
a team than it does with being technically “correct” individually.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-most-valuable-single-line-fix&quot;&gt;the most valuable single line fix&lt;&#x2F;h2&gt;
&lt;p&gt;We visited each service in our system working in this cadence. By our third or
fourth node service, the pattern for service resources was clear, and we
started to modularize our Terraform code. We had a fairly workable pattern
established: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.packer.io&#x2F;&quot;&gt;packer&lt;&#x2F;a&gt;, powered by &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.ansible.com&#x2F;&quot;&gt;ansible&lt;&#x2F;a&gt;, to provide base &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.aws.amazon.com&#x2F;AWSEC2&#x2F;latest&#x2F;UserGuide&#x2F;AMIs.html&quot;&gt;Amazon Machine
Images&lt;&#x2F;a&gt; for use in autoscaling groups provisioned by &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.terraform.io&#x2F;&quot;&gt;Terraform&lt;&#x2F;a&gt;. Terraform
additionally handled the &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;ashleygwilliams.github.io&#x2F;a-brief-history&#x2F;#67&quot;&gt;brackish residue&lt;&#x2F;a&gt; of per-service instance state via
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.aws.amazon.com&#x2F;AWSEC2&#x2F;latest&#x2F;UserGuide&#x2F;amazon-linux-ami-basics.html#amazon-linux-cloud-init&quot;&gt;cloudinit&lt;&#x2F;a&gt; templates – configuration service location, service name, etc.&lt;&#x2F;p&gt;
&lt;p&gt;The system was coming together. We had one last hurdle: Eaze’s largest
codebase, a monolithic C# application written against Microsoft IIS on a fairly
ancient version of .NET. All, of course, running on Windows. This still ran on
a dangerous, error-prone deploy system written on top of Chef and AWS
CodeDeploy.&lt;&#x2F;p&gt;
&lt;p&gt;There were the expected, mundane difficulties: the friction of having to switch
operating systems, learn PowerShell, &amp;amp; figure out the difference between
chocolatey and nuget. The sting of finding out that only a particular
combination of python version, ansible version, and ansible plugin version
worked to connect ansible runs. Trying in vain to remember that the directory
separator is &lt;code&gt;\\&lt;&#x2F;code&gt;. But we prevailed, and – we thought – we had a workable
solution we could deploy darkly, taking no production traffic.&lt;&#x2F;p&gt;
&lt;p&gt;We were wrong.&lt;&#x2F;p&gt;
&lt;p&gt;When we spun up our newly configured windows boxes in production, the
performance of the live application absolutely tanked. We quickly
decommissioned our boxes and went to investigate.&lt;&#x2F;p&gt;
&lt;p&gt;It turned out that we had a frankly ridiculous number of Redis connections.
Looking through the infrastructure repositories for context around this we
found that – shortly after April 20th, 2017, an infra engineer scaled the
application to 36 processes per box in reaction to unexpected failures.
Similarly, the redis box had been scaled up massively. While our load was not
insubstantial, ceej and I had some context here too – we had both seen much
smaller Redis instances meet the needs of much larger traffic loads at NPM.
This smelled like a misconfiguration issue.&lt;&#x2F;p&gt;
&lt;p&gt;We looked over the application setup and eventually saw the culprit: an
inversion-of-control container was responsible for registering a Redis
provider. Whenever this Redis provider was instantiated, it would attempt to
create a pool of 20 active connections to Redis. However, the provider was
configured to be instantiated &lt;strong&gt;on every request to any endpoint&lt;&#x2F;strong&gt;. Our
production windows box starved the live application of connections via the
healthcheck endpoint.&lt;&#x2F;p&gt;
&lt;p&gt;After consulting with our comrades, we changed the configuration and
redeployed. Success!&lt;&#x2F;p&gt;
&lt;p&gt;We were immediately able to downscale the managed redis instance we were
using. Having cleared that hurdle, we were able to proceed with replacing
the old deploy system in its entirety, including the Windows boxes.&lt;&#x2F;p&gt;
&lt;p&gt;It’s important to call out that this is, again, the bread and butter of
successful software engineering in legacy systems: it is anthropological study
of the situation that caused the system to arise, informed by second-hand
artifacts from the people involved in creating it. Lines of code are not a
valuable metric here; the value was in understanding the circumstances in which
the mistake was made, and determining that it was safe to fix the mistake. In
this case, the root problem was that there was such a divide between the prior
infrastructure team and backend teams – neither could find the problem by
themselves.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;growing-the-team-and-moving-on-to-new-problems&quot;&gt;growing the team and moving on to new problems&lt;&#x2F;h2&gt;
&lt;p&gt;Throughout this process, we had also been pairing with &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;jtthackery&quot;&gt;Joe&lt;&#x2F;a&gt; and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;psychronautron&quot;&gt;Chris&lt;&#x2F;a&gt;. They
had expressed interest in getting into infrastructure early in the year, though
they had historically only worked on Eaze’s website prior to that. They’re both
deep experts in that, but once trusted to work on the infrastructure they did
some amazing work in further reducing our AWS spend, moving services to the new
deploy flow, and grappling with our CDN configuration.&lt;&#x2F;p&gt;
&lt;p&gt;This informed the strategy for growing functioning teams: start by pairing on a
hard problem. Gradually, as the system begins to take working form, fold other
engineers in. The goal is to end up with agreement on values &amp;amp; team direction.
(This cuts both ways: not only are you onboarding the new teammate to your
values, but you’ve also got to be willing to take on some of their values!)
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;John_Gall_(author)#Gall%27s_law&quot;&gt;Gall’s law&lt;&#x2F;a&gt; applies to human systems.&lt;&#x2F;p&gt;
&lt;p&gt;Ceej and I stopped focusing on infrastructure around mid-to-late May. As our
final task, we added affordances for provisioning and decommissioning clusters.
We onboarded a familiar former coworker – &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;mobile.twitter.com&#x2F;maciejmalecki&quot;&gt;Maciej&lt;&#x2F;a&gt; – before moving on to our
next task.&lt;&#x2F;p&gt;
&lt;p&gt;There are still features I want to see in our infrastructure stack (automatic
nightly recreation of clusters!), but since Joe, Chris, and Maciej have
taken over the work, it’s only gotten better in their hands. The deploy system
has been a huge success: it started the long thaw of the technical debt
freezing our system in place. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;_randolph_west&quot;&gt;Others&lt;&#x2F;a&gt; have done incredible work accelerating
that thaw.&lt;&#x2F;p&gt;
&lt;p&gt;2020 has been a tough year, but this little corner of my life was hugely
fulfilling. I’m proud of the team we built and the work we did.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>What happened to July?</title>
          <pubDate>Fri, 07 Aug 2020 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://www.neversaw.us/2020/08/07/what-happened-to-july/</link>
          <guid>https://www.neversaw.us/2020/08/07/what-happened-to-july/</guid>
          <description xml:base="https://www.neversaw.us/2020/08/07/what-happened-to-july/">&lt;p&gt;July is over. We’re already seven days into August. Time sure does fly when
you’re quarantining, I guess. So what happened?&lt;&#x2F;p&gt;
&lt;p&gt;Well, between these two points, the feds were in Portland, OR., where I live.
Work on the Rust rewrite of our delivery system began in earnest. I started
helping with Orogene, another JavaScript package manager. I finished Zelda
(again.) I picked up Ghost of Tsushima, which is beautiful but empty by
comparison. Truly this generation of game consoles has been the “open world
with a bow-wielding, horse-riding protagonist” era. A friend’s brother died.
I… barbequed a lot more, because it’s been too hot to cook indoors. Another
person I know (distantly) died. Krysten and I painted a TV console (our first
time painting furniture!) We also finally broke into Overcooked. It’s been
a strange couple of weeks; time feels especially soupy these days.&lt;&#x2F;p&gt;
&lt;p&gt;I spent a lot of the last month struggling with the dissonance of things going
well at home vs. the wanton brutalizing of Portland protestors. Struggling to
maintain my focus and not let others set my pace for me. Struggling to balance
all the things I want to do in my free time with my need to rest, to do
&lt;em&gt;nothing&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;For a few weeks I tried working on my WASM parser on my off hours from work;
then tried (&amp;amp; failed) to resist the urge to contribute to Orogene. I noticed
my mood at work dip more and more: the longer I moonlit on these side-projects,
the more irritable &amp;amp; less effective I was during the day.&lt;&#x2F;p&gt;
&lt;p&gt;So, I took the last week “off.” All I’ve done in the evening is cook &amp;amp; play
video games. I’ve been getting to bed at a reasonable time, &amp;amp; reading comics
before that. Work this week has been fun, mostly, as a result.&lt;&#x2F;p&gt;
&lt;p&gt;The phrase – which sounds better in my head – that comes up when I’m trying
(and failing) to resist picking up side projects is “a torque on one’s soul.”
I’ll experience this as some new disquiet that’s compelling me to move forward,
towards a goal I didn’t have before. This is occasionally useful: I’ve
learned a lot by following this urge. The problem is that I have trouble
&lt;em&gt;ignoring&lt;&#x2F;em&gt; it.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>PLAN update</title>
          <pubDate>Wed, 15 Jul 2020 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://www.neversaw.us/2020/07/15/plan-update/</link>
          <guid>https://www.neversaw.us/2020/07/15/plan-update/</guid>
          <description xml:base="https://www.neversaw.us/2020/07/15/plan-update/">&lt;p&gt;Vacation is over! I’ve been back for about three days now.&lt;&#x2F;p&gt;
&lt;p&gt;I ended up writing a &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;developer.mozilla.org&#x2F;en-US&#x2F;docs&#x2F;WebAssembly&#x2F;Understanding_the_text_format&quot;&gt;WASM text format&lt;&#x2F;a&gt; (or “WAT”) parser in Rust over
vacation, in between watching movies projected on the side of my garage,
replaying Zelda: BOTW, and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=i_jRNESxR-M&quot;&gt;barbequeing&lt;&#x2F;a&gt;. My intention was to build a tiny
language runtime targeting WASM, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.neversaw.us&#x2F;2020-06-27-plan-update&#x2F;&quot;&gt;as frequent readers will recall&lt;&#x2F;a&gt;. I didn’t
quite get the parser done in that time, but I got pretty close: I finished up
fixing the last known bugs tonight.&lt;&#x2F;p&gt;
&lt;p&gt;Writing a parser against a language spec is a nice, meditative experience. It
involves repetitive work interleaved with research, leaving your mind free to
wander inbetween reading &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Backus%E2%80%93Naur_form&quot;&gt;Backus-Naur Form notation&lt;&#x2F;a&gt;. You get the discipline of
balancing letting your focus drift to the implications of your present technical
decisions in the near future while reining it in to take the next smallest
step in the right direction. Maybe I let my mind wander too far while writing
it – after all, I didn’t get done until today, ha.&lt;&#x2F;p&gt;
&lt;p&gt;All in all, it’s really not unlike the experience of drawing: a nice mix of
flow state, low-commitment strategic planning, and constant tactical feedback.
(I’m starting to feel the itch to illustrate again, to be honest.)&lt;&#x2F;p&gt;
&lt;p&gt;I’m working in a private repo right now; once I clean up the code a bit I’ll
open source it on GitHub. I think the next steps are:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Move the parser combinators and their tests into separate files.&lt;&#x2F;li&gt;
&lt;li&gt;Pull the AST node types up into a separate package workspace so they can be
used without having to pull in the parser. (Useful if you want to compile to
WASM but parse a different language.)&lt;&#x2F;li&gt;
&lt;li&gt;Add a canonicalization method to the nodes, to handle the “abbreviations”
present in WAT. (A sidenote: WAT had &lt;em&gt;way&lt;&#x2F;em&gt; more abbreviations than I expected.)&lt;&#x2F;li&gt;
&lt;li&gt;Emit WASM from canonicalized nodes. This should be suitable for running in
Node’s &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;nodejs.org&#x2F;api&#x2F;wasi.html&quot;&gt;WASI&lt;&#x2F;a&gt; module.&lt;&#x2F;li&gt;
&lt;li&gt;Pull in &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;lib.rs&#x2F;rusty_v8&quot;&gt;&lt;code&gt;rusty_v8&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;cjihrig&#x2F;uvwasi&quot;&gt;&lt;code&gt;uvwasi&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; to make a standalone runtime.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;That said.&lt;&#x2F;p&gt;
&lt;p&gt;I’m starting to get a bit of RSI in my right ring finger knuckle, so it’s
likely that I’m going to have to take some time to let that heal. Karma for
foolishly claiming that &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;mobile.twitter.com&#x2F;isntitvacant&#x2F;status&#x2F;1276978153135542272&quot;&gt;not mousing helps prevent RSI&lt;&#x2F;a&gt;, I suppose.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Career Progression</title>
          <pubDate>Sat, 04 Jul 2020 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://www.neversaw.us/2020/07/04/career-progression/</link>
          <guid>https://www.neversaw.us/2020/07/04/career-progression/</guid>
          <description xml:base="https://www.neversaw.us/2020/07/04/career-progression/">&lt;h1 id=&quot;career-progression&quot;&gt;Career Progression&lt;&#x2F;h1&gt;
&lt;p&gt;A few days ago, I was promoted to Principal Engineer at &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.eaze.com&#x2F;&quot;&gt;$dayjob&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;While I feel grateful for the recognition, I have to admit I’m a bit of a
skeptic when it comes to career ladders and titles. People aren’t comparable,
nor are their talents or knowledge. Attempts to reduce a group of
humans to points on a number line erase a lot of individual strengths.
On the other hand, titles are a way for the group to officially
recognize the personal practice of improving at the craft of
engineering. So, I’ve been stewing on this for a couple days now: what
does this promotion mean?&lt;&#x2F;p&gt;
&lt;p&gt;Speaking for the tech industry, titles are a measure for your experience,
efficacy, and ability to deliver value to your organization. They
represent how the organization at large views your talents and often
how they value your contributions. In theory, they reflect your day to
day responsibilities.&lt;&#x2F;p&gt;
&lt;p&gt;However.&lt;&#x2F;p&gt;
&lt;p&gt;The measure, as a proxy for the job, is doubly flawed. For one, it doesn’t
describe the job accurately &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;staffeng.com&#x2F;guides&#x2F;staff-archetypes&quot;&gt;across organizations&lt;&#x2F;a&gt;; further, two people with
the same title within the same organization may execute the title in wildly
different fashions. For two, we measure individuals, but the our ability to
contribute on an individual basis depends greatly upon the team around us, and
that team’s perception of us.&lt;&#x2F;p&gt;
&lt;p&gt;On the other hand, the measure corrects for insidious biases: the title can
lift some of the burden of constantly having to prove your worth, especially if
you’re not a member of a historically privileged group. It can also correct for
compensation bias: two staff engineers should be making the same amount, even
if one of them is a white guy and the other isn’t. (Compensation can get
perilously out of whack without banding tied to titles.) The bias is still
there, it’s been compartmentalized into convincing the org that you meet a
rubric, but you can at least bring receipts to that conversation.&lt;&#x2F;p&gt;
&lt;p&gt;So, I’m conflicted.&lt;&#x2F;p&gt;
&lt;p&gt;I am an ardent believer in self-improvement – that the craft of engineering
can be practiced like art in any other medium. I also believe that you will,
over the course of your career, encounter engineers who have practiced far
more (or less) than you, possess raw talent for thinking (analytically or
otherwise), whose communication skills and techniques you will envy and
seek to emulate for years afterward. You’ll work with people all across the
spectrum of possibility. Trying to reduce them to a number line erases so
much of what they have to offer, encourages zero-sum mentality, and stands
in the way of your own self-improvement. But that’s the realm of the ideal:
only a privileged few are afforded the ability to treat programming as an
art that can be practiced in isolation from society.&lt;&#x2F;p&gt;
&lt;p&gt;On the other hand.&lt;&#x2F;p&gt;
&lt;p&gt;I’ve been at the pointy end of a shift in organization culture. Two years ago
at a previous job, my manager told me point-blank that I had been doing the
Principal Engineer job for some time per the career ladder rubric, but because
of organizational changes there was a new VP who could not be convinced that I
should be promoted.  Ironically, before the change in management, I was one of
the parties responsible for &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;chrisdickinson&#x2F;659f7e3a233a0fef9cf07fb9e35af118&quot;&gt;designing the rubric&lt;&#x2F;a&gt; for that career ladder! That
same VP had pulled me aside earlier to explain that, because I had worked so
closely with the prior, unceremoniously booted, management, it “wasn’t clear”
what I had contributed over the past four years. I stuck around for months from
that point, trying to do everything I could to change their mind.&lt;&#x2F;p&gt;
&lt;p&gt;I still feel hurt by this, obviously. The insecurity I had internalized from
this experience factored into my decision to turn down a Principal Engineer
position during my subsequent job hunt. I’m here now though, so it’s all for
the best, I suppose. The lesson, however, is clear: a career ladder is a social
construct that is only as real as the people in power at your organization make
it.&lt;&#x2F;p&gt;
&lt;p&gt;Titles hurt in other ways: I’ve seen a brilliant, absolutely stellar programmer
get turned down for a position at a company because their ability to impress
their interviewer with a whiteboard and dry-erase marker wasn’t sufficient to
justify the title they were interviewing for. Again, there’s a lesson here: a
focus on measuring humans against a number line tends to turn technical
interviews into a hazing ritual. The point of the ritual hazing is to buy the
necessary cachet to justify a title with the existing engineering staff. This
is stupid and cruel, as you know.&lt;&#x2F;p&gt;
&lt;p&gt;So much of what exhausts me in tech is tied up in the constant drive to
establish a pecking order, and that might be what I’m really reacting against.
Career ladders are a pragmatic concession to this: if we’re going to keep
trying to rank engineers, we may as well do so with an established rubric. At
least then we can try to confront our biases. It’s worth considering the title
a floor when considering a person’s talents: they may be wildly more talented
than their title. There is no iron-clad rule that says an associate engineer
cannot teach a staff engineer something valuable.&lt;&#x2F;p&gt;
&lt;p&gt;I suppose this is all to say: I’m grateful for the recognition. I take it with
a grain of salt, because titles and career ladders are a mushy, social
construct that changes as people enter and leave the organization; I won’t let
it go to my head because there’s obviously so much more I can learn from my
colleagues, no matter where they are on this ladder. My intention as a
principal engineer is to highlight the achievements of my coworkers, work to
make sure they’re empowered, trusted, and happy, and to become better engineers
by working together.&lt;&#x2F;p&gt;
&lt;p&gt;I’ll write more about what’s worked for me in a subsequent post.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>PLAN update</title>
          <pubDate>Sat, 27 Jun 2020 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://www.neversaw.us/2020/06/27/plan-update/</link>
          <guid>https://www.neversaw.us/2020/06/27/plan-update/</guid>
          <description xml:base="https://www.neversaw.us/2020/06/27/plan-update/">&lt;p&gt;I’m coming up on a chunk of vacation, and I’d like to work on a
technical project during that time. I have a couple of plates already
spinning; Boltzmann documentation, for example. The itch(es) I’d like
to scratch are:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Parsing in Rust, possibly using &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pest.rs&#x2F;&quot;&gt;&lt;code&gt;pest&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; or &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.rs&#x2F;nom&#x2F;5.1.2&#x2F;nom&#x2F;&quot;&gt;&lt;code&gt;nom&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Learning more about WASM and WASI, possibly using them as a language compile
target.&lt;&#x2F;li&gt;
&lt;li&gt;Revisiting control flow graph generation of JS in Rust, using &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ratel-rust&quot;&gt;ratel&lt;&#x2F;a&gt;,
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.rs&#x2F;ressa&#x2F;0.7.0&#x2F;ressa&#x2F;&quot;&gt;RESSA&lt;&#x2F;a&gt;, or &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;esprit.surge.sh&#x2F;&quot;&gt;esprit&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Doing something graphical: some sort of &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www-cs-students.stanford.edu&#x2F;~amitp&#x2F;game-programming&#x2F;polygon-map-generation&#x2F;&quot;&gt;map generation&lt;&#x2F;a&gt; would be neat.
There’s quite a learning curve for me here; I’d probably be picking up
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;amethyst.rs&#x2F;&quot;&gt;Amethyst&lt;&#x2F;a&gt;, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.rs&#x2F;rendy&#x2F;0.5.1&#x2F;rendy&#x2F;&quot;&gt;Rendy&lt;&#x2F;a&gt;, or &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gfx-rs.github.io&#x2F;2019&#x2F;03&#x2F;06&#x2F;wgpu.html&quot;&gt;&lt;code&gt;wgpu&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Each of these has a research component: what is the state of these ecosystems?
How do the various pieces fit together? What does it look like to work with these
in a borrow-checked language like Rust?&lt;&#x2F;p&gt;
&lt;p&gt;So, breaking down the projects a bit:&lt;&#x2F;p&gt;
&lt;h2 id=&quot;write-a-tiny-language&quot;&gt;Write a tiny language&lt;&#x2F;h2&gt;
&lt;p&gt;Admittedly, there’s not a huge technical need for the sort of langauge I’d
write, nor or any sort of gap in existing tooling I’m attempting to address!
I’m interested in “walking the path”: what does it look like to write a language
today? What role might WASM play in early prototyping? What gaps exist?&lt;&#x2F;p&gt;
&lt;p&gt;And indeed, writing a scripting language is on my personal programming bucket
list. I’ve written tons of parsers in my day (and a single control-flow-graph
generator leveraging partial evaluation), but I haven’t had the chance yet
to write an executable language.&lt;&#x2F;p&gt;
&lt;p&gt;I plan to start small: iterate on a LISP-like language at first. Targeting
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;developer.mozilla.org&#x2F;en-US&#x2F;docs&#x2F;WebAssembly&#x2F;Understanding_the_text_format&quot;&gt;WAT&lt;&#x2F;a&gt; (“Web Assembly Text format”) and emitting WASM may be a good start. That
would let me target Node’s &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;nodejs.org&#x2F;api&#x2F;wasi.html&quot;&gt;WASI API&lt;&#x2F;a&gt; (&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;bytecodealliance&#x2F;wasmtime&#x2F;blob&#x2F;main&#x2F;docs&#x2F;WASI-intro.md&quot;&gt;“Web Assembly System Interface”&lt;&#x2F;a&gt;) to
get started, or perhaps &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;wasmtime.dev&#x2F;&quot;&gt;wasmtime&lt;&#x2F;a&gt;. Eventually this could lead to writing a
self-hosted runtime using &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.rs&#x2F;rusty_v8&#x2F;0.6.0&#x2F;rusty_v8&#x2F;&quot;&gt;&lt;code&gt;rusty_v8&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;cjihrig&#x2F;uvwasi&quot;&gt;&lt;code&gt;uvwasi&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;. (That would be a fun
learning experience, since it’d take me through using &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;rust-lang.github.io&#x2F;rust-bindgen&#x2F;&quot;&gt;&lt;code&gt;bindgen&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;.)&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;control-flow-graph-generation&quot;&gt;Control flow graph generation&lt;&#x2F;h2&gt;
&lt;p&gt;Six years ago (!!) I &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;chrisdickinson&#x2F;escontrol&quot;&gt;experimented&lt;&#x2F;a&gt; with building a &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Control-flow_graph&quot;&gt;control flow graph&lt;&#x2F;a&gt; generator for
JavaScript. My initial goals were to:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Build tooling to search a corpus of JavaScript for library use, in support
of estimating the potential fallout of making changes to Node.JS builtin
APIs.&lt;&#x2F;li&gt;
&lt;li&gt;Visualize code diffs from a novel angle: instead of looking at the textual
change, two graphs would be compared and the differences would be displayed
visually. (It would be easy to catch that new code introduces an exception edge
when looking at two directed graphs, less so in textual form.)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;I had some success; over the course of the year I spent at Wal-Mart Labs I
wrote ESControl, ESToc, and ESSim: a control flow graph generator, dependency
tracker, and simulator. However, looking back, I wish I had brought a bit more
rigor to my work: early on in the project it struck me that due to the nature
of JavaScript, very nearly ever node on the control flow graph would have to
draw an exception edge. That many edges with a common destination would’ve
completely obscured the rest of the graph when displayed visually, and yet
the exception edges represented valuable control flow information.&lt;&#x2F;p&gt;
&lt;p&gt;I cut that Gordian knot by backing into partial evaluation: as I walked the
graph I would keep a stack state machine that would allow me to make assertions
about certain exception edges as they appeared: as an example, if I had drawn
an exception edge for &lt;code&gt;x is undefined&lt;&#x2F;code&gt; earlier in the graph, I could omit the
edge on the next (straightline) lookup of &lt;code&gt;x&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D3C6AA; background-color: #2D353B;&quot;&gt;&lt;code data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DBBC7F;&quot;&gt;&amp;#39;use strict&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;x&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E69875;&quot;&gt; +=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D699B6;&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #859289;font-style: italic;&quot;&gt; &#x2F;&#x2F; draw an exception edge: what if &amp;quot;x&amp;quot; is undefined?&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;x&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E69875;&quot;&gt; +=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D699B6;&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span style=&quot;color: #859289;font-style: italic;&quot;&gt; &#x2F;&#x2F; if we reached this point we definitely know that &amp;quot;x&amp;quot; is defined!&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Approaching the problem this was expedient, but tipped the scale on other
load-bearing decisions: because it had the stack machine information available
to it, ESControl aggressively inlined functions. Eventually it reached a point
that for some small programs, I could generate ESControl IR and run the program
step-by-step with the same output.&lt;&#x2F;p&gt;
&lt;p&gt;I’m interested in revisiting this in Rust for a couple of reasons:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;I never got to the point of visualizing code diffs as control flow graph
changes, and I’m still intrigued by that&lt;&#x2F;li&gt;
&lt;li&gt;The memory usage characteristics of the JavaScript ESControl were not ideal;
Rust would force more rigor in memory use.&lt;&#x2F;li&gt;
&lt;li&gt;I’m interesting in taking door number two, so to speak: separating the control
flow graph generation from a simplification step that would run the partial evaluation
necessary to erase edges from the graph.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;This would require familiarizing myself with the state of JS parsing in Rust. I
would not be mad about that.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;map-generation&quot;&gt;Map Generation&lt;&#x2F;h2&gt;
&lt;p&gt;This one is a bit out there. At my &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.eaze.com&#x2F;&quot;&gt;$dayjob&lt;&#x2F;a&gt; we’ve been tasked with rethinking
how delivery fulfillment works; I’ve become enthusiastic about the idea of
modeling this as actor-owned task queues. Put another way, the data the system
operates on would work much like how real time strategy games model commands
issued to units. From there we’d layer on systems responsible for generating
and assigning efficient task queues. (This might not seem like much of a brain-wave,
but to be honest the way the system works right now was clouding my framing
of the problem.)&lt;&#x2F;p&gt;
&lt;p&gt;Of course, thinking about real-time strategy games got me thinking about game
programming again; at the same time, I’ve been missing some of my more &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.neversaw.us&#x2F;scratch&#x2F;terrain&#x2F;&quot;&gt;visual&lt;&#x2F;a&gt;
experiments. It’d be fun to build a terrain or city generator, then model unit
task queues on top of that! Kat’s &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;mobile.twitter.com&#x2F;zkat__&#x2F;status&#x2F;1274454258507608064&quot;&gt;recent work&lt;&#x2F;a&gt; in this space is inspiring, also.
(&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;phiresky.github.io&#x2F;procedural-cities&#x2F;presentation.html&quot;&gt;The presentation&lt;&#x2F;a&gt; Kat linked to earwormed me.)&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h1 id=&quot;currently-reading-open-in-tabs&quot;&gt;Currently reading &#x2F; open in tabs:&lt;&#x2F;h1&gt;
&lt;p&gt;&lt;strong&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;yoshuawuyts&#x2F;notes&#x2F;blob&#x2F;11ce15f29012ff9d3de5342357eb996805ec2660&#x2F;compilers&#x2F;resources.md&quot;&gt;Yoshua Wuyts’ writeup on compilers&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;: Yosh is super thoughtful and thorough; I’m
excited to read more of his writing. (Compliments aside, you can imagine how a
writeup on compilers might dovetail with my current interests!)&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;blog.tonari.no&#x2F;why-we-love-rust&quot;&gt;“Why we love Rust”&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;: a nice grab-bag of tips &amp;amp; tricks learned while delivering
an impressive low-latency video &amp;amp; audio streaming solution. I’m going to try integrating
some of the tools they suggest, like &lt;code&gt;cargo-flamegraph&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;cs.gmu.edu&#x2F;~sean&#x2F;book&#x2F;metaheuristics&#x2F;&quot;&gt;Essentials of Metaheuristics&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;: linked by a co-worker, &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;elihickox.com&#x2F;&quot;&gt;Eli&lt;&#x2F;a&gt;. As you can
imagine, optimizing delivery involves &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Travelling_salesman_problem&quot;&gt;a lot of&lt;&#x2F;a&gt; (NP-hard) &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Bin_packing_problem&quot;&gt;problems&lt;&#x2F;a&gt;, for
which heuristic approaches are a good fit. My experience with this is a bit
distant, so I am refreshing my memory by &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Simulated_annealing&quot;&gt;re-reading the simulated annealing&lt;&#x2F;a&gt;
article on wikipedia. (This also dovetails with my desire to build a CFG diffing
tool, which abuts the NP-hard-in-the-general-case &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Longest_common_subsequence_problem&quot;&gt;longest common subsequence&lt;&#x2F;a&gt; problem,
for which a &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Dynamic_programming&quot;&gt;dynamic programming&lt;&#x2F;a&gt; approach can solve specific cases in polynomial
time. This is all to say: it’s up my alley, and look, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.rs&#x2F;metaheuristics&#x2F;1.0.15&#x2F;metaheuristics&#x2F;&quot;&gt;there’s a Rust library for it&lt;&#x2F;a&gt;!)
I’m also taking a peek at &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.optaplanner.org&#x2F;&quot;&gt;Optaplanner&lt;&#x2F;a&gt; on his recommendation.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;grain-lang.org&#x2F;&quot;&gt;Grain Language&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;: a new language! Linked by &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;mobile.twitter.com&#x2F;BlaineBublitz&#x2F;status&#x2F;1275884962038771713&quot;&gt;Blaine&lt;&#x2F;a&gt;. I like Blaine’s
taste; if he’s enthusiastic about a language it’s probably worth checking out.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;staffeng.com&#x2F;&quot;&gt;StaffEng.com&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;: A great overview of what work in a staff engineering
position looks like. I feel some relief at the seeing the enumeration of the
types of roles staff engineers play at companies: I am somewhat allergic to
working at large companies with lots of process, so I’m not a great fit for
teams that use staff engineers to enforce process: whether that’s serving as
architecture review boards or tech leads responsible for assigning work.
However, I have it on other folks’ authority that I’m a good teacher, and I
know how to tactically deploy my technical skill in service of my larger
strategies. I’m in my feelings about this one still – that last year at NPM
really did a number on me, not least of all because the goalposts of what
staff engineering meant changed all at once. It’s probably worth a more
complete blog post in the future.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h1 id=&quot;other-thoughts-which-may-yet-become-blog-posts&quot;&gt;Other thoughts which may yet become blog posts:&lt;&#x2F;h1&gt;
&lt;p&gt;I’ve been ruminating a bit on my career progression lately. One of the
aspects of staff engineering I’m interested in is how we process negativity, or
grumpiness. It seems to me that as a profession we tend to reward negativity,
so I (&amp;amp; others) displayed more of it when mid-career. I’ve walked a lot of
that back over the last four years, but false positivity isn’t tenable in the
long run, either. I’ve been stewing on &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.infoq.com&#x2F;presentations&#x2F;rust-tradeoffs&#x2F;&quot;&gt;Steve Klabnik’s keen observation&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;As a programmer, I think it behooves us to think about not just the values
that we hold, but the values of the people that use our software hold and, as
a programmer, you should use tools that align with your values. I really like
programming languages and learning new ones, but there are some that I have
seen where I’m like, “You know what? This language is not for me, so I’m just
not going to use it.” I’m not going to denigrate any languages by naming
them, but it’s true that I would be unhappy if I had to program in some
languages and that’s because they value different things than I value and
that’s totally chill.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Ceej relayed the following from her husband, David:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Anger is a useful signal: it means your values are being violated in some way!&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Speaking of grumpiness because of violated values, I’d like to see a positive
workflow for ES Modules framed, if possible. Right now the story is all veggies
and no dessert.&lt;&#x2F;p&gt;
&lt;p&gt;Finally on this note: I’ve been thinking about React SSR quite a bit lately.
The thought bouncing around in my head is: React’s origin as a tool for managing
a live DOM makes it ill-suited for use as a server-side template language, which
is how most React SSR solutions position it. It’s another thing I find myself
grumping about, and it might be worth digging into in the future.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Boltzmann &amp; Nostalgia</title>
          <pubDate>Thu, 18 Jun 2020 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://www.neversaw.us/2020/06/18/boltzmann-and-nostalgia/</link>
          <guid>https://www.neversaw.us/2020/06/18/boltzmann-and-nostalgia/</guid>
          <description xml:base="https://www.neversaw.us/2020/06/18/boltzmann-and-nostalgia/">&lt;p&gt;Right now I’m writing templating middleware for Boltzmann (a JS framework.)
Three years ago around this time, I was writing something similar for Spife
(another JS framework) while waiting in the Oakland airport for my flight back
to Portland. I was entirely drained from another NPM all-hands experience, and
I kept staring out the windows at planes landing and taxiing to gates. It was
in the evening; everything outside was tinted lavender with orange highlights.
I was excited to get back home, but so tired; sad to be leaving, hoping I had
done good by my coworkers while I was out.&lt;&#x2F;p&gt;
&lt;p&gt;It’s last year, around this time. I’m writing the first version of Boltzmann
for Entropic while I’m in San Francisco for my two week (!!) onboarding at
[$dayjob]. At this point I’ve been camping out at the dark, slightly-dingy
hotel bar for about a week’s worth of evenings, idly poking at my laptop. By
the time I’m off work, I don’t really have the motivation to make it much
farther than “the hotel lobby.”&lt;&#x2F;p&gt;
&lt;p&gt;The bartender is pouring excellent Manhattans, which is why I keep coming back,
to be honest. By the end of next week, we’ll be on good enough terms that
he’ll pour me the occasional free shot of whiskey. At this point in my
life, I am shellshocked by how quickly and completely my NPM has changed
character, and my ego is deeply bruised by the preceding months. It’ll be
almost half a year before I start to feel better. I keep typing. We’re
presenting Entropic in 3 weeks. I miss Krysten and my cats.&lt;&#x2F;p&gt;
&lt;p&gt;It’s two years ago – 2018. I’m in Seattle to give a talk about Spife at a
local user conference in January or February. Our only engineering manager at
NPM quit. For a few months I’ve played the part of project manager, engineering
manager, and tech lead for the rewrite of the website. I am incredibly wound up
and anxious. I worry a lot about letting my coworkers down. Sometimes this
anxiety gets in the way of seeing how they’re rising to the occasion; how
they’re supporting me. I’m on a managers call; I’m gutted by how badly I’ve let
down one of my reports. This has been the winter of spam: attackers flooded
pretty much public content-hosting site with SEO spam, and NPM was not spared.
We didn’t have the tools or processes to deal with it, so we’re fighting a
rear-guard action on nights and weekends.&lt;&#x2F;p&gt;
&lt;p&gt;A package that wasn’t spam got deleted accidentally the weekend before, which
caused a fire drill. Someone reporting to me had warned repeatedly – weeks
ahead of this – that this was coming. Fuck. The manager’s meeting wrapped up.
I walked to the venue and talked about Spife, and about how it’s building your
own framework to address your problems is, in fact, good. Six months later
someone else at the company came to power &amp;amp; Spife fell out of fashion. I was
sidelined. After my talk, I saw a show.&lt;&#x2F;p&gt;
&lt;p&gt;It’s today. I’m writing boltzmann template middleware. We’re talking about
rewriting the website at [$dayjob]. I’m fretting about taking my car for some
maintenance tomorrow. Will people be wearing masks? Should I plan on staying there
while they work on the car, or should I rent a car and get back home? It’ll
be the longest I’ve been out of the house in public since quarantine started.&lt;&#x2F;p&gt;
&lt;p&gt;I traveled a lot more than I thought I would over the last five years. The
moments that stand out the most to me are the quiet ones, near the end of the
trip, waiting at the airport to go back home. Feeling melancholic about
leaving, but exhausted and happy to head home. I don’t know if I miss traveling
for work, but I’m definitely nostalgic for the feeling of coming home.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;It’s ten years ago. I’m at &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.johnnystavern.com&#x2F;locations&#x2F;north-lawrence&#x2F;&quot;&gt;Johnny’s Tavern&lt;&#x2F;a&gt; in North Lawrence, Kansas. I’ve
been working nights and weekends on a callback-based implementation of
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.djangoproject.com&#x2F;&quot;&gt;Django’s&lt;&#x2F;a&gt; template language, to integrate into a JS framework called Wilson.
I’ve just finished writing the template loading integration. My friends –
largely more seasoned Python programmers – nod along; they seem enthused,
supportive, and gently skeptical. After the evening winds down and we
say our goodbyes, I walk the few blocks home down Massachusetts street;
the sky is slate blue and peach, the future is bright and full of
possibility. There might be a future for me in this Node thing.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Watching: The Forgotten Art of Structured Programming</title>
          <pubDate>Tue, 16 Jun 2020 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://www.neversaw.us/2020/06/16/watching-structured-programming/</link>
          <guid>https://www.neversaw.us/2020/06/16/watching-structured-programming/</guid>
          <description xml:base="https://www.neversaw.us/2020/06/16/watching-structured-programming/">&lt;div &gt;
    &lt;iframe src=&quot;https:&#x2F;&#x2F;www.youtube-nocookie.com&#x2F;embed&#x2F;w0sz5WbS5AM&quot; webkitallowfullscreen mozallowfullscreen allowfullscreen&gt;&lt;&#x2F;iframe&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;This talk is a gold mine:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Impress your friends by casually using “afferent” and “efferent”
in conversation&lt;&#x2F;li&gt;
&lt;li&gt;Don’t miss “Reach for the banana, get the gorilla”, which might
be my new favorite turn of phrase. (Immediately applicable, too:
at &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.eaze.com&#x2F;&quot;&gt;$dayjob&lt;&#x2F;a&gt; today, we’re porting a Wordpress server to the new
Terraform-based infrastructure setup. We only use Wordpress for
its WYSIWYG editor!)&lt;&#x2F;li&gt;
&lt;li&gt;Discover the one weird reason bash uses &lt;code&gt;fi&lt;&#x2F;code&gt; to close &lt;code&gt;if&lt;&#x2F;code&gt; statements.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Some links I drew from the talk, which I’ll be reading (or re-reading) in
the coming week:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;dl.acm.org&#x2F;doi&#x2F;pdf&#x2F;10.5555&#x2F;1243380&quot;&gt;Structured Programming (Dahl, Dijkstra, Hoare)&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;dl.acm.org&#x2F;doi&#x2F;pdf&#x2F;10.1145&#x2F;1283920.1283934&quot;&gt;The Paradigms of Programming (Floyd)&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;homepages.cwi.nl&#x2F;~storm&#x2F;teaching&#x2F;reader&#x2F;Dijkstra68.pdf&quot;&gt;Go To Statement Considered Harmful (Dijkstra)&lt;&#x2F;a&gt; - not new to me, but always
interesting to re-read. Niklaus Wirth is responsible for the click-bait-y
title, which I did not know until this talk.&lt;&#x2F;li&gt;
&lt;li&gt;(In talking to my co-worker, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;ceejbot&#x2F;&quot;&gt;ceej&lt;&#x2F;a&gt;, she mentioned a great pun from Niklaus
Wirth – “Europeans call me by name - ‘veert’ – Americans call me by value –
‘worth’”)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;books.google.com&#x2F;books?id=sS7aPtrUuw4C&amp;amp;pg=PA166&amp;amp;lpg=PA166&amp;amp;dq=testing+is+the+engineering+rigor+of+software+neal+ford&amp;amp;source=bl&amp;amp;ots=-ii_OW1exM&amp;amp;sig=ACfU3U34AqMxD7EAH5_XZpihQsD_JxkhxA&amp;amp;hl=en&amp;amp;sa=X&amp;amp;ved=2ahUKEwibx5eS3f_pAhVSHM0KHfa-CGQQ6AEwAnoECAoQAQ#v=onepage&amp;amp;q=testing%20is%20the%20engineering%20rigor%20of%20software%20neal%20ford&amp;amp;f=false&quot;&gt;Testing is the Rigor of Software Engineering (Ford)&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;martinfowler.com&#x2F;articles&#x2F;testing-culture.html&quot;&gt;Unit Testing Culture (Bland)&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.win.tue.nl&#x2F;~wstomv&#x2F;quotes&#x2F;software-requirements-specifications.html&quot;&gt;Software Requirements &amp;amp; Specifications (Jackson)&lt;&#x2F;a&gt; - linking to a quotes page,
but I’m interested in reading the full book.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;My day job involves paying down a small mountain of tech debt: the previous
infrastructure team was laid off in January shortly before COVID was a going
concern. (Ha, at the time I was worried &lt;em&gt;work&lt;&#x2F;em&gt; would stress me out!)&lt;&#x2F;p&gt;
&lt;p&gt;So, since early February I’ve been pair programming with ceej on a daily
basis. She’s observed, accurately, that left unchecked we will gleefully burn
each other out by working too much – we both find the work fun, and ratchet each
other up into working more.&lt;&#x2F;p&gt;
&lt;p&gt;Looking back at the work we’ve gotten done in the last 4 months, I’m both
impressed and a little scared. Time started turning into soup before COVID, if
I’m being honest. We started by ditching our previous attempt at a new deploy
system which was stymied by, err, organizational problems.&lt;&#x2F;p&gt;
&lt;p&gt;We wrote a deployment system inspired by npm’s deploy system – a git flow that
acts on pushes to &lt;code&gt;deploy&#x2F;&amp;lt;cluster name&amp;gt;&lt;&#x2F;code&gt;. Along the way I’ve had to learn a
&lt;em&gt;lot&lt;&#x2F;em&gt; about ASP.NET and Windows server, Terraform, and GitHub actions. We’ve
been writing a lot of Bash, which is handily one of my favorite languages, and
a little bit of Rust for tooling. I’m happy with the result! Deploys used to
take thirty minutes, or up to an hour or more. Now they take minutes. Our
infrastructure costs a third of what it used to.&lt;&#x2F;p&gt;
&lt;p&gt;Really, our success here is down to breaking down the wall between
infrastructure and developers and adopting a (now-classic) devops approach.
This let us identify application-change level wins by observing the behavior of
the system in the real world.&lt;&#x2F;p&gt;
&lt;p&gt;To illustrate: A particularly pernicious one-line bug in a C# dependency
injector, coupled with a lack of communication between developers and
infrastructure, resulted in our system maintaining 40,000 redis connections at
a time, forcing us onto the most expensive elasticache instance. The wall that
existed between devs and infrastructure kept either side from identifying the
problem: we were creating a new Redis connection pool on every request to any
endpoint. The problem? The Redis pool manager was attached to the application
as a “scoped lifestyle” dependency – that is, instantiated at request time –
and it was indirectly depended upon by every endpoint. Changing the lifestyle
of the object fixed the bug and allowed us to drop to a reasonably sized
Elasticache instance. Sorry AWS.&lt;&#x2F;p&gt;
&lt;p&gt;It’s probably the most value I’ve ever introduced at a company with a one-line
change. So that’s been good for my ego.&lt;&#x2F;p&gt;
&lt;p&gt;This has been both the easy part and the hard part, though – hard, in that it
took major organizational changes to get here; easy, in that “running server
processes on an EC2 instance” is a fairly well-understood problem, even on
Windows. Now, we’re looking at rewriting a half-decade old (or older?) C#
monolith. We’re nearly out of the woods with the infrastructure problem –
we’ve dutifully turned our technical debt into documentation debt, as we
rewrite the system to match the needs of our current engineering team.&lt;&#x2F;p&gt;
&lt;p&gt;I can’t shake the feeling that we’ve only just started hiking up the mountain,
though. This application is layered, but each layer is attached to the next
like velcro. Methods hand database IDs to each other in lieu of passing objects;
methods may expect to be invoked by multiple callers for different purposes at
different layers. I found an entire class dedicated to making integers positive.
A critical delivery modality is, essentially, type-punned on top of a completely
different delivery modality. (“What if you built a pizza delivery company by
repurposing fleet planning software built for ice cream delivery trucks?”)&lt;&#x2F;p&gt;
&lt;p&gt;Everyone I know needs a vacation, but no one can leave their house.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>a statement of intent</title>
          <pubDate>Mon, 15 Jun 2020 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://www.neversaw.us/2020/06/16/a-statement-of-intent/</link>
          <guid>https://www.neversaw.us/2020/06/16/a-statement-of-intent/</guid>
          <description xml:base="https://www.neversaw.us/2020/06/16/a-statement-of-intent/">&lt;p&gt;I’m building a new blog. It’s been 3 months since the start of quarantine.
Neighbors are in the streets protesting police brutality against Black people.
And I’m building a blog.&lt;&#x2F;p&gt;
&lt;p&gt;(I would be remiss not to say this: &lt;strong&gt;Black lives matter&lt;&#x2F;strong&gt;. Defund the
police. Dismantle white supremacy.)&lt;&#x2F;p&gt;
&lt;p&gt;Why am I doing this? Why now?&lt;&#x2F;p&gt;
&lt;p&gt;Partly to self soothe, partly because I want to build a habit I can be
proud of a few years down the line. I want to practice the crafts of
journaling, technical writing, digital scrapbooking, and self-editing.
To some degree this is an exercise in nostalgia: when I started out as a
programmer, I really loved reading the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Finger_protocol&quot;&gt;PLAN files&lt;&#x2F;a&gt; of developers of
game devs like &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ESWAT&#x2F;john-carmack-plan-archive&quot;&gt;John Carmack&lt;&#x2F;a&gt; and the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.bluesnews.com&#x2F;cgi-bin&#x2F;finger.pl?id=297&amp;amp;time=19991214135840&quot;&gt;Dynamix team&lt;&#x2F;a&gt;. I miss the
internet of that era: carving out a corner of the web and, yanno, just
talking about your interests and being a person.&lt;&#x2F;p&gt;
&lt;p&gt;Social media feels a bit like being I’m being rented a birdhouse for a bit of
my soul (&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=NhjSzjoU7OQ&quot;&gt;HT TMBG&lt;&#x2F;a&gt;, sic). I don’t really own my twitter account, my Facebook
account, or my instagram account. I pay for it with my attention. I pay for it
by contorting myself to fit the platform. I feel constrained by the medium.&lt;&#x2F;p&gt;
&lt;p&gt;I want to be &lt;strong&gt;&lt;u&gt;careful&lt;&#x2F;u&gt;&lt;&#x2F;strong&gt; about that point, because it treads dangerously
close to the gross, entitled white guy mode. I mean “constrained” in the sense
that I unconsciously consider the audience when I post on social media. It is a
performative feedback loop and the act of participating changes me. The tiny
endorphin hit of posting something popular on Twitter and seeing notifications
roll in shapes what I’m likely to post in the future. I become lopsided. I have
been lopsided.&lt;&#x2F;p&gt;
&lt;p&gt;The other problem with this rented birdhouse is that by using it, I take up
space that others might use more effectively. I’m thinking of the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.vox.com&#x2F;recode&#x2F;2020&#x2F;6&#x2F;2&#x2F;21278051&#x2F;instagram-blackout-tuesday-black-lives-matter&quot;&gt;#blackout
Tuesday&lt;&#x2F;a&gt; Instagram tag in particular. In the middle of the protests, in an
attempt to show solidarity with protesters, folks started posting black
rectangles. Contrary to their intent, this had the effect of pushing useful
information about the protests out of Instagram feeds.&lt;&#x2F;p&gt;
&lt;p&gt;Posting about tech on Twitter right now feels like taking the bullhorn out of
the hands of people who need it to yell something inane about my hobbies. I
don’t want to do that, but I do want to write about my hobbies (Especially
right now as a desperately-needed form of self-soothing.) The internet
doesn’t have to be a zero-sum game this way, but that’s how social media works.&lt;&#x2F;p&gt;
&lt;p&gt;So, I’m going to write about my hobbies here. In the interest of
becoming a less lopsided person, I’m going to write about &lt;strong&gt;all&lt;&#x2F;strong&gt; of my
hobbies here, so tech stuff will be mixed in with art stuff, and that’ll
get mixed in with links to songs I’m listening to or videos I’m watching
or articles I’m reading. If it goes well it’ll make someone happy, even
if it’s just me. Watch this space.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;how-does-it-work&quot;&gt;How does it work?&lt;&#x2F;h2&gt;
&lt;p&gt;Okay, you asked for it – let’s navel-gaze.&lt;&#x2F;p&gt;
&lt;p&gt;This blog is HTML and assets served by Cloudflare from a public AWS S3
bucket. GitHub actions are responsible for downloading a zip file full
of MarkDown from Dropbox using their API, then rendering them with
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.getzola.org&#x2F;&quot;&gt;Zola&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Elsewhere, I’ve registered a Dropbox app and provided a webhook that
calls an AWS Lambda function via their API Gateway system. The Lambda
dispatches GitHub &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;help.github.com&#x2F;en&#x2F;actions&#x2F;reference&#x2F;events-that-trigger-workflows#external-events-repository_dispatch&quot;&gt;repository dispatch&lt;&#x2F;a&gt; events whenever a file in my
Dropbox changes. I have a locally symlinked &lt;code&gt;~&#x2F;blog&lt;&#x2F;code&gt; directory, in which
I write files using NeoVim.&lt;&#x2F;p&gt;
&lt;p&gt;To the extent possible, all of the infrastructure involved is managed
through &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.terraform.io&#x2F;&quot;&gt;Terraform&lt;&#x2F;a&gt; via my &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;chrisdickinson&#x2F;infrastructure&quot;&gt;personal infrastructure&lt;&#x2F;a&gt; project.&lt;&#x2F;p&gt;
&lt;p&gt;Notably, my use of these services is not an endorsement. In particular,
GitHub is problematic for its support of ICE; AWS for its treatment of
workers. Tech is complicit in white supremacy. I use these services
because they are where my expertise lay and I want to start this
practice today. I will work to move off of problematic platforms where
I am able to, and will agitate for them to do better where I am not.
(It’s not a lot, admittedly, but.)&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>x-post: adding promise support to Node.js</title>
          <pubDate>Sat, 13 Feb 2016 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://www.neversaw.us/2016/02/13/adding-promise-support-to-core/</link>
          <guid>https://www.neversaw.us/2016/02/13/adding-promise-support-to-core/</guid>
          <description xml:base="https://www.neversaw.us/2016/02/13/adding-promise-support-to-core/">&lt;p&gt;&lt;em&gt;This was originally posted &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;medium.com&#x2F;@isntitvacant&#x2F;adding-promise-support-to-core-a4ea895ccbda&quot;&gt;on my Medium account&lt;&#x2F;a&gt;; I’ve reposted it here
for posterity.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;h1 id=&quot;adding-promise-support-to-node-js-core&quot;&gt;Adding Promise Support to Node.js Core&lt;&#x2F;h1&gt;
&lt;p&gt;Two Sundays ago, I opened a &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;nodejs&#x2F;node&#x2F;pull&#x2F;5020&quot;&gt;pull request&lt;&#x2F;a&gt; to the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;nodejs&#x2F;node&quot;&gt;&lt;code&gt;nodejs&#x2F;node&lt;&#x2F;code&gt;
repository&lt;&#x2F;a&gt; introducing support for Promises. There’s been a lot of
discussion since that point, with over 400 comments in the main thread alone.
Several discussions have split into other issues. This post will summarize the
state of the discussion as it stands.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;why-add-promises&quot;&gt;Why add Promises?&lt;&#x2F;h2&gt;
&lt;p&gt;Given that many discussions around promises turn adversarial, and that
solutions currently exist in the ecosystem, why include them in core?&lt;&#x2F;p&gt;
&lt;p&gt;While it’s true that the topic can be contentious, I believe that this is
largely due to the framing of the conversation. It is often set up as a
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Zero-sum_game&quot;&gt;zero-sum game&lt;&#x2F;a&gt;: for promise users to make gains, callback users have to lose
ground, or vice versa. However, I believe that we can frame this in a more
productive fashion. If we accept that both callbacks &lt;em&gt;and&lt;&#x2F;em&gt; promises are &lt;strong&gt;both
valid ways to build asynchronous programs&lt;&#x2F;strong&gt;, the discussion becomes about better
supporting a set of users, instead of about invalidating current practices.
Callbacks are, and will continue to be, a sturdy, reliable pattern on
top of which to build your application — as will promises. This discussion
is about making life easier for a set of our users without incurring a
cost for another set of users. It is &lt;strong&gt;not&lt;&#x2F;strong&gt; about which pattern is best.&lt;&#x2F;p&gt;
&lt;p&gt;It’s natural to ask, “Why put them in Core, if they’re already useful as-is?”&lt;&#x2F;p&gt;
&lt;p&gt;The current situation front-loads a lot of decisions onto authors of
promise-based packages. That is, if I and another package author wish to
interoperate using promises, that agreement alone is insufficient for us to
proceed.&lt;&#x2F;p&gt;
&lt;p&gt;In order to interoperate, we have to agree on the shim, implementation, and
specific version of promises in order to allow promises to safely be used
between packages. Otherwise, a tricky (and manual) process of wrapping and
unwrapping promises at the edges of the package APIs is necessary. For most
users, both of these approaches are not ideal — they just want to use native
promises, not specify all of the details. Users that wish to use different
implementations still can, but the requirement of marshalling and unmarshalling
at package boundaries become “opt-in” for the majority of users.&lt;&#x2F;p&gt;
&lt;p&gt;Compounding this situation, &lt;code&gt;async&#x2F;await&lt;&#x2F;code&gt; syntax uses promises as the
underlying mechanism for representing asynchrony. Users that wish to use this
feature, at present, will have to pick a shim, implementation, and version in
order to use this syntax with Node APIs. This introduces friction for newcomers
to Node, especially those coming from the frontend where their preferred
patterns “just work”.&lt;&#x2F;p&gt;
&lt;p&gt;Exposing a Promise API aligns our interests with the interests of our
underlying VM. Promises are already part of the Node platform, by way of V8 and
the JavaScript specification. The language has woven them into multiple
syntaxes now — from the module specification to &lt;code&gt;async&#x2F;await&lt;&#x2F;code&gt;. Some number of
our users will expect Node to provide a JavaScript runtime comparable to
browsers environments. Node has a history of trying to align these platforms —
from small things, like making the timer API look-and-feel like the
&lt;code&gt;setTimeout&lt;&#x2F;code&gt; offered by the browser, to bigger things, like providing users our
own TypedArrays in-tree before our vendored V8 offered them.&lt;&#x2F;p&gt;
&lt;p&gt;Finally, this helps heal a rift in the community. By including a core promise
API alongside the callback API, at a platform level we reinforce the notion
that both patterns are valid. It does not matter to Node which pattern suits
you best. This makes participating in the Node ecosystem &lt;em&gt;and&lt;&#x2F;em&gt; in Node core
more welcoming for promise users.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-approach&quot;&gt;The Approach&lt;&#x2F;h2&gt;
&lt;p&gt;The callback API will not change to suit the promise API. It will remain the
same. The current approach installs a promisified version of each method
alongside the original method. We have the &lt;em&gt;option&lt;&#x2F;em&gt; of exposing core’s
promisification method via &lt;code&gt;util&lt;&#x2F;code&gt;, but currently it is &lt;strong&gt;internal&lt;&#x2F;strong&gt; to core.&lt;&#x2F;p&gt;
&lt;p&gt;In presenting the promise API as a regular transformation on top of the
callback layer, we ensure that the maintanence cost of the promise layer is a
small constant added to the maintanence cost of the callback layer. We also
ensure that callback users are not paying a performance tax to support promise
users.&lt;&#x2F;p&gt;
&lt;p&gt;This approach doesn’t preclude the later inclusion of a submodule or ES2015
module-based approach to surfacing a promise API, however, that is out of scope
for this PR. In that vein, returning a promise from callback APIs when no
callback is passed is not workable because some callback APIs already have
significant return values separate from their callback value. Additionally,
a few crypto APIs are synchronous when called without a callback.&lt;&#x2F;p&gt;
&lt;p&gt;The API is experimental and if approved will land behind a flag,
&lt;code&gt;--enable-promises&lt;&#x2F;code&gt;, which will be set to &lt;code&gt;false&lt;&#x2F;code&gt; by default. Work may continue
on the API once it has landed. It would be &lt;em&gt;at least&lt;&#x2F;em&gt; one major version until
the flag is lifted, and if the API proves untenable to support it may be
removed before that point. &lt;em&gt;At least&lt;&#x2F;em&gt; two major versions later, it would become
officially supported, meaning that it will not enter LTS support until another
year after that, as I understand it. The timeline on this feature is &lt;em&gt;long&lt;&#x2F;em&gt; and
there are go&#x2F;no-go checks before it becomes supported.&lt;&#x2F;p&gt;
&lt;p&gt;The earliest a flagged version could land is the week of the 22nd, February
2016. If landed, the first go&#x2F;no-go check for unflagging would happen in
October 2016.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D3C6AA; background-color: #2D353B;&quot;&gt;&lt;code data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E69875;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span&gt; fs&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E69875;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt; require&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DBBC7F;&quot;&gt;&amp;#39;fs&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fs&lt;&#x2F;span&gt;&lt;span style=&quot;color: #859289;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt;readFilePromise&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DBBC7F;&quot;&gt;&amp;#39;some&#x2F;file&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #859289;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt;then&lt;&#x2F;span&gt;&lt;span&gt;(data&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E69875;&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  console&lt;&#x2F;span&gt;&lt;span style=&quot;color: #859289;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt;log&lt;&#x2F;span&gt;&lt;span&gt;(data)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;})&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #859289;font-style: italic;&quot;&gt;&#x2F;&#x2F; shortcut for top-level promise API&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E69875;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span&gt; {readFile}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E69875;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt; require&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DBBC7F;&quot;&gt;&amp;#39;fs&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #859289;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;promised&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt;readFile&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DBBC7F;&quot;&gt;&amp;#39;some&#x2F;file&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #859289;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt;then&lt;&#x2F;span&gt;&lt;span&gt;(data&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E69875;&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  console&lt;&#x2F;span&gt;&lt;span style=&quot;color: #859289;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt;log&lt;&#x2F;span&gt;&lt;span&gt;(data)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;})&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Only “single occurrence” async APIs provide promise variants at the moment.
In practice, this means that the following core modules will include promise
variants:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;cluster&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;child_process&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;crypto&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;dgram&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;dns&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;fs&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;zlib&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Some methods of &lt;code&gt;net.Socket&lt;&#x2F;code&gt;, &lt;code&gt;readline&lt;&#x2F;code&gt;, and &lt;code&gt;repl&lt;&#x2F;code&gt; also provide promise
variants.&lt;&#x2F;p&gt;
&lt;p&gt;The Node Core Technical Committee is planning on meeting to determine how to
move forward on this PR sometime during the week of the 22nd.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;technical-issues-proposed-solutions&quot;&gt;Technical Issues &amp;amp; Proposed Solutions&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;asyncwrap-domains-and-microtask-queue&quot;&gt;AsyncWrap, Domains and Microtask Queue&lt;&#x2F;h3&gt;
&lt;p&gt;Native promises currently interact incorrectly with Domains and AsyncWrap. This
is largely due to a lack of visibility into, and control over, V8’s “microtask
queue.” The microtask queue is a language-mandated queue of functions to be run
after the exhaustion of a JavaScript stack. In the case of promises, settling a
promise with pending handlers OR the addition of handlers to a settled promise
is mediated through the microtask queue. AsyncWrap currently relies on Node’s
ability to exert full control over the top-level entry points from event loop
to JavaScript in order to provide hooks for users to track new sources of
asynchrony. Domains also lean on this ability. The microtask queue is
&lt;strong&gt;opaque&lt;&#x2F;strong&gt; to Node — Node cannot see &lt;em&gt;when&lt;&#x2F;em&gt; functions are added to the queue,
or &lt;em&gt;specifically when&lt;&#x2F;em&gt; those functions are executed inside the queue. Given
this, it’s impossible for Node to fire the appropriate AsyncWrap hooks, or to
associate the appropriate domain with a promise handler.&lt;&#x2F;p&gt;
&lt;p&gt;I am exploring making V8’s Microtask Queue pluggable, in the style of the
&lt;code&gt;ArrayBuffer::Allocator&lt;&#x2F;code&gt; API. This should allow us to add the necessary hooks
for &lt;code&gt;AsyncWrap&lt;&#x2F;code&gt; and domains, while affording us the opportunity to consolidate
the &lt;code&gt;nextTick&lt;&#x2F;code&gt; and microtask queues into a single queue.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;promises-unsuitable-for-post-mortem-debugging-tools&quot;&gt;Promises Unsuitable for Post Mortem Debugging Tools&lt;&#x2F;h3&gt;
&lt;p&gt;The &lt;strong&gt;@nodejs&#x2F;post-mortem&lt;&#x2F;strong&gt; working group has expressed concerns about Promise
use interfering with post-mortem debugging tooling. Specifically, the reliance
on using &lt;code&gt;throw&lt;&#x2F;code&gt; as a mechanism for error propagation means that in many cases,
processes that crash on unhandled rejection will have already unwound the
stack. Unwinding the stack is highly undesirable for post-mortem purposes, both
because the stack contains stack frame parameter information (which &lt;code&gt;Error&lt;&#x2F;code&gt;
objects lack), as well as because distancing the exceptional state from the
serialization of program state means that valuable heap information may have
changed before the program was serialized.&lt;&#x2F;p&gt;
&lt;p&gt;Two mitigations are currently being investigated:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Skip intermediate non-user-installed handlers on promise rejection. This
allows the rejection to propagated to the &lt;code&gt;unhandledRejection&lt;&#x2F;code&gt; handler
without unwinding the stack. Change the default &lt;code&gt;unhandledRejection&lt;&#x2F;code&gt;
behavior so that in the absence of a user-installed
&lt;code&gt;process.on(&#x27;unhandledRejection&#x27;)&lt;&#x2F;code&gt; listener the process crashes, and investigate
making synchronous rejections signal &lt;code&gt;unhandledRejection&lt;&#x2F;code&gt; immediately, versus
the current “on next tick” behavior. These steps would combine to make
unhandled rejections work “as expected” with current post-mortem tooling,
and align unhandled rejection behavior with uncaught exception behavior.
This also makes explicit an unwritten rule already in effect for package
authors, which is “avoid leaning on unhandled rejection behavior,” since
authors cannot currently rely on consumers not to crash the program when
unhandled rejections emerge. See &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;nodejs&#x2F;post-mortem&#x2F;issues&#x2F;16#issuecomment-183144104&quot;&gt;this comment&lt;&#x2F;a&gt; for more.&lt;&#x2F;li&gt;
&lt;li&gt;Explore adding a V8 &lt;code&gt;Context&lt;&#x2F;code&gt;-associated hook for VM-originated programmer
errors, like &lt;code&gt;ReferenceError&lt;&#x2F;code&gt;, &lt;code&gt;TypeError&lt;&#x2F;code&gt;, etc. This would allow post-mortem
users to short-circuit promise (&amp;amp; try&#x2F;catch) machinery and abort on programmer
error.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;I believe that we should have a clear answer for the Post Mortem WG’s concerns
before unflagging the feature, but not necessarily before landing the PR.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;rejecting-operational-errors-hides-programmer-errors&quot;&gt;Rejecting Operational Errors Hides Programmer Errors&lt;&#x2F;h3&gt;
&lt;p&gt;Some users wish to limit the use of &lt;code&gt;try&#x2F;catch&lt;&#x2F;code&gt; to truly exceptional,
unexpected situations. Node currently caters to this need by only throwing
exceptions from asynchronous methods if the provided arguments are invalid for
the API in question. These users would prefer to continue to reserve exceptions
for unexpected behavior as they start using &lt;code&gt;async&#x2F;await&lt;&#x2F;code&gt;. Most existing shims,
and indeed the original PR, treat operational errors — &lt;code&gt;EEXIST&lt;&#x2F;code&gt;, &lt;code&gt;ENOENT&lt;&#x2F;code&gt;,
&lt;code&gt;EMFILE&lt;&#x2F;code&gt; — as rejections, which map to thrown exceptions in &lt;code&gt;async&#x2F;await&lt;&#x2F;code&gt;
programs. As an example:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D3C6AA; background-color: #2D353B;&quot;&gt;&lt;code data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E69875;&quot;&gt;async&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E67E80;&quot;&gt; function&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt; reader&lt;&#x2F;span&gt;&lt;span&gt; (filename) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E67E80;&quot;&gt;  try&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E69875;&quot;&gt;    const&lt;&#x2F;span&gt;&lt;span&gt; data&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E69875;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E67E80;&quot;&gt; await&lt;&#x2F;span&gt;&lt;span&gt; fs&lt;&#x2F;span&gt;&lt;span style=&quot;color: #859289;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt;readFilePromise&lt;&#x2F;span&gt;&lt;span&gt;(filename)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E67E80;&quot;&gt; catch&lt;&#x2F;span&gt;&lt;span&gt; (err) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #859289;font-style: italic;&quot;&gt;    &#x2F;&#x2F; could be a programmer error (&amp;quot;filename was undefined&amp;quot;) or&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #859289;font-style: italic;&quot;&gt;    &#x2F;&#x2F; it could be an operational error (&amp;quot;filename does not exist&amp;quot;).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;For many users the above example represents acceptable use and is analogous to
the &lt;code&gt;fs.readFileSync&lt;&#x2F;code&gt; API. Others wish to keep programmer errors separated from
operation errors.&lt;&#x2F;p&gt;
&lt;p&gt;There are three potential mitigations:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;groundwater&#x2F;nodejs-symposiums&#x2F;pull&#x2F;5#issuecomment-181952520&quot;&gt;Via &lt;strong&gt;@littledan&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt;: When implementing the Promise API, use destructuring to
return &lt;code&gt;[err, value]&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;groundwater&#x2F;nodejs-symposiums&#x2F;pull&#x2F;5#issuecomment-182238021&quot;&gt;Via &lt;strong&gt;@zkat&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt;: Allow a &lt;code&gt;recovery&lt;&#x2F;code&gt; object to be passed to Promise-wrapped
functions in order to specify behavior in case of operational errors.&lt;&#x2F;li&gt;
&lt;li&gt;If implemented, the first mitigation approach from the post-mortem section
would separate programmer errors from operationals error by crashing the
programs lacking a &lt;code&gt;process.on(&#x27;unhandledRejection&#x27;)&lt;&#x2F;code&gt; handler on synchronous
rejection.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Examples follow:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D3C6AA; background-color: #2D353B;&quot;&gt;&lt;code data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #859289;font-style: italic;&quot;&gt;&#x2F;&#x2F; Mitigation 1 with async&#x2F;await&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #859289;font-style: italic;&quot;&gt;&#x2F;&#x2F; - err may be a programmer error _or_ a operational error&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E69875;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span&gt; [err, value]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E69875;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E67E80;&quot;&gt; await&lt;&#x2F;span&gt;&lt;span&gt; fs&lt;&#x2F;span&gt;&lt;span style=&quot;color: #859289;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt;readFilePromise&lt;&#x2F;span&gt;&lt;span&gt;(path)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #859289;font-style: italic;&quot;&gt;&#x2F;&#x2F; Mitigation 1 with raw promises&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fs&lt;&#x2F;span&gt;&lt;span style=&quot;color: #859289;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt;readFilePromise&lt;&#x2F;span&gt;&lt;span&gt;(path)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #859289;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt;then&lt;&#x2F;span&gt;&lt;span&gt;(([err, value])&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E69875;&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;})&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #859289;font-style: italic;&quot;&gt;&#x2F;&#x2F; Mitigation 2 with async&#x2F;await&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #859289;font-style: italic;&quot;&gt;&#x2F;&#x2F; - throws exception on bad &amp;quot;path&amp;quot; param&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E69875;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span&gt; value&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E69875;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E67E80;&quot;&gt; await&lt;&#x2F;span&gt;&lt;span&gt; fs&lt;&#x2F;span&gt;&lt;span style=&quot;color: #859289;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt;readFilePromise&lt;&#x2F;span&gt;&lt;span&gt;(path, {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt;  ENOENT&lt;&#x2F;span&gt;&lt;span&gt; () {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E67E80;&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D699B6;&quot;&gt; null&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;})&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #859289;font-style: italic;&quot;&gt;&#x2F;&#x2F; Mitigation 2 with raw promises&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fs&lt;&#x2F;span&gt;&lt;span style=&quot;color: #859289;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt;readFilePromise&lt;&#x2F;span&gt;&lt;span&gt;(path, {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt;  ENOENT&lt;&#x2F;span&gt;&lt;span&gt; () {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E67E80;&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D699B6;&quot;&gt; null&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;})&lt;&#x2F;span&gt;&lt;span style=&quot;color: #859289;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt;then&lt;&#x2F;span&gt;&lt;span&gt;(value&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E69875;&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;})&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #859289;font-style: italic;&quot;&gt;&#x2F;&#x2F; Mitigation 3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #859289;font-style: italic;&quot;&gt;&#x2F;&#x2F; - throws operational errors (ENOENT)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #859289;font-style: italic;&quot;&gt;&#x2F;&#x2F; - when passed a bad path, crashes the program (regardless&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #859289;font-style: italic;&quot;&gt;&#x2F;&#x2F;   of try&#x2F;catch)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E69875;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span&gt; data&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E69875;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E67E80;&quot;&gt; await&lt;&#x2F;span&gt;&lt;span&gt; fs&lt;&#x2F;span&gt;&lt;span style=&quot;color: #859289;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A7C080;&quot;&gt;readFilePromise&lt;&#x2F;span&gt;&lt;span&gt;(path)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;where-to-participate&quot;&gt;Where to Participate&lt;&#x2F;h2&gt;
&lt;p&gt;The &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;nodejs&#x2F;node&#x2F;pull&#x2F;5020&quot;&gt;main PR&lt;&#x2F;a&gt; is the best place to participate. I’ve added a FAQ at the top
with links to specific responses to make navigating the thread a bit easier. If
you don’t have the time to read the entire thread, please continue share your
concerns and I will attempt to address and direct them as they come in. If you’re
nervous about wading into the thread, please feel free to contact me directly
at christopher.s.dickinson at gmail dot com, or via Twitter &lt;strong&gt;@isntitvacant&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Thanks for your time!&lt;&#x2F;p&gt;
</description>
      </item>
    </channel>
</rss>
