<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.2.2">Jekyll</generator><link href="https://laughingmeme.org/feed.xml" rel="self" type="application/atom+xml" /><link href="https://laughingmeme.org/" rel="alternate" type="text/html" /><updated>2026-04-23T20:47:39+00:00</updated><id>https://laughingmeme.org/feed.xml</id><title type="html">Kellan Elliott-McCrea: Blog</title><subtitle>A personal blog of Kellan Elliott-McCrea. I don&apos;t really know what a &quot;laughing meme&quot; is. It sounded cool in 1999.</subtitle><author><name>Kellan Elliott-McCrea</name></author><entry><title type="html">Coding on Vacation</title><link href="https://laughingmeme.org/2026/03/24/coding-and-blogging-on-vacation.html" rel="alternate" type="text/html" title="Coding on Vacation" /><published>2026-03-24T14:37:37+00:00</published><updated>2026-03-24T14:37:37+00:00</updated><id>https://laughingmeme.org/2026/03/24/coding-and-blogging-on-vacation</id><content type="html" xml:base="https://laughingmeme.org/2026/03/24/coding-and-blogging-on-vacation.html"><![CDATA[<p>The question I asked myself (and the private Slack channel): is ensuring that I have a phone based approach to agentic coding while I’m on vacation healthy because I’m ensuring that I’m not on the computer, a phone is less instrusive, or extremely unhealthy, because you know (gestures broadly) the whole being on vacation thing.</p>

<p>First attempt was VPS + Tailscale + tmux + Moshi + Claude Code Remote Control.</p>

<p>Clunky. SSH on the phone is never going to be fun. Claude Code /rc is very much a 1.0 product (sorry Andy!), I didn’t have a good pipeline to serving the things I was building, and when I put CC on yolo’ing some network configurations I lost access to the VPS, and breaking back in is a post vacation activity.</p>

<p>Second was using exe.dev, and in particular their agent Shelley. (Frankenstein reference?)</p>

<p>It’s been a ton of fun, works great on mobile web. Comes with a sophisticated set of tools around coding, researching, brainstorming, testing in browsers (including mobile emulation, accessibility and performance), visual QA, etc. As someone who has been playing with souping up harnesses recently this feels like a nice one. It uses sub-agents by default, and async web UI so it’s all background work by default. Has a built in code to publish pipeline. I’m having a lot of fun with it. My only caveat is I’m not sure how much it’s going to cost, I can’t really reason about that bit yet.</p>

<p>Started building a fun toy while we waited on the tarmac at JFK: a <a href="https://garden.exe.xyz/">garden of generative coding techniques</a> (in an older sense of the word).</p>

<p>And then I had it check out my blog repo, new my new post script, and I transcribed this blog post while getting a break from the sun. Fun.</p>]]></content><author><name>Kellan Elliott-McCrea</name></author><summary type="html"><![CDATA[The question I asked myself (and the private Slack channel): is ensuring that I have a phone based approach to agentic coding while I’m on vacation healthy because I’m ensuring that I’m not on the computer, a phone is less instrusive, or extremely unhealthy, because you know (gestures broadly) the whole being on vacation thing.]]></summary></entry><entry><title type="html">Hack: claude -p</title><link href="https://laughingmeme.org/2026/03/20/hack-claude-p.html" rel="alternate" type="text/html" title="Hack: claude -p" /><published>2026-03-20T11:49:53+00:00</published><updated>2026-03-20T11:49:53+00:00</updated><id>https://laughingmeme.org/2026/03/20/hack-claude-p</id><content type="html" xml:base="https://laughingmeme.org/2026/03/20/hack-claude-p.html"><![CDATA[<p><code class="language-plaintext highlighter-rouge">claude -p</code> is a quick hack that I find myself using more.</p>

<p>Calling one of the various LLM APIs is easy. But requires key management. For me on a personal project that’s no big deal. In a work context it’s less trivial. But I’m working in <code class="language-plaintext highlighter-rouge">claude</code>, which means I have a tool talking to a LLM API running already all the time, that already has not only an API key, but also an allocated budget that is being managed around making me more productive. Much easier if all my LLM based productivity is spend hits a single line item.</p>

<p>E.g. a quick script to classify Github PRs has a section like:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="k">return</span> <span class="sa">f</span><span class="s">"""You are classifying GitHub pull requests for an engineering team.

  PRODUCT AREAS (choose exactly one per PR):
  </span><span class="si">{</span><span class="n">area_lines</span><span class="si">}</span><span class="s">

  WORK TYPES (choose exactly one per PR):
  </span><span class="si">{</span><span class="n">work_type_lines</span><span class="si">}</span><span class="s">

  For each PR, return a JSON array with these fields:
  - pr_id, product_area, work_type, confidence, keywords

  Return ONLY the JSON array. No prose, no markdown fences.

  PULL REQUESTS:
  </span><span class="si">{</span><span class="n">prs_text</span><span class="si">}</span><span class="s">"""</span>
