<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://berens.co/feed.xml" rel="self" type="application/atom+xml" /><link href="https://berens.co/" rel="alternate" type="text/html" /><updated>2026-10-19T12:49:49+00:00</updated><id>https://berens.co/feed.xml</id><title type="html">Paul Berens</title><subtitle>berens.co</subtitle><entry><title type="html">Going Acoustic</title><link href="https://berens.co/ebikes.html" rel="alternate" type="text/html" title="Going Acoustic" /><published>2026-10-18T00:00:00+00:00</published><updated>2026-10-18T00:00:00+00:00</updated><id>https://berens.co/ebikes</id><content type="html" xml:base="https://berens.co/ebikes.html"><![CDATA[<p>I’ve given the e-bike plenty of time, watching it go from novelty to fixture in just a few years. And yet I remain unconverted. My problem isn’t the technology (they’re beautiful machines in many cases); it’s the 32-year-old fella ripping through the Mission District at 30 mph with a serene countenance. I say to this homeboy: get an acoustic bike. Work your quads. And if you won’t, at least get out of the bike lane.</p>

<p>If you recall, e-bikes arrived in the late 2010s with dockless bikeshare (e.g., JUMP) but really ramped during the COVID pandemic, hitting 1.1 million imports in 2022, exceeding electric cars.<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup></p>

<p>Surveys at Marin and San Mateo County middle and high schools found 88% and 87% of the devices weren’t legal e-bikes at all but rather basically motorcycles with decorative pedals.<sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">2</a></sup></p>

<iframe width="458" height="815" style="max-width:100%" src="https://www.youtube.com/embed/t3L3hbz2XtQ" title="If you&#39;re not using the pedals, just take them off honestly." frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen=""></iframe>

<p>But maybe e-bikes are enabling pregnant women and/or the disabled or the poor to get around… Negative. A Portland State survey of North American owners found the market still dominated by white, male, affluent riders.<sup id="fnref:3" role="doc-noteref"><a href="#fn:3" class="footnote" rel="footnote">3</a></sup> Not to say there’s not a market beyond the core segment, but this is a rant about the 32-year-old in the corporate-branded fleece vest whose knees are perfectly fine and who’s casually barreling down John F. Kennedy Drive in Golden Gate Park at four o’clock on a Tuesday.</p>

<h2 id="the-device-assist-vs-throttle">The Device: Assist vs. Throttle</h2>

<p>It’s worth qualifying which machines I’m talking about. California sorts e-bikes into three classes:<sup id="fnref:4" role="doc-noteref"><a href="#fn:4" class="footnote" rel="footnote">4</a></sup></p>

<table>
  <thead>
    <tr>
      <th style="text-align: center">Class</th>
      <th>How the motor works</th>
      <th>Assist cuts out at</th>
      <th>Reqs</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: center">1</td>
      <td>Pedal-assist only</td>
      <td>20 mph</td>
      <td>Standard bike rules</td>
    </tr>
    <tr>
      <td style="text-align: center">2</td>
      <td>Throttle; no pedaling required</td>
      <td>20 mph</td>
      <td>Bike can be impounded if rider is under 16</td>
    </tr>
    <tr>
      <td style="text-align: center">3</td>
      <td>Pedal-assist only</td>
      <td>28 mph</td>
      <td>Speedometer, helmet, riders 16+</td>
    </tr>
  </tbody>
</table>

<p>Anything over 750 watts is <em>already</em> a moped or motorcycle, legally, not an e-bike. Nobody acts like it.</p>

<p>After my discovery of the bidet I’ve started wondering what else the Europeans have figured out that we haven’t and here’s another example: they do e-bike = pedal-only + 250 watts max (15.5 mph).</p>

<p>The Mineta Institute has recommended California move toward this model. Instead we got SB 1167, which stops sellers from calling e-motos e-bikes and does nothing about the guy already riding one.<sup id="fnref:5" role="doc-noteref"><a href="#fn:5" class="footnote" rel="footnote">5</a></sup></p>

<h2 id="leg-day">Leg Day</h2>

<p>The labels are coming January 1. Until then, all I’m askin’ for is a little shame. The humble bicycle is a miracle of 19th-century engineering: no battery to catch fire, no app, no firmware update, no unlock code. Its top speed is determined entirely by how often you skipped leg day. And every hill in this city is a free quad workout.</p>

<p>So I will tolerate pedal-assist (with slightly turned-up nose). But full throttle? No way. You have two great options: either upgrade to a real motorcycle—I’d recommend Triumph—or get in shape by rockin’ an acoustic.</p>

<p>— ᴘ. ᴍ. ʙ.</p>

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1" role="doc-endnote">
      <p>California State Assembly, Committee on Transportation, <a href="https://atrn.assembly.ca.gov/system/files/2026-04/1557.pdf"><em>AB 1557 (Papan): Vehicles: Electric Bicycles</em></a>, bill analysis, April 20, 2026, 3. <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:2" role="doc-endnote">
      <p>Assembly Committee on Transportation, <em>AB 1557 Analysis</em>, 5. <a href="#fnref:2" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:3" role="doc-endnote">
      <p>Cameron Steven Bennett, <a href="https://pdxscholar.library.pdx.edu/open_access_etds/6605/">“A Survey of North American Electric Bicycle Owners”</a> (master’s thesis, Portland State University, 2024). <a href="#fnref:3" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:4" role="doc-endnote">
      <p>Cal. Veh. Code § 312.5; summarized in Assembly Committee on Transportation, <em>AB 1557 Analysis</em>, 1–2, 6. <a href="#fnref:4" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:5" role="doc-endnote">
      <p>Assembly Committee on Transportation, <em>AB 1557 Analysis</em>, 6; <a href="https://bicycleretailer.com/industry-news/2026/10/01/california-signs-law-legislation-differentiate-e-motos-e-bikes">“California Signs into Law Legislation to Differentiate E-Motos from E-Bikes,”</a> <em>Bicycle Retailer and Industry News</em>, October 1, 2026. <a href="#fnref:5" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>]]></content><author><name>Paul Berens</name></author><category term="culture" /><summary type="html"><![CDATA[A rant from an e-bike holdout]]></summary></entry><entry><title type="html">Swarma, Pt. 2</title><link href="https://berens.co/swarma-public.html" rel="alternate" type="text/html" title="Swarma, Pt. 2" /><published>2026-09-15T00:00:00+00:00</published><updated>2026-09-15T00:00:00+00:00</updated><id>https://berens.co/swarma-public</id><content type="html" xml:base="https://berens.co/swarma-public.html"><![CDATA[<p><a href="/swarma-app.html">In our last episode</a>, Dear Reader, I described my vibe-coding adventures that yielded a Wear OS Swarm client that I sideloaded it onto my own Pixel Watch, and it bloody worked! I built Swarma because I wanted it, and thought it’d be fun to try my hand at Wear OS / Kotlin.</p>

<p>But since there was no native Wear OS Swarm client, I suspected I wasn’t the only one who’d be interested in this, so I went looking for testers in a couple of corners of Reddit (<code class="language-plaintext highlighter-rouge">r/WearOS/</code>, <code class="language-plaintext highlighter-rouge">r/SwarmApp/</code>, <code class="language-plaintext highlighter-rouge">r/Foursquare/</code>), and lo and behold, some latent demand from fellow Swarm nerds revealed itself…internationally, in fact: Australia, Deutschland, Greece, Nederland, España, et al. And that was all the confirmation I needed to turn this from a personal, sideloaded tool into something worth perfecting (i.e., get to an official public listing in the Google Play Store).</p>

