<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>mb21’s blog</title>
    <description>about society, philosophy, design, movies, tech, etc.</description>
    <link>/blog</link>
    <atom:link href="/blog/feed.xml" rel="self" type="application/rss+xml" />
    
      <item>
        <title>On Change and Craft in Software Design</title>
        <description>&lt;p&gt;Software seems to be that mathematical thing that can be perfected and finished. But somehow this never works in practice. Why not?&lt;/p&gt;
&lt;p&gt;We software developers keep struggling with that question. A lot of us instinctively want to write “beautiful” code and craft the “perfect” solution. Out in the real world, engineers may struggle with printers that jam, robot wheels that slip, machinery that gets worn down by use, or by harsh weather. Physical materials rot and decay, even when they’re just sitting there doing nothing – chemistry and time doing their thing. But in the virtual world, us software developers should be spared from these earthly troubles, right?&lt;/p&gt;
&lt;p&gt;To a certain extent, yes. Software in the abstract sense really does not change. It’s just information after all – like text or mathematic formula. Pythagoras’ theorem is still the same after two millennia after all. (Yes, the hardware carrying the bits and bytes may wane. But through the miracle of digital technology and error correcting codes, we can copy those bytes over to the next generation of carriers without any loss of information.)&lt;/p&gt;
&lt;h2 id=&quot;software-does-not-exist-in-isolation&quot;&gt;Software does not exist in isolation&lt;/h2&gt;
&lt;p&gt;But here’s the mistake I see a lot of us software developers make. We forget that no piece of software exists in isolation. While the software itself may be preserved unchanged, the world it’s interacting with &lt;em&gt;does&lt;/em&gt; change.&lt;/p&gt;
&lt;p&gt;Unless your software is a &lt;a href=&quot;/blog/2021/01/23/pure-functional-programming-and-shared-mutable-state.html&quot;&gt;pure function&lt;/a&gt;, it is doing IO, system calls, network calls, etc. If you want to run your program a decade later, the underlying OS still needs to behave the same, and any networked computers your program relies on need to still be there.&lt;/p&gt;
&lt;p&gt;And even if the technical environment remains compatible: your users change as well! An MS-DOS program might still be runnable in a VM, but users won’t like the UI anymore, especially on their smartphone.&lt;/p&gt;
&lt;h2 id=&quot;evolving-tech-ecosystems&quot;&gt;Evolving tech ecosystems&lt;/h2&gt;
&lt;p&gt;Different tech ecosystems have different rates of change. Microsoft is famous for their backwards-compatibility, going even so far as to &lt;a href=&quot;https://learn.microsoft.com/en-us/previous-versions/technet-magazine/ff625273(v=msdn.10)&quot;&gt;emulate old bugs&lt;/a&gt; in subsequent versions of Windows, so that old programs that relied on the previous behaviour would not break. Apple, in contrast, removes older APIs more aggressively, infuriating developers that need to change their apps if they want them to continue to run on the newest version of macOS or iOS, which is what most users will be running.&lt;/p&gt;
&lt;p&gt;Changes on one level of the tech stack sometimes enable more frequent changes on the levels above. Back when software was printed on physical media like CDs, major versions of OSes with new features were released once every couple of years. Today, Apple may still announce the new features at its yearly WWDC conference, but they’re actually rolled out in point updates over the course of the whole year. And for websites like Facebook or Google, it’s not uncommon for new versions to be deployed multiple times each day.&lt;/p&gt;
&lt;p&gt;Yet on the web, unless you were using Flash, your website from a decade ago still renders the same in modern browsers. However, “frontend” web developers have created an &lt;a href=&quot;https://news.ycombinator.com/item?id=43422162&quot;&gt;update-treadmill&lt;/a&gt; of their own: often relying on a baroque number of third-party dependencies, and building on top of frameworks that keep changing under their feet. While adopting newer and better technologies may make sense, the drive to work with the newest hip web framework often seems to be more similar to a fashion trend, or due to fear of being “left behind” in the job market (either as an employer or employee).&lt;/p&gt;
&lt;p&gt;When choosing the tech ecosystem on which you build your application, one crucial factor is its rate of change, and whether you like the direction of that change. Do you prefer a stable platform that doesn’t require you to invest a lot of time to keep up with it, or do you believe valuable new functionality continues to be added to the platform, and that you have the capacity to make use of that? Are the users I want to reach on the platform or moving away from it? Will there be developers familiar with the platform available for hire, and will they have the other skills I require?&lt;/p&gt;
&lt;h2 id=&quot;change-is-uncomfortable&quot;&gt;Change is uncomfortable&lt;/h2&gt;
&lt;p&gt;Make no mistake, change is uncomfortable. All else being equal, we humans prefer to stick what we know over taking a risk and investing time and energy in learning something new. Granted, us techies are generally more interested in new technologies. But it is a testament to how much beneficial technological progress we’ve been going through as a society, that so many of us are so often willing to take a bet on the next thing, assuming that it will bring us as much benefit as past innovations have done.&lt;/p&gt;
&lt;h2 id=&quot;innovation-waves&quot;&gt;Innovation waves&lt;/h2&gt;
&lt;p&gt;New technologies are &lt;a href=&quot;https://reactionwheel.net/2024/10/the-illusion-of-acceleration.html&quot;&gt;adopted in waves&lt;/a&gt;. If a new technology has a higher perceived advantage relative to its alternatives, it will be adopted more quickly. When a technology is new, it still changes quickly, as learnings come in and low-hanging fruits are picked. Later on, as the technology has matured and also more people and businesses rely on it, breaking changes become more expensive, and big improvements harder to achieve. The technology becomes entrenched. The cycle repeats and the next wave builds up when a new technology comes along that seems so much better, that it manages to overcome the &lt;a href=&quot;https://newsletter.squishy.computer/p/dont-fork-the-ecosystem&quot;&gt;ecosystem advantages&lt;/a&gt; of the existing technology.&lt;/p&gt;
&lt;h2 id=&quot;instigating-change&quot;&gt;Instigating change&lt;/h2&gt;
&lt;p&gt;As application developers, we are on the receiving end of change when it comes to the tech platform we build on. However, when it comes to the business we are building our product for, often we are the instigators of change. We want our customers to adopt our product, or the new version of our product. Suddenly, it’s us that need to walk the tight-rope between innovation and familiarity. It’s us that need to shepherd the ecosystem slowly forward, because “Being Too Early is The Same As Being Wrong”. And the path of innovation is always through the &lt;a href=&quot;https://newsletter.squishy.computer/p/evolution-adjacent-possible&quot;&gt;adjacent possible&lt;/a&gt;: each intermediate step needs to be advantageous, otherwise it’s not adopted.&lt;/p&gt;
&lt;h2 id=&quot;worthwhile-change&quot;&gt;Worthwhile change&lt;/h2&gt;
&lt;p&gt;You may long to build a product that lasts. This is easier in an established domain, since the broad strokes are clear and you can obsess over the details – you know the terrain that you want to find the maximum spot on. But if the domain is still moving and changing quickly, when you don’t know whether you hit a local maximum, because you don’t know the whole terrain yet, then you need to iterate on imperfect artifacts that evolve in symbiosis with the involved people and processes, so that the whole terrain can be discovered.&lt;/p&gt;
&lt;p&gt;In that case, even if your technology or product was used only for a small time and was quickly obsoleted by the next wave – it was still a necessary step. Even though your particular piece was superseded, your lasting contribution was to move the field forward as a whole.&lt;/p&gt;
&lt;p&gt;One example is in the field of aircraft design: the development of the Zero fighter, as portrayed in Miyazaki’s film &lt;em&gt;The Wind Rises&lt;/em&gt;, where its creator says he did “the best he could with the time that was given to him”.&lt;/p&gt;
&lt;h2 id=&quot;on-craft-and-deliberate-design&quot;&gt;On craft and deliberate design&lt;/h2&gt;
&lt;p&gt;But just because a product’s shelf-live may be limited, that does not mean it shouldn’t be designed properly, and crafted deliberately and with care. It seems to me, that’s a largely orthogonal quality.&lt;/p&gt;
&lt;p&gt;It’s true that some companies or teams move fast and carelessly (Facebook comes to mind). And established big corporations are famous for moving slow and carelessly: often they look at software development as a &lt;a href=&quot;/blog/2020/06/01/what-business-is-haskell-a-a-good-fit-for&quot;&gt;commodity to be de-risked&lt;/a&gt;, with managers not caring about the quality, as long as the widget is on schedule.&lt;/p&gt;
&lt;p&gt;On the other hand, companies like Apple or Nintendo demonstrate that even big companies can have a culture that deeply cares about design. In an established domain like laptops, Apple is iterating slow yet deliberately: the &lt;a href=&quot;https://arstechnica.com/apple/2025/03/apple-m4-macbook-air-review-i-have-no-notes/&quot;&gt;newest MacBook&lt;/a&gt; looks the same like the ones that have come before it, but each iteration is slightly tweaked with updated hardware.&lt;/p&gt;
&lt;p&gt;Finally, when entering a new domain, iterating quickly, the temptation may be strongest to cut corners. But you can still be deliberate in your design process, and decide carefully which corners to cut – which features you need now, and which can wait for a later iteration. That’s the definition of a minimum viable product, after all. The original iPhone may be one of the best known examples. When it launched, &lt;a href=&quot;https://arstechnica.com/gadgets/2007/07/iphone-review/&quot;&gt;reviewers complained&lt;/a&gt; about the basic camera and an Email client that missed enterprise features. It was also later revealed that on the first version, all programs were running in &lt;code&gt;sudo&lt;/code&gt; mode with elevated privileges – clearly a bad practice, but something Apple decided was okay to fix in a later software update, in order to focus on the features that made the iPhone unique, and get it out of the door in consumer’s hands now.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;carelessly&lt;/th&gt;
&lt;th&gt;deliberately&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;moving fast, iterating quickly&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Facebook&lt;/td&gt;
&lt;td&gt;iPhone at launch&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;iterating slow in a mature domain&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;most big corporations&lt;/td&gt;
&lt;td&gt;MacBook nowadays&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
</description>
        <pubDate>Sun, 13 Apr 2025 00:00:00 +0000</pubDate>
        <link>/blog/2025/04/13/on-change-and-craft-in-software-design.html</link>
        <guid isPermaLink="true">/blog/2025/04/13/on-change-and-craft-in-software-design.html</guid>
      </item>
    
      <item>
        <title>A MPA, no-bundler JavaScript meta-framework separating client- and server-code</title>
        <description>&lt;p&gt;Modern JavaScript meta-frameworks like Next.js, Nuxt, Astro, SolidStart, SvelteKit and Qwik all use a bundler/transpiler (like Vite or Webpack), and with the exception of Astro and Qwik, all of them are SPAs.&lt;/p&gt;
