<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>OOER</title>
    <link>https://ooer.com/</link>
    <description>Tech, frontend, and how the web came to be the way it is. Mostly stories about things that misbehaved, and what they turned out to be.</description>
    <language>en-GB</language>
    <lastBuildDate>Tue, 25 Aug 2026 00:00:00 GMT</lastBuildDate>
    <atom:link href="https://ooer.com/feed.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>What the model can't see</title>
      <link>https://ooer.com/posts/what-the-model-cant-see/</link>
      <guid isPermaLink="false">what-the-model-cant-see</guid>
      <pubDate>Tue, 25 Aug 2026 00:00:00 GMT</pubDate>
      <description>LLM debugging on the frontend is an observation problem, not a code-reading one.</description>
      <content:encoded><![CDATA[<p>An LLM debugs your frontend in proportion to what you let it observe, not in proportion to how much of your code it’s read.</p>
<p>The usual way to use one is as a very fast code reader. You hit an error and paste the stack trace and the offending component into a chat window, and something that has seen ten thousand versions of that mistake tells you which line is wrong. It works, and it’s faster than reading the file yourself. If you’re not doing it you’re leaving time on the table for nothing at all.</p>
<p>Notice what kind of bug that is though. It’s the sort where the code is wrong on its face: the missing dependency, the await that isn’t there, the effect that sets the state it depends on and spins forever. Bugs like that are visible in the text, which means you could have found them yourself by reading slowly and the model has just read slowly at a speed you can’t match.</p>
<p>The bugs that cost you a day aren’t like that. The code is fine in every sense that a reviewer would recognise. It’s correct and it’s idiomatic and it would pass anything you put it through. The page still does something stupid on a Tuesday for one customer on Safari. Nothing in the file will tell you why (the file is not where the fault is) because the fault is in the state the browser was in at the moment the code ran, and that browser is four hundred miles away on a laptop you will never touch.</p>
<p>So the expensive part of frontend debugging has never been the fix: it’s the reproduction, and once you can make the thing happen on demand with the elements in front of you and a breakpoint in the right place the fix is usually a few minutes of work and quite often embarrassingly obvious. Which is why the biggest single change you can make to how a model performs here is giving it a browser. Point it at a real page through Playwright or something like it and let it click the thing, read the console, dump the computed styles and take a screenshot. It then stops working from your description of the problem and starts working from the problem itself. I’ve had Claude debug GLSL shaders running in WebGL that way and it isn’t a thing it could have done from source.</p>
<p>The model doesn’t get cleverer when you do any of that. What changes is that a model with nothing to observe will still answer you, and what comes back is the most statistically plausible cause of a bug resembling the one you described. The correct response to a question you haven’t been given enough information to answer is a clarifying question, and that is the response you will almost never get. Anything else rests on an assumption that could be wrong. Sometimes it’ll be right and sometimes it won’t. Deciding which of those you are holding lies entirely with you.</p>
<p>Wrong code can’t fool you for long because you can run it and code that doesn’t work is immediately and obviously broken. A wrong explanation isn’t like that. Nothing executes it and nothing fails, so instead it sits in your head quietly shaping what you look at next. That’s where the damage is, because every plausible fix is locally reasonable. You apply it and the bug is still there, so you say so and you get handed the next most plausible cause instead, and five rounds later you’re holding five speculative changes and a mental model assembled out of the model’s guesses (rather than out of anything you saw happen). The original bug hasn’t moved an inch the whole time.</p>
<p>There’s a second thing it can’t see and that’s the machine. Web devs have always shipped things that aren’t slow on the Macbook they were written on, and then a user on a cheap Windows laptop can’t click anything. A model, by contrast, has no machine at all. Throttle the CPU and throttle the network and run the thing against something like what your users are really holding, because a class of bug that doesn’t exist in the environment you handed over is a class of bug it’s never going to find.</p>
<p>Data tells the same story. Bugs live in the long name and the empty array and the thirty second response and the record from 2014 with a null in a column that’s been non-null since 2016. Give the model your seed fixtures and it’ll tell you the component is fine (it is fine) and you’ll be no further forward than when you started.</p>
<p>And then there’s the class where none of this helps at all. Most bugs in shipped software are entirely valid code. Someone wrote something good that does the wrong thing because what the right thing was had never been pinned down properly. No amount of observation surfaces that, because the page is doing exactly what it was built to do, and the model has no access whatsoever to the thing it should have been built to do instead. It won’t flag that situation either, which is the part that should worry you. Ask it why the checkout total is wrong and it’ll find you a rounding error, because you asked it for a bug and it’s an obliging sort of thing. Knowing what correct actually looks like is still your job, and it’s still the hard part of the work.</p>
<p>None of this makes it a small tool, and it would be daft to read it that way. It’s an enormous one, and it’s improving fast enough that any confident statement about where its limits sit will look silly inside a year. The thing worth investing in isn’t the model though. It’s the pipe between your running application and the model, and that’s dull work so most people skip it (and then conclude from the wreckage that the model is bad at debugging).</p>
<p>What you’re left with is the job you always had. You still have to understand the code well enough to fix what you can’t prompt your way out of, you still have to know what right looks like before you can tell whether you’re looking at it, and you still have to be accountable for whatever you commit. All it really removes is the part where you type it in.</p>
]]></content:encoded>
      <category>ai</category>
      <category>frontend</category>
    </item>
    <item>
      <title>First transmission</title>
      <link>https://ooer.com/posts/first-transmission/</link>
      <guid isPermaLink="false">first-transmission</guid>
      <pubDate>Fri, 14 Aug 2026 00:00:00 GMT</pubDate>
      <description>What this place is for and who is talking.</description>
      <content:encoded><![CDATA[<p>Every blog opens with a post explaining why the blog exists, and every one of
them is skipped. This one is short in acknowledgement of that.</p>
<h2 id="what-this-is">What this is</h2>
<p>Notes on the web — how it is built now, and how it came to be built that way.
Frontend mostly, because that is what I have spent my time on, with regular
detours into the decisions that got made in 1996 and are still load-bearing.</p>
<h2 id="what-this-is-not">What this is not</h2>
<p>A tutorial site. There are enough of those, and most of them are wrong in the
same three ways. If something here reads like instruction, it is probably a
warning that has been misfiled.</p>
<p>The rest of the archive is more interesting than this page. Start anywhere.</p>
]]></content:encoded>
      <category>meta</category>
    </item>
    <item>
      <title>A one-pixel image was a layout engine</title>
      <link>https://ooer.com/posts/spacer-gif/</link>
      <guid isPermaLink="false">spacer-gif</guid>
      <pubDate>Tue, 11 Aug 2026 00:00:00 GMT</pubDate>
      <description>A short note on building pages out of transparent GIFs.</description>
      <content:encoded><![CDATA[<p>The interesting thing about the spacer GIF is not that it was a hack. It is that
it was a <em>good</em> hack, in the sense that it worked reliably across implementations
that agreed on almost nothing else.</p>
<p>A transparent single-pixel image, stretched with <code>width</code> and <code>height</code>, gave you
the one thing HTML would not: a box of an exact size that survived the trip
through four browsers with four different opinions about whitespace. It was
sound engineering against the platform that actually existed rather than the one
in the specification.</p>
<p>What replaced it was not a better hack. It was the platform finally growing the
feature — margins that collapse predictably, then flexbox, then grid. That is
the pattern the whole history follows, and the spacer GIF is the cleanest
example of it: the workaround is a bug report written in production traffic, and
eventually somebody reads it.</p>
]]></content:encoded>
      <category>history</category>
      <category>nostalgia</category>
    </item>
    <item>
      <title>Nothing on the web is ever removed</title>
      <link>https://ooer.com/posts/nothing-is-removed/</link>
      <guid isPermaLink="false">nothing-is-removed</guid>
      <pubDate>Sat, 08 Aug 2026 00:00:00 GMT</pubDate>
      <description>On deprecation as a social process rather than a technical one, and why the pile only grows.</description>
      <content:encoded><![CDATA[<p>Deprecation on the web means something different to deprecation anywhere else. In
most systems it is a schedule: marked in one release, warned about in the next,
gone in the one after. On the web it is a mood. Something is deprecated when the
people writing the specification would prefer you stopped, and that is the entire
mechanism.</p>
<h2 id="the-pile-only-grows">The pile only grows</h2>
<p>It is worth being concrete about how little actually leaves.</p>
<table>
<thead>
<tr>
<th>Feature</th>
<th>Deprecated</th>
<th>Still works today</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>&lt;center&gt;</code></td>
<td>1998</td>
<td>Yes</td>
</tr>
<tr>
<td><code>document.write</code></td>
<td>Discouraged for ~15 years</td>
<td>Yes</td>
</tr>
<tr>
<td>Quirks mode</td>
<td>Superseded by standards mode</td>
<td>Yes</td>
</tr>
<tr>
<td><code>&lt;marquee&gt;</code></td>
<td>Never standardised at all</td>
<td>Yes</td>
</tr>
<tr>
<td>Third-party cookies</td>
<td>Announced dead repeatedly</td>
<td>Complicated</td>
</tr>
</tbody>
</table>
<p>Only the last row is genuinely contested, and it is contested because it is the
only one where somebody with commercial leverage wanted it gone. That is the
tell. Removal is not a technical capability the browsers lack; it is a political
one they rarely have.</p>
<h2 id="why-the-constraint-is-real">Why the constraint is real</h2>
<p>The reason is the same one it has always been: nobody can redeploy the web. There
is no version of the corpus that gets recompiled. A page written in 1997 by
someone who has since died is still served, still requested, and a browser that
breaks it has broken the web rather than fixed it.</p>
<blockquote>
<p>The install base is not the browsers. The install base is every document ever
published, and it does not accept patches.</p>
</blockquote>
<p>This is a genuinely unusual engineering constraint and it deserves more respect
than it gets. Most of the platform’s apparent incoherence is the cost of it, paid
honestly.</p>
<h2 id="where-it-actually-bites">Where it actually bites</h2>
<p>The cost is not the dead features — those are inert and cheap. It is that every
new feature must be designed to coexist with the entire history, and that shows
up as syntax nobody would choose fresh. Cascade layers exist in the shape they do
because they had to slot into a cascade that could not change underneath them.</p>
<p>That is not a compromise imposed on good design. It <em>is</em> the design problem, and
the specifications that ignore it are the ones that never ship.</p>
]]></content:encoded>
      <category>history</category>
      <category>standards</category>
      <category>long-read</category>
    </item>
    <item>
      <title>Cascade layers settled an argument from 1998</title>
      <link>https://ooer.com/posts/cascade-argument/</link>
      <guid isPermaLink="false">cascade-argument</guid>
      <pubDate>Tue, 04 Aug 2026 00:00:00 GMT</pubDate>
      <description>Notes on specificity, and the twenty-five years spent working around it.</description>
      <content:encoded><![CDATA[<p>Specificity was always the part of CSS that people worked around rather than
with. Every methodology of the last two decades — BEM, utility classes, CSS-in-JS
scoping — is at bottom a strategy for never having to lose a specificity fight.</p>
<h2 id="the-workaround-era">The workaround era</h2>
<p>The honest description of what most codebases did is: keep every selector at the
same weight, so the cascade degenerates into source order, which is a thing
humans can actually reason about.</p>
<pre class="astro-code ooer" style="background-color:#14121c;color:#e8ecf5; overflow-x: auto;" tabindex="0" data-language="css"><code><span class="line"><span style="color:#98A0B5;font-style:italic">/* one class, always, forever — the whole methodology in one line */</span></span>
<span class="line"><span style="color:#E8ECF5">.</span><span style="color:#C9A9FF">card__title</span><span style="color:#E8ECF5"> { </span><span style="color:#7FE4F5">font-size</span><span style="color:#E8ECF5">: </span><span style="color:#FFC46B">1.25</span><span style="color:#FF8FC4">rem</span><span style="color:#E8ECF5">; }</span></span>
<span class="line"><span style="color:#E8ECF5">.</span><span style="color:#C9A9FF">card__title--muted</span><span style="color:#E8ECF5"> { </span><span style="color:#7FE4F5">color</span><span style="color:#E8ECF5">: #</span><span style="color:#FFC46B">7b88a4</span><span style="color:#E8ECF5">; }</span></span></code></pre>
<p>It worked, and it cost you the ability to express <em>intent</em>. A reset and a
component override are conceptually different kinds of rule, and flattening them
to the same weight throws that information away.</p>
<h2 id="what-layers-change">What layers change</h2>
<p><code>@layer</code> lets you say which bucket a rule belongs to, and the bucket wins before
specificity is consulted at all:</p>
<pre class="astro-code ooer" style="background-color:#14121c;color:#e8ecf5; overflow-x: auto;" tabindex="0" data-language="css"><code><span class="line"><span style="color:#E8ECF5">@</span><span style="color:#FF8FC4">layer</span><span style="color:#E8ECF5"> reset, base, components, utilities;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#E8ECF5">@</span><span style="color:#FF8FC4">layer</span><span style="color:#E8ECF5"> components {</span></span>
<span class="line"><span style="color:#E8ECF5">  #</span><span style="color:#C9A9FF">sidebar</span><span style="color:#E8ECF5"> .</span><span style="color:#C9A9FF">card__title</span><span style="color:#E8ECF5"> { </span><span style="color:#7FE4F5">color</span><span style="color:#E8ECF5">: </span><span style="color:#7FE4F5">var</span><span style="color:#E8ECF5">(</span><span style="color:#C9A9FF">--c-ink</span><span style="color:#E8ECF5">); }</span></span>
<span class="line"><span style="color:#E8ECF5">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#E8ECF5">@</span><span style="color:#FF8FC4">layer</span><span style="color:#E8ECF5"> utilities {</span></span>
<span class="line"><span style="color:#E8ECF5">  .</span><span style="color:#C9A9FF">u-muted</span><span style="color:#E8ECF5"> { </span><span style="color:#7FE4F5">color</span><span style="color:#E8ECF5">: </span><span style="color:#7FE4F5">var</span><span style="color:#E8ECF5">(</span><span style="color:#C9A9FF">--c-ink-faint</span><span style="color:#E8ECF5">); }  </span><span style="color:#98A0B5;font-style:italic">/* wins anyway */</span></span>
<span class="line"><span style="color:#E8ECF5">}</span></span></code></pre>
<p>The utility wins despite the ID in the component selector, because layer order
outranks specificity entirely. That single ID would previously have needed 100
points of counter-specificity or an <code>!important</code>, and now it needs nothing.</p>
<h2 id="the-part-worth-noticing">The part worth noticing</h2>
<p>This is the same story as the spacer GIF, one layer up. The methodologies were
not wrong; they were a workaround for a missing feature, deployed at enormous
scale, for long enough that everyone forgot it was a workaround and started
teaching it as architecture.</p>
<p>The interesting question is which of today’s conventions are the same thing, and
we will not know for another decade.</p>
]]></content:encoded>
      <category>css</category>
      <category>frontend</category>
    </item>
    <item>
      <title>It was never the bundle</title>
      <link>https://ooer.com/posts/not-the-bundle/</link>
      <guid isPermaLink="false">not-the-bundle</guid>
      <pubDate>Wed, 29 Jul 2026 00:00:00 GMT</pubDate>
      <description>A week spent making a page faster, and where the time actually went.</description>
      <content:encoded><![CDATA[<p>I spent a week on a page that everyone agreed was slow, with a shared assumption
that the JavaScript was to blame. The JavaScript was not to blame. It is worth
writing down what was, because the ordering surprised me.</p>
<h2 id="what-actually-cost-time">What actually cost time</h2>
<p>Roughly in order of severity:</p>
<ol>
<li><strong>A font that blocked first paint for 800ms.</strong> Self-hosted, no <code>font-display</code>,
and it was serving four weights of which the page used one.</li>
<li><strong>Three round trips before any content byte.</strong> A redirect, then a redirect to
add a trailing slash, then the document.</li>
<li><strong>An image sized for a display nobody had.</strong> 2400px wide, rendered at 380,
and it was above the fold so it competed with everything.</li>
<li><strong>The bundle.</strong> Real, measurable, and roughly a quarter of the total — which
is to say the thing everyone was arguing about was the fourth-largest problem.</li>
</ol>
<h2 id="why-the-ordering-is-predictable">Why the ordering is predictable</h2>
<p>The first three are all <em>latency</em> and the fourth is <em>throughput</em>, and latency has
not improved at anything like the rate bandwidth has. A 4G connection today moves
far more bytes per second than a 2010 connection but the round trip costs about
the same, so anything serialised is disproportionately expensive and stays that
way.</p>
<p>Bundle size is the thing that is easy to measure, easy to graph, and easy to
assign to a team. That is why it absorbs the attention. The waterfall is harder
to look at and is where the answer usually is.</p>
<h2 id="the-unsatisfying-conclusion">The unsatisfying conclusion</h2>
<p>We shipped the font fix and the redirect fix in an afternoon and got most of the
win. The bundle work took three weeks, landed later, and nobody could see it in
the numbers by then.</p>
]]></content:encoded>
      <category>performance</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Every framework is a bet about what stays the same</title>
      <link>https://ooer.com/posts/frameworks-are-bets/</link>
      <guid isPermaLink="false">frameworks-are-bets</guid>
      <pubDate>Wed, 22 Jul 2026 00:00:00 GMT</pubDate>
      <description>A short piece on why frontend churn is not fashion.</description>
      <content:encoded><![CDATA[<p>The standard complaint about frontend is that it churns for the sake of it. I
have never found that convincing, having watched several of the transitions from
close enough to see what drove them.</p>
<p>A framework is a bet that some part of the platform will hold still long enough
to build on. jQuery bet that the DOM APIs would stay incompatible. Backbone bet
that the server would keep rendering. React bet that the expensive part was
keeping a tree in sync with state. Every one of those was true when it was made.</p>
<p>The churn is what it looks like when a bet stops paying. The DOM APIs converged,
so jQuery’s reason to exist evaporated — not because it was bad, because it
<em>won</em>, and the platform absorbed the thing it was compensating for. That is the
best possible outcome for a library and it still reads as obsolescence.</p>
<p>What this means practically is that the useful question about any framework is
not whether it is good. It is which platform gap it is standing in, and whether
that gap is closing. Nobody asks this, because it requires knowing the history,
and the history is not what gets taught.</p>
]]></content:encoded>
      <category>frontend</category>
      <category>culture</category>
    </item>
    <item>
      <title>Word of mouth is doing all the work</title>
      <link>https://ooer.com/posts/word-of-mouth-is-doing-the-work/</link>
      <guid isPermaLink="false">word-of-mouth-is-doing-the-work</guid>
      <pubDate>Mon, 15 Jun 2026 00:00:00 GMT</pubDate>
      <description>What a restaurant website is for, and what it cannot do.</description>
      <content:encoded><![CDATA[<p>The advice is that a restaurant should put up its menu, its hours, its location and a phone number and that this covers what anybody needs.</p>
<p>Those are the right facts and they’re not quite what people want because people arrive with questions rather than a desire to read. Is the food good. Are the staff any good. What’s it going to cost me. And where is it which matters more than you’d think if the place isn’t on an obvious route.</p>
<p>You can’t really answer any of those with a website. Not the first three, anyway which are the ones that decide whether somebody comes. A restaurant telling you its food is excellent conveys nothing because every restaurant says that and everybody knows it. Reviews would do it if reviews were trustworthy and they’ve been gamed so thoroughly that most people have quietly stopped believing them.</p>
<p>What people want is a source they trust telling them the answer. That’s the whole mechanism and it’s why the overwhelming majority of a restaurant’s customers arrive through word of mouth, or through reputation built up in curated places like critics and directories, especially at the top end.</p>
<p>A website helps in two specific situations. It helps people visiting an area who have no local network to draw on which is a real and worthwhile group. And it helps a very new restaurant whose owners haven’t built a reputation yet, or who believe a site is the key to getting business which is usually wrong but does at least get the basic facts online.</p>
<p>Outside those cases the only thing that reliably drives trade is building a base of people who tell their friends and their colleagues about you. That’s slow, it can’t be bought and it’s almost entirely a function of whether the experience was good enough to mention.</p>
<p>None of this is an argument for not having one. If a restaurant is going to have a website it should be a good one because bad websites shouldn’t exist and there’s no excuse for putting up something broken when the basic version is a solved problem. It’s an argument about expectations.</p>
<p>A restaurant could run happily for decades on nothing but a social media page and it would make no difference to whether it succeeded. That’s an uncomfortable thing for anyone in this industry to sit with because we’d all prefer that the thing we make is the thing that decides. Mostly it isn’t. It’s a convenience for people who have already decided and the deciding happened somewhere we had nothing to do with.</p>
<p>The same shape applies well beyond restaurants and it’s worth checking against whatever you’re building. Ask what actually causes somebody to choose your thing, then ask honestly whether the piece you’re working on touches that at all. Quite often it doesn’t and the work is still worth doing because being shabby costs you something but it isn’t the lever you thought you were pulling.</p>
<p>Knowing which of the two you’re doing changes how much of your week it should get.</p>
<p>The restaurants that get this right seem to work it out by instinct rather than analysis. They put the menu up, keep the hours accurate, make the phone number easy to find, and then spend every remaining hour of the week on the food and the room, which is where all of the deciding was happening the whole time.</p>
<p>That ordering is available to almost any small business, and almost none of them believe it, because the website is the part somebody can sell you and the room is the part you have to fix yourself.</p>
]]></content:encoded>
      <category>website</category>
      <category>culture</category>
    </item>
    <item>
      <title>Nobody can tell you what the tech debt costs</title>
      <link>https://ooer.com/posts/nobody-can-tell-you-what-the-debt-costs/</link>
      <guid isPermaLink="false">nobody-can-tell-you-what-the-debt-costs</guid>
      <pubDate>Mon, 13 Apr 2026 00:00:00 GMT</pubDate>
      <description>Rewriting a prototype that works, and other things with no stated problem.</description>
      <content:encoded><![CDATA[<p>Everybody promises that once this gets promoted properly they’ll rewrite it from scratch and it never happens. That’s usually described as a failure of will. It’s worth asking why you’d do it at all.</p>
<p>If you have a working prototype that’s handling the demand, has the features it needs and doesn’t require rebuilding except to satisfy the sensibilities of the people who wrote it, then spending time and money on that makes no sense. Whether it was originally labelled a prototype or a proof of concept is irrelevant. What matters is whether you can say what’s actually wrong with it and if you can’t enumerate the problem then there isn’t a case.</p>
<p>I work with teams who complain constantly about being mired in tech debt, who describe it as a large risk and say it slows them down. So look at what the company actually records. The incidents log doesn’t show many incidents and none that trace back to running risky code in production and the risk register has nothing on it about ageing code or dependencies past their end of life. And no team has ever managed to articulate how the debt slows them down, or by how much.</p>
<p>Given that, nobody should be surprised when leadership won’t fund fixing a problem that has no visible impact. That’s not managers failing to understand engineering. That’s a reasonable response to a request with no evidence attached.</p>
<p>Which doesn’t mean the debt isn’t real. It might well be and the people closest to the code usually have an accurate feel for where the danger is. The problem is that a feeling doesn’t survive contact with a ordering meeting and the fix is to produce the evidence rather than to repeat the claim more forcefully. Attach the incidents to the code. Put the end-of-life dependency on the risk register where somebody has to sign next to it and measure how long a change takes in the bad area against a comparable one elsewhere.</p>
<p>The opposite failure exists too and it does more visible damage and I’ve watched a team spend months refactoring an application they’d written themselves, before it ever launched. They built it, decided they could make it better and reworked most of it while the value it was meant to deliver sat waiting. Leadership was furious, understandably, and what’s left afterwards is very little trust.</p>
<p>That’s the real cost of both versions. One team can’t get funding for work that might really matter because they never built a case. The other burned the credibility that would have got them the funding, on work nobody asked for, to fix code that wasn’t in front of a user yet.</p>
<p>The conversation worth having is about deliberately taking on debt and deliberately paying it down, with numbers on both sides. That’s a harder conversation than either complaining or quietly refactoring and it’s the only one that gets you the time.</p>
<p>There’s a decent test you can run on yourself before asking for the time. Write down what you expect to be true in six months if nobody touches this, in terms somebody outside your team would recognise, and then check whether any of it has been true over the last six. If the answer is that everything carried on working and nothing broke, that’s worth knowing before you make the case rather than after somebody else points it out in the meeting.</p>
<p>And if you’re on the other side of the table, the useful response to a tech debt request isn’t yes or no. It’s asking what breaks if you wait a year, and being willing to fund it properly when somebody can actually answer that.</p>
]]></content:encoded>
      <category>software</category>
      <category>work</category>
    </item>
    <item>
      <title>Most code only needs to work</title>
      <link>https://ooer.com/posts/most-code-only-needs-to-work/</link>
      <guid isPermaLink="false">most-code-only-needs-to-work</guid>
      <pubDate>Mon, 16 Feb 2026 00:00:00 GMT</pubDate>
      <description>What we say we want from software, and what businesses actually buy.</description>
      <content:encoded><![CDATA[<p>Getting a model to produce output that runs is one thing and getting output that’s good and maintainable is supposed to be a different and much harder thing.</p>
<p>Except almost nobody is prompting for good, maintainable code in the first place. There’s a collective assumption that this is what we’re all aiming at and from there people assume it must be what the model is aiming at too. That isn’t true and there’s no reason it would be. A model doesn’t care about our goals. It’s solving a problem probabilistically from its training data, the context you gave it and the way you asked.</p>
<p>Think about what that implies for the code you get back. Take all the code in the world and put it through a mixer and what comes out isn’t the Platonic ideal of the best possible build. It’s closer to a Lovecraftian horror that happens to produce the right output and the fact that it produces the right output is really remarkable rather than a shame.</p>
<p>That’s a positive finding, oddly. It means that with better prompting and context and training we might be able to guide these things toward knowing what good and bad look like because we know what good and bad look like and that knowledge is expressible. The gap isn’t a wall. It’s an alignment problem in the ordinary sense and those get worked on.</p>
<p>The more uncomfortable half is that good, maintainable code is often not what a business wants from a developer either.</p>
<p>In companies everywhere the actual goal is whatever works right now and maintainability can look after itself. When a business is three months from running out of money, time spent writing something you could still be extending in ten years feels like exactly what it is which is effort spent on a future that may not arrive. That’s not a failure of engineering culture. It’s a rational response to the situation.</p>
<p>Which means that for most code that gets written, it doesn’t need to be good and it doesn’t need to be maintainable. It needs to work. And if you go and look at what businesses are actually running, an enormous amount of it doesn’t even manage that.</p>
<p>That’s the honest frame for what you’re actually using these tools for. They’re a step forward at getting things to work in the first place which is the bar most software is failing at rather than the bar we talk about in conference talks. Judging them against our stated standard misses what they’re being used for.</p>
<p>If we can get to something like bug free at the level of individual units, that’s really useful. Above that level, at logic and architecture and security, it still has to come from a person because none of these things can hold the context of an entire application yet. Tech debt lives almost entirely at that higher level and I don’t think we get there for a long time.</p>
<p>The uncomfortable follow-on is what this does to how you should judge your own work. If you’ve spent a career caring about whether code is good and the market is mostly buying whether code works, then the thing you’ve been optimising and the thing being paid for have never quite been the same. That gap was always there. It just didn’t matter much while producing working code was slow enough that quality and speed travelled together.</p>
<p>Which is why the arguments about whether generated code is good enough keep going past each other. One side is measuring against what a careful engineer would write and the other is measuring against what actually shipped last quarter, and those two standards are much further apart than anybody involved wants to say out loud.</p>
]]></content:encoded>
      <category>ai</category>
      <category>software</category>
    </item>
    <item>
      <title>The complexity is not new, it is just visible</title>
      <link>https://ooer.com/posts/the-complexity-is-just-visible/</link>
      <guid isPermaLink="false">the-complexity-is-just-visible</guid>
      <pubDate>Mon, 12 Jan 2026 00:00:00 GMT</pubDate>
      <description>Twenty years ago the same problems existed. We ignored them.</description>
      <content:encoded><![CDATA[<p>Build pipelines, bundlers, CSS frameworks with their own toolchains, progressive web apps, Core Web Vitals, layout shifts, quick images and the list is real and the conclusion drawn from it usually isn’t.</p>
<p>I’ve been making things for the web for about as long as anyone writing these laments. Perl first then PHP 4 fairly soon after. I recognise the problem being described and I read it differently because all of that complexity was there twenty years ago and we simply ignored it. That isn’t the same as it being simpler. It means we were taking risks that look insane with hindsight.</p>
<p>Take deployment which is the part people get most nostalgic about and there were no build pipelines and we absolutely had scripts we ran to build things. There was Pagemill for making site-wide changes before pushing a new version. Then you’d make the changes, check briefly that it worked locally and FTP the files up by hand, breaking the site while you did it because anyone navigating during the upload would get half the old version and half the new one. Some of us put up a maintenance page for the duration which meant blocking every visitor rather than confusing a few of them.</p>
<p>That’s certainly simpler. It’s also much worse for the person using the site and on anything that touched data you were risking corrupting somebody’s records because their request arrived in the middle. The remarkable thing is how rarely it went badly wrong and I’m not confident it was rare so much as invisible to us.</p>
<p>We didn’t have CSS frameworks and we did have in-house templates and those had their own toolchains that nobody called a toolchain. Over time most of that migrated into content management systems and their template builder plugins and I’d take a modern utility framework over that arrangement without hesitating.</p>
<p>We had Core Web Vitals too, in the sense that we had traffic analytics telling us the same things less precisely. We had layout shift and called it a flash of unstyled content. We even had something like quick images, implemented as a pile of generated preload and swap functions from a visual editor and the modern picture element is a great deal nicer than that was.</p>
<p>So the complexity didn’t arrive. It got named, measured and turned into things you can be held accountable for. Every item on the list is a problem that always existed, that used to be absorbed silently by users and by luck and that somebody eventually built a tool to handle properly.</p>
<p>That’s why it feels heavier. Being handed a Core Web Vitals score is more work than not knowing your site is slow and knowing about layout shift is more work than shipping it and never finding out. The industry didn’t get more complicated so much as it stopped being able to pretend.</p>
<p>Writing web software is really good fun at the moment, better than it’s been for a long time. I use language models in my own work constantly because they’re excellent and not to simplify any of this. The complexity isn’t new. It’s just visible now and visible problems are the only kind anybody ever fixes.</p>
<p>If you want the older way back, you can have most of it and people do and write the HTML by hand, put the styles in a file, upload it and don’t measure anything. That works, it’s genuinely pleasant and the reason it feels lighter is that you’ve opted out of knowing whether it’s any good rather than because the problems went away.</p>
<p>What you can’t have back is the ignorance and that was always the thing doing the heavy lifting in the story about how simple it used to be.</p>
]]></content:encoded>
      <category>web</category>
      <category>history</category>
    </item>
    <item>
      <title>A sale is worth more than a thousand upvotes</title>
      <link>https://ooer.com/posts/a-sale-beats-a-thousand-upvotes/</link>
      <guid isPermaLink="false">a-sale-beats-a-thousand-upvotes</guid>
      <pubDate>Sat, 20 Dec 2025 00:00:00 GMT</pubDate>
      <description>What validation from an audience of enthusiasts actually tells you.</description>
      <content:encoded><![CDATA[<p>If an investor tells you to post your product on a link aggregator to show that people love it and your customers aren’t specifically the people who read link aggregators, walk away from that investor.</p>
<p>Being loved in a place like that means basically nothing and the readers are lovely and I’ve been one for over a decade and collectively we’re the magpies of the internet. We love seeing the new shiny thing. That reaction tells you the thing is shiny. It doesn’t tell you anybody will pay for it and those are completely different pieces of information that feel identical when they arrive.</p>
<p>The base rate makes the case on its own. For every product that got posted somewhere like that and went on to become enormous, there are hundreds of launches that received a pile of really warm commentary and then went nowhere at all. The comments weren’t dishonest. People meant them. Meaning it and buying it are separated by a gap that no amount of enthusiasm closes.</p>
<p>There’s a particular flavour of comment that’s worth learning to discount and it’s the most encouraging one you’ll get. Somebody says the thing looks great and they’d buy it, at a price they’ve invented which is invariably far below what you’d need to charge. That’s not a customer. That’s a person being nice about a demo and treating it as a signal will send you into a pricing conversation with yourself that has no basis in anything.</p>
<p>If you want to show an investor there’s something here, post about it where your actual customers are and take feedback from people who might one day hand you money. That’s harder and slower and a lot less pleasant because those people are not there to be encouraging and will tell you what’s wrong with it in flat, unenthusiastic terms.</p>
<p>If you really want to prove it, sell to them and get one sale off a prototype or a proof of concept or whatever rough thing you’ve currently got. A single person choosing to part with money for something visibly unfinished tells you more than a million people saying it looks good because paying is the only response that costs the person anything.</p>
<p>That’s the whole test and it’s why it works. Praise is free so people give it away. Money isn’t so it only moves when somebody has actually decided.</p>
<p>None of this means those places are useless, and plenty of good things have started there. What they’re good for is finding people like you to build with, getting a technical decision stress-tested by somebody who has made the same mistake already, and occasionally reaching a customer when your customers genuinely are developers. Those are real and they’re not validation.</p>
<p>The confusion is understandable because the feedback arrives in the same shape as the thing you want, and enthusiastic, specific, from people who clearly understood what you built. It’s just measuring interest rather than intent, and only one of those two turns into a business.</p>
<p>The cheapest way to find out which you’ve got is to ask for something small that costs the person something. A pre-order, a deposit, a scheduled call with somebody who’d have to sign off the purchase. Enthusiasm survives all of those questions or it doesn’t, and finding out in week three is a great deal less expensive than finding out in month nine after you built the whole thing on a comment thread.</p>
]]></content:encoded>
      <category>startup</category>
      <category>social</category>
    </item>
    <item>
      <title>Public wealth is the kind that makes you happy</title>
      <link>https://ooer.com/posts/public-wealth-is-what-makes-you-happy/</link>
      <guid isPermaLink="false">public-wealth-is-what-makes-you-happy</guid>
      <pubDate>Sat, 13 Dec 2025 00:00:00 GMT</pubDate>
      <description>Two sorts of wealth, and which one you actually live in.</description>
      <content:encoded><![CDATA[<p>By the metric currently in fashion which is how much stuff everybody has, the United States is the most successful country in human history.</p>
<p>That metric is only measuring one of the two kinds of wealth and the distinction explains a lot of what looks like a paradox from outside. Private wealth is what you own. The money in your account, the car on the drive, the house you live in, the things inside it and public wealth is what you share with everyone else and how good it is. The state of the roads and the trains. How easy it is to see a doctor. Whether public space is pleasant and whether it’s safe. How you feel when you’re not at home.</p>
<p>On private wealth, Americans do extraordinarily well, especially measured against anywhere else and on public wealth the country ranks a long way down.</p>
<p>The awkward part is that it’s public wealth that actually makes people happy, unless you’re rich enough to avoid shared space entirely which is a fraction of a fraction of the population and not a fraction anybody should be designing a society around.</p>
<p>You can see why once you look at how the two interact and owning a luxury car while the roads are terrible isn’t a luxury experience. It’s a daily reminder that your money can’t solve the problem you’re currently sitting in. Being able to afford the best restaurant in the city doesn’t help much if you’re nervous waiting outside for a cab afterwards and the meal doesn’t get better retrospectively because the wine was excellent.</p>
<p>That pattern holds across most of life. Private wealth buys you things. Public wealth determines what it’s like to be a person moving through a day and no amount of the first one buys you out of the second unless you can go from a gated house to a private car to a private terminal and never touch anything shared.</p>
<p>Which is the thing worth noticing about how wealth gets measured and argued about. Almost every comparison between countries is a comparison of the private kind because it’s easy to count and it fits in a chart. The other kind shows up as a feeling and feelings get treated as soft, and so the number that gets optimised is the one that turns out not to be the one people are experiencing.</p>
<p>Society has to feel safe before anybody can be properly happy inside it. That’s not a political claim so much as an observation about where most of your waking life happens which is outside your house, in places you don’t own and can’t improve on your own.</p>
<p>The practical version of this is what happens to a country over decades when it consistently trades one for the other. Every individual decision to spend less on shared things and leave the money with people to spend privately looks reasonable in isolation, and it hands you back a portion of what was being spent on your behalf, and you can point at exactly what you bought with it.</p>
<p>What you can’t point at is the thing that quietly stopped working, because nobody experiences the absence of a decent train service as a purchase they made. It arrives as a background sense that everything is slightly harder than it used to be, and there’s nothing to attribute it to.</p>
<p>It also explains why moving somewhere poorer can feel like an upgrade, which surprises people who only think in the private column. Take a smaller salary in a place with decent transport, walkable streets and healthcare you don’t have to think about, and the spreadsheet says you’ve gone backwards while the daily experience says otherwise. Both are true. They’re measuring different things, and only one of them is what you live in.</p>
]]></content:encoded>
      <category>money</category>
      <category>politics</category>
    </item>
    <item>
      <title>You will write a framework whether you meant to or not</title>
      <link>https://ooer.com/posts/you-will-write-a-framework/</link>
      <guid isPermaLink="false">you-will-write-a-framework</guid>
      <pubDate>Sun, 21 Sep 2025 00:00:00 GMT</pubDate>
      <description>The story that plays out at every company that avoids the standard one.</description>
      <content:encoded><![CDATA[<p>You don’t need a big framework or a pile of components to build an application. That’s true and it isn’t the end of the argument.</p>
<p>In any sufficiently complex application you’ll end up writing a sort of mini framework of your own because you’ll abstract the things that turn up more than a few times and that’s what abstracting them produces. It might be really nice at the start. Small, fitted exactly to the problem, no concepts you don’t need. Then the project continues and it gets hackier, especially when you’re short of people or time and the abstraction has to bend around something it wasn’t built for.</p>
<p>Eventually you’ll regret not using something standard. If there are more than a couple of developers involved it’ll be something nobody much likes after a year or two, and everybody will have a slightly different theory about which part is the problem.</p>
<p>The effect on hiring is where it really bites. Junior developers won’t want to be on it because from their side it’s old legacy code that teaches them nothing portable and looks like nothing on their next application. That makes it harder to find people who want to join which makes the team smaller and more senior and more attached to the thing which makes it harder still.</p>
<p>Then comes the part everyone can see coming. As recruiting gets harder because the codebase sits on a strange framework nobody knows, there’ll be a large project to move it onto something standard. That’ll probably be React because that’s what people know.</p>
<p>At the same time most of the senior developers will be arguing to scrap the whole thing and rebuild from nothing. They’ll be wrong, in almost every case and it won’t matter because what they actually want is a greenfield project where they get to try new things. That’s a completely human thing to want and it’s not a technical argument and it wins a surprising number of these debates anyway.</p>
<p>This story has played out at every large company building applications internally, and at a lot of startups once they matured enough to need real hiring. It’s so consistent that you can more or less read the year off which stage a team is at.</p>
<p>Which means you might as well skip it. Not because the standard framework is better in any interesting technical sense, and often it isn’t. Because the alternative isn’t no framework. The alternative is a framework you wrote by accident, that only your current team understands, that nobody documented and that you’ll spend three years migrating away from.</p>
<p>The honest version of the choice is between a framework with a community, documentation, hiring pool and upgrade path, and one with none of those that happens to fit your problem exactly on the day you started.</p>
<p>The counter-argument worth taking seriously is that a framework you wrote fits your problem and a general one doesn’t, which is true on day one and gets less true every quarter afterwards. Problems move, and the general framework has thousands of people pushing it to cover new ground while yours has whoever is free that sprint.</p>
<p>There’s a narrow case where writing your own is right. It’s when the thing you’re building is genuinely unlike what anyone else builds, and you can afford to keep a team on the tooling itself for years rather than treating it as something you’ll tidy up later. Almost nobody meets both conditions and almost everybody believes they meet the first.</p>
]]></content:encoded>
      <category>react</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Your degree stops mattering after about ten years</title>
      <link>https://ooer.com/posts/your-degree-stops-mattering/</link>
      <guid isPermaLink="false">your-degree-stops-mattering</guid>
      <pubDate>Sat, 19 Oct 2024 00:00:00 GMT</pubDate>
      <description>What a university name is worth, and for how long.</description>
      <content:encoded><![CDATA[<p>The claim that an elite degree keeps opening doors is mostly wrong and if it’s right anywhere it’s an advantage you wouldn’t want to be using.</p>
<p>Based on hiring people for the last twenty five years, from the side of the table doing the hiring rather than the applying, the pattern looks like this. Your degree matters for about a decade, then gives you steadily less over the few years after that and then it stops making any difference at all. Once you’ve got fifteen years of relevant experience behind you, what you studied and where has no bearing on how any good company reads your application.</p>
<p>There’s an exception and it works against you rather than for you. If you still believe the degree is important and you turn up to an interview and talk about how excellent your university was, that’s a signal about you and not a good one. It suggests the most impressive thing available is something that happened before your career started which is not what anybody wants to hear from somebody with fifteen years of work behind them.</p>
<p>The caveats here matter and I’d rather state them than pretend the observation is everywhere. I don’t have an elite degree myself. I’m not in the US, where the whole dynamic is reportedly much stronger. I’ve only ever hired developers, I’ve never worked anywhere that really needed people from particular institutions and the number of people I’ve hired is a tiny sample of a very large industry.</p>
<p>With all of that said, there’s a pattern in who believes the opposite and the people convinced that elite degrees matter are mostly people who have one. That isn’t a conspiracy. It isn’t even a criticism. It’s what you’d expect because the belief costs them nothing and confirms something they already paid a great deal for.</p>
<p>Where it becomes self-fulfilling is that those people often end up in hiring positions and then it does matter, in their company, for the roles they control. The belief creates the effect it claims to be describing. If you’re applying somewhere run that way then your degree is really a factor and the honest advice is that you probably don’t want to work there.</p>
<p>That’s the bit worth sitting with rather than the timeline. A company where a university name counts for more than fifteen years of demonstrated work is telling you something about how it evaluates everything else. It’ll apply the same reasoning to promotions, to who gets the interesting projects and to whose judgement gets trusted in a meeting.</p>
<p>You can get a job there. Plenty do. Some are happy. Just be clear that the thing getting you through the door is a proxy, and organisations that lean on proxies for hiring tend to lean on them everywhere else too.</p>
<p>The practical upshot for anyone earlier in this is that the decade of relevance is real and it’s worth using. Early on, the name does some work for you and there’s no sense pretending otherwise or refusing the advantage on principle. What matters is what you build during those years, because that’s the thing that replaces it, and the replacement has to be finished before the original wears out.</p>
<p>Anyone still leading with the university at year fifteen either had a quiet decade or hasn’t noticed the substitution was supposed to happen.</p>
<p>And if you’re on the hiring side of this, the cheapest improvement available is to stop reading the education line until after you’ve formed a view from the work. It costs nothing, it takes one change to how you lay out a shortlist, and it removes a proxy that stopped predicting anything useful about fifteen years into most people’s careers.</p>
]]></content:encoded>
      <category>job</category>
      <category>culture</category>
    </item>
    <item>
      <title>Going to a website for the content is nostalgia</title>
      <link>https://ooer.com/posts/going-there-for-content-is-nostalgia/</link>
      <guid isPermaLink="false">going-there-for-content-is-nostalgia</guid>
      <pubDate>Sat, 13 Jul 2024 00:00:00 GMT</pubDate>
      <description>Content was king. Then it stopped being content.</description>
      <content:encoded><![CDATA[<p>When I started building websites professionally in 1998, everybody used the same phrase about getting traffic. Content is king.</p>
<p>It was a play on the cash is king motto that small businesses ran on and it was accurate. If you wanted people to arrive you had to build something they’d tell each other about because search engines weren’t remotely as good as they are now and word of mouth did most of the work. The advice was real advice and it worked.</p>
<p>Then the web shifted. Between roughly 2005 and 2015 people moved from consuming what was on the web to making it, and everybody called that Web 2.0. Content was still king through all of that. People went to the sites they liked in order to make things that other people would then sit and read.</p>
<p>What came next was visible to anyone paying attention. Around 2015 people stopped making things for others to spend time with, and started making things that get seen for exactly as long as it takes to hit a like button. Content in any meaningful sense died there. It became a sentence, or a photograph, or a video short enough to finish before you’ve decided whether you want to.</p>
<p>Which means the entire premise that people visit websites for the content is nostalgia. That part of the internet is effectively dead, and I say that with no pleasure at all. There are noble and really good attempts to keep it alive and some of them work and they’re a rounding error against where attention actually goes.</p>
<p>The consequence for anyone doing this for a living is straightforward and gets argued about far more than it deserves. Very few people are paid to build static content sites any more. If you’re working as a web developer, you’re being paid to build an application that lets people do things in a browser and that means working with something like React whether it’s your preference or not.</p>
<p>Most of the rants about modern frontend are really grief about that transition. The complaint is that the tools are heavy and the builds are slow and nobody needs a framework to display an article and every part of that is correct about the case being described. It just isn’t the case most people are being paid for, and hasn’t been for close to a decade.</p>
<p>You can see the confusion clearly whenever somebody demonstrates that their blog loads in forty milliseconds without any JavaScript. That’s true and it’s good work and it isn’t an argument about the thing anyone is complaining about because a blog is a document and the thing being complained about is an application that happens to be delivered through a browser.</p>
<p>The honest version is that the web split in two and only one half is a job. The document half still exists, still works, and is better served now than it has ever been by the platform itself. The application half is where the money is and it has the constraints applications have always had, and those constraints are not going to be argued away by pointing at how fast a page of text can render.</p>
<p>There’s a version of this that isn’t defeatist, and it’s the one worth holding onto if you build things for the document half anyway. The audience is smaller than it was and it’s also more deliberate, because anyone who arrives at a long piece of writing in 2024 has had to actively choose it over roughly nine hundred easier options. That’s a better reader than the ones the old web delivered by default, and building for them is a completely reasonable thing to spend your time on.</p>
<p>Just don’t expect it to be the job. It’s the hobby that used to be the job, which is a thing that has happened to a great many crafts before this one.</p>
]]></content:encoded>
      <category>web</category>
      <category>culture</category>
    </item>
    <item>
      <title>No app needs a good UI until it has a rival</title>
      <link>https://ooer.com/posts/no-app-needs-a-good-ui/</link>
      <guid isPermaLink="false">no-app-needs-a-good-ui</guid>
      <pubDate>Sat, 06 Apr 2024 00:00:00 GMT</pubDate>
      <description>Why enormously successful software is so often unpleasant to use.</description>
      <content:encoded><![CDATA[<p>One of the most popular services in the world having one of the worst experiences of anything you use is not a puzzle. It’s a signal and it’s a common one.</p>
<p>What it tells you is that the value isn’t coming from the software. It’s coming from what the software gets you to, and in that situation the software doesn’t need to be good. People pay for access to an enormous library of music and podcasts and they put up with the interface because the interface is a toll rather than the thing they came for.</p>
<p>You can watch the same pattern anywhere you look. Nearly every business tool is a disaster from a usability point of view and they make fortunes because whatever the user gets out of the other end makes the mess worth tolerating. I could list hundreds of shockingly bad pieces of software I’ve used happily over forty years and every one of them did something I actually wanted done.</p>
<p>That’s worth knowing if you’re building something because it inverts the usual advice. People say every application needs a beautiful interface. What every application actually needs is to do something useful and the interface is a side issue until a specific thing happens.</p>
<p>The specific thing is a competitor arriving with a service that’s really equivalent. That’s the moment the interface starts to matter and it matters enormously at that point because it becomes the thing people use to pick between two options that are otherwise the same. Before that moment it’s a nice to have. After it, it’s the whole fight.</p>
<p>Which means the question to ask about your own product isn’t whether the interface is good. It’s whether anyone could offer the same underlying value tomorrow, and how quickly. If the answer is that the library took fifteen years and a thousand licensing deals to assemble, you have a long time to be ugly. If the answer is that a competent team could match you in a quarter, you were always in an interface fight and just hadn’t noticed yet.</p>
<p>There’s a related signal for anyone earlier than that. When you run a startup and people are hungry to use your product despite obvious flaws, that’s one of the classic signs you’ve found something valuable. Not because the flaws don’t matter but because tolerance of them is the clearest evidence available that the underlying thing is worth having. Somebody putting up with your rough edges is telling you more than any amount of praise for a polished demo.</p>
<p>The failure mode this explains is the beautiful product nobody wants. It happens constantly, it’s easy to fund, and everybody involved can see that the work is good. All of the effort went into the part that only becomes decisive once you’ve won the part that comes first.</p>
<p>The reason this is hard to act on is that it cuts against how designers and developers are trained to think, and against what feels like doing the work properly. Nobody wants to hear that the ugly thing is winning because the ugly thing solved the problem first, and the honest response is that you should still make it good, just after you’ve established there’s something worth making good rather than before.</p>
<p>Order of operations, again. Almost everything difficult about building products turns out to be order of operations.</p>
<p>The other thing it explains is why so much advice about product design is useless. Most of it is written by people describing a market where the underlying value was already settled, so all that was left to compete on was the surface. That advice is correct for them and actively misleading for anyone still trying to work out whether the thing is worth having at all.</p>
]]></content:encoded>
      <category>startup</category>
      <category>app</category>
    </item>
    <item>
      <title>The first memo already had applications in it</title>
      <link>https://ooer.com/posts/the-memo-already-had-applications/</link>
      <guid isPermaLink="false">the-memo-already-had-applications</guid>
      <pubDate>Wed, 08 Nov 2023 00:00:00 GMT</pubDate>
      <description>On the claim that the web was built for sharing documents.</description>
      <content:encoded><![CDATA[<p>Every time somebody says the web was originally created as a system for sharing documents there’s a small stabbing sensation somewhere behind my eyes because it isn’t true and it’s been repeated long enough to become furniture.</p>
<p>Go and read the original proposal yourself. Berners-Lee talks about pages built on the fly, and about special links out to external applications. The exact wording is that hypertext allows documents to be linked into live data so that the information is retrieved every time the link is followed and that if you sacrifice portability you can make following a link fire up a program so that diagnostic tools could be linked directly into a maintenance guide.</p>
<p>That’s an application launched from a link, described in the founding document, before any of the technology existed to do it well.</p>
<p>Dynamic applications running inside the browser weren’t really a thing until the later nineties and that’s the part people are half remembering when they make the claim. But reaching applications through the Common Gateway Interface, with HTML rendered fresh on every request, was there from very early on. That’s where I started my career and it wasn’t an exotic corner of the web at the time. It was how anything that needed to know something about you worked.</p>
<p>There’s a stronger version of the argument that gets missed. If the web had really been about static documents, it wouldn’t have needed to exist. We already had networked access to document systems. There were several of them and they worked. The thing that made this one worth building was precisely the parts that weren’t static and a proposal for yet another way to fetch a file would not have gone anywhere.</p>
<p>Then there’s the passage of time which is the part that should settle it regardless of what the memo says. That document is thirty four years old. The web in the sense people mean when they say the modern web has been running for at least twenty of those years. Even if the original had been purely about documents, there’s no reason to believe a design decision from 1989 still governs what the thing is in practice.</p>
<p>The reason you should care isn’t pedantry about history, though I’ll admit some of it is. It’s that the claim gets used to argue that everything since is a corruption of the original purpose and that if we went back to documents we’d have a better web. That argument needs the origin story to be true and it isn’t.</p>
<p>Plenty of the criticism you’ll read about the modern web is fair and I’d sign most of it. Pages are too heavy, too much of the interactivity is doing nothing for anybody and a good deal of what gets shipped as an application should have been a page. All of that stands perfectly well on its own.</p>
<p>It just doesn’t need a founding myth to support it, and building on one that’s wrong makes the whole case easier to dismiss by anybody who’s read the memo.</p>
<p>If you want to make the case that too much of the web is needlessly dynamic, and you should, then make it about what users get rather than about what the web was for. You’ll win that argument far more often, because you’ll be describing a page somebody is looking at right now instead of a design intention from before most of your readers were born.</p>
<p>There’s a smaller version of the same error that turns up constantly in this industry, which is treating an early design document as a statement of what a thing is permanently allowed to be. Protocols get repurposed, tools get used for jobs nobody imagined, and the people who built them are usually pleased about it rather than offended.</p>
]]></content:encoded>
      <category>history</category>
      <category>web</category>
    </item>
    <item>
      <title>Tailwind does not save you from CSS</title>
      <link>https://ooer.com/posts/tailwind-does-not-save-you/</link>
      <guid isPermaLink="false">tailwind-does-not-save-you</guid>
      <pubDate>Wed, 23 Aug 2023 00:00:00 GMT</pubDate>
      <description>A shorthand with a one to one mapping is not a replacement.</description>
      <content:encoded><![CDATA[<p>You aren’t learning anything valuable by learning Tailwind and you aren’t avoiding CSS either because you can’t use one without knowing a lot of the other.</p>
<p>There’s nothing in it that makes CSS easier or that hides the understanding you need to build things. Take a horizontal flexbox layout. Knowing display flex, flex direction row and flex wrap gets you there, and so does flex, flex-row and flex-wrap, and those two are functionally identical. You have to know what either set is doing before you can use it and there’s a one to one mapping between them so learning one means you know both.</p>
<p>That’s the whole thing. It’s a shorthand notation, and in a few places the equivalent of a macro. The arguments about whether it’s good or bad tend to skip past that and treat it as a different way of thinking about styling which it isn’t.</p>
<p>Learn CSS. That’s the part which will still be useful in twenty years and it’s the part that transfers to every project you touch regardless of what’s fashionable when you arrive. I don’t imagine Tailwind itself is going to last another twenty years and I do think people will keep using utility first libraries of some sort from here on. Nobody is going back to writing plain CSS by hand unless they have no choice about it.</p>
<p>The reason is worth being honest about because it isn’t fashion, and cSS keeps getting more capable and everything that gets more capable gets more complicated alongside it. What Tailwind offers is all that power with a less arcane syntax sitting in front of it, and once you’ve got that it’s hard to construct an argument for giving it up. That’s why it won and it’s a better reason than most winners have.</p>
<p>There’s a caveat I keep coming back to though. Tailwind is the CSS equivalent of jQuery and that comparison is meant as a compliment about its trajectory rather than a criticism of the thing.</p>
<p>jQuery was enormously good and enormously popular, and what eventually happened to it is that browsers absorbed the useful parts. The selector engine became a native method. The animation helpers became a specification. Everything people reached for it to do turned into a platform feature, until using it became a choice rather than a necessity and then a slightly odd choice. Nobody killed it. It got adopted.</p>
<p>Something similar is likely here. In five years or so a browser is going to ship a utility notation of some kind directly in the engine because the benefit is obvious enough that browser developers can see it as clearly as everyone else can. At that point the library becomes optional, and then it becomes a compatibility layer, and then it becomes a thing you find in old codebases.</p>
<p>So in one sense Tailwind will die and in the more useful sense it will have won completely which is exactly what happened to the last library that got this popular. Either way the underlying knowledge is the same on both sides of that transition and that’s the argument for learning the language rather than the abbreviation of it.</p>
<p>The practical consequence is about where you spend your learning time rather than which tool you pick for the next project. Time spent on the abbreviation is time spent on something with a shelf life, and time spent on the thing underneath keeps paying out through every abbreviation that comes after it.</p>
<p>Use whichever you like on Monday. Just be clear which of the two you are actually learning.</p>
]]></content:encoded>
      <category>css</category>
      <category>frontend</category>
    </item>
    <item>
      <title>High quality code comes much later</title>
      <link>https://ooer.com/posts/quality-comes-much-later/</link>
      <guid isPermaLink="false">quality-comes-much-later</guid>
      <pubDate>Wed, 10 May 2023 00:00:00 GMT</pubDate>
      <description>Building the right thing first, then refining it, does not work.</description>
      <content:encoded><![CDATA[<p>The plan is to talk to users, work out what to build, then go and produce a high quality first version with good architecture and decent performance and minimal bugs and iterate from there. That plan is wrong.</p>
<p>If you believe you can build the right product from the outset and then refine it by talking to people, you’ll end up with a garbage product. Not because the code will be bad but because what good architecture even looks like depends on the feedback you haven’t collected yet and so does what usable performance means and so does which parts need to be reliable.</p>
<p>You have to get something in front of users as soon as is humanly possible. If the thing you show them is well architected, has few bugs and performs nicely, then you’ve already spent too long on it. That sounds like an insult to careful work and it’s really a statement about what the early version is for. It exists to find out whether anybody wants this. Every hour spent on anything beyond that is an hour spent on a question you can’t answer yet.</p>
<p>First time founders find this really hard to accept and the reason is understandable. They’re frightened of losing potential customers by showing them something bad. What they should be frightened of is spending their time and their runway building the wrong thing which is the failure that actually happens and the one that can’t be recovered from.</p>
<p>There’s every chance the first version you show people is completely wrong. Not slightly off. Wrong in a way that means the next version shares almost nothing with it. When that happens, the quality of the code you wrote makes no difference at all because none of it survives and the six weeks you spent making it solid were six weeks of runway spent on a thing that got deleted.</p>
<p>That’s the trade nobody wants to look at directly. Good code is an investment in a thing continuing to exist. Early on you don’t yet know whether it will so the investment is a bet placed before the odds are visible and most of those bets lose.</p>
<p>If you’re focused on writing good code from day one then you’ve got the ordering wrong. High quality code comes much later, after you know what the thing is and after there’s a reason to believe it’ll still be here in a year. At that point quality stops being a cost and starts being the thing that lets you move quickly which is the argument its advocates make and which is entirely correct at that stage.</p>
<p>The mistake is applying it to the stage before, where the same discipline that makes a mature product fast to change makes an unproven one slow to discard.</p>
<p>The useful test, if you’re not sure which stage you’re in, is to ask what happens if you throw the whole thing away next month. If that would be a relief because you’d finally know what to build instead, you’re still early and should be moving faster. If it would be a disaster because people depend on it, you’re past that point and the careful work has started earning its keep.</p>
<p>None of this is licence to write badly forever, and the founders who use it that way end up with a different failure eighteen months later, buried under something nobody can change. The claim is about ordering. There’s a moment where quality starts mattering enormously, and it arrives after the thing has proven it deserves to exist rather than before.</p>
]]></content:encoded>
      <category>startup</category>
      <category>code</category>
    </item>
    <item>
      <title>Defaulting to the office is giving up</title>
      <link>https://ooer.com/posts/defaulting-to-the-office/</link>
      <guid isPermaLink="false">defaulting-to-the-office</guid>
      <pubDate>Wed, 03 May 2023 00:00:00 GMT</pubDate>
      <description>Remote work has problems. Offices are not a solution to them.</description>
      <content:encoded><![CDATA[<p>The claim that the era of remote work is over turns out to be narrower than the headline suggests and worth reading in full before you react to it.</p>
<p>What was actually said is that one of the industry’s worst mistakes was assuming everybody could go fully remote forever, that startups didn’t need to be together in person and that there’d be no loss of creativity from it. The claim is that the experiment is over and the technology isn’t yet good enough for people to be fully remote permanently, especially at startups.</p>
<p>Two things in there change the shape of it a lot. He’s talking about full remote which leaves hybrid entirely on the table. And he’s talking mostly about startups rather than established companies which is a much smaller claim about a much narrower set of situations. With both caveats in place it’s a lot less controversial than the headline wanted it to be.</p>
<p>It’s still a bit a shame though and the a shame part isn’t the conclusion. It’s that this reads like giving up.</p>
<p>The argument identifies real problems with remote work for creative teams which do exist and which you’ll have felt if you’ve tried it. Then instead of thinking about how to solve those problems, it defaults to putting everybody in a room which is not much better for creativity and a lot worse on every other axis. That’s a weak place to land.</p>
<p>This is somebody with an enormous amount of experience of how startups actually work, across a lot of companies, over a long period. The suggestion that he’s never seen a distributed team work well and can’t think of anything to try beyond everybody being in the same building, isn’t an exciting contribution to the question. If that’s the state of the art from someone with that much exposure to the problem then the problem hasn’t really been worked on.</p>
<p>The thing that would be interesting is the specific failure. Which part of the creative process degrades when people aren’t together. Is it the unplanned conversation, the shared context, the speed of a decision, or something about who feels able to interrupt whom. Those have different fixes. Some are solvable. None of that gets said because the conclusion arrived before the diagnosis did.</p>
<p>What makes it slightly funnier is that the remarks were made in an office, to a room of people who had travelled to be there. That’s the most creative environment available, apparently and it produced this.</p>
<p>What you’re left with, if you run a team, is that nobody senior is going to hand you a worked answer to this. The honest position is that fully remote has real costs, offices have different and larger ones and the interesting work is in finding which specific thing your team loses and buying that back deliberately rather than reaching for the building as a blunt instrument.</p>
<p>The part that should bother you most is what an argument like this does when it comes from somewhere with authority behind it. Plenty of people running teams will read the headline, skip the caveats about hybrid and about startups and use it to justify a policy that was already decided for reasons involving a lease.</p>
<p>That’s not the fault of whoever said it. It is the predictable use of it and anybody making an argument at that volume knows how it will travel.</p>
<p>If you’re on the receiving end of a policy like that, the question worth asking is which problem it’s meant to solve, and what would count as it having worked. A policy nobody can attach a measure to is usually a preference wearing a business case.</p>
]]></content:encoded>
      <category>work</category>
    </item>
    <item>
      <title>That behaviour is on you</title>
      <link>https://ooer.com/posts/that-behaviour-is-on-you/</link>
      <guid isPermaLink="false">that-behaviour-is-on-you</guid>
      <pubDate>Wed, 15 Mar 2023 00:00:00 GMT</pubDate>
      <description>Expecting a framework to compensate for the code you wrote.</description>
      <content:encoded><![CDATA[<p>Things get complicated once you’re signalling updates upward through context because the render cascades and you end up chasing an update that arrives seconds late.</p>
<p>The interesting question is whether that’s the framework’s fault and it mostly isn’t. If a child signals to a parent that state has changed, you should always expect that to cascade down the tree, and expect that cascade to cause further updates and further renders. That’s what the words mean. A framework that quietly decided not to propagate some of those updates would be doing something far stranger and far harder to reason about than the thing being complained about.</p>
<p>So the behaviour is on you. Not as a scolding but as an accurate description of where the decision was made because the shape of that cascade came from how the components were arranged and where the state was put.</p>
<p>This is the part of the argument about React that I think gets misplaced and it applies to most frameworks equally. People expect too much of them. If you hand over all of your judgement to the framework and assume it’ll work regardless of what design you throw at it, you’ll build a bad application and it won’t be because the framework let you down.</p>
<p>You still have to think things through. You still have to use your skills, understand what’s happening underneath and know why it’s happening. That’s always been true and it’s going to stay true through every generation of these tools because the thing being automated is the mechanics rather than the decisions. Nobody has built anything that removes the requirement to put the work in and the tools that claim to are usually moving the work somewhere less visible.</p>
<p>There’s a second thing in these complaints worth separating out. The feeling of being trapped, where your last job and your current one and probably your next one are all built on the same framework so you’re stuck with it whether it suits you or not.</p>
<p>That isn’t true unless you decide it is. It’s true right now which is different. If you put effort into learning other things and then look for roles that use them, options open up and that’s a process measured in months rather than a door that’s been locked. It takes real work and it can mean a step sideways or a pay cut for a while and it’s available.</p>
<p>You could also leave web development entirely, which people do, and find that a decade of knowing how state and rendering and network calls interact transfers further than expected. The framework you happen to know is the least portable thing you’ve learned. Everything underneath it goes with you.</p>
<p>Feeling stuck is worth taking seriously as a signal. It’s just usually a signal about what you’ve been prioritising rather than about what’s available.</p>
<p>The frameworks that survive tend to be the ones that are honest about this rather than the ones promising to think for you. A tool that does exactly what you told it, predictably, is more useful over a decade than one that guesses well most of the time, because you can build a model of the first one in your head and the second one will eventually guess wrong somewhere you can’t see.</p>
<p>What makes the trapped feeling worth taking seriously anyway is that it’s usually accurate about the last few years even when it’s wrong about the next few. If three jobs in a row have all been the same stack, something in how you’re choosing roles is producing that, and noticing the pattern is more useful than blaming whichever framework happened to be popular.</p>
]]></content:encoded>
      <category>react</category>
      <category>javascript</category>
    </item>
    <item>
      <title>You cannot cargo cult the layoffs</title>
      <link>https://ooer.com/posts/you-cannot-cargo-cult-the-layoffs/</link>
      <guid isPermaLink="false">you-cannot-cargo-cult-the-layoffs</guid>
      <pubDate>Thu, 24 Nov 2022 00:00:00 GMT</pubDate>
      <description>What copying a dramatic restructure would actually require.</description>
      <content:encoded><![CDATA[<p>Set aside which company and which owner because those are divisive enough to swallow the interesting question underneath.</p>
<p>What’s really being asked is what happens if somebody successfully implements a massive cutting back of how a technology company operates. Assume for the sake of it that the change does work which will take anything up to a couple of years to become clear either way.</p>
<p>The honest answer is that almost nothing changes elsewhere, unless people can work out how it worked. That’s the constraint everybody skips. You can’t copy firing half the staff, driving out another quarter, and slashing internal services down to nothing because doing that to most companies would end them within the quarter. It appears survivable in one specific case because a lot of what was being cut was really side to the product, and shutting those things down didn’t touch what users came for.</p>
<p>That’s a property of that company rather than a technique. Whether you have a large layer of non-core activity that can be removed without breaking anything is a question about your company’s history and the answer for most is a lot less than the people proposing the cut believe.</p>
<p>Then there’s what happens afterwards which gets less attention than it deserves. Recruiting into a business that just lost three quarters of its people is hard. Anyone considering it can see what happened and has to weigh whether they’d be next, so you’re hiring from a much smaller pool at a higher price. That means the things your remaining staff can’t already do are things you may simply not be able to start and you stagnate for a while if you survive at all. Stagnation eventually alienates investors and users, in that order.</p>
<p>So it’s an extremely risky thing to copy. Some companies are certainly looking at it and concluding they could do the same and a few will try and some of those will fail in a way that gets much less coverage than the original attempt received.</p>
<p>There’s a related point worth holding onto through all of this. Most businesses don’t employ people to babysit their products. They build the product to be resilient and to run without much attention, because people whose job is watching something work are expensive and automation is cheaper. If a company really has a large number of staff doing nothing visible, that’s a fact about that company rather than an insight into how software organisations work.</p>
<p>Which means the lesson people want to take from this, that everybody is carrying enormous needless weight, doesn’t follow from a single example even if that example works out. It might be true somewhere. Finding out by cutting first and looking afterwards is an expensive way to run the experiment and you only get to run it once.</p>
<p>What makes it dangerous as a template is that the failures will be quiet. A company that cuts too deep doesn’t announce it. It gets slower, ships less, loses the people it most wanted to keep, and eighteen months later is simply less relevant than it was, with no single event anybody can point at.</p>
<p>That’s the outcome to weigh, and it never makes the news. And the case being copied hasn’t finished yet. Anyone drawing a lesson from it is drawing it from the first year of something that needs several years to resolve, which is roughly the same as declaring a patient cured on the way out of surgery.</p>
]]></content:encoded>
      <category>work</category>
      <category>startup</category>
    </item>
    <item>
      <title>You are not in their thoughts at all</title>
      <link>https://ooer.com/posts/you-are-not-in-their-thoughts/</link>
      <guid isPermaLink="false">you-are-not-in-their-thoughts</guid>
      <pubDate>Wed, 12 Oct 2022 00:00:00 GMT</pubDate>
      <description>What other people are actually thinking about you.</description>
      <content:encoded><![CDATA[<p>The most useful thing anybody ever worked out about other people is that you occupy very little space in their minds.</p>
<p>Not you specifically. Everyone. Nobody in this is special or famous or rich enough for it to work differently and the ones who are famous mostly find it applies to them too once they’re out of view. People may see you and they don’t much care and that isn’t a self-effacing complaint dressed up as an observation. It’s that everyone is inside their own life, fighting whatever they’re currently fighting, and not spending much of the day thinking about anybody else.</p>
<p>We assume we’re being judged harshly when we do something we’ve decided is embarrassing. The reality is that we mostly aren’t being judged at all because the judging would require somebody to still be thinking about it and they aren’t.</p>
<p>Try it with a room. Walk into a bar with three hundred people in it and you’ll register maybe half a dozen of them. You’ll have a quick reaction to each one, some assessment you’d be slightly ashamed of if it were said out loud, and then it’s gone. You didn’t see the other two hundred and ninety four in any meaningful sense, and five minutes later you’ve forgotten all six as well, including whichever one you reacted to most strongly.</p>
<p>Everyone in that room is doing exactly the same thing which means the version of you that exists in a stranger’s head has a lifespan of about five minutes and roughly two adjectives in it. Why put any weight on what somebody might be thinking when the probability is very high that you’re not in their thoughts at all.</p>
<p>Getting that straight is what makes it possible to live the way you want to. Not through bravado or by deciding other people’s opinions don’t matter on principle but by noticing that the audience you’re performing for is largely imaginary. The scrutiny you’re managing is your own, projected outward onto people who are busy.</p>
<p>There’s an obvious exception and it’s worth stating rather than pretending to a detachment nobody has. What a partner thinks matters. What close friends think matters. The useful part there is that those people will tell you if they think something’s wrong which means you can stop guessing at their opinions and wait for them to arrive. If it’s important they’ll say so. If they haven’t said so, it probably isn’t and the version you’ve constructed of their disapproval is again your own.</p>
<p>That’s the whole thing and it takes about a decade to properly believe. Most of the discomfort you’re carrying about how you’re being perceived is being generated locally and the people you’re worried about have gone home and are worrying about something else entirely.</p>
<p>The practical use of this is narrower than it sounds, and it doesn’t make you braver and it won’t help with anything you’re avoiding for a good reason. What it removes is the phantom audience, and a surprising share of what stops people doing things is that audience rather than the thing itself.</p>
<p>The other thing it gives you is a bit of charity in the other direction. If nobody is thinking much about you, then you’re also not thinking much about them, and most of the slights you’ve collected over the years were probably somebody being distracted rather than somebody making a decision about you.</p>
<p>None of which makes the feeling go away, and knowing a thing and believing it are different operations. It does mean that when the feeling turns up you have somewhere to put it, which is more than most self-consciousness offers you.</p>
]]></content:encoded>
      <category>thinking</category>
      <category>culture</category>
    </item>
    <item>
      <title>React is not the code that gets bundled</title>
      <link>https://ooer.com/posts/react-is-not-the-bundle/</link>
      <guid isPermaLink="false">react-is-not-the-bundle</guid>
      <pubDate>Wed, 10 Aug 2022 00:00:00 GMT</pubDate>
      <description>Why a smaller, faster alternative usually is not one.</description>
      <content:encoded><![CDATA[<p>A library that reaches the same end result as React, in three kilobytes rather than thirty and runs faster in some situations, is still not an alternative to React.</p>
<p>Start with the numbers because they’re the part that sounds decisive and three kilobytes is better than thirty and that’s not in dispute. If your main bundle is three thousand kilobytes then swapping one for the other changes nothing anybody will notice and you’ve spent a rewrite on a rounding error. Every framework in current use is fast enough to hold sixty frames per second when it’s used properly and hardly any of them add more than a couple of percent to page weight.</p>
<p>Which of those matters depends entirely on who you’re serving and that’s a real decision rather than a general truth and a business tool with five hundred users can afford weight that a consumer product with two hundred million cannot. Choosing your technology against your actual audience is the sensible version of this argument and it’s not the version that gets made.</p>
<p>What most developers should be weighing instead is the ecosystem, the tooling, the documentation, the quality of the code itself and how testable the thing is. That’s where React is really strong. There’s an enormous supply of good libraries, several excellent tools, documentation that’s unusually well written and a core that’s accessible enough to read when you need to know what it’s doing. Largely thanks to one person’s efforts, React applications are also very testable which is not true of everything.</p>
<p>Add those together and you get something worth more than any benchmark. A React application can be written well, be close to bug free, be fast and be a reasonable foundation for a business. It very often isn’t any of those things and the important part is that nothing about the framework is stopping you.</p>
<p>This is exactly why a smaller, faster library usually isn’t an alternative. A developer using it will be less capable than a developer using React, not because they’re worse but because the tooling around it isn’t there. There’s no debugger built for it, no testing story anybody has refined and no stack of answers from people who hit the same thing last year and wrote it down. You’re doing the same work with fewer tools and less built up knowledge and the three kilobytes will not make up for it.</p>
<p>React isn’t the code that ends up in the bundle and it’s everything around the code and almost all of that is invisible in the comparison people publish.</p>
<p>So if you’re building something in this space and you want it adopted, shaving another millisecond or another tenth of a kilobyte is not the work. The gap between you and the incumbent is developer experience and it’s measured in documentation, tooling and years. That’s a much less exciting project than optimising the diffing algorithm and it’s the one that decides whether anybody can use what you built.</p>
<p>The same thing plays out with languages and databases and anything else people compare on a single axis. The winner is usually whichever one has had the most person-years poured into the boring surrounding work and that’s very hard to catch up on because it accrues rather than being built.</p>
<p>Speed is a feature you can add in a quarter. An ecosystem is not.</p>
<p>If you’re picking for a project rather than building one, the useful question is what happens when you get stuck at four in the afternoon on something odd. With a mature ecosystem you search a phrase and find three people who hit it. With a lean one you read the source. Both are fine. Only one of them is fine every week for two years.</p>
]]></content:encoded>
      <category>react</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Most apps are doing nothing most of the time</title>
      <link>https://ooer.com/posts/apps-are-doing-nothing/</link>
      <guid isPermaLink="false">apps-are-doing-nothing</guid>
      <pubDate>Wed, 03 Aug 2022 00:00:00 GMT</pubDate>
      <description>What a framework benchmark measures, and what users notice.</description>
      <content:encoded><![CDATA[<p>Very few applications need sustained rapid DOM changes over a long period and that’s the workload every framework benchmark is built around and almost nobody has it.</p>
<p>What most web apps do is sit idle about ninety nine percent of the time. Then somebody clicks a button or types in a box, and four or five things around the page need to update inside one frame which is roughly ten milliseconds once you’ve paid the browser’s own rendering overhead. That’s the actual job. It isn’t demanding and any framework written this decade can do it comfortably.</p>
<p>Which makes it really a shame that so many apps feel terrible anyway. They’re doing practically nothing and they still stutter, and no framework choice explains that because the thing being asked for is well within what all of them can deliver.</p>
<p>This is the part where React has been getting something right that gets missed in the comparisons. The work in React 18 is an attempt to work out which events matter most to the person sitting there, and to schedule the DOM changes from those interactions ahead of changes caused by everything else. When there are a lot of updates it batches them across several frames rather than trying to land them all at once.</p>
<p>The consequence is a bit odd. A React interface will probably be slower than one built on something leaner, measured properly with a stopwatch and it will feel faster. The changes that came from your interaction happen first and the rest arrives when it arrives and that’s what people actually want and it isn’t what a benchmark rewards.</p>
<p>Every framework has an upper bound on what it can push through. If you aren’t anywhere near yours then framework speed doesn’t matter at all and choosing on that basis is choosing on a number that will never bind. If you are near it, then React’s approach is the better one because it spends the available time on the part the user is paying attention to rather than spreading it evenly across work nobody asked about.</p>
<p>The technically faster frameworks are really faster and that’s worth something real. What it buys is headroom, and headroom is only valuable up to the point where you cross what the thing can do. Past that line the experience degrades quickly because there’s no ordering happening underneath to protect the interaction you care about.</p>
<p>Which matters more than it sounds, because a lot of web developers are not especially good at writing efficient code. That’s not a slight. It’s the ordinary distribution of skill in any large profession. If the framework can absorb some of that and still keep the interface quick, it’s doing something valuable that doesn’t show up in any measurement anybody publishes.</p>
<p>So the comparison to run isn’t which framework updates ten thousand rows fastest. It’s what happens to the one your users are looking at when your least experienced developer ships something careless into it on a Thursday.</p>
<p>There’s a wider habit hiding in this. Benchmarks get built around the hardest case anyone can construct, because that’s where the differences show up and a chart with no gaps in it isn’t worth publishing. Then everybody picks tools using a measurement taken at a load they’ll never see and the thing that actually decides how the app feels goes unmeasured because it’s harder to put on an axis.</p>
<p>Read the workload before you read the numbers.</p>
<p>The measurement that would actually help is one almost nobody publishes, which is how long it takes from a click to the first visible change on a page doing ordinary work on a mid-range phone over a normal connection. That number is unglamorous, it varies by app rather than by framework and it’s the only one your users are ever going to experience directly.</p>
]]></content:encoded>
      <category>performance</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Employers do not care what you did at the weekend</title>
      <link>https://ooer.com/posts/employers-do-not-care-about-weekends/</link>
      <guid isPermaLink="false">employers-do-not-care-about-weekends</guid>
      <pubDate>Thu, 12 May 2022 00:00:00 GMT</pubDate>
      <description>Four reasons the side project myth keeps going.</description>
      <content:encoded><![CDATA[<p>Staying sharp is supposed to mean keeping up with trends and building things in your own time. Employers mostly don’t care.</p>
<p>They don’t care about your side projects, or what you do at weekends, or what you taught yourself last month. A good number of them don’t especially want you learning new things during working hours either which is a separate problem and a worse one. The belief is close to everywhere in this industry and it’s worth pulling apart why it survives because none of the four reasons is evidence.</p>
<p>The first is that the developers you see talking about this are often not describing their own situation. A lot of visible, widely followed developers work as advocates for a company and their job is building small showy projects and then talking about them. They rarely mention that the project was work. Their audience sees somebody producing an impressive thing that couldn’t possibly have been built in office hours, concludes it must have been evenings and weekends and extrapolates that becoming that kind of developer requires giving up your Sundays. The thing being modelled is a full time job with a different title.</p>
<p>The second is that people involved in hiring say they look at public repositories. They do look, when there’s something to look at. Having been hiring developers for fifteen years I still interview enormous numbers of people who have nothing public at all and honestly a public profile is more likely to move me towards ruling somebody out than towards arranging a conversation. Most public repositories are quick hacks nobody returned to, starter projects that stopped on day two, or things documented so thinly it’s impossible to work out what they even do.</p>
<p>The third reason is that we like building things and it’s useful to have a excuse. When a partner or children or parents would rather you did something else on a Sunday evening, being able to say your career will wither without it is a really effective argument. It’s also mostly untrue and the people making it are usually the ones who’d be doing the project anyway.</p>
<p>The fourth is the only one with real force behind it and a side project is a route out of a bad job. If you’re working with technology you dislike, at a company that won’t let you near anything else, then building something in your own time is how you get evidence that you can do the other thing. That’s a strategy and it works. It’s also an escape plan rather than a upkeep and those get mixed up constantly.</p>
<p>Notice what none of those four is. None of them is an employer wanting to see it. The belief circulates because of how the industry talks about itself, not because there’s a hiring manager somewhere weighing your weekends.</p>
<p>What this costs is worth being clear about. If you think an unpaid second shift is the price of staying employable, then anyone without spare evenings is going to conclude they’re falling behind. People with young children, people caring for a relative, people with a long commute, people who simply want a life outside this. None of them is falling behind and the belief that they are does real damage to people who are already tired.</p>
<p>Do the side projects if you enjoy them. Do them because building something you chose is one of the better feelings available in this work. Just don’t do them because you think somebody is checking because they aren’t and the ones who say they are mostly haven’t looked.</p>
<p>The version worth keeping is much smaller than the one people repeat and stay curious about the work you’re doing, and when you hit something you don’t understand, go and understand it. That’s it. It happens during the week, it’s part of the job rather than an addition to it, and no employer worth working for will object to you spending an afternoon on it.</p>
<p>The test is simple enough. Ask anyone who’s told you this whether they’ve ever actually turned down a candidate for having nothing public, or promoted somebody for a weekend project. Almost nobody has a real example and the ones who do are usually describing a hire where the project was directly relevant to the role rather than evidence of general keenness.</p>
]]></content:encoded>
      <category>job</category>
      <category>culture</category>
    </item>
    <item>
      <title>Your salary is somebody's lost profit</title>
      <link>https://ooer.com/posts/your-salary-is-lost-profit/</link>
      <guid isPermaLink="false">your-salary-is-lost-profit</guid>
      <pubDate>Fri, 11 Mar 2022 00:00:00 GMT</pubDate>
      <description>Being in demand is a position rather than a property.</description>
      <content:encoded><![CDATA[<p>Having skills that are in demand, and being able to walk into another job whenever you like, is a description of the current market rather than a fact about you.</p>
<p>Try the hypothetical. Somebody builds a system that turns requirements into working code and it actually works. That’s a hard problem and nothing has solved it, and code generation has already shown it isn’t impossible to produce working output from a model. There are hundreds of founders working on this right now, possibly thousands, and one of them might get lucky.</p>
<p>How long are you in demand for after that lands. Years, months, less. Perhaps you’re fine because your value is in defining the requirements rather than typing the build and that’s a really fair position to be in. Perhaps your particular job is one where it can’t reach.</p>
<p>It would take out an enormous amount of the simple CRUD end of the industry though and that’s where the pressure would come from. If there are suddenly more developers than developer jobs, everything that keeps wages up stops working at once and you don’t get a raise when there are twenty people who’d take your role for less. You can’t negotiate terms when leaving means competing with all of them and the act of leaving pushes your own price down.</p>
<p>That’s one vaguely plausible scenario out of many, and I’m not predicting it and the point is what it reveals about the arrangement you’re currently in.</p>
<p>Developers are very well paid right now and it’s worth seeing that clearly for what it is which is an opportunity for disruption. Your salary is partly somebody’s lost profit. Companies do not want to pay what they pay and they pay it because the market makes them and that’s the entire mechanism holding the number where it is. There’s no other force involved.</p>
<p>Follow that through. If a company can cut that cost by lowering wages or lowering headcount, every employer in the industry will move on it at the same time because the incentive is identical across all of them and none of them has a reason to hold back. Founders know this is a large pain point for their customers and they’re working on it. That’s not a conspiracy. It’s the ordinary operation of people looking for something expensive to make cheaper.</p>
<p>Which is the thing worth sitting with when the subject of a union comes up and the answer is that you personally have options. You do, today. So did every worker in every industry that got reshaped, right up until the year they didn’t and the useful moment to have built something collective is always earlier than the moment it becomes obviously necessary.</p>
<p>Technological change reducing how many people you need has been the driving force behind a union in a lot of other industries. The scenario holds up even if the specific version where a machine writes your code turns out to be fanciful because the mechanism doesn’t depend on which technology does it.</p>
<p>None of that means the scenario arrives, and predictions about this have a poor record going back decades. What it means is that the reason you’re paid well is external to you, and anything external can move and the arguments people reach for about their own being safe are the ones every group has made shortly before finding out otherwise.</p>
<p>The part worth acting on is small and boring. Know what you’d do if the market moved, keep the relationships that would matter, and treat the current number as a position rather than an identity. That costs almost nothing while things are good and it’s the only version of this that’s useful before the fact rather than after it.</p>
]]></content:encoded>
      <category>money</category>
      <category>ai</category>
    </item>
    <item>
      <title>Comfort takes away the need</title>
      <link>https://ooer.com/posts/comfort-takes-away-the-need/</link>
      <guid isPermaLink="false">comfort-takes-away-the-need</guid>
      <pubDate>Tue, 14 Dec 2021 00:00:00 GMT</pubDate>
      <description>Two things the very rich have in common, and what removes one of them.</description>
      <content:encoded><![CDATA[<p>Living frugally when you don’t have to is a good way to have everything you need and it’s also a fairly reliable way of never getting rich.</p>
<p>That isn’t a criticism and for most people it isn’t a problem because having everything you need is the thing money is for and a Lamborghini is not obviously an improvement on it. It’s worth saying out loud anyway because the two goals get talked about as though one leads to the other and they mostly don’t.</p>
<p>Nearly every genuinely rich person I’ve met and by rich I mean assets over roughly a hundred million that weren’t inherited, has had two things in common.</p>
<p>The first is focus and it’s the one that sounds admirable. They can take an idea and see it all the way through which sounds like a small thing and is enormously rare. They believe in themselves, they believe in the specific idea and then they execute on it for years without the belief degrading. Anyone deliberately living below their means to work on something is displaying exactly that and it’s the harder of the two to acquire.</p>
<p>The second is need and it’s the one nobody puts in the interview. Actually needing the money whether to start at all or to fund a lavish life, or to keep up with a group of people whose approval matters to them, turns out to be a powerful driving force. Not a noble one. Powerful, and considerably more reliable than the noble version.</p>
<p>Those two interact in a way that catches people out. If you arrange your life so the need goes away, you’ve removed one of the two engines and most people cannot execute on an idea for a decade on focus alone. Grow your assets slowly until you’re comfortable and the odds are you never level up again because the thing that would have pushed you through the bad eighteen months in the middle isn’t there any more. You don’t need to. The comfortable version of you keeps making the reasonable decision.</p>
<p>So the advice, for anyone whose actual goal is to get rich rather than to be fine, is uncomfortable. Growing steadily and then working on an idea from a position of security is not how it usually happens. It’s much more common to see somebody young who needs it to work driving an idea all the way to an exit, precisely because there was no acceptable version of stopping.</p>
<p>None of that is universal and it isn’t a rule. Plenty of people come to an idea later, with a house and assets behind them, and execute brilliantly. It’s just noticeably less common and the explanation isn’t that older founders have worse ideas.</p>
<p>Which leaves a choice that mostly gets made by accident. Almost nobody sits down and decides between being comfortable and being rich. They optimise for security year by year because each individual decision is obviously correct, and then wonder later why the ambition drained out of it. The decisions were right. They just added up to a different life than the one being imagined alongside them.</p>
<p>The useful version of this isn’t a strategy for getting rich because most people reading it don’t want that and shouldn’t pretend otherwise. It’s that ambition of any kind runs on some sort of pressure, and comfort dissolves pressure indiscriminately without asking which of it you were using.</p>
<p>If there’s something you intend to do eventually, it’s worth noticing what currently makes it feel urgent, and whether you’re quietly in the process of removing that.</p>
]]></content:encoded>
      <category>money</category>
      <category>startup</category>
    </item>
    <item>
      <title>Most of the data you collect is a web counter</title>
      <link>https://ooer.com/posts/most-of-it-is-a-web-counter/</link>
      <guid isPermaLink="false">most-of-it-is-a-web-counter</guid>
      <pubDate>Tue, 07 Dec 2021 00:00:00 GMT</pubDate>
      <description>Tracking users you never intended to learn anything from.</description>
      <content:encoded><![CDATA[<p>Tracking people is almost always a bad idea, even when they get something back for it and even when they’ve said they don’t mind.</p>
<p>The part that makes it worse is that most sites gathering the data never use it. They put the script in because it’s what you do, and then the numbers accumulate in somebody else’s database and get looked at roughly never. Analytics gets installed on an enormous number of sites and ends up functioning as a web counter which is a thing you could have built in an afternoon in 1998 without telling anybody’s browser to phone home.</p>
<p>That’s infuriating if you think privacy is worth defending. Not because collecting data is automatically wrong but because the trade everyone keeps defending is supposed to have a benefit on the other side of it. If you’re going to violate my privacy, at least do it for a reason. Do something with the data you took. Learn something you couldn’t have learned otherwise and change the product because of it.</p>
<p>There are cases where hoovering up detailed information about real users is genuinely justified. Real user performance monitoring is one of them because the thing you’re trying to understand is what actually happens on the devices and networks people have rather than on the machine you build on, and no synthetic test can tell you that.</p>
<p>But be honest about who that applies to. Unless you’re a large company with real resources behind it, all of that performance data is going to sit in a database while a senior person occasionally opens the dashboard overview, thinks that the images could be smaller, notices that Android users are having a rough time, and then closes the tab. Those are not good reasons to be collecting real user data instead of running Lighthouse and reading the output.</p>
<p>Lighthouse is good enough for most people and the group it covers is a great deal larger than the group who believe they are in it. It runs locally and it costs nobody their privacy and the things it tells you are broadly the things a small team will have the capacity to act on anyway.</p>
<p>I suspect the frustrating part of working in web performance is watching exactly this happen. The small companies and startups don’t have the resources to do the real user measurement well so they cargo cult what the big companies do without ever spending the time to make good on whatever they might learn from it. You get the collection without the analysis which is the worst combination available, because it has all of the cost and none of the benefit.</p>
<p>To be fair to anyone writing about this seriously, they’re usually addressing people who do have the resources and the intent, and I’m the one turning up to apply their advice to an audience they weren’t talking to. That’s my fault more than theirs.</p>
<p>It’s still where most of the tracking on the web comes from. Not from careful teams with a plan for the data, but from everyone else copying the shape of what careful teams do, and leaving the script in place for years afterwards because nobody remembers who added it or why.</p>
<p>The test is easy enough to apply to your own site, and look at whatever you’re collecting and find the last time a decision changed because of it. If you can’t point at one, you aren’t measuring anything, you’re just paying a privacy cost on behalf of your users and getting a number you glance at when somebody asks how traffic is doing.</p>
<p>Turning it off is free. That’s the part that makes it awkward.</p>
]]></content:encoded>
      <category>privacy</category>
      <category>performance</category>
    </item>
    <item>
      <title>Leeching off the system is not a skill</title>
      <link>https://ooer.com/posts/leeching-is-not-a-skill/</link>
      <guid isPermaLink="false">leeching-is-not-a-skill</guid>
      <pubDate>Tue, 30 Nov 2021 00:00:00 GMT</pubDate>
      <description>Why a founder-shaped forum handles cryptocurrency badly.</description>
      <content:encoded><![CDATA[<p>Cryptocurrency threads on a founders’ forum go badly with such reliability that it’s worth asking what the mismatch actually is.</p>
<p>You’re on a site largely built for people who want to build things. That’s how it started and you can still see the shape of it in the Show HN posts and anything startup-flavoured, even though there’s far more going on now than there used to be. Code topics, machine learning, electric vehicles, environmental things, a bit of futurism. The core is still founders and that alone doesn’t rule out a good conversation about crypto because there are genuine opportunities in it and real pain points somebody could go and solve.</p>
<p>The trouble is that three things about the subject rub directly against what that audience respects.</p>
<p>The first is that a large number of the people making a living from crypto are purely speculating. They aren’t building anything at all. They’re trying to buy low and sell high which is a legitimate way to make money and is not a thing founders tend to admire. What gets respect from the people you’re talking to is going out, starting something, and building a thing that solves a real problem, even a problem the person admiring it doesn’t personally have. Leeching off the system isn’t a skill and an audience selected for wanting to build will read it that way whether or not that’s fair.</p>
<p>The second is that a lot of crypto isn’t solving a problem. It’s trying to be digital gold without the parts of gold that make gold useful so what’s left is a store of value and nothing else. There genuinely are good uses for the technology, and even for things like NFTs, and almost none of the speculation is about those. It’s the buying and selling and a forum full of people who make things is not a trading forum and has never wanted to be one.</p>
<p>The third is harder to argue away and it’s the one that ends most of the threads. However you cut it, the returns everybody is there to discuss depend on somebody else arriving later and paying more.</p>
<p>Put those together and you get a subject where the participants and the audience are optimising for different things, and both sides read the other as missing the point. The crypto side sees a group of people being sniffy about a technology they haven’t studied. The forum side sees speculation dressed up as engineering. Both are partly right. Neither will convince the other. The disagreement was never about the technology.</p>
<p>Which is why the threads don’t get better with more information. You can post the most careful technical explanation of a protocol anybody has written and the top comment will still be about the price because the price is what most of the visible activity in the space is about and everyone knows it.</p>
<p>The conversation that would work is the one nobody starts. Somebody building an actual product on this, solving an actual problem for actual customers, writing about what was hard. That gets a completely different reception and it gets it because it’s the thing the audience turns up for.</p>
<p>You can watch the same mismatch play out in other subjects when the audience shifts underneath a topic. Anything where most of the visible participants are extracting value rather than adding it gets the same treatment, and the people doing genuinely interesting work in that space end up paying for the behaviour of everybody around them, which is unfair and completely predictable.</p>
<p>If you’re building something real in a field like that, the useful move is to lead with the problem you solved and let the technology come second.</p>
]]></content:encoded>
      <category>crypto</category>
      <category>social</category>
    </item>
    <item>
      <title>Incompetence is not an explanation</title>
      <link>https://ooer.com/posts/incompetence-is-not-an-explanation/</link>
      <guid isPermaLink="false">incompetence-is-not-an-explanation</guid>
      <pubDate>Tue, 07 Sep 2021 00:00:00 GMT</pubDate>
      <description>What blaming one person costs everybody else.</description>
      <content:encoded><![CDATA[<p>Incompetence is a poor explanation for anything and it’s a very poor one for a security failure inside a large system.</p>
<p>It’s always available which is part of the problem. Something goes badly wrong, somebody’s name is attached to the change and the story writes itself in a sentence. The trouble starts the moment you follow the chain outward because the work was part of a team effort and you have to decide whether everyone on that team is also incompetent.</p>
<p>Take a database exposed in the cloud. The people who configured it were using a managed service which presumably didn’t warn them clearly enough so are the platform team incompetent for shipping something that dangerous by default. The documentation plainly did a bad job of explaining the security model so are the writers who drafted and checked and shipped it incompetent as well. If the companies involved employed a security team to audit their cloud applications then that team missed it as well. And if the security team did catch it and reported it, then somebody further up didn’t read the report properly which makes the reporting incompetent instead.</p>
<p>You can walk it in both directions and the chain never stops anywhere that satisfies you. That’s not a special property of this incident. It’s how every industry works, with layers of complexity stacked on layers and nobody anywhere in the stack having enough oversight to take real responsibility for a mistake that happened three floors down the rabbit hole.</p>
<p>Somewhere in there you could point at one decision and call it incompetence and be right. Doing that relieves everybody else of their small part in building the chain of tools and defaults and documentation that made the mistake easy to make and that’s the actual cost of the explanation rather than any unfairness to the individual.</p>
<p>Because if all the blame lands on one person, nobody else has any reason to change anything. The team can decide that Chris was terrible, feel relieved that Chris has been let go, and carry on with a system that will produce the same outcome as soon as somebody else is standing in the same place. The story satisfies you precisely because it asks nothing of anyone still in the building.</p>
<p>The other route is less satisfying and a lot more use to you. Accept that mistakes are inevitable, that anybody in that position could have made this one, and then ask what in the surrounding system made it likely. That produces a list of small changes across several teams, none of which is dramatic, and all of which reduce the chance of the next one.</p>
<p>It also takes away the thing you actually want from the blame story, which is a moment where the problem is over. There isn’t one. There’s just a slightly better system than yesterday, and another incident eventually and the same question to ask again.</p>
<p>There’s a practical reason to care beyond fairness, which is that the blame version gives you nothing to do. A report that names a person produces a dismissal and no change. A report that maps the chain produces a documentation fix, a default change, a check in a pipeline and a different escalation path, and any one of those would have broken the sequence on its own.</p>
<p>One of those outcomes feels like justice. The other one is the only one that alters the odds next time.</p>
<p>So when you next read an incident write-up and find a name in it, the useful question is what the other nine links in that chain were doing, and whether any of them changed afterwards.</p>
]]></content:encoded>
      <category>software</category>
      <category>security</category>
    </item>
    <item>
      <title>The design decisions get made either way</title>
      <link>https://ooer.com/posts/decisions-get-made-either-way/</link>
      <guid isPermaLink="false">decisions-get-made-either-way</guid>
      <pubDate>Tue, 20 Apr 2021 00:00:00 GMT</pubDate>
      <description>Before the code or after it, but somebody is deciding.</description>
      <content:encoded><![CDATA[<p>Nobody wants to work somewhere every small technical decision goes through three boards. That isn’t the argument.</p>
<p>Everyone who touches the application is making design decisions whatever process you run and the only thing that changes between one process and another is when those decisions happen and who gets to see them. In the old style they were made before the code was written and written down somewhere you could argue with. In the agile style they’re made after the code is written, by whoever wrote it, at the moment they wrote it.</p>
<p>Most of the time that’s fine for you and for everyone downstream of you. Developers are generally good at their work and they make decent decisions under time pressure and a decision made by the person holding the problem is often better than one made by a committee holding a document. That’s the real case for working the newer way and it’s a strong one.</p>
<p>Sometimes they get it wrong, though, and when they do you get code design problems that nobody spotted because there was no point in the process where spotting them was anyone’s job. The same gap is why automated tests so often miss cases that a decent QA engineer would have written without thinking about it. The tests cover what the developer imagined while building the thing which is exactly the set of cases they had already handled.</p>
<p>An enormous amount of the code in the applications you rely on every day was never designed at all. Nobody thought it through and nobody considered the edge cases because the feature was thrown together in a week and it sort of works. Every time you hit a broken website, or a bug in production, or something slow that has no business being slow, the explanation underneath is usually that the people who built it didn’t take the time to think about what they were building, and in the worse companies they weren’t given the time to take.</p>
<p>A lot of developers genuinely prefer working that way and I understand why. You get to hack on something, get it moving, and be onto the next problem before the first one has had a chance to bore you. That’s fun. Careful work often isn’t. Pretending otherwise is dishonest.</p>
<p>It’s also worse for users, and users are the people I care about more. I say that as somebody who has been making things for the web for close to twenty five years and who enjoys the hacking as much as anyone. The satisfaction of the person building the thing and the experience of the person using it are different quantities, and when a process optimises hard for the first one it tends to be quietly paid for by the second.</p>
<p>None of this is an argument for going back to Prince2 and waterfall, and my tolerance for that sort of bureaucracy is no higher than yours. The claim is narrower. Things have gone a long way in one direction and a good number of developers would produce better work if they spent longer thinking about what they were about to build before leaping into the first solution that would satisfy the acceptance criteria somebody in product wrote down.</p>
<p>That’s not a process change and it doesn’t need a board. It’s an hour with a pen, before you open the editor, on the parts of the problem where being wrong is expensive.</p>
<p>The reason this is hard to fix from inside a team is that the cost never lands where the decision was made. A feature shipped in a week with three unconsidered edge cases looks like a success on the day it goes out and turns into four support tickets a month for the next two years, handled by different people who have no idea the two things are connected.</p>
<p>Nobody is being lazy. The feedback loop is just long enough that the person who could have prevented it never finds out they didn’t.</p>
]]></content:encoded>
      <category>software</category>
      <category>work</category>
    </item>
    <item>
      <title>Nothing makes you write the next one</title>
      <link>https://ooer.com/posts/nothing-makes-you-write-the-next-one/</link>
      <guid isPermaLink="false">nothing-makes-you-write-the-next-one</guid>
      <pubDate>Tue, 19 Jan 2021 00:00:00 GMT</pubDate>
      <description>The unsolved problem in every blogging platform.</description>
      <content:encoded><![CDATA[<p>Every discussion about a new blogging platform ends up being about the tech which is the least interesting part of it.</p>
<p>What stack it uses, whether it’s static, what the markup looks like when you view source. All of that is secondary to whether you actually use the thing to build up a body of writing that shows what you know and what you think over a period of years. That’s what a blog is. It isn’t the tags and it isn’t the stylesheet. It’s the content sitting inside them, and any platform discussion that doesn’t get to that has stopped short of the point.</p>
<p>Where the next generation framing is right is in going after the friction between having a thought and having it published. That’s the real target and it’s worth attacking. There are three things any platform has to make trivially easy before it has a chance and the industry has comprehensively solved one of them.</p>
<p>The first is setup and maintenance. If my laptop dies and I can’t clone a repository and run two commands to be exactly where I was, it doesn’t work. That constraint rules out a surprising amount of what gets built and it’s the one thing the static site generation world has genuinely nailed.</p>
<p>The second is publishing itself. Most blogs run on Markdown with either frontmatter or a specific file path doing the work which is fine and puts most of the cognitive load onto the writer. You have to remember the shape of the frontmatter, and where the file goes, and what the slug should be, and whether you care about the URL structure enough to fight it. I use a static generator that’s very good and if I worried less about URLs than I do it would be close to perfect. But I do worry about them so it isn’t.</p>
<p>The third is the one nobody has ever solved and the reason most blogs die. There’s nothing that pushes you to write.</p>
<p>That’s the kicker. Every platform is built around the moment you already want to publish something and the actual bottleneck is the six weeks before that when you don’t. A tool that suggested posts you ought to write, based on what you’ve written before and what you keep circling back to, would produce more than any improvement to the publishing step. So would something that noticed you’d written and said so.</p>
<p>That sounds trivial and it’s slightly embarrassing to admit. It’s also the mechanism every social platform is built on and the reason people who never write anything anywhere will post four times a day to a timeline. The feedback isn’t a nice extra on top of the writing. For most people it’s the thing that produces the writing at all and a blog is a format that deliberately removes it.</p>
<p>One or two platforms have come close to taking that seriously. None of them have gone far enough and the ones that try tend to drift towards the timeline shape and stop being blogs. That trade might be unavoidable, and if it is then the honest version of a next generation blog platform is one that admits the hard problem is motivation rather than markup, and does something about it anyway.</p>
<p>The workaround most people land on is external and slightly undignified. You tell somebody you’re going to write a thing, or you set up a schedule you’d be embarrassed to break, or you find one reader whose interest you don’t want to lose. None of that is a feature of any platform and all of it works better than any platform, which tells you roughly where the real problem sits.</p>
<p>The tooling was never the bottleneck. It was just the part that could be improved by writing code.</p>
]]></content:encoded>
      <category>website</category>
      <category>meta</category>
    </item>
    <item>
      <title>Market rate is the median of bad negotiators</title>
      <link>https://ooer.com/posts/market-rate-is-the-median/</link>
      <guid isPermaLink="false">market-rate-is-the-median</guid>
      <pubDate>Tue, 29 Sep 2020 00:00:00 GMT</pubDate>
      <description>What a salary benchmark is actually measuring.</description>
      <content:encoded><![CDATA[<p>Nobody is suggesting that every penny a company makes should go to its employees. The suggestion is narrower and harder to dismiss.</p>
<p>It’s that companies might be paying people considerably less than they could and that developers might not be getting a good deal even though wages look high next to other industries. Those two things can both be true at once. A salary can be excellent compared to what a nurse earns and still be well below what the person is worth to the business, and pointing at the first comparison doesn’t answer the second.</p>
<p>The usual reply is to ask why anyone should expect more than the market rate for their labour. That sounds like it settles the matter and it only works if you don’t look at what market rate means. It’s the median negotiated salary for similar roles. That’s it. It’s a description of what other people managed to agree and it gets treated as though it were a price discovered by a market.</p>
<p>Prices work the way people expect when both sides have roughly comparable information and roughly comparable leverage. That isn’t the situation here. The employer knows what everyone in the building earns, what the budget for the role is, what the last three candidates asked for and what they eventually settled at. You know what you currently earn and whatever you managed to piece together from people willing to talk about it, and one side of that table is negotiating with data and the other is negotiating with a feeling.</p>
<p>Follow that through and the benchmark starts looking strange. If most developers negotiate badly, and most do because it’s an unpleasant thing to do occasionally against people who do it constantly, then the median of what they agreed is the median of a lot of bad outcomes. Getting the market rate means you did as well as the other people who didn’t do very well and it feels like a floor and functions like a ceiling.</p>
<p>Which means using market rate to set a salary might be holding wages down rather than discovering where they should sit. Every company benchmarks against the same surveys, every survey is built from what people accepted, and what people accepted was shaped by the previous round of the same exercise. The number reproduces itself and everyone involved can honestly say they’re paying the going rate.</p>
<p>I’m not claiming to have proved any of that. It’s a challenge to an assumption rather than an argument with numbers behind it and the assumption is doing an enormous amount of unexamined work in these conversations. Price theory is being applied to a market that doesn’t obviously have the properties price theory needs.</p>
<p>None of which changes anything on Monday and it’s fair to point out that this is mostly futile speculation, and nobody is going to restructure how developer salaries are set because of a comment on a forum. It’s still worth knowing that market rate is a description of what happened rather than a measure of what anything is worth, particularly at the moment somebody quotes it at you as though it settles the question.</p>
<p>The practical version, if you’re on the receiving end of it, is to notice what you’re being told when somebody quotes the figure at you. You’re being told what other people settled for, by a person who knows a great deal more about the distribution than you do and the implication that this is what the role is worth is doing work the number cannot support.</p>
<p>That doesn’t hand you any leverage on its own. It does mean you can stop treating the number as a fact about the world and start treating it as an opening position which is what it always was.</p>
]]></content:encoded>
      <category>money</category>
      <category>job</category>
    </item>
    <item>
      <title>Your app is not slow because of the framework</title>
      <link>https://ooer.com/posts/not-slow-because-of-the-framework/</link>
      <guid isPermaLink="false">not-slow-because-of-the-framework</guid>
      <pubDate>Tue, 21 Apr 2020 00:00:00 GMT</pubDate>
      <description>Where framework choice actually changes performance, and where it does not.</description>
      <content:encoded><![CDATA[<p>If your framework is making a real difference to how fast your app feels, you’ve probably made some horrible mistakes elsewhere.</p>
<p>React apps aren’t slow because of React. Vue apps aren’t slow because of Vue. Svelte apps aren’t slow because of Svelte and the pattern continues for every framework anyone has shipped. The people who build these things work very hard at not getting in your way and they do a genuinely good job of it and if your app is slow then the overwhelming likelihood is that the slow part is yours.</p>
<p>You can check this against what people have built. There are React apps handling tens of thousands of DOM elements at once and holding a solid sixty frames per second which is not what you’d expect if the framework carried an inherent penalty at scale. Meanwhile anyone could write a Svelte app that struggles along at five frames per second and it wouldn’t take much effort or any deliberate sabotage. Fast and slow are things you do rather than things you inherit.</p>
<p>There are real edge cases and they’re worth knowing about. When an app is genuinely pushing what the browser can do, framework choice starts to matter, and which one is right depends on what the app does rather than on any general ranking. If you’re updating enormous numbers of DOM elements continuously then Svelte is a good choice. If you have a lot of elements and you only touch a few of them at a time, then React or anything else built on a virtual DOM will probably serve you better.</p>
<p>Notice that both of those are statements about a workload. Neither is a statement that one framework is better than another and the benchmark posts that suggest otherwise are almost always measuring a workload that isn’t yours.</p>
<p>The awkward part is how few applications are anywhere near those edges and most web apps sit idle nearly all of the time and then change a handful of elements when somebody clicks something. If your app is a glorified to do list and an enormous number of them are, there’s no excuse for it being slow in any framework at all, and swapping the framework will not fix it because the framework was never the thing costing you the frames.</p>
<p>What usually costs the frames is more boring. Work happening on every render that only needed to happen once, and data fetched in a waterfall because it was easier to write that way. A list rendering every row when twenty are visible. Layout being read and written in the same tick and none of those care which framework you picked and all of them are yours to fix.</p>
<p>So the framework comparison is mostly a way of avoiding a harder conversation, and picking a faster one is a decision you can make in an afternoon and feel good about. Finding out which part of your own code is doing unnecessary work takes a profiler, some patience and a willingness to discover that the slow thing is something you wrote and were quite pleased with at the time.</p>
<p>The reason this matters beyond the argument is that framework choice gets made once, early, by whoever is around at the time, and then defended for years. If the team believes performance lives in that decision then every later slowdown becomes evidence about the framework rather than a thing to investigate and you end up with a rewrite proposal instead of a profile.</p>
<p>The profile is cheaper. It’s also considerably less fun to argue about at lunch which is most of why it doesn’t happen.</p>
]]></content:encoded>
      <category>performance</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Your old workflow was fine because nothing broke</title>
      <link>https://ooer.com/posts/nothing-broke-so-it-was-fine/</link>
      <guid isPermaLink="false">nothing-broke-so-it-was-fine</guid>
      <pubDate>Tue, 14 Apr 2020 00:00:00 GMT</pubDate>
      <description>Comparing git to the SVN setup you never saw fail.</description>
      <content:encoded><![CDATA[<p>Git is confusing and your old SVN workflow was simple, and you’re not doing anything wrong. That’s just how git works.</p>
<p>The comparison is worth pulling apart though, because a lot of it rests on an assumption you might not have noticed making. You’re taking the old setup as fine partly because it was straightforward and mostly because nothing catastrophic ever happened while you were using it. Those are different claims. The second one is luck reported as design.</p>
<p>Ask what would have happened if the SVN server had died. You’d have had a very bad time. Everybody would have downed tools until it came back, which on a large project is an expensive morning and possibly several. It isn’t an unrecoverable disaster and it is a shape of problem that git simply doesn’t have, because everyone already has the whole thing and you can stand up a new remote while people carry on working locally.</p>
<p>That’s the assumption baked into git that makes it feel over-engineered until the day it isn’t, and one day all of this is going to go horribly wrong. The tool is built by people who took that seriously, and the cost of taking it seriously is a mental model that’s harder to hold, which you pay for every single day in exchange for a bad day you might never have.</p>
<p>There’s a second assumption in there worth naming. Git treats the code as important in itself rather than only as a means to a working deployment. It isn’t just whether the thing runs. It’s whether the change is something the team has looked at and agrees with. Pull requests exist to give people visibility of how the codebase is moving and a way to have an input before it lands, which is a workflow decision rather than a technical one.</p>
<p>If your old process was that a feature did what it needed and UAT nodded it through, then there was very little oversight of what went to production. That can work well. It requires a solid UAT process and developers who genuinely care about the code they write, and where you have both of those you can go a long way without much ceremony. Where you don’t have both, the ceremony is doing something you weren’t seeing.</p>
<p>The branching model points the same way. Pulling the base branch into your local one and resolving conflicts on your own machine means the base branch should always work and always be deployable. With SVN it’s easy to break something and block everybody else while you sort it out, and the fact that this happened rarely doesn’t mean the exposure wasn’t there the whole time.</p>
<p>None of that makes git well designed as an interface, and the complaints about it are mostly fair. It’s just that a simpler tool feels simpler in the ordinary case and the difference between the two shows up in the cases you haven’t had yet.</p>
<p>That’s the honest comparison. Not simple against complicated, but which failures you’ve decided to buy insurance against, and whether the premium is worth it for the size of team and the length of project you’re actually running.</p>
<p>The general shape of this comes up whenever anyone compares a tool they know well to one they’re being made to learn. The familiar thing has failure modes you’ve internalised so thoroughly that you no longer count them as failures, and the new thing has failure modes you hit on the first afternoon and remember vividly. That asymmetry is real and it isn’t a reason to stay, and it also isn’t nothing.</p>
<p>What it means is that the comparison is worth doing on paper rather than from memory, because memory is systematically kind to whatever you already survived.</p>
]]></content:encoded>
      <category>code</category>
      <category>tech</category>
    </item>
    <item>
      <title>Nothing in the stack is as new as it looks</title>
      <link>https://ooer.com/posts/nothing-is-as-new-as-it-looks/</link>
      <guid isPermaLink="false">nothing-is-as-new-as-it-looks</guid>
      <pubDate>Tue, 07 Apr 2020 00:00:00 GMT</pubDate>
      <description>The pace of change, checked against the dates.</description>
      <content:encoded><![CDATA[<p>The complaint is that frontend moves too fast to keep up with and check the dates and most of it stops holding.</p>
<p>Take the list people usually reach for. Flexbox was defined in 2009 and landed in browsers about ten years ago and has been iterated on since and it was in the first public version of Chrome. That’s not new tech that blindsided anybody. It’s older than a good proportion of the codebases you’ll be asked to work on, and grid is a couple of years old and is the only genuinely recent thing on the list.</p>
<p>React was first released seven years ago and has been reasonably mainstream for five of them and you can dislike it for plenty of reasons and its arrival is not a dramatic change by any measure you’d apply to another industry. WASM has been around in browsers for a few years, the tooling for most languages is still patchy and it’s entirely unnecessary for 99.9% of web development. Most people using it are still in the phase of using it because it’s interesting rather than because it’s useful which is fine and isn’t the same as needing to learn it.</p>
<p>New JavaScript features get held up as the fast moving part and they aren’t moving especially fast either. What makes them feel fast is that transpilers hand you a feature long before the engines have it so you get to use things earlier than the standards process delivers them. That’s a choice you made. You can’t then blame the web for the pace when you opted into running ahead of it.</p>
<p>Countless frameworks is the one where the argument really comes apart. You don’t have to learn them all. Pick a number between zero and all of them, based on how much of your life you want to spend learning frameworks, and then learn that many. If the number feels overwhelming then you picked the wrong number and the thing generating the pressure is your own choice rather than the ecosystem. Same answer for plugins and build tools. Pick something, learn it properly, and refresh your tooling every few years when it stops earning its place.</p>
<p>None of this is a claim that nothing changes and extensions to the web platform arrive constantly and there’s no arguing that point. It’s that the specific things people list as evidence of unmanageable churn are mostly a decade old, mainstream for years, or optional in a way that makes the churn self inflicted.</p>
<p>What’s actually happening is a confusion between what exists and what you need. The volume of things that exist has genuinely exploded and the volume you need to do good work has barely moved and the anxiety comes from measuring yourself against the first number. Every conference talk and every newsletter is incentivised to describe the first number because the second one is boring and would take about ninety seconds to read.</p>
<p>So the useful question isn’t how to keep up. It’s how many of these you’ve decided to care about, and whether that decision was made deliberately or by reading too much of an industry that gets paid by the word.</p>
<p>There’s a version of this that isn’t complacent which is worth separating out. The platform genuinely does add things constantly and some of them matter a great deal, and staying employable does mean noticing when something changes the shape of the work rather than just adding another option. The skill is telling those apart and it’s a skill that gets harder every year because the volume of noise around each new thing keeps growing while the signal stays roughly constant.</p>
<p>Most of what arrives is an option. A few things a decade are a shift. Treating the first as the second is what exhausts people.</p>
]]></content:encoded>
      <category>javascript</category>
      <category>frontend</category>
    </item>
    <item>
      <title>A NodeList is not an HTMLCollection</title>
      <link>https://ooer.com/posts/a-nodelist-is-not-an-htmlcollection/</link>
      <guid isPermaLink="false">a-nodelist-is-not-an-htmlcollection</guid>
      <pubDate>Tue, 25 Feb 2020 00:00:00 GMT</pubDate>
      <description>What a DOM tutorial leaves out, and why the gaps matter.</description>
      <content:encoded><![CDATA[<p>A guide to managing the DOM without a library is a genuinely useful thing to have, and most of them tell you about half of what you need.</p>
<p>Take picking nodes which is the first page anyone reads. What tends to get left out is that every one of those calls lives on both a Document and an Element and the difference is the whole point. Calling getElementsByClassName on the document hands back everything in the page carrying that class, and calling it on an element hands back only its own descendants carrying it. If you’re wrangling a large page then one of those is dramatically better than the other, and chaining them is one of the more useful things you can do with the raw platform.</p>
<p>Then there’s the ID lookup which is described as fetching the one item with that ID. That’s right in the sense that you get one element back and wrong in that it implies only one could exist. Browsers don’t enforce ID uniqueness. You get the first match and the rest sit there in silence which is a gotcha that catches people new to this constantly. A framework would at least complain about a duplicate key. The platform will not say a word.</p>
<p>The one that costs people the most time is querySelectorAll which does not return a list of elements. It returns a NodeList and a NodeList is a different thing from the HTMLCollection that the older methods hand back. They print the same. Their behaviour diverges the moment you touch them. They behave differently the moment you try to do anything interesting. You can call forEach on a NodeList and you cannot call map, which throws people a curve ball at exactly the point they thought they understood the API.</p>
<p>And the guide manages not to mention querySelector at all, the call you actually want for a single node and the one most people should be reaching for first.</p>
<p>None of this is an argument for using a library instead. The plain API is fine and knowing it properly is worth more over a career than knowing any particular framework, which is the case the guide is making and it’s a good case. It’s that a walkthrough that lists method names without telling you how they differ from each other isn’t teaching the API. It’s teaching a list of names and the differences between them are precisely where you’ll lose an afternoon.</p>
<p>That’s the thing to watch for when you read this kind of material and a page that shows you what to type is easy to write and easy to check. A page that tells you what the platform will do when you’re not expecting it takes somebody who has been caught by it and that is the part worth paying for when you reach for prose instead of a reference.</p>
<p>If you’re writing this sort of guide, the return types are where the value is, and everything else is discoverable in ninety seconds with an editor open.</p>
<p>The deeper habit worth building is to check what came back rather than assume. Log the constructor rather than the contents, because two things that print identically in a console can behave completely differently the moment you try to iterate them and the platform has several pairs like this waiting for you.</p>
<p>It takes about four seconds and it will save you an afternoon roughly once a year for the rest of your career.</p>
]]></content:encoded>
      <category>javascript</category>
      <category>frontend</category>
    </item>
    <item>
      <title>You do not need to know how big the screen is</title>
      <link>https://ooer.com/posts/you-do-not-need-the-screen-size/</link>
      <guid isPermaLink="false">you-do-not-need-the-screen-size</guid>
      <pubDate>Tue, 14 Jan 2020 00:00:00 GMT</pubDate>
      <description>Native lazy loading, and who is supposed to do the measuring.</description>
      <content:encoded><![CDATA[<p>The objection to screen relative units for images is that you can’t use them because you don’t know how big the image will be and you don’t know that because you don’t know the size of the screen.</p>
<p>You don’t need to know. That’s the entire point of the units. When you set something to 25vh you’re telling the browser to use a quarter of the viewport height and the browser is the thing that knows what a quarter of the viewport height happens to be on this device at this moment. You’ve handed the measuring to the only participant with the measurements.</p>
<p>That’s useful in a specific way that matters here. If you want four images stacked vertically, the browser now knows it needs to reserve a box a quarter of the screen high and it can put that box in the layout before the image has arrived. Nothing shifts when the image loads. You’ve avoided the layout thrash that makes a page jump around while you’re trying to read it and you did it without measuring anything yourself.</p>
<p>The other half of the objection is that if JavaScript is still needed then the spec is worthless. That’s not quite what’s on the table. The parent case was wanting to change the width and height attributes of an image when the user resizes their browser and the resize event is precisely what exists for that. Wanting to react to a resize is a reason to use the resize event rather than evidence that the platform has failed you.</p>
<p>There’s a whole ladder of options underneath that, and which rung you want depends on what you’re trying to do. A fixed size image can have fixed width and height attributes and an image that should scale with the viewport can use relative units. Something that needs to be fixed on some devices and relative on others can be done with media queries, mixing and matching without a line of script. And if you genuinely need to compute the attributes at runtime, then yes, you write some JavaScript and that’s a normal thing to do rather than an admission of defeat.</p>
<p>The part worth being clear about is what the new specification actually buys. Lazy loading images with JavaScript worked perfectly well before this landed, and plenty of people had it working and the libraries were mature. The catch was that you needed the JavaScript which meant the weight of the code and the parse time and the dependency and the behaviour when script fails or is slow to arrive.</p>
<p>Getting the basic version of that behaviour from an attribute in the markup removes all of it for the common case. Not every case, and not the elaborate ones where you’re doing something clever with thresholds or placeholders. The common case which is the great bulk of images on almost every page anyone ships, where somebody just wants the images below the fold to wait their turn.</p>
<p>That’s a good trade and it’s the shape most platform features take and they don’t remove the need for script at the top end. They remove the need for script at the bottom end, where most of the web lives and the argument that they haven’t solved everything tends to come from people working at the top.</p>
<p>The wider habit here is worth naming because it comes up well beyond images. A lot of frontend work is people recomputing something the browser has already worked out, usually because the platform way of asking for it is less obvious than the arithmetic and the arithmetic feels more like programming. The result is code that goes out of date whenever the layout changes and that quietly disagrees with the browser at exactly the moments you would most like them to agree.</p>
<p>When you find yourself measuring the viewport, it’s worth a minute checking whether you could just describe what you want instead.</p>
]]></content:encoded>
      <category>web</category>
      <category>performance</category>
    </item>
    <item>
      <title>Most people choose to work anyway</title>
      <link>https://ooer.com/posts/most-people-choose-to-work/</link>
      <guid isPermaLink="false">most-people-choose-to-work</guid>
      <pubDate>Sat, 21 Dec 2019 00:00:00 GMT</pubDate>
      <description>The objection to basic income that has already been tested.</description>
      <content:encoded><![CDATA[<p>You can’t choose a thing and then expect not to get the drawbacks of that choice, except that people plainly can and do, all the time.</p>
<p>Take the case that annoys you most. Somebody lives on welfare and doesn’t work and spends their days doing something the person complaining considers worthless. They’re not doing anything criminal. They’re not doing anything immoral. They’re living entirely inside the bounds of what society has decided is acceptable, in exactly the way society decided to allow.</p>
<p>You might think welfare is a bad idea in the first place, and if you do then you’ll have heard yourself say the next part out loud and that we’d all be better off if people without jobs were left to starve. That’s a position and people hold it. But society as a collective has decided it doesn’t want that and having decided, it follows that we allow people to choose not to work and we pay their bills while they don’t. That’s not a loophole anyone is exploiting. That’s the system operating exactly as designed.</p>
<p>My own view is that a society is richer, by a long way, when people can live on their own terms. I’d far rather someone lived on welfare playing video games all day than was forced into a job they hate. Sometimes you’re just not in the right headspace to work and the amount of damage done by making a person in that state turn up somewhere every morning is not small and it doesn’t only land on them.</p>
<p>I took a couple of years off once and lived on my own money because I didn’t want a job any more. That’s the same choice with a different funding source and the only reason it looked respectable is that I’d been paid enough beforehand to cover it. If I ever need welfare to do that again, I’ll be very glad it exists and I’ll use it without any guilt about not contributing.</p>
<p>The objection is always the same. If most people did that, the system would collapse.</p>
<p>That’s true and it hasn’t happened. It hasn’t happened anywhere it’s been tried, over decades, in countries with far more generous provision than this one. Most people choose to work because living on welfare is fairly grim and most people want more than it affords them. The pull of a better life turns out to be considerably stronger than the pull of doing nothing, which is not a surprise to anyone who’s tried doing nothing for more than a fortnight.</p>
<p>So the what if argument doesn’t do the work people want it to. If the collapse were going to happen it would have happened already, in some country, at some point and we’d be able to point at it. Instead the thing we can point at is a long run of places where the provision exists and the overwhelming majority of people work anyway.</p>
<p>An objection that predicts something you have watched repeatedly fail to occur isn’t really an objection to the policy. It’s a statement about what somebody expects other people to be like.</p>
<p>There’s a version of this you can test on yourself, which is to ask what you’d actually do with a year of guaranteed income and no obligations. Most people who answer honestly describe about three weeks of doing nothing, followed by something that looks a great deal like work, because being useful to somebody turns out to be one of the things people want rather than one of the things they endure to get money.</p>
<p>If that’s true of you, it’s worth asking why you assume it stops being true of everybody else.</p>
]]></content:encoded>
      <category>money</category>
      <category>politics</category>
    </item>
    <item>
      <title>Most of it was never private</title>
      <link>https://ooer.com/posts/most-of-it-was-never-private/</link>
      <guid isPermaLink="false">most-of-it-was-never-private</guid>
      <pubDate>Tue, 02 Jul 2019 00:00:00 GMT</pubDate>
      <description>What people mean by spying, and what they actually gave away.</description>
      <content:encoded><![CDATA[<p>Nobody should spy on your life is the sort of statement that feels unarguable until you try to work out what either half of it means.</p>
<p>Start with spying. When you loaded this page, a server somewhere recorded your address and your browser string and the time you arrived. If you’re reading it on a forum you have an account on, then there’s a complete public history of what you’ve read, what you’ve voted on and everything you’ve ever said, sitting on a page anybody can open. None of that took any effort to collect and none of it was hidden from you.</p>
<p>Now take an hour and read someone’s comment history. From a first page of comments you can usually work out roughly what they do for a living, what they think about testing, whether they’ve got a cat, how they feel about the way other people spend money. Read someone with twenty thousand comments and you could build a fairly complete picture of a person, their opinions and their circumstances, without any special access or any tooling.</p>
<p>So is the forum spying on you when it keeps that page up. Am I spying on you when I read it. I don’t think either of those is the right word and the reason is that you put the data there deliberately, in public, knowing it was public because that was the whole point of writing it.</p>
<p>That’s the uncomfortable part of most of these arguments. A lot of what gets called spying is data people handed over in the open and the objection isn’t really to the collection. It’s to somebody being good at reading it. The analytics package that watches what you do on half the sites you visit is a genuine problem worth arguing about and it isn’t quite spying either because you gave it away in exchange for the thing you wanted and the deal was written down somewhere you chose not to read.</p>
<p>The definitional problem runs the other way too. Your life is doing as much work in that sentence as spying is. The comment you posted under a handle you’ve used for a decade is somewhere between public speech and personal life and where exactly it sits depends on who’s asking and what they plan to do with it. There’s no clean line and the people arguing about it are usually drawing it in different places without saying so.</p>
<p>This isn’t an argument that surveillance is fine. It’s an argument that absolute statements about it fall apart on contact and that the ones that fall apart fastest are the ones that sound most obviously right. If you want to be able to object to the bad cases, you need a definition that doesn’t also catch a stranger reading your public posts carefully.</p>
<p>The practical version is simpler and less satisfying. Assume anything you put in public is being read by the most attentive person who could possibly be reading it because eventually it will be. That’s not a reason to stay quiet. It’s just the actual situation and it was the actual situation long before anyone built a tool to make it easier.</p>
<p>Where this gets genuinely difficult is aggregation, and that’s the argument worth having instead. Any one of those public things is trivial on its own and nobody would call it sensitive, but assembling ten years of them into a single profile produces something you never chose to publish, built entirely out of things you did choose to publish. The pieces were public and the picture wasn’t, and no rule about the pieces will ever catch it.</p>
<p>That’s the version of the objection that survives scrutiny. It just isn’t the one people reach for first.</p>
]]></content:encoded>
      <category>privacy</category>
    </item>
    <item>
      <title>A proxy test measures the proxy</title>
      <link>https://ooer.com/posts/a-proxy-test-measures-the-proxy/</link>
      <guid isPermaLink="false">a-proxy-test-measures-the-proxy</guid>
      <pubDate>Tue, 18 Jun 2019 00:00:00 GMT</pubDate>
      <description>Why a hiring exercise that is not the job tells you very little.</description>
      <content:encoded><![CDATA[<p>If a test doesn’t reflect the job you’ll be doing, it isn’t a test of whether you can do the job.</p>
<p>That sounds obvious and it’s routinely ignored, mostly because a test that’s genuinely like the work is expensive to build and awkward to mark. What you get instead is something that assesses a nearby skill and stands in for the real one. Everybody involved knows it’s a stand-in and everybody quietly assumes the correlation is strong enough not to matter.</p>
<p>The trouble is that a proxy test measures the proxy. If your exercise only touches the skill you care about at an angle, then the result gets shaped by all the other things it touches head on and you’ve no way to separate them afterwards. You end up with a number that feels like evidence and is mostly made of something else.</p>
<p>Whiteboard exercises are the obvious case. Unless remembering an algorithm and explaining it standing up is something the role actually involves, the exercise is not testing what you think. It sort of tests how well someone explains an algorithm. What it really tests is memory and presentation and how a person handles being watched while thinking. Those are real skills and some jobs need them. They’re not the same skill as writing good software and someone brilliant at a whiteboard isn’t necessarily anyone you want near your codebase.</p>
<p>Hiring somebody because you were impressed by how well they explained something in front of a board feels wrong and it feels wrong for a reason. It feels especially wrong to people who aren’t good at the tangential stuff, which is a large number of perfectly capable developers who now have to get good at a performance in order to be allowed to do a job that doesn’t contain one.</p>
<p>Notice too that whether something counts as cheating depends entirely on the job rather than on the test. If you’re hiring for a role where you’re expected to know an application cold, then looking in the help is cheating. If reaching for the documentation is normal in the actual work, then it isn’t cheating, it’s the job and penalising it means selecting for people who’ve memorised things you don’t need memorised.</p>
<p>Which is why the clever alternatives often aren’t better. Take an exercise that asks someone to find their way around an unfamiliar application and work something out from the help. It sounds like it’s testing resourcefulness and it is, a bit. It’s also testing how comfortable they are in software they’ve never seen and how they cope with an odd interface and whether they happen to have used that specific tool before. Pick something like Blender and you’ve added a large advantage for anyone who’s touched 3D software and a large penalty for everyone who hasn’t, neither of which you meant to measure.</p>
<p>None of this means testing is hopeless. It means the further your test sits from the work, the more of the result is made of things you didn’t intend to assess and can’t see. The closer it sits, the more expensive it gets and that trade is the real decision. Most companies make it badly and then describe the outcome as a hiring bar.</p>
<p>The honest test is boring and it’s the one almost nobody runs. Give someone a small piece of the work you actually have, with the resources they’d actually have, and enough time to do it properly, then look at what comes back and talk to them about it. That costs real money and real hours from people who are busy, which is precisely why the industry keeps reaching for something cheaper and then describing the cheap thing as rigorous.</p>
<p>A bar you can clear in forty minutes at a whiteboard isn’t a high bar. It’s a cheap one, and those aren’t the same thing however it feels from the other side of the table.</p>
]]></content:encoded>
      <category>job</category>
    </item>
    <item>
      <title>A web page was never a document</title>
      <link>https://ooer.com/posts/a-web-page-was-never-a-document/</link>
      <guid isPermaLink="false">a-web-page-was-never-a-document</guid>
      <pubDate>Tue, 11 Jun 2019 00:00:00 GMT</pubDate>
      <description>The tree was always there. Only who edits it has changed.</description>
      <content:encoded><![CDATA[<p>People keep saying a web page is a document and it isn’t. It never was.</p>
<p>Go back as far as you like. Even when sites were static things the browser rendered once and then left alone, there was always a tree of nodes sitting underneath. That’s what the browser built and that’s what it drew from. The markup was never the page. It was a way of describing what the tree should look like before anything else happened to it and the browser threw the text away the moment it had what it needed.</p>
<p>What’s changed in three decades isn’t the tree. It’s that we now ship a small application alongside it that lets the user change the tree while they’re looking at it. That’s the whole difference and it’s a difference in who gets to edit rather than in what the thing fundamentally is. HTML is still just how we describe the starting state and you could argue it’s the wrong language for that job but that’s a separate argument.</p>
<p>This matters because of what follows from it. If you think of a page as a document then the markup you serve is the thing and anything that reads the web can expect to find what you sent. If you understand it as a tree with an application attached, then what you served is a starting position and you can’t expect it to still be there a second later. Software that consumes the web has to deal with that and quite a lot of it still doesn’t.</p>
<p>None of which is an argument against semantic markup. That’s still important for accessibility and for the machines that read pages without running them and getting it right is a real skill that’s worth having. It just doesn’t buy you the guarantee people think it does because the thing you carefully described is the initial state of something the page is about to start modifying.</p>
<p>If you’re old enough you’ll remember that HTML used to carry the visual description too. There were no stylesheets. We had font tags and color attributes and spacer gifs and we used them because there was nothing else. Then we stopped because it was awful and the visual description moved out into its own language where it belonged.</p>
<p>The same thing has been happening to the rest of it. Users wanted interactivity and they got exactly that and browsers turned into things that run small applications rather than things that render markup. The shift crept up slowly enough that people carried on describing the web the old way without ever noticing the description had quietly expired.</p>
<p>So thinking of the web as HTML pages is just out of date. Not wrong in some pedantic technical sense but out of date in the way that describing a phone as a thing you make calls on is out of date. It’s still true and it stopped being the useful description a long time ago.</p>
<p>Static content hasn’t gone anywhere and it’s still the right answer for a great many things, probably a good deal more of them than the industry currently believes when it reaches for a framework on the first day of a project. That isn’t the point. The point is that even your static page was always a tree and the tree is the part that was real the whole time.</p>
<p>The reason it’s worth getting right is that the wrong model produces bad decisions further down. If you believe you’re publishing documents then a crawler reading your markup is seeing your site, an accessibility tool reading your markup is seeing your site, and anything that disagrees with that is broken software you can safely ignore. If you understand that you’re publishing a starting state for a program, then all of those tools are reading a snapshot of something that has already moved on, and the gap between what you sent and what the user is looking at becomes your problem rather than theirs.</p>
<p>That’s a much less comfortable position and it’s the one we’ve actually been in since roughly the point browsers stopped being renderers.</p>
]]></content:encoded>
      <category>web</category>
      <category>history</category>
    </item>
    <item>
      <title>There is a ceiling on subscriptions</title>
      <link>https://ooer.com/posts/a-ceiling-on-subscriptions/</link>
      <guid isPermaLink="false">a-ceiling-on-subscriptions</guid>
      <pubDate>Tue, 05 Mar 2019 00:00:00 GMT</pubDate>
      <description>People used to manage four. The number has an upper bound.</description>
      <content:encoded><![CDATA[<p>The defence of subscription pricing is that people were always subscribed to things so nothing much has changed.</p>
<p>That’s true as far as it goes and it’s worth taking seriously before disagreeing with it. A household used to have a daily paper, a couple of monthly magazines and a cable package with sports on top. Call it four things to keep track of, arriving on a predictable schedule, at prices that didn’t move often. Nobody sat down at the kitchen table and experienced any of that as a burden worth managing.</p>
<p>What people are being pushed towards now is a music service, several television services, a gaming service, some sports channels, maybe a paid podcast and a news site. That’s not four things. It’s closer to a dozen. Each has its own billing date and its own renewal and its own quiet price rise, and the difference isn’t only the money. It’s the cognitive load of holding all of it in your head and knowing which one you’re paying for by accident.</p>
<p>If there’s an upper limit on how many of these anyone will tolerate and there obviously is, then people hit it quickly and start cancelling. Something has to go. What gets cancelled first is whatever provides the least utility for the money you hand over every month without thinking about it and that’s a brutal test for anything narrow. A service with a handful of excellent shows loses to one with hundreds of decent ones because when you’re cutting from ten down to five you’re not judging quality, you’re judging how often you open the thing.</p>
<p>That raises a real question about whether the smaller services ever work. Not whether they’re good. Plenty of them are very good. Whether the economics survive contact with a saturated market where every new customer has to be taken from somebody else.</p>
<p>There’s a second constraint underneath. People won’t hold two subscriptions that do the same job. Nobody is paying for two music services if they can help it so within each category the market isn’t really growing, it’s being divided. Once everyone who wants a music service has one, growth means persuading people to switch.</p>
<p>Switching somebody across is expensive in a way that growing a new market never was. You’re paying for marketing and a free trial and the discount that finally gets someone over the hump, and then for the friction of moving across whatever they have already built up in the thing they are leaving. If the cost of moving a customer across ends up higher than what that customer is worth over their lifetime, the whole model stops working and the thing that made the category attractive turns into the thing that makes it impossible.</p>
<p>That’s the spanner in the economics and it doesn’t get fixed by better content or a better app. It’s structural and it arrives at exactly the point where the category looks most successful which is when everybody who wants the thing already has one.</p>
<p>The part that should worry anyone running one of these is how the ceiling gets enforced, and nobody sits down and audits their subscriptions in an orderly way. What happens is that money gets tight in one particular month, or a card expires, or somebody notices a charge they can’t account for and then four things get cancelled in ten minutes on a feeling rather than an assessment. Whatever you were doing to justify the price that month is not part of that decision.</p>
<p>So the thing you’re really competing for isn’t value. It’s being remembered fondly enough to survive a bad Tuesday.</p>
<p>The cable package everybody points at as the precedent had one bill, one company and one thing to cancel when money got tight, and that made it far more durable than a dozen small charges that each look reasonable in isolation. Splitting the same spend across ten providers didn’t just move the money around, and it gave every one of them a separate opportunity to be the charge somebody finally notices.</p>
]]></content:encoded>
      <category>money</category>
      <category>video</category>
    </item>
    <item>
      <title>Harmful is not the same as offensive</title>
      <link>https://ooer.com/posts/harmful-is-not-offensive/</link>
      <guid isPermaLink="false">harmful-is-not-offensive</guid>
      <pubDate>Mon, 11 Feb 2019 00:00:00 GMT</pubDate>
      <description>Where a platform genuinely does have a duty to act.</description>
      <content:encoded><![CDATA[<p>If I insult somebody on a forum, the argument goes, how is the forum responsible for that.</p>
<p>It’s a bad analogy and it’s bad in a way worth pulling apart, because the flaw in it is the same flaw running through most of the arguments you’ll have about this. Whether something is insulting can only be decided by the person you aimed it at. The same goes for whether a comment is negative or stupid or whether a derivative work infringes anything. All of those are matters of opinion and the two parties involved will almost always take different positions on them. That’s not a flaw in the people arguing. It’s the nature of the category.</p>
<p>So when you ask a platform to act on that kind of content, you’re asking it to settle something with no fact of the matter in it. Whatever it decides, someone who honestly holds the other view gets overruled. That’s hard, and it’s why moderating speech stays a permanent argument rather than a problem you can expect anyone to solve.</p>
<p>Now change the example. Suppose I invent a piece of malware that’s just plain text and I post it in a comment. Should the platform take it down or leave it sitting there.</p>
<p>That’s a different question and it has a different shape because now there’s no matter of opinion involved. The thing does damage to whoever encounters it and it does the same damage regardless of how anyone feels about it. You don’t have to decide whether you’re offended. The harm is a property of the object rather than a relationship between two people.</p>
<p>My position is that when something is actively harmful in that sense, the publisher has a duty to protect its visitors by removing it or limiting what it can do. Not because publishers should be arbiters of what’s acceptable, which is the thing everybody is quite reasonably worried about but because those are two different jobs and only one of them requires a judgement about taste.</p>
<p>It’s worth noticing that this already happens on the sites you use and nobody objects much. The forums people hold up as bastions of free discussion have moderators who remove things in extreme cases and mechanisms for users to flag content so a consensus can hide it. That’s a form of censorship by any strict definition, it exists on the sites people praise for not having any and it’s mostly uncontroversial precisely because it’s aimed at the objective end of the spectrum.</p>
<p>Plenty of people take the opposite view and think platforms shouldn’t get involved at all. That’s a coherent position and I’m on the other side of it, though not by a huge margin. There are two sides to most arguments and this is one of the ones where the sides are arguing about different cases without noticing.</p>
<p>The useful move, if you want your own argument to survive more than one exchange, is to keep the two categories apart. Ask whether the harm exists whatever anyone thinks of it. If it does, you’ve given the platform something to act on that doesn’t need it to referee your taste. If it doesn’t, then whatever the platform does is going to be a judgement call and pretending otherwise is how these arguments stay unresolvable for a decade.</p>
<p>You can see how much work the distinction does by watching what happens when it collapses. Once a platform accepts that it should act on things people find upsetting, it has taken on a job with no stopping rule and no way to be right, and every decision it makes afterwards becomes evidence for whichever side lost. Once it accepts that it should act on things which do damage regardless of opinion, it has taken on a job that’s difficult and expensive and at least has a shape.</p>
<p>The first job is the one everybody argues about. The second is the one that actually protects anyone, and it gets very little attention because there’s nothing to argue about in it.</p>
]]></content:encoded>
      <category>social</category>
      <category>politics</category>
    </item>
    <item>
      <title>Sell it before it is ready</title>
      <link>https://ooer.com/posts/sell-it-before-it-is-ready/</link>
      <guid isPermaLink="false">sell-it-before-it-is-ready</guid>
      <pubDate>Tue, 11 Sep 2018 00:00:00 GMT</pubDate>
      <description>Waiting for good enough is how you run out of money.</description>
      <content:encoded><![CDATA[<p>The advice to wait until the product is good enough before showing it to anybody is the most expensive reasonable-sounding thing in software.</p>
<p>Start selling the moment it does enough to solve the customer’s pain. Not when it’s polished, not when the edges are smooth and not when you’d be comfortable demoing it to a peer because none of those are the bar. The bar is whether the thing it does is worth more to someone than the problem they currently have and that point arrives a great deal earlier than the point where you stop being embarrassed by it.</p>
<p>The worry is that a bad first experience costs you the customer permanently and sometimes that’s true. What happens far more often is that someone has a bad experience, you talk to them about it and you find out precisely which part was bad and why which is information you were never going to get any other way. That conversation is worth more than the sale. It’s certainly worth more than another six weeks of improvements chosen by you, alone, based on what you imagine matters.</p>
<p>Because that’s the actual risk in waiting. Making changes in isolation means making the wrong changes and you can’t know which ones are wrong without someone outside the building telling you. Every week spent polishing before contact is a week of decisions made on guesses and the guesses compound and the product drifts steadily towards being an excellent solution to a problem nobody described to you.</p>
<p>The other outcome is worth naming too because it happens. Sometimes people don’t have a bad experience at all. Either you got lucky and built roughly the right thing first time or the product is really horrible and still less horrible than the problem it removes which is a much lower bar than anybody wants to admit and clears far more often than it should. In that case you now have paying customers, some traction, something to show an investor and, most importantly, money coming in.</p>
<p>That last part is the whole argument. Selling early isn’t really about learning faster, though it does that. It’s about not running out of money which is the thing that actually kills companies and every week of polish before revenue is a week of runway spent on an assumption. Sell as soon as you can. That’s usually earlier than you think and it’s a lot earlier than the moment the product feels ready.</p>
<p>There’s one exception worth stating. If you’re in a market with essentially one customer, defence contracting being the obvious case, none of this applies in the same way. But you’ll have started the sales conversation before you wrote any code at all because if that single customer doesn’t want the thing then there was never any point building it and you’d want to know that in the first week rather than the eightieth.</p>
<p>The thing that makes this hard isn’t the reasoning which most people accept as soon as they hear it. It’s that showing someone an unfinished thing you made feels bad in a way that’s hard to argue yourself out of, and waiting feels like craft rather than fear. Six weeks later the product is better and you still don’t know whether anyone wants it.</p>
<p>That’s the trade you’re actually making. Not polish against speed, but comfort against knowing.</p>
<p>What you learn in the first month of selling something rough is worth more than what you learn in three months of building something good, and the reason is that only one of those two activities involves a person who is not you.</p>
]]></content:encoded>
      <category>startup</category>
    </item>
    <item>
      <title>Almost none of it runs on your machine</title>
      <link>https://ooer.com/posts/almost-none-of-it-runs-here/</link>
      <guid isPermaLink="false">almost-none-of-it-runs-here</guid>
      <pubDate>Mon, 21 May 2018 00:00:00 GMT</pubDate>
      <description>Doing real work on a very slow laptop.</description>
      <content:encoded><![CDATA[<p>I do serious development on an Acer Chromebook 11 with an eleven inch screen and two gigabytes of memory, in user mode, without Crostini.</p>
<p>The reason that works isn’t that the machine is secretly capable. It’s that very little of what I’m doing actually runs on it. Front end work happens in Codepen, which handles SASS and Babel and the rest of it on someone else’s server and the more involved things happen in Codenvy on someone else’s server as well. Some light Node and Python runs locally through Termux and that’s really all the local compute the day requires. The things I build this way end up on servers being used by thousands of people, which is the only test of serious that means anything.</p>
<p>There’s one real gap and it’s a stupid one. I would happily do more frontend work on the machine itself except that Chrome won’t let me reach localhost, which rules out the entire loop of running something and looking at it. Firefox for Android manages this perfectly well and has no developer tools to speak of so between the two of them you can have the thing you need or the tools you need to use it and never both at once.</p>
<p>The wider problem is that asking whether a class of machine is ready for serious development isn’t a question anyone can answer. Development covers editing a config file in VIM at one end and building an interface in XCode at the other and those two activities have almost nothing in common beyond both producing software. A machine that’s perfect for one is useless for the other and any yes or no you get is really an answer about what the person replying happens to spend their day doing.</p>
<p>So the honest answer is that it’s great and I wouldn’t want to run Android Studio on it. My iMac struggles with Android Studio, which tells you the question was never really about the Chromebook.</p>
<p>What’s worth taking from this is how much of modern development stopped needing a local machine without anybody announcing it. Compilation, bundling, transpiling and increasingly the whole environment moved somewhere else and the laptop turned into a way of looking at a screen and typing. That’s a genuine shift and it means the specification you actually need is much lower than the one you feel you need, right up until you hit the specific thing that must run locally and then no amount of remote power helps you at all.</p>
<p>Which is the useful way to choose hardware. Do not ask what a machine can do in general. Work out what has to happen on the machine in front of you rather than in a data centre and buy for that and accept that a browser that won’t talk to localhost can make a perfectly good computer useless for one particular job while remaining fine for everything else you do all week.</p>
<p>The part that dates worst in all this is the assumption that the constraint is the hardware. It usually isn’t. The constraint is one specific thing the machine won’t let you do, and it’s rarely the thing anyone would put in a review. Nobody comparing laptops writes about whether the browser will talk to a local server, and that single missing capability decided what I could do with this one.</p>
<p>So the specification is the wrong thing to argue about. Find the one blocker first.</p>
]]></content:encoded>
      <category>tech</category>
      <category>frontend</category>
    </item>
    <item>
      <title>The reason you published it shows in the code</title>
      <link>https://ooer.com/posts/the-reason-you-published-it/</link>
      <guid isPermaLink="false">the-reason-you-published-it</guid>
      <pubDate>Tue, 27 Mar 2018 00:00:00 GMT</pubDate>
      <description>Four motives for open sourcing something, and what each one produces.</description>
      <content:encoded><![CDATA[<p>People open source their code for four different reasons and the reason they did it’s visible in what they put out.</p>
<p>The first group is using the repository as a resume. They know someone may read it in an interview context so they put a great deal of effort into making it work well, look tidy and read cleanly and the result is usually the best code any of these groups produce. It’s also code shaped by an audience that may never turn up, which is a strange constraint to build under and produces its own odd effects.</p>
<p>The second group believes in the thing. They want what they built to be shared so other people can use it more freely and add to it and improve it and their code generally looks good and reads well without quite reaching the polish of the first group. That gap isn’t carelessness. It’s a difference in what matters, because for this group the results the software produces are more important than the impression the source makes and time spent on presentation is time not spent on the thing working.</p>
<p>Wanting to be known is the third. Publishing is a way to build a reputation so things get a bit of polish before they go up and quality tends to come second to quantity, since the reputation is built out of the count rather than any particular repository. This one is easy to be sniffy about and probably shouldn’t be, because a lot of really useful software exists because someone wanted their name on something.</p>
<p>Group four simply hasn’t made anything private. They write code for themselves, they push it somewhere public because that’s the default and there was no reason to pay for the alternative and they don’t much care whether anyone ever looks at it. The code is usually pretty hacky and it doesn’t matter to anybody, including the author, because nobody is reading it. I’m in the fourth group and I’ve been for years.</p>
<p>That’s why the anxiety about publishing something not good enough is worth examining before you act on it. The question isn’t whether your code meets some absolute standard, because there’s no such standard and the average public repository is a long way from one anyway. The question is which group you’re actually in, because that determines what the code is for and therefore what good enough even means.</p>
<p>If you’re in the second group and you’re hesitating because the source is untidy, you’re applying the first group’s standard to a piece of work with a different purpose. Tidy it up as much as you fairly can and then publish it and don’t lose any sleep over the parts that are ugly. The people who benefit from what it does aren’t the people who were going to audit how you did it and waiting until it reads beautifully mostly means it never goes out at all.</p>
<p>The one thing worth being honest about is which group you’re in, because it’s very easy to tell yourself you’re in the second while behaving like the third and the difference shows up in whether you keep working on something after the initial attention has moved on.</p>
<p>There’s a fifth case that doesn’t really count as a reason, which is code published because a client paid for it and the contract said so. That one produces the strangest repositories of all. The code is usually fine because someone was paid to make it fine, and there’s nobody left who cares about it, so it sits there working perfectly and slowly going out of date with no issues, no releases and no answer to any question you might have.</p>
<p>When you’re weighing up whether to use something, working out which group it came from tells you more than the star count does.</p>
]]></content:encoded>
      <category>opensource</category>
      <category>culture</category>
    </item>
    <item>
      <title>Some problems are not nails</title>
      <link>https://ooer.com/posts/some-problems-are-not-nails/</link>
      <guid isPermaLink="false">some-problems-are-not-nails</guid>
      <pubDate>Mon, 05 Feb 2018 00:00:00 GMT</pubDate>
      <description>Code is useful. It is also not the important part.</description>
      <content:encoded><![CDATA[<p>Solve a problem in the furniture industry and the worry is that you end up as nothing more than an innovative carpenter.</p>
<p>Ingvar Kamprad founded Ikea to solve a problem in the furniture industry and was at one point the eleventh richest person alive and he did it without writing a line of code. That isn’t a trick answer or a on purpose awkward counterexample. It’s the ordinary case. If you find a solution to a pain that a large number of people are actually suffering then you can make an enormous impact and quite possibly a great deal of money and the medium you happen to use to deliver it’s close to beside the point.</p>
<p>It doesn’t have to be code and it definitely doesn’t have to be good code, which is the part that tends to annoy people who take some pride in writing it well. Very often the whole thing can be done with no code in it anywhere and the fact that this feels faintly insulting to people who write software for a living is worth sitting with rather than arguing against.</p>
<p>Look at what actually kills things instead. You can ship the best functionality anybody has built in that space and fail totally because nobody hears about it or because the people who hear about it can’t work out what it does or because they understand it perfectly well and don’t care or because they care but can’t see how it helps them or because they can see exactly how it helps them and can’t afford it. Every one of those is fatal on its own and none of them is a technical problem. You don’t fix any of them by making the software better.</p>
<p>This is why the framing of the original worry is upside down. The concern is that solving a non-software problem wastes your technical ability, when the thing that most often goes to waste is technical ability applied to a problem where the hard part was never technical. The carpenter comparison is meant to sting and it should probably land the other way round, because the carpenter at least knows what business they’re in.</p>
<p>I like writing code and I solve a lot of problems with it. It’s also obvious after enough years that there are problems code isn’t suited to and that a decent proportion of what looks like a software problem at the start turns out to be a distribution problem or a pricing problem or a problem where the customer already has a workaround they’re perfectly happy with. Those don’t become software problems because a software person picked them up.</p>
<p>Code is a hammer. It’s an excellent hammer and there’s a lot of satisfaction in swinging it well and the reason so much effort gets spent on things that were never going to work is that the people holding it are very good at using it and would rather not find out that this particular problem isn’t a nail.</p>
<p>The test is easy enough to run on yourself. Take whatever you’re building and ask what has to be true for it to work, then sort that list into the parts that need code and the parts that don’t. If the code half is short and the rest of the list is long, you’re not doing a software project. You’re doing a business with some software in it, and the skill that decides how it goes is one you may not have been practising.</p>
<p>That isn’t a reason to stop. It’s a reason to stop treating the code as the hard bit.</p>
]]></content:encoded>
      <category>startup</category>
      <category>culture</category>
    </item>
    <item>
      <title>Nobody is reading your GitHub</title>
      <link>https://ooer.com/posts/nobody-is-reading-your-github/</link>
      <guid isPermaLink="false">nobody-is-reading-your-github</guid>
      <pubDate>Mon, 29 Jan 2018 00:00:00 GMT</pubDate>
      <description>Public code as a hiring signal, and why it fails.</description>
      <content:encoded><![CDATA[<p>Whiteboard tests are bad and replacing them with a look at your public repositories is a different bad thing rather than a fix.</p>
<p>Start with how hard the reading actually is. Judging code in a codebase you don’t know is hard even when you’ve all afternoon and understanding what someone’s commits mean requires knowing the project as a whole, the problem space it sits in and the environment it runs against. A hiring manager with forty candidates has none of that for any of them and no realistic way to acquire it so what they end up doing is skimming for a feeling and then calling the feeling a judgement.</p>
<p>Then there’s the spread, which is narrower than people assume. Most public code sits at roughly the same level of not very good, because what people write in their own time for their own fun is rarely commented or tested or documented to the standard they would apply at work. That isn’t laziness. It’s a rational response to nobody else needing to read it. Finding someone with good public code is a real signal and it’s also rare enough that a manager who has looked through a hundred profiles without finding one has fairly concluded the exercise isn’t paying for itself.</p>
<p>The trust problem sits underneath both of those. Cloning a few open projects and quietly taking credit for the work is trivial and nobody screening a stack of applications has the time to verify where it came from on any of it. So even a good profile only counts if you already believe the person, which rather defeats the purpose of using it as evidence about someone you haven’t met.</p>
<p>None of that’s the part that should bother you most though. Treating public code as evidence quietly filters your pipeline by who has spare evenings. People with young children don’t have a weekend of side projects in them. Neither do people with care responsibilities or a second job or a commute that eats two hours a day or simply an absorbing interest in something that isn’t programming. Any of those people can be excellent at the job and none of them will look excellent by this measure and you’ll never find out what you missed because the filter runs before you ever speak to them.</p>
<p>The Max Howell case gets quoted whenever this comes up and it’s usually quoted wrongly. Homebrew is really successful software used by an enormous number of people including, famously, the company that turned him down. It’s also not a proof of the specific computer science that particular interview was testing for, which is Howell’s own reading rather than a defence anyone else has had to construct for him. The story is a good example of a bad process and it isn’t evidence that reading his repositories would have produced a better answer.</p>
<p>What tends to happen in these arguments is that the goalposts move without anyone announcing it. The claim starts as “has code in public” and quietly becomes “has launched or really contributed to a successful open project”, which is a totally different and far more harder thing. Plenty of hiring managers do look well on the second and they’re right to and it describes a very small number of people. Using the first as a proxy for the second is where the reasoning falls apart.</p>
<p>The uncomfortable conclusion is that judging people is hard and none of the cheap signals work. Whiteboard trivia doesn’t work, public code doesn’t work and the length of someone’s commit history doesn’t work. Building a good team is about hiring good people rather than filtering for a particular kind of visible enthusiasm and the methods that get you there are slower and more expensive than looking at a profile page for ninety seconds and forming an impression you’ll later describe as instinct.</p>
<p>What you’re left with is that hiring is expensive and none of the shortcuts work. Talk to people. Give them something close to the actual work and pay them for it if it takes real time. Both of those are slower than a glance at a profile page, and slower is the price of finding out something true.</p>
]]></content:encoded>
      <category>job</category>
      <category>culture</category>
    </item>
    <item>
      <title>A library is its documentation</title>
      <link>https://ooer.com/posts/a-library-is-its-documentation/</link>
      <guid isPermaLink="false">a-library-is-its-documentation</guid>
      <pubDate>Sat, 30 Dec 2017 00:00:00 GMT</pubDate>
      <description>Why a small fast library still does not replace the big slow one.</description>
      <content:encoded><![CDATA[<p>A new library turns up that does what jQuery does in a fraction of the size, and the question is why anybody would keep using jQuery.</p>
<p>The answer isn’t about the code. That’s usually fine. Quite often it’s better than fine. The answer is that a couple of lines saying what the parameters are and what comes back is not enough for anyone to justify spending an afternoon finding out what the rest of it does. Documentation isn’t a nice extra that a good library eventually gets round to when the interesting work is finished. For everyone who didn’t write the thing, the documentation simply is the library, because it’s the only part of it they are in any position to act on.</p>
<p>The gap shows up in small, specific ways that are invisible from the inside. There’s no way to link to a particular page, so you can’t paste it into a channel and ask three colleagues what they think. That alone rules a library out for a team and it has nothing to do with the quality of the implementation. It’s a decision about whether other people can be brought into the conversation.</p>
<p>Then there are the choices the docs don’t warn you about. An ajax function that takes a callback instead of returning a promise will be fine in a small app and will turn into a mess in a chained one, unless everyone touching it is unusually disciplined. A style helper that creates a fresh tag in the head every time you call it will work perfectly in the demo and accumulate quietly in anything real. An iteration helper built on querySelectorAll hands you a static node list rather than an array, so anyone modifying the page as they walk it is going to have a confusing morning.</p>
<p>None of those is a bug. They’re all defensible. The last one is just what the platform returns. The problem is that a reader can’t tell whether they’re deliberate. Documentation that only lists arguments and return values tells you the shape of a call and nothing about what happens when you use it the way you’re going to use it.</p>
<p>That’s the real cost of thin docs, and it’s why size comparisons don’t move anyone. You aren’t choosing between thirty kilobytes and three. You’re choosing between a library where the failure modes are written down and one where you’ll find them yourself, in your own project, some months from now, in code somebody else wrote against assumptions they had no way to check.</p>
<p>There’s a version of this that sounds like a complaint about effort, and it isn’t. Writing documentation is harder and less enjoyable than writing the library, which is exactly why it’s the thing that distinguishes a project people can adopt from a project people admire and then don’t use. If you want the thing you built to replace the incumbent, the code is the part you’ve already done. The rest is what makes it possible for anyone else to have your intentions.</p>
<p>The same logic explains why the incumbent keeps winning long after somebody has beaten it on every number that gets measured. What jQuery had was fifteen years of people writing down what happens when you use it in anger, and almost all of that lives outside the project in answers, posts and half remembered advice from a colleague. That is an enormous asset and it does not show up in a bundle size comparison because there is no line for it.</p>
<p>So the honest way to read a benchmark against an established library is that the new thing has matched the part that was easy to measure. The part that decides adoption has not been started yet, and it is measured in years.</p>
]]></content:encoded>
      <category>javascript</category>
      <category>frontend</category>
    </item>
    <item>
      <title>A hackathon is the worst parts of the job, unpaid</title>
      <link>https://ooer.com/posts/hackathon-worst-parts/</link>
      <guid isPermaLink="false">hackathon-worst-parts</guid>
      <pubDate>Sun, 30 Jul 2017 00:00:00 GMT</pubDate>
      <description>On the assumption that all developers enjoy them.</description>
      <content:encoded><![CDATA[<p>Every writeup of a hackathon opens by saying that we all love them and it isn’t true.</p>
<p>There are two groups it isn’t true for and between them they cover most of the developers you’ll actually meet. The first is the large majority who go to work, write code, go home and then do something else with their evening. For those people writing software is a job and a good one and not a hobby that happens to pay. Offer them a weekend of it and you’ve offered them a weekend of work. That’s not a failure of enthusiasm on their part, it’s an accurate assessment of what’s on the table.</p>
<p>The second group is smaller and I’m in it. It’s the people who enjoy the process of building something properly rather than the specific pleasure of getting a thing on a screen fast. If what you like is the craft, a hackathon is not a compressed version of your job, it’s an inversion of it.</p>
<p>Look at what the format actually asks for. There’s practically no planning because there is no time to plan, very little testing for exactly the same reason and zero documentation because nobody is going to read any of it on Monday morning. No sleep. Bad food. Two days of not seeing anyone who isn’t also in the room. Every single one of those is a thing that makes real projects fail, assembled deliberately into an event and then described as fun.</p>
<p>I’ve worked on real, paid projects that were run in more or less exactly that way, under a deadline somebody else had promised without asking, and the experience is uniformly awful. The code is bad, the people are tired and the thing you ship has to be substantially rebuilt by somebody who wasn’t in the room. Having done it for money and disliked it, the offer to do the same thing at the weekend for a t-shirt is not obviously attractive.</p>
<p>So this isn’t an argument that hackathons shouldn’t exist. They clearly work for a lot of people, the output is often genuinely interesting and I like seeing what comes out of them. If you enjoy them you should go and none of what I’ve said takes anything away from that.</p>
<p>It’s the assumption I’d push back on. The problem with opening on “we all love hackathons” is that it quietly redefines who counts as a developer and it always redefines it in the direction of the person writing. If your evidence is the people who turn up to hackathons then of course they like hackathons and you’ve learned nothing except that self-selection works.</p>
<p>That matters a good deal more than it sounds, because the same assumption turns up in hiring, in what gets treated as evidence of enthusiasm and in who gets quietly read as serious about the work rather than merely competent at it. Someone who writes great code between nine and six and then goes to see their friends is not less committed than someone with a weekend full of side projects. They’ve just noticed that it’s a job.</p>
<p>If you think every developer loves a hackathon, the useful conclusion isn’t about hackathons at all. It’s that you need to know more developers.</p>
<p>There is a version of the format that avoids all of this and some companies do run it. Give people a couple of days inside working hours, let them pick the problem and judge nothing. What is left is time to think about something other than the roadmap, which is the part everybody actually says they valued when you ask them afterwards. The sleeplessness and the pizza were never the point and they were never what produced the good work either.</p>
<p>The reason the compressed weekend version persists anyway is that it makes a better story and a better photograph than a quiet Tuesday where four people read some documentation and tried an idea out.</p>
]]></content:encoded>
      <category>work</category>
      <category>culture</category>
    </item>
    <item>
      <title>Most people cannot afford the good idea</title>
      <link>https://ooer.com/posts/cannot-afford-the-good-idea/</link>
      <guid isPermaLink="false">cannot-afford-the-good-idea</guid>
      <pubDate>Sun, 04 Jun 2017 00:00:00 GMT</pubDate>
      <description>The five hour day, and who it is actually available to.</description>
      <content:encoded><![CDATA[<p>The five hour working day is a genuinely good idea that almost nobody is in a position to take.</p>
<p>The version that gets written up goes like this. You concentrate better in a short day so you get the same work done in less time so you trade some of your pay for some of your life and everybody wins. The person writing it up is usually right about their own situation. They did try it, it did work and the gains are real. There’s no trick being played.</p>
<p>The trouble starts when you ask who else is in that situation. Take a twenty percent pay cut for a forty percent reduction in hours and you’ve immediately excluded almost everyone because very few people can absorb a fifth of their income disappearing. Anyone with a mortgage set against their current salary is out. Anyone supporting somebody else is out. Anyone who is one bad month from trouble is out and that’s a lot more people than it’s comfortable to think about.</p>
<p>So it filters down to workers paid enough that losing a fifth of it doesn’t hurt, which mostly means the big technology employers. And those are exactly the companies where the offer makes no sense from the other side of the table. A business awash with cash isn’t looking to shave twenty percent off a wage bill it doesn’t notice. It wants more output and it’s already paying overtime to get it. Saving money on salaries isn’t an incentive there, it’s a rounding error and the thing you’re offering to give up is the thing they actually want more of.</p>
<p>Then there’s the commute and that is the part that gets left out of every version of this. If you spend an hour a day travelling, a shorter day doesn’t shorten it. The travel is fixed and the work shrinks around it so the proportion of your day spent getting to the thing goes up rather than down. A half day with a thirty minute commute each way feels like a waste in a way a full day never does and that feeling isn’t irrational, it’s an accurate read of the ratio.</p>
<p>None of this means the idea is bad. Where it fits it fits well and the people it fits should absolutely take it. It’s just that the conditions are doing far more work than the argument admits: you need to be paid well above your outgoings, at a company that values salary savings over output, with little or no travel, doing work that genuinely compresses.</p>
<p>That’s a real set of people. It isn’t many of them and it isn’t the ones who’d benefit most.</p>
<p>This is the pattern worth carrying away rather than the specific arithmetic of a shorter week. A working practice that requires you to already be comfortable is not a fix for being uncomfortable. It’s a perk and perks flow to the people who need them least, which is fine as long as nobody dresses it up as the future of work. The future of work for most people is the same number of hours and the interesting question is what happens inside them.</p>
<p>The wider version of this is worth holding on to whenever a new way of working gets written up. Ask who has to already be fine for it to work and the answer is usually somebody with savings, without dependents, without a commute and with an employer who is relaxed about output. Every one of those is a form of slack and the practices that get called innovative are mostly ways of converting slack you already have into something more pleasant.</p>
<p>That is worth doing if you have the slack. It just is not a model and treating it as one quietly tells everybody without slack that they are doing work wrong when what they are actually doing is paying a mortgage.</p>
]]></content:encoded>
      <category>work</category>
    </item>
    <item>
      <title>The default is the lever</title>
      <link>https://ooer.com/posts/the-default-is-the-lever/</link>
      <guid isPermaLink="false">the-default-is-the-lever</guid>
      <pubDate>Sun, 23 Apr 2017 00:00:00 GMT</pubDate>
      <description>Why the ad company can afford to block its own ads.</description>
      <content:encoded><![CDATA[<p>When Google announced an ad blocker inside Chrome, the obvious reading was that it would quietly spare Google’s own ads.</p>
<p>It’s a good guess. I think it’s wrong. Google will block their own ads and the reason has nothing to do with restraint. They don’t need the exception because they have something that works better and costs them nothing to use.</p>
<p>Start with what the exception would cost. A browser holding two thirds of the market, shipping a blocker that mysteriously classifies its owner’s inventory as acceptable, is a story that writes itself and then runs for years afterwards every time anybody writes about online advertising. The amount of trust lost would be immense and the gain is a slice of inventory they already dominate and nobody at that company is stupid enough to take that trade. It isn’t a moral position. It’s arithmetic. The arithmetic is not close.</p>
<p>Then look at what you have instead if you are the browser vendor. You control what the setting does when nobody touches it, which turns out to be almost everybody who will ever use the thing you shipped. That’s the whole game. It’s worth more than any blocklist could ever be, because the overwhelming majority of people will never open a settings panel in their entire life and whatever the browser does without being asked is therefore what the web does. Whatever the browser does out of the box is what the web does.</p>
<p>So the interesting question was never which ads get blocked. It’s what happens to the ones that don’t and who gets to decide which category any given ad falls into in the first place, because that decision is made once and then applies to everything afterwards without further argument. A blocker that ships switched off by default doesn’t need to protect anyone’s inventory. A blocker that ships switched on, with a definition of “acceptable” written by the largest seller of acceptable ads, doesn’t need to either. In both cases the outcome is set before any individual ad is judged, by a decision most users will never know was made.</p>
<p>This is the thing that’s easy to miss when you’re watching for the obvious corruption. You look for the thumb on the scale and you find the scale is fine because the thumb is on the question of who gets weighed. Blocklists are visible, arguable and auditable, which is exactly why they attract every ounce of the scrutiny that gets spent on this. Defaults are none of those things and they quietly move more traffic than any blocklist ever written.</p>
<p>Once you’re looking for it you can see the same shape more or less everywhere, in places that have nothing to do with advertising at all. The cookie banner that defaults to accept, the search engine that ships pre-selected, the analytics that’s on unless you turn it off, the sharing setting that starts at public. In every case there’s a visible mechanism that gets all the argument and a default that quietly does the actual work. The argument about the mechanism is genuine and it’s also a bit of a distraction from the part that decides the outcome.</p>
<p>Which is why “will they exempt themselves” was the wrong thing to be worried about, and it’s a question about the mechanism and the mechanism was always going to be clean. If you want to know what a browser vendor is going to do to the web, don’t read the blocklist. Find out what the checkbox says before anybody touches it and how hard it is to find.</p>
<p>None of that requires anyone to behave badly and that is what makes it durable. A blocklist has to be defended in public by somebody who can be asked why a particular ad is on it. A default gets set once, by a product decision nobody outside the company will ever read, and then it holds until someone notices it and cares enough to go and change it, which for the overwhelming majority of people is never. The mechanism gets all of the scrutiny for the simple reason that the mechanism is the part you can actually see, and you will spend your attention on the visible thing every time unless you make a deliberate effort not to.</p>
<p>So when a browser vendor tells you what its blocker will and will not stop, that is genuinely worth reading and it is not the important document. The important one is the spec for the first run experience and nobody publishes that.</p>
]]></content:encoded>
      <category>browser</category>
      <category>google</category>
    </item>
    <item>
      <title>No because is easier than yes if</title>
      <link>https://ooer.com/posts/no-because-yes-if/</link>
      <guid isPermaLink="false">no-because-yes-if</guid>
      <pubDate>Sun, 19 Feb 2017 00:00:00 GMT</pubDate>
      <description>Two ways of looking at an idea that probably will not work.</description>
      <content:encoded><![CDATA[<p>There are two ways to answer an idea that probably won’t work and which one you reach for decides what gets built.</p>
<p>The first is to explain why it fails. Someone proposes a basic income for a country where a third of the population in some areas has no bank account and you point out that the money will be spent on status symbols, that gold and mobiles will inflate, that the delivery mechanism doesn’t reach the people it’s aimed at. Every one of those is true and none of them is unfair, and you’ve read the proposal carefully enough to find the holes, which is a good deal more than most of the people in the room will have managed.</p>
<p>The economist Harrison Price called that the “no, because” answer and set it against the “yes, if” one. The second looks at the same proposal and says: yes, if we can find a way to get people bank accounts and yes, if the money reaches people in a form they spend on getting out of poverty rather than on looking like they already have. Same facts. Same holes. A completely different conversation on the other side of it.</p>
<p>The reason this matters is that the two answers feel identical from the inside. Both are analytical, both are evidence-based and both leave you feeling like the reasonable person in the room. “No, because” even feels more rigorous because listing failure modes is harder work than waving them away and you can point at the list.</p>
<p>But look at what each one leaves behind. A “no, because” answer ends the discussion and hands back nothing. A “yes, if” answer ends with a list of conditions and a condition is a piece of work somebody can pick up. It converts an objection into a specification. The holes don’t go anywhere and you haven’t pretended they aren’t there, you’ve just written them down in a form that can be worked on rather than a form that closes the meeting.</p>
<p>There’s nothing wrong with being a “no, because” person and there are rooms where it’s exactly what’s needed. If somebody is about to spend three years and other people’s money on something structurally impossible, the kindest thing available is a clear account of why. Some ideas genuinely should die in the meeting they were born in and the person who kills them has done everyone a favour.</p>
<p>The trouble is that it’s the default. It’s what you fall into when you’re tired, when the idea came from somebody you don’t rate or when you’ve been burned by the last three versions of it. It costs nothing and it always makes you look right because an idea that never gets built can never be shown to have worked. The failure mode is silent and it flatters you the whole time.</p>
<p>So the useful discipline isn’t to stop finding holes. You should find them and you’ll be better at it than most people if you’ve been doing this a while. The discipline is to finish the sentence differently. Not “this won’t work because the delivery mechanism is broken” but “this works if somebody fixes the delivery mechanism” and that is the same observation pointed at a person who can act on it.</p>
<p>You’ll notice fairly quickly which of the two your team runs on. In a “yes, if” team the objections turn into tickets. In a “no, because” team they turn into a reputation for being the person who spots problems, which is a genuinely valuable reputation to have and also a very comfortable place to sit for a decade without shipping anything you’d want to talk about.</p>
<p>What makes the habit hard to see is that it only ever looks like competence from the inside. Nobody thinks of themselves as the person who stops things. They think of themselves as the person who reads the proposal properly and says the thing everybody else was too polite to say, which is a genuinely useful role right up until it becomes the only move you have. The tell is whether anything ever leaves your desk in better shape than it arrived.</p>
]]></content:encoded>
      <category>thinking</category>
      <category>startup</category>
    </item>
  </channel>
</rss>