<h2 id="the-testers-found-the-bugs-co-pilot-couldnt">The testers found the bugs co-pilot couldn’t</h2>

<p>A few examples, because credit is owed:</p>
<ul>
  <li><strong>u/sorross</strong> flagged, almost immediately, that my first OAuth implementation used an in-app WebView instead of a proper browser tab, meaning users were typing their Foursquare password into <em>my</em> UI rather than Foursquare’s own site…which is a security issue, and he was right to call it out. Not a huge lift to move to a Chrome Custom Tab.</li>
  <li><strong>u/c99koder</strong> found and used the sticker feature harder than anyone, including me—actually, he’s the reason stickers exist at all in a meaningful way, and his bug reports (a gym sticker mysteriously vanishing from the picker) led to a whole rethink of how used-but-still-desirable stickers should be displayed.</li>
  <li>Other testers pushed back on UX decisions I’d made without enough evidence: e.g., a home screen that buried the actual venue list under a button press (an extra unnecessary click).</li>
</ul>

<p>Practically none of these were things an AI co-pilot could have caught on its own, and <em>a fortiori</em> for me: I could only catch things I noticed. For example, one user saw that sticker grid was left justified and running off the screen, but that’s because he had a larger screen (later Pixel Watch model) which displayed it that way whereas on mine you couldn’t tell.</p>

<h2 id="reverse-engineering-the-parts-foursquare-didnt-document">Reverse-engineering the parts Foursquare didn’t document</h2>

<p>The public Foursquare API (v2) is old, largely frozen, and it does more than its documentation admits. While building sticker support, I found that <code class="language-plaintext highlighter-rouge">checkins/add</code> quietly accepts a <code class="language-plaintext highlighter-rouge">stickerId</code> parameter that isn’t documented anywhere—and it works, amazingly. It applies weekly account-level bonuses correctly. What it <em>doesn’t</em> do is replicate the live, venue-specific multiplier the native Swarm app shows (the “3x right here, right now” bonuses)—that math happening behind an unexposed endpoint. Same for check-ins counting toward mayorships, I believe.</p>

<p>I originally displayed the static multiplier (e.g., “2x”) next to each sticker. Then a tester checked in with a sticker showing 2x in Swarma and got 3x in the native app, on the same check-in, minutes apart. Because I couldn’t get at Foursquare’s private multiplier logic, the fix was to stop offering a guesstimate multiplier, and show a plain “this sticker has <em>a</em> bonus” glyph instead. Sometimes the right technical decision is to say less.</p>

<h2 id="the-play-store-reviews-your-app-and-your-process">The Play Store reviews your app <em>and</em> your process</h2>

<p>Getting from “works on my watch” to “listed for the public” meant learning the rules of Google Play Store:</p>
<ul>
  <li><strong>Closed testing is a gate, not a suggestion.</strong> New developer accounts need 12 opted-in testers, continuously, for 14 days, before Google will even look at a production application. If you lose a tester and go below 12 the clock resets; which happened to me, twice. So overrecruit your testers so you’ve got a little buffer.</li>
  <li><strong>My first production application was rejected</strong> for weak tester engagement (installs without usage) and a missing set of phone screenshots (I’d only submitted watch screenshots, because in my head this was a watch app).</li>
  <li><strong>My watch and phone builds needed independent version-code bands</strong>, not sequential numbers a step apart, so I could update one without forcing a rebuild of the other. I learned this by hitting the wrong error message enough times.</li>
  <li><strong>A Wear-specific quality bar exists and is enforced separately</strong> from general Play policy. My “Checked in!” confirmation screen got flagged for missing a scroll position indicator, on a screen where the content fit without scrolling. Apparently that doesn’t matter and the indicator has to be there regardless, so that was a cycle.</li>
</ul>

<p>So not coding problems <em>per se</em> but more learning the platform’s expectations.</p>

<h3 id="killing-the-phone-app-a-second-time">Killing the phone app (a second time)</h3>

<p>The original OAuth design—the one from the <a href="/swarma-app.html">first post</a> worked, but it required a companion phone app whose only real job was opening a browser tab and shuttling a token to the watch over Bluetooth. It worked, but it was one more thing to install, one more thing to explain, and, as I mentioned, one more thing that could silently drift out of sync with the watch build.<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup></p>

<p>Wear OS has a purpose-built API for exactly this (<code class="language-plaintext highlighter-rouge">RemoteAuthClient</code>) that lets a watch app kick off an OAuth flow, have it resolve in the <em>phone’s own browser</em> via a system-level relay, and get the result back on the watch directly. If this could be utilized it would render the custom companion phone app unnecessary. It sounds like a small change, but it was not: it required a Google-mediated redirect URI I had to register with Foursquare, a PKCE code challenge that Google’s library mandates even though Foursquare’s OAuth server ignores it completely, and about a day of chasing crashes that all turned out to be the same root cause: an old, cached build quietly running on the watch while I debugged code that had already been fixed.</p>

<p>Once it worked, though, it was beautiful: tap “Sign In” on the watch, approve a prompt on your phone, done. The companion app is now optional.</p>

<h3 id="where-it-landed">Where it landed</h3>

<p>Swarma is public <a href="https://play.google.com/store/apps/details?id=co.berens.swarma" target="_blank">on the Play Store</a> now, for Pixel Watch and Galaxy Watch. Sign-in happens entirely on the watch. Stickers show an honest bonus indicator instead of a number I couldn’t back up. The venue list loads the moment you open the app, with the places you actually visit floating to the top.</p>

<p>None of that is a big engineering achievement in isolation. What surprised me is how little of the six months between “it works on my watch” and “it’s a real listing” was spent writing new features, and how much was spent on testing infrastructure, App Store bureaucracy, and OAuth architecture (once I understood it better).</p>

<p>The <a href="/swarma-app.html">first post</a>’s thesis was that vibe-coding shifts the hard part from implementation to everything around it: environment, product judgment, platform constraints, etc. Six months later I’d add one more item to that list: <em>institutional process:</em> test cohorts, review guidelines, version-code schemes, privacy evaluations. An AI co-pilot can write the Kotlin, but isn’t at the level of lining up and managing twelve testers for fourteen consecutive days on your behalf…yet.</p>

<p><a href="/swarma/" target="_blank"><img src="/assets/og/swarma/swarma_og.png" alt="Swarma landing page" /></a><span class="muted small">Swarma v1.1, now available on the Play Store.</span></p>

<p>Swarm lives on the Pixel Watch…now worldwide.</p>

<p>— ᴘ. ᴍ. ʙ.</p>

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1" role="doc-endnote">
      <p>The old design also had this thing where signing out on the phone cleared my app’s own token but not Foursquare’s browser session, so tapping “sign in” again silently logged you straight back into the same account. I never found a clean fix for that one as Foursquare doesn’t document a logout endpoint for third-party OAuth clients. <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>]]></content><author><name>Paul Berens</name></author><category term="tech" /><category term="product" /><summary type="html"><![CDATA[What it actually took to turn a personal afternoon project into a public Wear OS app.]]></summary></entry><entry><title type="html">Waymos</title><link href="https://berens.co/waymo.html" rel="alternate" type="text/html" title="Waymos" /><published>2026-08-11T00:00:00+00:00</published><updated>2026-08-11T00:00:00+00:00</updated><id>https://berens.co/waymo</id><content type="html" xml:base="https://berens.co/waymo.html"><![CDATA[<p><img src="/assets/og/post_waymo.jpg" alt="A white Waymo robotaxi with a roof-mounted sensor pod crosses an intersection under an overpass, sharp against blurred traffic and buildings." /></p>