&lt;p&gt;I would love to have a modern JS meta-framework that does away with these two conventions, but instead chooses to optimize for simplicity and leveraging browser-built-ins over client-side JavaScript:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;MPA over SPA. See the &lt;a href=&quot;https://mb21.github.io/blog/2023/09/18/building-a-modern-website-ssg-vs-ssr-spa-vs-mpa-svelte-vs-solid.html#single-page-app-spa-vs-multi-page-app-mpa&quot;&gt;&lt;em&gt;Single-Page App (SPA) vs. Multi-Page App (MPA)&lt;/em&gt; section of my previous blog post&lt;/a&gt;, but the gist is that for most use-cases, modern browsers can do client-side routing better than JS. This would also allow a simpler solution to what the Solid folks call the &lt;a href=&quot;https://dev.to/this-is-learning/why-efficient-hydration-in-javascript-frameworks-is-so-challenging-1ca3&quot;&gt;double data problem&lt;/a&gt;: that the complete template and associated data often ends up being sent to the client twice, as initial HTML and as JavaScript (because you may need it in JavaScript format for hydration or on client-side page navigation).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;No bundler. Instead using browser-native &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/importmap&quot;&gt;Import maps&lt;/a&gt; and &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel/modulepreload&quot;&gt;modulepreload links&lt;/a&gt; (i.e. the same approach that &lt;a href=&quot;https://github.com/rails/importmap-rails&quot;&gt;importmap-rails&lt;/a&gt; took). A very simple asset pipeline would still do two things: add a hash to the filename to enable long caching in a CDN, and converting TypeScript and JSX to plain JavaScript (TS and JSX now being so engrained in the ecosystem that it’s built into both Deno and Bun).&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Why? I think that for most use-cases (i.e. if you’re not building the next Figma or Google Docs), this will provide both superiour UX and superior developer-experience.&lt;/p&gt;
&lt;p&gt;A bundler (and related tooling) is just such a massive addition in complexity that the developer needs to understand in order to debug certain issues. It seems to be a historical accident (because bundlers have their roots in tooling for client-side-only SPAs) that lots of functionality is implemented in bundlers instead of in plain JavaScript functions, which you would call either during static site generation or during server-side rendering: like how &lt;code&gt;import.meta.env&lt;/code&gt; is replaced in the build step and not accessing the env variable when you run the server, or how CSS or SVG files are included into a component. This makes it unnecessarily difficult to call the vite-based code, that you wrote to render some HTML on your webiste, &lt;a href=&quot;https://stackoverflow.com/questions/77523087/how-to-run-a-command-line-typescript-file-in-the-vite-js-environment&quot;&gt;in a script&lt;/a&gt; (e.g. in a cron job to send an email). Also, the newcomers to modern JS-tooling that Astro targets routinely struggle with what exactly the behaviour of &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; and &lt;a href=&quot;https://docs.astro.build/en/guides/client-side-scripts/#opting-out-of-processing&quot;&gt;&lt;code&gt;&amp;lt;script is:inline&amp;gt;&lt;/code&gt;&lt;/a&gt; is (in addition to forgetting to add &lt;a href=&quot;https://docs.astro.build/en/concepts/islands/#creating-an-island&quot;&gt;&lt;code&gt;client:load&lt;/code&gt; to hydrate islands&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Finally, with the exception of Astro, all the modern meta-frameworks ship with some kind of &lt;a href=&quot;https://en.wikipedia.org/wiki/Remote_procedure_call&quot;&gt;RPC&lt;/a&gt; functionality that doesn’t make the network request explicit, and without forcing the developer to handle network errors: &lt;code&gt;use server&lt;/code&gt; in &lt;a href=&quot;https://react.dev/reference/react/use-server&quot;&gt;React/Next.js&lt;/a&gt; and &lt;a href=&quot;https://start.solidjs.com/api/server&quot;&gt;SolidStart&lt;/a&gt;, as well as &lt;code&gt;server$&lt;/code&gt; &lt;a href=&quot;https://qwik.dev/docs/server$/&quot;&gt;in Qwik&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;And even in Astro, it’s very easy to accidentally bundle some big npm package, that you meant to use only on the server, into the client-side bundle. For example, this can happen if you just import a self-contained pure helper function into the client, and that function happens to be in the &lt;a href=&quot;https://github.com/withastro/astro/issues/9902&quot;&gt;same file that imports some server code&lt;/a&gt;. That’s why I’ve started even in Astro projects, to name my files &lt;code&gt;*.client.ts&lt;/code&gt; and &lt;code&gt;*.server.ts&lt;/code&gt;. I’d like the framework to enforce such a rule:&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Strict separation of client-side and server-side code. To make sure that server-code never accidentally ends up on the client.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The reverse, client-code running on the server, is sometimes needed (to server-side-render components), and is less problematic, since you will immediately notice if you try to access &lt;code&gt;window&lt;/code&gt; on the server, because it will just crash.&lt;/p&gt;
&lt;p&gt;With these three constraints set, I’m not sure what the best architecture would look like.&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;#fn1&quot; id=&quot;fnref1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;Do you know of any such framework and/or would be willing to collaborate on creating one? Feel free to open a &lt;a href=&quot;https://github.com/mb21/mastro/issues&quot;&gt;&lt;em&gt;mastro&lt;/em&gt; issue&lt;/a&gt;.&lt;/p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol&gt;
&lt;li id=&quot;fn1&quot;&gt;
&lt;p&gt;Explicit &lt;a href=&quot;https://www.patterns.dev/vanilla/islands-architecture/&quot;&gt;islands&lt;/a&gt;? But then you’re still sending the whole code of client-side components to the browser. We could do even better by just sending the interactive parts. &lt;a href=&quot;#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
        <pubDate>Sat, 13 Apr 2024 00:00:00 +0000</pubDate>
        <link>/blog/2024/04/13/mpa-no-bundler-javascript-meta-framework-separating-client-server-code.html</link>
        <guid isPermaLink="true">/blog/2024/04/13/mpa-no-bundler-javascript-meta-framework-separating-client-server-code.html</guid>
      </item>
    
      <item>
        <title>Declaratively rendering components: HTML vs JS functions</title>
        <description>&lt;p&gt;I’m a big fan of the idea of &lt;a href=&quot;https://en.wikipedia.org/wiki/Declarative_programming&quot;&gt;declarative programming&lt;/a&gt;. Examples are HTML and functional programming.&lt;/p&gt;
