<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Tom MacWright Micro</title>
  <link href="https://macwright.com/micro/atom.xml" rel="self"/>
  <link href="https://macwright.com"/>
  <updated>2026-05-09T00:00:00Z</updated>
  <subtitle>JavaScript, math, maps, etc</subtitle>
  <icon>https://macwright.com/css/favicon.png</icon>
  <id>https://macwright.com/micro</id>
  <author>
    <name>Tom MacWright</name>
    <email>2025@macwright.com</email>
  </author>
  <entry>
    <title>Interview with Shelf Source</title>
    <link href="https://macwright.com/2026/05/09/shelf-source.html"/>
    <updated>2026-05-09T00:00:00Z</updated>
    <id>https://macwright.com/2026/05/09/shelf-source.html</id>
    <content type="html">&lt;p&gt;&lt;a href=https://zacharykai.net/ &gt;Zachary Kai&lt;/a&gt;, space fantasy writer and cool indie web maker, interviewed me for his &#39;Shelf Source&#39; series about people who like to read books. Read it to learn about some of my favorite books and stuff: &lt;a href=https://roadlessread.com/views/ss-macwright&gt;Shelf Source: Tom MacWright&lt;/a&gt;.&lt;/p&gt;</content>
    <author>
      <name>Tom MacWright</name>
      <uri>https://macwright.com/about/</uri>
    </author>
  </entry>
  <entry>
    <title>Brooklyn Experience Half Marathon</title>
    <link href="https://macwright.com/2026/04/26/brooklyn-experience-half-marathon.html"/>
    <updated>2026-04-26T00:00:00Z</updated>
    <id>https://macwright.com/2026/04/26/brooklyn-experience-half-marathon.html</id>
    <content type="html">&lt;p&gt;This is partly inspired by &lt;a href=https://v5.chriskrycho.com/journal/2026-boston-marathon-race-report/ &gt;Chris Krycho&#39;s report on the 2026 Boston Marathon&lt;/a&gt;. He is &lt;em&gt;proper fast&lt;/em&gt;. He ran the marathon at a 6:32/mi pace. My effort here is far less impressive, but is still a PR and a significant improvement on what I was running before, so I&#39;m writing it up. My running is solidly in the &lt;em&gt;impressive to non-runners, but not competitive&lt;/em&gt; bucket.&lt;/p&gt;&lt;p&gt;Anyway:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Official time: 1:31:21&lt;/li&gt;&lt;li&gt;Pace: 6:59/mi&lt;/li&gt;&lt;li&gt;Overall: 583th&lt;/li&gt;&lt;li&gt;Male 35-39: 71th&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;My previous PR was 1:36:21 , so it was exactly 5 minutes faster. W in the chat.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;How&#39;d it go training-wise?&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;The gist of the training block for this race was simply running more. I skimmed the &lt;a href=https://us.humankinetics.com/products/daniels-running-formula-4th-edition&gt;Daniels&#39; Running Formula&lt;/a&gt; as well, which influenced the kinds of runs I was doing: fitting them into his categories of long, easy, tempo, interval, and repetition. That was very helpful structure.&lt;/p&gt;&lt;p&gt;In previous training blocks, I&#39;ve maintained a rough target of 15 miles a week. This time around I aimed for 20-25, which I think is a lot more appropriate for the kinds of times I&#39;m aiming for. In general I&#39;ve performed better than training would predict by some combination of talent, pain tolerance, and experience.&lt;/p&gt;&lt;p&gt;By dialing back the intensity of my long runs and incorporating a lot of cross-training (40-60mi bike rides), it felt surprisingly sustainable to do the extra miles. That said, I didn&#39;t do a ton of very long runs and never hit the half-marathon distance in training. This is partly the Daniels influence which prioritizes a lot of runs (5-6/week) and so you have a lot of opportunities to get the distance in.&lt;/p&gt;&lt;p&gt;I did hit the usual stumbling blocks: some foot pain that required a trip to the local podiatrist and five days off two weeks before the race.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;How&#39;d the race go?&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;We lucked out with weather - started around 44°F and ended around 55°F. It rained before the race but didn&#39;t rain at all during, and the puddles were minimal.&lt;/p&gt;&lt;p&gt;I started in Wave 1 Corral A like last time, but instead of hanging way to the back, tried to find the spot where I&#39;d be running a goal space - vaguely &quot;low 1:30s.&quot; My previous PR was 1:36:21 but with more training and the confidence that I &lt;em&gt;should&lt;/em&gt; be running faster, I was thinking that 1:32 or something would be nice. And a &quot;7 minute mile&quot; is mentally comfortable for me, so targeting that felt both feasible and optimistic.&lt;/p&gt;&lt;p&gt;Starting too far back has been a trap in the past: psychologically, it&#39;s nicer to pass people than to be passed, but it means a ton of weaving and dodging early in the race which is a lot of energy and kind of risky. Lesson learned: start at the roughly correct spot!&lt;/p&gt;&lt;p&gt;This course is kind of brutal, basically nice and downhill for the first half, then it hits south Brooklyn&#39;s most notorious hill in Prospect Park at the end. The hill is not a huge deal at the start of a 5k but after 11 hard miles, it&#39;s tough. So, early on my pace was hovering around 6:45 but on the hilly segments it hit 7:19.&lt;/p&gt;&lt;p&gt;The stretch out to Eastern Parkway especially feels interminable, right at the middle-end of the race and with a gradual hill. That&#39;s where my mental game fell off a bit, but it wasn&#39;t a catastrophe and I was able to bring back the pace later on.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Lessons learned&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;As you can tell by my time, I am not a professional runner, and not in the front of the pack, but, ya know, not bad for an old guy. I&#39;ve had a bunch of basic realizations and improvements running-wise:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Just give in and get some &lt;a href=https://en.wikipedia.org/wiki/Super_shoes&gt;super shoes&lt;/a&gt;. I run in &lt;a href=https://runrepeat.com/brooks-hyperion-max-2&gt;Brooks Hyperion Max 2&lt;/a&gt;, which are kind of &quot;stability super-trainers&quot; but nevertheless have a nylon plate. They make a difference.&lt;/li&gt;&lt;li&gt;Fuel! Consume carbs. For a half-marathon, it&#39;s not as big a deal as for a full because the folk wisdom is that you need additional carbs after about 45 minutes of exertion. So halfway through I slugged down a Maurten 100 gel. Before the race in the early morning, overnight oats. Some caffeine too, which hits me extra-hard because my life is otherwise caffeine-free.&lt;/li&gt;&lt;li&gt;&lt;em&gt;Note&lt;/em&gt;: not really carb-loading! Pulling from &lt;a href=https://www.bakline.nyc/blogs/legwork/07-fuel-smarter-understanding-how-nutrition-works-in-training-and-racing&gt;Bakline&#39;s episode about fueling&lt;/a&gt;, it kind of only works if you do huge quantities, barely works for women, and has to be a multi-day affair. Plus, glycogen goes along with water so it increases your weight a bit. Overall I&#39;m not compelled to focus on it, but at the same time I wouldn&#39;t be surprised if I&#39;m totally wrong about this and swear by it in the future.&lt;/li&gt;&lt;li&gt;Warm up a lot. Real runners are doing 3 miles of warm-up before their races. The setup for this race makes pre-race warmup kind of cramped, jogging in a tiny lane next to the corrals, but still - do it. It works.&lt;/li&gt;&lt;li&gt;&lt;em&gt;Controversial take&lt;/em&gt;: eating a lot more protein has helped me overall. Big asterisk: I&#39;m a strict vegan and have been for a long time so my intake is probably low unless I really focus on it. But yeah - spending a little time to measure what I&#39;m actually getting versus what I&#39;m aiming for showed a wide gulf and I&#39;ve found that I recover a bit faster with more, around 100g/day at least, inconsistently hit.&lt;/li&gt;&lt;li&gt;The self-help stuff in the &lt;a href=https://macwright.com/2025/07/24/the-confident-mind-works-for-running&gt;Confident Mind&lt;/a&gt; helps me a lot: in particular, trying to appreciate nervousness as a positive. I&#39;ve also been enjoying the mantras of &quot;slow is smooth and smooth is fast,&quot; and &quot;relax and go faster.&quot; The mental stuff is invariably goofy to write about but it&#39;s real, it&#39;s a big part of the challenge.&lt;/li&gt;&lt;li&gt;Via &lt;a href=https://www.youtube.com/@PhilyBowden&gt;Phily Bowden&lt;/a&gt;, who I really admire for being very level-headed for an absolutely insane endurance athlete, I care about getting &lt;a href=https://www.youtube.com/shorts/Uy-Y8THXeCA&gt;decent sleep the night &lt;em&gt;before&lt;/em&gt; the night before the race&lt;/a&gt;. Like any brutally early wake-up for a thing I&#39;m nervous about - 5am in this case - I will try my hardest to sleep well the night before but realistically it&#39;s usually terrible. But the night &lt;em&gt;before&lt;/em&gt; that, pretty good, and it evens out to be fine! I did totally biff it on &lt;em&gt;fueling strategies you&#39;ve already tried&lt;/em&gt; because I had never had that kind of Maurten gel before, but it turned out fine.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;I&#39;ve been running competitively on-and-off since high school and still find stuff like this which seems basic that makes everything better. It&#39;s fun! My goal is just to get another PR at some point, and to be strong in this year&#39;s 5k series.&lt;/p&gt;</content>
    <author>
      <name>Tom MacWright</name>
      <uri>https://macwright.com/about/</uri>
    </author>
  </entry>
  <entry>
    <title>How to contribute to open source</title>
    <link href="https://macwright.com/2026/03/26/oss-contributions.html"/>
    <updated>2026-03-26T00:00:00Z</updated>
    <id>https://macwright.com/2026/03/26/oss-contributions.html</id>
    <content type="html">&lt;p&gt;&lt;a href=https://en.wikipedia.org/wiki/Inveniam_viam&gt;&lt;strong&gt;&lt;em&gt;Aut inveniam viam aut faciam&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt;: I shall either find a way or make one.&lt;/p&gt;&lt;p&gt;Another ranking of people on GitHub dropped, and for the odd metric of &#39;stars from repos where a developer has merged PRs&#39; I rank &lt;a href=https://gitranks.com/country/United%20States/contributions/1&gt;third, as of this writing, in the United States&lt;/a&gt;. Like all rankings, it&#39;s mostly lies, statistics, coincidence, and a reflection of GitHub&#39;s top-heavy usage.&lt;/p&gt;&lt;p&gt;But it&#39;s a nice metric because that is what I&#39;ve focused on for the last few years: instead of trying to create some popular new framework, I&#39;ve been trying to contribute more to existing projects.&lt;/p&gt;&lt;p&gt;So, free advice to the new open source contributor: &lt;strong&gt;when you hit a bug or a limitation in some project, file an issue and volunteer to fix it if you think you can.&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;You&#39;ll learn a lot from working in lots of projects - how do they set up tests and linter rules, what are their code styles, etc?&lt;/p&gt;&lt;p&gt;Don&#39;t use LLMs to do this. Using an LLM especially to write the PR description or anything like that cheats both you and them: you&#39;re missing out on the learning and experience, and they will become wary of automated contributions. Don&#39;t be lazy.&lt;/p&gt;&lt;p&gt;Is this still an effective way to stay in open source and do good: I think so. So, when you hit a bug, instead of doing a workaround, a patch, or switching tools, try and make a way by fixing it. Treat all bugs like your responsibility because you&#39;re an active community member.&lt;/p&gt;</content>
    <author>
      <name>Tom MacWright</name>
      <uri>https://macwright.com/about/</uri>
    </author>
  </entry>
  <entry>
    <title>Effect notes: PRs, progress, and joys</title>
    <link href="https://macwright.com/2026/03/18/effect-devlog.html"/>
    <updated>2026-03-18T00:00:00Z</updated>
    <id>https://macwright.com/2026/03/18/effect-devlog.html</id>
    <content type="html">&lt;p&gt;It&#39;s been three months since the &lt;a href=https://macwright.com/2026/01/06/effect-trpc&gt;last Effect devlog&lt;/a&gt; and I&#39;m still incrementally adopting Effect in &lt;a href=https://www.val.town/ &gt;Val Town&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Things are going well but not spectacularly. My approval rating is a solid &#39;B&#39; right now.&lt;/p&gt;&lt;p&gt;I&#39;m far from the only or most important Effect user, but I&#39;m bummed that a majority of my annoyances from October &amp; November of 2025 are outstanding: &lt;a href=&quot;https://github.com/Effect-TS/effect/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20author%3Atmcw&quot;&gt;a drizzle bug, a Cron bug, a vitest incompatibility, documentation improvements&lt;/a&gt; are all stalled. I write a brief fork that implemented Cron iteration in the reverse direction, Cron.prev, and &lt;a href=https://github.com/Effect-TS/effect/pull/5786&gt;Kit finished and merged it&lt;/a&gt;, but that took three months to get merged and has been stalled without release for another three months. The documentation for &lt;a href=https://github.com/Effect-TS/effect/issues/5860&gt;Effect.fn.Return&lt;/a&gt; got &lt;a href=https://github.com/Effect-TS/website/pull/1258&gt;written&lt;/a&gt; by a core team member but that PR got closed without merging. I tried writing some &lt;a href=https://github.com/Effect-TS/website/pull/1286&gt;docs for stream interop&lt;/a&gt; which never got merged or reviewed. I got a &lt;a href=https://github.com/Effect-TS/website/pull/1281&gt;minor documentation improvement about generators&lt;/a&gt; merged with explicit coordination from the Effect team.&lt;/p&gt;&lt;p&gt;None of that stuff is a dealbreaker and I know from privately chatting with the Effect team that they prefer PRs to be coordinated because there&#39;s so much in flight and so much to understand. I think the current scenario, in which people don&#39;t know that because it isn&#39;t written anywhere, and put in effort into PRs that stall, isn&#39;t very good for community vibes.&lt;/p&gt;&lt;p&gt;Probably some of this delay is because &lt;a href=https://effect.website/blog/releases/effect/40-beta/ &gt;Effect v4&lt;/a&gt; has been a major focus of the Effectful team. v4 does seem exciting: a smaller, more unified, faster module is great news. We haven&#39;t migrated yet because we use some of the deprecated APIs, like Runtime, and I try to avoid using beta releases in general in production software.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Obligatory LLM discourse&lt;/strong&gt;: my usual AI tool, Claude Code with Opus 4.6, is decent at using Effect but stumbles in the same places that the documentation is lacking, like that &lt;code&gt;Effect.fn.Return&lt;/code&gt; type - it doesn&#39;t like to use that. I&#39;ve used the LLM for roughly half of the refactors to Effect, but recently I&#39;ve been finding it &lt;em&gt;slower&lt;/em&gt; than doing things manually along with &lt;a href=https://ast-grep.github.io/ &gt;ast-grep&lt;/a&gt;. There are faster LLMs, but I&#39;ve found quality and speed to be strongly inversely correlated, and fast models like Minimax tend to get themselves into corners faster.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Effect joys&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;The &lt;a href=https://effect-ts.github.io/effect/effect/Duration.ts.html&gt;Duration&lt;/a&gt; and &lt;a href=https://effect-ts.github.io/effect/effect/DateTime.ts.html&gt;DateTime&lt;/a&gt; modules&lt;/strong&gt; have been really nice for describing times and limits in the application. Soon, &lt;a href=https://bloomberg.github.io/js-blog/post/temporal/ &gt;Duration&lt;/a&gt; will do a lot of the same things that those Effect utilities can do, but it&#39;s nice to have them a little early.&lt;/p&gt;&lt;p&gt;We have a lot of Drizzle queries that try to fetch one record, so &lt;code&gt;.limit(1)&lt;/code&gt; and then &lt;code&gt;.pipe(Effect.map(r =&gt; r.at(0))&lt;/code&gt; and I recently created a nice little dual method as a helper. This was not especially easy to write!&lt;/p&gt;&lt;pre class=language-ts&gt;&lt;code class=language-ts&gt;&lt;span class=&quot;token comment&quot;&gt;/**
 * For the many many database queries where we want to take the first
 * element and return NotFoundError if it is not found.
 *
 * @example
 * db.query(...)
 *  .pipe(takeFirst(&#39;Project not found&#39;));
 */&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; takeFirst &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; dual&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    that&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Error&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Requirements&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    self&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Effect&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Effect&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Error&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Requirements&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; Effect&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Effect&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;NonNullable&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Error &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; NotFoundError&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Requirements&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Error&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Requirements&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    self&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Effect&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Effect&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Error&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Requirements&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    that&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; Effect&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Effect&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;NonNullable&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Error &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; NotFoundError&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Requirements&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; message &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Not found&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; Effect&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;flatMap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; first &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;first &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;undefined&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;&amp;&lt;/span&gt; first &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; Effect&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;succeed&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;first&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; Effect&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fail&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;NotFoundError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; message &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The more methods get ported to Effect the more I can use &lt;code&gt;Effect.gen&lt;/code&gt; or &lt;code&gt;Effect.fn&lt;/code&gt; to combine them, which is nice - feels like a tipping point in many ways. This is something that I have noticed that LLMs are hesitant to do: they&#39;re pretty single-minded when working on a task and will happy let two &lt;code&gt;Effect.runPromise&lt;/code&gt; statements sit on consecutive lines when they could be combined.&lt;/p&gt;&lt;p&gt;The friction of Effect at boundaries is still there: Val Town uses Fastify, tRPC, React Router, etc., and we have a lot of existing code, so we aren&#39;t achieving the brilliant purity that Effect docs insist upon. Tests still don&#39;t use &lt;code&gt;@effect/vitest&lt;/code&gt; because of its missing feature and lack of &lt;a href=https://github.com/Effect-TS/effect/pull/6012&gt;vitest 4 support&lt;/a&gt;, so there&#39;s a lot of unwrapping Effects there too.&lt;/p&gt;&lt;p&gt;Overall: it rolls on, and I&#39;m starting to slowly introduce Effect to the tough core of the application, the part that actually runs vals, and has many complex asynchronous flows. That is going fairly well: the last push was to replace our homemade implementation of &lt;a href=https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/withResolvers&gt;Promise.withResolvers()&lt;/a&gt; that also had a &lt;a href=https://bun.com/reference/bun/peek&gt;Bun-inspired&lt;/a&gt; &lt;code&gt;.peek()&lt;/code&gt; method to synchronously get a Promise value if there is one. Effect&#39;s &lt;a href=https://effect-ts.github.io/effect/effect/Deferred.ts.html&gt;Deferred&lt;/a&gt; was a drop-in replacement for that problem area.&lt;/p&gt;</content>
    <author>
      <name>Tom MacWright</name>
      <uri>https://macwright.com/about/</uri>
    </author>
  </entry>
  <entry>
    <title>Placemark &amp; OSS Changelog</title>
    <link href="https://macwright.com/2026/03/15/oss-changelog.html"/>
    <updated>2026-03-15T00:00:00Z</updated>
    <id>https://macwright.com/2026/03/15/oss-changelog.html</id>
    <content type="html">&lt;p&gt;What&#39;s new with &lt;a href=https://www.placemark.io/ &gt;Placemark&lt;/a&gt; and open source recently:&lt;/p&gt;&lt;h4 id=placemark&gt;&lt;a href=https://www.placemark.io/ &gt;Placemark&lt;/a&gt;&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;The features table in Placemark now lets you sort by different columns in ascending or descending order.&lt;/li&gt;&lt;li&gt;The features table had resizable columns, which broke. I fixed that, and you can resize columns again.&lt;/li&gt;&lt;li&gt;I&#39;ve created a &lt;a href=https://placemark.github.io/docs/ &gt;documentation website&lt;/a&gt; for Placemark, recreating some of what existed with Webflow but with &lt;a href=https://starlight.astro.build/ &gt;Astro Starlight&lt;/a&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;h4 id=tokml&gt;&lt;a href=https://github.com/placemark/tokml&gt;tokml&lt;/a&gt;&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;I&#39;ve adopted &lt;a href=https://github.com/changesets/changesets&gt;changesets&lt;/a&gt; for release automation, like I&#39;ve been doing on all my projects. The combination of changesets with a release action that publishes to NPM using OIDC is really nice, and makes maintenance and updates easier.&lt;/li&gt;&lt;li&gt;I dropped the UMD build, making the NPM package roughly 30% smaller.&lt;/li&gt;&lt;/ul&gt;&lt;h4 id=simple-statistics&gt;&lt;a href=https://github.com/simple-statistics/simple-statistics&gt;simple-statistics&lt;/a&gt;&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Quantile computations now &lt;a href=https://github.com/simple-statistics/simple-statistics/pull/783&gt;match what R does&lt;/a&gt;. Thanks &lt;a href=https://github.com/zhengshui&gt;zhengshui&lt;/a&gt; for the fix.&lt;/li&gt;&lt;li&gt;Also, adopted changesets, like the rest of the projects.&lt;/li&gt;&lt;/ul&gt;&lt;hr&gt;&lt;p&gt;I&#39;ve been trying to &#39;fix what I find&#39; in projects - small fixes in stuff like &lt;a href=https://github.com/fastify/fastify-sensible/pull/215&gt;fastify-sensible&lt;/a&gt; and &lt;a href=https://github.com/noelforte/eleventy-plugin-vento/pull/423&gt;11ty-vento&lt;/a&gt;. Contributing to existing projects in small ways feels good, I think it would be nice if the average longevity of projects were higher, and small contributions are what keep me interested in my older projects, too.&lt;/p&gt;</content>
    <author>
      <name>Tom MacWright</name>
      <uri>https://macwright.com/about/</uri>
    </author>
  </entry>
  <entry>
    <title>ROOTS - Return Old Online Things to your own Site</title>
    <link href="https://macwright.com/2026/03/12/roots.html"/>
    <updated>2026-03-12T00:00:00Z</updated>
    <id>https://macwright.com/2026/03/12/roots.html</id>
    <content type="html">&lt;p&gt;Lisa Charlotte Muth &lt;a href=https://lisacharlottemuth.com/bringing-everything-back-to-my-website&gt;just coined ROOTS&lt;/a&gt;: &quot;Return Old Online Things to your own Site.&quot; She&#39;s collecting all her old content and putting it all on her site.&lt;/p&gt;&lt;p&gt;Good idea! I share all the sentiments in that post, and hope to do the same, and also do some manual review of my old posts to fix some bitrotted iframe embeds. Inlining &lt;em&gt;everything&lt;/em&gt; would be really nice - I want some self-hostable local playground element for interactive code examples.&lt;/p&gt;</content>
    <author>
      <name>Tom MacWright</name>
      <uri>https://macwright.com/about/</uri>
    </author>
  </entry>
  <entry>
    <title>Reactionary AI Centrism</title>
    <link href="https://macwright.com/2026/02/12/reactionary-ai-centrism.html"/>
    <updated>2026-02-12T00:00:00Z</updated>
    <id>https://macwright.com/2026/02/12/reactionary-ai-centrism.html</id>
    <content type="html">&lt;p&gt;The current wave of AI discourse is what I&#39;d call &quot;Radical AI Centrism.&quot; The gist is:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&quot;Good&quot; can mean &quot;morally or ethically good&quot; or &quot;effective and able to do what it says it does.&quot;&lt;/li&gt;&lt;li&gt;Many critics of AI have made arguments about &lt;em&gt;both&lt;/em&gt;: that AI is both a &#39;glorified spellcheck that doesn&#39;t work very well&#39; (not good at what it does) and &#39;increasing electricity prices, destroying jobs, etc.&#39; (not good in a moral sense)&lt;/li&gt;&lt;li&gt;In the last five months or so, AI models have gotten better at what they do, according to most quantitative and qualitative measures.&lt;/li&gt;&lt;li&gt;This has made some past critiques of AI inaccurate, and some critics have been slow to adjust their rhetoric for the new reality of AI models that &lt;em&gt;can&lt;/em&gt; write passable code.&lt;/li&gt;&lt;li&gt;Therefore, a new space for criticism has opened up: a &quot;backlash to the backlash&quot; in which AI critics are critiqued for insufficiently appreciating how AI is &#39;good at what it does.&#39;&lt;/li&gt;&lt;li&gt;This realm of argument is useful strategically because:&lt;ul&gt;&lt;li&gt;It is narrowly true.&lt;/li&gt;&lt;li&gt;It satisfies the &lt;a href=https://www.volts.wtf/p/all-about-reactionary-centrism&gt;reactionary centrist&lt;/a&gt; impulse to avoid straightforward descriptions of &#39;bad things&#39; and to instead find complex, sophisticated alternative takes.&lt;/li&gt;&lt;li&gt;For many people, it&#39;s more fun to argue with people in their own circle than to critique large corporations.&lt;/li&gt;&lt;li&gt;It shifts the argument away from the moral, ethical, and political realm (moral good) and toward the realm of technology and effectiveness (good at what it does).&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;</content>
    <author>
      <name>Tom MacWright</name>
      <uri>https://macwright.com/about/</uri>
    </author>
  </entry>
  <entry>
    <title>Media diet</title>
    <link href="https://macwright.com/2026/02/05/media-diet.html"/>
    <updated>2026-02-05T00:00:00Z</updated>
    <id>https://macwright.com/2026/02/05/media-diet.html</id>
    <content type="html">&lt;p&gt;I&#39;ve been tweaking my media diet recently for three goals:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;I don&#39;t want to be exposed to advertising.&lt;/li&gt;&lt;li&gt;I&#39;d like to avoid some big companies.&lt;/li&gt;&lt;li&gt;I want more honest news.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;I already pay for a few big newspapers and use &lt;a href=https://ublockorigin.com/ &gt;uBlock&lt;/a&gt; with my browser &lt;a href=https://github.com/imputnet/helium&gt;Helium&lt;/a&gt;, but I still get ads on the mobile versions of news apps like the New York Times and Bloomberg. Considering how much these subscriptions cost, I think that&#39;s pretty silly.&lt;/p&gt;&lt;p&gt;And it&#39;s very clear that those papers haven&#39;t been writing honest coverage of some important world events.&lt;/p&gt;&lt;p&gt;So, here&#39;s what I&#39;m listening/reading/watching more often:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=https://plus.npr.org/ &gt;NPR Plus&lt;/a&gt; is $96/yr and listening to 1A and Consider This cover most of my audio news needs.&lt;/li&gt;&lt;li&gt;&lt;a href=https://www.theguardian.com/us&gt;The Guardian&lt;/a&gt; is $90/yr and is ad-free for subscribers.&lt;/li&gt;&lt;li&gt;&lt;a href=https://newsasfacts.com/ &gt;News As Facts&lt;/a&gt; is good for global headlines and exclusively links to Wikipedia for terms, which is where I go anyway.&lt;/li&gt;&lt;li&gt;&lt;a href=https://nebula.tv/featured&gt;Nebula&lt;/a&gt; is not quite a YouTube alternative, but it has a few major creators who I follow, like &lt;a href=https://nebula.tv/adam-neely&gt;Adam Neely&lt;/a&gt;, and lets me watch their videos without ads for a relatively cheap subscription ($30/yr).&lt;/li&gt;&lt;/ul&gt;</content>
    <author>
      <name>Tom MacWright</name>
      <uri>https://macwright.com/about/</uri>
    </author>
  </entry>
  <entry>
    <title>What I haven&#39;t figured out</title>
    <link href="https://macwright.com/2026/01/29/what-i-havent-figured-out.html"/>
    <updated>2026-01-29T00:00:00Z</updated>
    <id>https://macwright.com/2026/01/29/what-i-havent-figured-out.html</id>
    <content type="html">&lt;p&gt;Some technical things that I feel like I&#39;ve never really figured out, that I&#39;m trying to figure out:&lt;/p&gt;&lt;h3 id=how-much-should-applications-fail-fast-and-how-much-should-they-tolerate-failure&gt;How much should applications fail-fast and how much should they tolerate failure?&lt;/h3&gt;&lt;p&gt;Failing fast feels right and I&#39;ve implemented it in a lot of places - using &lt;a href=https://github.com/KATT/envsafe&gt;envsafe&lt;/a&gt; or something similar is a necessity on any project I work on, for example: if an application isn&#39;t properly configured, it should fail at startup instead of limping along.&lt;/p&gt;&lt;p&gt;But should applications tolerate failed database queries in an elegant way? What about failed external services?&lt;/p&gt;&lt;p&gt;I think one clear line is that an application shouldn&#39;t allow &lt;em&gt;internal inconsistency&lt;/em&gt;. For example, if you have some function that&#39;s being called with an incorrect argument type, you update the callers instead of making the function more flexible. This probably isn&#39;t the case when companies grow in size because eventually you can&#39;t tell a whole team to just update all their code when an API changes.&lt;/p&gt;&lt;p&gt;But the line keeps moving: in particular, I think the last two years has shown me that it&#39;s useful to have a system that can fail partially, and that every single external service will fail at some point, and you should have a plan for those things, whether it&#39;s tolerating failure or doing retries.&lt;/p&gt;&lt;h3 id=how-should-logs-work&gt;How should logs work?&lt;/h3&gt;&lt;p&gt;Every application that I&#39;ve worked on eventually just generates several &#39;flavors&#39; of log messages out of stdout and stderr and logs stop being useful because they&#39;re filled with &#39;junk&#39; like request logs.&lt;/p&gt;&lt;p&gt;I&#39;ve tried structured JSON logs with &lt;a href=https://github.com/pinojs/pino&gt;pino&lt;/a&gt;, tried tslog, Betterstack, Axiom, and never got it. We&#39;ve never had a team member that really got value out of logs. I&#39;ve never really gotten value out of logs. I often wonder if servers should emit logs at all, and instead we should just do telemetry and metrics?&lt;/p&gt;&lt;hr&gt;&lt;p&gt;Update! &lt;a href=https://charlesharri.es/stream/how-to-read-and-write-logs&gt;Charles Harries responded with &#39;How to read and write application logs&#39;&lt;/a&gt;. Also: &lt;a href=https://loggingsucks.com/ &gt;loggingsucks.com&lt;/a&gt;.&lt;/p&gt;</content>
    <author>
      <name>Tom MacWright</name>
      <uri>https://macwright.com/about/</uri>
    </author>
  </entry>
  <entry>
    <title>Changing my mind</title>
    <link href="https://macwright.com/2026/01/13/mind-changing.html"/>
    <updated>2026-01-13T00:00:00Z</updated>
    <id>https://macwright.com/2026/01/13/mind-changing.html</id>
    <content type="html">&lt;p&gt;I&#39;ve changed my mind about a lot of stuff recently:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;I have been using Claude Code a bunch. I feel deeply conflicted about it: it isn&#39;t satisfying to use, it has all these ethical problems, but it works really well. Only the highest-level models work well for writing code: &lt;a href=https://opencode.ai/ &gt;opencode&lt;/a&gt; is much nicer and less glitchy than Claude Code, but it uses Grok by default which is a lot worse. I&#39;m only using it on work stuff. Partly the watershed moment was the Claude Code form factor: in-editor AI suggestions are annoying and disruptive, whereas the CLI editor-lite direction is a lot better. &lt;em&gt;Note: please don&#39;t recommend another coding CLI to me, I&#39;ve seen them all and despite using them, I am existentially tired by the LLM discourse.&lt;/em&gt;&lt;/li&gt;&lt;li&gt;I switched from Alfred to &lt;a href=https://www.raycast.com/ &gt;Raycast&lt;/a&gt;. The biggest reason was that I want to run less software, and Raycast replaces &lt;a href=https://www.stayinsession.com/ &gt;Session&lt;/a&gt; and &lt;a href=https://rectangleapp.com/ &gt;Rectangle&lt;/a&gt; for me. I&#39;ve also been impressed with &#39;Raycast-the-platform&#39; - its &lt;a href=https://www.raycast.com/samuelkraft/workouts&gt;Strava&lt;/a&gt; integration shows the last 4 weeks&#39; mileage in my menu bar. Not tied directly to Raycast as a quick switcher, but nifty. To rewind, every time I tried Raycast in the past I was frustrated about its &#39;quick switching&#39; abilities - typing a few characters of an application&#39;s name would be less reliable than with Alfred, presumably because Raycast was doing fancier string matching. But now I use &lt;a href=https://github.com/mikker/LeaderKey&gt;LeaderKey&lt;/a&gt; for switching and that&#39;s not an issue.&lt;/li&gt;&lt;li&gt;I&#39;ve been adopting &lt;a href=https://effect.website/ &gt;Effect&lt;/a&gt; at work, after swearing it off for a year. I think my qualms with it are still pretty true (the team does not care enough about documentation and it can be difficult to use) but there are also a lot of benefits - a big ecosystem that&#39;s pretty mature, and the opportunity to remove other NPM modules because Effect includes nice implementations of things like DateTime, Duration, and Cron types.&lt;/li&gt;&lt;li&gt;I switched this blog to use &lt;a href=https://www.11ty.dev/ &gt;11ty&lt;/a&gt; after being a holdout using Jekyll for roughly 14 years. Jekyll kept encountering problems building the site. 11ty is fine and the migration was mostly smooth. I still have some incremental work to do with it. The site builds slightly faster but that wasn&#39;t a real motivation for the switch, it was more about switching to a static site builder that is actively maintained. Plus I had a bunch of &lt;a href=https://macwright.com/2016/05/03/the-featherweight-website&gt;post-optimization&lt;/a&gt; involved with the site that was already written in JavaScript, and using 11ty let me integrate that with the site build process.&lt;/li&gt;&lt;/ul&gt;</content>
    <author>
      <name>Tom MacWright</name>
      <uri>https://macwright.com/about/</uri>
    </author>
  </entry>
</feed>