</code></pre></div></div>

<p>And the call itself:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="k">def</span> <span class="nf">_call_claude</span><span class="p">(</span><span class="n">prompt</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span> <span class="o">|</span> <span class="bp">None</span><span class="p">:</span>
      <span class="k">try</span><span class="p">:</span>
          <span class="n">result</span> <span class="o">=</span> <span class="n">subprocess</span><span class="p">.</span><span class="n">run</span><span class="p">(</span>
              <span class="p">[</span><span class="s">'claude'</span><span class="p">,</span> <span class="s">'-p'</span><span class="p">,</span> <span class="s">'--output-format'</span><span class="p">,</span> <span class="s">'text'</span><span class="p">],</span>
              <span class="nb">input</span><span class="o">=</span><span class="n">prompt</span><span class="p">,</span>
              <span class="n">capture_output</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span>
              <span class="n">text</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span>
              <span class="n">timeout</span><span class="o">=</span><span class="mi">300</span><span class="p">,</span>
          <span class="p">)</span>
          <span class="k">return</span> <span class="n">result</span><span class="p">.</span><span class="n">stdout</span><span class="p">.</span><span class="n">strip</span><span class="p">()</span> <span class="k">if</span> <span class="n">result</span><span class="p">.</span><span class="n">returncode</span> <span class="o">==</span> <span class="mi">0</span> <span class="k">else</span> <span class="bp">None</span>
      <span class="k">except</span> <span class="p">(</span><span class="n">subprocess</span><span class="p">.</span><span class="n">TimeoutExpired</span><span class="p">,</span> <span class="nb">FileNotFoundError</span><span class="p">):</span>
          <span class="k">return</span> <span class="bp">None</span>

</code></pre></div></div>
<p>Probably this is what the agent sdk is for? This worked.</p>]]></content><author><name>Kellan Elliott-McCrea</name></author><summary type="html"><![CDATA[claude -p is a quick hack that I find myself using more.]]></summary></entry><entry><title type="html">Timberborn 1.0, HTTP Lever, and Claude Code</title><link href="https://laughingmeme.org/2026/03/15/timberborn-1-0-http-lever-and-claude-code.html" rel="alternate" type="text/html" title="Timberborn 1.0, HTTP Lever, and Claude Code" /><published>2026-03-15T18:27:49+00:00</published><updated>2026-03-15T18:27:49+00:00</updated><id>https://laughingmeme.org/2026/03/15/timberborn-1-0-http-lever-and-claude-code</id><content type="html" xml:base="https://laughingmeme.org/2026/03/15/timberborn-1-0-http-lever-and-claude-code.html"><![CDATA[<p>Timberborn is very much my kind of game. Complex, cozy, climate change, water system design, beavers. (My friend <a href="https://schuyler.info/">Schuyler</a> pointed out at one point that my preferred genre of game is “management sims”, and that perhaps I was little over rotated on my day job.)</p>

<p>I played it a <em>ton</em> during Early Access, and it’s great to see it finally reach 1.0. I highly recommend it.</p>

<p>One of the things they added in 1.0 is a full automation system. <em>Finally</em>. (Though I’ll be honest I was mostly okay with Sluice Gate there by the end at least for basic reservoir management). But now you can get serious! Automations can work on water depth, flow, contamination, the weather, resource counts, population counts, etc. There is memory, and a full complement of logic gates for wiring up your very own beaver powered Turing machine.</p>

<p>But one of the things they <em>also</em> added to 1.0 is the ability to have the game call arbitrary HTTP endpoints, and vice versa.</p>

<p>If you build an “HTTP Lever”, Timberborn will expose HTTP endpoints for turning it off and on on localhost.  Connect it to a fireworks launcher and now you can have fireworks launch across the sky every time that endpoint is called.</p>

<p>Have Claude Code add a Notification hook that calls that endpoint like so, and now every time Claude needs your attention: fireworks launch in Timberborn.</p>

<p><img src="/img/timberborn-fireworks.png" alt="Fireworks in Timberborn" /></p>