&lt;p&gt;But which of the following two approaches is more declarative when you’re rendering a bunch of components on your server, and your server happens to be running JavaScript?&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Relying primarily on HTML, or&lt;/li&gt;
&lt;li&gt;relying primarily on JavaScript functions.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Consider the syntax of declaring a component: an &lt;a href=&quot;https://docs.astro.build/en/basics/astro-components/&quot;&gt;Astro component&lt;/a&gt; is primarily an HTML snippet:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-astro&quot;&gt;---
const { title } = Astro.props;
---
&amp;lt;details&amp;gt;
  &amp;lt;summary&amp;gt;{title}&amp;lt;/summary&amp;gt;
  &amp;lt;slot /&amp;gt;
&amp;lt;/details&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Whereas a &lt;a href=&quot;https://www.solidjs.com/tutorial/introduction_components&quot;&gt;React/Solid/JSX component&lt;/a&gt; is a JavaScript function:&lt;/p&gt;
&lt;div class=&quot;language-jsx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Popover&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;props&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;details&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;summary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;props&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;summary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;props&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;children&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;details&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Notice how child elements are passed to the component: in Astro you have to use a slot, similar to &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/slot&quot;&gt;HTML’s slot element&lt;/a&gt;, somehow mimicking how a poly-fill for native web functionality would work. But we’re running on a server here and rendering HTML to a string that will be sent over the network. There is no DOM, and Web Components will never be implemented in Node/Deno/whatever. In React/Solid, child elements are simply passed as &lt;code&gt;props.children&lt;/code&gt; – just like any other component prop.&lt;/p&gt;
&lt;p&gt;I’m sympathetic to Astro’s argument of starting out with the least powerful tool in the toolkit, which is HTML, and later you might add some frontmatter containing JavaScript. It’s nice that non-developers can contribute and only need to write HTML.&lt;/p&gt;
&lt;p&gt;But even in Astro, you won’t get very far without having to learn some JavaScript. Just passing some props to a component requires you to do that already (for the line &lt;code&gt;const { title } = Astro.props&lt;/code&gt;). In templating languages like handlebars, partials all live in a global namespace, whereas in Astro you need to use JavaScript import statements to be able to include your component in another page. It feels like Astro components live in this weird middle-ground: they try to be usable without JavaScript knowledge, but fail to be so for the most basic cases.&lt;/p&gt;
&lt;p&gt;In both Astro templates and JSX, we’re using a template system that’s embedded in its host language; meaning you can use arbitrary JavaScript syntax within the template, like &lt;code&gt;.map&lt;/code&gt; and &lt;code&gt;condition ? exp1 : exp2&lt;/code&gt; instead of&lt;!--  --&gt;
&lt;code&gt;{{for}}&lt;/code&gt; and &lt;code&gt;{{if condition}} exp1 {{else}} exp2 {{end}}&lt;/code&gt;).&lt;/p&gt;
&lt;!--  --&gt;
&lt;p&gt;Considering that, the answer may very well be be that leaning on JavaScript as much as possible (i.e. approach 2), requiring the developer to learn fewer different concepts, is the better approach. After all, functions are just such great &lt;a href=&quot;/blog/2021/09/11/composable-abstractions.html&quot;&gt;abstractions&lt;/a&gt;, when used well. Meaning the React/Solid folks got it right. An argument I tried to make over &lt;a href=&quot;https://github.com/withastro/roadmap/discussions/716&quot;&gt;on the Astro discussion board&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Wanting to explore this thought here a bit more, I pushed some code to GitHub: &lt;a href=&quot;https://github.com/mb21/mastro/&quot;&gt;mastro – a &lt;em&gt;m&lt;/em&gt;inimal, no-dependencies take on an experimental &lt;em&gt;Astro&lt;/em&gt;-like web framework&lt;/a&gt;.&lt;/p&gt;
</description>
        <pubDate>Thu, 01 Feb 2024 00:00:00 +0000</pubDate>
        <link>/blog/2024/02/01/declaratively-rendering-components-html-vs-js-functions.html</link>
        <guid isPermaLink="true">/blog/2024/02/01/declaratively-rendering-components-html-vs-js-functions.html</guid>
      </item>
    
      <item>
        <title>The right mental model for Git</title>
        <description>&lt;p&gt;This post was prompted by &lt;a href=&quot;https://jvns.ca&quot;&gt;Julia Evans&lt;/a&gt; ruminations on Mastodon while she was working on a tutorial zine about the version control system &lt;a href=&quot;https://git-scm.com&quot;&gt;Git&lt;/a&gt;. In particular, I posted a rough version of this post in &lt;a href=&quot;https://hachyderm.io/@mb21/111569162158572506&quot;&gt;this thread&lt;/a&gt; but wanted to flesh it out here.&lt;/p&gt;
