Daniel Moerner
https://moerner.com/
Recent content on Daniel MoernerHugoen-usSat, 28 Feb 2026 08:11:51 -0500Goodbye OpenAI
https://moerner.com/posts/goodbye-openai/
Sat, 28 Feb 2026 08:11:51 -0500https://moerner.com/posts/goodbye-openai/<p>I have canceled my personal subscriptions to ChatGPT and committed to not using
Codex or ChatGPT at work going forward. I cannot continue to support a company
that shows such disregard for my values and the values of its employees.</p>
<p>Last night, Sam Altman, the CEO of OpenAI, <a href="https://archive.ph/nipGb">announced</a> that OpenAI would be
entering into an agreement with the Department of Defense to use their models:</p>
<blockquote>
<p>Tonight, we reached an agreement with the Department of War [sic] to deploy our models in their classified network.</p>The Pragmatic Programmer in 2025
https://moerner.com/posts/pragmatic-programmer/
Tue, 15 Jul 2025 20:12:23 -0400https://moerner.com/posts/pragmatic-programmer/<p>Over the past few weeks, I read through the 20th Anniversary Edition of <em>The
Pragmatic Programmer</em>, by David Thomas and Andrew Hunt (2019). I’ve often seen this
book praised as a practical resource for software development. In this
low-effort blog post, I’m just going to reproduce a few of my notes on what I
found interesting or puzzling here. The book is divided into 53 Topics, which I
use to organize my notes.</p>On Interviewing in Tech and Academia
https://moerner.com/posts/interviewing/
Sat, 24 May 2025 09:54:18 -0400https://moerner.com/posts/interviewing/<p>I’ve recently switched careers from academia to software engineering. Some reflections on the interview and job market in these two different fields.</p>
<h1 id="adversarial-and-non-adversarial">Adversarial and Non-adversarial</h1>
<p>In my experience, every step in the interview process in academia is
adversarial. This both characterizes my own experience as an interviewee, and the interviews I gave as a
faculty member of at the University of Chicago. The first step in each meeting
is to get the interviewee to commit to something; the second step is to object
to it. This patterns holds from group interviews, to job talks, to one-on-one
meetings, and even to casual meals. Many one-on-one meetings begin with an
upfront claim that it will not be a discussion of work; they almost inevitably
evolve into a series of debates.</p>How to Make a One-Click File Upload Button in Svelte
https://moerner.com/posts/svelte-file-upload-button/
Thu, 06 Mar 2025 17:50:17 -0500https://moerner.com/posts/svelte-file-upload-button/<p>I’ve recently started using Svelte for some personal projects, like <a href="https://github.com/dmoerner/svelteclick">SvelteClick</a> and <a href="https://github.com/dmoerner/pytorrent">PyTorrent</a>, which is a collaborative project developed with Lamone Armstrong. While writing the front-end for PyTorrent, I wanted to make a one-click file upload and submit button. Why? Because this is ugly:</p>
<p><img src="./ugly-button.png" alt="Separate buttons for Browse and Upload"></p>
<p>And this is nice:</p>
<p><img src="./nice-button.png" alt="Single button to open dialogue window and upload"></p>
<p>Sure, you can style the former, but the problem is that the workflow is clunky:
There’s no reason to make the user click twice just to upload a file. This blog
post outlines how I failed and then how I got it working. Thanks to Teon Brooks
for pairing on this with me!</p>When do you need nonlocal or global in Python?
https://moerner.com/posts/python-nonlocal-global/
Wed, 19 Feb 2025 09:23:52 -0500https://moerner.com/posts/python-nonlocal-global/<p>I recently realized I had a slightly hazy understanding of name scope in
Python. I knew I needed to use <code>global</code> or <code>nonlocal</code> in some instances, but I wasn’t
exactly clear when and where they were needed. In practice this means
scattering them everywhere they might be used.</p>
<p>I think I figured it out, and
it’s really quite simple, but I didn’t find as clear a statement as I would
have liked in the documentation. This post draws on the <a href="https://docs.python.org/3/reference/simple_stmts.html">official Python 3
documentation</a>
and <a href="https://peps.python.org/pep-3104/">PEP 3104 - Access to Names in Outer
Scopes</a>, as well as my own testing.</p>etracker Public Demo
https://moerner.com/posts/etracker-public-demo/
Mon, 17 Feb 2025 18:25:06 -0500https://moerner.com/posts/etracker-public-demo/<p>Over the past two months I have been sharing work here and on
<a href="https://github.com/dmoerner/etracker">Github</a> on a new BitTorrent tracker
<code>etracker</code>. I’m happy to share that a public demo is now available:
<a href="https://etracker.moerner.com/">https://etracker.moerner.com/</a>. The public demo is deployed with a small
infohash allowlist consisting of recent Linux ISOs. An expanded frontend with
support for suggesting allowed infohashes is under development.</p>
<p>To briefly summarize: <code>etracker</code> is a tracker designed to contribute to solving
free-riding problems in the BitTorrent protocol at the tracker level. Clients
which behave poorly (failing to seed snatches; failing to upload more than they
download) receive proportionately less peers from the tracker than clients
which are well-behaved. New BitTorrent clients to the tracker receive a full
complement of peers, so there is no startup penalty when initially joining the
tracker.</p>fatal: bad object HEAD
https://moerner.com/posts/fatal-bad-object-head/
Sat, 08 Feb 2025 13:19:48 -0500https://moerner.com/posts/fatal-bad-object-head/<p>Thanks to all my friends and colleagues for such a wonderful in-person week at
the <a href="https://www.recurse.com/">Recurse Center</a> hub in Brooklyn. I got so much
out of the pairing, the social environment, and especially the opportunity to
present my work in-person at Presentations+. Part of me wishes I had spent a
week in-person earlier, but part of me also believes it was so great precisely
because it was so late in the batch and my work was in a good place for
collaboration.</p>Learning React and Rethinking JavaScript's Warts
https://moerner.com/posts/rethinking-js-react/
Wed, 29 Jan 2025 10:44:51 -0500https://moerner.com/posts/rethinking-js-react/<p>There are many ways to do the same thing in every popular programming language,
but not all of them are made equal. (I presume this is a corollary of Turing
completeness.) This is why it is so
important when learning a new language to get a grip on common patterns and
<a href="https://en.wikipedia.org/wiki/Anti-pattern">anti-patterns</a>. Otherwise we risk
making the wrong choices (like assuming that tail recursion is always the optimal
recursive algorithm even though with small inputs the time costs of reversing the result may be larger than
the benefits in space complexity), or being paralyzed by the thought of too
many choices (like I felt when I learned the Node <code>fs</code> module provides <a href="https://nodejs.org/en/learn/manipulating-files/reading-files-with-nodejs">three
interfaces</a>
that all do the same thing).</p>Bad Counterpoint, and MIDI and HTML5 in 2025
https://moerner.com/posts/midi-html-2025/
Tue, 21 Jan 2025 20:48:04 -0500https://moerner.com/posts/midi-html-2025/<p>Today I spent some toy throwing together a toy music generator in Python, <a href="https://github.com/dmoerner/badbach">Bad
Bach</a>. Counterpoint is a musical style
with roots in the Renaissance which follows a strict set out of rules. I set out to deliberately write bad
counterpoint, or what I later learned is called <a href="https://en.wikipedia.org/wiki/Counterpoint#Dissonant_counterpoint">dissonant
counterpoint</a>, which breaks as many of those rules as possible. I initially approached this as a puzzle solver problem, with the goal of maximizing under a set of constraints. However, I realized this music would be too deterministic for my taste. So instead I constructed a set of weights for (breaking) each rule, and then randomly generate rule-breaking harmonies based on those weights.</p>Is Communication within the Youtube Apparatus Meaningless?
https://moerner.com/posts/is-youtube-meaningless/
Tue, 14 Jan 2025 18:57:51 -0500https://moerner.com/posts/is-youtube-meaningless/<p>Over the past day there has been discussion of a provocative essay by Kevin
Munger, <a href="https://kevinmunger.substack.com/p/in-the-belly-of-the-mrbeast">in the belly of the MrBeast</a>, which builds on his recent book <a href="https://www.cambridge.org/core/elements/youtube-apparatus/36600D69788530F805C650B70976A585">The YouTube Apparatus</a>. I want to applaud the author for publishing this under CC-BY-NC 4.0, since otherwise I wouldn’t be able to read it.</p>
<p>Central to both essay
and book is the thesis that there is something meaningless about YouTube. As
the book puts it, “This is what I mean by <em>nihilism</em>: Communication within the YouTube Apparatus <em>has no meaning</em>.” As summarized in the essay:</p>A Curious Moon in Podman or Docker
https://moerner.com/posts/docker-postgres-makefile/
Sun, 12 Jan 2025 10:34:11 -0500https://moerner.com/posts/docker-postgres-makefile/<p>I recently started working through <a href="https://sales.bigmachine.io/curious-moon">A Curious Moon</a>, a wonderfully clever data science “mystery” in PostgreSQL. The setup in the book uses Postgres on bare metal, but I wanted to use Postgres in <a href="https://docs.podman.io/en/latest/">Podman</a>, which is like Docker. One interesting suggestion in the book is to use a Makefile to organize ETL. But this needed a little massaging work with Podman on Fedora, which I want to share here.</p>
<p>Here is my Compose file:</p>Brainstorming BitTorrent Peer Distribution Algorithms
https://moerner.com/posts/brainstorming-peer-distribution-algorithms/
Thu, 12 Dec 2024 12:55:53 -0500https://moerner.com/posts/brainstorming-peer-distribution-algorithms/<p>Recently, I’ve been working on <a href="https://github.com/dmoerner/etracker">etracker</a>, an experimental BitTorrent tracker designed to incentivize healthy client behavior. If you already know about the Bittorrent protocol or about my project, feel free to skip ahead to the actual <a href="#brainstorming">brainstorming</a>.</p>
<h1 id="project-background">Project Background</h1>
<p>BitTorrent is a P2P file transfer protocol, which can use centralized trackers to distribute peer lists to clients, who in turn connect to each other. A collection of clients announcing a particular content infohash is a swarm, which consists of some clients “seeding” content they already have, and other “leeching” content they do not yet have. A tracker must keep track of many clients, each in one or more swarms.</p>Where can you use a PostgreSQL parameter placeholder?
https://moerner.com/posts/postgresql-parameter-placeholders/
Wed, 11 Dec 2024 15:54:46 -0500https://moerner.com/posts/postgresql-parameter-placeholders/<p>This blog post is mostly a note to future me. As I work on my latest Go project
<a href="https://github.com/dmoerner/etracker">etracker</a>, I’ve been using PostgreSQL
for the first time, using the excellent <a href="https://github.com/jackc/pgx">pgx</a>
driver.</p>
<p>When writing dynamic statements, best practice is to use a parameter
placeholder:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#a6e22e">_</span>, <span style="color:#a6e22e">err</span> = <span style="color:#a6e22e">dbpool</span>.<span style="color:#a6e22e">Exec</span>(<span style="color:#a6e22e">context</span>.<span style="color:#a6e22e">Background</span>(),
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">`INSERT INTO peers (peer_id, ip_port, info_hash)
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> VALUES ($1, $2, $3)
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> ON CONFLICT (peer_id, info_hash)
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> DO UPDATE SET ip_port = $2;`</span>,
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">announce</span>.<span style="color:#a6e22e">peer_id</span>, <span style="color:#a6e22e">announce</span>.<span style="color:#a6e22e">ip_port</span>, <span style="color:#a6e22e">announce</span>.<span style="color:#a6e22e">info_hash</span>)
</span></span></code></pre></div><p>Although the pgx driver supports this with variable parameter methods, it’s
just an abstraction on top of the underlying PostgreSQL PREPARE statement:</p>Isn't Go Reflection Slow?
https://moerner.com/posts/isnt-go-reflection-slow/
Tue, 03 Dec 2024 01:02:49 +0000https://moerner.com/posts/isnt-go-reflection-slow/<p>Sharing a short note about something which surprised me today.</p>
<p>I’ve just started working on a self-healing Bittorrent tracker, which uses
tracker-level tools (peer allocation algorithms and error messages) to handle
unhealthy Bittorrent swarms. Ordinarily, such unhealthy swarms (low seeder to
leecher ratio, broken clients, etc.) are either ignored or are handled
outside the protocol using a separate frontend. I want to explore to what
extent they can be handled by the tracker itself, within the constraints of the
Bittorrent protocol. For more information, check out the README on my Github,
although none of this is actually implemented yet:
<a href="https://github.com/dmoerner/etracker">https://github.com/dmoerner/etracker</a>.</p>"For Historical Reasons": Go String and Int Conversion
https://moerner.com/posts/for-historical-reasons-go-string-int-conversion/
Mon, 25 Nov 2024 20:15:44 +0000https://moerner.com/posts/for-historical-reasons-go-string-int-conversion/<p>Damilola Israel Oluwole and I have started learning Go, and decided to play
around with the language to write a toy implementation of <a href="https://en.wikipedia.org/wiki/Run-length_encoding">Run-length
encoding</a>. While working on
this little project we ran into a corner case with Go type conversion, which
turns out to be documented in the Go spec but neither of us were aware of.</p>
<p>Run-length encoding is a simple lossless text compression algorithm which
encodes each sequence of <em>n</em> identical characters <em>c</em> into the substring “cn”.
For example, “Hello” is encoded as “H1e1l2o1”, and “AAAAAAAAAAH” is encoded as
“A10H1”. Obviously in the worst case, a string with no adjacent identical
characters, an RLE encoding of a string of length <em>n</em> requires length <em>2n</em>.
However, in the best case, a string which consists of a single sequence of a
single character, the encoded length scales as the <del>square root</del> log of the
original length. (Thank you to Charles Eckman for the correction!) Our
implementation can be found on Github: <a href="https://github.com/dmoerner/go-rle">https://github.com/dmoerner/go-rle</a>.</p>When Impossible Day Feels Impossible: /tmp Inode Exhaustion
https://moerner.com/posts/impossible-day-inode-exhaustion/
Tue, 19 Nov 2024 21:16:04 +0000https://moerner.com/posts/impossible-day-inode-exhaustion/<p>Impossible Stuff Day is a special sprint at the <a href="https://www.recurse.com/">Recurse Center</a> devoted to working beyond the edge of your abilities. I had an ambitious day planned around <a href="https://mirageos.org">MirageOS</a> microkernels, but I made one critical mistake: I did not test my OCaml development environment with MirageOS.</p>
<p>But that’s no problem: There’s a nice guide to <a href="https://mirage.io/docs/install">install MirageOS</a>, and it looks pretty simple. We can install MirageOS and confirm that the <a href="https://mirage.io/docs/hello-world">Hello World</a> tutorial works. However, it very much does not:</p>Benchmarking a Binary Search Optimization, from 1991 to 2024
https://moerner.com/posts/benchmarking-binary-search/
Fri, 08 Nov 2024 20:00:00 +0100https://moerner.com/posts/benchmarking-binary-search/<p>While reading Chris Okasaki’s <a href="https://www.cambridge.org/core/books/purely-functional-data-structures/0409255DA1B48FA731859AC72E34D494">Purely Functional Data Structures</a> I became aware of an interesting optimization for binary search proposed by Arne Andersson in his 1991 paper, <a href="https://user.it.uu.se/~arneande/ps/searchproc.pdf">A Note on Searching in a Binary Search Tree</a>. This blog post is an investigation of this optimization, including some updated benchmarks in Go and OCaml.</p>
<h1 id="binary-search-algorithms">Binary Search Algorithms</h1>
<p>As a reminder, a binary search tree can be thought of as a data structure consisting of empty leaves and non-empty nodes; each node contains a value and pointers to left and right subtrees. A binary search tree must satisfy the BST Invariant: For any node <em>n</em>, every node in the left subtree of <em>n</em> has a value less than <em>n</em>’s value, and every node in the right subtree of <em>n</em> has a value greater than <em>n</em>’s value. This naturally suggests the following algorithm for binary search, implemented in Go:</p>About
https://moerner.com/about/
Mon, 01 Jan 0001 00:00:00 +0000https://moerner.com/about/<p>Formerly an Assistant Professor of Philosophy at the University of Chicago, now taking a break to explore my passions in tech and coding at <a href="https://www.recurse.com/">The Recurse Center</a>. Here is a <a href="./files/Moerner-CV-2025-03-06.pdf">copy of my CV</a>. Contact me at <a href="mailto:[email protected]">[email protected]</a>.</p>
<p>I also try to host public deployments and demos of many of my personal projects. A non-exhaustive list:</p>
<ul>
<li>etracker, a BitTorrent tracker: <a href="https://etracker.moerner.com/">https://etracker.moerner.com/</a></li>
<li>badbach, a music generator: <a href="https://moerner.com/awful-twinkle.html">https://moerner.com/awful-twinkle.html</a></li>
<li>svelteclick, an idle clicker game: <a href="https://moerner.com/svelteclick/">https://moerner.com/svelteclick/</a></li>
<li>A CIDR calculator: <a href="https://moerner.com/cidr-calc/">https://moerner.com/cidr-calc/</a></li>
</ul>