<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Matthias Portzel]]></title><description><![CDATA[Matthias Portzel is a programmer, web developer, and writer. ]]></description><link>https://matthiasportzel.com/</link><image><url>https://matthiasportzel.com/favicon.png</url><title>Matthias Portzel</title><link>https://matthiasportzel.com/</link></image><generator>Ghost 5.53</generator><lastBuildDate>Sun, 05 Apr 2026 17:13:00 GMT</lastBuildDate><atom:link href="https://matthiasportzel.com/backroom/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Useless use of @as]]></title><description><![CDATA[Zig beginners frequently overuse the almost-useless @as. But if it's useless, why is it in the language?]]></description><link>https://matthiasportzel.com/useless-use-of-as/</link><guid isPermaLink="false">66baaee51cc01d04c25999bc</guid><category><![CDATA[idea]]></category><dc:creator><![CDATA[Matthias Portzel]]></dc:creator><pubDate>Tue, 13 Aug 2024 02:30:49 GMT</pubDate><content:encoded><![CDATA[<p><code>@as</code> in Zig doesn&apos;t cast. If you get an error about incompatible types, <code>@as</code> will do absolutely nothing to help you.</p><pre><code class="language-zig">const my_float: f64 = 5.5;
const my_int: u64 = my_float;
_ = my_int;
// error: fractional component prevents float value &apos;5.5&apos; from coercion to type &apos;u64&apos;</code></pre><p>Let&apos;s add <code>@as</code> and see if it helps!</p><pre><code>const my_float: f64 = 5.5;
const my_int: u64 = @as(u64, my_float);
_ = my_int;
// error: fractional component prevents float value &apos;5.5&apos; from coercion to type &apos;u64&apos;</code></pre><p>Wow, it did nothing!</p><p>If we want this to work, we have to use the <code>intFromFloat</code> built-in.</p><pre><code>const my_float: f64 = 5.5;
const my_int: u64 = @as(u64, @intFromFloat(my_float));
_ = my_int;
// It compiles!</code></pre><p>Whoa! It compiles. But there&apos;s another problem.</p><p>This program has introduced a useless-use of <code>@as</code>. See, we added <code>@intFromFloat</code> but didn&apos;t remove the <code>@as</code>. This is a common mistake people make when first debugging Zig code. They need to do a simple cast, they try using <code>@as</code>, and then when it doesn&apos;t do anything, they leave it in. We can get rid of the <code>@as</code> and our program still compiles.</p><pre><code>const my_float: f64 = 5.5;
const my_int: u64 = @intFromFloat(my_float);
_ = my_int;
// No error.</code></pre><p>And this isn&apos;t specific to <code>f64</code> and <code>u64</code>. This is true for any two types. If you get an error about incompatible types without <code>@as</code>, you&apos;re going to get an error with <code>@as</code>. (Some exceptions may apply.)</p><h2 id="is-as-useless">Is @as useless?</h2><p>If <code>@as</code> doesn&apos;t cast, is it useless? No. To explain what <code>@as</code> does though, you need some understanding of RLS. (This is a very rough sketch of the RLS concept and in particular, result-types.)</p><p>RLS stands for Result Location Semantics. This means that (in Zig) an expression can have a Result Type.</p><p>Think of the Result Type as a property of the hole that you&apos;re going to fill with some value. In the following code, three examples of &quot;holes&quot; are denoted with <code>...</code>.</p><pre><code>const a: usize = ...;
const b: usize = 5 + a + ... + 3;

