<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="/feed.xml" rel="self" type="application/atom+xml" /><link href="/" rel="alternate" type="text/html" /><updated>2026-02-19T06:15:48+00:00</updated><id>/feed.xml</id><title type="html">Boris Cherny’s Blog</title><subtitle>Write an awesome description for your new site here. You can edit this line in _config.yml. It will appear in your document head meta (for Google search results) and in your feed.xml site description.</subtitle><entry><title type="html">NPM and NodeJS should do more to make ES Modules easy to use</title><link href="/javascript,/typescript/2024/06/19/ES-Modules-Are-A-Mess.html" rel="alternate" type="text/html" title="NPM and NodeJS should do more to make ES Modules easy to use" /><published>2024-06-19T00:00:00+00:00</published><updated>2024-06-19T00:00:00+00:00</updated><id>/javascript,/typescript/2024/06/19/ES-Modules-Are-A-Mess</id><content type="html" xml:base="/javascript,/typescript/2024/06/19/ES-Modules-Are-A-Mess.html"><![CDATA[<p>Coming back to JavaScript and TypeScript after a few years neck deep in Python and Hack, I kept hitting a number of new, cryptic errors when running NodeJS code in my dev environment:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># when I ran ESM TypeScript code the wrong way:</span>
Error <span class="o">[</span>ERR_REQUIRE_ESM]: Must use import to load ES Module

<span class="c"># when I imported an ESModule from a CommonJS .js file:</span>
Error <span class="o">[</span>ERR_REQUIRE_ESM]: require<span class="o">()</span> of ES Module .../lodash.js from .../index.cjs not supported

<span class="c"># when I imported an ESModule from a .ts file:</span>
error TS1479: The current file is a CommonJS module whose imports will produce <span class="s1">'require'</span> calls

<span class="c"># when I used ES6 import syntax in a .js file:</span>
SyntaxError: Cannot use import statement outside a module
</code></pre></div></div>

<p>These errors are all related to importing, typechecking, and loading modules. The JavaScript ecosystem moves fast, and things changing over the last few years was not a surprise. However, it was surprising to see so many errors related to such a core piece of the language!</p>

<h2 id="how-we-got-here">How we got here</h2>

<p>Modules in JavaScript and TypeScript have changed significantly over time:</p>

<ul>
  <li>Years ago, there was no module system for JavaScript and TypeScript. A number of solutions sprang up around ways to declare and load modules: IIFEs, <a href="https://github.com/getify/LABjs">LabJS</a>, <a href="https://github.com/amdjs/amdjs-api/blob/master/AMD.md">AMD</a>, <a href="https://requirejs.org/">require.js</a>, <a href="https://www.typescriptlang.org/docs/handbook/namespaces.html">TypeScript namespaces</a>, and more. Tooling support and interop were hit or miss.</li>
  <li>CommonJS emerged as a standard-by-convention for modules, across browser, server, JavaScript, and TypeScript.</li>
  <li>When ES6 came out, folks started switching over to <code class="language-plaintext highlighter-rouge">import</code> and <code class="language-plaintext highlighter-rouge">export</code> syntax (from CommonJS’s <code class="language-plaintext highlighter-rouge">require</code> and <code class="language-plaintext highlighter-rouge">module.exports</code>), using tools like Babel and TypeScript to compile code down to CommonJS.</li>
  <li>CommonJS can be challenging to statically analyze, and uses an <a href="https://www.youtube.com/watch?v=W5CXzo4TZVU">inefficient</a>, synchronous module loading algorithm at runtime. ES Modules were <a href="https://tc39.es/ecma262/#sec-modules">introduced</a> as the way to use <code class="language-plaintext highlighter-rouge">import</code> and <code class="language-plaintext highlighter-rouge">export</code>, while at the same time improving code load times at runtime.</li>
  <li>ES Modules introduced significant complexity for NodeJS in particular: instead of reusing the <em>.js</em> and <em>.ts</em> file extensions, ES Modules in NodeJS require either using <em>.mjs</em>, or setting <code class="language-plaintext highlighter-rouge">type=module</code> in your <em>package.json</em>. Interoperating these modules with an ecosystem-ful of CommonJS remains painful.</li>
</ul>

<h2 id="current-state-by-the-numbers">Current state, by the numbers</h2>

<p>I was curious – since ES Modules (<code class="language-plaintext highlighter-rouge">import</code>/<code class="language-plaintext highlighter-rouge">export</code>) were introduced in <a href="https://262.ecma-international.org/6.0/#sec-modules">2015</a>, and NodeJS has supported <code class="language-plaintext highlighter-rouge">type=module/commonjs</code>, <em>.mjs</em>, and <em>.cjs</em>, with the goal of replacing <em>.js</em>, since <a href="https://nodejs.org/api/packages.html#type">2019</a>, to what degree have these new conventions been adopted?</p>

<p>I answered this with data, using two approaches:</p>

<ol>
  <li>Looking at the most starred JavaScript and TypeScript repos on Github</li>
  <li>Looking at the most downloaded packages on NPM</li>
</ol>

<p>The <a href="https://github.com/bcherny/es-module-stats">results</a> are not rosy. After 5+ years, adoption of ES Modules remains weak:</p>

<ol>
  <li>Between 9-27% of JavaScript/TypeScript projects declare themselves to be ES Modules via the <code class="language-plaintext highlighter-rouge">type</code> (and lesser-used <code class="language-plaintext highlighter-rouge">exports</code>) fields in their <em>package.json</em>s.</li>
  <li>Less than 6% of JavaScript/TypeScript files declare that they are ES Modules via the <em>.mjs</em>, <em>.cjs</em>, <em>.mts</em>, etc. file extensions.</li>
</ol>

<p>Note that these ranges come from the two approaches I used to estimate the numbers. Head <a href="https://github.com/bcherny/es-module-stats">here</a> for more detailed data and code.</p>

<h2 id="how-do-we-fix-it">How do we fix it?</h2>

<p>This helps explain why it’s so painful to interoperate ES Modules and CommonJS across both NodeJS and TypeScript: enough libraries use ES Modules that for many projects you need to either use ES Modules, or figure out how to interoperate ES Modules with your CommonJS code. At the same time, enough code still uses CommonJS that you often need to figure out how to include that legacy code in your otherwise-ES Module project.</p>

<p>The benefits of ES Modules are significant. Rolling everything back to CommonJS is not the way forward. Is there more we can do to simplify the ecosystem, and push harder on adoption? Some ideas:</p>

<ol>
  <li>We should kill <em>.mjs</em>, <em>.cjs</em>, <em>.mts</em>, etc. The vast majority of projects use <code class="language-plaintext highlighter-rouge">type=module</code> in their <em>package.json</em>, rather than file extensions. It would simplify things considerably if we drop support for these new file extensions and stick to <em>.js</em>, <em>.jsx</em>, <em>.ts</em>, and <em>.tsx</em>.</li>
  <li>We should make <code class="language-plaintext highlighter-rouge">type=module</code> the <a href="https://github.com/npm/cli/issues/7594">default</a> for new <em>package.json</em> files for the <code class="language-plaintext highlighter-rouge">npm init</code>, <code class="language-plaintext highlighter-rouge">yarn init</code>, and <code class="language-plaintext highlighter-rouge">pnpm init</code> commands. Package managers’ <code class="language-plaintext highlighter-rouge">publish</code> commands should warn when <code class="language-plaintext highlighter-rouge">type</code> is not set to <code class="language-plaintext highlighter-rouge">module</code>.</li>
  <li>We should upgrade the most common libraries used by the community to ES Modules, either manually or through automated pull requests (this feels like something that can be semi-automated).</li>
  <li>The NPM registry can require an explicit <code class="language-plaintext highlighter-rouge">module</code> field on new packages, making it clear when a package intentionally uses CommonJS (eg. because it targets legacy NodeJS versions).</li>
  <li>NodeJS can officially drop support for <code class="language-plaintext highlighter-rouge">require</code> and <code class="language-plaintext highlighter-rouge">module.exports</code> in a future version, creating a bit more pressure to migrate.</li>
</ol>

<p>I’d love to hear others’ thoughts. Have you also felt the pain of interoperating ES Modules and CommonJS?</p>

<hr />

<p>Discuss this post on <a href="https://news.ycombinator.com/item?id=40737508">HackerNews</a> or on <a href="https://www.threads.net/@boris_cherny/post/C8aDJuGI5HM">Threads</a>.</p>]]></content><author><name></name></author><category term="JavaScript," /><category term="TypeScript" /><summary type="html"><![CDATA[Coming back to JavaScript and TypeScript after a few years neck deep in Python and Hack, I kept hitting a number of new, cryptic errors when running NodeJS code in my dev environment:]]></summary></entry><entry><title type="html">Learning to work (very) remotely</title><link href="/tech/2023/12/10/Working-Remotely.html" rel="alternate" type="text/html" title="Learning to work (very) remotely" /><published>2023-12-10T00:00:00+00:00</published><updated>2023-12-10T00:00:00+00:00</updated><id>/tech/2023/12/10/Working-Remotely</id><content type="html" xml:base="/tech/2023/12/10/Working-Remotely.html"><![CDATA[<p>For the last year and a half, I have been working at Instagram in Japan. It’s a bit of an unusual setup: I live and work remotely from Nara, Japan, in a timezone that few other Meta engineers work in (most of Instagram and Meta are spread across the US and Europe).</p>

<p>I am fortunate to have the opportunity to have a setup like this. How I ended up here is a long story, which I will save for another post. For this post, I’d like to talk about what I have learned about effectively contributing to an engineering organization when you are isolated from your coworkers physically, temporally, and organizationally.</p>

<h2 id="learning-to-work-again">Learning to work again</h2>

<p>Before moving to Japan, I served as the tech lead for Facebook Groups. That meant organizing meetings, building slide decks and spreadsheets, writing scoping documents, responding quickly to chat messages and emails to keep teams unblocked… You know what I wasn’t doing a lot of? Coding.</p>

<p>After moving to Japan, with so little timezone overlap (9am my time is 4pm in San Francisco, 7pm in New York) I suddenly found myself with nearly the whole day free. My coworkers went offline a couple hours after my day started, until London woke up for the last hour of my working day. That meant nearly zero meetings and few synchronous chats.</p>

<p>Due to the incompatible timezones, I started attending group meetings less and less. At the same time, my coworkers naturally took me out of the critical paths of important projects. If anything was time-sensitive, I was no longer a good person to take care of it. I wouldn’t be included in chats and email threads anymore. My directors wouldn’t ask me to put together quick planning docs after exec reviews, nor would I be included in those reviews in the first place. This stung, at first – I was used to being included in meetings, and learning about new information before others did. These are the things that made me feel important! I didn’t want to give them up. But I had no choice.</p>

<p>At first I struggled to figure out how to spend my new-found free time, and how to feel good about my contributions to Instagram. I experimented with a few ideas: hacking on new product ideas with the other engineers in Japan, mentoring engineers in our Singapore office (larger than the one in Tokyo), fixing tech debt that others left behind.</p>

<p>It turned out that most of this work wasn’t easy to do. It was hard to effectively work on product while disconnected from the bulk of our US-based product organization; and it was hard to be a good mentor while having little context on what was going on in the Singapore office.</p>

<p>However, I did find that writing code again was rewarding. In my first two weeks in Japan, I landed more code than I had in the previous year in Menlo Park. I’m an engineer, and this made me happy – I missed coding! While hacking on a few product ideas (<a href="https://techcrunch.com/2022/07/19/instagram-new-searchable-map-experience/">Instagram Maps</a> and <a href="https://mashable.com/article/qr-code-instagram">QR Codes</a>) and fixing tech debt around our Python codebase, I kept a running list of opportunities I found along the way: abstractions that were repeatedly slowing down engineers and causing reliability issues, small improvements we could make to the type safety of our libraries, new infrastructure that we could build and ways we could make existing infrastructure better.</p>

<h2 id="leaning-in">Leaning in</h2>

<p>I started to shift the kinds of things I worked on, to focus more on simplifying our codebase, improving our infrastructure, and making our engineers more productive. I had done infra and DevX work in the past (some of it <a href="https://github.com/bcherny">open source</a>), but it had always been limited to 20% time projects. It was never my main gig. I considered myself a product engineer, but found myself sliding deeper into the world of infrastructure and DevX.</p>

<p>This shift was not something I did intentionally. Because my day no longer filled up with meetings and obligations that other people put on my plate, coding and fixing the issues I found while coding gradually took up more and more of my time, until six months into being in Japan I realized that it had become my main work. I felt happy about the work I was doing, and satisfied to write code again. I started to gain a reputation as an engineer that knows the codebase and has good technical opinions, despite having been at Instagram a relatively short time, due to how much code I was churning out and the pain points I was fixing for other engineers. (By this point, I was in the top 1% of engineers at Instagram by code output.)</p>

<p>Reflecting back on this a year later, I realize I was doing the work that other engineers should have been doing, but often couldn’t due to the realities of being in an organization that demands more of your time and attention as you grow more senior. Famously, at Meta even senior engineers are expected to code (we don’t have many architect types), but their level of code output is often not the same as more junior engineers. I had essentially turned myself into an intern, coding 80% of the day. This was a powerful change, which let me identify and execute on opportunities that others simply couldn’t.</p>

<h2 id="shifting-how-i-operate">Shifting how I operate</h2>

<p>As I did this, I had to get comfortable leading from behind. I spun out a number of projects, recruiting engineers in the US and EMEA to lead and take over as soon as an effort developed sigificant communciation or coordination components. This meant delegating, and letting these emerging leaders be the public faces of projects that I might have previously spent longer incubating myself. I felt anxious about getting credit for this work, but quickly found that my worries were misplaced, and that my reputation continued to grow, and engineers and managers around the organization were not only aware of my work, but were appreciative of the opportunities I created for others and the impact this was having on Instagram. By becoming a more effective delegator, I was able to grow more engineers more quickly than I had in the past. It was gratifying, and it let me deliver results without having to participate in most meetings and synchronous communications myself.</p>

<p>Around this time, I shifted my communication style from trying to make my previous approach work in a new environment, to using my odd timezone to my advantage:</p>

<ol>
  <li>Instead of rapid back-and-forth over chat, I caught up on accumulated messages in the mornings and spent the first hour of every day responding in long form. I had to anticipate what the person at the other end of the chat was really asking, how they would respond, and what else they would need to know. By taking time to word a better response, I avoided time-consuming back-and-forth for both of us.</li>
  <li>Instead of meetings, I used Workplace posts (Meta’s internal version of Facebook Group posts) to share thoughts, start discussions, and make announcements. This had the benefit of serving as a system of record and a form of documentation, while at the same time being more inclusive of people in different timezones and those who would not have been invited to or would not have felt comfortable speaking up at a meeting.</li>
  <li>I focused my 1-2 hours of available meeting time each day on the conversations that absolutely had to be synchronous. This meant spacing weekly 1-1s out to biweekly or monthly, and turning down meetings more often.</li>
  <li>I began flying to the US every quarter or so for in-person time. No matter how good I felt about my newfound ability to work asynchronously, there is simply no alternative to seeing your coworkers in person, catching up about their families and lives without the ticking clock of a virtual meeting, and grabbing beer after-hours to kvetch and ideate and get to know each other as friends.</li>
</ol>

<p>I also had to adjust my schedule to better manage my own health. When I worked in California, I would drive from San Francisco to get to Menlo Park around 10am, then head home around 6 or 7pm. Now, since my time overlap with the US was in the morning, I had to shift my meeting times earlier, often to 8 or 9am. At the same time, it is important for my mental health to have a morning routine: I like to run, make coffee, and study in the morning; to avoid compromising on this, I shifted my schedule up, waking up at 6:30am to have time for these must-haves.</p>

<h2 id="closing">Closing</h2>

<p>Overall, the move turned out well for me: I have learned to work effectively from a very different timezone, and am happy with the results. I don’t think this setup would work well for everyone, and I feel lucky that I was able to iterate to a working style that is good for me. I am grateful that my organization supports and appreciates the work I do, and is accommodating of the way I do it. I hope my experience resonates with others, and am eager to learn about others’ experiences in similar setups.</p>

<p>Discuss this post on <a href="https://www.threads.net/@boris_cherny/post/C0r9eUcPTCs">Threads</a>.</p>]]></content><author><name></name></author><category term="Tech" /><summary type="html"><![CDATA[For the last year and a half, I have been working at Instagram in Japan. It’s a bit of an unusual setup: I live and work remotely from Nara, Japan, in a timezone that few other Meta engineers work in (most of Instagram and Meta are spread across the US and Europe).]]></summary></entry><entry><title type="html">Time and Timing</title><link href="/2022/09/07/time-and-timing.html" rel="alternate" type="text/html" title="Time and Timing" /><published>2022-09-07T00:00:00+00:00</published><updated>2022-09-07T00:00:00+00:00</updated><id>/2022/09/07/time-and-timing</id><content type="html" xml:base="/2022/09/07/time-and-timing.html"><![CDATA[<p>You often hear that “timing matters”. It helps to think about this as two related concepts: time and timing.</p>

<p>For some things, time is more important than timing:</p>

<ul>
  <li><strong>Investing (long term)</strong>. Investing for the long term is <a href="https://www.washingtonpost.com/business/barry-ritholtz-time-not-timing-is-key-to-investing-success/2014/08/21/b3443d9a-27d2-11e4-86ca-6f03cbd15c1a_story.html">all about</a> holding a diverse set of assets for as long as possible. It doesn’t matter if you invest at discounted price, because (a) most of your gains come from the long-term effects of compounding, not from the price you bought at, and (b) you’ll probably time it wrong anyway.</li>
  <li><strong>Learning</strong>. It’s never too late to learn a new skill or expertise. But the earlier you start, the more you will be rewarded with better opportunities, improved decision making, and <a href="https://www.goodreads.com/book/show/13525945-so-good-they-can-t-ignore-you">higher job satisfaction</a>. Like an investment, your knowledge will compound to improve all the choices you make and things you do throughout life.</li>
  <li><strong>Relationships</strong>. Building your social network will give you access to opportunities and friends/partners you wouldn’t have had otherwise. The longer you do this, the more you’ll benefit yourself and others.</li>
</ul>

<p>For other things, timing is more important than time:</p>

<ul>
  <li><strong>Investing (short term)</strong>. I once sold my three best Pokemon cards on eBay for $0.99 plus shipping; today, those cards would have fetched at least 100x that. Short-term investing is about timing the market to sell at a peak, buy at a trough, or exploit an inefficiency before everyone else catches on.</li>
  <li><strong>Starting a business</strong>. Many good business ideas failed because they were tried at the wrong time – either the market wasn’t ready for them, or the tech wasn’t ready. Successful businesses don’t just have a great idea and execute it well, but they need to do it at just the right time.</li>
  <li><strong>Genes</strong>. For a mutated gene to take off in a population, it has to give its carriers a reproductive advantage in the environment at the time. A drought resistance gene isn’t useful in a year with heavy rain.</li>
</ul>

<p>What’s the difference between these two classes of phenomena? Things that compound are all about <em>time</em>; the longer you do them, the faster the benefits build on each other. Things that are about exploiting a new opportunity are about <em>timing</em>; if you don’t do them at the right time, you won’t be rewarded. Try not to confuse the two.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[You often hear that “timing matters”. It helps to think about this as two related concepts: time and timing.]]></summary></entry><entry><title type="html">Dinosaur Food: 100 million year old foods we still eat today</title><link href="/food/2022/01/17/Dinosaur-food.html" rel="alternate" type="text/html" title="Dinosaur Food: 100 million year old foods we still eat today" /><published>2022-01-17T00:00:00+00:00</published><updated>2022-01-17T00:00:00+00:00</updated><id>/food/2022/01/17/Dinosaur-food</id><content type="html" xml:base="/food/2022/01/17/Dinosaur-food.html"><![CDATA[<p>I just finished Oliver Sacks’ excellent <em><a href="https://www.penguinrandomhouse.com/books/538576/everything-in-its-place-by-oliver-sacks/">Everything in Its Place</a></em>. In it, he mentioned as an aside that the <em>Ginkgo biloba</em> tree is hundreds of millions of years old, and its phenotype has been practically frozen since then – a living fossil.</p>

<p>Of course, this is the same tree that grows ぎんなん (Ginkgo nuts), an East Asian delicacy found in many dishes, 茶碗蒸し (Chawanmushi) for example.</p>

<p>Ginkgo has been around so long, it predates the dinosaurs! And we still eat it! How cool is that. This got me thinking – what are the oldest foods we consume today?</p>

<p>Criteria:</p>

<ol>
  <li>Must be edible by humans</li>
  <li>Must be morphologically unchanged since its fossil age</li>
</ol>

<table>
  <thead>
    <tr>
      <th>Photo</th>
      <th>Kingdom</th>
      <th>Species</th>
      <th>Common name</th>
      <th>Age (years)</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><img src="https://upload.wikimedia.org/wikipedia/commons/1/1b/Limulus_polyphemus_horseshue_crab_on_coast.jpg" width="60" /></td>
      <td>Animalia</td>
      <td>Tachypleus tridentatus</td>
      <td>Horseshoe crab</td>
      <td><a href="https://www.frontiersin.org/articles/10.3389/feart.2020.00098/full">480M</a></td>
    </tr>
    <tr>
      <td><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/7/78/GinkgoLeaves.jpg/1280px-GinkgoLeaves.jpg" width="60" /></td>
      <td>Plantae</td>
      <td>Ginkgo biloba</td>
      <td>Maidenhair nuts</td>
      <td><a href="https://www.sciencedirect.com/science/article/abs/pii/S1871174X0900002X?via%3Dihub">290M</a></td>
    </tr>
    <tr>
      <td><img src="https://upload.wikimedia.org/wikipedia/commons/e/e1/WilaBig.jpg" width="60" /></td>
      <td>Plantae</td>
      <td>Bryoria fremontii</td>
      <td>Wila</td>
      <td><a href="https://en.wikipedia.org/wiki/Moss#Geological_history">250M</a>?</td>
    </tr>
    <tr>
      <td><img src="https://upload.wikimedia.org/wikipedia/commons/2/29/Cladonia_portentosa_top.JPG" width="60" /></td>
      <td>Plantae</td>
      <td>Cladonia rangiferina</td>
      <td>Reindeer lichen</td>
      <td><a href="https://en.wikipedia.org/wiki/Moss#Geological_history">250M</a>?</td>
    </tr>
    <tr>
      <td><img src="https://upload.wikimedia.org/wikipedia/commons/3/3b/Cycas_inflorescence.jpg" width="60" /></td>
      <td>Plantae</td>
      <td>Cycas revoluta</td>
      <td>Sago palm</td>
      <td><a href="http://www1.biologie.uni-hamburg.de/b-online/library/cycads/fossilspast.htm">200M</a></td>
    </tr>
    <tr>
      <td><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/1/1b/Zweig_der_Andentannne.JPG/2560px-Zweig_der_Andentannne.JPG" width="60" /></td>
      <td>Plantae</td>
      <td>Araucaria araucana</td>
      <td>Monkey puzzle tree nuts</td>
      <td><a href="https://www.pacificu.edu/about/campuses-locations/forest-grove-campus/guide-trees/monkeypuzzle">160M</a></td>
    </tr>
    <tr>
      <td><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/2/23/Equisetum_arvense_foliage.jpg/2560px-Equisetum_arvense_foliage.jpg" width="60" /></td>
      <td>Plantae</td>
      <td>Equisetum arvense</td>
      <td>Horsetail</td>
      <td><a href="https://en.wikipedia.org/wiki/Equisetum#Evolutionary_history">140M</a></td>
    </tr>
    <tr>
      <td><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/e/ec/Welwitschia_mirabilis_%28female%29.jpg/2560px-Welwitschia_mirabilis_%28female%29.jpg" width="60" /></td>
      <td>Plantae</td>
      <td>Welwitschia</td>
      <td>-</td>
      <td><a href="https://pubmed.ncbi.nlm.nih.gov/33504814/">112M</a></td>
    </tr>
    <tr>
      <td><img src="https://upload.wikimedia.org/wikipedia/commons/2/26/Cinnamon_fern.jpg" width="60" /></td>
      <td>Plantae</td>
      <td>Osmundastrum cinnamomeum</td>
      <td>Cinnamon fern</td>
      <td><a href="https://www.journals.uchicago.edu/doi/10.1086/314134">70M</a></td>
    </tr>
    <tr>
      <td><img src="https://upload.wikimedia.org/wikipedia/commons/f/f3/Water-caltrops.jpg" width="60" /></td>
      <td>Plantae</td>
      <td>Trapa natans</td>
      <td>Water caltrop nuts</td>
      <td><a href="https://en.wikipedia.org/wiki/Water_caltrop#Fossil_record">66M</a></td>
    </tr>
    <tr>
      <td><img src="https://upload.wikimedia.org/wikipedia/commons/d/d9/Nelumbo_lutea_blossom.jpeg" width="60" /></td>
      <td>Plantae</td>
      <td>Nelumbo lutea, Nelumbo nucifera</td>
      <td>Lotus</td>
      <td><a href="https://ebrary.net/27989/environment/lotus">65M+</a></td>
    </tr>
  </tbody>
</table>

<p><em>Note: I’m a hobbyist, and not a paleobotanist. Additions and edits are <a href="https://github.com/bcherny/bcherny.github.io/edit/main/_posts/2022-01-17-Dinosaur-food.md">welcome</a>, if I misclassified or missed anything.</em></p>]]></content><author><name></name></author><category term="Food" /><summary type="html"><![CDATA[I just finished Oliver Sacks’ excellent Everything in Its Place. In it, he mentioned as an aside that the Ginkgo biloba tree is hundreds of millions of years old, and its phenotype has been practically frozen since then – a living fossil.]]></summary></entry><entry><title type="html">Data Management on the Web Still Sucks</title><link href="/javascript/2021/03/13/Data-Fetching.html" rel="alternate" type="text/html" title="Data Management on the Web Still Sucks" /><published>2021-03-13T00:00:00+00:00</published><updated>2021-03-13T00:00:00+00:00</updated><id>/javascript/2021/03/13/Data-Fetching</id><content type="html" xml:base="/javascript/2021/03/13/Data-Fetching.html"><![CDATA[<p>It’s 2021, and data management on the web still sucks. This is crazy!</p>

<p>If you’re building a web app at scale you have plenty of options for data fetching, transport, caching, and management:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">fetch</code>, <code class="language-plaintext highlighter-rouge">XMLHTTPRequest</code>, etc. (REST)</li>
  <li><a href="https://swagger.io/">Swagger</a> (REST)</li>
  <li><a href="https://github.com/Netflix/falcor">Falcor</a> (REST)</li>
  <li><a href="https://github.com/apollographql/apollo-client">Apollo</a> (GraphQL)</li>
  <li><a href="https://github.com/facebook/relay">Relay</a> (GraphQL)</li>
  <li><a href="https://github.com/protobufjs/protobuf.js">Protobuf</a></li>
  <li><a href="https://github.com/grpc/grpc-node">gRPC</a></li>
  <li>…</li>
</ul>

<p>Each of these does a few things well, leaving the rest to you. What do you need to do well to be a good data fetching library?</p>

<h2 id="fetching-data">Fetching Data</h2>

<ul>
  <li><strong>Consistency when fetching data</strong>. When your app fetches new data, the UI should automatically update everywhere that data is used.</li>
  <li><strong>Request batching</strong>. When multiple requests are made at the same time, they should be combined into one request, when reasonable, to avoid hitting browser-imposed concurrency limits.</li>
  <li><strong>Avoiding network waterfalls</strong>. When fetching data for a component, you should make one request that includes data for all its descendents too, to avoid lots of network round trips. GraphQL solves this with fragments, but it’s still painful in modern clients (eg. Relay does this by requiring you manually compose fragments up the React tree so they’re fetched together, then pass fragment pointers down the tree to tell Relay where to look for fetched data; it also requires a compilation step).</li>
  <li><strong>UX when fetching data</strong>. It’s a big burden for engineers to have to manually add loading spinners and error states, and engineers often forget.</li>
  <li><strong>Colocation</strong>. You should declare data dependencies close to where they’re used, ideally in the same file. Same principle as colocating CSS with your components.</li>
  <li><strong>File size</strong>. You shouldn’t have to ship kilobytes of metadata describing your data schema to clients in order to fetch data.</li>
  <li><strong>Type safety</strong>. Your code should know what type of data it got from the server.</li>
  <li><strong>Versioning</strong>. Updating your data model should be backwards-compatible; clients should be forwards-compatible.</li>
  <li><strong>Realtime updates</strong>. Sometimes, you want data to be pushed, not pulled (eg. for things like notifications). But the APIs for pushing and pulling data are often different, both on the client and on the server.</li>
</ul>

<h2 id="updating-data">Updating Data</h2>

<ul>
  <li><strong>Consistency when updating data</strong>. When you update a piece of data, your data fetching library should automatically refetch dependent data that will change after the request completes (eg. if you update <code class="language-plaintext highlighter-rouge">Person.FirstName</code>, <code class="language-plaintext highlighter-rouge">Person.FullName</code> should automatically be refetched).</li>
  <li><strong>Optimistic updates</strong>. The UI should optimistically render the success state before a server response comes back, if there’s a high chance the request will succeed. This makes your UI feel snappy and fun to use. Today’s data fetching libraries make this a lot of manual work.</li>
  <li><strong>Request queueing</strong>. Requests that depend on one another need to be queued; independent requests can be sent in parallel. Otherwise, network weather and server queuing can cause your client to end up in a state that’s inconsistent with the server.</li>
  <li><strong>UX when updating data</strong>. Product engineers shouldn’t need to manually render loading spinners and success and error notifications.</li>
  <li><strong>Durability when updating data</strong>. Exponential backoff for retrying idempotent requests and idempotence tokens for network failures; eager persistance to disk for client/server failures.</li>
  <li><strong>Type safety</strong>. You shouldn’t be able to send invalid input to the server, for some definition of invalid.</li>
  <li><strong>Versioning</strong>. Updates to your mutation APIs should be backwards-compatible; clients should be forwards-compatible.</li>
</ul>

<h2 id="why">Why?</h2>

<p>I think the reason this hasn’t been solved is it’s a hard problem that’s at the intersection of a bunch of fast-moving technologies:</p>

<ol>
  <li>Programming languages (to infer what data depends on what)</li>
  <li>Databases (client-side stores are small databases)</li>
  <li>Server APIs and protocols (REST, GraphQL, RPC, etc.)</li>
  <li><del>UI frameworks</del> (at this point, React has won)</li>
  <li>User experience and perceived performance</li>
</ol>

<p>So far, every attempt at solving data fetching has either tightly coupled all of these layers, leading to trouble gaining mass adoption (think <a href="https://www.meteor.com/">Meteor</a>); other solutions have tackled just one layer, ignoring the rest. This smells to me like the abstractions &amp; APIs for each layer are wrong: you shouldn’t need tight coupling to solve data fetching. Instead, you need better abstractions.</p>

<p>Is this a problem that can be solved?</p>]]></content><author><name></name></author><category term="JavaScript" /><summary type="html"><![CDATA[It’s 2021, and data management on the web still sucks. This is crazy!]]></summary></entry><entry><title type="html">Public Opinion</title><link href="/politics/2021/01/06/Public-Opinion.html" rel="alternate" type="text/html" title="Public Opinion" /><published>2021-01-06T00:00:00+00:00</published><updated>2021-01-06T00:00:00+00:00</updated><id>/politics/2021/01/06/Public-Opinion</id><content type="html" xml:base="/politics/2021/01/06/Public-Opinion.html"><![CDATA[<p>I don’t usually write about politics, but today was a weird day.</p>

<p>Thousands of people gathered outside the Capitol building in Washington DC today, some of them going into the building, some with guns. A woman got shot. All of this in response to Donald Trump’s <a href="https://www.usatoday.com/story/news/nation/2021/01/06/dc-protests-live-updates-trump-supporters-electoral-college-proud-boys/4126018001/">remark</a>:</p>

<blockquote>
  <p>We’re going to try and give our Republicans the kind of pride and boldness that they need to take back our country.</p>
</blockquote>

<p>This is the latest in an escalating, years-long trend of different people seeing completely different realities in the US. What is to some a long-running trend of <a href="https://longnow.org/seminars/02012/oct/08/decline-violence/">declining violence</a> feels to others like a sharp increase; what’s to some a trend of increasing wealth and prosperity, is to others shrinking opportunity; what is to some a fair election, is to others an unfair steal.</p>

<p>It’s a good thing that different people have different political philosophies and values – competition of ideas is good, and leads to better ideas in the long run. We need conservatives and liberals and libertarians and socialists to ask questions and argue for ideas that others don’t.</p>

<p>There have always been radicals, good and bad, but the public largely agreed on most things most of the time, when it comes to the facts. Why has this changed? Or, maybe it’s just taking longer for people to converge on a common set of facts on a given issue?</p>

<p>⁂⁂⁂</p>

<p>I just finished Walter Lippmann’s 1922 classic <a href="https://smile.amazon.com/Public-Opinion-Walter-Lippmann/dp/0684833271">Public Opinion</a>. In it he argues that different people often draw completely different conclusions from the same facts due to three things:</p>

<ol>
  <li>
    <p><strong>Sampling</strong>. There’s a big universe of facts out there, and each media outlet reports on a tiny piece of this universe.</p>
  </li>
  <li>
    <p><strong>Stereotypes</strong>. When you read a news story, you unconsciously pattern match and associate it to related examples you have in your mind (poor people are lazy, young mothers are desparate, immigrants are criminals, etc.).</p>
  </li>
  <li>
    <p><strong>Context</strong>. When you read a news story, you subconsciously have some fascet of your own identity in mind (as a Republican, as a pro-choice person, etc.).</p>
  </li>
</ol>

<p>All three are in effect when stories are reported on and consumed. It’s a series of lenses that samples, then distorts, the truth in a way that given the same real-world event, different people may come to completely different conclusions about what happened.</p>

<p>For example, one person might read a CNN article about how voter turnout has been great this election, picture in their mind a stereotype of a concerned citizen going out to due their civic duty and vote for the first time, and feel proud about how this will help their party, the Democrats, win.</p>

<p>Concurrently, another person might listen to their trusted Breitbart podcast about several documented cases of voter fraud – which invokes in their mind a stereotype of a crazed liberal trying to push their unpopular policy by whatever means necessary – and feel their duty as a patriot to do something about it.</p>

<p>Both stories may have grains of truth within them, but by the time they are reported on and consumed by people, these grains are far gone and the two peoples’ resulting perceptions couldn’t be more different.</p>

<p>⁂⁂⁂</p>

<p>I’d add a #1b to Lippmann’s series of lenses: Fake News.</p>

<p>Fake News amplifies #1 (sampling) significantly. It was less of a problem in Lippmann’s time since the News world was much smaller, and only highly edited and fact-checked publications – with their reputations at stake – had enough circulation to influence public opinion nationally.</p>

<p>Lippmann might have called Fake News “rumors”, not “news”, since they definitely existed in and before his time (think medieval stories about Jews putting Christian babies’ blood in Matzos). What’s changed now is rumors have national circulation.</p>

<p>⁂⁂⁂</p>

<p>So, where do we go from here?</p>

<p>I think we should use Lippmann’s framework for public opinion as a roadmap for how to unify public opinion a bit more:</p>

<ul>
  <li><strong>Sampling</strong>:
    <ol>
      <li>Regulate news stations, and force them to give air time to the other side too (the FCC’s Fairness Doctrine Act did this in the US till 1987 – last year there was a bill to bring it back, H.R. 4401).</li>
      <li>1000x government grants for public media, to make it possible for stations like NPR to compete with Fox, CNN, NYTimes, etc. in terms of national distribution, and to spur more competition in public media.</li>
      <li>Encourage social media companies to downrank content from people whose past content has been disputed.</li>
    </ol>
  </li>
  <li><strong>Stereotypes</strong>:
    <ol>
      <li>Improve public education by paying teachers more, breaking up unions, increasing competition in public schools (with vouchers, etc.), and funding early childhood and after-school programs.</li>
      <li>Increase arts grants to spur empathy and imagination.</li>
      <li>Invest in ways to get rural folks to move to cities for a few years, and vice-versa. People need to see the other side as concrete people, not abstract evils.</li>
    </ol>
  </li>
  <li><strong>Context</strong>:
    <ol>
      <li>Invest in a national counter-propaganda (in the <a href="https://smile.amazon.com/Propaganda-Edward-Bernays/dp/0970312598">Bernays</a> sense) that promotes shared values (democracy, freedom, decency) over the tribal propagandas of today.</li>
      <li>Discourage tribalism and build a stonger a national identity with all of the above.</li>
    </ol>
  </li>
</ul>]]></content><author><name></name></author><category term="Politics" /><summary type="html"><![CDATA[I don’t usually write about politics, but today was a weird day.]]></summary></entry><entry><title type="html">React+TypeScript: Use unions of objects for props</title><link href="/typescript/react/2019/12/24/Use-unions-of-objects.html" rel="alternate" type="text/html" title="React+TypeScript: Use unions of objects for props" /><published>2019-12-24T00:00:00+00:00</published><updated>2019-12-24T00:00:00+00:00</updated><id>/typescript/react/2019/12/24/Use-unions-of-objects</id><content type="html" xml:base="/typescript/react/2019/12/24/Use-unions-of-objects.html"><![CDATA[<p>When typing React component <code class="language-plaintext highlighter-rouge">props</code> using TypeScript, I often see code that makes use of optional and nullable fields:</p>

<div class="language-tsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">type</span> <span class="nx">Props</span> <span class="o">=</span> <span class="p">{</span>
  <span class="nx">href</span><span class="p">?:</span> <span class="kr">string</span>
  <span class="nx">onClick</span><span class="p">?:</span> <span class="p">()</span> <span class="o">=&gt;</span> <span class="k">void</span>
  <span class="na">text</span><span class="p">:</span> <span class="kr">string</span>
<span class="p">}</span>

<span class="kd">function</span> <span class="nx">Button</span><span class="p">(</span><span class="nx">props</span><span class="p">:</span> <span class="nx">Props</span><span class="p">)</span> <span class="p">{</span>
  <span class="k">if</span> <span class="p">(</span><span class="dl">'</span><span class="s1">href</span><span class="dl">'</span> <span class="k">in</span> <span class="nx">props</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="p">(</span>
      <span class="p">&lt;</span><span class="nt">a</span> <span class="na">className</span><span class="p">=</span><span class="s">"Button"</span> <span class="na">href</span><span class="p">=</span><span class="si">{</span><span class="nx">props</span><span class="p">.</span><span class="nx">href</span><span class="si">}</span><span class="p">&gt;</span>
        <span class="si">{</span><span class="nx">props</span><span class="p">.</span><span class="nx">text</span><span class="si">}</span>
      <span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
    <span class="p">)</span>
  <span class="p">}</span>
  <span class="k">if</span> <span class="p">(</span><span class="dl">'</span><span class="s1">onClick</span><span class="dl">'</span> <span class="k">in</span> <span class="nx">props</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="p">(</span>
      <span class="p">&lt;</span><span class="nt">button</span> <span class="na">className</span><span class="p">=</span><span class="s">"Button"</span> <span class="na">onClick</span><span class="p">=</span><span class="si">{</span><span class="nx">props</span><span class="p">.</span><span class="nx">onClick</span><span class="si">}</span><span class="p">&gt;</span>
        <span class="si">{</span><span class="nx">props</span><span class="p">.</span><span class="nx">text</span><span class="si">}</span>
      <span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;</span>
    <span class="p">)</span>
  <span class="p">}</span>
  <span class="k">throw</span> <span class="nx">ReferenceError</span><span class="p">(</span><span class="dl">'</span><span class="s1">You must pass either href or onClick to &lt;Button /&gt;</span><span class="dl">'</span><span class="p">)</span>
<span class="p">}</span>

<span class="kd">let</span> <span class="nx">a</span> <span class="o">=</span> <span class="p">&lt;</span><span class="nc">Button</span> <span class="na">text</span><span class="p">=</span><span class="s">"Click me"</span> <span class="na">href</span><span class="p">=</span><span class="s">"https://github.com"</span> <span class="p">/&gt;</span>
<span class="kd">let</span> <span class="nx">b</span> <span class="o">=</span> <span class="p">&lt;</span><span class="nc">Button</span> <span class="na">text</span><span class="p">=</span><span class="s">"Click me"</span> <span class="na">onClick</span><span class="p">=</span><span class="si">{</span><span class="p">()</span> <span class="o">=&gt;</span> <span class="p">{}</span><span class="si">}</span> <span class="p">/&gt;</span>

<span class="c1">// OK. Should be an error</span>
<span class="kd">let</span> <span class="nx">c</span> <span class="o">=</span> <span class="p">&lt;</span><span class="nc">Button</span> <span class="na">text</span><span class="p">=</span><span class="s">"Click me"</span> <span class="na">href</span><span class="p">=</span><span class="s">"https://github.com"</span> <span class="na">onClick</span><span class="p">=</span><span class="si">{</span><span class="p">()</span> <span class="o">=&gt;</span> <span class="p">{}</span><span class="si">}</span> <span class="p">/&gt;</span>

<span class="c1">// OK. Throws an error at runtime</span>
<span class="kd">let</span> <span class="nx">d</span> <span class="o">=</span> <span class="p">&lt;</span><span class="nc">Button</span> <span class="na">text</span><span class="p">=</span><span class="s">"Click me"</span> <span class="p">/&gt;</span>
</code></pre></div></div>

<p>In this example, <code class="language-plaintext highlighter-rouge">Button</code> is a React component that takes a prop <code class="language-plaintext highlighter-rouge">text</code>, and either an <code class="language-plaintext highlighter-rouge">href</code> or <code class="language-plaintext highlighter-rouge">onClick</code> prop controlling what happens when you press the button. Either <code class="language-plaintext highlighter-rouge">href</code> or <code class="language-plaintext highlighter-rouge">onClick</code> might be defined, and we throw a runtime exception if neither of them are defined.</p>

<p>This code has a few problems:</p>

<ol>
  <li>The error case (when neither <code class="language-plaintext highlighter-rouge">href</code> nor <code class="language-plaintext highlighter-rouge">onClick</code> are passed in) is caught at runtime. Can we catch it at compile time instead?</li>
  <li>As a person using <code class="language-plaintext highlighter-rouge">&lt;Button /&gt;</code>, I don’t know if I should pass in <code class="language-plaintext highlighter-rouge">href</code>, <code class="language-plaintext highlighter-rouge">onClick</code>, or both.</li>
  <li>We only handled 2 cases in our component’s implementation, but there are actually 4 cases to handle!</li>
</ol>

<table>
  <thead>
    <tr>
      <th>Was <code class="language-plaintext highlighter-rouge">href</code> passed in?</th>
      <th>Was <code class="language-plaintext highlighter-rouge">onClick</code> passed in?</th>
      <th>Did we handle it?</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>No</td>
      <td>No</td>
      <td>No</td>
    </tr>
    <tr>
      <td>Yes</td>
      <td>No</td>
      <td>Yes</td>
    </tr>
    <tr>
      <td>No</td>
      <td>Yes</td>
      <td>Yes</td>
    </tr>
    <tr>
      <td>Yes</td>
      <td>Yes</td>
      <td>No</td>
    </tr>
  </tbody>
</table>

<p>When you have an object type with nullable, optional, or union-typed fields, the number of states the object can be in quickly explodes. This example has two optional fields, leading to 2<sup>2</sup>=4 states. If it had 3 optional fields that would be 2<sup>3</sup>=8 states, 4 would be 2<sup>4</sup>=16 states, and so on. The number of states can grow fast, slowing down typechecking, introducing subtle bugs in your code, and making your APIs a little bit harder to reason about.</p>

<p>When possible, use unions of objects instead of objects with nullable fields.</p>

<p>Since TypeScript unions are not disjoint by default, you’ll want to also add a special “tag” field on each object in the union: a field that’s typed as a literal (string, number, boolean, etc.) that hints to TypeScript that the union is disjoint – that is, that <code class="language-plaintext highlighter-rouge">props</code> must be the first object in the union, or the second, but not an object that has fields from both. (Concretely, if you don’t add the field, TypeScript won’t complain about <code class="language-plaintext highlighter-rouge">c</code> below):</p>

<div class="language-tsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">type</span> <span class="nx">Props</span> <span class="o">=</span>
  <span class="o">|</span> <span class="p">{</span><span class="na">text</span><span class="p">:</span> <span class="kr">string</span><span class="p">;</span> <span class="nl">type</span><span class="p">:</span> <span class="dl">'</span><span class="s1">href</span><span class="dl">'</span><span class="p">;</span> <span class="nl">href</span><span class="p">:</span> <span class="kr">string</span><span class="p">}</span>
  <span class="o">|</span> <span class="p">{</span><span class="na">text</span><span class="p">:</span> <span class="kr">string</span><span class="p">;</span> <span class="nl">type</span><span class="p">:</span> <span class="dl">'</span><span class="s1">onClick</span><span class="dl">'</span><span class="p">;</span> <span class="nx">onClick</span><span class="p">():</span> <span class="k">void</span><span class="p">}</span>

<span class="kd">function</span> <span class="nx">Button</span><span class="p">(</span><span class="nx">props</span><span class="p">:</span> <span class="nx">Props</span><span class="p">)</span> <span class="p">{</span>
  <span class="k">if</span> <span class="p">(</span><span class="nx">props</span><span class="p">.</span><span class="kd">type</span> <span class="o">===</span> <span class="dl">'</span><span class="s1">href</span><span class="dl">'</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="p">(</span>
      <span class="p">&lt;</span><span class="nt">a</span> <span class="na">className</span><span class="p">=</span><span class="s">"Button"</span> <span class="na">href</span><span class="p">=</span><span class="si">{</span><span class="nx">props</span><span class="p">.</span><span class="nx">href</span><span class="si">}</span><span class="p">&gt;</span>
        <span class="si">{</span><span class="nx">props</span><span class="p">.</span><span class="nx">text</span><span class="si">}</span>
      <span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
    <span class="p">)</span>
  <span class="p">}</span>
  <span class="k">return</span> <span class="p">(</span>
    <span class="p">&lt;</span><span class="nt">button</span> <span class="na">className</span><span class="p">=</span><span class="s">"Button"</span> <span class="na">onClick</span><span class="p">=</span><span class="si">{</span><span class="nx">props</span><span class="p">.</span><span class="nx">onClick</span><span class="si">}</span><span class="p">&gt;</span>
      <span class="si">{</span><span class="nx">props</span><span class="p">.</span><span class="nx">text</span><span class="si">}</span>
    <span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;</span>
  <span class="p">)</span>
<span class="p">}</span>

<span class="kd">let</span> <span class="nx">a</span> <span class="o">=</span> <span class="p">&lt;</span><span class="nc">Button</span> <span class="na">text</span><span class="p">=</span><span class="s">"Click me"</span> <span class="na">type</span><span class="p">=</span><span class="s">"href"</span> <span class="na">href</span><span class="p">=</span><span class="s">"https://github.com"</span> <span class="p">/&gt;</span>
<span class="kd">let</span> <span class="nx">b</span> <span class="o">=</span> <span class="p">&lt;</span><span class="nc">Button</span> <span class="na">text</span><span class="p">=</span><span class="s">"Click me"</span> <span class="na">type</span><span class="p">=</span><span class="s">"onClick"</span> <span class="na">onClick</span><span class="p">=</span><span class="si">{</span><span class="p">()</span> <span class="o">=&gt;</span> <span class="p">{}</span><span class="si">}</span> <span class="p">/&gt;</span>

<span class="c1">// Compile-time error</span>
<span class="kd">let</span> <span class="nx">c</span> <span class="o">=</span> <span class="p">(</span>
  <span class="p">&lt;</span><span class="nc">Button</span>
    <span class="na">text</span><span class="p">=</span><span class="s">"Click me"</span>
    <span class="na">type</span><span class="p">=</span><span class="s">"href"</span>
    <span class="na">href</span><span class="p">=</span><span class="s">"https://github.com"</span>
    <span class="na">onClick</span><span class="p">=</span><span class="si">{</span><span class="p">()</span> <span class="o">=&gt;</span> <span class="p">{}</span><span class="si">}</span>
  <span class="p">/&gt;</span>
<span class="p">)</span>

<span class="c1">// Compile-time error</span>
<span class="kd">let</span> <span class="nx">d</span> <span class="o">=</span> <span class="p">&lt;</span><span class="nc">Button</span> <span class="na">text</span><span class="p">=</span><span class="s">"Click me"</span> <span class="p">/&gt;</span>
</code></pre></div></div>

<p>This approach enforces at compile time that either <code class="language-plaintext highlighter-rouge">href</code> or <code class="language-plaintext highlighter-rouge">onClick</code>, and not both, are passed as props to <code class="language-plaintext highlighter-rouge">&lt;Button /&gt;</code>. That means we don’t need to throw runtime exceptions anymore, and we can trust TypeScript to verify that we’ve covered our cases.</p>

<p>Note that you can’t always use this approach. There are times when it’s impossible or needlessly wordy to split out your object of unions into a union of objects. Keep this technique in mind for the times that it does make your code more terse, safe, and easy to use.</p>]]></content><author><name></name></author><category term="TypeScript" /><category term="React" /><summary type="html"><![CDATA[When typing React component props using TypeScript, I often see code that makes use of optional and nullable fields:]]></summary></entry><entry><title type="html">On Contagion</title><link href="/philosophy/of/programming/2019/09/08/On-Contagion.html" rel="alternate" type="text/html" title="On Contagion" /><published>2019-09-08T00:00:00+00:00</published><updated>2019-09-08T00:00:00+00:00</updated><id>/philosophy/of/programming/2019/09/08/On-Contagion</id><content type="html" xml:base="/philosophy/of/programming/2019/09/08/On-Contagion.html"><![CDATA[<p>If you have a tree with a node that has a property <code class="language-plaintext highlighter-rouge">P</code>, and all of its parents also need to have property <code class="language-plaintext highlighter-rouge">P</code>, then <code class="language-plaintext highlighter-rouge">P</code> is contagious.</p>

<p>When can that happen?</p>

<ul>
  <li>Exceptions bubble up through the call tree</li>
  <li>State has to be lifted up to the root of a call tree</li>
  <li>If a function is <code class="language-plaintext highlighter-rouge">async</code>, its ancestors must be too</li>
  <li>Centralized services also centralize any decentralized services that call them</li>
  <li>In a physical system, if you know the position and momentum of an object <code class="language-plaintext highlighter-rouge">A</code> and it collides with another object <code class="language-plaintext highlighter-rouge">B</code> that you don’t know one of those quantities for, then you no longer know them about <code class="language-plaintext highlighter-rouge">A</code>. (caveat: I’m no physicist)</li>
</ul>

<p>Concretely:</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">async</span> <span class="kd">function</span> <span class="nx">a</span><span class="p">()</span> <span class="p">{</span>
  <span class="c1">// a has to be async to await b()</span>
  <span class="k">await</span> <span class="nx">b</span><span class="p">()</span>
<span class="p">}</span>

<span class="k">async</span> <span class="kd">function</span> <span class="nx">b</span><span class="p">()</span> <span class="p">{</span>
  <span class="c1">// b has to be async to await c()</span>
  <span class="k">await</span> <span class="nx">c</span><span class="p">()</span>
<span class="p">}</span>
</code></pre></div></div>

<p>As a programmer, that seems bad. Bubbling up breaks encapsulation and makes things harder to compose. If I have a nice application and need to mark a function deep in the app <code class="language-plaintext highlighter-rouge">async</code>, why do I need to update all of its callers to be <code class="language-plaintext highlighter-rouge">async</code> too? Why should a parent know about its grandchild?</p>

<p>For good reason. At runtime, some contagious things are special:</p>

<ul>
  <li>Exceptions bubble up through the call stack</li>
  <li><code class="language-plaintext highlighter-rouge">await</code> pauses execution</li>
</ul>

<p>We want to model these runtime behaviors in our language:</p>

<ul>
  <li>Asynchronous code needs to be awaited before continuing. As a consumer of an asynchronous function, you want to know that it’s asynchronous so that you can treat it as special.</li>
  <li>State is a function parameter, because the function’s computation depends on it. As a consumer, you need to pass the state to it.</li>
  <li>Functions that throw are modeled with a <code class="language-plaintext highlighter-rouge">throws</code> clause, <code class="language-plaintext highlighter-rouge">Either</code>, <code class="language-plaintext highlighter-rouge">Err</code>, or nothing, depending on the language. As a consumer, you might want to know that something throws so you can handle it.</li>
</ul>

<p>In some languages, all of these are captured in a function’s return type. The idea is that these aren’t implementation details – consumers really should know about them. These languages model runtime behavior using types.</p>

<ul>
  <li>Async: <code class="language-plaintext highlighter-rouge">Future</code>/<code class="language-plaintext highlighter-rouge">Promise</code></li>
  <li>State: The <code class="language-plaintext highlighter-rouge">State</code> monad, or passing a callback down the call stack</li>
  <li>Exception: <code class="language-plaintext highlighter-rouge">Either</code>, <code class="language-plaintext highlighter-rouge">Err</code>, <code class="language-plaintext highlighter-rouge">throws</code></li>
</ul>

<p>But, you sometimes want a trap door:</p>

<ul>
  <li>Async: <code class="language-plaintext highlighter-rouge">.then</code>, React suspense boundaries</li>
  <li>State: Mutable state, React local state</li>
  <li>Exceptions: <code class="language-plaintext highlighter-rouge">try</code>/<code class="language-plaintext highlighter-rouge">catch</code>, React error boundaries</li>
</ul>

<p>These are ways to avoid contagion.</p>

<p>What unites all of those? They’re effects, that different languages model differently. Some languages keep them implicit (like <code class="language-plaintext highlighter-rouge">throw</code> in languages that don’t have <code class="language-plaintext highlighter-rouge">throws</code> clauses), some make them explicit (the <code class="language-plaintext highlighter-rouge">State</code> monad).</p>

<p>There’s nothing inherently contagious about these things, as evidenced by the languages that support trap doors for them. It’s up to language designers to say “this thing should be contagious” or “this thing shouldn’t”.</p>

<p>What should be contagious, but isn’t? What is contagious, but shouldn’t be?</p>]]></content><author><name></name></author><category term="Philosophy" /><category term="of" /><category term="programming" /><summary type="html"><![CDATA[If you have a tree with a node that has a property P, and all of its parents also need to have property P, then P is contagious.]]></summary></entry><entry><title type="html">13 Tips for Writing a Technical Book</title><link href="/writing/2019/05/26/Tips-For-Writing-A-Technical-Book.html" rel="alternate" type="text/html" title="13 Tips for Writing a Technical Book" /><published>2019-05-26T00:00:00+00:00</published><updated>2019-05-26T00:00:00+00:00</updated><id>/writing/2019/05/26/Tips-For-Writing-A-Technical-Book</id><content type="html" xml:base="/writing/2019/05/26/Tips-For-Writing-A-Technical-Book.html"><![CDATA[<p>I spent the last year and a half writing my first technical book for O’Reilly (<a href="https://smile.amazon.com/Programming-TypeScript-Making-JavaScript-Applications/dp/1492037656">Programming TypeScript</a>). I’d never written a technical book before. In fact, prior to the 300-page book, the longest thing I’d written was a 20-something-page paper in college.</p>

<p>Why’d I write the book? I love TypeScript, and I didn’t see any great resource out there that explained not just the language and build system features, but went deeper to explain <em>why</em> things were designed the way they were, how the different parts of the language fit together, how that compares to other languages out there, and how it all looks in practice. Those are the sorts of things you can only learn through lots of research and practice, and that was sorely missing from the handful of relatively brief and practical TypeScript guides out there today.</p>

<p>The rest of this post is a brief laundry list of tips for writing your own technical book.</p>

<h2 id="getting-a-book-deal">Getting a book deal</h2>

<p><strong>Make ‘em fight for it</strong>. One day, I got a cold email from Packt Publishing asking me to write a book on TypeScript. I’d actually been thinking about the idea for a few months, having sent a series of unreturned cold emails to an O’Reilly acquisitions editor pitching a handful of topics to write about (one that’s close to my heart, which I hope to revisit someday, is a book that teaches you functional programming in JavaScript, starting from basic middle school algebra). I really wanted to write a book for O’Reilly since they published a bunch of the technical books that I’d learned from over the years (Zakas’ excellent <a href="http://shop.oreilly.com/product/9780596802806.do">High Performance JavaScript</a> and Grigorik’s <a href="https://hpbn.co/">High Performance Browser Networking</a> are a couple of my favorites). So I forwarded Packt’s email to O’Reilly, and got a response the next day that O’Reilly was interested, and that I should send over an outline and a timeline. We had a signed contract within the week – I’d get 10% of print sales, plus 25% of digital sales.</p>

<p><strong>Pad the timeline</strong>. Like any other engineering project, the time you think it will take to write a book is going to end up being a fraction of the time it actually takes. Why? Even if you’re a subject matter expert with an outline in hand, there are a lot of unknowns: the time it takes to do research; the time it takes to come up with good examples; the time it takes to derive reference implementations; the number of times you delete and re-write sections to get them right; the overhead of coordinating contributors, and so on. Take your estimate, and pad it like you would an engineering estimate. For example, I estimated 8 months, while it actually ended up taking 15.</p>

<h2 id="writing">Writing</h2>

<p><strong>Start with an outline</strong>. Without a clear idea of what you’ll cover, it’s easy to get off-topic. It’s also easy to get burnt out from the sense of having a lot of content left to cover with no clear sense of progress or of what’s left. With an outline, it’s easy to know how far you’ve come, and how long you have left to go.</p>

<p><strong>Schedule regular time to write: every morning, every weekend, etc</strong>. With a full-time job, it can be hard to find time to write. And when you’re not writing, you might feel guilty that you’re not writing, which can lead to stress. That’s why blocking off regular time to write is key. My schedule was most Saturdays and Sundays, from 9am to 6pm. I also noticed that mornings were by far the most productive for me: while in the morning I could often get into a state of flow, this was much harder to do at night. Rinse and repeat: doing this every weekend, for months at a time, I steadily chipped away at my outline.</p>

<p><strong>Get feedback early, get feedback often</strong>. Like starting a business, you’ll often have intuition about what problem needs to be solved by your book. And like a business, you’re going to get a lot of the details wrong at first. To make sure you’re on the right track, get as much feedback as you can from potential readers: show your outline to colleagues before you write, run your drafts by friends and readers recommended by your editor (I asked O’Reilly for this on a couple of occasions); get as much feedback as you can, as early as you can. In <a href="https://smile.amazon.com/High-Output-Management-Andrew-Grove/dp/0679762884">Andy Grove</a>’s words, “a common rule we should always try to heed is to detect and fix any problem at the lowest-value stage possible”.</p>

<p><strong>Keep a running list of stylistic conventions</strong>. You’re going to have to form a point of view on a huge number of stylistic conventions as you write. For me, that included things like whether to use tabs or spaces, semicolons or no semicolons, how to consistently represent inferred types in code blocks (I used comments), how to consistently represent evaluated results in code blocks (I used comments prefixed with “evaluates to”), how to represent function and method names when talking about a function (<code class="language-plaintext highlighter-rouge">fn</code>, <code class="language-plaintext highlighter-rouge">fn()</code>, <code class="language-plaintext highlighter-rouge">.fn</code>, or <code class="language-plaintext highlighter-rouge">.fn()</code>?), and so on. There’s a lot of decisions to make, and you won’t be able to make all of them upfront. Keep a running list, and when you make up your mind about one, go back and update your manuscript to conform to that convention. The earlier you can make up your mind, the easier it will be to update everything.</p>

<p><strong>Use lots of <code class="language-plaintext highlighter-rouge">TODO</code>s to keep track of what’s left</strong>. Anytime you want to revisit something – a missing code sample, a section that reads weird and should be re-worded, a section that you don’t feel like writing at this very moment and want to circle back on later – leave a <code class="language-plaintext highlighter-rouge">TODO</code>. It’s easy to grep for later on, and it’ll help make sure you don’t miss anything.</p>

<h2 id="editing">Editing</h2>

<p><strong>When editing, print out your manuscript and edit it with a red pen</strong>. Yes, I mean with a real pen, on real paper. There’s a lot of issues you’ll catch this way that you won’t notice on screen: from grammatical errors and formatting, to discontinuities, to explanations that could use more work. Also, it feels fancy to sit at a cafe and edit a 300-page stack of papers in pen (unless you’re a teacher, in which case you’re thinking “that’s cute”).</p>

<p><strong>Read your manuscript all the way through</strong>. It might sound surprising, but after months spent writing it’s not easy to pause and take the time to read throught everything you just wrote. When you read all the way through your manuscript, you’ll notice issues that you wouldn’t have noticed when reading through a section or a chapter at a time. Certain kinds of problems you’ll only be able to find this way: things like stylistic inconsistencies (eg. you used capitalized comments in one place, and lowercased in another place), discontinuities (eg. you covered a topic twice, or forgot to give context for something), and so on. This sort of editing can be exhausting, but is critical to a high-quality result. Think of it as dogfooding.</p>

<p><strong>Expert reviewers won’t give you as much as you want</strong>. While reviewers suggested by O’Reilly were super helpful as a sanity check, they won’t give you the deep domain-specific insights and pushback that you want. They’ll review for high level structure and comprehension, but won’t go into details like “is this the right way to derive a <code class="language-plaintext highlighter-rouge">Promise</code> type?” or “is this statement about module loading technically correct?”. More generally–</p>

<p><strong>Getting good technical editors is hard</strong>. While O’Reilly provided good technical editors, I had to seek out subject matter experts myself and convince them to look at my manuscript. To do that, I asked a few friends, and emailed a bunch of people that I’ve met via <a href="https://github.com/bcherny">Github</a> and on <a href="https://www.meetup.com/San-Francisco-TypeScript-Meetup/">Meetup</a> to ask if they’d like to take a pass through my manuscript. Of course, that’s a giant ask that comes with a significant time commitment and little pay-off (O’Reilly can front technical editors a few hundred bucks as a thank you, which can feel inadequate for the 10+ hours an editor might spend editing your manuscript). Despite that, <a href="https://twitter.com/drosenwasser">Daniel Rosenwasser</a> from the TypeScript team offered to step in and edit. His contributions were the most valuable edits I recieved by an order of magnitude, and I’m immensely grateful for his taking the time to give feedback on my manuscript.</p>

<h2 id="misc">Misc.</h2>

<p><strong>While getting good technical editors is hard, getting good contributors is harder</strong>. Initially, I was hoping to get a range of contributions by subject matter experts: someone to talk about module loading, someone to talk about reactive programming, people to talk about React, Vue, and Angular. Turns out, a lot of subject matter experts don’t have time to do that. Of the dozen contributors that I planned to recruit, I ended up with two, one of which O’Reilly suggested. For these two contributors, it took a lot of work to get their contributions to a place where I could integrate them with my manuscript: back-and-forth on what content they should include, updating formatting, and integrating their sections with the rest of the manuscript. Eventually, I ended up re-working their sections significantly. As an author you have a lot of opinions about how to best present content, which can be hard to reconcile with other contributors – unlike collaborating on code, where you can enforce conventions with frameworks and linters, it’s a lot harder to be on the same page when it comes to writing style.</p>

<p><strong>Writing is lonely</strong> (Ben Horowitz <a href="https://smile.amazon.com/Hard-Thing-About-Things-Building-ebook/dp/B00DQ845EA">said it first</a>). No one knows better than you whether to write A or B, what’s the right way to explain something, or whether or not your solution is actually correct. No one can tell you whether one way to explain something is better than another way. You’re going to spend an inordinate amount of time by yourself, at a cafe or at home, going back and forth on different ways to do something, wincingly playing out in your mind the reactions from the community (“This is the worst idea ever!”; Or, “this is ground-breaking stuff!”). Explore different ways to do a thing and run it by as many people as you can; then, pick an option – no one else can do that for you.</p>

<hr />

<p>If you’re just starting to write your technical book, or have been thinking about taking the leap, I hope this list helps you. Am I missing anything? <a href="mailto:boris@performancejs.com">Shoot me an email</a> with edits, additions, or insinuations.</p>]]></content><author><name></name></author><category term="Writing" /><summary type="html"><![CDATA[I spent the last year and a half writing my first technical book for O’Reilly (Programming TypeScript). I’d never written a technical book before. In fact, prior to the 300-page book, the longest thing I’d written was a 20-something-page paper in college.]]></summary></entry><entry><title type="html">On Derived State</title><link href="/javascript/typescript/react/2018/08/10/On-Derived-State.html" rel="alternate" type="text/html" title="On Derived State" /><published>2018-08-10T00:00:00+00:00</published><updated>2018-08-10T00:00:00+00:00</updated><id>/javascript/typescript/react/2018/08/10/On-Derived-State</id><content type="html" xml:base="/javascript/typescript/react/2018/08/10/On-Derived-State.html"><![CDATA[<p>Derived state for frontend applications comes up a lot. State <code class="language-plaintext highlighter-rouge">B</code> depends on State <code class="language-plaintext highlighter-rouge">A</code>, so after you update <code class="language-plaintext highlighter-rouge">A</code>, by the time you read <code class="language-plaintext highlighter-rouge">B</code> you want it to be updated based on the latest value of <code class="language-plaintext highlighter-rouge">A</code>. There’s a bunch of ways to model this, involving different tradeoffs:</p>

<ul>
  <li>Do you treat derived data and non-derived data the same?</li>
  <li>Should users interact with the two the same way?</li>
  <li>Do you re-compute dependent data in a lazy or eager way?</li>
  <li>How much control do you need over re-computing derived data?</li>
</ul>

<p>A popular solution is selector libraries like <a href="https://github.com/reduxjs/reselect">Reselect</a>. The way they work is:</p>

<ol>
  <li><code class="language-plaintext highlighter-rouge">A</code> changes</li>
  <li>Define a function (“selector”) <code class="language-plaintext highlighter-rouge">S</code> that takes State <code class="language-plaintext highlighter-rouge">A</code> and returns State <code class="language-plaintext highlighter-rouge">B</code></li>
  <li>When you want to read <code class="language-plaintext highlighter-rouge">B</code>, you call <code class="language-plaintext highlighter-rouge">S</code> with <code class="language-plaintext highlighter-rouge">A</code></li>
</ol>

<p>To make this pattern work efficiently, <code class="language-plaintext highlighter-rouge">S</code> of course has to be memoized, and State <code class="language-plaintext highlighter-rouge">A</code> immutable for that memoization to work. This approach makes the following tradeoffs:</p>

<ul>
  <li>You treat derived and non-derived data fundamentally differently</li>
  <li>Users interact with the two differently</li>
  <li>You re-compute derived data in a lazy way</li>
  <li>You don’t have control over how derived data is re-computed</li>
</ul>

<p><strong><a href="http://undux.org/">Undux</a> makes a different set of choices when it comes to derived data.</strong></p>

<p>With Undux, you treat derived data the same as non-derived data, both from the store’s point of view and your user’s point of view. That’s because from your Component’s point of view, the two are the same. In fact, if your component (or its container) knows what’s derived and what isn’t, that might be a sign of poor encapsulation.</p>

<p>To derive data in Undux, you just compute it with an effect. Optionally, prefix its key with something:</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">store</span>
  <span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="dl">'</span><span class="s1">networkData</span><span class="dl">'</span><span class="p">)</span>
  <span class="p">.</span><span class="nx">pipe</span><span class="p">(</span><span class="nx">map</span><span class="p">(</span><span class="nx">postProcessData</span><span class="p">))</span>
  <span class="p">.</span><span class="nx">subscribe</span><span class="p">(</span><span class="nx">store</span><span class="p">.</span><span class="kd">set</span><span class="p">(</span><span class="dl">'</span><span class="s1">derived/processedNetworkData</span><span class="dl">'</span><span class="p">))</span>
</code></pre></div></div>

<p>This approach makes different tradeoffs than selector libraries do:</p>

<ul>
  <li>You treat derived and non-derived data the same</li>
  <li>Users interact with the two the same (less a namespace like <code class="language-plaintext highlighter-rouge">derived/</code>, if you want)</li>
  <li>You recompute data in an eager way by default, though you can make it lazy if you want</li>
  <li>You have fine control over how to re-compute derived data:</li>
</ul>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">store</span>
  <span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="dl">'</span><span class="s1">networkData</span><span class="dl">'</span><span class="p">)</span>
  <span class="p">.</span><span class="nx">pipe</span><span class="p">(</span>
    <span class="nx">debounceTime</span><span class="p">(</span><span class="mi">200</span><span class="p">),</span>
    <span class="nx">filter</span><span class="p">((</span><span class="nx">_</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="nx">_</span> <span class="o">!==</span> <span class="kc">null</span><span class="p">),</span>
    <span class="nx">map</span><span class="p">(</span><span class="nx">postProcessData</span><span class="p">)</span>
  <span class="p">)</span>
  <span class="p">.</span><span class="nx">subscribe</span><span class="p">(</span><span class="nx">store</span><span class="p">.</span><span class="kd">set</span><span class="p">(</span><span class="dl">'</span><span class="s1">derived/processedNetworkData</span><span class="dl">'</span><span class="p">))</span>
</code></pre></div></div>

<p>Why does Undux do it this way? Isn’t there something holy about a clean source of truth?</p>

<p>My view is there isn’t. Fundamentally, all data is derived. Even the list of users you got back from a GraphQL endpoint – that’s a function of two things:</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">users</span> <span class="o">=</span> <span class="nx">F</span><span class="p">(</span><span class="nx">initialState</span><span class="p">,</span> <span class="nx">API</span> <span class="nx">request</span><span class="p">)</span>
</code></pre></div></div>

<p>Or, a count of how many times you pressed a button. That’s derived from:</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">count</span> <span class="o">=</span> <span class="nx">F</span><span class="p">(</span><span class="nx">initialCount</span><span class="p">,</span> <span class="nx">Stream</span><span class="p">(</span><span class="nx">clicks</span><span class="p">))</span>
</code></pre></div></div>

<p>That is, users are derived from an initial state and a network request. And a click count is derived from an initial count and a stream of clicks.</p>

<p>Selector libraries draw a line between primary state – stuff like initial state, state from the network, state from user intreactions – and n-ary state that’s computed from that state. But isn’t all state (except intial state) computed when it comes down to it? Because JavaScript doesn’t have first-class monads, you don’t usually think of it like that. But you should.</p>

<p>And when you do, you realize it makes life easier to forget about drawing lines about where state comes from, and letting components interact with all state the same way. It’s a simpler mental model, it’s easier to reason about, it’s better enapsulation, and with Undux, is more powerful too.</p>

<p>What do you think?</p>]]></content><author><name></name></author><category term="JavaScript" /><category term="TypeScript" /><category term="React" /><summary type="html"><![CDATA[Derived state for frontend applications comes up a lot. State B depends on State A, so after you update A, by the time you read B you want it to be updated based on the latest value of A. There’s a bunch of ways to model this, involving different tradeoffs:]]></summary></entry></feed>