<p class="muted small">Waymo robotaxis at 13th &amp; South Van Ness. Photo by <a class="muted" href="https://commons.wikimedia.org/wiki/User:Mliu92" target="_blank">Mliu92</a>, via <a class="muted" href="https://commons.wikimedia.org/wiki/File:Waymo_robotaxis,_San_Francisco_3.jpg" target="_blank">Wikimedia Commons</a> (CC BY-SA 3.0).</p>

<p>Riding my bicycle through the Mission District of San Francisco, I’ve got the same protocol at every intersection, with every vehicle I encounter: peer through the windshield, find the face, and try to catch the eyes. Sometimes I get a courteous wave. Sometimes an expressionless stare. But more often than I’d like, the eyes are down—at a phone, presumably—and I have to figure out when and how to proceed so that I don’t get hit.</p>

<p>The <em>San Francisco Chronicle</em> recently polled San Francisqueños about autonomous vehicles (AVs):</p>

<iframe title="How San Franciscans feel about self-driving cars in San Francisco" aria-label="Bar Chart" id="datawrapper-chart-YDAup" src="https://datawrapper.dwcdn.net/YDAup/1/" scrolling="no" frameborder="0" style="width: 0; min-width: 100% !important; border: none;" height="265" data-external="1"></iframe>
<script type="text/javascript">(function(){function e(){window.addEventListener(`message`,function(e){if(e.data[`datawrapper-height`]!==void 0){var t=document.querySelectorAll(`iframe`);for(var n in e.data[`datawrapper-height`])for(var r=0,i;i=t[r];r++)if(i.contentWindow===e.source){var a=e.data[`datawrapper-height`][n]+`px`;i.style.height=a}}})}e()})();</script>

<p>42% good, 18% bad, and a big fat 39% sitting in the middle with mixed feelings. The Chronicle then breaks the results down by demographic—Progressive, Liberal, Moderate, Conservative, Male, Female, College-educated, No college degree—but I’d like to see it sliced by <strong>Runner</strong>, <strong>Cyclist</strong>, and <strong>¬Runner/Cyclist</strong>, because any San Franciscan who runs or rides through the city would rather share the road with a fleet of Waymos than with the average set of motorists, in a heartbeat. And I suspect very few of them would land in that 39% middle, because the middle isn’t where you sit after you’ve had a close call.</p>

<p>The peer-reviewed safety record is lopsided in Waymo’s favor: 82% fewer injury crashes involving cyclists, 92% fewer involving pedestrians, 82% fewer involving motorcyclists, measured against human drivers in the same places.<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup></p>

<p>There are good drivers out there (mil gracias), but most of us famously overestimate our talent.<sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">2</a></sup> And look, bumping a Model T down an empty gravel road was one thing, but we aren’t built with the reaction time or the processing bandwidth for <em>today’s</em> traffic complexity.</p>

<p>But the deeper problem isn’t the average driver at all, because cycling safety isn’t a function of the average driver; rather it’s a function of the worst one. Ninety-nine attentive drivers don’t protect you from the hundredth.</p>

<p>None of which means the AVs are there yet. There are real <a href="https://www.nytimes.com/2026/08/10/technology/waymo-expansion-edge-cases.html?smid=tw-share">gaps</a> left to close, and one of the sharpest complaints about robotaxis in this city comes from cyclists, not from Luddites: Waymo has told the SF Bicycle Coalition that pulling into bike lanes for pickups and dropoffs is “normal practice,” and that keeping out of them is “too high a bar.” A cyclist is currently suing after she was doored by an exiting passenger in a marked lane and thrown into a second Waymo blocking the same lane. But notice that failure isn’t perception or judgment or reaction time; it’s a (changeable) <em>product decision</em>—which is precisely why I’m bullish: because a defect fix improves the entire Waymo fleet at once whereas there’s no equivalent patch for our worst drivers; there’s only a reprimand issued after somebody’s already dead.</p>

<p>(Also, yes, we must acknowledge that drivers will lose jobs. That’s a real cost and I don’t mean to wave it away in a parenthetical; it’s just not apropos of this post.)</p>

<p>You can’t make eye contact with a Waymo, but of course you don’t need to, because it’s already more reliable than its human counterpart, which makes you realize that eye contact is just a mediocre proxy for reliability, an attempt to infer a stranger’s intention through the glass at 20 mph.<sup id="fnref:3" role="doc-noteref"><a href="#fn:3" class="footnote" rel="footnote">3</a></sup></p>

<p>Time to hand over the keys, folks. Jeeves is electric now, and isn’t looking at his phone.</p>