<p>(Or you can add it to the Stop hook if you want to know every time Claude stops)</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
  </span><span class="nl">"hooks"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"Notification"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
      </span><span class="p">{</span><span class="w">
        </span><span class="nl">"matcher"</span><span class="p">:</span><span class="w"> </span><span class="s2">""</span><span class="p">,</span><span class="w">
        </span><span class="nl">"hooks"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
          </span><span class="p">{</span><span class="w">
            </span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"command"</span><span class="p">,</span><span class="w">
            </span><span class="nl">"command"</span><span class="p">:</span><span class="w"> </span><span class="s2">"curl -s 'http://localhost:8080/api/switch-on/HTTP%20Lever%201'"</span><span class="w">
          </span><span class="p">}</span><span class="w">
        </span><span class="p">]</span><span class="w">
      </span><span class="p">}</span><span class="w">
    </span><span class="p">],</span><span class="w">
    </span><span class="nl">"Stop"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
      </span><span class="p">{</span><span class="w">
        </span><span class="nl">"matcher"</span><span class="p">:</span><span class="w"> </span><span class="s2">""</span><span class="p">,</span><span class="w">
        </span><span class="nl">"hooks"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
          </span><span class="p">{</span><span class="w">
            </span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"command"</span><span class="p">,</span><span class="w">
            </span><span class="nl">"command"</span><span class="p">:</span><span class="w"> </span><span class="s2">"curl -s 'http://localhost:8080/api/switch-on/HTTP%20Lever%201'"</span><span class="w">
          </span><span class="p">}</span><span class="w">
        </span><span class="p">]</span><span class="w">
      </span><span class="p">}</span><span class="w">
    </span><span class="p">]</span><span class="w">
  </span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>]]></content><author><name>Kellan Elliott-McCrea</name></author><summary type="html"><![CDATA[Timberborn is very much my kind of game. Complex, cozy, climate change, water system design, beavers. (My friend Schuyler pointed out at one point that my preferred genre of game is “management sims”, and that perhaps I was little over rotated on my day job.)]]></summary></entry><entry><title type="html">Socialize the Plan</title><link href="https://laughingmeme.org/2026/03/05/socialize-the-plan.html" rel="alternate" type="text/html" title="Socialize the Plan" /><published>2026-03-05T11:45:16+00:00</published><updated>2026-03-05T11:45:16+00:00</updated><id>https://laughingmeme.org/2026/03/05/socialize-the-plan</id><content type="html" xml:base="https://laughingmeme.org/2026/03/05/socialize-the-plan.html"><![CDATA[<p>On AI and code review.</p>

<p>Anyone who tells you they have this current moment in coding figured out is lying to someone (you or themselves). I’m going to keep sharing half-formed thoughts, and bits of things I’ve learned.</p>

<p>As the cost of writing code goes to zero new strains and bottlenecks appear. This is what we expect when we think about building software as a system. For most teams the first place that strain appears is in code review.</p>

<p><em>No one</em> wants their job to become spending all day carefully reviewing code that someone else had a machine generate in minutes.</p>

<p>Simon wrote yesterday about the anti-patterns of <a href="https://simonwillison.net/guides/agentic-engineering-patterns/anti-patterns/#inflicting-unreviewed-code-on-collaborators">Inflicting unreviewed code on collaborators</a>. Also nice to read the recent <a href="https://www.latent.space/p/reviews-dead">How to Kill the Code Review</a>, and see an old friend like the <a href="https://en.wikipedia.org/wiki/Swiss_cheese_model">Swiss cheese model</a>.</p>

<p>Code review is a funny topic.</p>

<p>Most senior engineers and engineering leaders I know have always been quietly skeptical of its value. It’s expensive, and the data on defect detection doesn’t justify the cost. Meanwhile teams tend to put too much trust in code review while underinvesting in other tools to gain confidence: monitoring, automation, better coding tools and practices, training, etc. (Swiss cheese!)</p>

<p>Code review ubiquity is tied to GitHub’s (really quite recent I promise you!) rise to ubiquity, a tool designed for open source development, that quickly sublimated into being “conventional wisdom and best practice”. So much to say about how in software, we keep believing we’ve found “normal” and “best practice,” forgetting we’re 50 years into an experiment where we tear up and reinvent best practices every 5–10 years.</p>

<p>As a senior leader you sort of shrug and sigh, and be glad that code review has some nice side benefits like ensuring that information is dispersing through the organization, that people are talking to each other, learning and teaching is happening, all of which are valuable.</p>

<p>But that is all about code review for human written code and so I digress.</p>

<p>On my team we’re not ready (yet?) to ditch code review, but I got this insightful feedback on the first large AI generated PR I tried to land that has shaped my thinking. </p>