&lt;p&gt;While (almost) everyone agrees that the user-experience of Git&apos;s command-line interface is terrible (there are a lot of confusing names to memorize, and any one command does a lot of different things), people disagree on whether the underlying concepts of Git are intuitive or not. I happen to be one of those people that are perfectly happy thinking of a Git repository as a DAG (&lt;a href=&quot;https://en.wikipedia.org/wiki/Directed_acyclic_graph&quot;&gt;Directed Acyclic Graph&lt;/a&gt;) of commits.&lt;/p&gt;
&lt;p&gt;While I&apos;m not claiming this is 100% right, the following mental model of Git has served me very well:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;A &lt;strong&gt;commit&lt;/strong&gt; is identified by a &lt;a href=&quot;https://www.codecademy.com/resources/blog/what-is-hashing/&quot;&gt;hash&lt;/a&gt; (e.g. &lt;code&gt;84ecff443c07dd3c7e8a3b6cee5a0fd51dc7f891&lt;/code&gt;), which is computed from:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;a &lt;a href=&quot;https://en.wikipedia.org/wiki/Diff&quot;&gt;diff&lt;/a&gt; of all the changes,&lt;/li&gt;
&lt;li&gt;the commit message,&lt;/li&gt;
&lt;li&gt;a parent pointer (which is just the parent commit’s hash).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;By following a commit&apos;s parent pointers recursively and adding all the diffs from the beginning, a snapshot of your files at any point in the history can be reconstructed. (Implementation-wise these snapshots surely are cached, because otherwise things would be very slow, but that’s best seen as an implementation detail.)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A &lt;strong&gt;branch&lt;/strong&gt; (e.g. &lt;code&gt;main&lt;/code&gt;) is a named pointer to a commit. The pointer is often automatically moved along (e.g. when adding new commits to a branch).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A &lt;strong&gt;merge commit&lt;/strong&gt; has two parent pointers, which makes them a bit hard to work with.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;There are various git commands that are known under the term &lt;strong&gt;rewriting history&lt;/strong&gt; (e.g. &lt;code&gt;git rebase&lt;/code&gt;, &lt;code&gt;--amend&lt;/code&gt;, etc). However, these commands don&apos;t modify a commit (which is impossible, since that would change its hash). These commands actually create new commits from old ones, and then point the branch to the last new commit.&lt;/p&gt;
&lt;p&gt;The old commits are usually orphaned by that operation – meaning they’re not reachable by following the parent pointers of any branch. But you can still find orphaned commits via &lt;code&gt;git reflog&lt;/code&gt; – until they’re garbage collected.&lt;/p&gt;
&lt;p&gt;Rewriting history and then pushing the change to a remote branch (e.g. on GitHub) requires a force-push. You should only do that if you know what you’re doing, and should never do that if others already have started work based on that branch, as that would leave their local branch in an incompatible state with the remote branch (their parent pointers would point to commits that no longer exist).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A &lt;strong&gt;remote&lt;/strong&gt; (e.g &lt;code&gt;origin&lt;/code&gt;) is a shortname for a url (e.g &lt;code&gt;https://github.com/my-user/my-repo&lt;/code&gt;), with the url locating a remote repository (often on GitHub). &lt;code&gt;git fetch&lt;/code&gt; downloads commits from that url into a local branch (e.g. &lt;code&gt;origin/main&lt;/code&gt;), which can then be merged into a normal local branch (e.g. &lt;code&gt;main&lt;/code&gt;). &lt;code&gt;git pull&lt;/code&gt; does &lt;code&gt;git fetch&lt;/code&gt; followed by &lt;code&gt;git merge&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The bad news is that there are more Git concepts than just these (such as ssh keys, tags, stashing, merge strategies, etc). But keeping this mental model in mind should keep you mostly sane.&lt;/p&gt;
&lt;p&gt;While I had the (mis-)fortune to just bite the bullet and learn git on the commandline, I&apos;ve heard good things of &lt;a href=&quot;https://gitup.co&quot;&gt;GitUp&lt;/a&gt; (if you&apos;re a mac user) and &lt;a href=&quot;https://magit.vc&quot;&gt;Magit&lt;/a&gt; (if you&apos;re an emacs user). Finally, if you just want something simple and stupid, &lt;a href=&quot;https://desktop.github.com&quot;&gt;GitHub Desktop&lt;/a&gt; works fairly well (you might want to start with &lt;a href=&quot;https://www.youtube.com/watch?v=8Dd7KRpKeaE&quot;&gt;this 20min video&lt;/a&gt;).&lt;/p&gt;
</description>
        <pubDate>Wed, 13 Dec 2023 00:00:00 +0000</pubDate>
        <link>/blog/2023/12/13/right-mental-model-for-git.html</link>
        <guid isPermaLink="true">/blog/2023/12/13/right-mental-model-for-git.html</guid>
      </item>
    
      <item>
        <title>Building a Modern Website? SSG vs. SSR, SPA vs. MPA, Svelte vs. Solid</title>
        <description>&lt;p&gt;You wanna build a modern website? Okay. Assuming you have no baggage (like existing know-how with PHP, Ruby on Rails or similar), you most likely go with the one programming language that not only runs on servers, but also in the browser: JavaScript. Or more accurately, assuming you believe in statically-typed languages (discovering bugs already at compile-time, types as documentation, easier refactoring), you go with TypeScript.&lt;/p&gt;
&lt;p&gt;(If you won&apos;t ever need rich interactivity in the browser, or you&apos;re fine with learning two programming languages and stacks, you can of course also choose something else then JavaScript to run on your server, and use a bit of vanilla JavaScript or &lt;a href=&quot;https://htmx.org/&quot;&gt;HTMX&lt;/a&gt; to add some limited interactivity.)&lt;/p&gt;
&lt;h2 id=&quot;static-site-generation-ssg-vs-server-side-rendering-ssr&quot;&gt;Static-Site-Generation (SSG) vs Server-Side-Rendering (SSR)&lt;/h2&gt;
&lt;p&gt;If you have an ordinary website with less than a couple thousand pages, go with Static-Site-Generation (SSG). It&apos;s simple. You don&apos;t have to run a server: that means no server to harden against load spikes or attacks, it&apos;s basically free, and out-of-date dependencies aren&apos;t really a security issue. Put up a repository on GitHub and connect it with &lt;a href=&quot;https://www.netlify.com/&quot;&gt;Netlify&lt;/a&gt; or &lt;a href=&quot;https://vercel.com/&quot;&gt;Vercel&lt;/a&gt;. Whenever somebody edits or adds a new page (either by editing a markdown file on GitHub, through &lt;a href=&quot;https://decapcms.org/&quot;&gt;Decap CMS&lt;/a&gt;, or through a headless CMS), a new build is triggered, the whole website is regenerated and its static HTML, CSS (and perhaps JS) files are uploaded to some &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Glossary/CDN&quot;&gt;CDN&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Unless regeneration of the website is taking too long for you, there is rarely a reason to not stick with SSG.&lt;/strong&gt; (Except if you have other fancy requirements, like serving different HTML to different users and you cannot just customise that with some JavaScript on the client after page-load.)&lt;/p&gt;
&lt;p&gt;If you need your users to submit a form, or you need to add a few other dynamic features, you can always add a &amp;quot;serverless function&amp;quot; (fancy-speak for an AWS Lambda function) or an &amp;quot;edge function&amp;quot; (fancy-speak for a Cloudflare Worker or similar) and usually you&apos;ll be fine.&lt;/p&gt;
&lt;p&gt;But perhaps you have millions of pages, so the regeneration takes longer than a few minutes. Or perhaps even three minutes is too long for you, since you want to publish breaking news. Or perhaps your many authors update the content so often, or your developers update the code so often, that the couple of minutes of generation time are just too annoying to put up with every time.&lt;/p&gt;
&lt;p&gt;Then perhaps, it&apos;s time to consider Server-Side-Rendering (SSR). Each page is generated on-demand, only when the user requests it from the server. You can do that with &amp;quot;serverless functions&amp;quot; (although currently AWS Lambdas don&apos;t support HTTP streaming), or &amp;quot;edge functions&amp;quot; (although you&apos;ll have a long round-trip-time from the edge to the central database – if you have one – so you benefit little from running on the edge close to your users). Or you can go fully old-school and do what everyone did in the PHP and Ruby days: just run a server. Nowadays it&apos;s running somewhere in the cloud (on &lt;a href=&quot;https://render.com/&quot;&gt;render.com&lt;/a&gt;, &lt;a href=&quot;https://fly.io/&quot;&gt;fly.io&lt;/a&gt;, or just AWS or Azure) – and you can scale horizontally and add more servers once that&apos;s needed – but the principle is fundamentally the same. And it&apos;s still a great option.&lt;/p&gt;
&lt;h2 id=&quot;interlude-the-pendulum-of-technology&quot;&gt;Interlude: the pendulum of technology&lt;/h2&gt;
&lt;p&gt;If you&apos;ve been around building websites for a couple of decades, you may know that static-site generation is a terribly old hat. In the first days of the web, that was in fact the only way to build a website: you would just upload your static files via FTP to some server. And some folks, that were fed up with having to change the header and footer in &lt;em&gt;all&lt;/em&gt; their HTML files whenever it needed updating, they even cobbled together bash scripts to do static-site generation – even though it wasn&apos;t known under that name at that time. Of course, once servers gained the ability to run PHP, almost everyone switched to doing that (and thanks to WordPress and its ilk, a lot of websites are still server-side rendered with PHP). Until static generation came back again with static-site generators like &lt;a href=&quot;https://jekyllrb.com/&quot;&gt;Jekyll&lt;/a&gt;, which is still the default for &lt;a href=&quot;https://pages.github.com/&quot;&gt;GitHub Pages&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;And that&apos;s the way it is with a lot of technologies: the pendulum swings back and forth between two extremes as time goes by. Some of it is just fashion. Some of it is also driven by technological constraints at that moment. And these things influence each other: the more people think of a certain approach or technology as &amp;quot;hip&amp;quot; or &amp;quot;state of the art&amp;quot;, the more resources will go into improving that. Until other people start to think of it as a dead-end and will start working on a different approach, sometimes taking into accounts the lessons from the past, sometimes less so. And thus the pendulum starts to slow and eventually swing back.&lt;/p&gt;
&lt;p&gt;Another example is the pendulum swinging between where the majority of the work happens: on the client or on the server. For a time, you had mainframe servers that did the heavy lifting, with thin clients/terminals attached. Then came the personal computer, which shifted work back to the client (the desktop PC). Then came the World Wide Web, and later the cloud, and shifted work back to servers. Meanwhile, with the advent of lots of JavaScript/AJAX in websites and native apps in iPhones, the GUI shifted back to the client for a while, with the server relegated to just providing a JSON API to sync up the data.&lt;/p&gt;
&lt;h2 id=&quot;single-page-app-spa-vs-multi-page-app-mpa&quot;&gt;Single-Page App (SPA) vs. Multi-Page App (MPA)&lt;/h2&gt;
&lt;p&gt;For some time, in the early 2010s, people would go even so far as to not have the server render any HTML, but just serve a blank page with a bunch of JavaScript that would then render the GUI, and even take over the task of page navigation from the browser: the quintessential SPA. By 2020, people realized that serving a blank page gave users a slow initial page load, so the first page was server-side rendered in Next.js and similar frameworks. But on page navigation (when a user clicks a link), the whole code for the next page needed to be downloaded and run in the browser after all.&lt;/p&gt;
&lt;p&gt;This is not the case with React-Server-Components (RSC) and Next.js App Router anymore. There, server-components are rendered on the server and then the JSX is serialized and sent over the wire.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;But the definitional feature of a SPA remains: the browser loads only a single page, later page navigations are simulated with JavaScript.&lt;/strong&gt; That’s called a client-side router, and it has to reimplement browser features like loading indicators, scroll restoration on back navigation, which adds to the JavaScript bundle size, and never works quite the same. And it definitely doesn&apos;t work while the browser has already rendered the initial HTML, but the JavaScript hasn&apos;t executed yet.&lt;/p&gt;
&lt;p&gt;The idea of a SPA is that you’re trading upfront page load time with a better user experience later on. You don’t need to reinitialize everything after a page navigation. And arguably, SPAs have better page transitions than browsers used to have.&lt;/p&gt;
&lt;p&gt;But guess what; browsers have improved since and the &lt;a href=&quot;https://nolanlawson.com/2022/05/21/the-balance-has-shifted-away-from-spas/&quot;&gt;balance has started to shift away from SPAs again&lt;/a&gt;. Modern browsers have no flash of white between pages anymore, they have &lt;a href=&quot;https://web.dev/articles/bfcache&quot;&gt;back-forward caching&lt;/a&gt; and service workers for offline functionality, etc.&lt;/p&gt;
&lt;p&gt;There are still some use-cases that can only be realized in a SPA, like playing audio or video during page navigation, or otherwise keep state in the DOM (like cursor position) that cannot be easily persisted in localStorage. And if you need any of this, because you&apos;re building the next Figma, then absolutely, go with a SPA.&lt;/p&gt;
&lt;p&gt;But for most cases, I would just do a MPA, profit from the reduction in JavaScript bundle size, let the browser handle what is was built to do: page navigation, scroll restoration, page caching, streaming in HTML – and an HTTP GET that returns HTML is way easier to debug than RSC&apos;s stream of JSX. Finally, RSCs are currently only available in Next.js&apos;s App Router – which is production-ready in name only as of 2024. Meanwhile, &lt;a href=&quot;https://astro.build/&quot;&gt;Astro&lt;/a&gt; is a MPA-framework in version 3.0 today, that brings everything you’d expect from a modern framework: components, CSS modules, TypeScript, etc.&lt;/p&gt;
&lt;p&gt;(If you don&apos;t do a classical SPA, you don&apos;t have to build a dedicated REST or GraphQL backend which would need to be secured and maintained – just query the database directly in your server code. Especially when you&apos;re still small, and don&apos;t have separate backend and frontend teams, this is a huge time-saver.)&lt;/p&gt;
&lt;h2 id=&quot;svelte-vs-solid&quot;&gt;Svelte vs. Solid&lt;/h2&gt;
&lt;p&gt;At some point, there comes the time for your project to add some client-side interactivity that goes beyond what can be reasoned about in vanilla JavaScript; when you need to maintain some state and keep the GUI synced with it. In Astro, you can place &lt;a href=&quot;https://docs.astro.build/en/concepts/islands/&quot;&gt;islands&lt;/a&gt; of client-side interactivity in the server-side rendered page. Islands can be implemented in any of the popular client-side GUI frameworks like React, Preact, etc. And obviously only the islands&apos; JavaScript needs to be downloaded to the browser. To &lt;a href=&quot;https://docs.astro.build/en/core-concepts/sharing-state/&quot;&gt;share client-side state between the islands&lt;/a&gt;, you can use a library like Nano Stores or just use Solid signals.&lt;/p&gt;
&lt;p&gt;Now you need to choose a GUI framework. Let’s say you bring no baggage, like existing know-how in React (which still has the biggest market-share) or similar. Or you&apos;re looking to learn something new. You want it to be fast and small. I would argue then you only have to choose between &lt;a href=&quot;https://svelte.dev/&quot;&gt;Svelte&lt;/a&gt; and &lt;a href=&quot;https://www.solidjs.com/&quot;&gt;Solid&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;(And perhaps &lt;a href=&quot;https://qwik.builder.io/&quot;&gt;Qwik&lt;/a&gt;, which I haven&apos;t evaluated deeply. Definitely cool that they claim to be viable solution for both SPAs and MPAs. But if you&apos;ve decided to go for an MPA already, then I&apos;d trust Astro Island&apos;s explicit separation between client and server code a bit more than Qwik&apos;s approach where one developer&apos;s mishap might inadvertently pull in lots of code and even secrets into the client-bundle.)&lt;/p&gt;
&lt;p&gt;Both Svelte and Solid are truly reactive frameworks (unlike React), meaning when something changes, not the whole component is recomputed, but a dependency-graph is followed, to figure out what exactly needs to be updated.&lt;/p&gt;
&lt;p&gt;Solid&apos;s syntax is almost the same as React. You&apos;re just writing &lt;code&gt;const [count, setCount] = createSignal()&lt;/code&gt; instead of &lt;code&gt;const [count, setCount] = useState()&lt;/code&gt; (having separate getter and setters is called Read/Write Segregation and enforces unidirectional flow).&lt;/p&gt;
&lt;p&gt;Svelte uses a compiler for reactivity, adding some JavaScript to each component, whereas Solid ships a small runtime and reuses that in each component. Therefore, for small apps Svelte has smaller bundle size but for a bit larger apps, Solid quickly takes the lead.&lt;/p&gt;
&lt;p&gt;Svelte uses the bit weird &lt;code&gt;$&lt;/code&gt; label to mark up reactive regions, which the compiler then transforms, whereas in Solid the reactive system is just a library. It&apos;s just JavaScript all the way down – except for JSX, which is the only thing compiled in Solid (although there are a few transformations happening in the JSX that you have to get used to). Solid&apos;s approach also means that the reactivity graph is debuggable at runtime.&lt;/p&gt;
&lt;p&gt;An area where Svelte shines is great out-of-the-box support for animations, and it can support those better with component lifecycle hooks.&lt;/p&gt;
&lt;p&gt;Considering all the above, for most use-cases, I would personally choose Solid.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;So there you have it. Here&apos;s my advice: for the most common cases, build a statically-generated Astro MPA with some Solid islands. Feel free to disagree.&lt;/p&gt;
</description>
        <pubDate>Mon, 18 Sep 2023 00:00:00 +0000</pubDate>
        <link>/blog/2023/09/18/building-a-modern-website-ssg-vs-ssr-spa-vs-mpa-svelte-vs-solid.html</link>
        <guid isPermaLink="true">/blog/2023/09/18/building-a-modern-website-ssg-vs-ssr-spa-vs-mpa-svelte-vs-solid.html</guid>
      </item>
    
      <item>
        <title>An example of Algebraic Data Types in Swift, Kotlin, Rust and TypeScript</title>
        <description>&lt;p&gt;This post contains a simple example of using algebraic data types in Swift, Kotlin, Rust and TypeScript. The example is the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Define a product type &lt;code&gt;User&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Define a sum type &lt;code&gt;State&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Implement a pure function &lt;code&gt;render&lt;/code&gt; that pattern-matches on the sum type.&lt;/li&gt;
&lt;li&gt;Call &lt;code&gt;render&lt;/code&gt; with a state containing a user and print the resulting string.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;swift&quot;&gt;Swift&lt;/h2&gt;
&lt;p&gt;See also the nice blog post &lt;a href=&quot;https://medium.com/nerd-for-tech/algebraic-data-types-in-swift-2a777b24253d&quot;&gt;Algebraic Data Types in Swift&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;State&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;loading&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;loggedOut&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;loaded&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;State&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;state&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;loading&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;...&quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;loggedOut&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Please log in...&quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;loaded&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Logged in as &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;me@gmail.com&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;me&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;state&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;State&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;loaded&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nf&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h2 id=&quot;kotlin&quot;&gt;Kotlin&lt;/h2&gt;
&lt;div class=&quot;language-kotlin highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;data class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// by sealing the class, the compiler will know all subclasses&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// and can thus warn us about non-exhaustive pattern matches&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;sealed&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;State&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;object&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Loading&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;State&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;object&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;LoggedOut&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;State&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;data class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Loaded&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;User&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;State&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;State&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// still, exhaustiveness checking only works if the&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// `when` is used as an expression, like here&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;State&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Loading&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;...&quot;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;State&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;LoggedOut&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Please log in...&quot;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;State&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Loaded&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Logged in as ${state.user.name}&quot;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;me@gmail.com&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;me&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;state&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;State&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Loaded&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h2 id=&quot;rust&quot;&gt;Rust&lt;/h2&gt;
&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nd&quot;&gt;#[allow(dead_code)]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nd&quot;&gt;#[allow(dead_code)]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;State&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Loading&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;LoggedOut&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;Loaded&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;State&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;state&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nn&quot;&gt;State&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Loading&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;...&quot;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.to_string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
      &lt;span class=&quot;nn&quot;&gt;State&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LoggedOut&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Please log in...&quot;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.to_string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
      &lt;span class=&quot;nn&quot;&gt;State&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Loaded&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nd&quot;&gt;format!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Logged in as {}&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;.name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;email&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;me@gmail.com&quot;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.to_string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;me&quot;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.to_string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;state&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;State&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Loaded&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{}&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h2 id=&quot;typescript&quot;&gt;TypeScript&lt;/h2&gt;
&lt;div class=&quot;language-ts highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;State&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;loading&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;loggedOut&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;User&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// it&apos;s important to put a return type here,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// otherwise exhaustiveness checking will not work&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;render&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;State&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// js switch can only match on primitive types like strings&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// in this example, we can abuse default case to reach the User object&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;loading&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;loggedOut&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Please log in...&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;`Logged in as &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;state&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;me@gmail.com&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;me&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Or more explicitly (but slightly more verbose):&lt;/p&gt;
&lt;div class=&quot;language-ts highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;State&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;loading&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;loggedOut&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;render&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;State&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;loading&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;loggedOut&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Please log in...&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;`Logged in as &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;me@gmail.com&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;me&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;State&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</description>
        <pubDate>Sun, 10 Apr 2022 00:00:00 +0000</pubDate>
        <link>/blog/2022/04/10/example-of-algebraic-data-types-in-swift-kotlin-rust-typescript.html</link>
        <guid isPermaLink="true">/blog/2022/04/10/example-of-algebraic-data-types-in-swift-kotlin-rust-typescript.html</guid>
      </item>
    
      <item>
        <title>A Categorization of Programming Languages</title>
        <description>&lt;p&gt;There are many ways to categorize a given set of things. I find it useful to place today’s major general-purpose programming languages (and then some I added because I find them interesting) in three dimensions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;x-axis: type system – from weak dynamic typings, progressing to strong dynamic typing (which doesn’t make that much of a difference) on the left, to compile-time checked static typings like C and Java and finally much more expressive static &lt;a href=&quot;https://en.wikipedia.org/wiki/Type_system&quot;&gt;typings&lt;/a&gt; like &lt;a href=&quot;https://en.wikipedia.org/wiki/Hindley%E2%80%93Milner_type_system&quot;&gt;Hindley–Milner type systems&lt;/a&gt; on the right.&lt;/li&gt;
&lt;li&gt;y-axis: degree to which a language is conductive to writing code in a functional style – from not at all (imperative paradigm) at the bottom, to multi-paradigm languages in the middle and finally  &lt;a href=&quot;https://en.wikipedia.org/wiki/Purely_functional_programming&quot;&gt;purely functional&lt;/a&gt; languages at the top.&lt;/li&gt;
&lt;li&gt;color-code: of all the languages shown, only three have no runtime-overhead due to &lt;a href=&quot;https://en.wikipedia.org/wiki/Garbage_collection_(computer_science)&quot;&gt;garbage collection&lt;/a&gt;: C, C++ and Rust. (Swift is using &lt;a href=&quot;https://en.wikipedia.org/wiki/Automatic_Reference_Counting&quot;&gt;ARC&lt;/a&gt;, which is not strictly speaking garbage collection, but still comes with some runtime overhead.) The others either target a common runtime system (JVM, .NET, Erlang runtime), have their language-specific runtime (JavaScript or compile-to-JavaScript, Python, Ruby, PHP), or bundle the runtime with each binary (Go, Haskell).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/blog/assets/2021-09-18-categorization-of-programming-languages/categorization-of-programming-languages.svg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Of course, these are only what I find are the three major technical considerations. When picking a language for a specific project, there are also a lot of soft factors to consider, like community and ecosystem, experience of the team, etc.&lt;/p&gt;
</description>
        <pubDate>Sat, 18 Sep 2021 00:00:00 +0000</pubDate>
        <link>/blog/2021/09/18/categorization-of-programming-languages.html</link>
        <guid isPermaLink="true">/blog/2021/09/18/categorization-of-programming-languages.html</guid>
      </item>
    
      <item>
        <title>Composable Abstractions in Practice</title>
        <description>&lt;p&gt;This is the final part of a four-part series:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/blog/2021/01/23/functional-programming.html&quot;&gt;Part 1: What is functional programming?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/2021/01/23/pure-functional-programming-and-shared-mutable-state.html&quot;&gt;Part 2: Pure functional programming and shared mutable state&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/2021/01/23/pure-functional-programming-in-javascript.html&quot;&gt;Part 3: Pure functional programming in JavaScript&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Part 4: Composable abstractions in practice&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;All programming can be seen as coming up with &lt;a href=&quot;https://medium.com/javascript-scene/abstraction-composition-cb2849d5bdd6&quot;&gt;abstractions&lt;/a&gt; and using them to build even higher abstractions.&lt;/p&gt;
&lt;p&gt;This pyramid of abstractions can be seen on the system level (hardware &amp;gt; operating system &amp;gt; application), but also in the evolution of programming languages themselves. I&apos;ve picked four representative languages, each one at a higher level of abstraction than the previous one:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;x86 assembly: consistent interface to different CPUs with different microarchitectures&lt;/li&gt;
&lt;li&gt;C: eliminating manual register management and introducing loops in favour of jump/goto&lt;/li&gt;
&lt;li&gt;Java: garbage collector instead of manual memory management and eliminating goto completely&lt;/li&gt;
&lt;li&gt;Haskell: immutable data structures instead of stateful memory and map/recursion instead of loops&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Functional programming offers the insight that simple functions are great abstractions.&lt;/p&gt;
&lt;h2 id=&quot;what-is-abstraction&quot;&gt;What is abstraction&lt;/h2&gt;
&lt;p&gt;The process of abstraction is removing things (e.g. concrete implementations), so only the essential idea remains (exposed). The result of this process is also called an abstraction.&lt;/p&gt;
&lt;p&gt;A good abstraction hides complexity behind a simple interface.&lt;/p&gt;
&lt;p&gt;Sure, at some point every programming abstraction breaks down and the underlying implementation&apos;s characteristics &lt;a href=&quot;https://www.joelonsoftware.com/2002/11/11/the-law-of-leaky-abstractions/&quot;&gt;leak through&lt;/a&gt;. But if it&apos;s a good abstraction for what you&apos;re trying to do, this happens relatively rarely. And while it doesn&apos;t, the programmer&apos;s mind only must keep the simple interface in his or her head – e.g. when calling a pure function, you usually only need to care about its interface, not its implementation.&lt;/p&gt;
&lt;p&gt;If done right, the underlying abstractions don&apos;t (need to) change as often, so they can be carefully built and tested once. Higher-level code, which implements more specific things (e.g. business requirements), can then be easily changed more frequently.&lt;/p&gt;
&lt;h2 id=&quot;good-abstractions-compose-well&quot;&gt;Good abstractions compose well&lt;/h2&gt;
&lt;p&gt;Programming consists of decomposing your problem recursively into smaller and smaller sub-problems. As your experience as a programmer (or your projects&apos;s scope) grows, you&apos;ll see similar solutions pop up again and again to only slightly different problems. You can then tease out what these solutions have in common, extract that, and hide it behind a more general abstarction. By giving the abstraction a name, it can be reused again and again.&lt;/p&gt;
&lt;p&gt;It’s true that the more general an abstraction is, the more widely it can be reused. But the most general abstraction is no good if it isn&apos;t simple to use for a specific use-case. (It&apos;s easy to create a very general function by just having it take lots of arguments, but that&apos;s hardly hiding complexity behind a simple interface.) If a function hides a lot of complexity behind a simple interface, it does it’s job – even if it’s only used in one other place in the codebase. Yet too often, programmers try to come up with abstractions that are too general, and end up with something that’s not composable and not simple to use.&lt;/p&gt;
&lt;p&gt;Good abstractions compose well – like Lego bricks. Or like adding two integers alwyas yields an integer again (unlike pesky division).&lt;/p&gt;
&lt;p&gt;In order to facilitate building your solution up from sub-solutions, good abstractions expose consistent and composable interfaces – meaning that the abstractions that live at the same level in your sytem, should be easily composable to build the next higher level. Think of how neatly Lego bricks always fit together to build bigger structures. The crazy thing in programming is that you can build shipping containers using Legos – and then you can continue to do the same thing at the next level and stack whole shipping containers to build a house.&lt;/p&gt;
&lt;h2 id=&quot;functional-thinking-in-practice&quot;&gt;Functional thinking in practice&lt;/h2&gt;
&lt;p&gt;As explained very well in &lt;a href=&quot;https://www.manning.com/books/grokking-simplicity&quot;&gt;Eric Normand’s Grokking Simplicity&lt;/a&gt;, functional programmers divide all code in:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;data&lt;/li&gt;
&lt;li&gt;calculations (pure functions)&lt;/li&gt;
&lt;li&gt;actions (impure functions)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Data can be composed very easily (e.g. numbers can be added, strings and arrays can be concatenated, and maps can be merged). Pure functions are harder to compose than simple data, but not as hard as impure functions. Impure functions are more general than pure functions, but because you always have to worry about side-effects and order of execution, they are less composable.&lt;/p&gt;
&lt;p&gt;That’s why functional programmers prefer data over pure functions, and they prefer pure functions over impure functions.&lt;/p&gt;
&lt;h2 id=&quot;composable-abstractions-in-practice&quot;&gt;Composable abstractions in practice&lt;/h2&gt;
&lt;p&gt;If I had to come up with a list of the most important abstractions that functional programmers use in practice, it would be this list of simple yet extremely powerful abstractions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Data is modelled with &lt;a href=&quot;https://funprogramming.substack.com/p/algebraic-data-types&quot;&gt;algebraic data types&lt;/a&gt; (Ideally, the programming language supports pattern matching on those data types, meaning that the code branches (think &lt;code&gt;if/else&lt;/code&gt; or &lt;code&gt;switch&lt;/code&gt;) depending on the shape of the data that’s matched on.)&lt;/li&gt;
&lt;li&gt;Calculations are modelled using pure functions and actions are modelled using impure functions. If the behaviour of a function needs to be more configurable, often the best way to do so is to have it take another function as an argument. It’s then a &lt;a href=&quot;https://eloquentjavascript.net/05_higher_order.html&quot;&gt;higher-order function&lt;/a&gt;. (For this to work, functions need to be first-class citizens in your programming language.)&lt;/li&gt;
&lt;li&gt;A programming language’s syntax is an abstraction over assembly. Unfortunately, a lot of current programming languages have both expressions &lt;em&gt;and&lt;/em&gt; statements. While expressions can be endlessly nested, combined and composed to form bigger expressions, statements can only be combined sequentially using the semicolon. That’s why functional programmers favour expressions over statements.&lt;/li&gt;
&lt;li&gt;Generics are used to make both data (&lt;code&gt;Array&amp;lt;T&amp;gt;&lt;/code&gt;) and functions  (&lt;code&gt;identity: (a: T) =&amp;gt; T&lt;/code&gt;) polymorphic, providing an easy way to generalize a given abstraction if it works the same for different types anyway.&lt;/li&gt;
&lt;li&gt;Mathematical algebraic structures are a powerful way of thinking about, and generalizing over, a diverse set of structures we encounter routinely in programming. One of the most ubiquitous ones are &lt;a href=&quot;https://marmelab.com/blog/2018/04/18/functional-programming-2-monoid.html&quot;&gt;monoids&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Sat, 11 Sep 2021 00:00:00 +0000</pubDate>
        <link>/blog/2021/09/11/composable-abstractions.html</link>
        <guid isPermaLink="true">/blog/2021/09/11/composable-abstractions.html</guid>
      </item>
    
      <item>
        <title>Pure functional programming in JavaScript</title>
        <description>&lt;p&gt;This is the third part of a four-part series:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/blog/2021/01/23/functional-programming.html&quot;&gt;Part 1: What is functional programming?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/2021/01/23/pure-functional-programming-and-shared-mutable-state.html&quot;&gt;Part 2: Pure functional programming and shared mutable state&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Part 3: Pure functional programming in JavaScript&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/2021/09/11/composable-abstractions.html&quot;&gt;Part 4: Composable abstractions in practice&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;In the first part of this blog series, we looked at the functional programmimg style with some examples given in JavaScript. In the second part, we looked at pure functional programming and why shared mutable state is the root of all evil. In this third part we look at what pure functional programming can mean in JavaScript.&lt;/p&gt;
&lt;h3 id=&quot;reactjs&quot;&gt;React.js&lt;/h3&gt;
&lt;p&gt;By using React.js’s state handling functionality (&lt;code&gt;useState&lt;/code&gt;, &lt;code&gt;useReducer&lt;/code&gt;), you also mostly avoid shared mutable state. Every mutation of state is only applied on the next re-render, so for the duration of the current rendering cycle, there is no mutation of shared state. If you need side effects (to modify state outside React), you use &lt;code&gt;useEffect&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;do-pure-functions-exist-in-javascript&quot;&gt;Do pure functions exist in JavaScript?&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://hackernoon.com/do-pure-functions-exist-in-javascript-b128ed5f0ed2&quot;&gt;Arguably&lt;/a&gt;, in JavaScript there are no pure functions, since basic building blocks of the language can be tampered with between function calls. For example the &lt;code&gt;Array.map&lt;/code&gt; prototype can be polluted, making any function that uses &lt;code&gt;.map&lt;/code&gt; return something else than it did before the tampering.&lt;/p&gt;
&lt;p&gt;But as long as you have an agreement among all programmers working on the code to not do such crazy things, the notion of a pure function is still useful in JavaScript.&lt;/p&gt;
&lt;h3 id=&quot;mutable-reference-arguments&quot;&gt;Mutable reference arguments&lt;/h3&gt;
&lt;p&gt;Previously, we said that “a pure function’s return value is the same for the same arguments”. But we didn’t specify a definition of “same”.&lt;/p&gt;
&lt;p&gt;Object reference equality seems a bad definition (since e.g. &lt;code&gt;[] === []&lt;/code&gt; is &lt;code&gt;false&lt;/code&gt;), but using something like &lt;a href=&quot;https://lodash.com/docs/4.17.15#isEqual&quot;&gt;lodash’s &lt;code&gt;_.isEqual&lt;/code&gt;&lt;/a&gt; seems to be useful in practice (even if &lt;a href=&quot;https://stackoverflow.com/questions/65872468/is-this-javascript-function-taking-a-mutable-reference-argument-a-pure-functio&quot;&gt;not perfect&lt;/a&gt;). Now, in most programming languages it makes perfect sense that if a function takes a mutable references as an argument, it cannot be pure, since another thread might modify the data structure while our function is running. In JavaScript’s single-threaded environment however, as long as your function doesn’t use any asynchronous code, this actually cannot happen.&lt;/p&gt;
&lt;h3 id=&quot;immutability-in-practice&quot;&gt;Immutability in practice&lt;/h3&gt;
&lt;p&gt;JavaScript doesn’t ship with immutable data structures, but you might think of:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;libraries like Immutable.js that &lt;a href=&quot;https://github.com/immutable-js/immutable-js/issues/1689&quot;&gt;used to&lt;/a&gt; enjoy some popularity, but it&apos;s not the same thing as having support built right into the language, since it adds some overhead (both syntactical and in terms of dependencies).&lt;/li&gt;
&lt;li&gt;you can use &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze&quot;&gt;Object.freeze&lt;/a&gt;, but you have to remember to write that everywhere you create a new object and it’s shallow (the freeze doesn’t affect nested objects).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;However, you can write pure functions relatively easily by using the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax&quot;&gt;spread syntax&lt;/a&gt; to create a shallow copy of an object or array, instead of modifying the argument your function received. Modifying a deeply nested object may still be tempting, but would of course make your function impure.&lt;/p&gt;
&lt;h3 id=&quot;performance&quot;&gt;Performance&lt;/h3&gt;
&lt;p&gt;Because making lots of new objects can be expensive in JavaScript, in rare cases, you may also want to forgo purity simply due to performance reasons. (But beware of premature optimization!)&lt;/p&gt;
&lt;p&gt;These functions still don&apos;t do any I/O and they don&apos;t access non-local variables. But they may modify the objects given to them as arguments. It is then the caller&apos;s responsibility to take those modifications into account, or to not use the references to those objects anymore – which in the absence of Rust’s borrow checker, is of course a lot easier said than done and can be the cause of bugs.&lt;/p&gt;
</description>
        <pubDate>Sat, 23 Jan 2021 00:00:00 +0000</pubDate>
        <link>/blog/2021/01/23/pure-functional-programming-in-javascript.html</link>
        <guid isPermaLink="true">/blog/2021/01/23/pure-functional-programming-in-javascript.html</guid>
      </item>
    
      <item>
        <title>Pure functional programming and shared mutable state</title>
        <description>&lt;p&gt;This is the second part of a four-part series:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/blog/2021/01/23/functional-programming.html&quot;&gt;Part 1: What is functional programming?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Part 2: Pure functional programming and shared mutable state&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/2021/01/23/pure-functional-programming-in-javascript.html&quot;&gt;Part 3: Pure functional programming in JavaScript&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/2021/09/11/composable-abstractions.html&quot;&gt;Part 4: Composable abstractions in practice&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;In the previous post, I talked about four key concepts of functional programming.
Pure (or purely) functional programming adds a fifth one:&lt;/p&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Use pure functions wherever possible. And where interaction with shared mutable state is necessary, make it explicit.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;(In fact, in a purely functional programming language, there are only pure functions.)&lt;/p&gt;
&lt;p&gt;A &lt;strong&gt;pure function&lt;/strong&gt; has both of the following properties:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Its return value is the same for the same arguments&lt;br /&gt;
(no reading of shared mutable state)&lt;/li&gt;
&lt;li&gt;Its evaluation has no side effects&lt;br /&gt;
(no writing to shared mutable state)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Thus a pure function behaves like a mathematical function. This means you can replace the function call with its result without changing the behaviour of your program (this property is called &lt;a href=&quot;https://en.wikipedia.org/wiki/Referential_transparency&quot;&gt;referential transparency&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;A function has a &lt;strong&gt;side effect&lt;/strong&gt; if it modifies some state outside its local environment – i.e. calling the function has an observable effect (to the caller) besides returning a value.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shared mutable state&lt;/strong&gt; is a bit of a mouthful, so let’s break it down:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;state&lt;/em&gt; is some data that is persisted over time. (A stateful system remembers previous events or user interactions.)&lt;/li&gt;
&lt;li&gt;state is &lt;em&gt;mutable&lt;/em&gt; if it can be modified.&lt;/li&gt;
&lt;li&gt;state is &lt;em&gt;shared&lt;/em&gt; if multiple parties can access it concurrently. (e.g. multiple programs accessing the same file, or multiple parts of a program accessing the same memory location)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It should be clear now that the notions of “pure/impure functions”, “side effects” and “shared mutable state” are three aspects of the same concept.&lt;/p&gt;
&lt;h3 id=&quot;the-root-of-all-evil&quot;&gt;The root of all evil&lt;/h3&gt;
&lt;p&gt;Shared mutable state is believed by many to be the “root of all evil”, or at least the cause of most of the accidental complexity in our code. And “Complexity is &lt;em&gt;the&lt;/em&gt; root cause of the vast majority of problems with software today.” (from &lt;a href=&quot;http://curtclifton.net/papers/MoseleyMarks06a.pdf&quot;&gt;Out of the Tar Pit&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;Shared mutable state makes code unpredictable, hard to reason about and hard to test. It’s bad for the same reason global variables are bad. Data should be kept as local as possible and side effects should be avoided.&lt;/p&gt;
&lt;p&gt;Finally, if you add &lt;a href=&quot;https://en.wikipedia.org/wiki/Concurrent_computing&quot;&gt;concurrency&lt;/a&gt; to a program making use of shared mutable state, you easily get &lt;a href=&quot;https://en.wikipedia.org/wiki/Race_condition&quot;&gt;race conditions&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;two-kinds-of-shared-mutable-state&quot;&gt;Two kinds of shared mutable state&lt;/h3&gt;
&lt;p&gt;Shared mutable state can be divided into two categories, depending on where it is persisted:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;the world outside the program&lt;/li&gt;
&lt;li&gt;the program’s own memory&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Interacting with the outside world is generally called I/O (input/output) and includes writing to (or reading from) a file, a database, a network, etc. Most programmers are on some level aware that these things represent a form of external state (which is obviously shared and mutable), and the danger this entails. (For example cache invalidation is arguably just a special case of mutating shared state.)&lt;/p&gt;
&lt;p&gt;Relatively few programmers on the other hand appreciate the danger of different parts of your own program being able to modify the same memory location. Hearing it phrased like this, many will say that in most programming languages at least we don’t have pointers any more, and cannot access arbitrary memory locations by address like you can in C. But having references to shared memory locations (and being able to write to them), is only a slight improvement.&lt;/p&gt;
&lt;p&gt;Since any real program eventually needs to interact with the outside world, I/O cannot be avoided completely. But we can try to write as much as possible of our program in pure functions (especially the tricky parts like business logic that need to be tested and reasoned about), and clearly separate those from the parts of the program that does the necessary I/O.&lt;/p&gt;
&lt;p&gt;The following mitigation techniques exist to the two problems:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;code that does any kind of I/O is explicitly marked as such. (Using an IO monad or other effect system. This is somewhat similar to how the &lt;code&gt;async&lt;/code&gt; keyword works in JavaScript.)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;concurrent mutation of shared memory is prevented by either:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;using immutable data structures&lt;/li&gt;
&lt;li&gt;having mutable data structures that are not shared&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In purely functional programming, immutable data structures are used almost exclusively. The Rust programming language’s “borrow checker” is a notable implementation of option 2.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;p&gt;Continue reading &lt;a href=&quot;/blog/2021/01/23/pure-functional-programming-in-javascript.html&quot;&gt;the last part in this blog series&lt;/a&gt;.&lt;/p&gt;
</description>
        <pubDate>Sat, 23 Jan 2021 00:00:00 +0000</pubDate>
        <link>/blog/2021/01/23/pure-functional-programming-and-shared-mutable-state.html</link>
        <guid isPermaLink="true">/blog/2021/01/23/pure-functional-programming-and-shared-mutable-state.html</guid>
      </item>
    
  </channel>
</rss>