<p>— ᴘ. ᴍ. ʙ.</p>

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1" role="doc-endnote">
      <p>Kusano, K., Scanlon, J., et al., <a href="https://doi.org/10.1080/15389588.2025.2499887" target="_blank">“Comparison of Waymo Rider-Only crash rates by crash type to human benchmarks at 56.7 million miles,”</a> <em>Traffic Injury Prevention</em> (2025). <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:2" role="doc-endnote">
      <p>Svenson, O., <a href="https://doi.org/10.1016/0001-6918(81)90005-6" target="_blank">“Are we all less risky and more skillful than our fellow drivers?”</a> <em>Acta Psychologica</em> 47 (1981): 143–148. Successfully replicated by Koppel et al. (2023), N = 1,203: 91% rated themselves safer and 93% more skilled than the average driver. <a href="#fnref:2" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:3" role="doc-endnote">
      <p>Though there <em>are</em> people working on how these things might signal intent to the rest of us, and I’m sure it’s a harder design problem than it sounds, but it sure would be nice to have both the confirmation and the competence. <a href="#fnref:3" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>]]></content><author><name>Paul Berens</name></author><category term="tech" /><category term="product" /><summary type="html"><![CDATA[It can't come quickly enough.]]></summary></entry><entry><title type="html">L’Étoile du Nord</title><link href="https://berens.co/mn.html" rel="alternate" type="text/html" title="L’Étoile du Nord" /><published>2026-07-07T00:00:00+00:00</published><updated>2026-07-07T00:00:00+00:00</updated><id>https://berens.co/mn</id><content type="html" xml:base="https://berens.co/mn.html"><![CDATA[<blockquote>
  <p>That’s my Middle West—not the wheat or the prairies or the lost Swede towns, but the thrilling returning trains of my youth, and the street lamps and sleigh bells in the frosty dark and the shadows of holly wreaths thrown by lighted windows on the snow. I am part of that, a little solemn with the feel of those long winters…</p>

  <p>— St. Paul native F. Scott Fitzgerald, <cite>The Great Gatsby</cite></p>
</blockquote>

<p><img src="/assets/og/post_drinking.from.hose.png" alt="drinking from a garden hose on a hot summer day" /></p>

<p>We just got back from a few glorious days’ vacation in Minnesota, with a nice blast of heat to warm up my fog-chilled bones. And it occurs to me that the sharp contrasts among the seasons (the opposite of San Francisco) are part of what give Minnesota so much character, and anchor my own childhood memories and nostalgia.</p>

<p>So here’s a year of my Minnesota (conjured while I still can): the sights, the sounds, the sensations.</p>

<h2 id="summer">Summer</h2>

<p>🎧 <a href="https://music.youtube.com/watch?v=xDASfSMHHPQ" target="_blank">“Alex Chilton” – The Replacements</a></p>

<p>I lay supine on the fresh-cut grass in the backyard of our Merriam Park home. The scattered cumulus clouds slowly slide across the mostly sunny day, while a mourning dove’s <em>coo-ah, coo, coo</em> is equally unhurried, and the sheets on the clothesline <em>flap-flop</em>. It’s hot (mid-80s [Fahrenheit]), but not as hot as yesterday over at Fort Snelling where the sun scorches the long grasses, and the grasshoppers’ long, droning chirps let you know it’s summer… if you hadn’t noticed already. On such days, the sun-warmed sap of the white spruces and white pines emits this sweet ‘n’ spicy, uniquely refreshing resin aroma. But even when you sweat in the heat and humidity—at Grand Ol’ Days in June, at the Basilica Block Party in July, at the State Fair in August—you welcome it because it won’t last long.</p>

<p><em>It’s summer in Minnesota.</em></p>

<h2 id="autumn">Autumn</h2>

<p>🎧 <a href="https://music.youtube.com/watch?v=sWk9KjHQVtg" target="_blank">“Alone” – Trampled by Turtles</a></p>

<p>Then the days and nights grow more brisk…maybe a touch before you’re ready. The sky is a solid light grey and the wind whips through the trees. As you inhale, the cool air is mixed with woodsmoke from the first fireplace fires of the season. Bring on the Honeycrisp apple pies and hearty hotdishes (casseroles), and high school football under Friday night lights. Dry oak leaves <em>skitter</em> across the pavement, but the ones in the yard are raked into big tannic-scented piles.</p>

<p><em>It’s autumn in Minnesota.</em></p>

<h2 id="winter">Winter</h2>

<p>🎧 <a href="https://music.youtube.com/watch?v=3w68krri0bw" target="_blank">“Re: Stacks” – Bon Iver</a><sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup></p>

<p>Even when the January temps are cold enough to sting the nostrils, bright bluesky days still lift the spirits…and give you hope. Shinny (tennis ball, no high-sticking, no checking) with kids aged seven to 17 at Groveland Park’s outdoor ice rink. If we dressed properly—and we typically did—the cold didn’t intimidate us, and it made coming back into the warm house <em>hygge</em>.</p>

<p>Driving at night in a snowstorm as best described by David Rhodes in <em>Driftless</em>:</p>

<blockquote>
  <p>The pickup’s headlights did not penetrate very far into the blowing snow, a situation made worse by her inability to suffer the dizzying sight of warp speed interstellar space travel whenever she attempted to use the high beams.</p>
</blockquote>

<p>Scraping our way down the icy slopes of Afton Alps and Hyland Hills Ski Area, and later running slalom gates under the lights of Buck Hill<sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">2</a></sup>.</p>

<p><em>It’s winter in Minnesota.</em></p>

<h2 id="spring">Spring</h2>

<p>🎧 <a href="https://music.youtube.com/watch?v=HGzHFMJ3mc8" target="_blank">“New Morning” – Bob Dylan</a></p>

<p>Winter habitually overstays its welcome—as Prince says, ‘sometimes it snows in April’—drawing groans in unison when it does. Of course, we couldn’t wait for spring either: street hockey on Rollerblades with half-melted snow and ice remnants at the edges, water trickling into the gutters. But everything is muddy and dingy until the first real rains thaw the earth, coaxing out the earthworms and releasing everything held tight all winter. And then the first mowed grass and the lilacs sweeten the air, and eventually the air is just warm enough to warrant opening the windows and letting the breeze freshen the house. The black-capped chickadee’s <em>fee-bee</em>—its true spring song—reassures:</p>

<p><em>It’s spring in Minnesota.</em></p>

<h2 id="hiraeth">Hiraeth</h2>

<p>But the child’s Minnesota and the present one aren’t the same place, much as I’d love to step back into it. The Welsh have a word for the ache of longing for a home you can’t return to: <em>hiraeth</em>. I might still lie back on the fresh-cut grass and hear the mourning dove’s <em>coo</em>; it just wouldn’t be the same grass, the same dove…much less the same me (as <a href="/alice.html">Alice would point out</a>). As Derek Sivers puts it, geography is four-dimensional: you can only know a place as it was at a time<sup id="fnref:3" role="doc-noteref"><a href="#fn:3" class="footnote" rel="footnote">3</a></sup>. Much of the Minnesota I love is stamped with a <em>when</em> I can only reach through faded memories.</p>

<p>— ᴘ. ᴍ. ʙ.</p>
<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1" role="doc-endnote">
      <p>Justin is technically a Sconnie, but Eau Claire is, what, an hour from the Minnesota border? I’m claiming him. <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:2" role="doc-endnote">
      <p>The rule was that we practice at anything above -5°F / ~-20°C (windchill not factored), and I distinctly remember the pain of thawing a foot in the chalet post-practice when it was right around that temperature cut-off. <a href="#fnref:2" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:3" role="doc-endnote">
      <p><a href="https://sive.rs/4d">Geography is four-dimensional</a> <a href="#fnref:3" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>]]></content><author><name>Paul Berens</name></author><category term="places" /><summary type="html"><![CDATA[A sensory tour through Minnesota's seasons]]></summary></entry><entry><title type="html">1 in 6,500,000</title><link href="https://berens.co/odds.html" rel="alternate" type="text/html" title="1 in 6,500,000" /><published>2026-06-03T00:00:00+00:00</published><updated>2026-06-03T00:00:00+00:00</updated><id>https://berens.co/odds</id><content type="html" xml:base="https://berens.co/odds.html"><![CDATA[<p>Yesterday, I headed out for a regular training run. It’s my <a href="/runs/twin-peaks-sutro/">Twin Peaks Mt. Sutro loop</a> that I crafted a few years ago and quite enjoy but don’t all that often: South Peak, North Peak, over to the UCSF trails on Mt. Sutro, down through the Parnassus Campus, and up Eighth Avenue toward home.</p>

<p>As I ascend the steps to the parking lot level of Twin Peaks, I meet two older women who ask a breathless me for directions. We chat briefly, they thank me for stopping—I didn’t have much of a choice given my aerobic condition—and then we go on our separate merry ways, them taking their time on the ascent of South Peak and me trying to get after it to train for the <a href="/runs/dipsea/">Dipsea Race</a>.</p>

<p><img src="/assets/og/post_mt-sutro-twin-peaks.jpg" alt="Mt Sutro and Twin Peaks" />
<span class="muted small">(L-R): Mt. Sutro, North Peak, and South Peak; as seen from our kitchen window on a lucky St. Patrick’s Day, 2025.</span></p>

<p>I’m heading up Eighth, some forty or forty-five minutes after the staircase encounter, rounding one of the last few blocks before home, and I take a second glance at a woman getting out of a car.</p>

<p><em>Did you just happen to be on Twin Peaks?</em> I ask.</p>

<p><em>You’re the same guy! Where do you live,</em> she inquires.</p>

<p>Less than a quarter mile away, it turns out. I assert that it was God’s Providence that we met not once but twice this day, because <strong><em>what are the odds?</em></strong></p>

<p>Indeed. What <em>are</em> they:</p>

<p>Well, we can safely assume Carol visits Twin Peaks infrequently since she and her friend had to ask for directions, so let’s be generous and peg that at one visit per annum—although it’s probably far less frequent in reality. The timing window of her arriving at her home and getting out of the car was perhaps thirty seconds wide since I was running and not walking by, against a plausible overlap window of twenty or thirty minutes, I’d guess: call it one in fifty odds.</p>

<table>
  <thead>
    <tr>
      <th style="text-align: left">Factor</th>
      <th style="text-align: left">Assumption</th>
      <th style="text-align: left">Odds</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left">I run this route</td>
      <td style="text-align: left">~10x/year</td>
      <td style="text-align: left">1 in 36 days</td>
    </tr>
    <tr>
      <td style="text-align: left">Carol visits Twin Peaks</td>
      <td style="text-align: left">~1x/year</td>
      <td style="text-align: left">1 in 365 days</td>
    </tr>
    <tr>
      <td style="text-align: left">We overlap on the mountain</td>
      <td style="text-align: left">My ~1hr window out of 10 daylight hrs</td>
      <td style="text-align: left">1 in 10</td>
    </tr>
    <tr>
      <td style="text-align: left"><strong>We are both there at the same time</strong></td>
      <td style="text-align: left">Combined above</td>
      <td style="text-align: left"><strong>1 in 131,400</strong></td>
    </tr>
    <tr>
      <td style="text-align: left">I pass her house as she exits her car</td>
      <td style="text-align: left">~30 sec overlap out of ~25 min plausible window</td>
      <td style="text-align: left">1 in 50</td>
    </tr>
    <tr>
      <td style="text-align: left"><strong>Combined probability</strong></td>
      <td style="text-align: left"> </td>
      <td style="text-align: left"><strong>1 in 6,500,000</strong></td>
    </tr>
  </tbody>
</table>

<p>But there’s another fun wrinkle: somewhere on the trail that runs along Twin Peaks Boulevard, a man had stopped me to confirm his route—a twenty-second exchange that may have been exactly the delay required to place me at the top of those stairs at the same time Carol and friend arrived. Pull that thread and you find another beneath it. The causality just doesn’t bottom out.</p>

<p>The tiny odds are amusing, but it’s also the texture of it—just think of how many frictionless near-misses must precede the one that lands.</p>

<p>Happy Global Running Day.</p>

<p>— ᴘ. ᴍ. ʙ.</p>]]></content><author><name>Paul Berens</name></author><category term="places" /><summary type="html"><![CDATA[A chance set of events.]]></summary></entry><entry><title type="html">Avenue of Mysteries</title><link href="https://berens.co/ave-mysteries.html" rel="alternate" type="text/html" title="Avenue of Mysteries" /><published>2026-05-19T00:00:00+00:00</published><updated>2026-05-19T00:00:00+00:00</updated><id>https://berens.co/ave-mysteries</id><content type="html" xml:base="https://berens.co/ave-mysteries.html"><![CDATA[<p><img src="/assets/og/bkreview_ave_mysteries.jpg" alt="Avenue of Mysteries by John Irving" style="width: 160px; height: auto;" /></p>