const Side = enum { left, right };
extern myFunction(foo: Side) void;
myFunction(...);</code></pre><p>Can you determine what the result types of these &quot;holes&quot; are?</p><p>Zig is smart, and so it can deduce the type of two of these result locations, but not the type of the third. Let&apos;s take them one at a time.</p><h3 id="example-1">Example 1</h3><pre><code>const a: usize = ...;</code></pre><p>The Result Type here is obviously <code>usize</code>, because that type is annotated as part of the variable declaration. The compiler knows that regardless of the type of the value or expression used here. If the expression has a different type than `usize`, then Type Coercion is performed.</p><p><a href="https://ziglang.org/documentation/master/?ref=matthiasportzel.com#Type-Coercion">https://ziglang.org/documentation/master/#Type-Coercion</a> Type Coercion in the Zig Language Reference</p><h3 id="example-2">Example 2</h3><pre><code>const b: usize = 5 + a + ... + 3;</code></pre><p>In this example, the type of the &quot;hole&quot; is unknown.</p><p>Result Type information is optional. Most of the time, this hole will be filled with an expression that has a known type (either another <code>comptime_int</code> or another usize variable).</p><pre><code>const b: usize = 5 + a + 2 + 3;</code></pre><p><code>b</code> and <code>a</code> are <code>usize</code>. <code>5</code>, <code>2</code>, <code>3</code> are <code>comptime_int</code>, and Zig can do peer-type resolution on these types, so there&apos;s no issue.</p><h3 id="example-3">Example 3</h3><p>Before getting into an example where the type of the expression is also unknown, let&apos;s look at our third example. This is the other example where Zig can determine the type of the result.</p><pre><code>const Side = enum { left, right };
extern myFunction(foo: Side) void;
myFunction(...);</code></pre><p><code>myFunction</code> is going to be called with an instance of the <code>Side</code> <code>enum</code>, since that&apos;s the type declared in its function signature.</p><p>RLS is what allows you to write code like <code>myFunction(.left)</code> and have Zig know that <code>.left</code> is referring to the type of <code>Side</code>, and not some other enum with a <code>.left</code> feild.</p><h3 id="what-if-there-is-no-result-type">What if there is no Result Type</h3><p>Let&apos;s say we wanted to write code like this:</p><pre><code>const b: usize = 5 + a + @intFromFloat(5.5) + 3;</code></pre><p>What&apos;s the type of the expression <code>@intFromFloat(5.5)</code>? &#xA0;<code>@intFromFloat</code> returns <code>anytype</code>. Let&apos;s look at the documentation:</p><blockquote>Converts the integer part of a floating point number to the inferred result type.</blockquote><p>Okay. This is the same result type we were talking about before. Zig uses this result type to determine the result integer type of <code>@intFromFloat</code>.</p><p>But wait. This is the second example again, where there was no result type. What does the compiler do?</p><pre><code>const b: usize = 5 + a + @intFromFloat(5.5) + 3;
// error: @intFromFloat must have a known result type
// note: use @as to provide explicit result type</code></pre><p>Aha! The compiler errors, and the hint? &quot;<code>use @as</code>&quot;</p><h3 id="the-real-use-of-as">The real use of @as</h3><p>This is why <code>@as</code> exists in the language. <code>@as</code> allows you to create a &quot;hole&quot; with a defined result type (without needing an intermediate variable or function call).</p><p>Our code above can be fixed by adding <code>@as</code> and specifying the Result Type.</p><pre><code>const b: usize = 5 + a + @as(usize, @intFromFloat(5.5)) + 3;
// Compiles!</code></pre><p>There are definite uses for this, like when doing math with floats and ints in a single expression. But <code>@as</code> is never the thing doing the casting. All it&apos;s doing is telling Zig what the Result Type of a cast should be.</p><h2 id="how-to-actually-cast">How to actually cast</h2><p>Zig doesn&apos;t have a single syntax for casting.</p><p>Instead it has a number of built-ins which cast between different types with different semantics. When casting from a float to an int:</p><ul><li>do you want to <code>@intFromFloat</code>?</li><li>do you want to <code>@bitCast</code>?</li></ul><p>Ultimately, these builtins give fine-grained control over casting which is less error prone and more useful than a single casting builtin. But man, wouldn&apos;t it be nice if <code>@as</code> actually did everything for you!</p><blockquote>The title of this post is modeled off of &quot;useless use of cat.&quot;</blockquote>]]></content:encoded></item><item><title><![CDATA[The Linoleum Club]]></title><description><![CDATA[A Discord server for people to talk about programming and technology, but with a twist.]]></description><link>https://matthiasportzel.com/linoleum-club/</link><guid isPermaLink="false">6603876e9c53e4048dfd705f</guid><category><![CDATA[project]]></category><dc:creator><![CDATA[Matthias Portzel]]></dc:creator><pubDate>Wed, 27 Mar 2024 02:53:09 GMT</pubDate><content:encoded><![CDATA[<p>The Linoleum Club is a Discord server for people to talk about computers, programming, technology, and similar topics. If you&apos;re interested in joining a community around that type of conversation, there&apos;s a link to join the server at the bottom of the post.</p><figure class="kg-card kg-image-card"><img src="https://matthiasportzel.com/content/images/2024/03/image.png" class="kg-image" alt="&quot;Welcome to The Linoleum Club&quot; in Discord&apos;s font" loading="lazy" width="1636" height="174" srcset="https://matthiasportzel.com/content/images/size/w600/2024/03/image.png 600w, https://matthiasportzel.com/content/images/size/w1000/2024/03/image.png 1000w, https://matthiasportzel.com/content/images/size/w1600/2024/03/image.png 1600w, https://matthiasportzel.com/content/images/2024/03/image.png 1636w" sizes="(min-width: 720px) 720px"></figure><p>However, in order to join the club and participate in the conversation every week, you have to solve a new programming-related puzzle. Once you have, a custom Discord bot will grant you a role giving you permission to speak in channels.</p><p>At the end of the week (0:00 Sunday, UTC), everyone&apos;s role will be cleared, and all users will be locked out. A new puzzle will be posted, and everyone will have a chance to solve it.</p><p>This is meant to be a fun filter that ensures that the people participating in the conversation have some shared investment. It intentionally discourages drive-by commenters.</p><p>So far, I&apos;ve been writing most of the puzzles (which means none of them are too difficult). But I have a mechanism for server members to submit puzzles as well.</p><p>Join the server and see if you can solve this week&apos;s puzzle:</p><p><a href="https://discord.gg/5vWNUZBX?ref=matthiasportzel.com">https://discord.gg/5vWNUZBX</a></p>]]></content:encoded></item><item><title><![CDATA[Editing remote files over SSH by pretending to use rmate]]></title><description><![CDATA[TextMate might have invented the best way of editing remote files 11 years ago.]]></description><link>https://matthiasportzel.com/rmate/</link><guid isPermaLink="false">654f936f83de18f4b8b0905e</guid><category><![CDATA[idea]]></category><dc:creator><![CDATA[Matthias Portzel]]></dc:creator><pubDate>Wed, 27 Mar 2024 02:35:51 GMT</pubDate><content:encoded><![CDATA[<p>Today, many developers edit files on a remote computer by using VSCode&apos;s remote editing functionality, or by opening an in-terminal editor like Nano or Vim. However, these are not your only options. There&apos;s another elegant and easy-to-use alternative, which was invented by TextMate over 10 years ago. </p><h2 id="easy-usage">Easy Usage</h2><p>I have my remote VPS configured such that I can edit files on it simply by SSHing to it and issuing <code>sl &lt;filepath&gt;</code>. This command returns instantly, placing me back at the shell, but not before opening the specified file in Sublime Text on my local computer. I can edit the file in Sublime, and when I press Save, the file changes are magically written back to the file on my server.</p><p>If the file requires root access to edit, I can still do something similar. I can run <code>sudoedit &lt;filepath&gt;</code>, which will again open and edit the file in Sublime on my computer, but it will wait for me to close the file locally before the command exits and results are written to the remote server.</p><p>These options are super easy to use for editing files if I&apos;m already at a console on the remote machine. I can initiate the editing session on the remote computer, but then I can do my editing on my computer. This means that I have the editing experience that I&apos;m used to, with zero latency and my Sublime configuration.</p><h2 id="how">How</h2><p>This is made possible because of a tool developed for TextMate called <code>rmate</code>. This was a companion to the <code>mate</code> command, which was the CLI tool for opening files in TextMate (on the same computer). You could instead run <code>rmate</code> on a remote computer and it would work as described above, opening the file in your local instance of TextMate for local editing.</p><p><a href="https://macromates.com/blog/2011/mate-and-rmate/?ref=matthiasportzel.com">https://macromates.com/blog/2011/mate-and-rmate/</a> mate and rmate, from the TextMate blog</p><p>Today, I don&apos;t use rmate on the server and I don&apos;t use TextMate on my laptop, but I can still take advantage of this workflow.</p><blockquote>Note on terminology:<br>I&apos;m going to use &quot;server&quot; and &quot;server-side&quot; to refer to my VPS, the machine I&apos;m connecting to over SSH. This is technically the &quot;rmate client,&quot; since it initiates the rmate connection. But I&apos;ll avoid this confusing terminology.</blockquote><p>On the server, I use Harald Lapp&apos;s re-implementation of the <code>rmate</code> script in pure bash. (The original version was written in Ruby, which I don&apos;t have globally installed on my VPS.) This project&apos;s README is also an excellent reference&#x2014;it has links and instructions which I drew from when writing this post.</p><p><a href="https://github.com/aurora/rmate?ref=matthiasportzel.com">https://github.com/aurora/rmate</a> </p><p>On my computer, I use the Sublime Text plugin RemoteSubl, which implements the local side of the rmate connection. If you don&apos;t use Sublime Text, there are plugins for other editors like VSCode and Pulsar (the editor formerly known as Atom).</p><p><a href="https://github.com/randy3k/RemoteSubl?ref=matthiasportzel.com">https://github.com/randy3k/RemoteSubl</a></p><p>I find it amusing that I&#x2019;m not using the original rmate technology on the client or the server; yet, both of them think that the other one is. In this way, even though TextMate is not as relevant as it once was, its name and innovations live on.</p><h2 id="configuration">Configuration</h2><p>If you&apos;re a CLI pro, this configuration will be trivial. However, if you&apos;re a CLI pro, you probably have a method for editing remote files that you&apos;re happy with. So I&apos;m going to walk through this slowly so that you can follow along, provided you&apos;re already familiar with SSH.</p><p>This configuration is in-depth so that, at the end of it, you&apos;ll have the best remote editing experience possible. There are simpler instructions in the repositories for the tools linked above, but I&apos;ve found a little bit more configuration is required to remove the pain points and make it so that you don&apos;t have to fall back to <code>vi</code>.</p><h3 id="remote-configuration">Remote configuration</h3><p>The first step is installing the rmate bash script on your remote server. Since this is a simple script, we just need to download it, mark it as executable, and make sure it is on the path. I personally place it in ~/bin and then add that directory to my path, to avoid globally installing with sudo.</p><pre><code>mkdir -p ~/bin
curl -Lo ~/bin/rmate https://raw.githubusercontent.com/aurora/rmate/master/rmate
chmod +x ~/bin/rmate</code></pre><p>Then we need a few simple changes to the remote .bashrc (or equivalent if you&apos;re using a different shell):</p><pre><code># Set PATH to include ~/bin
export PATH=&quot;$HOME/bin:$PATH&quot;

# Set $EDITOR so other tools know what editor to use
# This should be an absolute path, not `rmate` or `~/bin/rmate`
export EDITOR=&quot;$HOME/bin/rmate -w&quot;

