alecb.me
https://alecb.me
Valuing startup equity<p>The standard answer is that you should value startup equity at \$0.</p>
<p>This is dumb and obviously wrong.
<em>No one</em> values their startup equity at \$0. Here’s how to check: ask
someone if they’ll give you their startup equity in exchange for \$0. If
they won’t, they value their equity at more than \$0.</p>
<p>Maybe ask them if they’ll give it up for \$1? They still won’t, so they must value it at more than \$1. \$1,000? For most people, still no. \$1,000,000? For a lot of people, yes.</p>
<p>I’m being cranky; I get that the ethos behind “value startup equity at \$0” is something like “don’t <em>expect</em> that your equity will be worth anything” or “there’s a high, probably >50% chance that your equity will be worth \$0”.</p>
<p>This is true, but “value your equity at \$0” is a bad general way of phrasing this. When you’re trying to see if you can afford to buy a house this year, yes, startup equity is worth \$0. If you’re trying to decide if you’re being shafted by accepting 0.001% equity in a startup you’re set on joining, startup equity is not worth \$0.</p>
<h1 id="break-even-valuations">Break-even valuations</h1>
<p>(The rest of this post is mostly about VC-backed startups.)</p>
<p>In general, you value equity based on how successful you think the company will be. I try to look specifically at opportunity costs and break-even points:</p>
<ul>
<li>I could be making \$A working at some large tech company</li>
<li>Instead, a startup is offering me \$B and X% equity</li>
<li>You have an opportunity cost of \$A - \$B, which is probably positive
<ul>
<li>If it’s not, go to <a href="https://www.levels.fyi/">levels.fyi</a>, convince yourself you could probably get a job at a big tech co if you put your mind to it, and use that number instead</li>
</ul>
</li>
<li>Now, see what value the startup would have to be worth for your X% equity to cover that cost, decide how likely you think that is, and make a decision based on that.</li>
</ul>
<p>For example:</p>
<ul>
<li><a href="https://www.levels.fyi/salary/Google/SE/L3/">An L3 at Google makes about \$180k/year</a>
<ul>
<li>(This includes stock, but that’s fine, because Google stock is basically just cash, unlike a startup’s stock.)</li>
</ul>
</li>
<li>Say a startup offers you \$80k/year, plus .01% equity <em>over 4 years</em>
<ul>
<li>That’s .01% / 4 = .0025% equity per year</li>
</ul>
</li>
<li>Your opportunity cost per year is \$180k - \$80k = \$100k</li>
<li>In order for your .0025% to cover that \$100k, the company would need to be worth \$100k / .0025% = \$4 billion</li>
<li>How likely do you think it is that this company will be worth at least \$4 billion?
<ul>
<li>Remember that this is the <em>break-even</em> point. You’re taking a risk by joining the startup, so ideally your return is better than break-even.</li>
</ul>
</li>
</ul>
<p>On the other hand, if the company offered you:</p>
<ul>
<li>.1% equity, your break-even is \$400 million</li>
<li>1% equity, \$40 million</li>
<li>5% equity, \$8 million</li>
</ul>
<p>Similarly, if they kept the equity at .01% but raised the salary to:</p>
<ul>
<li>\$100,000, your break-even is \$3.2 billion</li>
<li>\$120,000, \$2.4 billion</li>
<li>\$170,000, \$400 million</li>
<li>\$175,000, \$200 million</li>
</ul>
<p class="info">At \$180,000, you’ve already broke even, because at that point you have “no risk”. Of course that’s not quite true, a startup is always going to carry more risk than a stable company (i.e., that you’ll lose your job suddenly).</p>
<p>This model isn’t perfect, but I like it because it boils down to a
single number (the break-even valuation) before having to introduce any
probabilistic reasoning. It doesn’t tell you anything about how to decide if
a company is actually going to be worth \$X, but at least quantifies the
situation in a way that I think makes things more accessible and easier to
reason about.</p>
<p class="info">The break-even valuation is what people are calculating when they infer valuations based on venture capital investment. If a VC invests \$X for Y% of a company, their “valuation” of the company is \$X / Y%. A startup employee’s “valuation” in this way is almost always going to be way higher than the VC valuation (the VC is getting a better deal than employees).</p>
<p class="info">One thing I skipped: usually, startups aren’t giving you shares directly but are giving you <a href="https://www.investopedia.com/terms/s/stockoption.asp">options</a>: the option to buy a share at some set price/share \$X, the “strike price”. You should in theory factor this into your math, but the opportunity costs are usually so much higher than the strike that it doesn’t change things too much.</p>
<h1 id="dilution">Dilution</h1>
<p><a href="https://www.investopedia.com/terms/d/dilution.asp">Dilution</a> unfortunately
complicates things.</p>
<p>When a company says they’re giving you X%, what they mean is that they’re
giving you an amount of shares that, <em>as of right now</em>, represents X% of the
company. But the total number of shares can increase over time, which means
the % that your shares represent goes down.</p>
<p>The main way new shares get created is during fundraising: the company wants
money from investors, investors want shares in the company, so the company
creates new shares to give to the investors.</p>
<p>How much you get diluted, then, has to do with:</p>
<ol>
<li>How much money the company needs/wants.</li>
<li>How highly investors value the company.</li>
</ol>
<p>Which are both probably related to how well the company is doing and how old
it is.</p>
<p>My rule of thumb has been to just to assume some ~standard amount of dilution
per round, and make a guess at number of rounds to exit. 20% per round is a
figure I’ve heard. I once found a site that had some more concrete data on
this… I’ll be sure to link to it if I ever find it again.</p>
Tue, 26 May 2020 00:00:00 +0000
https://alecb.me/valuing-startup-equity
https://alecb.me/valuing-startup-equityPutnam 2017 A1<p><a href="https://www.maa.org/sites/default/files/pdf/Putnam/Competition_Archive/2017PutnamProblemsSolutions.pdf">Putnam 2017 A1</a>:</p>
<blockquote>
<p>Let $S$ be the “smallest” set (i.e., any other set is a superset) of positive integers such that:</p>
<ol>
<li>$2 \in S$</li>
<li>$n^2 \in S \implies n \in S$</li>
<li>$n \in S \implies (n+5)^2 \in S$</li>
</ol>
<p>Which positive integers aren’t in $S$?</p>
</blockquote>
<p>Since one rule has a square and the other undoes a square, it’s tempting to
combine them:</p>
<div>
\[n \in S \underset{\text{rule 3}}{\implies} (n+5)^2 \in S \underset{\text{rule 2}}{\implies} n + 5 \in S \]
</div>
<p>If $n$ is in $S$, $n+5$ is also in $S$. This
already tells us a lot. First we know that 2 + 5 = 7 is in $S$,
that 7 + 5 = 12 is in $S$, and so on: 2 more than any multiple of 5 is in
$S$: 2, 7, 12, 17, 22, 27, 32, …</p>
<p>But more generally, it hints that we maybe only really need to worry about
things in $S$ modulo 5. For example, if we knew that 3, 4, 5, and 6 were
also in $S$, we would know that $S$ has to contain all numbers
greater than 2.</p>
<hr />
<p>Given the mod 5 hint, let’s take a look at what our two operations do mod 5.</p>
<p>What does squaring do mod 5?</p>
<div>
\[
\begin{align*}
0^2 &\equiv 0 \pmod 5 \\
1^2 &\equiv 1 \pmod 5 \\
2^2 &\equiv 4 \pmod 5 \\
3^2 \equiv 9 &\equiv 4 \pmod 5 \\
4^2 \equiv 16 &\equiv 1 \pmod 5 \\
\end{align*}
\]
</div>
<p>0 stays at 0, 1 stays at 1, 2 goes to 4, 3 goes to 4, and 4 goes to 1.</p>
<p><img src="/putnam-2017-a1-diagram.png" alt="" /></p>
<p>And because adding 5 doesn’t change where we are mod 5, the picture for
$(n+5)^2$ is the same.</p>
<p>Two interesting things to note:</p>
<ul>
<li>0 is an island all by itself</li>
<li>Everything else eventually gets to and stays at 1</li>
</ul>
<p>This is powerful. We know from before that if we get something that’s 1 mod 5 into
$S$, we can then get any sufficiently large number that’s 1 mod 5 into
$S$. And because repeatedly squaring something that’s 1, 2, 3, or 4 mod 5
will get us to something large that’s 1 mod 5, if we can get
<em>anything</em> that’s 1 mod 5 into $S$, we can keep applying squareroots to
get to 1, 2, 3, or 4 mod 5.</p>
<p class="info">A wrinkle is that we can’t get 1 itself to be in $S$. Normally squaring
an integer makes it bigger, which allows us to be “sufficiently big”, but the
exception is 1, which is itself squared. This, combined with the fact that
rule 3 only ever forces bigger things into $S$, makes it clear that we
can’t ever force 1 into $S$.</p>
<p>Well, starting with 2, if we apply rule 3 twice, we’ll get something that’s 1
mod 5. This is implied by the diagram above, but specifically, we have:</p>
<div>
\[
\begin{align*}
&(2+5)^2 = 7^2 = 49 \in S \\
\implies &(49+5)^2 = 54^2 = 2916 \in S \\
\end{align*}
\]
</div>
<p>From here, we can keep adding 5 to get to any number larger than 2916 that’s
also 1 mod 5, which then can get us to 3, 4, and 6 via squarerooting. Again,
we know this must work because of the diagram and because squaring makes
things bigger, but specifically:</p>
<div>
\[
\begin{align*}
6561 \in S \implies 81 \in S \implies 9 \in S &\implies 3 \in S \\
65536 \in S \implies 256 \in S \implies 16 \in S &\implies 4 \in S \\
1679616 \in S \implies 1296 \in S \implies 36 \in S &\implies 6 \in S \\
\end{align*}
\]
</div>
<p>We had $2 \in S$ from before, so this forces everything that’s not a
multiple of 5 into $S$ (except 1). But have we proved that it’s
impossible for rules 2 and 3 to force a multiple of 5 into the set? Let’s
take another look at the diagram:</p>
<p><img src="/putnam-2017-a1-diagram.png" alt="" /></p>
<p>This is the diagram for squaring mod 5, but if we reverse the arrows, we get
the diagram for squarerooting mod 5. The important thing to note is that even
if you reverse the arrows, 0 is totally isolated: the only way for something
squared or something squarerooted to be a multiple of 5 is if the thing you
started with was a multiple of 5.</p>
<p>And we’re done! $S$ <em>must</em> contain everything except 1 and multiples of
5.</p>
<p class="footnote">Inspired by <a href="https://www.youtube.com/watch?v=WFTw_3J2HU4">Michael Penn’s video</a>. Drawings by <a href="https://excalidraw.com/">Excalidraw</a>.</p>
Sat, 23 May 2020 00:00:00 +0000
https://alecb.me/putnam-2017-a1
https://alecb.me/putnam-2017-a1Is $n$ a multiple of 5 if $n^2$ is?<p>Say $n$ is a natural number and $n^2$ is a multiple of 5. Does that
mean $n$ is a multiple of 5?</p>
<p>This seems to be true. If we look at squares:</p>
<div>
\[
\begin{align*}
2^2 &= 4 & 3^2 &= 9 & 4^2 &= 16 & \mathbf{5^2} &\mathbf= \mathbf{25} \\
6^2 &= 36 & 7^2 &= 49 & 8^2 &= 64 & 9^2 &= 81 \\
\mathbf{ {10}^2 }&\mathbf= \mathbf{100} & {11}^2 &= 121 & {12}^2 &= 144 & {13}^2 &= 169 \\
{14}^2 &= 196 & \mathbf{ {15}^2 }&\mathbf= \mathbf{225} & {16}^2 &= 256 & {17}^2 &= 289 \\
{18}^2 &= 324 & {19}^2 &= 361 & \mathbf{ {20}^2 }&\mathbf= \mathbf{400} & {21}^2 &= 441\\
\end{align*}
\]
</div>
<p>Seems to be that $n^2$ is a multiple of 5 only when $n$ is. Can we prove it?</p>
<p>If $n^2$ is a multiple of 5, then $n^2 = 5k$ for some $k \in
\mathbb{N}$. Then $n = 5k/n = 5(k/n)$, which means $n$ is a multiple of
5 as long as $k/n$ is an integer… which is true if $k$ is a multiple of
$n$. Is $k$ a multiple of $n$?</p>
<p>Well, $k = n^2/5 = n(n/5)$, which means $k$ is a multiple of $n$
if $n$ is a multiple of 5… ah, we’re in a loop here. Let’s try
something else.</p>
<hr />
<p>Maybe we need to use something specific about 5. Is this property true for all
numbers? What about 4: is $n$ a multiple of 4 whenever $n^2$ is?</p>
<div>
\[
\begin{align*}
\mathbf{2^2} &\mathbf= \mathbf{4} & 3^2 &= 9 & \mathbf{4^2} &\mathbf= \mathbf{16} & 5^2 &= 25 \\
\mathbf{6^2} &\mathbf= \mathbf{36} & 7^2 &= 49 & \mathbf{8^2} &\mathbf= \mathbf{64} & 9^2 &= 81 \\
\mathbf{ {10}^2} &\mathbf= \mathbf{100} & {11}^2 &= 121 & \mathbf{ {12}^2} &\mathbf= \mathbf{144} & {13}^2 &= 169 \\
\end{align*}
\]
</div>
<p>No! 4, 36, and 100 are multiples of 4, but 2, 6, and 10 are not multiples of 4.</p>
<p>There must be something different about 5 that makes this work for it. 5 is prime… can that help?</p>
<p>The <a href="https://en.wikipedia.org/wiki/Fundamental_theorem_of_arithmetic">fundamental theorem of
arithmetic</a>
is often handy when dealing with primes. Let’s represent $n$ as its prime
factorization:</p>
<div>
\[
n = p_1p_2\cdots p_n
\]
</div>
<p>Then:</p>
<div>
\[
n^2 = p_1^2p_2^2\cdots p_n^2
\]
</div>
<p>If $n^2$ is a multiple of 5, then 5 must be in $n^2$’s prime
factorization. Which means 5 must be one of the primes $p_i$, which in
turn means that $n$ itself must also have $5$ as a factor. Woohoo!</p>
<hr />
<p>So we’ve proved this is true for 5. And, clearly, it’s true for any other
prime number. We know it’s not true for 4. Is this true <em>only</em> for primes?
Let’s look at 6:</p>
<div>
\[
\begin{align*}
2^2 &= 4 & 3^2 &= 9 & 4^2 &= 16 & {5^2} &= {25} \\
\mathbf{6^2} &\mathbf= \mathbf{36} & 7^2 &= 49 & 8^2 &= 64 & 9^2 &= 81 \\
{10}^2 &= {100} & {11}^2 &= 121 & \mathbf{12}^2 &\mathbf= \mathbf{144} & {13}^2 &= 169 \\
{14}^2 &= 196 & {15}^2 &= {225} & {16}^2 &= 256 & {17}^2 &= 289 \\
\mathbf{18}^2 &\mathbf= \mathbf{324} & {19}^2 &= 361 & { {20}^2 }&= {400} & {21}^2 &= 441\\
\end{align*}
\]
</div>
<p>Hm… seems like this actually might be true for 6, even though 6 isn’t
prime. Can we prove it? It turns out we can make a pretty similar argument:</p>
<p>If $n^2 = p_1^2p_2^2\cdots p_n^2$ is a multiple of 6, 6 <em>won’t</em> be any of
the $p_i$ (because 6 isn’t a prime). But 6 = 2*3, which means one of the
$p_i$ must be 2 and another of the $p_i$ must be 3.</p>
<p class="info">In case it isn’t clear why: if $m$ is a multiple of 6, then $m = 6k = 2\cdot3\cdot k$. We can prime-factorize $k = q_1q_2\cdots q_n$, which means $m = 2\cdot3\cdot q_1\cdot\cdots\cdot q_n$.</p>
<p>This means $n$’s prime factorization contains 2 and 3, which means
$n$ is a multiple of 6. QED</p>
<hr />
<p>So hang on… since every number has a prime factorization, can’t we make
this argument for any number? What goes wrong with 4?</p>
<p>If $n^2 = p_1^2p_2^2\cdots p_n^2$ is a multiple of 4, since 4 = 2*2, one
of the $p_i$ must be 2 and another of the $p_i$ must be… ah, 2
again. So we can’t actually prove that $n$ is a multiple of 4, but we
<em>can</em> prove that it’s a multiple of 2.</p>
<p>4 happens to be a perfect square, but we’ll actually run into this problem
for other numbers too. 12 = 2*2*3. If $n^2 = p_1^2p_2^2\cdots p_n^2$ is
a multiple of 12, one of the $p_i$ is 2, one of the $p_i$ is 2
(again), and one of the $p_i$ is 3. So all we know for sure is that
$n$ is a multiple of 2*3 = 6.</p>
<p>So it’s clear that this property holds for any $k$ that doesn’t have any
repeats in its prime-factorization. These numbers are called
<a href="https://en.wikipedia.org/wiki/Square-free_integer">square-free</a>.</p>
<p>But even if our number isn’t square-free (like 4, or 12), we can still say
something, which is that $n$ is a multiple of the number that you get when
you get rid of all the duplicates in $k$’s prime factorization. The term
for this is an integer’s
<a href="https://en.wikipedia.org/wiki/Radical_of_an_integer"><em>radical</em></a>:</p>
<div>
\[
\begin{align*}
\operatorname{rad}({4}) &= \operatorname{rad}({2^2}) = 2 \\
\operatorname{rad}({5}) &= 5 \\
\operatorname{rad}({6}) &= \operatorname{rad}({2\cdot3}) = 2\cdot3 = 6 \\
\operatorname{rad}({12}) &= \operatorname{rad}({2^23}) = 2\cdot3 = 6 \\
\end{align*}
\]
</div>
<p>So the most general thing we can say is: if $n^2$ is a multiple of $k$, $n$ is a multiple of $\operatorname{rad}(k)$.</p>
<p class="footnote">Inspired by <a href="https://www.youtube.com/watch?v=WFTw_3J2HU4">Putnam 2017 A1</a>.</p>
Sat, 23 May 2020 00:00:00 +0000
https://alecb.me/n-squared-divisors
https://alecb.me/n-squared-divisorsPermutation Pairity<p>A quick proof that if two sequences of swaps lead to the same overall
<a href="https://en.wikipedia.org/wiki/Permutation">permutation</a>, the number of swaps
must both be even or both be odd (i.e., the number of swaps has the same
parity).</p>
<hr />
<p>First note that any permutation can be broken up into cycles, where a cycle
is just N positions all swapping places with each other in a circle.</p>
<p>To see this for any given permutation, just
start at the first position, note where it goes, then note where that
position goes, and keep going, until you get back to 1. If there are any
positions you haven’t touched yet, start the process again starting there.</p>
<p>For example:</p>
<!-- https://excalidraw.com/#json=5722559043600384,htxQdOvoCwEfUDLHA5wWvw -->
<ul>
<li>
<p>The permutation of 4 elements where everything stays the same is made up of
four cycles: 1 swapping with itself, 2 swapping with itself, 3 swapping with
itself, and 4 swapping with itself</p>
<p><img src="/permutation-1.png" alt="" /></p>
</li>
<li>
<p>Here, 1 maps to 2, 2 maps to 3, 3 maps to 4, and 4 maps to 1. So this is the single cycle 1 → 2 → 3 → 4</p>
<p><img src="/permutation-2.png" alt="" /></p>
</li>
<li>
<p>In this permutation:</p>
<p><img src="/permutation-3.png" alt="" /></p>
<ul>
<li>1 maps to 2, 2 maps to 5, 5 maps 1; this is the cycle (1 → 2 → 5)</li>
<li>4 maps to 3 and 3 maps to 4, which is the cycle (3 → 4)</li>
</ul>
</li>
</ul>
<p>Importantly, there is just one, unique way to break up any given permutation into cycles.</p>
<hr />
<p>Now, note that if we take a permutation and swap any two elements, a and b, one of two things happens:</p>
<ul>
<li>either a and b were already part of the same cycle, in which case their cycle will split into two</li>
<li>or, a and b were part of two different cycles, in which case their cycles will join together</li>
</ul>
<p><img src="/permutation-swap-1.png" alt="" /></p>
<p><img src="/permutation-swap-2.png" alt="" /></p>
<!-- https://excalidraw.com/#json=5719836663480320,0sshvSNnOV66tzwx29uoNQ) -->
<p>Importantly, the number of cycles always changes (up or down) by exactly one.</p>
<p>And that’s all we need! If we can build up a permutation with N swaps, adding
an (N+1)st swap will change the number of cycles by 1, resulting in a
different permutation. We need at least an (N+2)nd swap to get us back to the
original permutation.</p>
<p>An (N+2)nd swap will either get us back to the correct cycle count, <em>or</em>, put
us 2 away from the correct cycle count, which means we need at least an
(N+3)rd and an (N+4)th swap to get back to the correct count.</p>
<p>No matter what happens, you always need to add an even number of swaps to get
back to the right count, which means the total number of swaps will remain at
whatever pairity it was to begin with.</p>
<p class="footnote">Inspired by <a href="https://youtu.be/YI1WqYKHi78">Numberphile</a>. Drawings by <a href="https://excalidraw.com/">Excalidraw</a>.</p>
Sun, 26 Apr 2020 00:00:00 +0000
https://alecb.me/permutation-parity
https://alecb.me/permutation-parityThings I use to use git<h1 id="new"><code class="language-plaintext highlighter-rouge">new</code></h1>
<p><code class="language-plaintext highlighter-rouge">new</code> creates a new branch based on current (i.e., up-to-date) <code class="language-plaintext highlighter-rouge">origin/master</code>:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">function </span>new<span class="o">()</span> <span class="o">{</span>
git fetch <span class="nt">-q</span> origin master
git branch <span class="s2">"</span><span class="k">${</span><span class="nv">1</span>:?<span class="k">}</span><span class="s2">"</span> origin/master
git checkout <span class="s2">"</span><span class="k">${</span><span class="nv">1</span>:?<span class="k">}</span><span class="s2">"</span>
<span class="o">}</span>
</code></pre></div></div>
<h1 id="master"><code class="language-plaintext highlighter-rouge">master</code></h1>
<p><code class="language-plaintext highlighter-rouge">master</code> checks out current <code class="language-plaintext highlighter-rouge">origin/master</code> (as a detached head). (See also
<a href="/dont-checkout-master">“Don’t checkout master locally”</a>.)</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">function </span>master<span class="o">()</span> <span class="o">{</span>
git fetch <span class="nt">-q</span> origin master
git checkout origin/master
<span class="o">}</span>
</code></pre></div></div>
<h1 id="stowunstow"><code class="language-plaintext highlighter-rouge">stow</code>/<code class="language-plaintext highlighter-rouge">unstow</code></h1>
<p>Like a branch-specific “stash”. I think many people initially assume <code class="language-plaintext highlighter-rouge">git
stash</code> will behave kind of like this, but the stash is shared across all
branches.</p>
<p><code class="language-plaintext highlighter-rouge">stow</code> either saves your pending changes in a commit with message “stow”,
or, if you’ve already stowed changes, ammends the stow commit with your new
changes.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">function </span>stow<span class="o">()</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">[[</span> <span class="si">$(</span>git log <span class="nt">-1</span> <span class="nt">--format</span><span class="o">=</span>%B<span class="si">)</span> <span class="o">==</span> <span class="s2">"stowed"</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then
</span>git commit <span class="nt">-a</span> <span class="nt">--amend</span> <span class="nt">--date</span><span class="o">=</span>now <span class="nt">--no-edit</span>
<span class="k">else
</span>git commit <span class="nt">-a</span> <span class="nt">-m</span> stowed
<span class="k">fi</span>
<span class="o">}</span>
</code></pre></div></div>
<p><code class="language-plaintext highlighter-rouge">unstow</code> undoes a stowed commit (by resetting to the commit before it):</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">function </span>unstow<span class="o">()</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">[[</span> <span class="si">$(</span>git log <span class="nt">-1</span> <span class="nt">--format</span><span class="o">=</span>%B<span class="si">)</span> <span class="o">==</span> stowed <span class="o">]]</span><span class="p">;</span> <span class="k">then
</span>git reset @^
<span class="k">else
</span><span class="nb">echo</span> <span class="s2">"Nothing to unstow"</span>
<span class="k">fi</span>
<span class="o">}</span>
</code></pre></div></div>
<h1 id="changes"><code class="language-plaintext highlighter-rouge">changes</code></h1>
<p>What changes have been made from <code class="language-plaintext highlighter-rouge">origin/master</code>?</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git config <span class="nt">--global</span> alias.changes <span class="s1">'diff origin/master...'</span>
</code></pre></div></div>
<h1 id="update"><code class="language-plaintext highlighter-rouge">update</code></h1>
<p>Rebase your commit(s) onto master:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git config <span class="nt">--global</span> alias.update <span class="s2">"pull origin master --rebase"</span>
</code></pre></div></div>
<h1 id="save"><code class="language-plaintext highlighter-rouge">save</code></h1>
<p>This is kind of similar to <a href="#stowunstow"><code class="language-plaintext highlighter-rouge">stow</code></a>. If you don’t currently have
a change “in progress”, it creates a new commit. Otherwise, it just ammends
the “in progress” commit. “In progress” is defined as “not an ancestor of <code class="language-plaintext highlighter-rouge">origin/master</code>”.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">function </span>save<span class="o">()</span> <span class="o">{</span>
<span class="k">if </span>git merge-base <span class="nt">--is-ancestor</span> HEAD origin/master<span class="p">;</span> <span class="k">then
</span>git commit <span class="nt">-va</span>
<span class="k">else
</span>git commit <span class="nt">-va</span> <span class="nt">--amend</span> <span class="nt">--date</span><span class="o">=</span>now <span class="nt">--no-edit</span>
<span class="k">fi</span>
<span class="o">}</span>
</code></pre></div></div>
<p><em>TODO: Make this work better with branch pipeling.</em></p>
<h1 id="branch-cleanup"><code class="language-plaintext highlighter-rouge">branch-cleanup</code></h1>
<p>Deletes any branches that have already been merged onto master, where
“merged” means either that the branch has no delta from master, or that a
commit equivalent to the branch’s latest is already on master:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">function </span>branch-cleanup<span class="o">()</span> <span class="o">{</span>
git fetch <span class="nt">--all</span> <span class="nt">--quiet</span>
<span class="k">for </span>b <span class="k">in</span> <span class="si">$(</span>git <span class="k">for</span><span class="nt">-each-ref</span> refs/heads <span class="nt">--format</span><span class="o">=</span><span class="s2">"%(refname:short)"</span><span class="si">)</span><span class="p">;</span> <span class="k">do
if</span> <span class="o">[[</span> <span class="o">!</span> <span class="si">$(</span>git cherry <span class="nt">-v</span> origin/master <span class="s2">"</span><span class="k">${</span><span class="nv">b</span>:?<span class="k">}</span><span class="s2">"</span> | <span class="nb">grep</span> <span class="s2">"^+"</span><span class="si">)</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then
</span>git branch <span class="nt">-D</span> <span class="s2">"</span><span class="k">${</span><span class="nv">b</span>:?<span class="k">}</span><span class="s2">"</span>
<span class="k">elif </span>git diff <span class="nt">--exit-code</span> <span class="nt">--quiet</span> <span class="s2">"origin/master...</span><span class="k">${</span><span class="nv">b</span>:?<span class="k">}</span><span class="s2">"</span><span class="p">;</span> <span class="k">then
</span>git branch <span class="nt">-D</span> <span class="s2">"</span><span class="k">${</span><span class="nv">b</span>:?<span class="k">}</span><span class="s2">"</span>
<span class="k">fi
done</span>
<span class="o">}</span>
</code></pre></div></div>
Tue, 25 Feb 2020 00:00:00 +0000
https://alecb.me/git-aliases
https://alecb.me/git-aliasesWaterfall, and software as a blueprint<p>Here’s some guesses as to why waterfall is a thing and why it doesn’t work
well for developing software.</p>
<p><em>tl;dr</em>:</p>
<ul>
<li>In the real world you first design things and then implement the designs.</li>
<li>The magic of software is that implementing is ~free.</li>
<li>We didn’t quite get this, and tried to split what’s really a “design” step
into two “design” and “implement” steps.</li>
</ul>
<hr />
<p>I don’t know much about making hardware but that won’t stop me from
speculating.</p>
<p>Building a physical thing takes time. Mass-producing a lot of physical
things takes a lot of time, and also a lot of up-front work. You need to:</p>
<ul>
<li>Get factories ready and configured correctly</li>
<li>Prepare to have enough supply of the things you’ll need to build
the thing</li>
<li>Make sure that things being built actually work, without
side-effects, and that they do what you wanted them to do</li>
<li>Y’know, uh… other hardware stuff?</li>
</ul>
<p>Because of all this effort, before you start mass-producing a thing, you need
to be really sure you’re doing it right. Finding out part-way through the
process of mass-producing that you got something wrong is really expensive.</p>
<p>Faced with this, it makes sense to break your process up into two steps:</p>
<ol>
<li>Come up with very specific blueprints of what you’re making.</li>
<li>Use the blueprint to make a bunch of instances of the thing.</li>
</ol>
<p>Note that the output from step 1 here isn’t a “rough plan” of what to do.
It’s a very specific, precise blueprint. Getting even minor details of things
wrong in step #2 is very expensive.</p>
<p>Thus, the first step is probably going to involve a lot of trial and error to
make sure that the blueprint actually makes sense. If you’re doing it well,
it may involve a lot of speaking with the people who are going to actually
use the blueprint to mass-produce things and iterating with them.</p>
<p>But the magic of software is that there’s no step #2.</p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">The act of describing a program in unambiguous detail and the act of programming are one and the same.</p>— Kevlin Henney (@KevlinHenney) <a href="https://twitter.com/KevlinHenney/status/3361631527?ref_src=twsrc%5Etfw">August 17, 2009</a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<p>Writing software is <em>exactly</em> producing an unambiguous description of how to
do a thing. Source code <em>is</em> a blueprint: it’s just a blueprint implemented
not by factories and people on assembly lines but by CPUs.</p>
<p>Any kind of English-language/block-diagram based specification of a software
system that tries to be unambiguous but can’t actually be executed by a CPU is:</p>
<ul>
<li>at worst, too imprecise to be considered a “blueprint” for the purposes of
this process</li>
<li>at best, a lot of extra work with not much benefit vs. just expressing it as
source code</li>
</ul>
<p>Once you do have the software, “implementing” it in a mass-production kind of
way is just a matter of copying bits. You obviously still need machines to
execute the code, devops is definitely a thing, etc., but it’s:</p>
<ul>
<li>a) Still much cheaper than mass-producing physical things, but more importantly:</li>
<li>b) <em>Largely</em> agnostic to the actual software being executed. Again, the whole
<em>point</em> of <strong><em>soft</em></strong>ware is that a CPU can execute whatever code you give it
(vs. having to print specific circuits to do specific things).</li>
</ul>
<hr />
<p>Nonetheless, we had this “waterfall-y” process that worked for hardware, and it
had two steps: first design, then implement. So we tried to map both these
steps to software development, despite the fact that it’s really only the
“design” part.</p>
<p>I think this is the real, core failure of waterfall. It’s not necessarily a bad
system in the abstract: it’s applied to software <em>incorrectly</em>.</p>
<p>Going in to step #2, we only have a vague plan of what to do. It hasn’t been
battle-tested down to the details (if it really had been, you’d already have
the source code – because that’s how you’d battle-test it). So of course,
there’s going to be issues that come up. But the waterfall is not at all
engineered around these conflicts and/or how to resolve them.</p>
<p>It also results in a lot of duplication: the details of your software system
now encoded in both source code and one (or several) documents.</p>
Tue, 04 Feb 2020 00:00:00 +0000
https://alecb.me/waterfall
https://alecb.me/waterfallWhy do we still use passwords?<p>Almost all websites let you reset your password via email. This means that
access to your email account is already going to imply access to almost all
websites you have an account with. Instead of authenticating people with
passwords, why don’t we authenticate them via email?</p>
<p>If you had to do this on every visit it’d be terrible. But most websites let
you stay logged in for a while (or indefinitely) if you don’t log out.
Logging in periodically by clicking a link in an email feels acceptable.</p>
<p>This is basically just using email as a kind of SSO protocol. Actual
SSO via Google or some provider might be a better flow in certain cases. But
the point is if you allow password resets via email, you’re already using
email as a kind of SSO.</p>
<p>You can already approximate this flow with a lot of sites by just choosing an
ephermeral random password that you immediately forget, and using password
reset links every time you need to “login”.</p>
Mon, 08 Apr 2019 00:00:00 +0000
https://alecb.me/why-passwords
https://alecb.me/why-passwordsDon't checkout master locally<p>It’s common to use short-lived branches to organize your work into individual
features, instead of committing directly onto persistent “mainline” branches
like <code class="language-plaintext highlighter-rouge">master</code>. This:</p>
<ul>
<li>Ensures you have an easy way of getting back to a known good state that’s not in the middle of some new feature</li>
<li>Logically groups individual features/bug fixes</li>
<li>Makes it easy to manage multiple concurrent changes</li>
</ul>
<p>But even if you don’t commit directly onto a local master branch, you still
often need to refer to the <em>remote</em> master branch to do things like:</p>
<ul>
<li>Start new feature branches off of master.</li>
<li>Take changes that have been made to master and pull them into a feature branch.</li>
<li>Do diffs against master.</li>
</ul>
<p>You don’t need to have a locally checked out master branch to do any of that:
git already allows you to refer to remote branches directly, via <a href="https://git-scm.com/book/en/v2/Git-Branching-Remote-Branches">remote
tracking branches</a>, like
<code class="language-plaintext highlighter-rouge">origin/master</code>.</p>
<ul>
<li>Need to do a diff against master? <code class="language-plaintext highlighter-rouge">git diff origin/master</code></li>
<li>Need to pull in changes from master? <code class="language-plaintext highlighter-rouge">git merge origin/master</code> (usually after a <code class="language-plaintext highlighter-rouge">git fetch origin</code>; or just do <code class="language-plaintext highlighter-rouge">git pull origin master</code> in one step)</li>
<li>Need to start a new branch based on master? <code class="language-plaintext highlighter-rouge">git branch my-new-branch origin/master</code></li>
</ul>
<p>Sometimes you need more direct access to the content at master. E.g., maybe
you want to just do a build at master, without necessarily starting a new
topic branch.</p>
<p>You can do this using <a href="https://git-scm.com/docs/git-checkout#_detached_head">detached
heads</a>. In addition to
checking out branches, git lets you check out arbitrary commits. So you can
just checkout a remote tracking branch directly, with <code class="language-plaintext highlighter-rouge">git checkout
origin/master</code>.</p>
<p>Why not just checkout master? Because it’s simpler not to: If you checkout
master locally, you now need to mentally deal with your local view of the
remote master (<code class="language-plaintext highlighter-rouge">origin/master</code>) and your local copy of master (<code class="language-plaintext highlighter-rouge">master</code>),
which can diverge.</p>
<p>E.g., without a local master branch, bringing in changes from master is <code class="language-plaintext highlighter-rouge">git
pull origin master</code>. If you have a local copy of master (and you don’t want
it to become stale), you’d instead need to:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># starting with a feature branch checked out</span>
git checkout master
git pull origin master
git checkout -
git merge master
</code></pre></div></div>
Tue, 22 Jan 2019 00:00:00 +0000
https://alecb.me/dont-checkout-master
https://alecb.me/dont-checkout-master