<p>I didn’t love it. And I <em>do</em> like Irving. But my problems were:</p>
<ol>
  <li>Catholic themes felt sacrilegious and unconvincing.
    <ul>
      <li>I may be too sensitive here, but Irving’s use of Catholic iconography came across as surface-level and hollow.</li>
      <li>The theology was too basic to engage with seriously. For example, Juan Diego holds the predictable progressive Catholic positions (pro-choice, anti-Church-on-sexuality) without ever really wrestling with them—they’re held as priors, not arrived at.</li>
      <li>In contrast, <em>A Prayer for Owen Meany</em>, which I read decades ago and loved; took faith, doubt, and providence a little more seriously</li>
    </ul>
  </li>
  <li>Too much lasciviousness for my taste. Call me prudish, but the erotic content (with Miriam and Dorothy mostly) felt gratuitous rather than purposeful.</li>
  <li>The heightened reality / myth-making—dump kids, a mind-reading sister, psychic lions—didn’t work for me. I mean, it was amusing/interesting in places but overall I couldn’t get into it.</li>
</ol>

<p>— ᴘ. ᴍ. ʙ.</p>]]></content><author><name>Paul Berens</name></author><category term="books" /><category term="theology" /><summary type="html"><![CDATA[]]></summary></entry><entry><title type="html">Humani Nihil a Me Alienum Puto</title><link href="https://berens.co/good-and-evil.html" rel="alternate" type="text/html" title="Humani Nihil a Me Alienum Puto" /><published>2026-05-06T00:00:00+00:00</published><updated>2026-05-06T00:00:00+00:00</updated><id>https://berens.co/good-and-evil</id><content type="html" xml:base="https://berens.co/good-and-evil.html"><![CDATA[<p>Remember Cops &amp; Robbers? It was clear: there were good guys and there were bad guys. The world made sense.</p>

<p>And then you get older, and life and literature<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup> instruct us that evil can be more nuanced: e.g., ends justify the means conflicts, the corruption of the good / redemption of the evil, etc.</p>

<p>But at the same time there are narratives that keep bringing us back to cosmic dualism: maybe best expressed in our <strong>cancel culture</strong> or <strong>true crime culture</strong> where we virtue signal through performative outrage.</p>

<p>The first move for those condemning others in the town square (Twitter/X, Substack, etc.) is to first to put some distance between themselves and the other guys: affirmation of self; discounting and forgetting my own sins. And then it’s: <em>oh, I would never do that. I would never say that. Because I’m not perfect, but at least I’m not like him…who is almost evil.</em><sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">2</a></sup></p>

<p>In fact there’s a concept called <strong>moral pollution</strong> which describes acting like bad reputations are contagious, and mere proximity to something labelled immoral is dangerous/toxic. Brands cut ties with people deemed unethical not because they value ethics, but because they fear contamination (cancellation as moral quarantine).</p>

<p>But Aleksandr I. Solzhenitsyn is much more thoughtful in <em>The Gulag Archipelago:</em></p>

<blockquote>
  <p>Gradually it was disclosed to me that the line separating good and evil passes not through states, nor between classes, nor between political parties either—but right through every human heart—and through all human hearts. This line shifts. Inside us, it oscillates with the years. And even within hearts overwhelmed by evil, one small bridgehead of good is retained. And even in the best of all hearts, there remains…an unuprooted small corner of evil.</p>
</blockquote>

<p>That’s not to say we can’t and ought not name evil and seek it out and fight it courageously, but it does mean that we should do so with humility and not triumphalism.<sup id="fnref:3" role="doc-noteref"><a href="#fn:3" class="footnote" rel="footnote">3</a></sup></p>

<p>The Roman playwright Terence put it this way: <em>Homo sum, humani nihil a me alienum puto</em> (“I am a human being; nothing human is alien to me.”) Maya Angelou returned to this line throughout her life, and explained why it matters:</p>

<blockquote>
  <p>‘I am a human being. Nothing human can be alien to me.’ If you can internalize at least a portion of that, you will never be able to say of an act, of a criminal act, ‘Well I couldn’t do that.’ No matter how heinous the crime, if a human being did it you have to say ‘I have in me all the components that are in her, or in him…’</p>
</blockquote>

<p>Because after all, sin <em>(mysterium iniquitatis)</em> entered the world and we’re naive if we deny it or put our blinders on. Remember the line from <em>The Usual Suspects</em>: “The greatest trick the Devil ever pulled was convincing the world he didn’t exist.” There’s indeed a dangerous trap to avoid: if I think myself too “good” I might move toward believing I’m not in need of a savior—save me from what?—which might mean I’ve already “earned” heaven from being such a good guy. This is <strong>Pelagianism</strong> and it’s rampant.</p>

<p>Revelation 3:16-17:</p>
<blockquote>
  <p>So, because you are lukewarm, neither hot nor cold, I will spit you out of my mouth. For you say, ‘I am rich and affluent and have no need of anything,’ and yet do not realize that you are wretched, pitiable, poor, blind, and naked.</p>
</blockquote>