# Create an alias for our use
alias sl=&quot;rmate&quot;</code></pre><p>The first change adds <code>~/bin</code> to the <code>PATH</code>, as we discussed.</p><p>The second change sets <code>$EDITOR</code>. This is used by tools like <code>git commit</code> and <code>sudoedit</code>. <code>sudoedit</code> in particular is tricky to configure since it looks up the editor without your modified <code>PATH</code> or aliases, so it should be an absolute path to the editor executable. The <code>-w</code> at the end of the <code>EDITOR</code> tells <code>rmate</code> to wait until the file has been closed on your remote computer&#x2014;this is the behavior that most tools expect from <code>$EDITOR</code>.</p><blockquote><code>sudoedit</code> is a helper provided by <code>sudo</code> &#xA0;for editing files which require root access, without running your editor as the root user.</blockquote><p>The third change is a simple alias so that you don&apos;t have to type <code>rmate</code> if you don&apos;t want to. I use <code>sl</code> since that&apos;s the alias I have on my local computer to open Sublime Text, and it makes for seamless transitions between the local and remote CLI.</p><h3 id="local-configuration">Local Configuration</h3><p>There are also a couple of things to set up locally in order for this to work.</p><p>First, you need an editor plugin, as discussed above. Check the settings for your plugin, you may need to turn it on or make sure that it&apos;s using the default <code>rmate</code> port (52698). However, subsequent times that you open your editor, it will start automatically and will not require further action, which is very convenient. </p><p>Second, you need to configure SSH to forward the <code>rmate</code> port when you connect to the remote computer. This can be done by passing an option at the command line, but this is cumbersome if you, like me, are using this as your default strategy for editing remote files.</p><p>Instead, I highly recommend creating a rule in your SSH config. On Mac, my SSH config lives in <code>~/.ssh/config</code>, and the rule that I&apos;ve added looks like:</p><pre><code># rmate forwarding
RemoteForward 52698 localhost:52698</code></pre><p>This means that when you open an ssh connection to a remote computer, it automatically creates a connection between port 52698 on the remote and local machines which <code>rmate</code> can use for communication.</p><blockquote>It&apos;s overkill to explain in this post, but you can of course configure this forwarding rule on a per-host basis, which is what I do in practice.</blockquote><h2 id="conclusion">Conclusion</h2><p>There are a couple of drawbacks to this.</p><ul><li>As you saw, there&apos;s a little bit of manual configuration involved.</li><li>Your editor has to be open locally, <code>rmate</code> can&apos;t open the editor application on your local computer.</li><li>There&apos;s no overwrite protection if the file you&apos;re editing with <code>rmate</code> is modified as you&apos;re editing it</li></ul><p>However, these are all very minor and understandable issues.</p><p>In my experience, this workflow is much more convenient than opening the file in Vim or Nano on the remote machine, and it&apos;s a lot simpler than mounting the remote filesystem or installing VSCode remote editing tools to edit a config file. Not to mention that these solutions rarely play well with <code>sudo</code>.<code>rmate</code> is a really impressive piece of engineering from the TextMate team, and I hope that I can continue using it for a long time.</p>]]></content:encoded></item><item><title><![CDATA[Only Git Commits are Real]]></title><description><![CDATA[I think of Git commits as being more real than branches and other Git objects. This has been a great help when understanding how Git works.]]></description><link>https://matthiasportzel.com/only-git-commits-are-real/</link><guid isPermaLink="false">6595604183de18f4b8b0924c</guid><category><![CDATA[idea]]></category><dc:creator><![CDATA[Matthias Portzel]]></dc:creator><pubDate>Sun, 07 Jan 2024 03:58:40 GMT</pubDate><content:encoded><![CDATA[<blockquote>The terminology in this post represents how I&apos;ve come to think about certain Git data structures, after using Git for close to 6 years. It does not reflect the official terminology used in the Git manual, and it does not reflect the Git implementation internals (of which I remain blissfully unaware).</blockquote><p>Git branches (and repositories, remotes, pull requests, etc) are not real. At least not in the way that a commit is.</p><h2 id="what-makes-a-commit-real">What makes a commit real?</h2><p>A commit is more real than these other objects in the git world for a couple of reasons:</p><ul><li>Commits are immutable&#x2014;they cannot be edited or moved</li><li>Commits are indestructible&#x2014;they cannot be deleted</li><li>Commits are complex&#x2014;most other git objects are trivial</li></ul><p>To understand the practical implications of these properties, it&apos;s useful to understand that a commit has a &quot;commit hash.&quot; You&apos;ve surely seen a commit hash if you&apos;ve worked with Git before. You can get the hash of the current commit (the commit at HEAD) with:</p><pre><code>git rev-parse HEAD</code></pre><p>A commit hash uniquely identifies a commit. (In fact, the commit hash is a hash of all of the metadata in the commit, and all the files at the moment of the commit. You can&apos;t change the files or the metadata without breaking this hash.) If you have the commit hash, you can find the commit and switch to it with <code>git switch --detach &lt;hash&gt;</code> or you can read the commit information with <code>git show &lt;hash&gt;</code>.</p><p>There are obviously operations in Git that appear to violate the above &quot;immutable&quot; property. At a basic level, <code>git commit --amend</code> will let you edit a commit, and at a more advanced level, <code>git rebase</code> is a tool for moving commits.</p><p>However these commands are really generating new commits, based on the old ones. These new commits will have new hashes (since their data will be different) and the old commits will still exist and still be usable if you have their hashes. Here&apos;s a basic example demonstrating this:</p><pre><code>$ git commit -m &quot;Exampel commit&quot; # commit with misspelling
[master 8fd3e68] Exampel commit
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 README
$ git rev-parse HEAD
8fd3e68b316f89357cb2bec8fb783d78c6ba6f9b
$ git commit --amend -m &quot;Example commit&quot; # fix spelling
[master fae17a7] Example commit
 Date: Wed Jan 3 08:47:41 2024 -0500
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 README
$ git rev-parse HEAD
fae17a7e41683cf4789f9ac5a7a889147a5ec2a0
$ git show 8fd3e68 --format=oneline -s # show the original unchanged commit
8fd3e68b316f89357cb2bec8fb783d78c6ba6f9b Exampel commit</code></pre><h2 id="what-makes-a-git-branch-not-real">What makes a Git branch not-real?</h2><p>Obviously, Git branches do exist. To understand what I mean when I say that they&apos;re not as real as commits, I&apos;d like you consider a ski slope.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://matthiasportzel.com/content/images/2024/01/Screen-Shot-2024-01-05-at-4.58.01-PM.png" class="kg-image" alt="A map of Bald Mountain from the 2023 Deer Valley Press Kit" loading="lazy" width="1442" height="1022" srcset="https://matthiasportzel.com/content/images/size/w600/2024/01/Screen-Shot-2024-01-05-at-4.58.01-PM.png 600w, https://matthiasportzel.com/content/images/size/w1000/2024/01/Screen-Shot-2024-01-05-at-4.58.01-PM.png 1000w, https://matthiasportzel.com/content/images/2024/01/Screen-Shot-2024-01-05-at-4.58.01-PM.png 1442w" sizes="(min-width: 720px) 720px"><figcaption>2023 Deer Valley Press Kit</figcaption></figure><p>This is a map of Bald Mountain. The runs, or suggested routes down the mountain, are denoted with solid lines. If you squint, it looks kind of like a Git commit tree (or some sort of directed acyclic graph).</p><p>These routes, however, are not etched into the mountain in a definitive fashion. In fact, here&apos;s an image of the mountain.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://matthiasportzel.com/content/images/2024/01/image-002.png" class="kg-image" alt="An image of Bald Mountain from the 2023 Deer Valley Press Kit" loading="lazy" width="1899" height="1256" srcset="https://matthiasportzel.com/content/images/size/w600/2024/01/image-002.png 600w, https://matthiasportzel.com/content/images/size/w1000/2024/01/image-002.png 1000w, https://matthiasportzel.com/content/images/size/w1600/2024/01/image-002.png 1600w, https://matthiasportzel.com/content/images/2024/01/image-002.png 1899w" sizes="(min-width: 720px) 720px"><figcaption>2023 Deer Valley Press Kit</figcaption></figure><p>You can see the general shape of the runs, where the resort has cleared trees, but without the map you can&apos;t tell the exact route of the runs. When skiing, you&apos;re allowed to cut through thin sections of trees or zig-zag between different sections of snow. This is why I&apos;m using a ski slope, and not a road or train track, as a metaphor. A train track exists in the real world and the train has to stay on it. There are no such tracks when skiing.</p><p>Git branches are the same way. If commits are the actual mountain, then branches are just the lines on the map.</p><p>Normally, when using Git, you stick to the branches, and your branches and your commits evolve at the same time. For example, when you make a commit, your current branch updates to point to the new commit.</p><pre><code class="language-sh">$ git branch -v
* master fae17a7 Example commit
$ git commit -m &quot;Test commit&quot;
[master 8ea77b2] Test commit
$ git branch -v
* master 8ea77b2 Test commit</code></pre><p>But this is not necessarily the case. We can move our branch back to the previous commit.</p><pre><code>$ git reset --hard HEAD~ # Reset the current branch to the parent of the HEAD commit
HEAD is now at fae17a7 Example commit
$ git branch -v
* master fae17a7 Example commit
$ git show 8ea77b2 --format=oneline -s
8ea77b29c0bc56c612a0668a00b929f9d11f45fc Test commit </code></pre><p>As can be seen in the example, this hasn&apos;t deleted the commit. In fact, this operation hasn&apos;t changed &quot;the mountain&quot; at all. It&apos;s only moved the &quot;line on the map.&quot; The commit is still there.</p><p>In fact, if we first switch to a different branch, we can delete the branch entirely, and this doesn&apos;t effect the commits.</p><pre><code>$ git switch -c feature-branch
Switched to a new branch &apos;feature-branch&apos;
$ git branch -D master
Deleted branch master (was fae17a7).</code></pre><p>All of our commits are still there. However, since they&apos;re not all on a branch, some of them are unreachable!</p><h2 id="what-does-it-mean-to-be-on-a-branch">What does it mean to be &quot;on a branch&quot;</h2><p>The &quot;on a branch&quot; terminology is very frequently used in the Git world. This terminology confused me when I was learning Git, and it&apos;s doesn&apos;t reflect how I think about Git commits or branches today.</p><p>Saying &quot;this commit is on the branch master&quot; reflects a lot more about the location of the branch than it does the location of the commit. The branch is movable; the commit is not. In the ski-slope metaphor, you could say &quot;this spot is on the run Evergreen,&quot; but that doesn&apos;t mean the spot could move to a different run.</p><p>Additionally, this phrase is confusing because a branch does not have a list of commits which are &quot;on it.&quot; Rather, a branch stores only the single commit which is at its tip. In this sense, branches are less like runs on a ski slope, and more like points placed on the map.</p><p>Here&apos;s the best definition for this concept that I can give: a commit is &quot;on a branch&quot; if and only if that commit is an ancestor of the commit at the tip of the branch.</p><p>One interesting consequence of this definition is that once two branches have been merged, they have exactly the same set of commits, and it&apos;s impossible (without looking at commit messages or PR messages) to tell which commits were originally on which branches.</p><h2 id="what-happens-to-commits-that-arent-on-a-branch">What happens to commits that aren&apos;t on a branch?</h2><p>Commits that aren&apos;t on a branch are called &quot;unreachable.&quot; This doesn&apos;t mean that they&apos;re completely unreachable&#x2014;as we showed, if you have the commit id, you can still inspect or switch to these commits. However, they&apos;re not reachable from a branch (or other reference like a tag).</p><p>Unreachable commits include commits that have been edited with git commit --amend, commits that have been copied and superceeded by a git rebase, or commits that were left behind by branch-moving or deletion shenanigans. They exist in a sort of purgatory. They normally exist completely out of sight. And then, after 90 days, they are deleted forever by Git&apos;s garbage collection. However, they can be saved if a kind Git user (like you) makes them reachable again.</p><p>We can view the state of our Git tree with <code>git log</code>. However, if we want to include unreachable commits, we have to pass their commit hashes so that git log knows to look for them.</p><pre><code>$ git log --graph 8ea77b2 8fd3e68
* commit 8ea77b29c0bc56c612a0668a00b929f9d11f45fc
| Author: Matthias Portzel &lt;MatthiasPortzel@gmail.com&gt;
| Date:   Sat Jan 6 14:52:08 2024 -0500
|
|     Test commit
|
* commit fae17a7e41683cf4789f9ac5a7a889147a5ec2a0 (HEAD -&gt; feature-branch)
| Author: Matthias Portzel &lt;MatthiasPortzel@gmail.com&gt;
| Date:   Wed Jan 3 08:47:41 2024 -0500
|
|     Example commit
|
| * commit 8fd3e68b316f89357cb2bec8fb783d78c6ba6f9b
|/  Author: Matthias Portzel &lt;MatthiasPortzel@gmail.com&gt;
|   Date:   Wed Jan 3 08:47:41 2024 -0500
|
|       Exampel commit
|
* commit 530fa49f63df2382c26e5c3a7f13530568d38d12
| Author: Matthias Portzel &lt;MatthiasPortzel@gmail.com&gt;
| Date:   Wed Jan 3 08:44:44 2024 -0500
|
|     Example commit 1
|
* commit 1160ba1470ab0496293a1db0e7abee4c74863337
  Author: Matthias Portzel &lt;MatthiasPortzel@gmail.com&gt;
  Date:   Wed Jan 3 08:44:33 2024 -0500

      Test commit 1</code></pre><p>In this commit tree, you can see two unreachable commits, 8ea77b2 and 8fd3e68. fae17a7 and its three generations of parents are reachable because they exist on the <code>feature-branch</code> branch.</p><p>Let&apos;s finish this post by &quot;saving&quot; commit 8ea77b2 from its unreachable state. We just have to create a new branch at that commit.</p><pre><code class="language-sh">$ git branch master 8ea77b2</code></pre><p>Simple.</p><p>Hopefully this post gave you a better understanding of how to think about commits and branches; and hopefully this framework makes it easier to understand potentially confusing Git operations like rebase, merge, and more.</p>]]></content:encoded></item><item><title><![CDATA[Declarative package management with a Brewfile]]></title><description><![CDATA[I love macOS and Brew, but my workflow looks very different from most Brew users.]]></description><link>https://matthiasportzel.com/brewfile/</link><guid isPermaLink="false">64ab3f017feb2e7b723d8803</guid><category><![CDATA[idea]]></category><dc:creator><![CDATA[Matthias Portzel]]></dc:creator><pubDate>Sun, 01 Oct 2023 23:26:00 GMT</pubDate><content:encoded><![CDATA[<p>I&#x2019;m a big fan of macOS, and I&#x2019;m a big fan of the most popular package manager on macOS, Homebrew. It&#x2019;s one of the first things I install on a new Mac, and I use it for managing both casks (applications) as well as normal packages.</p>