<blockquote>
  <p>In a manually coded PR, if a reviewer comes in and pushes back on the design, then that’s often a smell that the design wasn’t sufficiently socialized prior to spending time on the implementation. So we have meetings to review designs, we write RFCs, etc, to get consensus about how to do a thing before we commit effort to it. In this case, you went through the planning phase with the agent to determine the approach to take, and then had it churn out the diff.</p>
</blockquote>

<blockquote>
  <p>getting design push-back in a manually written PR is annoying because the effort expended to write it was wasted if the design has to shift. But if the agent is able to quickly produce a new diff once a plan is updated to reflect design feedback, then push-back on the plan isn’t a big deal because we can just update the plan and re-run the agent.</p>
</blockquote>

<p>Anyone working with coding agents regularly knows the planning phase is where the bulk of the time is spent not to mention where the human cognition and creativity is happening (that and designing the verification steps). Plan → save the plan → implement → describe diff → review → verify → fix → possibly update the plan.</p>

<p>Implementation, the generating of code, is really a rather minor and cheap part of the process. Why obsess on getting feedback on that part?</p>

<p>That’s our latest learning as a team: <strong>Socialize and get feedback on the plan.</strong> (Also on the verification steps. And maybe on how you configure your reviewers.)</p>

<p>This is the most human to human high bandwidth work.</p>

<p>I liked a lot of the framing of the problem in Simon’s and Ankit’s posts (and seeing an old friend like Swiss cheese model). But I think their solutions missed out on a plan for ensuring the continuation of the real value that code review provides: socialization, information dispersal, learning and teaching.</p>

<p>Ankit is right, the human work moves upstream (as it always has).</p>

<p>You can look at the code. But honestly, it’s the human driving the agent’s job to worry about the code, ensure it works, and that they meet the standards of the org. We can do something more valuable with our teammates time when we ask them to review our work.</p>]]></content><author><name>Kellan Elliott-McCrea</name></author><summary type="html"><![CDATA[On AI and code review.]]></summary></entry><entry><title type="html">Ed’s Software, in a Time of Fear</title><link href="https://laughingmeme.org/2026/03/01/software-in-a-time-of-fear.html" rel="alternate" type="text/html" title="Ed’s Software, in a Time of Fear" /><published>2026-03-01T13:58:18+00:00</published><updated>2026-03-01T13:58:18+00:00</updated><id>https://laughingmeme.org/2026/03/01/software-in-a-time-of-fear</id><content type="html" xml:base="https://laughingmeme.org/2026/03/01/software-in-a-time-of-fear.html"><![CDATA[<p>I enjoyed this essay from my friend Ed Lyons, which I think speaks well to <em>my</em> particular state of mind as someone who has been in this industry for 30+ years, a parent, a people leader, a builder.</p>

<p><a href="https://mysteriousrook.medium.com/software-in-a-time-of-fear-4e5a08ac7c63">Software, in a Time of Fear</a></p>

<blockquote>
  <p>Up front, here are the lessons:</p>

  <ol>
    <li>Stop listening to people who are afraid</li>
    <li>Seek first-hand testimony, not opinions</li>
    <li>Go with someone much more enthusiastic than you</li>
    <li>Do not look down</li>
    <li>You must get different equipment</li>
    <li>Put the summit out of your mind</li>
  </ol>

  <p>Yet I hope you stay for the hike up.</p>
</blockquote>

<p>Personally I’m working on 1, 2, 3, and 5. I’m struggling with 4 and 6.</p>]]></content><author><name>Kellan Elliott-McCrea</name></author><summary type="html"><![CDATA[I enjoyed this essay from my friend Ed Lyons, which I think speaks well to my particular state of mind as someone who has been in this industry for 30+ years, a parent, a people leader, a builder.]]></summary></entry><entry><title type="html">Software Practices from the Scrap Heap?</title><link href="https://laughingmeme.org/2026/02/15/software-practices-from-the-scrap-heap.html" rel="alternate" type="text/html" title="Software Practices from the Scrap Heap?" /><published>2026-02-15T14:53:50+00:00</published><updated>2026-02-15T14:53:50+00:00</updated><id>https://laughingmeme.org/2026/02/15/software-practices-from-the-scrap-heap</id><content type="html" xml:base="https://laughingmeme.org/2026/02/15/software-practices-from-the-scrap-heap.html"><![CDATA[<p>I’m going to keep writing half baked things about AI, because it’s what I’m spending a noticeable number of hours thinking about these days, and because I don’t think it’s possible to be fully baked on the topic. Apologies in advance for those who find it irritating.</p>

