<?xml version="1.0" encoding="UTF-8" ?> <?xml-stylesheet href="./rss.xsl" type="text/xsl"?> <rss version="2.0"> <channel> <title>Write every day</title> <link>https://writing.takashiidobe.com</link> <description>Writing every day for practice</description>
<item>
<title>Are Bootcamps dead?</title>
<guid>https://write-every-day/19.html</guid>
<description><![CDATA[<h1 class="title" id="are-bootcamps-dead">Are
Bootcamps dead?</h1>
<p>Lambda school recently shut its doors, bringing an end to one of the
most infamous bootcamps of its time.</p>
<p>In 2017, I was looking for a career change, and Lambda School was one
of the most recommended coding bootcamps. But it had an allure all its
own – driven mainly by “Income share agreements”, or ISAs. Before
signing up for Lambda School’s course, you would sign a contract that
saying you didn’t have to pay for your education up front. If you got a
job as a SWE paying more than 50k, you would pay a portion of your
earnings back. Otherwise, you would pay nothing.</p>
<p>Lambda school was on your side, unlike all those other bootcamps. Too
bad they lied and went bankrupt.</p>
<p>It’s hard to pinpoint where it all went wrong, because Lambda
School’s early cohort(s) did work out – but then they got onto the
growth bug. There are many people who want to learn how to code, but
very few who are willing to go the distance. Quality instructors are
hard to find – and you have to teach droves of students in a compressed
time (most of these bootcamps are from 3-9 months, and some are part
time). Programming isn’t easy, and it takes a lot of grit.</p>
<p>On top of that, Lambda School’s ISAs bled money. They were earning
about $6000 per student, and paid $13000. You can’t run a business that
sells a dollar for 50 cents forever.</p>
<p>It takes a long time to build a successful department. The college
that I went to ran into the same problem that Lambda School did – the
government wanted to attract overseas students to study in the country.
They did that by giving grants to a few select institutions if they met
some criteria for the funding, which meant offering classes in English
and having a certain percentage of foreigners in that department. The
university did that, received its grant money, and started its program,
accepting many students.</p>
<p>Unfortunately, there weren’t enough professors that spoke English, so
the classes were difficult for non-native speakers of the mother
language. The professors didn’t know what classes they were teaching
until a few weeks before the semester started, and lots of professors
didn’t even want to teach the classes.</p>
<p>The result? After the grant funding dried out, professors were cut,
and people weren’t able to meet their major credit requirements to
graduate.</p>
<p>Success in teaching means taking it slow, because quality instructors
are very difficult to attract. Likewise, finding qualified students is
also hard.</p>
<p>It’s a shame because I think alternative paths to getting a quality
education are sorely needed – universities in America haven’t been
increasing their enrollment rates by much, leaving a glut of students
trying out these new schools.</p>
<p>I’ve seen some arguments that a CS degree couldn’t be taught in 6
months because it requires depth and engineering maturity that takes
time, but I think there are plenty of jobs where you can understand the
basics and be productive, and 6 months is plenty of time to be “on the
job ready” as a junior engineer. Yours truly taught himself how to code
in 6 months, enough to get a job where I made more money than I had ever
seen before, so I don’t think its impossible to make a bootcamp that’s
successful, just hard to make a fast scaling one that’s
successful.</p>]]></description>
</item>
<item>
<title>Learning: A ChatGPT Based Approach</title>
<guid>https://write-every-day/18.html</guid>
<description><![CDATA[<h1 class="title"
id="learning-a-chatgpt-based-approach">Learning: A ChatGPT Based
Approach</h1>
<p>Recently I’ve subscribed to ChatGPT to get ChatGPT 4 as a tool to
help teach myself math. It’s a great tool in the toolbelt for breaking
down hard concepts.</p>
<p>I really like the problem solving approach, where the textbook has
some light exposition on its topics and lots of problems.</p>
<p>The problems are where the hard work gets done – learning inside your
brain.</p>
<p>But most textbooks aren’t geared towards self-learners – they rarely
have solutions and even the ones that do may have incorrect or terse
solutions. Since you want (preferably) multiple solutions to an answer,
that won’t fly. ChatGPT solves that problem by being the bridge between
problem and solution.</p>
<p>You can ask it to drill deep into one part of the problem, rephrase
the problem another way, give similar problems to a problem, ask about
certain concepts and many more. The sky is the limit. The math is a
lagniappe.</p>
<p>You can learn almost any concept you’d like as well, being mindful of
hallucinations – but that’s not that big of a downside.</p>
<p>When I was younger, I researched topics through the library. I’d find
some “authoritative source” (whatever that means) which was usually a
fairly dated book, skim it, find the main ideas, and engage with it,
either choosing to devote more time to fully reading it or giving up
there. Those books had plenty of “hallucinations”, where they mixed up
historical facts or had a message to push. In the humanities, you can’t
get a purely objective view of the world, even for the smallest events
and ideas. You have to side with the author or against the author
sometimes, and find other sources that agree or disagree with the points
you’re currently reading.</p>
<p>In other words, gaining knowledge has always been lossy, and always
will be lossy. Using an LLM in this way is no different than opening up
a book at the library – it’s an adversarial
experience.</p>]]></description>
</item>
<item>
<title>The Interpreter Pattern</title>
<guid>https://write-every-day/17.html</guid>
<description><![CDATA[<h1 class="title" id="the-interpreter-pattern">The
Interpreter Pattern</h1>
<p>Of all the design patterns in all the world, this one is my favorite.
The interpreter pattern involves encoding the actions a user can take
through an app into a clean structure and interpreting that.</p>
<p>This is useful for many reasons: video games use this extensively –
if you want your players to be able to “mod” the game and change things
about it, they have to provide a recipe that your game can read, and
voila – they can extend your game.</p>
<p>Want to provide replays? You can create a video player in your game
that reads a stream of instructions and displays those actions on the
screen, thereby compressing the replay file to just a set of binary
encoded instructions.</p>
<p>Say you want to add redo and undo to your application. If you do it
normally, you can’t do undo anything, because you’ve deleted the
previous state of the application, and can’t undo the mutation. With
actions, you can define a redo and undo for each action, thereby adding
that to your app.</p>
<p>Say you want to test your application by giving it a valid set of
instructions and making sure it does the right thing. If you don’t have
a set of instructions to pass in, and the app can’t execute them, you’re
out of luck. But if you can, you can randomly generate a set of
instructions and see if you get the result you want, or scaffold a test
that does a specific set of actions and verifies its output. You can
even take this to an extreme and fuzz your entire application this
way.</p>
<p>There’s many other things you can do by turning an application into
one that interprets a set of instructions, but these were the ones that
came to my mind.</p>]]></description>
</item>
<item>
<title>Quantity vs Quality</title>
<guid>https://write-every-day/16.html</guid>
<description><![CDATA[<h1 class="title"
id="quantity-vs-quality">Quantity vs Quality</h1>
<p>I took this quote from Anthropic: <a
href="https://transformer-circuits.pub/2024/qualitative-essay/index.html">Reflections
on Qualitative Research</a></p>
<blockquote>
<p>Early scientific fields are often quite qualitative and become more
quantitative as they mature. For example, discovering cells is a
qualitative result, which can then mature (over many decades) into
quantitative tools like counting white blood cells in cancer
research.</p>
</blockquote>
<p>And one from Jeff Bezos:</p>
<blockquote>
<p>The thing I have noticed is when the anecdotes and the data disagree,
the anecdotes are usually right. There’s something wrong with the way
you are measuring it.</p>
</blockquote>
<p>Or this S-curve diagram from Clayton Christensen, where new ideas,
when iterated on sufficiently, overtake incumbents before becoming
incumbents themselves.</p>
<figure>
<img src="../img/s-curves.png" alt="Technology S-Curves" />
<figcaption aria-hidden="true">Technology S-Curves</figcaption>
</figure>
<p>There’s a focus on research these days to focus on “quantifiable
data”, in the hunt for replicable studies. Increasingly, papers accepted
to journals these days have more of a quantitative bent to them, because
they’re easy to validate. You can compare them to other results that use
the same scale and test them against each other.</p>
<p>But the hardest things to gauge are the most important. New
innovations or new ideas that require new ways of thinking to solve an
old problem. Good ideas are enduring, primarily because they don’t just
encapsulate a slot of the problem space, but because they pitch a tent
in that space. The cell, or philosophical ideas can’t be measured in a
quantitative fashion. The current AI boom comes from a new idea in
Machine Learning, the transformer. It wasn’t an incremental improvement
on some other model that came before it – it was an idea that birthed a
trillion dollar industry.</p>
<p>I fear that many companies have become short-term profit chasers,
filled with the wrong type of management. They focus on oft used metrics
like EBITDA or revenue growth to appease their shareholders. Running a
company like a consultancy is a lazy way to mediocrity. It’s fine if you
want to be taken down by a innovator.</p>]]></description>
</item>
<item>
<title>Pointer Complications</title>
<guid>https://write-every-day/15.html</guid>
<description><![CDATA[<h1 class="title"
id="pointer-complications">Pointer Complications</h1>
<hr />
<h1 class="toc-title" id="contents">Contents</h1>
<ul>
<li><a href="#how-do-you-represent-a-pointer"
id="toc-how-do-you-represent-a-pointer">How do you represent a
pointer?</a></li>
</ul>
<hr />
<p>Let’s talk about pointers. As a quick refresher, pointers hold the
location of a slot in memory. You can then manipulate this location,
either by dereferencing it and getting the items that are being pointed
to, or by moving the pointer around with pointer addition.</p>
<p>In C/C++, arrays and pointers are pretty similar, so you can loop
through an array using a pointer.</p>
<p>Take this program, which prints out 1 to 5:</p>
<div id="cb1" class="sourceCode">
<div class="sourceCode" id="cb1"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;stdio.h&gt;</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>    <span class="dt">int</span> x<span class="op">[]</span> <span class="op">=</span> <span class="op">{</span><span class="dv">1</span><span class="op">,</span><span class="dv">2</span><span class="op">,</span><span class="dv">3</span><span class="op">,</span><span class="dv">4</span><span class="op">,</span><span class="dv">5</span><span class="op">};</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>    <span class="dt">int</span><span class="op">*</span> start <span class="op">=</span> x<span class="op">;</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>    <span class="dt">int</span><span class="op">*</span> end <span class="op">=</span> x <span class="op">+</span> <span class="dv">5</span><span class="op">;</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>    <span class="cf">for</span> <span class="op">(;</span> start <span class="op">&lt;</span> end<span class="op">;</span> start<span class="op">++)</span> <span class="op">{</span> printf<span class="op">(</span><span class="st">&quot;</span><span class="sc">%d</span><span class="st">, &quot;</span><span class="op">,</span> <span class="op">*</span>start<span class="op">);</span> <span class="op">}</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</div>
<p>Pointers are useful in many cases – if you want to represent a
recursive data structure, you can do so with pointers:</p>
<div id="cb2" class="sourceCode">
<div class="sourceCode" id="cb2"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> Node <span class="op">{</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>    <span class="dt">int</span> value<span class="op">;</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">struct</span> Node<span class="op">*</span> next<span class="op">;</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span></code></pre></div>
</div>
<p>Also, if you want to just listen to an update to some other memory,
you can do so with pointers. Without them, or some related construct,
any update to would have to be written to all the listeners, which could
be very expensive.</p>
<p>But this makes optimizing code much harder.</p>
<p>Take this simple example:</p>
<div id="cb3" class="sourceCode">
<div class="sourceCode" id="cb3"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> is_a<span class="op">(</span><span class="dt">char</span> <span class="op">*</span>a<span class="op">,</span> <span class="dt">char</span> <span class="op">*</span>b<span class="op">)</span> <span class="op">{</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>    <span class="op">*</span>a <span class="op">=</span> <span class="ch">&#39;a&#39;</span><span class="op">;</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>    <span class="op">*</span>b <span class="op">=</span> <span class="ch">&#39;b&#39;</span><span class="op">;</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="op">*</span>a <span class="op">==</span> <span class="ch">&#39;a&#39;</span><span class="op">;</span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</div>
<p>Since we set the <code>a</code> pointer to ‘a’, and the
<code>b</code> pointer to ‘b’, and then check if the <code>a</code>
pointer is ‘a’, this should just be <code>return 1</code>. However, the
<code>a</code> pointer and the <code>b</code> pointer could be the same
pointer.</p>
<p>But the function allows us to pass the same pointer as <code>a</code>
and <code>b</code>, which breaks this assumption:</p>
<div id="cb4" class="sourceCode">
<div class="sourceCode" id="cb4"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;stdio.h&gt;</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;stdlib.h&gt;</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> is_a<span class="op">(</span><span class="dt">char</span> <span class="op">*</span>a<span class="op">,</span> <span class="dt">char</span> <span class="op">*</span>b<span class="op">)</span> <span class="op">{</span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>    <span class="op">*</span>a <span class="op">=</span> <span class="ch">&#39;a&#39;</span><span class="op">;</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>    <span class="op">*</span>b <span class="op">=</span> <span class="ch">&#39;b&#39;</span><span class="op">;</span></span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="op">*</span>a <span class="op">==</span> <span class="ch">&#39;a&#39;</span><span class="op">;</span></span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a>    <span class="dt">char</span><span class="op">*</span> a <span class="op">=</span> malloc<span class="op">(</span><span class="kw">sizeof</span><span class="op">(</span><span class="dt">char</span><span class="op">));</span></span>
<span id="cb4-12"><a href="#cb4-12" aria-hidden="true" tabindex="-1"></a>    printf<span class="op">(</span><span class="st">&quot;is_a, </span><span class="sc">%d</span><span class="st">&quot;</span><span class="op">,</span> is_a<span class="op">(</span>a<span class="op">,</span> a<span class="op">));</span></span>
<span id="cb4-13"><a href="#cb4-13" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</div>
<p>In which case this returns 0.</p>
<p>If there was some way to say that pointer <code>a</code> and pointer
<code>b</code> could not be the same pointer, then we could do this
optimization.</p>
<p>C does have a keyword, <code>restrict</code> that hints to the
compiler that the memory locations do not alias (they don’t intersect),
but in this case it doesn’t generate any better code and it isn’t a
compile time restriction, so this keyword isn’t useful in this case.</p>
<section id="how-do-you-represent-a-pointer" class="level2">
<h2>How do you represent a pointer?</h2>
<p>Recently, I’ve been working on a C compiler, and got to the point
where I had to support pointers in C.</p>
<p>Most people think that a pointer is a <em>number</em> (with its
length being your computer’s word size, normally 64 bits these days),
but that doesn’t work. In the previous example above, I did pointer
arithmetic on an <code>int* start</code>, with <code>start++</code>
(increment start by 1). However, since an <code>int</code> is 4 bytes,
and since each increment prints the next number, this actually
increments the pointer by 4 bytes. But if I had a <code>char*</code>,
since <code>char</code> is 1 byte, incrementing a <code>char</code>
increments the pointer by 1 byte.</p>
<p>On top of its size, a pointer also needs to store its type (since you
can’t pass a pointer of a different type to a function that wants a
specific pointer), but you also need to support casting.</p>
<p>A pointer can be cast to a number, or to another pointer type. If
cast to a number, and then back to a pointer, what happens to its type
information, or its size? Does it disappear? Some important questions to
ponder.</p>
<p>Also, you’d want to have type-safety with pointers. It would be odd
to take a pointer to an int and then change it to a pointer to another
type, like an array. It makes sense to increment or decrement the
pointer to an array, but not for a pointer to an int. If this is the
case, then pointers should also hold their type.</p>
<p>On top of that, pointers can point to initialized or uninitialized
memory. So that needs to be handled too – in C++, the <code>end</code>
pointer of a collection always points to one past the end of a
collection, which is generally uninitialized.</p>
<p>Also for optimization reasons, it’s also useful to know if pointers
<em>alias</em>, or if a certain location in memory is only accessible by
one pointer or multiple. In the <code>is_a</code> example above, if we
know that the two pointers are different and cannot access the same
location, then we can emit “return true” for the function. But that also
requires keeping track of where it came from, which is called
<em>provenance</em>. This information is important for optimizations,
but also useful for error messages to the user – if the compiler knows
where a pointer came from, and the user tries to use it incorrectly,
it’ll have more information about how things went wrong.</p>
<p>Pointers are complicated. They’re also not just a number.</p>
</section>]]></description>
</item>
<item>
<title>Ways to Test</title>
<guid>https://write-every-day/14.html</guid>
<description><![CDATA[<h1 class="title" id="ways-to-test">Ways to
Test</h1>
<hr />
<h1 class="toc-title" id="contents">Contents</h1>
<ul>
<li><a href="#unit-tests" id="toc-unit-tests">Unit Tests</a></li>
<li><a href="#snapshot-tests" id="toc-snapshot-tests">Snapshot
Tests</a></li>
<li><a href="#mutation-tests" id="toc-mutation-tests">Mutation
Tests</a></li>
<li><a href="#fuzzing" id="toc-fuzzing">Fuzzing</a></li>
<li><a href="#property-tests" id="toc-property-tests">Property
Tests</a></li>
</ul>
<hr />
<p>Learning how to test well is a requirement to being a good software
engineer. It doesn’t matter how good your code is – code has bugs. And
how do we find those bugs? The most engineering way possible. Writing
test programs.</p>
<p>Let’s create a (somewhat dumb) example of adding two numbers and show
how we’d test it, and some of the pitfalls of doing so.</p>
<div id="cb1" class="sourceCode">
<div class="sourceCode" id="cb1"><pre
class="sourceCode rust"><code class="sourceCode rust"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> add(a<span class="op">:</span> <span class="dt">u32</span><span class="op">,</span> b<span class="op">:</span> <span class="dt">u32</span>) <span class="op">-&gt;</span> <span class="dt">u32</span><span class="op">;</span></span></code></pre></div>
</div>
<section id="unit-tests" class="level2">
<h2>Unit Tests</h2>
<p>The first way is the most obvious. Write out a test case and verify
it makes sense.</p>
<p>We could write that <code>2 + 2</code> should be <code>4</code>.</p>
<div id="cb2" class="sourceCode">
<div class="sourceCode" id="cb2"><pre
class="sourceCode rust"><code class="sourceCode rust"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="at">#[</span>test<span class="at">]</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> unit() <span class="op">{</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>    <span class="pp">assert_eq!</span>(add(<span class="dv">2</span><span class="op">,</span> <span class="dv">2</span>)<span class="op">,</span> <span class="dv">4</span>)<span class="op">;</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</div>
<p>But there are a few problems:</p>
<ol type="1">
<li>We have to know what inputs to provide the function and what output
that would return before writing the test case.</li>
</ol>
<p>Let’s say I misunderstand how addition works, and write this
implementation:</p>
<div id="cb3" class="sourceCode">
<div class="sourceCode" id="cb3"><pre
class="sourceCode rust"><code class="sourceCode rust"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> add(a<span class="op">:</span> <span class="dt">u32</span><span class="op">,</span> b<span class="op">:</span> <span class="dt">u32</span>) <span class="op">-&gt;</span> <span class="dt">u32</span> <span class="op">{</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>    a <span class="op">+</span> b <span class="op">+</span> <span class="dv">1</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</div>
<p>It’s pretty easy to also write my test program incorrectly:</p>
<div id="cb4" class="sourceCode">
<div class="sourceCode" id="cb4"><pre
class="sourceCode rust"><code class="sourceCode rust"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="at">#[</span>test<span class="at">]</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> unit() <span class="op">{</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>    <span class="pp">assert_eq!</span>(add(<span class="dv">2</span><span class="op">,</span> <span class="dv">2</span>)<span class="op">,</span> <span class="dv">5</span>)<span class="op">;</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</div>
<p>And then the unit test is worse than useless – it reassures me that
I’m testing an input properly when I am not.</p>
<ol start="2" type="1">
<li>There are 4 billion choices for the first parameter to the function,
and 4 billion more choices for the second. I can’t write all of these
test cases by hand. Moreover, it’s hard to find interesting test cases
that actually trigger a bug.</li>
</ol>
</section>
<section id="snapshot-tests" class="level2">
<h2>Snapshot Tests</h2>
<p>Snapshot tests are like unit tests, but instead of having to write
out the output, you verify that the output is correct. This is useful
for cases where it’s a pain to write the output value, like for an AST
in a compiler.</p>
<p>They make it easier to write tests, but they still share the pitfall
with unit tests, where you still need to know what went wrong.</p>
</section>
<section id="mutation-tests" class="level2">
<h2>Mutation Tests</h2>
<p>Mutation tests are a bit different from the previous ways of testing:
they take your existing unit tests and change (mutate) the body of a
function under test, and check if the tests still hold.</p>
<p>For example, for the add function, it might change the operator or
the numbers to something else like so:</p>
<div id="cb5" class="sourceCode">
<div class="sourceCode" id="cb5"><pre
class="sourceCode rust"><code class="sourceCode rust"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> add(a<span class="op">:</span> <span class="dt">u32</span><span class="op">,</span> b<span class="op">:</span> <span class="dt">u32</span>) <span class="op">-&gt;</span> <span class="dt">u32</span> <span class="op">{</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>    a <span class="op">-</span> b</span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</div>
<p>The test runner would then run all of your unit tests and note
whether or not they fail. If they don’t all fail, then there’s some
overlap between this new program and your program, and either the tests
are not representative enough, or the function could be implemented
incorrectly.</p>
<p>Either way, mutation tests are useful because even if you implement a
function incorrectly, they have a chance of telling you that you’ve done
something incorrectly.</p>
<p>But they do give false positives:</p>
<p>Imagine the add function is mutated to the following:</p>
<div id="cb6" class="sourceCode">
<div class="sourceCode" id="cb6"><pre
class="sourceCode rust"><code class="sourceCode rust"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> add(a<span class="op">:</span> <span class="dt">u32</span><span class="op">,</span> b<span class="op">:</span> <span class="dt">u32</span>) <span class="op">-&gt;</span> <span class="dt">u32</span> <span class="op">{</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>    a <span class="op">*</span> b</span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</div>
<p>And the test case is:</p>
<div id="cb7" class="sourceCode">
<div class="sourceCode" id="cb7"><pre
class="sourceCode rust"><code class="sourceCode rust"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="at">#[</span>test<span class="at">]</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> unit() <span class="op">{</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a>    <span class="pp">assert_eq!</span>(add(<span class="dv">2</span><span class="op">,</span> <span class="dv">2</span>)<span class="op">,</span> <span class="dv">4</span>)<span class="op">;</span></span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</div>
<p>This test case passes with the unchanged add function and the newly
changed one. Thus, this function will be flagged as potentially
implemented incorrectly, even if it is correct.</p>
</section>
<section id="fuzzing" class="level2">
<h2>Fuzzing</h2>
<p>What happens if we want to try to generate some use cases? One way of
doing this is by using some “interesting” cases and see what
happens.</p>
<p>If we do the following:</p>
<div id="cb8" class="sourceCode">
<div class="sourceCode" id="cb8"><pre
class="sourceCode rust"><code class="sourceCode rust"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a>add(<span class="dt">u32</span><span class="pp">::</span><span class="cn">MAX</span><span class="op">,</span> <span class="dt">u32</span><span class="pp">::</span><span class="cn">MAX</span>)<span class="op">;</span></span></code></pre></div>
</div>
<p>We’ll get an integer overflow, and the program will crash.</p>
<p>Fuzzing creates interesting test cases and then tests to see if the
function(s) under test crash with some input. If it does, it tries to
find the shortest input that does so.</p>
<p>However, it’s not foolproof:</p>
<p>Imagine we wrote add like so:</p>
<div id="cb9" class="sourceCode">
<div class="sourceCode" id="cb9"><pre
class="sourceCode rust"><code class="sourceCode rust"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> add(a<span class="op">:</span> <span class="dt">u32</span><span class="op">,</span> b<span class="op">:</span> <span class="dt">u32</span>) <span class="op">-&gt;</span> <span class="dt">u32</span> <span class="op">{</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>    a<span class="op">.</span>saturating_add(b)</span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</div>
<p>This function should no longer crash, rendering our fuzz tests
useless.</p>
<p>Fuzzing is good for testing lots of use cases, but we lose a nice
property – we’re just trying to make the function crash, and no longer
verifying its output.</p>
</section>
<section id="property-tests" class="level2">
<h2>Property Tests</h2>
<p>What if we know some things about the function we’re trying to
test?</p>
<p>If we add two numbers where both numbers are <code>&gt;= 0</code>, we
know that the number has to be at least as large as the maximum of both
numbers.</p>
<p>We can formalize this:</p>
<div id="cb10" class="sourceCode">
<div class="sourceCode" id="cb10"><pre
class="sourceCode rust"><code class="sourceCode rust"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="at">#[</span>test<span class="at">]</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> property() <span class="op">{</span></span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span> X<span class="op">:</span> <span class="dt">u32</span> <span class="op">=</span> random_number()<span class="op">;</span></span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span> Y<span class="op">:</span> <span class="dt">u32</span> <span class="op">=</span> random_number()<span class="op">;</span></span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span> result <span class="op">=</span> add(X<span class="op">,</span> Y)<span class="op">;</span></span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a>    <span class="pp">assert!</span>(result <span class="op">&gt;=</span> X<span class="op">.</span>max(Y))<span class="op">;</span></span>
<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</div>
<p>We have now found some useful property to test, so instead of just
testing for a crash, we also have some guarantee that the function is
correct.</p>
<p>That being said, we could still fool the property by writing
this:</p>
<div id="cb11" class="sourceCode">
<div class="sourceCode" id="cb11"><pre
class="sourceCode rust"><code class="sourceCode rust"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> add(a<span class="op">:</span> <span class="dt">u32</span><span class="op">,</span> b<span class="op">:</span> <span class="dt">u32</span>) <span class="op">-&gt;</span> <span class="dt">u32</span> <span class="op">{</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a>    a<span class="op">.</span>max(b) <span class="op">+</span> <span class="dv">1</span></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</div>
<p>Which would pass our previous property test.</p>
</section>]]></description>
</item>
<item>
<title>Math is Fundamental</title>
<guid>https://write-every-day/13.html</guid>
<description><![CDATA[<h1 class="title" id="math-is-fundamental">Math is
Fundamental</h1>
<p>As your average American going to high school, I learned the four
core subjects (English, Science, Math, History) and a foreign language
(Spanish). Since we were allowed to take two years of a subject every
year, I ended up taking 5 years of English, 7 years of science, 6 years
of history, 5 years of Spanish, and the state minimum of 3 years of
math. Believe me, I thought math was useless. It seems like most people
agree - the most math they’ll ever do can be computed by a
calculator.</p>
<p>And yet, my 16 year old self could not have been more wrong. While I
think all of the subjects are useful (I read and write every day, I use
the past to inform my decisions, and I lived in a foreign country, so my
language acquisition skills turned out to be very important), math and
science ended up being much more useful than I thought, not least
because I program for a living.</p>
<p>Math turned out to be fundamental.</p>
<p>My first job required accounting skills. I needed to calculate
expenses, payroll, taxes, profits, and find out who missed payments for
the business. At a small enough scale, you can put this in your brain,
but you’ll forget eventually and the business will suffer. Accounting is
an important skill. To do that, I used Microsoft excel, but you still
need to know how to double-entry bookkeep and measure your revenue, cost
to acquire said revenue, and profit. You also need to be able to look to
the past, account for any changes due to things outside of your control
(employees leaving, seasonal shifts, etc), and control for those to keep
the business running smoothly. It takes little more than arithmetic and
some plotting, but it makes or breaks many businesses of any size.</p>
<p>Say you have a record which stores an album you listen to. Over time,
the record player (and your handling of the record) will dull out the
sound of the album – some parts will sound off. The reason? Records are
etched with the sound the record player is supposed to play, and over
time, the physical needle that the record player uses to read off the
record will change those engravings, distorting the sound. Also, if you
happen to damage any part of the record, that section of the album will
become unplayable, and you’ll have to skip it.</p>
<p>How would we do better? The first guess might be to make two copies
of the same data, and then if you damage one, you can go to the other.
But that requires a human operator – somebody that can judge that both
copies are correct, one is correct, or neither are correct. If we want
the machine to be able to do it for us, we’ll need three copies of the
data. Unfortunately, that cuts the space on our media by 3, and it still
has pitfalls – if you manage to corrupt two of the same parts on two of
the copies of the disk, you’ll still lose that chunk of data on
disk.</p>
<p>Sounds pretty bad. We can do better – take a CD, for example. If you
scratch a small part of the CD, chances are it still works. The reason
why it works is because the CD has a scheme for error detection and
error correction. The CD is partitioned into two parts: the actual bits
and bytes for the data, and digits that can correct the data, should it
be damaged. If you damage any part of the CD, as long as the rest of the
CD can compensate for it, the CD can restore the bytes it has and play
as if there was no problem. This is because of Reed-Solomon encoding,
which encodes the data on polynomials and restores the underlying data
points. This is also tunable, so you can allocate as many bytes as you
want for error detection, so the algorithm can correct fewer or more
errors, taking up as little space as required.</p>
<p>One potential scheme involves using 223 data bits for every 256 bits
on disk, thereby using up 32 bits for error detection and correction.
Since half the bits can be used for correction (16), this scheme would
cost (223/256) or about 13% of total disk space, but be able to correct
up to 16 bits that were flipped in each 256 bits on disk, or about 6%,
or 32 bits that were erased, so 13% of bits.</p>
<p>DNA uses error correcting codes as well. If our DNA wasn’t resilient,
we’d most likely have died before we got here.</p>
<p>What about compression? If you’ve tried to compress files on disk,
you’ll know that text files are easy to compress, while binary files,
video and picture files don’t compress much. The reason why? Entropy.
The same entropy from science class. Entropy measures the chaos of a
system – in chemistry class, we learn that converting matter to energy,
or various energies to other forms incurs a tax – some of the energy is
lost, and adds to the chaos of the system we live in. Thus, entropy
always increases – if you walk, some amount of kinetic energy spent is
lost forever as friction.</p>
<p>The written languages we speak have good compression – we only have a
certain set of words and punctuation we can use, and we mix and match
them to form sentences. Compression can exploit this fact, and create a
dictionary for a file, and turn a file into a set of bits, with the
dictionary used to decode the file back to its original format.
Compression exploits the redundancy of the underlying data to turn it
into a more compact form, thus, it has low entropy. Imagine we used a
language with totally random words, which could appear in a totally
random way. This language would have high entropy to encode, and thus,
would not be compressable. The more predictable an input is, the easier
it is to compress, and the less predictable an input is, the harder it
is to compress.</p>
<p>This knowledge came in handy when I worked as a chef at a restaurant.
Imagine you had a restaurant where you could serve any dish, and
customers would come at any time to order any of those dishes. Your
input (customer orders) are random across time and space (they can order
any dish). Thus, it is impossible to hire a set of chefs, and give them
a schedule that would satisfy all of their orders efficiently.</p>
<p>Thus, restaurants have to employ some form of compression. We may
choose to focus on a certain cuisine with similar dishes – thus, you
limit the set of ingredients you can use to those common to that
cuisine. This also allows our chefs to specialize in those dishes, and
the customers can only order from a specific set. Thus, we’ve compressed
our input in terms of space. But we also want to provide our chefs a
good schedule across time – so we may choose a set of working hours
(lunch hours and evening hours) that make ordering at certain times
impossible, so we can pay our chefs for their most profitable hours
without going broke, and our chefs don’t have to work 24 hour days all
the time.</p>
<p>So the obvious forms of compression are already done (most places
don’t work around the clock, and they don’t serve every dish known to
man). But one that came up during my time was how to support delivery.
We had to think about how much of the menu to support (some dishes just
aren’t deliverable feasibly), what containers we would use to transport
it, and how to allocate couriers to deliver the food.</p>
<p>Basically, we had a choice to add entropy to our system in exchange
for increased profits. We tried it delivery out for a bit, but found
that customers didn’t really enjoy our food when it wasn’t hot off the
grill, and our overall orders were coming out slower due to the extra
time required to prepare food for delivery, not to mention the decrease
in shelf space to hold containers for delivery as well. At the end of
the day, we stopped delivering food, and gave up those increased
profits, since it wasn’t worth it, in the end. We choose to focus
(compress) on what we did best to keep our customers happy.</p>
<p>Entropy also turned out to be fundamental when I worked in finance.
We used to say that banks exist to turn risk into reward. We would take
our customers money, chase returns, and then the rewards would be split
– some goes to the customer, and some goes to the bank. The bank thus
has to choose a set of allocations (a portfolio) for the assets that
they manage.</p>
<p>They can choose assets that have low correlation with each other (and
thus, the portfolio has low entropy), but in exchange, since the risk of
this strategy is low, the expected payoff should also similarly be low.
They can also choose the inverse, where the assets have high correlation
with each other (and thus, high entropy), with high risk, for the chance
of high payoffs.</p>
<p>But in reality, you don’t really want to do either. Be too
conservative, and you’ll lose all your customers to your competitors who
can offer higher returns. Be too risky, and you’ll lose all your
customers money. Banks spend most of their time managing risk –
calculating the amount of entropy in a particular portfolio, and
calculating whether or not it is worth it to invest. The only problem?
The risk of financial instruments can’t be seen in advance. It’s always
just an estimation. Therefore, understanding entropy and calculating its
flows through the market is essential in finance. Do it right, and
there’s profits abound. Do it wrong, and you’ll be the next one the
tabloids.</p>]]></description>
</item>
<item>
<title>Beautiful Programs</title>
<guid>https://write-every-day/12.html</guid>
<description><![CDATA[<h1 class="title"
id="beautiful-programs">Beautiful Programs</h1>
<hr />
<h1 class="toc-title" id="contents">Contents</h1>
<ul>
<li><a href="#the-repl" id="toc-the-repl">the REPL</a></li>
<li><a href="#the-universal-server" id="toc-the-universal-server">The
Universal Server</a></li>
<li><a href="#a-metacircular-evaluator"
id="toc-a-metacircular-evaluator">A Metacircular evaluator</a></li>
<li><a href="#a-simple-regular-expression-engine"
id="toc-a-simple-regular-expression-engine">A Simple Regular Expression
Engine</a></li>
<li><a href="#the-rest" id="toc-the-rest">The Rest?</a></li>
</ul>
<hr />
<p>For today’s post, we’re diving into beautiful programs. I picked a
few that I personally like which are small, explainable, yet pack a big
punch, way above their class.</p>
<section id="the-repl" class="level2">
<h2>the REPL</h2>
<p>The REPL is a prompt that interprets results on the fly and returns
them to the user. Almost all interpreted languages have one, and they
call them a “REPL”, which is short for <strong>R</strong>ead
<strong>E</strong>valuate <strong>P</strong>rint
<strong>L</strong>oop.</p>
<p>In lisp, it’s four functions:</p>
<div id="cb1" class="sourceCode">
<div class="sourceCode" id="cb1"><pre
class="sourceCode lisp"><code class="sourceCode commonlisp"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a>(<span class="kw">loop</span> (<span class="kw">print</span> (<span class="kw">eval</span> (<span class="kw">read</span>))))</span></code></pre></div>
</div>
<ol type="1">
<li>You read input from the user</li>
<li>You evaluate it</li>
<li>You print the result</li>
<li>You repeat infinitely</li>
</ol>
<p>In lisp it’s easy to implement like this because it’s easy to
evaluate any lisp program you write (lisp programs are interpreted the
same way they’re typed, so evaluating is not that hard).</p>
<p>Simply putting together these four functions in this way allows for a
new way of experimenting with programming – you can write code and get
immediate feedback, instead of having to write code, compile it, and run
it. Most people start off with learning interpreted languages, and these
four functions are responsible for getting many people into programming,
myself included.</p>
</section>
<section id="the-universal-server" class="level2">
<h2>The Universal Server</h2>
<p>Joe Armstrong wrote about his favorite program, <a
href="https://joearms.github.io/published/2013-11-21-My-favorite-erlang-program.html">The
Universal Server</a>.</p>
<p>It’s simple:</p>
<div id="cb2" class="sourceCode">
<div class="sourceCode" id="cb2"><pre
class="sourceCode erlang"><code class="sourceCode erlang"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="fu">universal_server()</span> <span class="op">-&gt;</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">receive</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>       <span class="fu">{</span><span class="ch">become</span><span class="fu">,</span> <span class="va">F</span><span class="fu">}</span> <span class="op">-&gt;</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>           <span class="va">F</span><span class="fu">()</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>    <span class="kw">end</span><span class="fu">.</span></span></code></pre></div>
</div>
<p>5 lines of code define a process that can take any arbitrary work and
becomes that function.</p>
<p>He defines a factorial function, which calculates the factorial of an
integer it receives:</p>
<div id="cb3" class="sourceCode">
<div class="sourceCode" id="cb3"><pre
class="sourceCode erlang"><code class="sourceCode erlang"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="fu">factorial_server()</span> <span class="op">-&gt;</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">receive</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>       <span class="fu">{</span><span class="va">From</span><span class="fu">,</span> <span class="va">N</span><span class="fu">}</span> <span class="op">-&gt;</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>           <span class="va">From</span> <span class="op">!</span> <span class="fu">factorial(</span><span class="va">N</span><span class="fu">),</span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>           <span class="fu">factorial_server()</span></span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a>    <span class="kw">end</span><span class="fu">.</span></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a><span class="fu">factorial(</span><span class="dv">0</span><span class="fu">)</span> <span class="op">-&gt;</span> <span class="dv">1</span><span class="fu">;</span></span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a><span class="fu">factorial(</span><span class="va">N</span><span class="fu">)</span> <span class="op">-&gt;</span> <span class="va">N</span> <span class="op">*</span> <span class="fu">factorial(</span><span class="va">N</span><span class="op">-</span><span class="dv">1</span><span class="fu">).</span></span></code></pre></div>
</div>
<p>And then you can write a function that spawns it and run it.</p>
<div id="cb4" class="sourceCode">
<div class="sourceCode" id="cb4"><pre
class="sourceCode erlang"><code class="sourceCode erlang"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="fu">test()</span> <span class="op">-&gt;</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>    <span class="va">Pid</span> <span class="op">=</span> <span class="fu">spawn(</span><span class="kw">fun</span> <span class="ch">universal_server</span><span class="op">/</span><span class="dv">0</span><span class="fu">),</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>    <span class="va">Pid</span> <span class="op">!</span> <span class="fu">{</span><span class="ch">become</span><span class="fu">,</span> <span class="kw">fun</span> <span class="ch">factorial_server</span><span class="op">/</span><span class="dv">0</span><span class="fu">},</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>    <span class="va">Pid</span> <span class="op">!</span> <span class="fu">{self(),</span> <span class="dv">50</span><span class="fu">},</span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>    <span class="kw">receive</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>        <span class="va">X</span> <span class="op">-&gt;</span> <span class="va">X</span></span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a>    <span class="kw">end</span><span class="fu">.</span></span></code></pre></div>
</div>
<p>In 5 lines, this defines a universal protocol for servers – they
receive input and return a message. Any server that follows that rule
can be spawned by this universal server. Pretty cool. If you have a
server running a version right now and you want it to run another
version? Go write the code for a new server, and send it over.</p>
</section>
<section id="a-metacircular-evaluator" class="level2">
<h2>A Metacircular evaluator</h2>
<p>Another lisp program? A Metacircular evaluator is an evaluator that
can evaluate programs written in itself.</p>
<p>This is from Structure and Interpretation of Computer Programs:</p>
<div id="cb5" class="sourceCode">
<div class="sourceCode" id="cb5"><pre
class="sourceCode lisp"><code class="sourceCode commonlisp"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a>(define (<span class="kw">eval</span> <span class="kw">exp</span> env)</span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>  (<span class="kw">cond</span> ((self-evaluating? <span class="kw">exp</span>) <span class="kw">exp</span>)</span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>        ((variable? <span class="kw">exp</span>) (lookup-variable-value <span class="kw">exp</span> env))</span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a>        ((quoted? <span class="kw">exp</span>) (text-of-quotation <span class="kw">exp</span>))</span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a>        ((assignment? <span class="kw">exp</span>) (eval-assignment <span class="kw">exp</span> env))</span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a>        ((definition? <span class="kw">exp</span>) (eval-definition <span class="kw">exp</span> env))</span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a>        ((if? <span class="kw">exp</span>) (eval-if <span class="kw">exp</span> env))</span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a>        ((lambda? <span class="kw">exp</span>)</span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a>         (make-procedure (lambda-parameters <span class="kw">exp</span>)</span>
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true" tabindex="-1"></a>                         (lambda-body <span class="kw">exp</span>)</span>
<span id="cb5-11"><a href="#cb5-11" aria-hidden="true" tabindex="-1"></a>                         env))</span>
<span id="cb5-12"><a href="#cb5-12" aria-hidden="true" tabindex="-1"></a>        ((begin? <span class="kw">exp</span>)</span>
<span id="cb5-13"><a href="#cb5-13" aria-hidden="true" tabindex="-1"></a>         (eval-sequence (begin-actions <span class="kw">exp</span>) env))</span>
<span id="cb5-14"><a href="#cb5-14" aria-hidden="true" tabindex="-1"></a>        ((cond? <span class="kw">exp</span>) (<span class="kw">eval</span> (cond-&gt;if <span class="kw">exp</span>) env))</span>
<span id="cb5-15"><a href="#cb5-15" aria-hidden="true" tabindex="-1"></a>        ((application? <span class="kw">exp</span>)</span>
<span id="cb5-16"><a href="#cb5-16" aria-hidden="true" tabindex="-1"></a>         (<span class="kw">apply</span> (<span class="kw">eval</span> (operator <span class="kw">exp</span>) env)</span>
<span id="cb5-17"><a href="#cb5-17" aria-hidden="true" tabindex="-1"></a>                (list-of-values (operands <span class="kw">exp</span>) env)))</span>
<span id="cb5-18"><a href="#cb5-18" aria-hidden="true" tabindex="-1"></a>        (else</span>
<span id="cb5-19"><a href="#cb5-19" aria-hidden="true" tabindex="-1"></a>         (<span class="kw">error</span> <span class="st">&quot;Unknown expression type -- EVAL&quot;</span> <span class="kw">exp</span>))))</span></code></pre></div>
</div>
<p>There’s more to the program, but this is the core of it.</p>
<p>All lisp programs can be defined by two things: their body, the
actual program and an environment, which is the bindings required to
make the language work. For example, if you have a program:</p>
<div id="cb6" class="sourceCode">
<div class="sourceCode" id="cb6"><pre
class="sourceCode lisp"><code class="sourceCode commonlisp"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a>(<span class="kw">print</span> x)</span></code></pre></div>
</div>
<p>You need some definition for two things, <code>x</code> and
<code>print</code>. Normally you’d define <code>x</code> in the course
of your program, but you probably wouldn’t define the <code>print</code>
function of your language. Thus, you can divide this program into two
pieces, its environment (what it needs to run) and the textual
definition of the program itself.</p>
<div id="cb7" class="sourceCode">
<div class="sourceCode" id="cb7"><pre
class="sourceCode lisp"><code class="sourceCode commonlisp"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a>{ print: <span class="st">&quot;some implementation here&quot;</span> } <span class="co">; The &quot;environment&quot;</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>(<span class="kw">print</span> x) <span class="co">; The program</span></span></code></pre></div>
</div>
<p>That’s all you need to evaluate your language, a set of variables,
and the program itself. If you want to write a modern programming
language, you need to support scopes:</p>
<div id="cb8" class="sourceCode">
<div class="sourceCode" id="cb8"><pre
class="sourceCode rust"><code class="sourceCode rust"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> <span class="kw">mut</span> x <span class="op">=</span> <span class="dv">10</span><span class="op">;</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a>    x <span class="op">=</span> <span class="dv">15</span><span class="op">;</span></span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</div>
<p>All you need to support that is nested hashmaps:</p>
<div id="cb9" class="sourceCode">
<div class="sourceCode" id="cb9"><pre
class="sourceCode lisp"><code class="sourceCode commonlisp"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a>{ x: <span class="dv">10</span>, { x: <span class="dv">15</span> }}</span></code></pre></div>
</div>
<p>If you’re in a nested scope, choose that value instead of the higher
level value. A language is itself and its environment.</p>
</section>
<section id="a-simple-regular-expression-engine" class="level2">
<h2>A Simple Regular Expression Engine</h2>
<p>This comes from The Practice of Programming by Rob Pike and Brian
Kernighan, a simple regular expression matcher.</p>
<div id="cb10" class="sourceCode">
<div class="sourceCode" id="cb10"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="co">/* match: search for regexp anywhere in text */</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> match<span class="op">(</span><span class="dt">char</span> <span class="op">*</span>regexp<span class="op">,</span> <span class="dt">char</span> <span class="op">*</span>text<span class="op">)</span></span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="op">(</span>regexp<span class="op">[</span><span class="dv">0</span><span class="op">]</span> <span class="op">==</span> <span class="ch">&#39;^&#39;</span><span class="op">)</span></span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> matchhere<span class="op">(</span>regexp<span class="op">+</span><span class="dv">1</span><span class="op">,</span> text<span class="op">);</span></span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a>    <span class="cf">do</span> <span class="op">{</span>    <span class="co">/* must look even if string is empty */</span></span>
<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a>        <span class="cf">if</span> <span class="op">(</span>matchhere<span class="op">(</span>regexp<span class="op">,</span> text<span class="op">))</span></span>
<span id="cb10-8"><a href="#cb10-8" aria-hidden="true" tabindex="-1"></a>            <span class="cf">return</span> <span class="dv">1</span><span class="op">;</span></span>
<span id="cb10-9"><a href="#cb10-9" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span> <span class="cf">while</span> <span class="op">(*</span>text<span class="op">++</span> <span class="op">!=</span> <span class="ch">&#39;</span><span class="sc">\0</span><span class="ch">&#39;</span><span class="op">);</span></span>
<span id="cb10-10"><a href="#cb10-10" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="dv">0</span><span class="op">;</span></span>
<span id="cb10-11"><a href="#cb10-11" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb10-12"><a href="#cb10-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-13"><a href="#cb10-13" aria-hidden="true" tabindex="-1"></a><span class="co">/* matchhere: search for regexp at beginning of text */</span></span>
<span id="cb10-14"><a href="#cb10-14" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> matchhere<span class="op">(</span><span class="dt">char</span> <span class="op">*</span>regexp<span class="op">,</span> <span class="dt">char</span> <span class="op">*</span>text<span class="op">)</span></span>
<span id="cb10-15"><a href="#cb10-15" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb10-16"><a href="#cb10-16" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="op">(</span>regexp<span class="op">[</span><span class="dv">0</span><span class="op">]</span> <span class="op">==</span> <span class="ch">&#39;</span><span class="sc">\0</span><span class="ch">&#39;</span><span class="op">)</span></span>
<span id="cb10-17"><a href="#cb10-17" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> <span class="dv">1</span><span class="op">;</span></span>
<span id="cb10-18"><a href="#cb10-18" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="op">(</span>regexp<span class="op">[</span><span class="dv">1</span><span class="op">]</span> <span class="op">==</span> <span class="ch">&#39;*&#39;</span><span class="op">)</span></span>
<span id="cb10-19"><a href="#cb10-19" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> matchstar<span class="op">(</span>regexp<span class="op">[</span><span class="dv">0</span><span class="op">],</span> regexp<span class="op">+</span><span class="dv">2</span><span class="op">,</span> text<span class="op">);</span></span>
<span id="cb10-20"><a href="#cb10-20" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="op">(</span>regexp<span class="op">[</span><span class="dv">0</span><span class="op">]</span> <span class="op">==</span> <span class="ch">&#39;$&#39;</span> <span class="op">&amp;&amp;</span> regexp<span class="op">[</span><span class="dv">1</span><span class="op">]</span> <span class="op">==</span> <span class="ch">&#39;</span><span class="sc">\0</span><span class="ch">&#39;</span><span class="op">)</span></span>
<span id="cb10-21"><a href="#cb10-21" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> <span class="op">*</span>text <span class="op">==</span> <span class="ch">&#39;</span><span class="sc">\0</span><span class="ch">&#39;</span><span class="op">;</span></span>
<span id="cb10-22"><a href="#cb10-22" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="op">(*</span>text<span class="op">!=</span><span class="ch">&#39;</span><span class="sc">\0</span><span class="ch">&#39;</span> <span class="op">&amp;&amp;</span> <span class="op">(</span>regexp<span class="op">[</span><span class="dv">0</span><span class="op">]==</span><span class="ch">&#39;.&#39;</span> <span class="op">||</span> regexp<span class="op">[</span><span class="dv">0</span><span class="op">]==*</span>text<span class="op">))</span></span>
<span id="cb10-23"><a href="#cb10-23" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> matchhere<span class="op">(</span>regexp<span class="op">+</span><span class="dv">1</span><span class="op">,</span> text<span class="op">+</span><span class="dv">1</span><span class="op">);</span></span>
<span id="cb10-24"><a href="#cb10-24" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="dv">0</span><span class="op">;</span></span>
<span id="cb10-25"><a href="#cb10-25" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb10-26"><a href="#cb10-26" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-27"><a href="#cb10-27" aria-hidden="true" tabindex="-1"></a><span class="co">/* matchstar: search for c*regexp at beginning of text */</span></span>
<span id="cb10-28"><a href="#cb10-28" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> matchstar<span class="op">(</span><span class="dt">int</span> c<span class="op">,</span> <span class="dt">char</span> <span class="op">*</span>regexp<span class="op">,</span> <span class="dt">char</span> <span class="op">*</span>text<span class="op">)</span></span>
<span id="cb10-29"><a href="#cb10-29" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb10-30"><a href="#cb10-30" aria-hidden="true" tabindex="-1"></a>    <span class="cf">do</span> <span class="op">{</span>    <span class="co">/* a * matches zero or more instances */</span></span>
<span id="cb10-31"><a href="#cb10-31" aria-hidden="true" tabindex="-1"></a>        <span class="cf">if</span> <span class="op">(</span>matchhere<span class="op">(</span>regexp<span class="op">,</span> text<span class="op">))</span></span>
<span id="cb10-32"><a href="#cb10-32" aria-hidden="true" tabindex="-1"></a>            <span class="cf">return</span> <span class="dv">1</span><span class="op">;</span></span>
<span id="cb10-33"><a href="#cb10-33" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span> <span class="cf">while</span> <span class="op">(*</span>text <span class="op">!=</span> <span class="ch">&#39;</span><span class="sc">\0</span><span class="ch">&#39;</span> <span class="op">&amp;&amp;</span> <span class="op">(*</span>text<span class="op">++</span> <span class="op">==</span> c <span class="op">||</span> c <span class="op">==</span> <span class="ch">&#39;.&#39;</span><span class="op">));</span></span>
<span id="cb10-34"><a href="#cb10-34" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="dv">0</span><span class="op">;</span></span>
<span id="cb10-35"><a href="#cb10-35" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</div>
<p>The driver function, <code>match</code>, checks if a string matches a
given regular expression. If the regex starts with <code>^</code>, it
must only match from the beginning, so it checks that with
<code>matchhere</code>. If not, the regex could match from any position
in the string, so it checks for the regexes’ match from every position
in the string.</p>
<p>The helper function, <code>matchhere</code>, checks if the regex
matches starting from the first position in the string. It handles
<code>*</code> for repetition, and <code>$</code> for ending.</p>
<p><code>matchstar</code> finds zero or more matches of a regex in the
string. This is done with a do while loop because there are 0 or more
occurrences possible.</p>
<p>All in all, three functions that clearly explain what they’re doing
and compose beautifully to tackle the problem at hand. Regexes are
extremely useful in programming, and to see most of them boiled down to
just these three functions makes this program beautiful, in my eyes.</p>
</section>
<section id="the-rest" class="level2">
<h2>The Rest?</h2>
<p>There are many beautiful programs – I just chose a few from my memory
but I’m sure you have plenty that spring to mind – if so, write about
them!</p>
</section>]]></description>
</item>
<item>
<title>Boring Technology</title>
<guid>https://write-every-day/11.html</guid>
<description><![CDATA[<h1 class="title" id="boring-technology">Boring
Technology</h1>
<p>In tech, there’s a love of “boring technology”, the stuff that people
know, and is fairly simple, so building upon the technology means that
you won’t run into many roadblocks. In short, the known knowns are there
and there are fewer unknown unknowns. I mainly agree with this sentiment
– if you want to build something stable, you don’t want to be a bug
tester for the underlying technology – you have your own bugs and
features to build for your own application, let alone the stuff you
build upon.</p>
<p>But, as with everything, it depends.</p>
<p>Nintendo is probably the biggest follower of this mantra – year after
year they release consoles that use fairly old hardware. They’ve gone on
record to say they like “withered technology”, since it’s easier for
developers to understand (the hardware they use has generally been
around for 5-10 years) and it forces the developers to create simpler
games (so less turnaround on game development). Of course, there’s a
trade-off – newer developers aren’t necessarily used to any one
platform, so using an older technology offers less benefit, and some
game studios wouldn’t want to build a game on weaker hardware – so they
went to the other consoles, like Sega, Sony, and Microsoft.</p>
<p>One example of Nintendo’s love of withered technology – in 1989 they
released the Gameboy – a small, hand-held device that let you play games
on the go. The CPU Nintendo decided to put in each of these? A 4MHz
Sharp LR35902. This chip was on par with other chips in the early 80s,
so by the time production started picking up in the early 90s, Gameboys
were shipping with 10 year old chips. Nearly 10 years later, in 1998,
Nintendo released a successor called the Gameboy color, with the same
chip, doubling the clock speed (8Mhz to run Gameboy color games).</p>
<p>The Gameboy was extremely successful.</p>
<p>But there are countless examples of not using boring technology to
achieve success too. Amazon, in 1996, decided to change the operating
system on all its data center servers from Solaris to a very unstable,
barely 1.0 Linux. Back then, there were a multitude of Unixes, with few
of them being open-source (and thus, requiring payment to a company in
exchange for support). It was a gutsy choice, and not without its trials
and tribulations, but fast-forward to today and I doubt many people use
any other Unix than Linux server-side.</p>
<p>In the late 2000s, many small startups sprung up to compete in the
SaaS market. Lots of them ended up using this “cool” and “new” framework
called Ruby on Rails. Ruby on Rails released in 2005, and within a few
years, many companies that would later become famous, like Shopify,
Github, Twitter, and many more built their businesses on it. They
could’ve chosen a boring technology like Java, or C#, or PHP, but they
liked it enough to give it a shot. Plenty of companies these days find
success using Ruby on Rails, and there are still a lot of developers for
it.</p>
<p>So where does that leave us? I think using boring technology requires
a few caveats. For one, boring technology is useful when you want to do
something that’s been done before. If you use similar technologies to do
a task that’s been done before, you’re probably not going to break the
underlying technology.</p>
<p>But if you’re building something to last, it’s hard to stick to
“boring technology” perpetually. You’ll always want to break backwards
compatibility sometimes. It would be absurd to build your new app in
Cobol (although you can), or something like RPG (every IBM computer
since the 1960s can run your app, think about backwards compatibility!).
You can only make good decisions, and revise them as you go.</p>
<p>One project that’s been around for a while, LLVM, had this to say
about its code churn, from the Architecture of Open Source
Applications:</p>
<blockquote>
<p>Despite its success so far, there is still a lot left to be done, as
well as the ever-present risk that LLVM will become less nimble and more
calcified as it ages. While there is no magic answer to this problem, I
hope that the continued exposure to new problem domains, a willingness
to reevaluate previous decisions, and to redesign and throw away code
will help. After all, the goal isn’t to be perfect, it is to keep
getting better over time.</p>
</blockquote>
<p>Predicting the future is a hard problem. If you could, you wouldn’t
be reading this post – buy a lottery ticket and start sipping mimosas on
the beach. You might choose some technology, built by some company, and
learn that company went bankrupt. Boring technology is only boring at
the moment, but it might become boring later on down the road – you just
have to pick the winners before they win.</p>
<p>Take the story on choosing Ruby on Rails: in 2022, a comment on
Hackernews about:</p>
<blockquote>
<p>If you Think Github, Gitlab and Shopify are relevant, then yes. Ruby
on Rails remains an excellent technical choice for mature products… Note
that, just like any other tool it has pros and cons, one should analyze
the system requirements and use whatever makes sense. I would however,
dare say that it is a great fit for majority of businesses. Honestly,
majority of frameworks out there today will get you 90% of the way:
Rails, Laravel, Phoenix and Django just to name a few. As I get older, I
tend to prefer boring tech myself..</p>
</blockquote>
<p>In 2005, Ruby on Rails was considered exciting. 15 years later, it’s
boring. Linux was exciting then, and hosting Solaris on the server-side
today? Unheard of. You can’t choose boring technology. You can only
choose the right choices for the time. Some choices work out, and some
don’t.</p>
<p>Invest in psychics to see the future.</p>]]></description>
</item>
<item>
<title>Computability and Consciousness</title>
<guid>https://write-every-day/10.html</guid>
<description><![CDATA[<h1 class="title"
id="computability-and-consciousness">Computability and
Consciousness</h1>
<hr />
<h1 class="toc-title" id="contents">Contents</h1>
<ul>
<li><a href="#computability-and-consciousness"
id="toc-computability-and-consciousness">Computability and
Consciousness</a></li>
</ul>
<hr />
<section id="computability-and-consciousness" class="level1">
<h1 id="computability-and-consciousness-1">Computability and
Consciousness</h1>
<p>There are a lot of problems that are hard for computers to solve but
are easy for us. For example, driving in a closed course, walking, and
handwriting detection all took many years for computers to handle
tolerably (sometime within the last 20 years). Clearly we’re not like
computers – it doesn’t take billions of operations in our mind to walk,
see, or read or write.</p>
<p>Also computers can’t solve all problems. Computers have many light
switches that can be used to signal two states (on or off). In terms of
a computer, that means that a computer program can take in as input some
finite number of 0s and 1s and return as a response some finite number
of 0s and 1s. Any problem that fits within that realm is solvable. In
more math terms, that means that computers can only solve problems that
fit within the countably infinite set – any problem that lies on the
number line from 0 to infinity. The set of countably infinite numbers is
enumerable: if you add 1 to 0 you get 1, if you add 1 to 1, you get 2,
and so on. You can keep going until you hit infinity.</p>
<p>But the actual number of questions that we can pose is more than
that. If you ask the question of how many numbers there are between 0
and 1, and prove that a computer could solve them all, you would try to
prove that the numbers between 0 and 1 are enumerable, and thus,
countably infinite. But if you say there are 3 steps, 0, 0.5, 1, you can
further subdivide those to 0, 0.25, 0.5, 0.75, 1. And so on and so forth
infinitely. Thus we can’t actually enumerate from 0 to 1, because any
smaller gap from 0 to the number proposed has a sea of infinity between
it, even if the number was infinitely small. Thus we can’t even count
the numbers between 0 and 1. Thus, computers cannot solve all problems
that we care about, since there are an uncountably infinite number of
them, and computers can only count to infinity.</p>
<p>Since we know that computers can’t solve all problems, the next
question is to ask if computers can solve some other questions we care
about, like consciousness. Thinking about evolution, if the Earth and
all life on it could be modeled as some large state machine, where every
organism would have some set of states it could call every tick of life
and all life on earth would be a collection of these. If life really
acted in this way, it would be possible to have life on earth be
simulated by a computer. But there’s an assumption that we could model
life with some state machine, which is something computable. But is what
we do captured by a state machine? The actions that we perform could
possibly be computable, but the motivations may not be. And if so,
consciousness would be fundamentally different actions in a state
machine.</p>
</section>]]></description>
</item>
<item>
<title>Improve vs Explore</title>
<guid>https://write-every-day/9.html</guid>
<description><![CDATA[<h1 class="title" id="improve-vs-explore">Improve
vs Explore</h1>
<p>Should you make something new for breakfast or eat eggs and toast
like you have for years? Should you learn something new or keep
practicing what you already know? Is it worth it to read that new book
or read an old classic you’ve already read, looking for new wisdom?</p>
<p>Every day we make choices that can broadly fall into two buckets:
Improving and Exploring. If you want to improve a skill you already
know, you can try to perfect it by doing some well-known exercises. In
music, that could mean playing scales or easier pieces you already know.
If you want to explore, that could mean anything from learning a new
piece to add to your repertoire to picking a new instrument to play. One
choice is more familiar and easy to quantify, whereas the other is
unfamiliar and hard to quantify. If a piano player learns how to play
the drums, how do you know before your invest hours into the drums how
much better you’ll get at the piano, or music in general? Exploring is
also hard because there are infinite things to explore at any time. I
could continue playing the piano, or choose the drums, or choose any
number of instruments to pick up or any number of music pieces to learn,
and for all of them, the rewards are uncertain.</p>
<p>The familiar improvement sure sounds nice, but you’ll eventually run
out gains from doing the same thing. Keep doing the same exercises?
It’ll take longer to build muscle in the same area. Keep playing the
same piece? Eventually you’ll play it just about as well as you can. So
you’re forced to explore a little bit.</p>
<p>Exploration sure sounds better, but it can be a slog. You might try
something new and realize your old skills have atrophied. Maybe you’ll
find that whatever you found out was strictly worse than whatever you
used to do in the past, and it was just better off to improve instead of
explore. If you get burnt too many times exploring, you’ll find the warm
embrace of improvement through familiar activities inviting.</p>
<p>There’s no real wisdom to be gleamed here. Even if you had the
fastest computer in the world and a relatively simple improve vs explore
dilemma, the computer most likely wouldn’t be able to find the optimal
allocation of improving vs exploring – that means there’s no one “best”
way of living life or improving a skill. I find something nice about
that – that we can’t reduce hard problems to simple computation makes
life worth living.</p>
<p>There are more areas in which this conflict comes up – you might
choose to believe stereotypes vs spending the time to think through
every scenario. We’ve learned that stereotypes are bad – they underpin
most of the injustices in the world today – but they’re also a great
evolutionary heuristic. If we always had to make a case for why the bear
in front of us could be nice and not maul us to death or that jumping
off a cliff might be good for us, there’d be a lot fewer people. Put
more simply, we have a conscious and an unconscious brain. The
unconscious brain just does things for us without rhyme or reason. It’s
the reason why we don’t have to consciously breathe or why our reflexes
move our hands off a hot stove. It takes less energy than our conscious
brain, and is resistant to exploring. The conscious part of us is more
malleable, but it takes a lot more time and energy. Thus, it’s less
likely to get stuck in a local minimum of reasoning, but only if our
brain has enough resources to devote to this kind of thinking. We’ve
also learned how to fuse the two – we’re very good at pattern matching,
but this can fail us when things seem incoherent, or otherwise defy our
expectations.</p>
<p>That just leaves how we choose to live our lives or improve our
skills. There’s probably many ways to get close enough to the top
(either being fulfilled or good at what you do) that there’s not much to
say about it. Some people choose pursuits that are very straightforward
and more amenable to more of the improve side, like chess, but that’s
not to say that top chess players don’t try to explore new ways to
improve their chess. Other pursuits that are more creative like pursuing
art or music require a lot of exploration to master. Some people prefer
to spend their time more focused on a routine whereas some are more free
form. Who’s to say what works for you?</p>]]></description>
</item>
<item>
<title>To master your tools, make them</title>
<guid>https://write-every-day/8.html</guid>
<description><![CDATA[<h1 class="title"
id="to-master-your-tools-make-them">To master your tools, make them</h1>
<hr />
<h1 class="toc-title" id="contents">Contents</h1>
<ul>
<li><a href="#a-toy-os" id="toc-a-toy-os">A toy OS</a></li>
<li><a href="#a-compiler" id="toc-a-compiler">A Compiler</a></li>
</ul>
<hr />
<p>I admire the tools I use in everyday life: it’s great how vehicles
can get us from one location to another swiftly, food is made, money
trades hands, and society works well enough that a large amount of
people can get what they need done without much coordination. It’s kind
of a wonder how well society works – I assume that most people haven’t
studied the law and yet we have a rough understanding of what is and
isn’t legal. I assume most people don’t have precise knowledge of how
the economy works, or how politics gets stuff done, or even how medicine
works, and yet, here we are, still trucking along. Most of these show
good design by those who designed the systems. Take money, for example:
it’s very complicated to understand how and why money gets produced, how
it’s valued, and so on, but we’ll buy or sell a lot of things and the
rest of that doesn’t really matter. Same with medicine, we take for
granted that most medicine does what it says, but it’s very hard to
prove that medicine actually works in the way we want it to.</p>
<p>To learn more about anything, it’s important to get hands-on
experience. In my case, as a programmer, we have many layers of
abstraction between our code and the computer. Most of these exist for
good reason (I would rather not run my code without an operating system
or write my code in machine code without a compiler), and there are good
implementations, so why bother learning more about them?</p>
<p>In my humble opinion, it improves our skills as craftspeople. You
learn a lot about your tools in the process, and the reasons why they
made the trade-offs they did. I personally seek to increase my
appreciation of stuff so I can keep myself motivated to learn something.
What better way to appreciate something than to learn how painful it is
to implement?</p>
<p>I’ve tried implementing many things, but my favorite things have to
be an OS, and compiler, and I’ll explain why I chose those projects.</p>
<section id="a-toy-os" class="level2">
<h2>A toy OS</h2>
<p>The bridge between hardware and software is the operating system. The
code that protects you from yourself. I started off by reading through
<a href="https://pages.cs.wisc.edu/~remzi/OSTEP/">Operating Systems:
Three Easy Pieces</a>, and implementing most of the projects throughout
the book. The companion code and problems outline some basic programs to
write, but you’re generally benchmarking your host OS to learn more
about it. That wasn’t enough for me.</p>
<p>I moved onto reading <a
href="https://www.amazon.com/Lions-Commentary-Unix-John/dp/1573980137">Lion’s
commentary on Unix</a> since it gave commentary on an actual system
(Unix V6), but I found the code hard to digest since it was using C from
the 70s. Finally, I stumbled upon <a
href="https://github.com/o8vm/octox">Octox</a> which is an
implementation of xv6-riscv in rust, and you can run the entire system
with a <code>cargo run</code> command. I took this code, tweaked it a
bunch, and learned a lot about operating systems in the process.</p>
<p>Operating systems have the tricky job of taking a scarce resource
(the hardware of the computer) and doling them out to multiple users at
the same time, while also not allowing the users to step on each other’s
toes. The operating system also has to provide a stable interface that
doesn’t change, since any user visible changes require changes in a lot
of code that rely upon the OS, and I learned about providing a strict
interface boundary. Data in, data out. Don’t break your promises. For a
normal monolithic kernel, it gets very hard to keep this promise,
because so much of the kernel is hidden from the user. For a
microkernel, since most of the functionality of the OS is owned by
various services in user and kernel space, it’s not as bad to break
backwards compatibility, since that only affects the code that requires
that particular service, rather than the whole world.</p>
<p>Boundaries are important for all of us.</p>
</section>
<section id="a-compiler" class="level2">
<h2>A Compiler</h2>
<p>I followed <a href="https://craftinginterpreters.com/">Crafting
Interpreters</a> to implement two interpreters, the first part in Rust
and the second part in C. A compiler really is just another program –
you give it a program, some knobs to tweak, and you get back an
executable program.</p>
<p>Writing a compiler was useful in more areas than language design – I
improved at parsing various data structures and stopped trying to hack a
duct tape parser with regex, but started composing parsers off of
smaller parts to make a better parser. My knowledge in interpreting code
also helped for projects at work that required constructing languages
that supported powerful features like macros, but I also learned that
testing is invaluable to a program as complicated as a compiler.</p>
<p>You have to generate tests for any arbitrarily valid grammar and the
compiler always needs to give the correct result. The way that most
compiler writers do that these days? Fuzzing. I added it to my toolbox
and started fuzzing my own projects to find bugs. I found a lot of them.
Now I have a lot more bugs to fix.</p>
<p>Overall, the world became easier to parse.</p>
</section>]]></description>
</item>
<item>
<title>Why you should read position papers</title>
<guid>https://write-every-day/7.html</guid>
<description><![CDATA[<h1 class="title"
id="why-you-should-read-position-papers">Why you should read position
papers</h1>
<hr />
<h1 class="toc-title" id="contents">Contents</h1>
<ul>
<li><a href="#a-critique-of-verbal-behavior"
id="toc-a-critique-of-verbal-behavior">A Critique of Verbal
Behavior</a></li>
<li><a href="#a-theory-of-justice" id="toc-a-theory-of-justice">A Theory
of Justice</a></li>
<li><a href="#the-end-of-history" id="toc-the-end-of-history">The End of
History</a></li>
<li><a href="#prospect-theory" id="toc-prospect-theory">Prospect
Theory</a></li>
<li><a
href="#the-unreasonable-effectiveness-of-mathematics-in-the-natural-sciences"
id="toc-the-unreasonable-effectiveness-of-mathematics-in-the-natural-sciences">The
Unreasonable Effectiveness of Mathematics in the Natural
Sciences</a></li>
<li><a href="#why-most-published-research-findings-are-false"
id="toc-why-most-published-research-findings-are-false">Why Most
Published Research Findings are False</a></li>
<li><a href="#c-is-not-a-low-level-language"
id="toc-c-is-not-a-low-level-language">C is not a Low-level
Language</a></li>
</ul>
<hr />
<p>My favorite papers to read are position papers – papers that explain
a conflict in an area of research and where the author picks a side and
defends their position. Position papers are great for sparking
discussion: it’s especially good to read a paper where you disagree with
the author’s point of view and use it to reflect upon your own
position.</p>
<p>Position papers are also interesting to look at historically: some
position papers won, in which they become part of the mainstream and
integrated as common sense. Other times, the position paper loses and
the other side wins. Either way, I respect authors who are willing to
drive their flag into one side or another and defend their position. It
takes a lot of gusto, cause if you’re right, it looks like you were
preaching to the gospel, and if you’re wrong, you lose credibility. I’m
all about writing down my take for history to make fun of, so I’m going
to write about some of my favorite position papers and why you should
read them – hopefully you can think back to a few of your favorite
position papers as well.</p>
<p>P.S. Not all of these are papers, but they are on a position and a
writing so they count!</p>
<section id="a-critique-of-verbal-behavior" class="level2">
<h2>A Critique of Verbal Behavior</h2>
<ul>
<li><a href="https://chomsky.info/1967____/">A Critique of Verbal
Behavior</a></li>
</ul>
<p>Psychologists have long wondered how language is acquired by humans.
It seems to defy all of our traditional understanding – people who have
been isolated at birth long enough seem not to “acquire” language in the
complex ways that socialized humans do. However, children who grow up in
otherwise linguistically lacking environments can still command language
in a complex way, even if other people around them do not. Thus,
language acquisition is probably not all acquired by the environment, or
determined genetically since both factors intertwine to determine our
control of language.</p>
<p>In the first half of the 1900s, Behaviorism became a popular way of
explaining cognition scientifically – compared to previous movements
which were untestable, like Psychoanalytics, which focuses on the
unconscious self, Behaviorists sought to make more of psychology
directly testable. The Behaviorists turned their eye to language
acquisition, and a prominent figure at the time, Skinner, wrote the book
“Verbal Behavior”, and a then young Chomsky wrote a rebuttal to it.</p>
<p>The crux of the rebuttal takes Skinner’s point that external stimuli
are of “overwhelming importance” to language acquisition, since
behaviorists believe that reinforcement is paramount in enforcing
behaviors in humans, and counters it. Chomsky explains that the rules of
grammar are far too complicated to be learned from simple interactions
with people, and thus, children who utter sentences must have some
innate knowledge about the rules of grammar and stimulus helps them
learn new words and concepts but not the underlying grammar. Chomsky
says “This task [language] is accomplished in an astonishingly short
time, to a large extent independently of intelligence, and in a
comparable way by all children…”.</p>
<p>He concludes by saying: “The fact that all normal children acquire
essentially comparable grammars of great complexity with remarkable
rapidity suggests that human beings are somehow specially designed to do
this, with data-handling or ‘hypothesis-formulating’ ability of unknown
character and complexity.”</p>
<p>While it’s not true that Skinner believed the language acquisition
was purely via stimulus (and so Skinner and Chomsky agreed that their
must be something natural to language acquisition), this paper was
widely influential in psychology and computation, and sparked a whole
set of debates on the computability of language and how we acquire
language.</p>
</section>
<section id="a-theory-of-justice" class="level2">
<h2>A Theory of Justice</h2>
<ul>
<li><a href="https://en.wikipedia.org/wiki/A_Theory_of_Justice">A Theory
of Justice</a></li>
</ul>
<p>A Theory of Justice is a political philosophy book by John Rawls from
1971, who famously talks about a thought experiment called “the original
position” also referred to as the “veil of ignorance”.</p>
<p>Imagine that you’re a soul, and some arbiter gives you two choices
for the society you could live in. Since you’re just a soul (thus you
don’t know anything about your physical or mental capabilities or the
structure of society), what rules should you employ to make society work
out for you?</p>
<p>Rawls argues that with this starting point, the only way to create a
society is to create one that is “fair to all”, since if you choose to
privilege an arbitrary group in society, there is a chance you will not
end up in that group, and thus, be disenfranchised. So, you’ll lean
towards a fair society. Thus, Rawls says, the original position informs
a set of principles that create a fair society for all, and one that
everyone would agree upon.</p>
<p>The principles are:</p>
<ol type="1">
<li>Each person has a set of basic liberties, compatible with the rest
of society.</li>
<li>Everyone has an equal opportunity to pursue any office or
position</li>
<li>Socioeconomic inequalities are set to give the greatest benefit to
the worst off.</li>
</ol>
<p>A Theory of Justice does well in explaining a simple thought
experiment and using it as the basis for some axioms to build society
and then discuss how said society would function, and sparked a lot of
discussion in a lot of different fields.</p>
<p>They even made a musical out of it.</p>
</section>
<section id="the-end-of-history" class="level2">
<h2>The End of History</h2>
<ul>
<li><a
href="https://www.amazon.com/End-History-Last-Man/dp/0743284550">The End
of History</a></li>
</ul>
<p>The End of History is a book by Francis Fukuyama in 1992, a political
scientist who makes a bold claim: with the fall of the Soviet Union,
“the end of history” has come, that Western liberal democracy is the
final form of human government, and that it will remain that way,
forever.</p>
<p>Fukuyama draws upon Hegel and Marx to explain that history is a
progression of different eras with different dominant political
frameworks: mercantilism, capitalism, communism, liberal democracy all
came one after another and coincided with each other.</p>
<p>This is probably the most “position” writing on this list. I chose
this book (it’s also a paper) because I completely disagree with it – in
2024, things look a lot less rosy than they did in 1992. Russia has
re-emerged as a power, North Korea gained weapons of mass destruction,
China is increasing pressure on Taiwan and Hong Kong, and the political
situation in the middle east has completely crumbled after the war on
terror.</p>
<p>Fukuyama also intertwines western liberal democracy with economics –
he picks liberal democracy for the political side and capitalism for the
economic side. While there has been some turn against liberal democracy
and towards autarky, a lot of people changed their minds about the
efficacy of capitalism after the Great Financial Crash. Capitalism is on
top for now and so is liberal democracy, but will it be that way
forever, as Fukuyama so bravely declares? I think not.</p>
<p>Even if I’m wrong, forever is a long time so I’ll just keep stalling
until I’m dead or right.</p>
</section>
<section id="prospect-theory" class="level2">
<h2>Prospect Theory</h2>
<ul>
<li><a
href="http://www.albacharia.ma/xmlui/bitstream/handle/123456789/31987/kahnmtversky.pdf">Prospect
Theory</a></li>
</ul>
<p>Two psychologists write a math paper and win a Nobel prize in
economics. Want any more argument to study widely?</p>
<p>This paper written by Tversky and Kahneman starts out by discussing
the way most economists thought of utility at the time, expected utility
theory, discusses its shortfalls, and then outlines a new theory,
prospect theory.</p>
<p>In economics, you choose a game for participants to play, and all
actors have certain choices to make, and all choices grant a certain
amount of utility that can be reduced to a single number. All agents in
this game should make all choices rationally, given the amount of
information they have available. Rational in this case means agents
should maximize utility. This is of course mathematically optimal, but
as the paper points out, we aren’t perfectly rational, and so this
assumption is flawed.</p>
<p>Prospect theory notes experimentally that we view losses and gains
differently, and are not always risk-neutral. If you’re given a choice
between losing money and gaining money, people dislike losing money a
lot more than gaining money. We tend to remember the bad times more than
the good times. That makes sense – we’re all attracted like moths to a
flame to bad news or gossip. Why shouldn’t it be the case for us as
economic actors?</p>
<p>This paper was widely influential, and economics in particular has
seen a boon in experimental research – every year we find more cognitive
biases in the ways we interact in economic settings, and learn more
about human psychology through these findings.</p>
<p>Sometimes challenging the mainstream has good prospects.</p>
</section>
<section
id="the-unreasonable-effectiveness-of-mathematics-in-the-natural-sciences"
class="level2">
<h2>The Unreasonable Effectiveness of Mathematics in the Natural
Sciences</h2>
<ul>
<li><a href="https://www.maths.ed.ac.uk/~v1ranick/papers/wigner.pdf">The
Unreasonable Effectiveness of Mathematics in the Natural
Sciences</a></li>
</ul>
<p>In 1960, a mathematician named Eugene Wigner published this paper,
where he notes that mathematics is extremely useful in modeling the real
world.</p>
<p>In 2024, I think you could change the title of this piece to “The
Unreasonable Effectiveness of Mathematics”, full stop. Even as a
international relations major taking mainly economics and political
science classes, I had a lot of math and statistics classes to take. You
just can’t read papers in those fields without math. Every economics
paper has either statistics or math in it. Almost all political science
papers require a solid foundation in statistics to even read.</p>
<p>Mathematics has really won out over here, and it took over the
natural sciences a long time ago.</p>
<p>It’s kind of funny to read this paper with Wigner giving such basic
examples like gravity or using linear algebra in physics, when we live
in a world now with AI models using linear algebra to create models that
can respond in a chatbot like fashion.</p>
</section>
<section id="why-most-published-research-findings-are-false"
class="level2">
<h2>Why Most Published Research Findings are False</h2>
<ul>
<li><a
href="https://www.tandfonline.com/doi/full/10.1080/09332480.2019.1579573">Why
Most Published Research Findings are False</a></li>
</ul>
<p>In 2005, a physician named John Ioannidis wrote this highly talked
about paper that uses some back of the envelope numbers to come to the
conclusion that at least 50% of papers (in medicine) might be false
positives, and thus, false.</p>
<p>Variables in the study that have an effect return significant
results, but there is some acceptance of false-positives, determined by
the p-value the researcher chooses. Normally, a false-positive rate of
5%, or less than 0.05 is considered acceptable, so there’s a 5% chance
that something that did not have an effect shows up as having an effect.
So the p-value metric is supposed to make the upper bound of
false-positives 5%.</p>
<p>Unfortunately, it’s not quite so rosy. Since journals tend to only
publish significant results (since scientists read papers to learn what
has an effect, instead of combing through articles to find out what had
no effect). For an example, let’s say there is a researcher, A, who
finds that some variable B, is significant in some experiment E. They
rush to publish a result and are published. Meanwhile, 19 other
researches try the same thing and find no effect, which follows since
our p-value is 0.05. However, even though they were 19 chances to
disprove the efficacy of changing variable B in the experiment, those
weren’t published, only the false positive.</p>
<p>Whether or not “most” published research findings are false is up for
debate, but Ioannidis points out that experiments in medicine use
experiments with smaller sizes in clinical trials to find medicine that
works for patients. But this is doomed, since the smaller the sample,
the less power of the study and the more likely it is to find a
false-positive, which would do more harm than good to society at
large.</p>
<p>The paper gives 6 corollaries for ways to find research that’s more
likely to be wrong:</p>
<ol type="1">
<li>The smaller the studies conducted in a scientific field, the less
likely findings are to be true.</li>
<li>The smaller the effect size, the less likely findings are to be
true.</li>
<li>The greater the number and lesser the selection of tested
relationships in a scientific field, the less likely findings are to be
true.</li>
<li>The greater the flexibility in designs, definitions, outcomes, and
analytical modes, the less likely findings are to be true.</li>
<li>The greater the financial and other interests and prejudices in a
scientific field, the less likely findings are to be true.</li>
<li>The hotter a field, the less likely findings are to be true.</li>
</ol>
<p>This paper goes against the grain by questioning how useful currently
published research is, and gives a reason for why the current
replication crisis is ongoing. Researchers pursue fairly complicated
models which give them a large degree of freedom to find significant
results, regardless of if they’re significant.</p>
</section>
<section id="c-is-not-a-low-level-language" class="level2">
<h2>C is not a Low-level Language</h2>
<ul>
<li><a href="https://dl.acm.org/doi/pdf/10.1145/3212477.3212479">C is
not a Low-level Language</a></li>
</ul>
<p>David Chisnall, a computer architect wrote this paper in 2018 to
discuss why C is not a low-level language, and all the troubles that
causes, motivated by the recent exploitations in instruction level
parallelism, spectre and meltdown.</p>
<p>Low level languages map closely to the underlying hardware, in
contrast to higher-level languages, which are more abstract and map
moreso towards the way a programmer might think about a problem. C is
considered a low-level language, which makes it a fit for writing
performant systems, like operating systems, compilers, and databases.
However, C is a language that was written for the PDP-11, a 16-bit
computer from the 1960s. C defines a virtual machine where instructions
execute one by one in serial order. This made sense in when C was
written, since computers actually executed instructions one by one.</p>
<p>In 2024, that hasn’t been true for decades. Compilers are free to
reorder code in order to speed up execution, so C code that you write
might be executed in a completely different order than the one that you
specify. Even worse? Many instructions are executed on different
processors at the same time (the author notes that a modern intel
processor has ~180 instructions in flight at the same time), and states
that this quest for speed without embedding this into the language
caused these exploitations and numerous more throughout the years.</p>
<p>As well, memory is no longer sequential (as the C virtual machine
believes) and computers have layers of caches, many more registers,
especially ones which can process the same data in parallel, and padding
is required on data structures to avoid large performance penalties in
data fetching. None of these features are built into C, because C
predates all of these requirements, and it would be nigh impossible to
add these restrictions into C, and thus, we should look towards newer
languages to code in, since the future will likely be on more
heterogeneous computing (CPUs, GPUs, FPGAs, mobile, cloud, desktop), and
the hardware will have lots of extra functionality to tap into that C
has a hard time using.</p>
<p>I like this paper because it challenges common gospel and gives
reasons for why our mental model of the code we write is so important.
Most programmers don’t really care about the virtual machine their code
targets, but it has a lot of implications in practice. Code reordering
might hoist a pointer dereference before a null check, thus crashing a
program that should never crash. A small change in some code might cause
a program to run 10x slower due to an increase in cache misses. There
are many more problems that occur in practice, but neither the
programmer nor the compiler writer really have a way around it, since
even the processor can reorder instructions due to the need for
speed.</p>
<p>We’re all doomed.</p>
</section>]]></description>
</item>
<item>
<title>Offline learning: tools of the trade</title>
<guid>https://write-every-day/6.html</guid>
<description><![CDATA[<h1 class="title"
id="offline-learning-tools-of-the-trade">Offline learning: tools of the
trade</h1>
<p>20 years ago in 2005, a movement called “One Laptop per Child” (OLPC)
was born at MIT. Its aim? Hand an affordable (sub $100 laptop) to every
child on earth. The laptop that they produced, the OLPC XO1 was meant to
be mass produced, cheap, rugged, and use so little electricity it could
be powered completely by a hand crank. Kofi Annan, then UN
secretary-general took quick notice, bringing the initiative
international acclaim and funding.</p>
<p>20 years later, I think we’ve learned that not every child needs a
laptop. But OLPC planted the seeds of a movement. Wikipedia offers its
pages for download, and even created software called Kiwix to allow
users to browse all of Wikipedia for a (now small) footprint of about
10GB. Similarly, Khan Academy and other sites started popping up,
offering courses for K-12 education. Universities started offering their
course materials and recording lectures so that people could learn any
topic they wanted to asynchronously and from the comfort of their
home.</p>
<p>I was a big proponent of using technology as a tool for education. I
went through all the Khan Academy modules I could and went through
courses offered at universities like MIT, Stanford, and Harvard. It was
great like getting a golden ticket, to a higher quality education.</p>
<p>I still think the internet is a useful tool for education, but in the
past 20 years, the internet has become a tool to divert our attention
for profit. It is no longer the text-based browse a bit tool of
yesteryear, but rather, a more attention seeking medium meant to glue us
to our screens for engagement. This isn’t in the users best
interests.</p>
<p>One way I’ve found to help with this is to limit my internet
consumption by moving to a polling model. Instead of visiting my
favorite sites constantly, I’ll just use their RSS feeds to get updates,
and when I have no more updates to read, that’s it for the day. My RSS
feed doesn’t even get updates every day, so it’ll be more of a once a
week thing.</p>
<p>Taking that to its extreme is downloading everything for offline
usage. Sometimes I’ll be out on the town, or traveling, and data is
patchy. In that case, If I want to be productive, I need my content to
be available, preferably on both my phone and my computer, in a way that
doesn’t compromise the quality of what I’m trying to enjoy.</p>
<p>To that end, I’ve been iterating on my own “Offline OS”: a set of
files I keep on my laptop and backed up, organized and searchable
through a web browser. Even if a web browser isn’t connected to the
internet, it is a remarkably useful piece of technology – it can serve
HTML files that can perform search in a local search index on disk, so
anything can be found in milliseconds. I keep my music, podcasts,
lectures, notes, papers, bookmarks, recipes and more in this format. I
sync this with my phone, so with just one command I can browse my
content offline on my laptop or my phone, whichever is more
convenient.</p>
<p>In my case, I have a lot of lecture videos, so my content on disk is
about 400GB, which can’t fit on my phone. To do so, I don’t sync any
video files to my phone, since website content and documents aren’t that
heavy.</p>
<p>Personal computing has come a long way: you can save high quality
resources on disk for the cost of almost nothing. In fact, the dream
everyone having a computer for $100 is taken for granted these days that
we don’t even talk about it. A used computer with decent enough specs (a
quick search on ebay turned up a computer with a processor <span
class="citation" data-cites="3.2GHz">@3.2GHz</span> w/ 8GB of RAM and a
128GB SSD) goes for about $25, or about 4 hours of minimum wage in
America. If not, there are plenty of cheap or even free computers with
similar or better specs to get from your local recycler of
computers.</p>
<p>The tools to learn anything you want are out there now for a very low
price. All that’s left is to find the motivation to learn.</p>
<p>And that might be the hardest thing of all.</p>]]></description>
</item>
<item>
<title>Karma Police: the resurgence of attention</title>
<guid>https://write-every-day/5.html</guid>
<description><![CDATA[<h1 class="title"
id="karma-police-the-resurgence-of-attention">Karma Police: the
resurgence of attention</h1>
<hr />
<h1 class="toc-title" id="contents">Contents</h1>
<ul>
<li><a href="#email" id="toc-email">Email</a></li>
<li><a href="#forums" id="toc-forums">Forums</a></li>
<li><a href="#the-resurgence-of-scarcity"
id="toc-the-resurgence-of-scarcity">The resurgence of scarcity</a></li>
<li><a href="#why-attention-matters" id="toc-why-attention-matters">Why
attention matters</a></li>
</ul>
<hr />
<p>With Reddit’s IPO imminent, I figured it’d be a good time to talk
about social communities online, how they’ve changed through the years,
and the seeds of their demise.</p>
<section id="email" class="level2">
<h2>Email</h2>
<p>I’m going to start with email since it has capabilities to create a
community (with mailing lists). Email between person to person isn’t
that different from sending a letter, but creating carbon copies allow
it to create a community: you can send the same mail to many people and
they can respond in a thread.</p>
<p>Needless to say, email became very popular, but people don’t use it
as a social community much: some OSS software uses it for development
(Linux, Postgres) and some folks use it to arrange meetings or
discussions. Although using email is very convenient, many people hate
it:</p>
<p>Donald Knuth famously said this about email in 1990:</p>
<blockquote>
<p>I have been a happy man ever since January 1, 1990, when I no longer
had an email address. I’d used email since about 1975, and it seems to
me that 15 years of email is plenty for one lifetime.</p>
</blockquote>
<blockquote>
<p>Email is a wonderful thing for people whose role in life is to be on
top of things. But not for me; my role is to be on the bottom of things.
What I do takes long hours of studying and uninterruptible
concentration. I try to learn certain areas of computer science
exhaustively; then I try to digest that knowledge into a form that is
accessible to people who don’t have time for such study.</p>
</blockquote>
<blockquote>
<p>On the other hand, I need to communicate with thousands of people all
over the world as I write my books. I also want to be responsive to the
people who read those books and have questions or comments. My goal is
to do this communication efficiently, in batch mode — like, one day
every six months. So if you want to write to me about any topic, please
use good ol’ snail mail…</p>
</blockquote>
<p>Many people dream of “inbox zero”, where they have no more emails to
read or respond to. Email suffers the same problem almost everything
that reduces friction does: it causes problems of abundance.</p>
<p>In the 60s and 70s in America, as telephones became more popular,
some people racked up huge phone bills to talk to their friends and keep
up with the gossip in their friend group. The telephone, a tool for
increased communication, did the opposite: it isolated people from their
community.</p>
<p>Email is a rudimentary social network: it wasn’t very popular until
the 90s and people didn’t use its social capabilities much. Onto the
next era.</p>
</section>
<section id="forums" class="level2">
<h2>Forums</h2>
<p>With the World Wide Web becoming popular in the late 90s, people
wanted to find similarly minded people to discuss things with: so they
created specialized websites, called forums for this purpose. Someone
(or a team of people) manage the site, and everyone discusses on or
off-topic things. Moderation was loose and things were hectic, but they
worked. Sometimes your favorite forum would disappear, or the mods would
make it invite-only, but anybody was free to spin up their own new
forum.</p>
<p>Forums had threads as a first-class feature: you could make a thread
and users could comment on it to discuss. Some forums had upvotes and
downvotes natively, expressing approval or disapproval of posts on the
forum.</p>
<p>Reddit saw the use of forums and decided to create a meta-forum: a
website where users could create a forum about any topic, moderate it
however they wished, and so users wouldn’t have to remember all the
forums they used in the past. Reddit would handle the discovery: they
would aggregate every subreddit like google did for the web, and they
had an interesting way of arranging content: highly upvoted posts would
float to the top, so users could read “interesting” content quickly,
keeping them engaged.</p>
<p>It was a smash hit. By the early 2010s, many communities moved to
Reddit, and over 10 years later, Reddit is now looking to IPO.</p>
<p>But can you really turn a forum run by users into a profitable
business?</p>
<p>Reddit’s business model is to own the website reddit.com, and own
searching, but there’s no reason that anybody has to keep using the
site. Reddit is the overlord of the fiefdom, but the vassals don’t get
paid taxes.</p>
<p>As well, there’s been a turn against “engaging” content. Our
attention spans are finite, and engaging content in surplus becomes
trite.</p>
<p>The upvote has lost, and the karma police will collect their dues. I
predict a messy IPO.</p>
</section>
<section id="the-resurgence-of-scarcity" class="level2">
<h2>The resurgence of scarcity</h2>
<p>For most normal economic goods, suppliers prefer scarcity to increase
profit margins, but they prefer surplus to maximize profits. If one
supplier can corner the market, there’s a monopoly price that introduces
scarcity to strictly maximize profits. If there are enough suppliers,
all suppliers tend towards surplus to maximize their payoffs (which is
zero).</p>
<p>On the other side, users tend to prefer goods in surplus since it
lowers the cost of their goods and increases quality and choice.</p>
<p>But the economics of surplus don’t make sense for everything.</p>
<p>When people left the communist bloc to see the western world, surplus
was all they saw. Grocery stores were stocked to the brim where they
stores would waste perfectly good food to entice customers with only the
freshest food. There weren’t lines to order food or shortages.</p>
<p>But while we don’t starve, we have another problem: in America, the
obesity rate is nearly 45%. In 1960, it was 13%. Our life expectancy
hasn’t gotten much better either, from about 70 years to 76 years, with
most of the gains coming from earlier on in life.</p>
<p>With attention too, people are rethinking their relationship with
technology. Communities without internet have popped up, with eager
urbanites moving into those rural areas. Others have decided to restrict
the time that they use technology to unwind. Basically, self-imposed
scarcity, with promising results, like improving mental health and
increasing the meaning in their life.</p>
<p>Most of all, with the ever increasing tide of technology and
capitalism, people are re-learned that the incentives of suppliers and
consumers aren’t always aligned. Capitalized social media platforms like
Facebook, Reddit, and Twitter need your attention to keep generating
profits.</p>
</section>
<section id="why-attention-matters" class="level2">
<h2>Why attention matters</h2>
<p>As a disgruntled 20-something, I used social media as a crutch to
stop myself from thinking the woes in my life. I wasn’t going anywhere,
I was working increasingly long hours doing hard labor jobs that I knew
I couldn’t maintain, being paid next to nothing to maintain my pitiful
existence. Where I worked, I knew of people who died by alcoholism,
suicide, and were maimed in the workplace. Every extra day I worked in
these conditions, I increased my chances of being one of those people,
long forgotten.</p>
<p>I talked to a coworker who had been working similar jobs for 20
years, being paid minimum wage just like myself. He couldn’t afford to
raise his family and was in heavy debt. His health was terrible from the
alcohol and drug consumption needed to keep up with the 80 hour work
weeks. He had professed a love of social media as a tool to stop himself
from thinking about his miserable experience. He told me all this to say
that time and focus was the resource he misused the most in his life. He
was a 40 something guy, but I was in my 20s. I had time. I took his
lesson to heart and began to take care of myself and preserve my
attention. I learned a desirable skill to leave the never-ending cycle
of low skill, low paid work and started to turn my life around.</p>
<p>As Socrates said, “The unexamined life is not worth living”. I wish I
learned that sooner.</p>
</section>]]></description>
</item>
<item>
<title>Great Design</title>
<guid>https://write-every-day/4.html</guid>
<description><![CDATA[<h1 class="title" id="great-design">Great
Design</h1>
<hr />
<h1 class="toc-title" id="contents">Contents</h1>
<ul>
<li><a href="#the-unix-file-api" id="toc-the-unix-file-api">The Unix
File API</a></li>
<li><a href="#utf-8" id="toc-utf-8">UTF-8</a></li>
<li><a href="#tcp" id="toc-tcp">TCP</a></li>
<li><a href="#message-passing" id="toc-message-passing">Message
Passing</a></li>
</ul>
<hr />
<p>Software has plenty of examples of bad design, but the well designed
stuff becomes almost invisible and isn’t talked about very much. Today I
chose a few of my favorite ideas and implementations that deserve the
mantle of truly “Great” design.</p>
<section id="the-unix-file-api" class="level2">
<h2>The Unix File API</h2>
<p>If you write a file in Unix, you just need a few system calls.
<code>open</code>, <code>read</code>, <code>write</code>,
<code>seek</code>, and <code>close</code>. That’s all you need. The
caller doesn’t need to know about the perils of writing a file, or where
the bytes go, they create a file, read and write data from it, and
that’s all they need to do.</p>
<p>None of the implementation details bleed out to the caller: you don’t
have to worry about what kind of device you’re writing to, whether it be
an SSD, HDD, tape, or even a piece of paper. The operating system
figures that out for you. If you read or write, the operating system
moves the needle on tape, the pen on paper, or talks to the SSD’s block
controller.</p>
<p>The interface itself doesn’t care about its backing store, since it
assumes the caller doesn’t. If the caller notices that operations are
slow, they might start looking at the storage media, but not before
admiring how nice the interface is.</p>
<p>Writing to persistent storage is a gargantuan task: Linux file system
drivers are millions of lines of dense code that works behind the
scenes, and the user doesn’t have to know a thing about it.</p>
<p>Other operating systems decided to create system calls that were tied
to the physical media. That meant that programmers would have to change
their code if their storage media changed, which meant the code was
brittle and hard to port. The Unix file API sidesteps all that. The user
doesn’t have to change a thing no matter the backing media.</p>
<p>The API is also easy to optimize – if your storage media supports
concurrent reading and writing, <code>read</code> and <code>write</code>
can fire off as many workers as needed to make your request as fast as
possible, or <code>read</code> out of order on disk as long as the
caller has their requirements met, which is the bytes arrive in the
order they are on disk.</p>
<p>A true paragon of good design.</p>
</section>
<section id="utf-8" class="level2">
<h2>UTF-8</h2>
<p>In the 1990s, many people speaking many different languages started
to use the internet. Many languages have more than 256 symbols, so they
don’t fit in a byte, and many languages had created their own custom
encodings that made browsing the web a struggle – you’d need to download
dozens of encodings for all these different languages to just browse the
internet.</p>
<p>That was until UTF-8 became dominant. Now, UTF-8 is the encoding of
the web, but it wasn’t always that way – even 15 years ago the Japanese
web had many pages using Shift-JIS.</p>
<p>The ingenuity of UTF-8 lies in its interoperability with ASCII with
no overhead, and the ability to encode either 1, 2, 3, or 4-byte
characters by only using 1, 5, 8, or 11 bits to signal the remaining
length of each character. With 21 bits still remaining for a 4-byte
character, UTF-8 can support <code>2^21</code> bytes, or a little over 2
million characters.</p>
<p>That should be enough for a while.</p>
</section>
<section id="tcp" class="level2">
<h2>TCP</h2>
<p>TCP was introduced 50 years ago, and it still holds up as good
design: it provides one guarantee, like re-requesting lost packets and
providing in-order transmission of packets between two programs. TCP
also notifies the client of an error if packets couldn’t be received
from the sender. These strengths, in exchange for less throughput and
higher latency make it easy for people to implement higher level
protocols on top of TCP, like HTTP. As well, its transmission control
algorithms were invaluable in helping the internet scale to its current
usage.</p>
<p>TCP shows the importance of abstraction in design – IP, which TCP is
built on top of, may lose packets in transmission due to network
congestion, load balancing, or other hardware problems in the physical
or link layers. Packets could also be corrupted, or come in any order.
TCP handles error handling and, with little overhead, turns those
unwiedly packets into a set of ordered packets.</p>
<p>If you’re skeptical of the guarantees TCP provides, try writing an
application without it, using just UDP – it’s hard. You have to build a
robust in-order network stack at the system level so the application
layer can consume bytes in-order, or write your application to tolerate
out of order transmissions, dropped packets, and unbounded timeouts.</p>
<p>TCP takes care of that.</p>
</section>
<section id="message-passing" class="level2">
<h2>Message Passing</h2>
<p>If Smalltalk won, this section would be called “Object-Oriented
Languages”. Alas, Smalltalk did not win, and everyone thinks OOP means
Java style interfaces and inheritance. Sigh. Erlang might be the only
true Object Oriented language still around.</p>
<p>Message Passing is what it sounds like. You pass a message to an
actor, who receives the message and acts accordingly based on the
message. In Erlang, objects are processes that can only receive and send
messages and cannot share any state except by message passing. This
metaphor is very powerful up and down the stack.</p>
<p>A computer nowadays has many cores (my computer has 16), and they all
have their own memory and have to read and write to both core-local and
shared caches in order to receive and broadcast their state (the results
of their computations). Rather than have each core have access to each
other core (which would get messy quickly), cores can pass messages to
each other, allowing them to coordinate (e.g. invalidate a value because
it has become stale, or publish a new value since it’s been
updated).</p>
<p>If I choose to read a webpage on my browser, I receive some HTML,
CSS, and JS over the wire and my browser renders it. If I pass some
extra parameters along with my request, like query parameters or a body,
I can customize the response I get. I can also send some data to the
computer, which it can respond to in kind by sending a POST request. I
have no access to the internals of the server, and the server has no
access to my computer’s internals. Message passing becomes the boundary.
As long as both sides make backwards compatible changes (like still
responding to the same messages the same way), either side can make any
arbitrary changes.</p>
<p>When we converse with other people, we pass messages through spoken
word to each other to understand each other’s internal state
(emotions).We also use the written word to do the same thing. Without
message passing, we would have to do brain surgery to understand each
other’s thoughts, and even then, since we’re not translate physical
signals from the brain into coherent thoughts, this wouldn’t work
either.</p>
<p>When I try to design something, I always prefer stateless message
passing. If two actors can get away with message passing, even if it
makes things a little harder in the short-term, it’s almost always worth
it in the long-term. The less I need to know, the better.</p>
</section>]]></description>
</item>
<item>
<title>Higher level languages always win</title>
<guid>https://write-every-day/3.html</guid>
<description><![CDATA[<h1 class="title"
id="higher-level-languages-always-win">Higher level languages always
win</h1>
<p>Assembly is the lowest level language in common use. It’s translated
into machine code that your computer can understand directly, leaving no
abstraction between you and the machine. With no abstraction, there
should be no overhead, right? And yet, almost no programmers write
assembly routines. Fortran, long touted for its efficient use of
computing power, is also not common anymore. And it’s not because
programmers care less about performance – in the age of the cloud,
billions of embedded devices, phones, and laptops, more areas than ever
need better performance. But performance gains are hard to come by using
such low level languages.</p>
<p>Take the history of Unix: before Unix, most operating systems were
written in an assembly language, which made them fast on a particular
machine, but nigh impossible to port. To fulfill the promise of a truly
portable operating system, the researchers at Bell labs wrote C, a “high
level language” at the time and rewrote Unix in it. This allowed the
Unix operating system to be portable: as long as you had a C compiler
that could target your machine, you could build Unix for your machine.
The duty of learning optimization from C to generated assembly was left
to the compiler writers, and the compiler writers and operating systems
people could work on their own interests, improving both in the process.
In <a href="https://dsf.berkeley.edu/cs262/unix.pdf">The Unix
Time-Sharing System</a>, the authors note that the resulting Unix
rewritten in C was about 1/3rd larger, but the tradeoff of using a
higher level language to write the operating system was worth it for
extensibility, and so, Unix stayed written in C.</p>
<p>Even by the 80s, most operating systems had a plethora of assembly
for performance, mixing in some high level languages. By the 90s, most
operating systems were written in a higher level language, like C. At
some point, the amount of architectures an operating system had to
support made writing assembly an arduous task – you had to write
everything with nothing. You want a stack? Go use <code>%rsp</code>. You
want a heap? Go call <code>brk</code> and <code>sbrk</code>. You want
for loops? You want functions? Use labels and goto. The language itself
was intimately bound to the platform, and there were too many platforms.
And compilers were getting better too – they could implement more
optimizations, allowing high level constructions to get fast, just as if
you were writing low level code.</p>
<p>Even today, previously “high-level constructs” like the C-style for
loop are under attack. Let’s take a look at the following program:</p>
<div id="cb1" class="sourceCode">
<div class="sourceCode" id="cb1"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>    <span class="dt">int</span> x <span class="op">=</span> <span class="dv">1</span><span class="op">;</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>    <span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> i <span class="op">=</span> <span class="dv">0</span><span class="op">;</span> i <span class="op">&lt;=</span> <span class="dv">143</span><span class="op">;</span> i<span class="op">++)</span> <span class="op">{</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>        <span class="cf">if</span> <span class="op">(</span>i <span class="op">&lt;</span> <span class="dv">10</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>            x <span class="op">+=</span> i<span class="op">;</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> x<span class="op">;</span></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</div>
<p>If you take a look at this program, you should notice that it can be
optimized away at compile time. Basically, you just add <code>i</code>
as it’s just 45 (the sum of 0..9) + 1, which is 46.</p>
<p>With x86_64 clang trunk (the version after 17.0.1), with
<code>-O3</code> optimizations on, the compiler generates this monstrous
code:</p>
<p>Code generated by x86-64 clang</p>
<div id="cb2" class="sourceCode">
<div class="sourceCode" id="cb2"><pre
class="sourceCode asm"><code class="sourceCode fasm"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="fu">.LCPI0_1:</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>        .long   <span class="dv">0</span>                               <span class="op">#</span> <span class="bn">0x0</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>        .long   <span class="dv">1</span>                               <span class="op">#</span> <span class="bn">0x1</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>        .long   <span class="dv">2</span>                               <span class="op">#</span> <span class="bn">0x2</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>        .long   <span class="dv">3</span>                               <span class="op">#</span> <span class="bn">0x3</span></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a><span class="fu">.LCPI0_2:</span></span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>        .long   <span class="dv">4</span>                               <span class="op">#</span> <span class="bn">0x4</span></span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a>        .long   <span class="dv">4</span>                               <span class="op">#</span> <span class="bn">0x4</span></span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a>        .long   <span class="dv">4</span>                               <span class="op">#</span> <span class="bn">0x4</span></span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a>        .long   <span class="dv">4</span>                               <span class="op">#</span> <span class="bn">0x4</span></span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a><span class="fu">.LCPI0_3:</span></span>
<span id="cb2-12"><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a>        .long   <span class="dv">2147483648</span>                      <span class="op">#</span> <span class="bn">0x80000000</span></span>
<span id="cb2-13"><a href="#cb2-13" aria-hidden="true" tabindex="-1"></a>        .long   <span class="dv">2147483648</span>                      <span class="op">#</span> <span class="bn">0x80000000</span></span>
<span id="cb2-14"><a href="#cb2-14" aria-hidden="true" tabindex="-1"></a>        .long   <span class="dv">2147483648</span>                      <span class="op">#</span> <span class="bn">0x80000000</span></span>
<span id="cb2-15"><a href="#cb2-15" aria-hidden="true" tabindex="-1"></a>        .long   <span class="dv">2147483648</span>                      <span class="op">#</span> <span class="bn">0x80000000</span></span>
<span id="cb2-16"><a href="#cb2-16" aria-hidden="true" tabindex="-1"></a><span class="fu">.LCPI0_4:</span></span>
<span id="cb2-17"><a href="#cb2-17" aria-hidden="true" tabindex="-1"></a>        .long   <span class="dv">2147483658</span>                      <span class="op">#</span> <span class="bn">0x8000000a</span></span>
<span id="cb2-18"><a href="#cb2-18" aria-hidden="true" tabindex="-1"></a>        .long   <span class="dv">2147483658</span>                      <span class="op">#</span> <span class="bn">0x8000000a</span></span>
<span id="cb2-19"><a href="#cb2-19" aria-hidden="true" tabindex="-1"></a>        .long   <span class="dv">2147483658</span>                      <span class="op">#</span> <span class="bn">0x8000000a</span></span>
<span id="cb2-20"><a href="#cb2-20" aria-hidden="true" tabindex="-1"></a>        .long   <span class="dv">2147483658</span>                      <span class="op">#</span> <span class="bn">0x8000000a</span></span>
<span id="cb2-21"><a href="#cb2-21" aria-hidden="true" tabindex="-1"></a><span class="fu">.LCPI0_5:</span></span>
<span id="cb2-22"><a href="#cb2-22" aria-hidden="true" tabindex="-1"></a>        .long   <span class="dv">8</span>                               <span class="op">#</span> <span class="bn">0x8</span></span>
<span id="cb2-23"><a href="#cb2-23" aria-hidden="true" tabindex="-1"></a>        .long   <span class="dv">8</span>                               <span class="op">#</span> <span class="bn">0x8</span></span>
<span id="cb2-24"><a href="#cb2-24" aria-hidden="true" tabindex="-1"></a>        .long   <span class="dv">8</span>                               <span class="op">#</span> <span class="bn">0x8</span></span>
<span id="cb2-25"><a href="#cb2-25" aria-hidden="true" tabindex="-1"></a>        .long   <span class="dv">8</span>                               <span class="op">#</span> <span class="bn">0x8</span></span>
<span id="cb2-26"><a href="#cb2-26" aria-hidden="true" tabindex="-1"></a><span class="fu">.LCPI0_6:</span></span>
<span id="cb2-27"><a href="#cb2-27" aria-hidden="true" tabindex="-1"></a>        .long   <span class="dv">1</span>                               <span class="op">#</span> <span class="bn">0x1</span></span>
<span id="cb2-28"><a href="#cb2-28" aria-hidden="true" tabindex="-1"></a><span class="fu">main:</span>                                   # @main</span>
<span id="cb2-29"><a href="#cb2-29" aria-hidden="true" tabindex="-1"></a>        <span class="bu">pxor</span>    <span class="op">%</span><span class="kw">xmm0</span><span class="op">,</span> <span class="op">%</span><span class="kw">xmm0</span></span>
<span id="cb2-30"><a href="#cb2-30" aria-hidden="true" tabindex="-1"></a>        <span class="bu">movd</span>    <span class="op">.</span>LCPI0_6<span class="op">(%</span>rip<span class="op">),</span> <span class="op">%</span><span class="kw">xmm1</span>           <span class="op">#</span> <span class="kw">xmm1</span> <span class="op">=</span> <span class="op">[</span><span class="dv">1</span><span class="op">,</span><span class="dv">0</span><span class="op">,</span><span class="dv">0</span><span class="op">,</span><span class="dv">0</span><span class="op">]</span></span>
<span id="cb2-31"><a href="#cb2-31" aria-hidden="true" tabindex="-1"></a>        <span class="bu">movdqa</span>  <span class="op">.</span>LCPI0_1<span class="op">(%</span>rip<span class="op">),</span> <span class="op">%</span><span class="kw">xmm2</span>           <span class="op">#</span> <span class="kw">xmm2</span> <span class="op">=</span> <span class="op">[</span><span class="dv">0</span><span class="op">,</span><span class="dv">1</span><span class="op">,</span><span class="dv">2</span><span class="op">,</span><span class="dv">3</span><span class="op">]</span></span>
<span id="cb2-32"><a href="#cb2-32" aria-hidden="true" tabindex="-1"></a>        movl    <span class="op">$</span><span class="bn">144</span><span class="op">,</span> <span class="op">%</span><span class="kw">eax</span></span>
<span id="cb2-33"><a href="#cb2-33" aria-hidden="true" tabindex="-1"></a>        <span class="bu">movdqa</span>  <span class="op">.</span>LCPI0_2<span class="op">(%</span>rip<span class="op">),</span> <span class="op">%</span><span class="kw">xmm3</span>           <span class="op">#</span> <span class="kw">xmm3</span> <span class="op">=</span> <span class="op">[</span><span class="dv">4</span><span class="op">,</span><span class="dv">4</span><span class="op">,</span><span class="dv">4</span><span class="op">,</span><span class="dv">4</span><span class="op">]</span></span>
<span id="cb2-34"><a href="#cb2-34" aria-hidden="true" tabindex="-1"></a>        <span class="bu">movdqa</span>  <span class="op">.</span>LCPI0_3<span class="op">(%</span>rip<span class="op">),</span> <span class="op">%</span><span class="kw">xmm4</span>           <span class="op">#</span> <span class="kw">xmm4</span> <span class="op">=</span> <span class="op">[</span><span class="dv">2147483648</span><span class="op">,</span><span class="dv">2147483648</span><span class="op">,</span><span class="dv">2147483648</span><span class="op">,</span><span class="dv">2147483648</span><span class="op">]</span></span>
<span id="cb2-35"><a href="#cb2-35" aria-hidden="true" tabindex="-1"></a>        <span class="bu">movdqa</span>  <span class="op">.</span>LCPI0_4<span class="op">(%</span>rip<span class="op">),</span> <span class="op">%</span><span class="kw">xmm5</span>           <span class="op">#</span> <span class="kw">xmm5</span> <span class="op">=</span> <span class="op">[</span><span class="dv">2147483658</span><span class="op">,</span><span class="dv">2147483658</span><span class="op">,</span><span class="dv">2147483658</span><span class="op">,</span><span class="dv">2147483658</span><span class="op">]</span></span>
<span id="cb2-36"><a href="#cb2-36" aria-hidden="true" tabindex="-1"></a>        <span class="bu">movdqa</span>  <span class="op">.</span>LCPI0_5<span class="op">(%</span>rip<span class="op">),</span> <span class="op">%</span><span class="kw">xmm6</span>           <span class="op">#</span> <span class="kw">xmm6</span> <span class="op">=</span> <span class="op">[</span><span class="dv">8</span><span class="op">,</span><span class="dv">8</span><span class="op">,</span><span class="dv">8</span><span class="op">,</span><span class="dv">8</span><span class="op">]</span></span>
<span id="cb2-37"><a href="#cb2-37" aria-hidden="true" tabindex="-1"></a><span class="fu">.LBB0_1:</span>                                # =&gt;This Inner Loop Header<span class="op">:</span> Depth<span class="op">=</span><span class="dv">1</span></span>
<span id="cb2-38"><a href="#cb2-38" aria-hidden="true" tabindex="-1"></a>        <span class="bu">movdqa</span>  <span class="op">%</span><span class="kw">xmm2</span><span class="op">,</span> <span class="op">%</span><span class="kw">xmm7</span></span>
<span id="cb2-39"><a href="#cb2-39" aria-hidden="true" tabindex="-1"></a>        <span class="bu">paddd</span>   <span class="op">%</span><span class="kw">xmm3</span><span class="op">,</span> <span class="op">%</span><span class="kw">xmm7</span></span>
<span id="cb2-40"><a href="#cb2-40" aria-hidden="true" tabindex="-1"></a>        <span class="bu">movdqa</span>  <span class="op">%</span><span class="kw">xmm2</span><span class="op">,</span> <span class="op">%</span>xmm8</span>
<span id="cb2-41"><a href="#cb2-41" aria-hidden="true" tabindex="-1"></a>        <span class="bu">pxor</span>    <span class="op">%</span><span class="kw">xmm4</span><span class="op">,</span> <span class="op">%</span>xmm8</span>
<span id="cb2-42"><a href="#cb2-42" aria-hidden="true" tabindex="-1"></a>        <span class="bu">movdqa</span>  <span class="op">%</span><span class="kw">xmm5</span><span class="op">,</span> <span class="op">%</span>xmm9</span>
<span id="cb2-43"><a href="#cb2-43" aria-hidden="true" tabindex="-1"></a>        <span class="bu">pcmpgtd</span> <span class="op">%</span>xmm8<span class="op">,</span> <span class="op">%</span>xmm9</span>
<span id="cb2-44"><a href="#cb2-44" aria-hidden="true" tabindex="-1"></a>        <span class="bu">movdqa</span>  <span class="op">%</span><span class="kw">xmm7</span><span class="op">,</span> <span class="op">%</span>xmm8</span>
<span id="cb2-45"><a href="#cb2-45" aria-hidden="true" tabindex="-1"></a>        <span class="bu">pxor</span>    <span class="op">%</span><span class="kw">xmm4</span><span class="op">,</span> <span class="op">%</span>xmm8</span>
<span id="cb2-46"><a href="#cb2-46" aria-hidden="true" tabindex="-1"></a>        <span class="bu">movdqa</span>  <span class="op">%</span><span class="kw">xmm5</span><span class="op">,</span> <span class="op">%</span>xmm10</span>
<span id="cb2-47"><a href="#cb2-47" aria-hidden="true" tabindex="-1"></a>        <span class="bu">pcmpgtd</span> <span class="op">%</span>xmm8<span class="op">,</span> <span class="op">%</span>xmm10</span>
<span id="cb2-48"><a href="#cb2-48" aria-hidden="true" tabindex="-1"></a>        <span class="bu">pand</span>    <span class="op">%</span><span class="kw">xmm2</span><span class="op">,</span> <span class="op">%</span>xmm9</span>
<span id="cb2-49"><a href="#cb2-49" aria-hidden="true" tabindex="-1"></a>        <span class="bu">paddd</span>   <span class="op">%</span>xmm9<span class="op">,</span> <span class="op">%</span><span class="kw">xmm1</span></span>
<span id="cb2-50"><a href="#cb2-50" aria-hidden="true" tabindex="-1"></a>        <span class="bu">pand</span>    <span class="op">%</span><span class="kw">xmm7</span><span class="op">,</span> <span class="op">%</span>xmm10</span>
<span id="cb2-51"><a href="#cb2-51" aria-hidden="true" tabindex="-1"></a>        <span class="bu">paddd</span>   <span class="op">%</span>xmm10<span class="op">,</span> <span class="op">%</span><span class="kw">xmm0</span></span>
<span id="cb2-52"><a href="#cb2-52" aria-hidden="true" tabindex="-1"></a>        <span class="bu">paddd</span>   <span class="op">%</span><span class="kw">xmm6</span><span class="op">,</span> <span class="op">%</span><span class="kw">xmm2</span></span>
<span id="cb2-53"><a href="#cb2-53" aria-hidden="true" tabindex="-1"></a>        addl    <span class="op">$-</span><span class="dv">8</span><span class="op">,</span> <span class="op">%</span><span class="kw">eax</span></span>
<span id="cb2-54"><a href="#cb2-54" aria-hidden="true" tabindex="-1"></a>        <span class="cf">jne</span>     <span class="op">.</span>LBB0_1</span>
<span id="cb2-55"><a href="#cb2-55" aria-hidden="true" tabindex="-1"></a>        <span class="bu">paddd</span>   <span class="op">%</span><span class="kw">xmm1</span><span class="op">,</span> <span class="op">%</span><span class="kw">xmm0</span></span>
<span id="cb2-56"><a href="#cb2-56" aria-hidden="true" tabindex="-1"></a>        <span class="bu">pshufd</span>  <span class="op">$</span><span class="bn">238</span><span class="op">,</span> <span class="op">%</span><span class="kw">xmm0</span><span class="op">,</span> <span class="op">%</span><span class="kw">xmm1</span>              <span class="op">#</span> <span class="kw">xmm1</span> <span class="op">=</span> <span class="kw">xmm0</span><span class="op">[</span><span class="dv">2</span><span class="op">,</span><span class="dv">3</span><span class="op">,</span><span class="dv">2</span><span class="op">,</span><span class="dv">3</span><span class="op">]</span></span>
<span id="cb2-57"><a href="#cb2-57" aria-hidden="true" tabindex="-1"></a>        <span class="bu">paddd</span>   <span class="op">%</span><span class="kw">xmm0</span><span class="op">,</span> <span class="op">%</span><span class="kw">xmm1</span></span>
<span id="cb2-58"><a href="#cb2-58" aria-hidden="true" tabindex="-1"></a>        <span class="bu">pshufd</span>  <span class="op">$</span><span class="bn">85</span><span class="op">,</span> <span class="op">%</span><span class="kw">xmm1</span><span class="op">,</span> <span class="op">%</span><span class="kw">xmm0</span>               <span class="op">#</span> <span class="kw">xmm0</span> <span class="op">=</span> <span class="kw">xmm1</span><span class="op">[</span><span class="dv">1</span><span class="op">,</span><span class="dv">1</span><span class="op">,</span><span class="dv">1</span><span class="op">,</span><span class="dv">1</span><span class="op">]</span></span>
<span id="cb2-59"><a href="#cb2-59" aria-hidden="true" tabindex="-1"></a>        <span class="bu">paddd</span>   <span class="op">%</span><span class="kw">xmm1</span><span class="op">,</span> <span class="op">%</span><span class="kw">xmm0</span></span>
<span id="cb2-60"><a href="#cb2-60" aria-hidden="true" tabindex="-1"></a>        <span class="bu">movd</span>    <span class="op">%</span><span class="kw">xmm0</span><span class="op">,</span> <span class="op">%</span><span class="kw">eax</span></span>
<span id="cb2-61"><a href="#cb2-61" aria-hidden="true" tabindex="-1"></a>        retq</span></code></pre></div>
</div>
<p>In gcc trunk (which will land in gcc-13.3, or gcc-14), it correctly
optimizes away the program:</p>
<div id="cb3" class="sourceCode">
<div class="sourceCode" id="cb3"><pre
class="sourceCode asm"><code class="sourceCode fasm"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="fu">main:</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>        movl    <span class="op">$</span><span class="bn">46</span><span class="op">,</span> <span class="op">%</span><span class="kw">eax</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>        <span class="cf">ret</span></span></code></pre></div>
</div>
<p>If you just turn the <code>&lt;=</code> into an <code>&lt;</code> for
clang, it optimizes away the program: the compiler can now see that the
if block is redundant, and the for loop can be evaluated statically, and
optimizations kick in.</p>
<p>In rust (or other higher-level languages), you can write this code
with iterators:</p>
<div id="cb4" class="sourceCode">
<div class="sourceCode" id="cb4"><pre
class="sourceCode rust"><code class="sourceCode rust"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="kw">use</span> <span class="pp">std::process::</span>exit<span class="op">;</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a><span class="kw">pub</span> <span class="kw">fn</span> main() <span class="op">{</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span> <span class="kw">mut</span> x <span class="op">=</span> <span class="dv">1</span><span class="op">;</span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>    x <span class="op">+=</span> (<span class="dv">0</span><span class="op">..=</span><span class="dv">143</span>)<span class="op">.</span>take_while(<span class="op">|</span>i<span class="op">|</span> <span class="op">*</span>i <span class="op">&lt;</span> <span class="dv">10</span>)<span class="op">.</span><span class="pp">sum::</span><span class="op">&lt;</span><span class="dt">u8</span><span class="op">&gt;</span>()<span class="op">;</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>    exit(x<span class="op">.</span>into())</span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</div>
<p>And with rustc 1.75.0, with the flags <code>-C opt-level=2</code>, it
optimizes it all away.</p>
<div id="cb5" class="sourceCode">
<div class="sourceCode" id="cb5"><pre
class="sourceCode asm"><code class="sourceCode fasm"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="fu">example:</span>:main<span class="op">:</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>        <span class="bu">push</span>    <span class="kw">rax</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>        <span class="bu">mov</span>     <span class="kw">edi</span><span class="op">,</span> <span class="dv">46</span></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a>        <span class="cf">call</span>    <span class="dt">qword</span> <span class="dt">ptr</span> <span class="op">[</span>rip <span class="op">+</span> std<span class="op">::</span>process<span class="op">::</span>exit<span class="fu">@</span><span class="er">G</span>OTPCREL<span class="op">]</span></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a>        <span class="bu">ud2</span></span></code></pre></div>
</div>
<p>There’s a little extra ceremony since rust doesn’t allow returning
from main, but if it did, it would basically be the gcc version.</p>
<p>The higher-level code is both clearer in intent and is easier to
optimize.</p>
<p>But that’s not all: since iterators don’t have to specify iteration
order (as long as the same result is returned), you can parallelize or
iterate out of order if that speeds up code.</p>
<p>In C, you’d have to use an extended language like Cilk to do the same
thing, whereas higher-level languages can implement these features in
libraries, as C++ and Rust do. So you get readability, extendibility,
and performance.</p>
<p>At the beginning, I mentioned that fortran and C are hard to
optimize. But it’s not old languages that are hard to optimize: Lisp,
for example, is not one of them. Since lisp specializes in higher-level
constructs, like <code>map</code>, <code>reduce</code>,
<code>filter</code>, and others, the language doesn’t put many
restrictions on the executed low-level code. Thus, as compilers get
better, lisps get better.</p>
<p>Dropping down to lower-level languages or using lower-level language
features is always a trade-off in short-term performance for long-term
maintainability and performance woes. One day, a compiler will run
circles around you and you’ll be left in the dust.</p>
<p>That’s what ended up happening to GeOS. A fast OS written in
assembly, which couldn’t be ported to enough devices to get enough
market share to stick. Meanwhile, Linux, the BSDs, Windows, and Mac
did.</p>
<p>Higher-level languages always win. The assembly programmers learned
that when fortran took their programmers. The fortran programmers
learned when C took bites of scientific computing. The C programmers
learned about OOP when C++ came, and the C++ folks learned about the
importance of memory safety when Rust came out. What’s next, I can’t say
– all I can say is that the next higher level language will come, and
I’ll be glad it did.</p>]]></description>
</item>
<item>
<title>Ideas I miss: Microkernels</title>
<guid>https://write-every-day/2.html</guid>
<description><![CDATA[<h1 class="title"
id="ideas-i-miss-microkernels">Ideas I miss: Microkernels</h1>
<hr />
<h1 class="toc-title" id="contents">Contents</h1>
<ul>
<li><a href="#the-resurgence-of-microkernels"
id="toc-the-resurgence-of-microkernels">The resurgence of
Microkernels</a></li>
</ul>
<hr />
<p>You’re probably reading this post on a Monolithic OS of some kind: A
computer running windows, mac, linux, or a BSD. There are some
microkernel features in them, but since most of them run a single
process in kernel space, I’m going to call them monolithic OSes and you
can’t stop me.</p>
<p>Microkernels, like Minix (the inspiration for Linux) and Mach (the
inspiration for Mac OS X), relegate as little as possible to kernel
space, and instead work by passing messages from user space to various
services that can exist in kernel or user space. This allows for a very
minimal implementation of a kernel – Minix’s first release was only
12,000 lines of C code. In fact, the entirety of the OS can be
implemented with just two system calls, <code>send</code> and
<code>receive</code>. Linux currently has hundreds of system calls, some
of which are deprecated but can’t be removed, multiple ways to duplicate
a file descriptor, and multiple ways to fork a new process. Minix can
implement the entire POSIX system call interface with just these two
calls.</p>
<p>Microkernels are also more secure, since an exploit to one part of
the kernel, like the drivers doesn’t affect any other service. In a
monolithic kernel, a faulty driver can bring down the entire system,
since the kernel runs on one process, or worse, exfiltrate data, as
drivers have elevated permissions when running in a monolithic kernel.
Kernel extensions are also problematic, since they can run as root and
users may download arbitrary extensions from the internet without
vetting them. In Minix, the file system, memory management, drivers, can
all be run as separate processes, even in user space. Thus, the worst an
exploit to any of these services can do is crash or compromise that
particular service. If you compromise a service in user space, you
basically do nothing, since all code runs in user space.</p>
<p>Microkernels also allow for independent evolution of parts of the OS
in a way a monolithic kernel cannot. In a microkernel, writing your own
file system, network stack, or device driver is a cinch, since it’s
working on a service that reacts to messages. You parse the message, do
a relevant action, return a relevant response, and continue on. If you
want to make a part of the service more efficient, you can test it
easily, benchmark it, and keep iterating. In a monolithic kernel, some
parts are hopelessly intertwined with the rest of the system. To write
and test out a file system, you have to mock out the rest of the kernel
or compile your file system with the rest of the Linux kernel. To test
out the scheduler or networking capabilities, you have to do the
same.</p>
<section id="the-resurgence-of-microkernels" class="level2">
<h2>The resurgence of Microkernels</h2>
<p>Linux developers got tired of always having to go into the kernel to
make a change. If I want to improve a scheduler, I shouldn’t have to
know about anything other than tasks. Fundamentally, a scheduler should
see a list of tasks that want to run, some information about each task,
pick one, and run it for some time before restarting. That’s it. I
should be able to judge whether or not my change was good without
thinking about the rest of the system. If I want to debug some code that
runs in the kernel, I should have a way to do so that doesn’t involve
peeking into the kernel. What was the solution? Creating user space
equivalents of critical kernel space facilities, like the following:</p>
<ul>
<li><p><a href="https://en.wikipedia.org/wiki/EBPF">eBPF</a> (extended
Berkeley Packet Filter) was created to allow users to run sandboxed
programs in the kernel without having to load a module or recompile the
kernel. It became especially popular in the networking space, since
observability and performance of networks are in short supply in
linux.</p></li>
<li><p><a
href="https://en.wikipedia.org/wiki/Filesystem_in_Userspace">FUSE</a>
(File system in userspace) was created as an interface to allow
non-privileged users to write and run a file system in userspace that
calls into kernel space.</p></li>
<li><p><a href="https://lwn.net/Articles/922405/">Sched_ext</a> is a
kernel subsystem that allows writing schedulers in userspace.</p></li>
</ul>
<p>Lots of users may want to customize parts of their OS, tweaking
subsystems to optimize their use cases. Computing has become more
heterogeneous, and users have more diverse needs than ever, since they
use a plethora of devices like embedded devices, phones, tablets,
laptops, desktops, cloud daily. It’s impossible for a single monolith to
make all the right choices for every user. Instead, imagine a
distribution of Linux that really cared about power consumption, so it
decided to pick power efficient subsystems, or a hyperscaler
distribution that optimized for virtualization. It’s hard to do with
current linux, but with the changes coming in the future to break up the
monolithic kernels into distinct services, maybe the microkernel future
will be coming soon.</p>
</section>]]></description>
</item>
<item>
<title>How to design an App (and not hate yourself)</title>
<guid>https://write-every-day/1.html</guid>
<description><![CDATA[<h1 class="title"
id="how-to-design-an-app-and-not-hate-yourself">How to design an App
(and not hate yourself)</h1>
<hr />
<h1 class="toc-title" id="contents">Contents</h1>
<ul>
<li><a href="#document-your-thoughts"
id="toc-document-your-thoughts">Document your thoughts</a></li>
<li><a href="#managing-state" id="toc-managing-state">Managing
State</a></li>
<li><a href="#having-fun" id="toc-having-fun">Having fun</a></li>
</ul>
<hr />
<p>Many times I’ve started a project, raring to go, and after a few days
realized I wished I thought out the design of the damn thing better.
I’ll always start out with a small proof of concept that works, then
I’ll add a feature here and a feature there and the app will become
spaghetti code, even in less than 1000 lines of code. Or maybe I’ll come
back to a project after a few years and realize I can’t understand what
I was trying to do, or the features I was trying to add, or the bugs I
needed to fix.</p>
<p>I decided to take a stand and come up with some structure that would
help me tackle these problems.</p>
<section id="document-your-thoughts" class="level2">
<h2>Document your thoughts</h2>
<p>I don’t frequently comment my code, mainly from my years working in
corporate. I brought that habit over to my personal projects, because I
believe the code itself should be written in a way that intent is clear.
What’s not clear, however, is why you chose to do something one way over
any other way, and the trade-offs that entailed. For that, I’ll write an
<code>architecture</code> file that explains some of the decisions,
goals, and explicit non-goals. This document is invaluable when coming
back to a project.</p>
<p>As well, tests are great for jogging the mind. If I write a library,
I find myself wanting to run it to see what it did and where I left off.
Tests let me do that – I can read the tests and see what features/bugs
the library has. I’ll write some failing tests and a comment that
explains the feature or bug briefly, and leave it failing. When I come
back to it, I’ll try to fix it up.</p>
<p>On top of traditional testing, I’ve recently fallen in love with
fuzzing my code. Fuzzing involves generating random structured data and
then calling a function in your program, and trying to crash (or
otherwise trigger a bad state). I recently wrote a <a
href="https://riak.com/assets/bitcask-intro.pdf">bitcask</a> database in
Rust, and when I thought it was satisfactory, I wrote up a few unit
tests and I started fuzzing my app. In less than a second it found 3
bugs, checking code paths that would be difficult to do by hand. These
test cases are then easily transferable to your normal unit testing
suite, which can act like a regression suite.</p>
</section>
<section id="managing-state" class="level2">
<h2>Managing State</h2>
<p>The second part I find difficult about writing a project is managing
state – If I start out with a small core and adding features to it in an
unstructured way, I tend to end up with a jumbled mess with state
everywhere. The frontend world took a nod from the functional world and
decided to keep state in stores, where state and state management
routines are housed, and the rest of the application has to call into
the stores to get or set specific values. These values are also purely
functional, which allows for time-travel debugging, where you can go
back in time to a point where the app was at a certain state. Gary
Bernhardt took this further and espoused a philosophy called “functional
core, imperative shell”. Any part of the application that can be pure,
or only rely on its arguments is easy to test and hard to get wrong. As
much of as possible of the program should be written in this style. Any
part of the program that is required to deal with state, or has side
effects (network requests, Disk I/O) should be shunted around the
functional core, and use integration tests. This is kind of like MVC,
where the controllers and the model are the imperative shell, making
network requests or doing file I/O, and the view shuffles data between
both of them.</p>
<p>This breaks your application up into modules based on how much they
interact with state. This is a big win for understanding your code after
a break – the duties of each module is clearer, and testing duties are
also clearer, since you don’t have to stub any part of the system out,
just integration test + fuzz the boundaries of the code and fuzz + unit
test the functional core.</p>
</section>
<section id="having-fun" class="level2">
<h2>Having fun</h2>
<p>Normally I dislike structure, instead doing things that I enjoy
without strictly adhering to rules. What I found interesting was that
having just the right amount of structure increased the amount of
enjoyment I got from coding and other projects. I didn’t have to spend
as much time reimmersing myself in the project, which I found boring and
a blocker to coming back to hard projects. It also made me a better
programmer, since testing was easier and I could spot out troublesome
patterns of code and became more efficient at testing. Also, I started
tackling harder projects because I could build things up incrementally
faster and not hit the cognitive wall where making a change was higher
than the amount of enjoyment I would get from said change.</p>
<p>The right amount of structure is like the right amount of spice. It
makes everything taste better.</p>
</section>]]></description>
</item>
<item>
<title>index</title>
<guid>https://write-every-day/index.html</guid>
<description><![CDATA[<hr />
<h1 class="toc-title" id="contents">Contents</h1>
<ul>
<li><a href="#write-every-day" id="toc-write-every-day">Write every
day</a>
<ul>
<li><a href="#posts" id="toc-posts">Posts</a></li>
<li><a href="#misc" id="toc-misc">Misc</a></li>
</ul></li>
</ul>
<hr />
<section id="write-every-day" class="level1">
<h1>Write every day</h1>
<section id="posts" class="level2">
<h2>Posts</h2>
<ul>
<li>2024-02-05: <a href="./1.html">How to write an app and not hate
yourself</a></li>
<li>2024-02-05: <a href="./2.html">Ideas I miss: Microkernels</a></li>
<li>2024-02-05: <a href="./3.html">Higher level languages always
win</a></li>
<li>2024-02-06: <a href="./4.html">Great Design</a></li>
<li>2024-02-07: <a href="./5.html">Karma Police: the resurgence of
attention</a></li>
<li>2024-02-08: <a href="./6.html">Offline learning: Tools of the
trade</a></li>
<li>2024-02-09: <a href="./7.html">Why you should read position
papers</a></li>
<li>2024-02-10: <a href="./8.html">To master your tools, make
them</a></li>
<li>2024-02-15: <a href="./9.html">Improve vs Explore</a></li>
<li>2024-02-23: <a href="./10.html">Computability and
consciousness</a></li>
<li>2024-02-29: <a href="./11.html">Boring Technology</a></li>
<li>2024-03-02: <a href="./12.html">Beautiful Programs</a></li>
<li>2024-03-06: <a href="./13.html">Math is fundamental</a></li>
<li>2024-03-25: <a href="./14.html">Ways to Test</a></li>
<li>2024-04-21: <a href="./15.html">Pointer Complications</a></li>
<li>2024-05-02: <a href="./16.html">Quantity vs Quality</a></li>
<li>2024-05-23: <a href="./17.html">The Interpreter Pattern</a></li>
<li>2024-05-23: <a href="./18.html">Learning: A ChatGPT Based
Approach</a></li>
<li>2024-06-20: <a href="./19.html">Are Coding Bootcamps Dead?</a></li>
</ul>
</section>
<section id="misc" class="level2">
<h2>Misc</h2>
<ul>
<li><a href="./rss.xml">RSS Feed</a></li>
<li><a href="./sitemap.xml">Sitemap</a></li>
</ul>
</section>
</section>]]></description>
</item>
</channel></rss>