<p>However, my Brew workflow looks very different from most people. In this post, I&#x2019;m going to describe my workflow and then give examples of what benefits this gives me.</p>
<p>My package management workflow revolves around a Brewfile. This is a text file that lets me declaratively list what packages I want to be installed. Instead of imperatively issuing commands like <code>install</code> and <code>uninstall</code>, I edit this text file to include the package that I want, then run a single command that syncs my system with the text file (installing missing packages and uninstalling extra packages), as well as upgrading any out-of-date packages.</p>
<p>That magic command is:</p>
<pre><code>alias bbic=&quot;brew update &amp;&amp;\
    brew bundle install --cleanup --file=~/.config/Brewfile&quot;</code></pre>
<ul><li><code>brew update</code> connects to the brew API server to fetch the newest version of all packages.</li><li><code>brew bundle</code>, the main command, installs and upgrades the requirements listed in the Brewfile.</li><li>Passing <code>--cleanup</code> removes any installed formula that aren&apos;t listed in the Brewfile.</li></ul>
<p>An example excerpt from my Brewfile:</p>
<pre><code># Moreutils provides, for example, vipe
brew &quot;moreutils&quot;

# macOS ships with a slightly out-of-date `less`
brew &quot;less&quot;

# jq, a command line JSON editor
brew &quot;jq&quot;

# Emacs (packaged for macOS)
tap &quot;d12frosted/emacs-plus&quot;
brew &quot;d12frosted/emacs-plus/emacs-plus&quot;, args: [&quot;with-memeplex-wide-icon&quot;]