<p>Had a call with <a href="https://blog.fsck.com/">Jesse</a> the other week and we discussed how we’re <a href="https://blog.fsck.com/2026/02/03/managing-agents/">speed running the last few decades of engineering management</a>. The swarm craze of the last few weeks bringing us solidly up to Fred Brooks.</p>

<p>Writing about software development over the years has always suffered from at least two key challenges:</p>

<ul>
  <li>
    <p>the vast majority of the writing suffers from survivor bias and serves as a record of something that worked for <em>this particular set of humans</em> in <em>this particular set of circumstances</em>.</p>
  </li>
  <li>
    <p>most of the writing has implicitly assumed a highly rational, implacable, rule following software engineer completely at odds with all the software engineers I’ve known (and wildly at odds with the best of them)</p>
  </li>
</ul>

<p>But if our software theories often assumed emotionally and morally stunted automatons with limitless patience, might they be useful in today’s context?</p>

<ul>
  <li>TDD, always hit and miss for humans, clearly works well for agents.</li>
  <li>The folks I’ve spoken with who are experimenting with maximalist approaches to agentic coding talk a lot about components and isolation in ways that remind me of microservices (terrible for humans), and CORBA before it.</li>
  <li>Bake-offs (the agent might get attached to their implementation, but only for the space of that shell)</li>
  <li>Sub-agents have <em>some</em> of the insights of pair programming encoded in the practice, enough that it makes me wonder about the rest of the XP toolkit.</li>
  <li>UML and Rational Rose coming back?</li>
</ul>

<p>I wonder what else from the scrap heap is worth poking at?</p>

<p><strong>update:</strong> Big Up Front planning was pointed out to me as a classic technique that worked poorly with humans and is coming back as planning becomes more key</p>]]></content><author><name>Kellan Elliott-McCrea</name></author><summary type="html"><![CDATA[I’m going to keep writing half baked things about AI, because it’s what I’m spending a noticeable number of hours thinking about these days, and because I don’t think it’s possible to be fully baked on the topic. Apologies in advance for those who find it irritating.]]></summary></entry><entry><title type="html">Code has _always_ been the easy part</title><link href="https://laughingmeme.org/2026/02/09/code-has-always-been-the-easy-part.html" rel="alternate" type="text/html" title="Code has _always_ been the easy part" /><published>2026-02-09T17:05:30+00:00</published><updated>2026-02-09T17:05:30+00:00</updated><id>https://laughingmeme.org/2026/02/09/code-has-always-been-the-easy-part</id><content type="html" xml:base="https://laughingmeme.org/2026/02/09/code-has-always-been-the-easy-part.html"><![CDATA[<p>When I joined Etsy the team was two years into a rewrite chasing a more elegant architecture (actually two distinct incompatible elegant architectures), and hadn’t shipped a customer facing feature in that time. I like to say (and it may even be true) that stopping and pivoting the team to standardizing on PHP was critical to unlocking everything that came later at Etsy. After all, no one ever has to argue about what elegant PHP looks like.</p>

<p>We’ve <em>always</em> had this tension. We’ve always fetishized the act of writing code, the quality of the code, the code as the primary artifact and IP. And on the other hand successful teams have <em>always</em> known that the value is the system, the value is human-technology hybrid that allows a product to be delivered, meet customer needs, evolve to provide more value over time, meet the spoken and unspoken needs of the problem domain, etc. This confusion in our thinking has laid at the heart of why, for example, technical hiring was such a disaster for so long. (Hiring continues to be terrible but it’s actually <em>much</em> better than it used to be. We now make fun of teams that ask you to reverse a linked list on a whiteboard while evaluating if they’d like to have a beer with you. That used to be the norm)</p>

<p>Said another way, we’ve known for a <em>long</em> time that code is the easy part. Has arguably <em>always</em> been the easy part, but certainly has been the easiest part of building software for the last several decades.</p>

<p>Yes: this is a genuinely new moment.</p>

<p>Yes: the last 3-4 months of frontier models, and Claude Code and its ilk are genuinely something new in the world.</p>

<p>Yes: the cost of producing code is plunging towards something near to zero faster than almost any of us can imagine, and that’s going to require a ton of change.</p>

<p>Yes: it’s already breaking social contracts and requiring rethinking about how teams work together. (<a href="https://siddhantkhare.com/writing/ai-fatigue-is-real">Review is <em>fatiguing</em> in a way that creating is not</a>, something else we’ve known for a while.)</p>

<p>Also yes: I’m feeling the <a href="https://simonwillison.net/2026/Feb/6/tom-dale/">dissociative awe at the temporal compression of change</a>.</p>

<p>But code being the easy and cheap part is not new.</p>

<p>Technology changes requiring us to rethink our social contracts and how our teams work is not new.</p>