<p>If that’s the Christian lens, the behavioral economics lens is the <a href="/systems/"><strong>Licensing Effect</strong></a>, where believing you’re good can actually make you behave badly: i.e., those who consider themselves virtuous worry less about their own behavior, making them more susceptible to ethical lapses.</p>

<p>And how do you end up considering yourself virtuous? By defining virtue<sup id="fnref:4" role="doc-noteref"><a href="#fn:4" class="footnote" rel="footnote">4</a></sup> yourself, on your own terms; as opposed to looking to scripture and law, the saints and philosophers, etc.</p>

<p>So what do we do with all this? We can’t stop naming and calling out and thwarting evil lest we succumb to cowardice — but that must be balanced with humility.</p>

<p>Dom Christian de Chergé was a Trappist monk who remained in Algeria knowing he would likely be killed…and was. Shortly before his martyrdom, he wrote: “I have lived long enough to know that I am an accomplice in the evil which seems to prevail so terribly in the world, even in the evil which might blindly strike me down.”</p>

<p><img src="/assets/og/post_taking_of_christ-caravaggio.jpg" alt="Taking of Christ, Caravaggio, 1602" />
<span class="muted small"><i>The Taking of Christ,</i> Caravaggio (c. 1602). The figure holding the lantern at right is believed to be Caravaggio himself — present at the betrayal, looking on. He doesn’t exempt himself from the scene…and neither can we.</span></p>

<p>Maybe the nuance here is that instead of letting people off the hook, there is still an accounting; but instead of demonizing and continuing to hold in contempt, this humility we speak of requires <strong>forgiveness</strong>. C. S. Lewis says that to be a Christian means to forgive the inexcusable because God has forgiven the inexcusable in you.</p>

<p>The theological ground for this is <em>Imago Dei</em>: that every human being, however contemptible by their actions and disfigured by sin, bears the image and likeness of God. Sin obscures that image, but cannot erase it. Despite everything, they remain a child of God—someone for whom Christ died.</p>

<p>This is the corrective to both the cancel culture impulse and the Pelagian trap: not the relativizing <em>I guess what they did wasn’t so bad,</em> but <em>I share in the same fallen nature, and I am commanded to love what God loves.</em></p>

<p>— ᴘ. ᴍ. ʙ.</p>
<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1" role="doc-endnote">
      <p><em>The Brothers Karamazov,</em> <em>Les Misérables,</em> <em>Hamlet,</em> <em>Fargo,</em> etc. <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:2" role="doc-endnote">
      <p>Aristotle noticed this, too: in his <em>Nicomachean Ethics</em> IX.4 he observes that ordinary men, “poor creatures though they may be,” exhibit the marks of self-friendship precisely because they are “satisfied with themselves and think they are good.” <a href="#fnref:2" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:3" role="doc-endnote">
      <p>St. Nicholas remembered this about all children: in Hungary he leaves both treats and some twigs (a switch), because no one is either all good nor all bad. <a href="#fnref:3" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:4" role="doc-endnote">
      <p>I won’t go all the way down the relativism rabbit hole, but this reminds me of Bishop Robert Barron’s frequent citation of the 1992 Supreme Court case <em>Planned Parenthood v. Casey</em>, where he highlights the passage authored by Justice Kennedy: “At the heart of liberty is the right to define one’s own concept of existence, of meaning, of the universe, and of the mystery of human life.” <a href="#fnref:4" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>]]></content><author><name>Paul Berens</name></author><category term="theology" /><category term="culture" /><category term="first principles" /><summary type="html"><![CDATA[The line separating good and evil passes not through states, nor classes, nor political parties; but through every human heart.]]></summary></entry><entry><title type="html">Swarma</title><link href="https://berens.co/swarma-app.html" rel="alternate" type="text/html" title="Swarma" /><published>2026-03-29T00:00:00+00:00</published><updated>2026-03-29T00:00:00+00:00</updated><id>https://berens.co/swarma-app</id><content type="html" xml:base="https://berens.co/swarma-app.html"><![CDATA[<p>I’m old school fringe consumer tech: <a href="https://en.wikipedia.org/wiki/Path_(social_network)">Path</a> for social media, <a href="https://en.wikipedia.org/wiki/Songza">Songza</a> for music, Foursquare—now <a href="https://swarmapp.com/">Swarm</a>—for lifelogging.</p>

<p>I’ve also deepened my commitment to Google hardware over the years—first Google Home, then <a href="/phones/">Pixel phone</a>, now Pixel Watch.</p>

<p>But there’s no Swarm app on Wear OS (!), which leaves the 63 of us in this cross-sectional segment with a choice: find and beg a Swarm product manager to prioritize it in the backlog, or vibe-code it.</p>

<p>Option B is a lot more realistic (and fun), and thus <strong>Swarma</strong>™ (pronounced <em>shawarma)</em> was born.</p>

<p>This is my third or fourth <a href="/vibe-coding.html">vibe-coding</a> project with Claude as co-pilot: I’ve done <a href="/now/">APIs</a>, a <a href="/song-bot.html">Telegram bot</a>, <a href="/dark-mode.html">dark mode</a>, etc. The pattern is familiar by now: describe what I want, iterate, and ship it. But this time the <em>platform</em> was completely new to me: Android Studio, Kotlin, Jetpack Compose, Wear OS.</p>

<p>The core app logic came together relatively easily: hitting the Foursquare Places API, grabbing nearby venues, displaying a scrollable list, etc. Then Claude handled the Kotlin syntax, the Compose UI components, the API calls, same as it would in JavaScript or Python.</p>

<p>What <em>wasn’t</em> interchangeable was everything around the code:</p>

<ul>
  <li><strong>Environment.</strong> Android Studio generated a project that immediately failed to build. Then a Gradle plugin version didn’t exist. And my corporate VPN was silently blocking downloads via SSL inspection—🤫. Next the Wear OS template ships with the wrong UI library. And finally the app crashes on first launch for missing permissions that the compiler never warned me about. So all of the above you’d chalk up to platform faffing; not coding problems. So I just spent more cycles having Claude diagnose them, because in many cases I didn’t know the right questions to ask (or the best way to ask them).</li>
  <li><strong>UX decisions.</strong> Lo and behold, the Foursquare API treats the radius parameter as a suggestion; not a hard limit, and so venues were populating 8km away when I’d asked for 300 meters. An actual product decision: do I trust the API’s venue ranking, or enforce my own filtering and sorting? I’ve tested various tunings and have landed at a good middle ground, methinks, but the points is that a co-pilot doesn’t have all the product context to make that call.</li>
  <li><strong>OAuth on a browserless device.</strong> The app needs Foursquare authentication, which means OAuth, which means a browser, but wait: there <em>is</em> no browser on Wear OS. I hadn’t thought of how to get the token in there so my first design had a form field where I actually had to bang in the 48-character token on the watch keyboard, which is either comical or infuriating depending on how much sleep you got the night before. This led me to create a companion phone app, which would open a Chrome Custom Tab, intercept the OAuth redirect via authorization code flow, and send the token to the watch via Bluetooth. Minimal, one-time setup.<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup></li>
</ul>

<p>Vibe-coding scales to unfamiliar platforms as long as you can identify and decompose the problem. The AI handles syntax and boilerplate. So it seems the hard parts of building have shifted from the code (implementation) to everything else: environment, architecture, product judgment, platform constraints…at least where I sit here in early 2026<sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">2</a></sup>.</p>

<p>The whole thing—from opening Android Studio for the first time to checking into a Foursquare venue from my watch—took about an afternoon (a.k.a. naptime) to get sorted. Whether anyone else actually will want this is an open question, but at least I’ve solved for my own need.</p>