# Sublime Text editor
cask &quot;sublime-text&quot;</code></pre>
<p>As you can see from this example, the syntax is very simple. Other declarative package management systems (Nix, for example) require learning a new syntax and a new system. But a Brewfile is just an unordered list of Homebrew packages.</p>
<h2 id="advantage-1-package-tracking">Advantage 1: Package tracking</h2>
<p>Other than the simplicity, the other thing to notice in that example excerpt is the comments. A Brewfile allows me to sort and comment on the packages inline, instead of having to keep in my head why I installed or uninstalled something. (To uninstall, I&#x2019;ll frequently just comment out the line with the package.)</p>
<p>This keeps my system organized, and ensures that I can keep track of every installed package and what its purpose is.</p>
<h2 id="advantage-2-easy-software-trials">Advantage 2: Easy Software Trials</h2>
<p>I like to be able to quickly and easily try out software, and uninstall it when I&#x2019;m done. I don&#x2019;t think installing software should be a commitment. If I&apos;m trying out a software, I can just run <code>brew install example-test-software</code>, which installs the software like normal. But the next time I run <code>bbic</code>, it will cleanup by uninstalling <code>example-test-software</code>, since it&apos;s not listed in my Brewfile. Since I like to &quot;trial-run&quot; software without hassle, this &quot;unsaved-by-default&quot; behavior is a plus for me.</p>
<h2 id="advantage-3-everything-always-up-to-date">Advantage 3: Everything always up-to-date</h2>
<p>If I want to permanently install a piece of software, I just edit <code>~/.config/Brewfile</code>, add the package (and a comment explaining why I added it), and then run <code>bbic</code>. This installs the software, but it also updates Homebrew and upgrades any out-of-date software at the same time. This ensures that every package on my system is always up to date. (This command invokes feelings of the famous <code>pacman -Syu</code> that I&apos;d grown fond of when using Arch.)</p>
<p>I can imagine many other workflows similar to this one, like having a Brewfile per-project and taking advantage of the ability to run a Brewfile-specific sandbox, or having &quot;install&quot; and &quot;uninstall&quot; aliases that edit the Brewfile for you. I&apos;m just describing what works for me. Hopefully this post gets you thinking about other ways of managing packages (that don&apos;t require switching operating system).</p>
<p>I originally started using this method because Brew didn&apos;t provide a way to automatically remove packages that were originally installed as dependencies, which made temporarily installing software difficult. Brew now, however, offers <code>brew autoremove</code>.</p>]]></content:encoded></item><item><title><![CDATA[Micromouse Robotics]]></title><description><![CDATA[A small robot that can autonomously solve a maze]]></description><link>https://matthiasportzel.com/micromouse/</link><guid isPermaLink="false">650cfc4f83de18f4b8b08fa0</guid><category><![CDATA[project]]></category><dc:creator><![CDATA[Matthias Portzel]]></dc:creator><pubDate>Fri, 22 Sep 2023 02:37:18 GMT</pubDate><content:encoded><![CDATA[<p>I was the software team lead on Case Western&apos;s Micromouse robotics team for four years.</p><p>Micromouse is a robotics competition where teams compete to create and program a small (mouse-sized) robot to solve a maze. The robot functions completely autonomously (without any remote-control) and has to navigate to the center of the maze with no prior information.</p><p>As software lead, I implemented a tweaked version of the A* search algorithm to navigate the maze, and closed loop sensor control in order to avoid crashing into walls.</p><figure class="kg-card kg-image-card"><img src="https://matthiasportzel.com/content/images/2023/09/finished-robot.JPG" class="kg-image" alt="A picture of a small robot with two wheels and exposed wires" loading="lazy" width="2000" height="1500" srcset="https://matthiasportzel.com/content/images/size/w600/2023/09/finished-robot.JPG 600w, https://matthiasportzel.com/content/images/size/w1000/2023/09/finished-robot.JPG 1000w, https://matthiasportzel.com/content/images/size/w1600/2023/09/finished-robot.JPG 1600w, https://matthiasportzel.com/content/images/size/w2400/2023/09/finished-robot.JPG 2400w" sizes="(min-width: 720px) 720px"></figure><p>We used the Teensy 3.1 as an embedded microcontroller and the Arduino platform to program the robot.</p><p>In 2023, we earned a Silver award at the National Robotics Challenge.</p><p><a href="https://github.com/cwruRobotics/Micromouse-2022-23/blob/78124fc846af2402fe96ae7799d17e1432611dc3/software/Micromouse/Micromouse.ino?ref=matthiasportzel.com">Source Code on GitHub</a></p><p>Myself and another former member of that team continued developing small autonomous robots with our entry into the APEC 2025 Micromouse contest.</p>]]></content:encoded></item><item><title><![CDATA[How I learned to stop worrying and start studying (0.75 to 3.75 GPA)]]></title><description><![CDATA[Stress makes work miserable, which leads to procrastination, which leads to stress. How did I escape?]]></description><link>https://matthiasportzel.com/stop-worrying/</link><guid isPermaLink="false">64f2081ef3909ddb0d836d9e</guid><category><![CDATA[idea]]></category><dc:creator><![CDATA[Matthias Portzel]]></dc:creator><pubDate>Fri, 01 Sep 2023 17:18:30 GMT</pubDate><content:encoded><![CDATA[<p>I used to be a huge procrastinator. I tried to do as little work as possible, do it as quickly as possible, and do it as close to the deadline as possible. This post is how I changed my mindset and restructured my life in order to effectively get homework done on time in college. Notably, it didn&#x2019;t require &#x201C;trying harder&#x201C; or sacrificing my happiness.</p><p>This productivity system is inspired by many other approaches, but combines them together into a system that has allowed me to break out of the procrastinator&#x2019;s mindset and get things done. Unlike other systems, it is not designed to maximize productivity or efficiency. Rather, it minimizes stress and anxiety, and asks relatively little of me.</p><blockquote>My yoke is easy and my burden is light.<br>&#x2014;Matthew 11:30</blockquote><p>This is the description of the productivity system that I currently use. I wish that I had this document 4 years ago. It would have honestly been life-changing. I knew I needed something like this system, but none of the other systems that I tried helped me.</p><p>I&#x2019;m sharing it because I think you might be interested, and it might be helpful for you. But I don&#x2019;t know if it will be. I use &#x201C;you should&#x201D; or &#x201C;you have to&#x201D; several times because it is convenient. But I am not telling you to use this system.</p><h2 id="the-procrastinator%E2%80%99s-failure-mode">The Procrastinator&#x2019;s Failure Mode</h2><p>In high school, my days were packed full of classes, homework, and extracurricular activities, with very little flexibility. In college, I had fewer extracurriculars, less time in class, and copious free time. I was utterly unprepared to make use of this time, but I didn&#x2019;t realize it at first. I tried to apply the same strategies that I did in high school: wait until the last minute and try to spend as little time on things as possible. This worked fine in high school because I had so much going on. (I couldn&#x2019;t have spent more time on my assignments if I had wanted to.) But my second semester Junior year, I ended with a 0.75 GPA (that&#x2019;s 2 F&#x2019;s, a D and a C). Something went horribly wrong.</p><p>I want this to be a post about the strategies I use now, not the particular failure mode that I ended up in. But I do need to explain why I ended up failing half my classes.</p><ul><li>I was smart enough to understand the concepts in my classes. While difficult, the complexity of the topics was not the source of my troubles.</li><li>I had plenty of time. I was only taking four classes, and participating in minimal extracurriculars.</li></ul><p>In short, my problem was simply that I couldn&#x2019;t make myself spend time on it. This led to a disastrous feedback loop. See, the less time you spend on work, the more important the time that you spend is. If you&#x2019;ve procrastinated, and you have two hours before the assignment is due to complete it, then that two hours is extremely important. This leads to engaging in two hours of work, which frankly, are miserable. It&#x2019;s rushed, high stakes (you don&#x2019;t have time to make mistakes), and high stress. The chronic procrastinator knows this, and so they are right to be extremely unwilling to sit down and face this two hours of work. So instead, they procrastinate more.</p><h2 id="audience">Audience</h2><p>This post is applicable to a very particular type of person. High schoolers and younger, who largely have their time managed for them, are limited in how much they can mismanage their time, and thus how much this can help. Similarly, if you have a job that requires you to work defined shifts, then there&#x2019;s little room to procrastinate. In fact, this approach is heavily inspired by the effectiveness of shift work.</p><p>I expect the primary audience is college students like myself, but this could also be helpful for people working from home with flexible hours.</p><p>In order for this to be effective, your work and your expectations cannot be exceptional. This system is designed to minimize stress and anxiety, and increase your enjoyment of the work as a consequence. Once this happens, it&#x2019;s easy to get enough done to satisfy other people. In a college setting, what this means is that you have to be okay with getting Cs. (I found that once I implemented this system, I very rarely got below a B, but you have to be okay with Cs.) Look at it this way. Maintaining a 4.00 is stressful, and there&#x2019;s no system I can give you that will make it stress-free. But a lot of procrastinators are stressed about trying not to fail. And not-failing shouldn&#x2019;t be stressful. You can do it.</p><h2 id="four-mindset-shifts">Four Mindset Shifts</h2><p>At the end of the day, chronic procrastination isn&#x2019;t a failure of an organizational system. It&#x2019;s a mindset failure. While there are lots of resources for procrastinators to change their systems, few people talk about the required mindset shifts.</p><ol><li>Recognize that your time is not valuable.</li><li>You should be comfortable enough that you can work forever.</li><li>Create and stick to a routine.</li><li>Left-align tasks.</li></ol><p>This is the hard part. All of these mindset shifts are required. You can&#x2019;t implement one of them and expect results, they all play into one another. If you think that your time is valuable, you&#x2019;ll find it very hard to stick to a routine. If you&#x2019;ve organized your time into a routine, you&#x2019;ll be forced to left-align your tasks.</p><p>The next four sections will explain what I mean by each of these.</p><h2 id="recognize-that-your-time-isn%E2%80%99t-valuable">Recognize that your time isn&#x2019;t valuable</h2><p>I posit that the single biggest reason that procrastination is so hard to break out of is that this required leap is so counter-intuitive. At least for me, I tried to break out of procrastination by telling myself that my time was too valuable to be wasting procrastinating, and that I should start working right now. But as mentioned in the beginning, the procrastinator, usually, is under too much stress, not too little. Rather, I take the pressure off. It&#x2019;s okay. You&#x2019;re going to be okay.</p><blockquote>And we know that God works all things together for the good of those who love Him, who are called according to His purpose.<br>&#x2014;Romans 8:28</blockquote><p>Procrastination, really, is a productivity system that&#x2019;s concerned with spending as little time as possible on the work. What I&#x2019;m about to suggest, in the later section on routine, is allocating way more time than you need to do the work. But before you can do that, you have to be okay with &#x201C;wasting&#x201D; your time by not perfectly scheduling everything. The procrastinator is frugal with their time, hoarding it, spending as little as possible and only when it is absolutely necessary. You should be liberal with your time, spending time doing work even when you don&#x2019;t need to.</p><p>Additionally, lowering the stakes makes the work much more enjoyable. It removes the pressure and obligation from any one decision to do work.</p><h2 id="you-should-be-able-to-work-forever">You should be able to work forever</h2><p>This is more difficult to describe than the other things discussed in this post. It&#x2019;s also less important, so I&#x2019;ll spend less time on it. It&#x2019;s really a feeling, the feeling that you can continue at the same pace for the rest of your life.</p><p>I have a temptation to think that I just need to &#x201C;push through&#x201D; or &#x201C;work hard for a short amount of time&#x201D; but this temptation is antithetical to the system that is being described.</p><p>This is a system for pacing yourself. If you find yourself seriously struggling, that is a good opportunity to step back and reflect on why. If you&#x2019;re not under time pressure, you can get help or take a break and do something easier.</p><p>Life isn&#x2019;t a sprint, and it&#x2019;s not even a marathon. It&#x2019;s not a race at all. You can set your own goals and your own pace.</p><h2 id="routine-is-more-important-than-getting-things-done">Routine is more important than getting things done</h2><p>Routine is what happens when a schedule becomes habit. But you first need a schedule.</p><p>My current daily schedule (7 days a week) looks something like this:</p><ul><li>wake up at 7</li><li>start working (usually on school work) at 8:30</li><li>work until 12</li><li>eat lunch</li><li>resume work at 12:30</li><li>work until 5</li><li>relax for an hour</li><li>eat dinner at 6</li><li>relax until I get tired and go to bed (usually at 10)</li></ul><p>It feels silly writing this out, because it&#x2019;s not that peculiar of a schedule. However! What is unusual is my mindset. What is unusual is that I actually think about my day at this level of granularity. At 5:00 on the dot, I close my open documents, change clothes, and open YouTube. For a while I had these events in my phone calendar (&#x201C;Study, 8:30&#x2014;12&#x201D; etc), until they became second nature.</p><p>The specifics of the times of course don&#x2019;t matter, and I&#x2019;m leaving out many details. For example, sometimes I&#x2019;ll add a third working time block from 7-9pm for work on personal projects. What I want you to take away is merely the efficiency of the idea of large &#x201C;working blocks,&#x201D; without further subdivisions. I try to avoid breaking down my day any further. I never estimate the time it will take to do individual assignments or dedicate blocks of time to working on them.</p><p>In order to ensure I have enough time to get everything done, I simply allocate more time than I actually need. I don&#x2019;t need to spent 8 hours a day doing work. But that is a reasonable amount of time to spend (it is an amount that I can commit to forever), based on the idealized day of 8 hours work / 8 hours at home / 8 hours sleep.</p><p>Having a distinct routine for working and taking breaks has no less than five distinct advantages: unscheduled productive time, consistent sleep, stress-free breaks, easy decision making, develop of habit. (I had to stop myself from adding more advantages. These are the main five.)</p><h3 id="unscheduled-productive-time">Unscheduled productive time</h3><p>As explained, most weeks I can get all of my work done in less than 40 hours. What, then, do I do with the rest of the time? All of the time during one of my &#x201C;working blocks,&#x201D; when I&#x2019;m not doing schoolwork, is spent in one of these ways.</p><p>First, I&#x2019;m okay with &#x201C;wasting&#x201D; this time. Some of this time I spend scrolling on my phone, taking a nap, or making myself a snack. These breaks from work are relatively quick, and I&#x2019;m often thinking about work, so they&#x2019;re different from the hour-long &#x201C;relaxation&#x201D; block after work, where I&#x2019;ll watch a TV show or read a book.</p><p>Second, some of this time is spent doing &#x201C;miscellaneous productive things.&#x201D; This includes updating my TODO-list, updating my calendar, making plans, cleaning my room, reorganizing files on my computer, etc.</p><p>Third, some of this time is spent on personal projects. If I really don&#x2019;t have any school work to do and my room is spotless, then I&#x2019;ll use my working time to write blog posts or code for my own projects.</p><p>Many procrastinators skip these things all together. Doing homework at the last minute is no fun, but it&#x2019;s even less fun if your room is a mess and you don&#x2019;t know what homework you have to do. So this time spent not doing homework is super important.</p><h3 id="consistent-sleep">Consistent sleep</h3><p>I&#x2019;m a huge believer in the importance of sleep, and not just quantity of sleep, but consistency. If you wake up at the same time every time every day, and go to bed 9 hours before that, your body will learn your sleep schedule. You&#x2019;ll start to feel tired at your bed time and awake in the morning.</p><p>I had nights in college where I stayed up until 5am and said hi to my roommate waking up at 5am. It&#x2019;s fun. But it does lead to an effect where your body starts to fight you, and &#x201C;demand&#x201D; more sleep than it actually needs, because it doesn&#x2019;t know when you&#x2019;ll be able to sleep again.</p><p>On at least one occasion, I tried to fix my sleep schedule by going to bed early. All that happened was I slept through my alarm and slept for over 12 hours. I was very discouraged by this, but I shouldn&#x2019;t have expected my sleep schedule to fix itself in a day. It takes closer to 2 weeks.</p><h3 id="100-stress-free-guilt-free-relaxation-time">100% Stress-free, guilt-free relaxation time!</h3><p>During my relaxation blocks, I straight up do not allow myself to work. This, combined with the fact that these blocks are relatively short (less than the work time and never a full day), means that I very rarely get bored or sick of playing too much Minecraft or binging too many Dropout.tv videos. It was honestly shocking to me how, after just a few days of scheduled work, I felt more passionate about my hobbies than I had before. If you stop working and immediately go eat dinner, then there&#x2019;s little time for rest or recreation. During my 5pm-6pm &#x201C;relax&#x201D; block, I&#x2019;m tired and hungry, but I&#x2019;m also more likely to pick up a book and read than at any other time of the day.</p><h3 id="easy-decision-making">Easy Decision Making</h3><p>For me, the most difficult part of doing homework was always making the decision to work on it. Making that decision always felt like it took a lot of motivation and energy and commitment.</p><p>One of the advantages of having a schedule is that it allows me a level of indirection. For the procrastinator, the decision to work is a complex affair, based on the amount of work they have to do, how difficult that work is going to be, when the assignment is due, etc. In contrast, I now need one piece of information to decide whether I&#x2019;m working or not, and that is the current time.</p><p>Once I&#x2019;ve decided to work, I still have to decide what to work on, but having these decisions be split up is actually an advantage. It&#x2019;s easy to decide to work when you don&#x2019;t have to decide what you&#x2019;re working on, and it&#x2019;s easy to decide what to work on when you&#x2019;ve already decided that you&#x2019;re going to work. For the details of how I decide what to work on, see the later section on my TODO list, but remember that &#x201C;cleaning my room&#x201D; or other low-stress tasks are always an option.</p><h3 id="build-habits">Build Habits</h3><p>There&#x2019;s a line in BoJack Horseman that gets used a motivational quote. BoJack (I think that&#x2019;s his name, I don&#x2019;t watch the show), has given up jogging and has laid down on the ground. Another character says to him, &#x201C;Every day it gets a little easier&#x2026; But you gotta do it every day&#x200A;&#x2014;&#x200A;that&#x2019;s the hard part. But it does get easier.&#x201D;</p><p>Now, in my experience, this quote isn&#x2019;t true in general. Math homework is hard, and doing math homework every day doesn&#x2019;t make it easier. But it is extremely true for one thing, and that is sticking to a routine. Every morning that you get out of bed and choose to get stuff done, makes doing it the next day easier. They say it takes about two weeks to build habits. After that point, your default option is to continue in the habit. That didn&#x2019;t make the work easier, and honestly, the voice in my head saying &#x201C;screw this, go back to bed&#x201D; never went away. But my default option is now getting out of bed. It just kind of happens.</p><p>To reiterate. The amazing thing about routine is that if you make the decision 14 times, then making the decision future times happens automatically.</p><p>Now, I want to add a quick note on deviations from routine. I ascribe a very high importance to following my schedule every day. That is my number one priority. However, it is still important not to beat yourself up when you do deviate from the routine. Let&#x2019;s say, as an example, that it&#x2019;s my 3rd or 4th day following a new routine, and I sit down for my lunch break, and I forget to get up. I got sucked into reading Twitter, and 1pm came and went, and now it&#x2019;s 3pm. Well, my first inclination is to give up on my new routine. My second inclination is to &#x201C;make up&#x201D; the lost time and work from 3 to 7. But both of these responses make the problem worse. The correct response is for me to work for the remainder of the time block, until 5, then relax at 5. &#x201C;But Matthias,&#x201D; you say, &#x201C;you haven&#x2019;t earned that break.&#x201D; But when you&#x2019;re following a routine, there&#x2019;s no concept of &#x201C;earning&#x201D; breaks. I&#x2019;m going to relax at 5 because the schedule says to, and the quicker that I can re-align with the schedule, the better.</p><h2 id="left-aligning-tasks">Left-aligning tasks</h2><p>When I say &#x201C;left-aligned,&#x201D; I mean that you start work on assignments as soon as possible, rather than as late as possible. This allows you to avoid the last-minute crunch. Additionally, it helps reduces stress, guilt, and pressure around completing, postponing, or failing to complete tasks.</p><p>The procrastinator is always working on the assignment that is due soonest. But since I have flexibility to choose what to work on, I end up working on whatever item I&#x2019;m most prepared to tackle at any given time. Sometime I won&#x2019;t be in the mood for writing, but would rather clean my room. Other times I&#x2019;ll be physically tired, unable to stand up, but have no problem doing some writing. This keeps me from fighting my body.</p><p>I&#x2019;ve re-organized my TODO-list in order to store assignments in a &#x201C;left-aligned&#x201D; way, which encourages my to work on them soonest-first.</p><h3 id="a-better-todo-list">A better TODO list</h3><p>TODO lists are necessary to keep track of what needs to be done. However, TODO lists should not be the motivator for whether you are doing work; that is the job of a schedule.</p><p>I removed the due-dates from my TODO list, and was left with just a list of work to be done. This re-organization allows the TODO list to keep track of all available work.</p><p>This is what that looks like for me. I keep my TODO-list in a paper notebook. I start a new TODO list on a new page in the notebook every day, and then I list out everything that I should or could be working on. This includes a section for homework and as well as any chore or other tasks. The one requirement is that everything on the list must be &#x201C;immediately actionable.&#x201D; If I can&#x2019;t start working on something immediately, then it becomes a reminder or a calendar event. (Often I create scheduled reminders simply to add something to my TODO list.)</p><p>The list is roughly sorted by importance. I check my calendar often enough that I know what assignments are due in the next few days, and these assignments end up on the top of the TODO list. But the due dates are not written down on the TODO list itself.</p><p>What this means is that if I don&#x2019;t complete a task on one day, then I have to re-write it on the TODO list for the next day. This can be annoying, since some assignments will stay on the list for a while, being moved from day-to-day and being re-written many times. However, this has one big advantage: I can put things that don&#x2019;t have hard deadlines in my TODO list. Things like &#x201C;do laundry&#x201D; or &#x201C;send email&#x201D; go on my TODO list. (When I was using a TODO-list app with deadlines, I would put in &#x201C;Do laundry&#x201D; with a to-do date of &#x201C;Today.&#x201D; But tomorrow that&#x2019;s marked as &#x201C;Overdue&#x201D; with a red exclamation mark, which is stressful and not helpful.) The second advantage of forcing myself to re-write things is that I can easily re-word the task as the requirements shift. If I work on &#x201C;Assignment 3&#x201D; on Monday, but get stuck on question 4, when I re-write the TODO list on Tuesday, I might say &#x201C;ask teacher about question 4 on Assignment 3.&#x201D; On Wednesday, after asking my question, it may be &#x201C;finish and submit assignment 3.&#x201D; With a due-date-based list, it doesn&#x2019;t make as much sense for me to edit or replace a task that&#x2019;s been partially completed. On a day that doesn&#x2019;t have much homework, &#x201C;re-organize closet&#x201D; might end up on the TODO list. But if the next day I have a lot of homework, it&#x2019;s easy to omit this unimportant task when rewriting the list. Manually re-writing the list ensures that entries always make sense to work on and aren&#x2019;t &#x201C;stale.&#x201D;</p><p>This removes the focus from &#x201C;getting items completed&#x201D; and shifts it to &#x201C;getting work done.&#x201D; My TODO list is not a list of things I have to do, it&#x2019;s a list of things that I could do.</p><p>(In practice, if my TODO list hasn&#x2019;t changed significantly, I won&#x2019;t re-write it. But most days it does.)</p><h3 id="other-examples-of-left-aligning-tasks">Other examples of left-aligning tasks</h3><p>I had asked some of my friends who were more organized than me how they kept track of things. One of them said that she has a planner/calendar that she writes assignments in. The catch? She writes them in the planner section corresponding to the date they are assigned, not when they&#x2019;re due. This is nonsensical from the perspective of someone who is right-aligning tasks, but you can now recognize that this is just left-aligning tasks. Another friend of mine has a whiteboard where he keeps a list of assignments to work on. He tries to erase it regularly and re-write it from scratch to avoid stale entries. This is also a left-aligned system, since the entries aren&#x2019;t sorted and he doesn&#x2019;t write out the dates.</p><h2 id="conclusion">Conclusion</h2><p>This article is much longer than I expected it to be. If you read all of that, congratulations! If you didn&#x2019;t, let me summarize:</p><ul><li>Escaping procrastination is difficult because you need to be less frugal with your time, not more.</li><li>If what you&#x2019;re doing is really difficult for you, you&#x2019;re probably working too hard, or not used to working at all.</li><li>Deciding to work a structured 8 hours a day is a great way to fix the above problems. A casual 8 hours of work is better than a rushed 2 hours.</li><li>When filling your time, work on things as soon as possible, not as late as possible. Don&#x2019;t worry about when they&#x2019;re due, just work on making progress on them.</li></ul><p>Hopefully some of these ideas are helpful for you in your own life. If not, hopefully you found it an interesting insight into my life.</p>]]></content:encoded></item><item><title><![CDATA[Docker is 4 things]]></title><description><![CDATA[Docker is not just a way of running programs on Linux without a virtual machine. Docker is 4 things.]]></description><link>https://matthiasportzel.com/docker/</link><guid isPermaLink="false">64efdd5af3909ddb0d836d51</guid><category><![CDATA[idea]]></category><dc:creator><![CDATA[Matthias Portzel]]></dc:creator><pubDate>Thu, 31 Aug 2023 00:35:03 GMT</pubDate><content:encoded><![CDATA[<ul><li>First, the Dockerfile file format for declaratively describing a machine (operating system, installed packages, processes, etc).</li><li>Second, the Docker Engine which takes a Dockerfile and runs it on a Linux host natively, without a virtual machine.</li><li>Third, the Docker Desktop app which takes a Dockerfile and runs it on a Mac or Windows host, using a Linux virtual machine.</li><li>Fourth, the Docker Hub container repository which allows a community to share Dockerfiles for common configurations.</li></ul><p>Often, when people evaluate Docker or make statments about &quot;Docker,&quot; they&apos;re referring only to the Docker Engine. But most of the time, this is not a useful view to take. Most of time, the practicality of Docker comes from a combination of all four of these things.</p>]]></content:encoded></item><item><title><![CDATA[MatthiasPortzel.com]]></title><description><![CDATA[This portfolio website]]></description><link>https://matthiasportzel.com/matthiasportzel-com/</link><guid isPermaLink="false">64b70e20dd3628a14f9b80bf</guid><category><![CDATA[project]]></category><dc:creator><![CDATA[Matthias Portzel]]></dc:creator><pubDate>Tue, 18 Jul 2023 22:14:16 GMT</pubDate><content:encoded><![CDATA[<p>For a long time, I published projects under the pseudonym MatthiasSaihttam.<br>In late 2021, I created this website to centralize all of my notable projects in one place.</p><p>The backend of this site has been completely written several times. Originally it used Next.js, but as I wasn&apos;t using many of Next&apos;s features, I re-wrote it with the Nano.jsx library and my own glue code. However, Summer 2023, I launched a new version of MatthiasPortzel.com based on Ghost. Having an Admin view that allowed me to edit and manage posts increased the amount that I was able to write and update the site. And by creating a wholely custom theme, I could preserve MatthiasPortzel.com&apos;s unique look.</p>]]></content:encoded></item><item><title><![CDATA[Lucid Education]]></title><description><![CDATA[Part-time web development for Lucid Education.]]></description><link>https://matthiasportzel.com/lucid-education/</link><guid isPermaLink="false">64b70e06dd3628a14f9b80b6</guid><category><![CDATA[project]]></category><dc:creator><![CDATA[Matthias Portzel]]></dc:creator><pubDate>Tue, 18 Jul 2023 22:11:24 GMT</pubDate><content:encoded><![CDATA[<p>I worked on the frontend of a system managing account for an online education platform with over 1,000 students. I did frontend development using the APS.NET framework, working in both C# and Javascript.<br><br>The project was version controlled with Microsoft&apos;s proprietary system and the code is not owned by me.</p>]]></content:encoded></item><item><title><![CDATA[Eradani Inc]]></title><description><![CDATA[Developed websites for Eradani]]></description><link>https://matthiasportzel.com/eradani/</link><guid isPermaLink="false">64b70d90dd3628a14f9b809f</guid><category><![CDATA[project]]></category><dc:creator><![CDATA[Matthias Portzel]]></dc:creator><pubDate>Tue, 18 Jul 2023 22:09:31 GMT</pubDate><content:encoded><![CDATA[<p>Eradani works with clients to update old IBM-i systems with modern web frontends.<br><br>I worked to develop proof-of-concepts for their clients, building something that could be demoed, with just a couple weeks turn-around.<br><br>Examples include internal tracking tools for large distributors of kitchen supplies and automobile glass, which you&apos;ve probably used if not heard of.<br><br>I worked on a React/Typescript frontend, coordinating with 2 other interns working on other parts of the same project.<br><br>We had to work quickly, pushing to Github and merging code often.<br><br>All code I did for Eradani is closed-source and owned by Eradani.</p>]]></content:encoded></item><item><title><![CDATA[KA Hearth]]></title><description><![CDATA[A blog where I discuss Khan Academy.]]></description><link>https://matthiasportzel.com/ka-hearth/</link><guid isPermaLink="false">64b70d30dd3628a14f9b8093</guid><category><![CDATA[project]]></category><dc:creator><![CDATA[Matthias Portzel]]></dc:creator><pubDate>Tue, 18 Jul 2023 22:07:56 GMT</pubDate><content:encoded><![CDATA[<p>I created the KA Hearth to document a lot of the 3rd-party reverse engineering of Khan Academy that I was doing.<br><br>I talk about interesting technical changes to KA&apos;s platform, and give background for people interested in participating in KA&apos;s computer-science community.<br><br>With almost 50 posts over more than 2 years, it&apos;s an interesting source for understanding the Khan Academy computer science community.&quot;<br><br>The KA Hearth is hosted with Github Pages. It&apos;s built with Jekyll using the Modernist theme (linked in its footer).<br><br>The KA Hearth is open-source on Github, which has allowed people to make PRs to fix my typos.<br><br><a href="https://ka-hearth.learnerpages.com/?ref=matthiasportzel.com">The KA Hearth</a></p>]]></content:encoded></item><item><title><![CDATA[KA User Search]]></title><description><![CDATA[A searchable database of Khan Academy users]]></description><link>https://matthiasportzel.com/ka-user-search/</link><guid isPermaLink="false">64b70d0fdd3628a14f9b8088</guid><category><![CDATA[project]]></category><dc:creator><![CDATA[Matthias Portzel]]></dc:creator><pubDate>Tue, 18 Jul 2023 22:07:34 GMT</pubDate><content:encoded><![CDATA[<p>Khan Academy doesn&apos;t have any practical way of searching for users, something which I find myself wanting to do often.<br><br>This website concatenates data from several scrapes of KA programs and users (some done by me, some by others).<br><br>The result is a list of KA users/nicknames which filters as you type. (If a user changed their nickname, they will be listed by all nicknames to ensure they are findable.)<br><br>This project was an experiment in infrastructure minimalism.<br><br>The backend is a single NodeJS file, with a dependency only to connect to the database.<br><br>The frontend is a single HTML file, which is of course available.<br><br>Since there is so little code here, it is closed-source, though I do track it with git.</p>]]></content:encoded></item><item><title><![CDATA[KA Challenge Council Member]]></title><description><![CDATA[I was a member of the official Khan Academy Challenge Council]]></description><link>https://matthiasportzel.com/ka-challenge-council/</link><guid isPermaLink="false">64b70ce1dd3628a14f9b807c</guid><category><![CDATA[project]]></category><dc:creator><![CDATA[Matthias Portzel]]></dc:creator><pubDate>Tue, 18 Jul 2023 22:06:40 GMT</pubDate><content:encoded><![CDATA[<p>After a number of KA users (including myself) petitioned KA to interact more actively with their computer-science students, KA created the Challenge Council.<br><br>As a member of the inaugural council, I helped develop monthly contests for KA students, and judged their entries.<br><br>I enjoyed giving back to the community where I had learned programming.<br><br>I served on the council for 2 years before leaving voluntarily to focus on other projects.</p>]]></content:encoded></item><item><title><![CDATA[KA Contributions]]></title><description><![CDATA[I've been able to contribute code to KA on a couple of occasions.]]></description><link>https://matthiasportzel.com/ka-contributions/</link><guid isPermaLink="false">64b70cbcdd3628a14f9b8071</guid><category><![CDATA[project]]></category><dc:creator><![CDATA[Matthias Portzel]]></dc:creator><pubDate>Tue, 18 Jul 2023 22:06:07 GMT</pubDate><content:encoded><![CDATA[<p>Khan Academy&apos;s live-editor, which powers their computer programming environment, is open source. I&apos;ve made a couple of contributions to this code-base, and so am thanked for help with Special Projects on KA&apos;s volunteer page (under the name MatthiasSaihttam).<br><br><a href="https://www.khanacademy.org/contribute/credits?ref=matthiasportzel.com">KA&apos;s Volunteer credit page.</a><br><br>I&apos;ve also reported a security bug, and have their &quot;Friendly Hacker&quot; badge.<br><br>I was able to review KA&apos;s AP Computer Science Principles content before it was publicly available.</p>]]></content:encoded></item></channel></rss>