<p>The web, CI/CD, large scale sites, mobile, SPAs, machine learning and data, all of these broke how teams worked and required us to invent new ways of working.</p>

<p>I think it’s fascinating to <a href="https://simonwillison.net/2026/Feb/7/software-factory/">read about running a dark software factory with a team of 3 people</a>. I think as a leader with a much larger (though comparatively small) team of humans I’m going to need to be equally creative on the right way to incorporate humans rather than exclude them from the process. And honestly those conversations are fun. It’s been a <em>while</em> since we’ve gotten to throw all the pieces up in the air and see what works.</p>

<p>It’s reasonable to be skeptical of AI because so much of the hype around it, and so many of the people hyping it (and profiting from it) are also at the nexus of the most amoral and sometimes out right evil aspect of how capital has transformed tech. (Does anyone else miss when tech was funded by nice, morally uncomplicated actors, like the US Department of Defense, back when it was still called the Department of Defense)</p>

<p>It’s also reasonable for people who entered technology in the last couple of decades because it was good job, or because they enjoyed coding to look at this moment with a real feeling of loss. That feeling of loss though can be hard to understand emotionally for people my age who entered tech because we were addicted to feeling of agency it gave us. The web was objectively awful as a technology, and genuinely amazing, and nobody got into it because programming in Perl was somehow aesthetically delightful. (The language is referred to as write only line noise for a reason)</p>

<p>The cost of code is going to zero. That’s genuinely neat, and mind blowing, and going to require reinventing so many things. It was still never the hard part.</p>]]></content><author><name>Kellan Elliott-McCrea</name></author><summary type="html"><![CDATA[When I joined Etsy the team was two years into a rewrite chasing a more elegant architecture (actually two distinct incompatible elegant architectures), and hadn’t shipped a customer facing feature in that time. I like to say (and it may even be true) that stopping and pivoting the team to standardizing on PHP was critical to unlocking everything that came later at Etsy. After all, no one ever has to argue about what elegant PHP looks like.]]></summary></entry><entry><title type="html">Web app for looking up NYC street trees</title><link href="https://laughingmeme.org/2025/06/01/nyc-street-trees.html" rel="alternate" type="text/html" title="Web app for looking up NYC street trees" /><published>2025-06-01T17:05:30+00:00</published><updated>2025-06-01T17:05:30+00:00</updated><id>https://laughingmeme.org/2025/06/01/nyc-street-trees</id><content type="html" xml:base="https://laughingmeme.org/2025/06/01/nyc-street-trees.html"><![CDATA[<p>I spent Thursday at King’s County Court House finding out whether I was going to be called for jury duty. I used the opportunity to reach <em>way back</em> in the spark file for a silly side project, a web app for browsing NYC’s street trees.</p>

<p><img src="/img/spark-trees-near-you.jpg" /></p>

<p>This project has been on my todo list for a long time (probably even before the 2016 date I have written down here). I was inspired by <a href="https://www.treesnearyou.com/">Trees Near You</a>, an awesome hack from <a href="https://www.brettcamper.com/">Brett Camper</a> at a hackathon the city threw to promote its new open data initiatives (back when NYC did that kind of thing). At some point Apple changed some APIs and Brett’s awesome app stopped working and I conceived the notion to rebuild it for the web.</p>

<p>Now this project is largely pointless, because in the intervening decade <a href="https://tree-map.nycgovparks.org/">NYC Parks has launched an excellent website to serve just this purpose</a>. But it’s a fun, self contained little project, and I’ve picked up a couple of different times to try out new technology. (The React and React Native versions never really worked. A version I tried to build with Claude’s help in 2023 on Svelte mostly worked locally in Chrome, but never on Safari or in production). With Claude Code this time I got further.</p>

<p>So here is a <a href="https://treesnyc.onrender.com/">simple Trees NYC web app</a>. Relatively vanilla Javascript, SQLite backend. Please enjoy New Yorks 650k+ trees.</p>

<p>(and I was dismissed from jury duty, I don’t think the vibe coding was the reason.)</p>]]></content><author><name>Kellan Elliott-McCrea</name></author><summary type="html"><![CDATA[I spent Thursday at King’s County Court House finding out whether I was going to be called for jury duty. I used the opportunity to reach way back in the spark file for a silly side project, a web app for browsing NYC’s street trees.]]></summary></entry><entry><title type="html">Vibe coding for teams, thoughts to date</title><link href="https://laughingmeme.org/2025/05/25/vibe-coding-for-teams.html" rel="alternate" type="text/html" title="Vibe coding for teams, thoughts to date" /><published>2025-05-25T17:05:30+00:00</published><updated>2025-05-25T17:05:30+00:00</updated><id>https://laughingmeme.org/2025/05/25/vibe-coding-for-teams</id><content type="html" xml:base="https://laughingmeme.org/2025/05/25/vibe-coding-for-teams.html"><![CDATA[<p>(note: this is still a <em>topic</em> I’m interested in and thinking about a lot, but this blog post from 8 months ago is so out of date as to be useless - 2026/02/07)</p>