<p><img src="/assets/og/swarma/pixel.app.drawer.png" alt="Swarma on Pixel Watch" /><span class="muted small">Swarma v1.0, as side-loaded on my Pixel Watch.</span></p>

<p>Swarm lives on my Pixel Watch 🤘</p>

<p>— ᴘ. ᴍ. ʙ.</p>
<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1" role="doc-endnote">
      <p>The first version of the companion app used a WebView instead of a Chrome Custom Tab—meaning users were authenticating inside my app rather than on Foursquare’s own site. A tester on the Wear OS subreddit (<a href="https://www.reddit.com/user/sorross/">u/sorross</a>) flagged it immediately as a bad design (why would I feel comfortable giving a third party app full account control?). He was right, and so I took an hour and fixed it. The co-pilot had taken the path of least resistance, but a savvy human caught it. Which is another lesson here. <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:2" role="doc-endnote">
      <p>I’m confident this post will age rapidly. <a href="#fnref:2" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>]]></content><author><name>Paul Berens</name></author><category term="tech" /><category term="product" /><summary type="html"><![CDATA[What vibe-coding a wearable app taught me about where the hard parts have shifted.]]></summary></entry><entry><title type="html">Desirable Difficulties</title><link href="https://berens.co/spanish.html" rel="alternate" type="text/html" title="Desirable Difficulties" /><published>2026-02-27T00:00:00+00:00</published><updated>2026-02-27T00:00:00+00:00</updated><id>https://berens.co/spanish</id><content type="html" xml:base="https://berens.co/spanish.html"><![CDATA[<p>People are always surprised when they find out I speak Spanish. I don’t speak perfectly, but well enough to hold a real conversation, and well enough that occasionally someone asks <em>¿De qué país son tus padres?</em> Which is the real compliment.</p>

<p>But the more common question is <em>¿Cómo aprendiste el español?</em> and I find that question itself telling. In the US, while we all take language classes in school, virtually no one ends up even passably proficient…so much so that there’s not even an expectation. The richest country in the world, and we seem to have made our peace with monolingualism, conveniently blaming geography and the global dominance of English.</p>

<p>My path was accidental, and it started with my one-of-a-kind seventh-grade Spanish teacher, Sr. David Donch.</p>

<h2 id="el-señor-donch">El Señor Donch</h2>

<p>David Donch is a New Jersey native who joined the Peace Corps in his youth, ended up in Venezuela, and didn’t come back until he brought a beautiful Venezolana home with him. He was unconventional in the best sense: he threw out the textbook—which I’m sure cost him countless hours of curriculum development—and replaced it with vocab bingo cards and audio cassettes. (To this day I associate <em>la sal</em> and <em>el azúcar</em> together because they shared a bingo square.)</p>

<p>When I moved to a different school the following year, my new Spanish teacher was a <em>gringa</em> with a flat accent and a standard-issue textbook (“turn to page 78 for today’s lesson”). So Sr. Donch graciously agreed to tutor me, and he’d make the trek across St. Paul to our house. Then one day he mentioned he needed to repair the roof of his casita in the Venezuelan Andes, and suggested I (and a couple other students) come along to really learn the language. And do some fly fishing.</p>

<p>I was fourteen. My parents (amazingly) said yes. And it changed everything.</p>

<h2 id="my-month-in-venezuela-at-age-14">My Month in Venezuela at Age 14</h2>

<p>We landed in Maracaibo with duffel bags, my very first passport, and an English-Spanish dictionary. The first night we stayed with friends of Sr. Donch’s, and I sat there absorbing the language—or trying my best to—while missing the vast majority of it. Total sensory overload. Would I like something to drink? <em>¿Coca?</em> (that is, <em>Cocaine?</em>)—instead of <em>una Coca-Cola</em>. The place erupted. The heat rose in my cheeks as I laughed at myself…embarrassment is an extraordinarily effective teacher.</p>

<p>But no one tells you that you have to be willing to look like an idiot to learn a language. That there’s really no other path forward. Actually, you can extend that beyond langauge to nearly anything. Shane Parrish puts it well: “we’re often unwilling to look foolish in the short term to succeed in the long term.” And that trade-off isn’t optional: you either make the mistakes or you don’t learn; full stop.</p>

<p>The other aspect of this was the fullness of the immersion. We spent the majority of the trip in the beautiful mountainous state of Trujillo, where very few people spoke English—and Mr. Donch was pretty good about not bailing me out. It was a full commit, which was hard at first. But it was a gift to not be placed with a host family where English creeps back in at the dinner table, or being surrounded by fellow English speakers the way so many study abroad programs inadvertently arrange things…where your native tongue becomes a constant refuge and the whole point is quietly defeated.</p>

<h2 id="the-mechanics">The Mechanics</h2>

<p>Looking back, a few things stand out that I think generalize beyond Spanish:</p>

<p>One has to let language wash over you rather than chase every word. If you try to translate everything in real time, you’ll fall behind and miss what comes next. But here’s the thing: we naturally do this in our native language without realizing it. Have you ever been half-listening to someone and suddenly gotten caught off guard by an unexpected turn of phrase (because you’d already mentally finished their sentence for them)? I’m often aware of myself doing this. There’s a technical term for this: <strong>collocation</strong>—the phenomenon where certain words reliably travel together, and a fluent brain learns to anticipate the pairing. Salt pulls pepper; trial pulls error. In corpus linguistics it’s defined as words that co-occur more often than chance would predict, but experientially it’s just what normal fluency feels like. But when you’re learning a new language, and you don’t have those grooves yet, every phrase is a surprise, which is why immersion works: you’re forcing those associations at speed. At some point you stop translating and just start anticipating, which is how and when things unlock.</p>

<p><strong>Accent matters</strong> more than you might think, and for an unexpected reason. I ended up sounding reasonably native—partly, I think, because of an ear trained by music and years of mimicking sounds—while having vocabulary gaps that a native six-year-old wouldn’t have. But the effect was that native speakers engaged with me <em>as if</em> I knew what I was doing. They didn’t switch to English out of pity but rather kept going since I sounded somewhat legit. Compare this to others I know who have impeccable grammar (correct tenses and conjugation, etc.), but comically American accents: and watch how native speakers will jump to bail them out, which is nice but, of course, hinders improvement. The friction I got from <em>sounding</em> like I belonged was itself a form of instruction.</p>

<p>Memory works through collision and surprise. <em>Sal</em> and <em>azúcar</em> are fused in my brain because they bumped into each other on that bingo card. The <em>cocaína</em> incident is seared in because it was a learning moment. As I understand it, these are what cognitive science researchers call <strong>desirable difficulties</strong>, the counterintuitive finding that harder, less comfortable learning conditions produce better long-term retention than easy, smooth ones. Fluency isn’t built through frictionless repetition but rather through the moments that make you catch yourself and recalibrate.</p>

<h2 id="the-ai-question">The AI Question</h2>

<p>AI is close to making real-time translation seamless, where you’ll be able to speak to anyone in any language and be understood, without ever having learned a word. Does that mean learning a language will be a thing of the past? I don’t know. Probably not in the short-term as there are still latency issues and the clumsiness of having devices in the mix.</p>

<p>But the better question is what AI does to the process of learning itself (langauge included).</p>

<p>Done right, an AI tutor could be extraordinary: infinitely patient, available at one o’clock in the morning, able to accommodate your precise needs relative to where you are in the learning process. Conversational AI built specifically to teach could in some ways replicate the immersive pressure I felt in Trujillo without requiring a plane ticket.</p>