<p>I’ve got <a href="https://www.anthropic.com/claude-code">Claude Code</a> running in the background while I tab between writing this, sipping a Powers, and fielding phone calls from a team slightly panicked about the end of quarter QBR. This blog post is being written on May 27th, 2025, things may have changed by the time you read it. It was a toss up whether to post this on <a href="https://kellanem.com/notes/">Notes on engineering leadership</a>, or here, but eventually decided this was too loose for even Notes low standards. You’ve been warned (or at least given a context window with which to understand the remaining blog post).</p>

<p>LLMs are without a doubt the most disruptive change to how code gets written I’ve seen in my career since the introduction of the World Wide Web. As someone who largely <em>started</em> on the web at a time when most people weren’t, I remember reading <a href="https://en.wikipedia.org/wiki/Dr._Dobb%27s_Journal">Dr. Dobb’s</a> 30 years ago and seeing all these ads for weird C++ binaries I could pay to include in binaries I shipped on CDs. (Jokes on me as I now work at a <a href="https://www.adobe.com/">company</a> that has C++ in production that dates to that era). That said, as of today, LLMs don’t change some key fundamental physics of writing code as a team. Importantly, as of today, they haven’t changed the fundamental calculation that writing code is always easier than understanding code.</p>

<p>The insight that reading code is harder than writing leads naturally to the insight that <a href="https://kellanem.com/notes/towards-an-understanding-of-technical-debt">every line of code is tech debt</a>. Every line of code encodes your best current understanding of the problem you’re trying to solve (for increasingly weird definitions of “you”). Nothing has changed the fact that your current understanding is probably limited, and wrong in several ways.</p>

<h3 id="updating-your-mental-model-even-harder-for-llms-than-for-engineers">Updating your mental model even harder for LLMs than for engineers</h3>

<p>If you’ve ever had the questionable joy of participating in a “technological transformation” (whether or not it was called that) than you’ve had the specific experience of how challenging it is to convince an engineering team to give up on its current test suite (for extremely variable values of “test suite”). It doesn’t matter how much you argue that the test suite is a product of the practices and understanding of the problem you’re trying to over turn. And you’ll have this same conversation iterated for each historical technical decision (but especially tests). I’ve gone through the process of convincing a toddler to give up their pacifier, and convincing engineers to give up their tests, and I’d choose reasoning with the 2 year old any day of the week.</p>

<p>LLMs are more challenging. As soon as you instruct them to start building context from an existing codebase, you’re in a battle to change their mind about what’s important. From tests, to schemas, to dependencies. Given the lack of explicit tools for operating on their internal model, it’s a shockingly similar process to convincing an engineer (I should note the approaches that work with a toddler <em>do not work</em> with LLMs, in particular bribery is largely a failure).</p>

<p>The saving grace for engineers is the handful of folks who through inclination or trauma either believe in a better world or just want to see the current world burn and are therefore inclined to radical departures. My experimental data suggests telling LLMs they “just want to watch the world burn” does not make them more comfortable deleting obsolete test cases.</p>

<h3 id="nih-wasnt-invented-here-but-we-did-perfect-it">NIH wasn’t invented here, but we did perfect it.</h3>

<p>Current generations of LLM are very happy to write you a new function for functionality you already have in your codebase. Your tips on incantations to add to CLAUDE.md to change this behavior welcome. Just telling it “DRY” ain’t getting the job done. (and honestly, <a href="https://wiki.c2.com/?DontRepeatYourself">DRY</a> was always problematic advice that lead to premature abstraction, and that was before the nightmare that was dependency injection). Code bases with significant AI contribution are … bushy. Arguably as long as no humans are required to reason about the codebase we’re fine. It does preclude, practically from first principles, those exceptional individuals many of us have encountered in our career who seemed to be able to hold the entire code base in their brains. Arguably that’s a net positive. Those individuals were always problematic similar to those folks who are willing to <a href="https://www.google.com/search?q=heroes+considered+harmful">work 80 hours a week and jump on every incident</a>. At a minimum they make the rest of us look bad. But it’s still an arms race between the LLM and itself. I may be skeptical of TDD as a human practice, but as a LLM practices it’s the gold standard. But if every member of your team has their own bespoke approach to common functionality is your test suite doing its job? At a minimum you’re burning a lot of Github Actions CPU. And that’s before you ponder what does the response to <a href="https://nvd.nist.gov/vuln/detail/cve-2021-44228">Log4Shell</a> look like in a world where everyone on your team has their own NIH bespoke logging code?</p>

<h3 id="a-small-number-of-well-known-tools--if-it-was-opposite-day">A Small Number of Well Known Tools … if it was opposite day.</h3>

<p>Highly productive engineering teams (historically) reach that productivity by building a deep expertise in their tool chain. This is why it is so critical to closely examine <a href="https://kellanem.com/notes/new-tech">introducing new technologies</a> to your stack. An under examined cost of complicated technologies is that the cost of defining the preferred subset of capabilities falls on each development team instead of the industry as a whole. For example think about how every team that uses a “big language” (like Typescript or Scala) defines their own local subset, or paucity of Postgres best practices vs MySQL. <a href="https://wiki.c2.com/?ThereIsMoreThanOneWayToDoIt">TIMTOWTDI</a> isn’t actually a good thing. (<a href="https://docs.python.org/3/tutorial/stdlib.html#batteries-included">“batteries included”</a> definitely won that argument) LLMs radically lower the cost of writing code (already the cheapest part of software development). With LLMs it is often easier to code an approach than research one. The exploding ecological diversity in our software environments is breathtaking.</p>

<h3 id="where-were-at-today">Where we’re at today</h3>

<p>Local, bespoke, unique, noisy, bushy, <em>big</em> codebases seem like the inevitable byproduct of our current tools and models. It’s possible that LLMs can be shaped into tools that making code reading and code reasoning more powerful; that help us refactor, refine, and reduce the complexity of our codebases. I’m certainly encouraging my team to experiment with what is possible. Lowering the cost of <em>writing</em> code was the thing that no engineering leader asked for, but it’s the thing we got.</p>

<p>How are you changing your leadership practices in the face of LLMs?</p>

<p>You’ve spent $0 on LLM APIs reading this blog post.</p>]]></content><author><name>Kellan Elliott-McCrea</name></author><summary type="html"><![CDATA[(note: this is still a topic I’m interested in and thinking about a lot, but this blog post from 8 months ago is so out of date as to be useless - 2026/02/07)]]></summary></entry><entry><title type="html">GDrive to S3</title><link href="https://laughingmeme.org/2024/10/05/drive-to-s3.html" rel="alternate" type="text/html" title="GDrive to S3" /><published>2024-10-05T14:05:30+00:00</published><updated>2024-10-05T14:05:30+00:00</updated><id>https://laughingmeme.org/2024/10/05/drive-to-s3</id><content type="html" xml:base="https://laughingmeme.org/2024/10/05/drive-to-s3.html"><![CDATA[<p>I have <a href="https://takeout.google.com/?pli=1">Google Takeout</a> setup to periodically export to GDrive as a series of 10Gb .zip files. I’ve been meaning to get these over to S3 for a bit in part for backup purposes, and in part because I wanted to futz with the photos.</p>

<p>I’m quite confident I’m not the first person to want to do something like this. But we’ve reached an awkward and unfortunate moment in the Web’s journey where search just doesn’t work very well anymore. Except searching the latent information space of a LLM trained on the entire Web actually works unreasonably well for this sort of thing. Meaning, it is easier to write your own than find an existing solution. That’s going to have all sorts of weird consequences I’m sure.</p>

<p>So here’s my script, <a href="https://gist.github.com/kellan/2a8ff0e614ae96034f5592513f9a717a">gdrive-to-s3.py</a>. It use the <a href="https://googleapis.github.io/google-api-python-client/docs/epy/googleapiclient.http.MediaIoBaseDownload-class.html">MediaIoBaseDownload</a> API to fetch files in byte ranges from Gdrive and multi-part S3 uploads which in combination remove the need to read any of these 10Gb files directly into memory or store then locally (either of which would rather rules out running the script on a t2.micro) and instead allows you to stream the data from one storage provider to another in manageable chunk sizes.</p>

<p>I used to leave long running jobs hanging around in load bearing screen sessions all the time. Kind of nice to return to my roots.</p>]]></content><author><name>Kellan Elliott-McCrea</name></author><summary type="html"><![CDATA[I have Google Takeout setup to periodically export to GDrive as a series of 10Gb .zip files. I’ve been meaning to get these over to S3 for a bit in part for backup purposes, and in part because I wanted to futz with the photos.]]></summary></entry></feed>