<p>The danger now is using AI to just get to the answer and avoid the cognitive struggle, or in language, avoid the embarrassment of the wrong word when you can simply not speak and let the tool speak for you. The risk is that AI removes friction entirely for everyone, regardless of style, if we let it.</p>

<p>And here’s what I keep coming back to: even if tinkerers and systematizers learn differently, even if some people need structure and others need to poke at things until they yield, I suspect there’s a floor of friction below which nobody actually learns. The form of difficulty may vary, but difficulty itself doesn’t.</p>

<p>Sr. Donch intuitively understood this, which is why he deliberately didn’t make things easy. He made things <em>interesting,</em> and then he made things <em>hard</em> in the right ways: bingo cards as a mnemonic device, a total-immersion trip with no English escape hatch.</p>

<p>The question for anyone building AI tools is whether we’re designing for that same principle, or whether we’re quietly engineering away the very resistance that produces learning.</p>

<p>¿Entendiste, pues?</p>

<p>— ᴘ. ᴍ. ʙ.</p>]]></content><author><name>Paul Berens</name></author><category term="culture" /><category term="american identity" /><summary type="html"><![CDATA[Learning a language as a template for learning anything]]></summary></entry><entry><title type="html">Claude Code, Dark Mode</title><link href="https://berens.co/dark-mode.html" rel="alternate" type="text/html" title="Claude Code, Dark Mode" /><published>2026-01-23T00:00:00+00:00</published><updated>2026-01-23T00:00:00+00:00</updated><id>https://berens.co/dark-mode</id><content type="html" xml:base="https://berens.co/dark-mode.html"><![CDATA[<p>Ladies and Gentlemen, at long last…by popular demand…I give you…</p>

<p><strong><em>…dark mode on berens.co</em></strong><sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup> [Cue rampageous applause.]</p>

<p><img src="/assets/og/post_dark_mode.png" alt="Introducing Dark Mode on berens.co" />
<span class="muted small">Dark Mode insisted on a lifestyle photoshoot before going live.</span></p>

<h2 id="clarification">Clarification</h2>

<p>Hold up. <em>(Screeching brakes.)</em></p>

<p>This post isn’t so much about the wonders of dark mode on my website as about <em>how it was achieved</em>.</p>

<h2 id="background">Background</h2>

<p>Last October I chronicled my experience <a href="/vibe-coding.html">“vibe coding”</a>—building things through AI-assisted trial and error without formal programming knowledge—and then again in November on how I used an LLM to spin up <a href="/song-bot.html">my first bot</a>. That workflow looked like this: describe what I want → Claude generates code snippets → I copy the code → I paste it into the right file → I save the file → I commit to git → I push to GitHub → the site rebuilds → I test it → if it fails, I report the error and repeat.</p>

<p>It worked, but it was pretty manual and the onus was on me to move code around and ensure everything ends up in the right place.</p>

<p>Then I discovered <strong>Claude Code</strong> and old-school vibe coding instantly became dial-up internet.</p>

<p>For those unfamiliar, Claude Code is a command-line tool that connects to your GitHub repository and can read, write, debug, and test code directly in your codebase—all through natural language commands. Basically your own AI coding assistant or “pair programmer”.</p>

<h2 id="the-dark-mode-case-study">The Dark Mode Case Study</h2>

<p>I needed a project to test drive it: how about building dark mode, everyone’s favorite UI enhancement. I pointed it at berens.co, authenticated, and it was ready to work directly in my codebase.</p>

<p>In the old vibe coding workflow, this would have meant dozens of copy-paste cycles across multiple files—CSS variables, media queries, template updates, testing each piece. Instead, I opened Claude Code and typed: “what’s the simplest way to implement a ‘dark mode’ on my current setup; one that inherits the ‘system preference’ of the browser?”</p>

<p>Claude Code didn’t just spit out some generic code. It read my entire site structure to understand the setup, analyzed my current CSS file, then converted all hardcoded colors to CSS custom properties. It created a complete <code class="language-plaintext highlighter-rouge">@media (prefers-color-scheme: dark)</code> section with a carefully chosen dark color palette, added the proper meta tag to my HTML header, tested the implementation, and committed everything to a new git branch.</p>

<p><strong>My role?</strong> Overbearing supervisor and critic. I looked at the preview and said “here’s a better color palette” (showing a screenshot). Claude Code adjusted. I mentioned “the table headers need work”—it read <code class="language-plaintext highlighter-rouge">pages/today.md</code>, identified the issue, and fixed it. Back and forth we went, refining details:</p>

<ul>
  <li>“The input boxes should be darker”</li>
  <li>“The highlighting is too faint”</li>
  <li>“Kill those right borders”</li>
  <li>“Make the left border invisible unless it’s highlighting”</li>
  <li>“Do me a favor and lose five pounds immediately or get out of my building like now!”</li>
</ul>

<p>Each time, Claude Code read the relevant files, understood the context, made the changes, tested them, and committed them. I never opened my code editor nor touched git. I just hollered out what I wanted.</p>

<p><img src="/assets/og/post_claude_code.png" alt="Claude Code doing its thing" />
<span class="muted small">Claude Code taking the wheel.</span></p>

<h2 id="this-is-agentic-ai">This Is Agentic AI</h2>

<p>This was my first real experience with an <strong>agentic AI</strong>—an AI that doesn’t just generate outputs for you to handle, but actually takes actions in your environment.</p>

<p>The difference is astounding. With my original vibe coding, “Advisory Claude” generates the code; whereas here Claude Code actually builds the feature itself. Advisory Claude gives me the recipe; Claude Code cooks dinner. Advisory Claude gives me directions; Claude Code is the autonomous vehicle that drives us there.</p>

<p>It’s not that one is smarter than the other—they’re using the same underlying model—it’s that Claude Code has <em>agency</em> in that it can read files, edit them, run tests, commit changes. It operates in my development environment like a junior developer who’s skilled at interpreting my terrible, inexact prompts.</p>

<h3 id="near-zero-learning-curve">Near-Zero Learning Curve</h3>

<p>Because I was already fluent in traditional vibe coding—hey, I should add that to my résumé—there’s really no ramp to Claude Code. It’s essentially the same process:</p>
<ul>
  <li>Describe desired outcomes clearly</li>
  <li>Provide visual feedback (screenshots)</li>
  <li>Iterate on details</li>
  <li>Recognize when something isn’t quite right</li>
</ul>

<p>So it’s the same process as with Advisory Claude; the only difference was that now I didn’t have to be the one moving the pieces around.</p>

<h2 id="what-this-means">What This Means</h2>

<p>The barrier to building things is shifting from “can I figure out how to code this?” to “can I convey what I want?” If you’ve been vibe coding you’re already positioned for this shift.</p>

<p>For most, the future isn’t about becoming a traditional developer. It’s about being able to articulate what you want to build, recognize when it’s right, and iterate until it works.</p>

<p>Feels about right to me: the computer handles syntax, file structure, and other minutiae; the humans worry about design, taste, and imagination.</p>

<p>But I, for one, welcome our agentic overlords.</p>

<p>— ᴘ. ᴍ. ʙ.</p>
<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1" role="doc-endnote">
      <p>Still seeing light mode? That’s because your system or browser is set that way—the <a href="/colophon/">colophon</a> shows what we detected. Flip the preference in your OS or browser and the page will update right away. <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>]]></content><author><name>Paul Berens</name></author><category term="tech" /><category term="product" /><summary type="html"><![CDATA[Hey, Claude Code, make me a sandwich!]]></summary></entry></feed>