<?xml version="1.0" encoding="UTF-8"?>
  <?xml-stylesheet href="/pretty-feed-v3.xsl" type="text/xsl"?>
  <rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
      <title>John’s internet house</title>
      <updated>Wed, 24 Jun 2026 00:00:00 GMT</updated>
      <description>My Blog</description>
      <language>en-us</language>
      <ttl>60</ttl>
      <author>
        <name>John Whiles</name>
        <uri>https://johnwhiles.com</uri>
      </author>
      <link rel="alternate" href="https://johnwhiles.com"/>
      <link rel="self" href="https://johnwhiles.com/atom.xml"/>
      <rights>All rights reserved</rights>
      <atom:link href="https://johnwhiles.com/atom.xml" rel="self" type="application/rss+xml" />
      
        <item>
          <title><![CDATA[Started including non-blog updates in the RSS feed]]></title>
          <content type="html"><![CDATA[So, now I can update my RSS readers about things other than blog posts. Blogs are dead IMO]]></content>
          <pubDate>Wed, 24 Jun 2026 00:00:00 GMT</pubDate>
          <link>https://johnwhiles.com/atom.xml</link>
          <guid isPermaLink="true">https://johnwhiles.com/atom.xml+2026-06-24</guid>
        </item>
        <item>
          <title><![CDATA[Created a site history page]]></title>
          <content type="html"><![CDATA[This is a new page that shows how the design of my homepage has evolved over time! It relies on a weekly job that takes screenshots of the website, so it should automatically update as time goes by.]]></content>
          <pubDate>Wed, 24 Jun 2026 00:00:00 GMT</pubDate>
          <link>https://johnwhiles.com/history</link>
          <guid isPermaLink="true">https://johnwhiles.com/history+2026-06-24</guid>
        </item>
        <item>
          <title><![CDATA[Why and how I rewrote these Obsidian plugins]]></title>
          <content type="html"><![CDATA[<h1>Why and how I rewrote these Obsidian plugins</h1>
<p>If you’re plugged into “The JavaScript World” then you’ve probably been hearing a lot about supply chain attacks recently. The NPM ecosystem has seen a self replicating worm spread by malicious post-install scripts - and in response a lot of people are becoming more worried about their dependency on... dependencies.</p>
<p>In an attempt to capitalise on this rare surge of interest in software security  the Obsidian team wrote an ill judged blog post about how they’re <a href="https://obsidian.md/blog/less-is-safer/">delivering a more secure product by having less dependencies</a>. In the post they explain how Obsidian is built to minimise third party dependencies and how by being particular, and not very timely, in how they update those dependencies they can further minimise supply chain attack risks. I think the main result of this blog post has been to draw people’s attention to some <a href="https://forum.obsidian.md/t/security-of-the-plugins/7544">long standing</a> concerns about their plugin system.</p>
<p><img loading='lazy' src=https://images.johnwhiles.com/1760962020730-IMG_6640.jpeg?w=800&fm=webp alt=A pile of stones /></p>
<h2>What is wrong with Obsidian’s plugin system?</h2>
<p>So, Obsidian lets you write “plugins” in JavaScript. These plugins get access to a bunch of Obsidian APIs so you can build weird new features into what is by default a fairly bare bones app. This is catnip for people who like to spend more time configuring their tools than doing things.</p>
<p>In order for these plugins to be sufficiently powerful, they need to be able to do anything that the Obsidian app itself can do. Which means, for most users, that plugins can read any file on a computer they run on, make requests to random web servers, delete things at random. They can more or less do anything. If you install a plugin made by a malicious developer they can easily slurp up any information in your Obsidian vault, and cause a lot of other damage.</p>
<p>Obsidian have tried to mitigate these risks by locking plugins behind a scary opt-in, requiring plugins to be reviewed and approved before they appear in their ‘marketplace’, and by requiring source code to be open. But once a plugin is approved, its author is able to push new versions at will - and because everyone now minifies and transpiles the code they write, the build code that gets installed can easily <em>not</em> match the published source code without anyone realising.</p>
<p>There are thousands of plugins in Obsidian’s marketplace, many of which are unmaintained, but still popular. It would be relatively easy for an attacker to take of an existing plugin, and then push malicious code to all the users of that plugin. We’ve seen this happen in like every other similar system, so chances are that it will at some point happen in Obsidian.</p>
<h2>Obsidian isn’t especially dangerous</h2>
<p>I want to stress that I don’t think Obsidian is doing anything unusually bad with their plugin systems. Many other applications have similar systems with the same risk profile. The CEO of Obsidian correctly <a href="https://www.reddit.com/r/ObsidianMD/comments/1nlyk5f/comment/nffzed8/?context=3">notes</a> that “This is not unique to Obsidian. VS Code (and Cursor) works the same way despite Microsoft being a multi-trillion dollar company.”</p>
<p>Obsidian is a different threat model for most users though, since it contains a lot of personal, potentially sensitive information. Whereas their Virtual Studio Code just contains company secrets. </p>
<h2>How I’ve tried to mitigate the risk from Obsidian’s plugins</h2>
<p>So, circuitously we approach the point. I like Obsidian, but am genuinely concerned about the risks in the plugin ecosystem. Unfortunately the amount of noise around software supply chain attacks has materially increased the risk that someone will successfully attack the ecosystem. The advent of AI tools has also made it easier to automate the process of finding ways to attack the ecosystem, and the amount of attention means that someone is certainly trying.</p>
<p>Therefore I’ve decided that I will not update any community plugins that I am currently using, I will only use new plugins if they are made by myself, or by the core Obsidian team and I will begin replacing the plugins that I do use with my own re-implementations.</p>
<p>Now I want to tell you about how it was easy, and also fun, to rewrite a bunch of plugins! Obsidian plugins are straightforward to build - but if you look at the source code of most popular plugins you will be overwhelmed. This is because widely used plugins need to consider lots of different use cases, and provide lots of options for their many users. A plugin might, for example, let people do things like select their prefered date format, or link format, or enable and disable features in a granular manner. Plugins also tend to bundle various tangentially related functionality together, and it’s common to install a plugin in order to use a tiny subset of its feature set. </p>
<p>So I’ve been rewriting the plugins that I’ve used in the most barebones way possible - avoiding dependencies other than build tools, and Obsidian itself.</p>
<h2>Here’s what I’ve done</h2>
<h3><a href="https://github.com/mirnovov/obsidian-homepage">Homepage</a> -&gt; <a href="https://github.com/Jwhiles/Johnsidian-Homepage">Johnpage</a></h3>
<p>I was using a plugin called Homepage, that lets you set a note as a “homepage”. You can then open that page with a keyboard shortcut, or when the app opens, or when you open a new tab or whatever. </p>
<p>The Homepage plugin also has a bunch of features that I frankly don’t understand and is hundreds of lines of code.</p>
<p>My version <em>only</em> lets you set a file as a homepage, and then bind a key to open it. Nothing else. Most of the code is to create an input box so you can select the file that should open.</p>
<h3><a href="https://github.com/argenos/nldates-obsidian">Nldates</a> -&gt; <a href="https://github.com/Jwhiles/Johnsidian-nat-lang-dates/tree/main">Johnldates</a></h3>
<p>Nldates is a nice plugin which lets you write <code>@today</code> or <code>@next friday</code> or whatever and have that get turned into a link into a daily note. It also has a bunch of weird other features that I have no interest in, like custom URI actions, and a date picker. It also pulls in <a href="https://www.npmjs.com/package/chrono-node/v/2.0.3">Chrono</a> to actually parse the dates which weighs in at a sweet 154kB when minified!</p>
<p>I just wanted to be able to write <code>@Today</code> or <code>@Saturday</code> or similar, and so I figured that I could replace the Chrono library with something simpler. Like a series of if statements.</p>
<p>I started by building a somewhat nightmarish regex that handled the subset of natural language dates that I actually cared about writing. It looked something like this</p>
<pre><code class="language-typescript">const regex = /(Today|Yesterday|Tomorrow)|(last|next)?\s?(Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday)/
</code></pre>
<p>It’s ugly, but worked perfectly for my particular use case. As I’m only building these plugins for myself that’s the only use case I need to think about.</p>
<p>However, after a few days I felt a bit unsatisfied with this approach. I realised that if I wanted to handle other sorts of input, then I’d need to <em>update a Regex</em>. So instead I decided to use a <a href="https://www.johnwhiles.com/posts/implementing-a-trie">Trie</a>. This was really fun, because I got to actually write and use a data structure for the first time since I last prepared for a job interview.</p>
<h3><a href="https://github.com/Vinzent03/obsidian-git">Obsidian Git</a> -&gt; a cronjob</h3>
<p>I was using this plugin to sync my vault into a git repo on a regular basis. I’m now doing roughly the same thing with a cronjob. It doesn’t work as well, and shows no feedback in the UI, but it’s okay.</p>
<h2>What’s left?</h2>
<p>I have one theme, and two community plugins that I didn’t write.</p>
<p>The theme is “Minimal” - made by the CEO of Obsidian. I Hopefully this one should remain safe. Ditto for “Minimal Theme Settings” - a plugin he made to let you toggle elements of that theme.</p>
<p>The final plugin is Style Settings - which I use to further customise the minimal theme. It was last updated a year ago. </p>
<p>So for now I plan to leave these plugins installed and never update them. Alternatively, I could probably remove them and then simply use the default UI. Which would be fine.</p>
<p>Oh and I’ll probably have to think about my neovim config. Since it’s susceptible to all the same threats as Obsidian. And then also think about every other program on my computer.</p>
<p>:(</p>
<p>Anyway. A lot of the time we assume that to do something on a computer, we need to rely on someone to do it for us. But it’s fun and empowering to make your own things.</p>
<h3>Further reading</h3>
<ul>
<li><a href="https://forum.obsidian.md/t/security-of-the-plugins/7544">Thread about plugin security from 2020</a></li>
<li><a href="https://www.emilebangma.com/Writings/Blog/An-open-letter-to-the-Obsidian-team">An open letter to the Obsidian team</a></li>
<li><a href="https://www.reddit.com/r/ObsidianMD/comments/1nlyk5f/comment/nffzed8/?context=3">CEO of Obsidian responds to plugin concerns</a></li>
</ul>
]]></content>
          <pubDate>Mon, 20 Oct 2025 11:39:16 GMT</pubDate>
          <link>https://johnwhiles.com/posts/obsidian-plugins</link>
          <guid isPermaLink="true">https://johnwhiles.com/posts/obsidian-plugins</guid>
        </item>
        <item>
          <title><![CDATA[AI slows down open source developers. Peter Naur can teach us why.]]></title>
          <content type="html"><![CDATA[<h1>AI slows down open source developers. Peter Naur can teach us why.</h1>
<p>Metr recently published <a href="https://metr.org/blog/2025-07-10-early-2025-ai-experienced-os-dev-study/">a paper</a> about the impact AI tools have on open-source developer productivity<sup id="marked-fnref:1"><a href="#marked-fn:1">1</a></sup>. They show that when open source developers working in codebases that they are deeply familiar with use AI tools to complete a task, then they take longer to complete that task compared to other tasks where they are barred from using AI tools. Interestingly the developers predict that AI will make them faster, and continue to believe that it did make them faster, even after completing the task slower than they otherwise would!</p>
<blockquote>
<p>When developers are allowed to use AI tools, they take 19% longer to complete issues—a significant slowdown that goes against developer beliefs and expert forecasts. This gap between perception and reality is striking: developers expected AI to speed them up by 24%, and even after experiencing the slowdown, they still believed AI had sped them up by 20%.
<cite href='https://metr.org/blog/2025-07-10-early-2025-ai-experienced-os-dev-study/'>Measuring the Impact of Early-2025 AI on Experienced Open-Source Developer Productivity</cite></p>
</blockquote>
<p>We can&#39;t generalise these results to all software developers. The developers in this study are a very particular sort of developer, working on very particular projects. They are experienced open source developers, working on their own projects. This study tells us that the current suite of AI tools appear to slow such developers down - but it doesn&#39;t mean that we can assume the same applies to other developers. For example, we might expect that for corporate drones working on a next.js apps that were mostly built by other people who&#39;ve long since left the company (me) see huge productivity improvements! </p>
<p>One thing we can also do, is theorise about why these particular open source developers were slowed down by tools that promise to speed them up.</p>
<p>I&#39;m going to focus in particular on why they were slowed down, not the gap between perceived and real performance. The inability of developers to tell if a tool sped them up or slowed them down is fascinating in itself, probably applies to many other forms of human endeavour, and explains things as varied as why so many people think that AI has made them 10 times more productive, why I continue to use Vim, why people drive in London etc. I just don&#39;t have any particular thoughts about why this gap arises beyond. I do have an opinion about why they are slowed down.</p>
<p><img loading='lazy' src=https://images.johnwhiles.com/1752480281950-wizar.png?w=800&fm=webp alt=two wizards examine the moon /></p>
<h2>So why are they slowed down</h2>
<p>A while ago <a href="https://johnwhiles.com/posts/programming-as-theory">I wrote, somewhat tangentially</a>, about an old paper by Peter Naur called <a href="https://pages.cs.wisc.edu/~remzi/Naur.pdf">programming as theory building</a>. That paper states </p>
<blockquote>
<p>programming properly should be regarded as an activity by which the programmers form or achieve a certain kind of insight, a theory, of the matters at hand</p>
</blockquote>
<p>That is to say that the real product when we write software is our mental model of the program we&#39;ve created. This model is what allowed us to build the software, and in future is what allows us to understand the system, diagnose problems within it, and work on it effectively. If you agree with this theory, which I do, then it explains things like why everyone hates legacy code, why small teams can outperform larger ones, why outsourcing generally goes badly, etc. </p>
<p>We know that the programmers in Metr&#39;s study are all people with extremely well developed mental models of the projects they work on. And we also know that the LLMs they used had no real access to those mental models. The developers could provide chunks of that mental model to their AI tools - but doing so is a slow and lossy process that will never truly capture the theory of the program that exists in their minds. By offloading their software development work to an LLM they hampered their unique ability to work on their codebases effectively.</p>
<p>Think of a time that you&#39;ve tried to delegate a simple task to someone else, say putting a baby to bed. You can write down what you think are unambiguous instructions - &quot;give the baby milk, put it to bed, if it cries <em>do not</em> respond&quot; but you will find that nine times out of ten, when you get home the person following those instructions will do the exact opposite of what you intended. Maybe they&#39;ll have gotten the crying baby out of bed and taken it on a walk to see some frogs.</p>
<p>The mental models with which we understand the world are incredibly rich, to the extent that even the simplest of them take an incredible amount of effort to transfer to another person. What&#39;s more that transfer can never be totally successful, and it&#39;s very hard to determine how successful the transfer has been, until we run into problems caused by a lack of shared understanding. These problems are what allow us to notice a mismatch, and mutually adapt our mental models to perform better in future. When you are limited to transferring a mental model through text, to an entity that will never challenge or ask clarifying questions, which can&#39;t really learn, and which cannot treat one statement as more important than any other - well the task becomes essentially impossible.</p>
<p>This is why AI coding tools, as they exist today, will generally slow someone down if they know what they are doing, and are working on a project that they understand.</p>
<h2>Should I ban LLMs at my workplace?</h2>
<p>Well, maybe not. In the previous paragraph I wrote that AI tools will slow down someone who &quot;knows what they are doing, and who is working on a project they understand&quot; - does this describe the average software developer in industry? I doubt it. Does it describe software developers in your workplace?</p>
<p>It&#39;s common for engineers to end up working on projects which they don&#39;t have an accurate mental model of. Projects built by people who have long since left the company for pastures new. It&#39;s equally common for developers to work in environments where little value is placed on understanding systems, but a lot of value is placed on quickly delivering changes that mostly work. In this context, I think that AI tools have more of an advantage. They can ingest the unfamiliar codebase faster than any human can, and can often generate changes that will essentially work. </p>
<p>So if we take this narrow and short termed view of productivity and say that it is simply time to produce business value - then yes I think that an LLM can make developers more productive. I can&#39;t prove it - not having any data - but I&#39;d love if someone did do this study. If there are no takers then I might try experimenting on myself.</p>
<p>But there is a problem with using AI tools in this context.</p>
<h2>What about building mental models</h2>
<p>Okay, so if you don&#39;t have a mental model of a program, then maybe an LLM could improve your productivity. However, we agreed earlier that the main purpose of writing software is to build a mental model. If we outsource our work to the LLM are we still able to effectively build the mental model? I doubt it<sup id="marked-fnref:2"><a href="#marked-fn:2">2</a></sup>.</p>
<p>So should you avoid using these tools? Maybe. If you expect to work on a project long term, want to truly understand it, and wish to be empowered to make changes effectively then I think you should just write some code yourself<sup id="marked-fnref:3"><a href="#marked-fn:3">3</a></sup>. If on the other hand you are just slopping out slop at the slop factory, then install cursor<sup id="marked-fnref:4"><a href="#marked-fn:4">4</a></sup> and crack on - yolo.</p>
<hr>
<p><sup id="marked-fn:1">1</sup> 
    It&#39;s a really fabulous study, and I strongly suggest reading at least the summary.</p>
<p><sup id="marked-fn:2">2</sup> 
    One of the commonly suggested uses of Claude Code et al is that you can use them to quickly onboard into new projects by asking questions about that project. Does that help us build a mental model. Maybe yes! Does generating code 10 times faster than a normal developer lead to a strong mental model of the system that is being created? Almost certainly not.</p>
<p><sup id="marked-fn:3">3</sup> 
    None of this is to say that there couldn’t be AI tools which meaningfully speed up developers with a mental model of their projects, or which help them build those mental models. But the current suite of tools that exist don’t seem to be heading in that direction. It’s possible that if models improve then we might get to a point that there’s no need for any human to ever hold a mental model of a software artifact. But we’re certainly not there yet.</p>
<p><sup id="marked-fn:4">4</sup> 
    Don&#39;t install cursor, it sucks. Use Claude Code like an adult.</p>
]]></content>
          <pubDate>Sat, 12 Jul 2025 13:48:58 GMT</pubDate>
          <link>https://johnwhiles.com/posts/mental-models-vs-ai-tools</link>
          <guid isPermaLink="true">https://johnwhiles.com/posts/mental-models-vs-ai-tools</guid>
        </item>
        <item>
          <title><![CDATA[This site is in the internet phonebook!]]></title>
          <content type="html"><![CDATA[<h1>This site is in the internet phonebook!</h1>
<p>A while ago I submitted this very website for inclusion in ”the internet phonebook”.
I’m pleased to say that it seems to have been included!</p>
<p><img loading='lazy' src=https://images.johnwhiles.com/1747334864371-Screenshot-2025-05-15-at-19.47.01.png?w=800&fm=webp alt=In the internet phonebook /></p>
<p>At some point I hope to get my hands on a copy and take a look at what else is in there!</p>
<h2>Other updates</h2>
<p>I wrote up some thoughts on why <a href="https://johnwhiles.com/cryptocurrency-dangers">you don’t want to own crypto</a>.
Previously I would have written this as a blog post - but I&#39;m feeling inclined to move this website away from being a blog and more towards being some sort of wild untamed Wiki with things in all sorts of weird places.
However I also want to keep providing my RSS feed. I’m thinking about how best to achieve that. The answer might include pulling all of my content back out of the sqlite database I made and deprecating my hand made CMS. hmm.</p>
]]></content>
          <pubDate>Thu, 15 May 2025 18:47:06 GMT</pubDate>
          <link>https://johnwhiles.com/posts/internet-phonebook</link>
          <guid isPermaLink="true">https://johnwhiles.com/posts/internet-phonebook</guid>
        </item>
        <item>
          <title><![CDATA[How can you save anything?]]></title>
          <content type="html"><![CDATA[<h1>How can you save anything?</h1>
<p><img loading='lazy' src=https://images.johnwhiles.com/1738699396580-dithered-image(1).png?w=800&fm=webp alt=dithered-image(1).png /></p>
<ul>
<li>Paper rots</li>
<li>Discs <a href="https://en.wikipedia.org/wiki/Disc_rot">also rot</a><sup id="marked-fnref:1"><a href="#marked-fn:1">1</a></sup></li>
<li>Magnetic tape dissolves, oxidizes, warps.</li>
<li>Dropbox, or any equivalent, can and will stop existing at any moment. Or else just delete your files by accident.</li>
</ul>
<p>Even if you have the perfect backup system, unless someone else understands it and cares as much as you do - well.  </p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/dziJoaj4RrI?si=LU6PrZWKF6f-uayP" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

<blockquote>
<p>Goodbye, secret files When I&#39;m gone, all this information will die </p>
</blockquote>
<h1>Lets learn from the past</h1>
<p>Some things we know because they are carved out of stone</p>
<p>Some things we know because they are built at monumental scale</p>
<p>Some things are saved by the vagaries of fate. Fossilized, drowned in a bog, or carbonized in just the right way to nerd snipe a generation.</p>
<p>Some things we think we remember from antiquity, but really they only ever existed for a small class of Americans in the 60s<sup id="marked-fnref:2"><a href="#marked-fn:2">2</a></sup></p>
<p>But what actually works consistently, and with intention? The most human method of preservation - which is replication.</p>
<p>Rhapsodes read the odyssey aloud, Peisistratos demands a written copy be created, Alexandrian scholars copied and annotated. Through countless purges, rebellions, wars, new copies were were created, secreted across borders.
Then the printing press created so many copies that posterity was guaranteed.</p>
<p>The Ise Grand Shrine is rebuilt every twenty years, ensuring that is in constant good repair, and that the knowledge of how to build such a structure is maintained. </p>
<p>The members of r/DataHoarder <a href="https://www.reddit.com/r/DataHoarder/comments/1ig524b/comment/malvgt6/?utm_source=share&utm_medium=web3x&utm_name=web3xcss&utm_term=1&utm_content=share_button">download US government data</a> on pricing and climate, distributing it amongst hundreds of peers via bit-torrent - because they believe that truth should be preserved.</p>
<h1>Elsewhere</h1>
<p><a href="https://modemworks.com/research/heirloom-hardware/">Heirloom Hardware</a></p>
<hr>
<p><sup id="marked-fn:1">1</sup> M-discs claim to last for up to 1000 years when stored in an ideal environment. Hard to test this though. And you better hope whatever format you store your data in is still supported</p>
<p><sup id="marked-fn:2">2</sup> This one goes out to all the trad spouses in the audience</p>
]]></content>
          <pubDate>Tue, 04 Feb 2025 19:34:40 GMT</pubDate>
          <link>https://johnwhiles.com/posts/how-can-you-save-anything</link>
          <guid isPermaLink="true">https://johnwhiles.com/posts/how-can-you-save-anything</guid>
        </item>
        <item>
          <title><![CDATA[Quote Bag January 2024]]></title>
          <content type="html"><![CDATA[<h1>Quote Bag January 2024</h1>
<p><em>This is episode one of what may or may not be a regular feature. QUOTE BAG. Photos taken by me</em></p>
<blockquote>
<p>My father defended a lot of murderers — his favorite clients, because he said they had generally got rid of the one person on earth who was really bugging them, and a kind of peace had descended over them</p>
</blockquote>
<p>Source: <a href="https://www.google.com/url?sa=t&source=web&rct=j&opi=89978449&url=https://www.nytimes.com/2021/03/02/books/review/lolita-obscenity-cancel-culture-emily-mortimer.html%23:~:text%3DMy%2520father%2520defended%2520a%2520lot,his%2520other%2520specialty%2520was%2520obscenity.&ved=2ahUKEwjHw4CO46CLAxUWUEEAHb9nGxAQFnoECB8QAw&usg=AOvVaw1lbnUdGDlsyTa_uZhlk6-9">How ‘Lolita’ Escaped Obscenity Laws and Cancel Culture</a></p>
<blockquote>
<p>You’re reading this right now. You’re here reading this because you either found me on substack or on twitter. You’re addicted to your phone—but, much more than for most people, your phone addiction consists largely of reading text.</p>
</blockquote>
<p>Source: <a href="https://www.sympatheticopposition.com/p/read-more-with-minimal-discipline">Read More With Minimal Discipline</a> by sympathetic opposition</p>
<p><img loading='lazy' src=https://images.johnwhiles.com/1738354922616-IMG_2155.jpg?w=800&fm=webp alt=IMG_2155.jpg /></p>
<blockquote>
<p>wherever you walk, seek out changes in elevation. The paths that follow the contours of the land, or confront them head-on, are almost always more rewarding to walk than those on flat ground. Keep a topographic map handy as you navigate.</p>
</blockquote>
<p>Source: <a href="https://www.samholden.jp/p/hints-from-japans-hillsides?publication_id=363357&utm_campaign=email-post-title&r=3s5t8&utm_medium=email">Hints from Japan&#39;s hillsides</a> by Sam Holden</p>
<blockquote>
<p>The secret is that there is no secret; Singapore simply tries. It applies Western methods of government with a genuine focus on competence and results i.e. meritocracy... An important additional question after meritocracy is that of commerce. Singaporeans really believe in it:</p>
</blockquote>
<p>Source: <a href="https://justifications.substack.com/p/notes-on-singapore?utm_medium=email">Notes on Singapore</a> by Fergus McCullough</p>
<p><img loading='lazy' src=https://images.johnwhiles.com/1738354941235-IMG_2125.jpg?w=800&fm=webp alt=IMG_2125.jpg /></p>
<blockquote>
<p>Starting on January 19, 2025 Facebook&#39;s internal policy makers decided that Linux is malware and labelled groups associated with Linux as being &quot;cybersecurity threats&quot;. Any posts mentioning DistroWatch and multiple groups associated with Linux and Linux discussions have either been shut down or had many of their posts removed.  </p>
</blockquote>
<p>Source: <a href="https://distrowatch.com/weekly.php?issue=20250127#sitenews">DistroWatch</a> by DistroWatch</p>
<blockquote>
<p>I think if you wanted to turn someone into a socialist you could do it in about an hour by taking them for a spin around the paddock of a Formula 1 race. No need for corny art singing tribute to the worker or even for the Manifesto. Never before had I seen so many wealthy people gathered all in one place. If a tornado came through and wiped the whole thing out, the stock market would plummet and the net worth of a country the size of Slovenia would vanish from the ledgers in a day.</p>
</blockquote>
<p>Source: <a href="https://web.archive.org/web/20240301170542/https://www.roadandtrack.com/car-culture/a46975496/behind-f1-velvet-curtain/">Behind F1&#39;s Velvet Curtain</a> by Kate Wagner</p>
<p><img loading='lazy' src=https://images.johnwhiles.com/1738355047756-IMG_2161.jpg?w=800&fm=webp alt=IMG_2161.jpg /></p>
<blockquote>
<p>How can you be someone with a project, with ambitions, with taste and aspirations…and not make yourself wildly, neurotically unhappy?</p>
</blockquote>
<p>Source: <a href="https://www.personalcanon.com/p/the-divine-discontent?utm_source=post-email-title&publication_id=2160572&post_id=150631038&utm_campaign=email-post-title&isFreemail=true&r=3s5t8&triedRedirect=true">The divine discontent</a> by Celine Nguyen</p>
]]></content>
          <pubDate>Fri, 31 Jan 2025 20:17:46 GMT</pubDate>
          <link>https://johnwhiles.com/posts/quote-bag-january-2024</link>
          <guid isPermaLink="true">https://johnwhiles.com/posts/quote-bag-january-2024</guid>
        </item>
        <item>
          <title><![CDATA[I can’t believe how bad the Substack UX is]]></title>
          <content type="html"><![CDATA[<h1>I can’t believe how bad the Substack UX is</h1>
<p>Here’s a screenshot of an article on Substack:
<img loading='lazy' src=https://images.johnwhiles.com/1736760565844-Screenshot-2025-01-13-at-09.28.31.png?w=800&fm=webp alt=Substack /></p>
<p>At the time that I took this screenshot I had spent ~10-seconds trying to click on the link to Wikipedia.
It wasn’t working. Was my trackpad out of battery? No. Was my browser frozen? No. Had the NSA hackers finally taken control of my laptop? No (I think).</p>
<p>I gave up on clicking the link, and continued reading. I then scrolled down a few more pixels and this appeared:</p>
<p><img loading='lazy' src=https://images.johnwhiles.com/1736760783734-Screenshot-2025-01-13-at-09.32.53.png?w=800&fm=webp alt=Screenshot 2025-01-13 at 09.32.53.png /></p>
<p>It’s a fucking modal. And of course, because a modal is on the screen we need to make all the other elements on the page uninteractable.
If you look very closely at the previous screenshot you can see it appearing it at the bottom of the screen. Of course you wouldn’t notice, because it’s the same colour as the background and it’s on the part of the screen you’re not looking at.</p>
<p>It’s 2025 now. We all know that modals suck. Modals that slowly scroll onto the screen and block your view of what you’re trying to read, and prevent you from clicking on links suck even more.</p>
<p>Time till Substack is viewed in the same light as medium.com - 175 days.</p>
]]></content>
          <pubDate>Mon, 13 Jan 2025 09:27:46 GMT</pubDate>
          <link>https://johnwhiles.com/posts/substack-ux</link>
          <guid isPermaLink="true">https://johnwhiles.com/posts/substack-ux</guid>
        </item>
        <item>
          <title><![CDATA[Adding data to a request object is totally an anti-pattern]]></title>
          <content type="html"><![CDATA[<h1>Adding data to a request object is totally an anti-pattern</h1>
<p><img loading='lazy' src=https://images.johnwhiles.com/1736192985880-dithered-image.png?w=800&fm=webp alt=dithered-image.png />
I&#39;m currently working on a Next.js project (for my sins). This project has a pretty extensive backend. Unfortunately, said backend is a nest of middleware and implicit argument passing. Pretty much all functionality has been implemented by means of saving things to a request object, and then reading them later.</p>
<p>This is, of course, completely incomprehensible, isn&#39;t type-checked, and breaks all the time because the scope of any change is unclear. I spend a lot of time trying to unpick existing work, to get into a position where a simple change can be made.</p>
<p>Here are my current key principles for writing maintainable software</p>
<ul>
<li>Don&#39;t use mutable global state for everything</li>
<li>Just write functions and pass arguments to them. You don’t need middleware, you don’t need a request object, you don’t need dependency injection, you don’t need complicated abstraction. Just write something that isn’t bad.</li>
</ul>
]]></content>
          <pubDate>Mon, 06 Jan 2025 16:46:33 GMT</pubDate>
          <link>https://johnwhiles.com/posts/request-object-bad</link>
          <guid isPermaLink="true">https://johnwhiles.com/posts/request-object-bad</guid>
        </item>
        <item>
          <title><![CDATA[Most browsers can natively lazy load images]]></title>
          <content type="html"><![CDATA[<h1>Most browsers can natively lazy load images</h1>
<p>I just learnt that most browsers natively support lazy loading images.
It’s remarkably easy to use this feature. 
You can simply add the attribute <code>loading=&#39;lazy&#39;</code> to your images, and then the browser will only load them when they come into view. Apparently this also works for iframes. Sick.</p>
<pre><code class="language-html">&lt;img loading=&#39;lazy&#39; src=&quot;images.johnwhiles.com/1735220926159-IMG_1040.jpeg&quot; alt=&quot;lazy&quot; /&gt;
</code></pre>
<h2>Time marches ever onwards. Browsers keep getting better.</h2>
<p>Since I started working as web developer in 2017, I’ve implemented at least two custom lazy loading image components.
If I had been asked to do the same again tomorrow I wouldn’t have thought to check whether this was now a <a href="https://caniuse.com/loading-lazy-attr">widely supported</a> browser feature.
If someone could send me a weekly summary of what new features are being added to web browsers I&#39;d really appreciate it! I’m currently waiting for <a href="https://caniuse.com/mdn-css_properties_grid-template-columns_masonry">masonry</a></p>
<p>Anyway here&#39;s a picture. If you have a really tiny screen it might have been lazy loaded!</p>
<p><img loading='lazy' src=https://images.johnwhiles.com/1735220926159-IMG_1040.jpeg?w=800&fm=webp alt=Not a good deal /></p>
]]></content>
          <pubDate>Thu, 26 Dec 2024 13:42:13 GMT</pubDate>
          <link>https://johnwhiles.com/posts/lazy-loading-in-html</link>
          <guid isPermaLink="true">https://johnwhiles.com/posts/lazy-loading-in-html</guid>
        </item>
        <item>
          <title><![CDATA[I’m making Claude write Anki cards for me]]></title>
          <content type="html"><![CDATA[<h1>I&#39;m making Claude write Anki cards for me</h1>
<p><img loading='lazy' src=https://images.johnwhiles.com/1734037788620-dfds.png?w=800&fm=webp alt=dfds.png />
This might be a terrible idea but I&#39;m now asking claude to write anki cards for me.</p>
<p>When I&#39;m trying to learn something I will write some semi-coherent notes and when I feel satisfied with my understanding I&#39;ll try to turn those notes into Anki cards. Well I plan to, but often I put it off repeatedly until the moment has passed and the cards never get created.  </p>
<p>Sometimes I will instead try and make the cards as I go - but this means making cards before really understanding a topic. Unfortunately for spaced repetition to work you actually need to learn the thing first. Testing yourself on an Anki card over and over can help you retain information - but if you never really understood the topic in the first place you won&#39;t have much luck. You also risk making a card that is fundamentally wrong, and not realising it before you&#39;ve embedded the information into your brain. This mistake has bitten me in the past - especially when I tried to learn German. I made cards without truly understanding something, assuming that because I would see them over and over again I would eventually understand them. But you don&#39;t learn things by doing space repetition - you just reinforce them!</p>
<p>So anyway, the card-making process is a bit painful. Do it too early and you get bad cards. Leave it too late and the moment is gone. I also suspect that the act of creating the cards is not actually a super important part of the process.<sup id="marked-fnref:1"><a href="#marked-fn:1">1</a></sup> </p>
<p>I&#39;m now testing giving Claude my notes, a list of key concepts that I want to retain and then asking it to write the Anki cards.</p>
<p>I&#39;m optimistic about this approach because instead of treating the Anki cards as the artifact that I&#39;m making, I&#39;ll be thinking about learning the thing and then outsourcing the creation of the Anki cards to a robot.</p>
<h2>Possible downsides of this approach</h2>
<ul>
<li>I might end up with too many cards and reviewing them will suck.</li>
<li>Claude doesn&#39;t automatically know how to write good flashcards. For example, I had to stress that I wanted the cards to feature clear success and failure conditions.<sup id="marked-fnref:2"><a href="#marked-fn:2">2</a></sup> It&#39;s probably doing some other stuff that is sub-optimal</li>
<li>I might fill my brain with hallucinated information.</li>
</ul>
<p>Bye!</p>
<p><sup id="marked-fn:1">1</sup> I&#39;m probably wrong.</p>
<p><sup id="marked-fn:2">2</sup> A prompt I&#39;ve tried: &quot;You, a brilliant and supportive tutor, are going to write Anki flashcards to help me retain information about the topic at hand. Each card should aim to test a single atomic concept. Please ensure that when reviewing cards it&#39;s not ambiguous whether I have the correct answer. In some cases you can make cards that test the same concept in both directions, for example you could create a card asking for the definition of a word, and then another card asking for that word given its definition.&quot;</p>
]]></content>
          <pubDate>Thu, 12 Dec 2024 20:50:22 GMT</pubDate>
          <link>https://johnwhiles.com/posts/claude-anki</link>
          <guid isPermaLink="true">https://johnwhiles.com/posts/claude-anki</guid>
        </item>
        <item>
          <title><![CDATA[(Don’t) Use Computer]]></title>
          <content type="html"><![CDATA[<h1>(Don&#39;t) Use Computer</h1>
<p>Anthropic has just released a new product called &quot;Use Computer&quot; which allows Claude to, erm, use a computer. They provide the Claude, you provide the computer.</p>
<p><img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/6d7A0GfC1Zu4KSlGZRpMzk/254f10d9ec5356ab60d272b4ef8de0c4/IMG_3305.jpeg?w=800&fm=webp alt=IMG 3305 /></p>
<p>With the existence of multimodal models, this was quite an obvious step - and I&#39;d be surprised if someone in the world of open source hadn&#39;t already rigged up something similar. If you just wanted a browser, you could probably wrangle something together with an API key and <a href="https://pptr.dev">puppeteer</a> - the innovation here is the interface that lets Claude interact with any element on your computer desktop. And the productisation.</p>
<p><em>Anyway</em> - the exciting thing about this release is that it allowed people to demonstrate how giving an LLM control over your computer is <a href="https://x.com/PalisadeAI/status/1849017294174802299">incredibly</a> <a href="https://embracethered.com/blog/posts/2024/claude-computer-use-c2-the-zombais-are-coming/">risky</a>. These demonstrations are almost redundant, as it&#39;s trivially obvious that such vulnerabilities exist and will be exploited. Anthropic knows this, and provides a lengthy disclaimer where they tell you just how dangerous this thing is:</p>
<blockquote>
<p>Computer use is a beta feature. Please be aware that computer use poses unique risks that are distinct from standard API features or chat interfaces. These risks are heightened when using computer use to interact with the internet... In some circumstances, Claude will follow commands found in content even if it conflicts with the user&#39;s instructions. For example, Claude instructions on webpages or contained in images may override instructions or cause Claude to make mistakes. We suggest taking precautions to isolate Claude from sensitive data and actions to avoid risks related to prompt injection.
Source: <a href="https://docs.anthropic.com/en/docs/build-with-claude/computer-use">Anthropic Docs</a> by Unknown</p>
</blockquote>
<p>I would go further and say that if you let Claude use your computer, you should assume that it&#39;s owned. Wipe and reset any passwords and credentials associated with it.<sup id="marked-fnref:1"><a href="#marked-fn:1">1</a></sup></p>
<h2>What&#39;s wrong with LLMs</h2>
<p>LLMs can&#39;t distinguish the operations they are tasked with from the data that they are operating on. Tellingly, some of the most commonly exploited vulnerabilities in traditional software have occurred when programmers have accidentally allowed the data a program operates on to be interpreted as instructions. Think of SQL injection attacks, or all the damage caused by people running JavaScript&#39;s eval on user input. Consider that when building an LLM system, you are always operating in this mode.</p>
<p>It&#39;s critical to remember that when you use an LLM to build systems that operate with the outside world or accept user input then you are in a very hazardous environment. The more capabilities you give the LLM, the more dangerous things become. Giving an LLM access to your own computer, and letting it browse the internet is pretty much the worst case scenario.</p>
<p>I really cannot state this firmly enough. You should never let an LLM drive a computer with any data you would prefer kept secret, or with access to anything even vaguely important. If you do, you will be compromised, lose data, be hacked and you will only have yourself to blame.</p>
<p><strong>Don&#39;t use Computer</strong><sup id="marked-fnref:2"><a href="#marked-fn:2">2</a></sup></p>
<hr>
<p><sup id="marked-fn:1">1</sup> Why owned? Well consider the following: Any content the LLM processes could contain hidden instructions. The LLM has access to everything the desktop session can access. It&#39;s nearly impossible to audit what the LLM might have accessed or modified. The attack surface is enormous - any website, document, or image could contain malicious prompts. It&#39;s almost impossible to tell if any given action taken by the LLM is malicious. Rendering an image, for example, is a <a href="https://ainoya.dev/posts/llm-application-security-practice-markdown-img-tag/">classic chat interface vulnerability</a>.</p>
<p><sup id="marked-fn:2">2</sup> unless it&#39;s in a locked down sandbox. Maybe a docker container with access to a browser? Maybe a VM running on a cloud? IDK.</p>
]]></content>
          <pubDate>Fri, 25 Oct 2024 20:13:00 GMT</pubDate>
          <link>https://johnwhiles.com/posts/dont-use-computer</link>
          <guid isPermaLink="true">https://johnwhiles.com/posts/dont-use-computer</guid>
        </item>
        <item>
          <title><![CDATA[Features I'd like to add to this website]]></title>
          <content type="html"><![CDATA[<h1>Features I&#39;d like to add to this website</h1>
<ul>
<li>A widget that suggests some other links to follow at the bottom of each page. I recently learnt that the most important thing someone reads on a website is the second article - since that is when they can become &#39;hooked&#39;. When you reach the bottom of one of my pages you get a confused mess of forms and no obvious way to find anything else on the website.</li>
<li>An audio livestream that is present on every page that plays live sounds from either my garden<sup id="marked-fnref:1"><a href="#marked-fn:1">1</a></sup> or some generative music I&#39;ve made.</li>
<li>Sending emails to commenters when I approve their comment or when someone responds to one of their comments. (This is actually almost done, and will be deployed soon)</li>
<li>A catalog of all the items of clothing I own and what I think of them.</li>
<li>Comments on every page! Not just on blog posts</li>
<li>A widget on the homepage (or sidebar) that surfaces the latest comments or webmentions posted by readers - inspired by the comments on gkbrk.com
<img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/5U5OhyljCTx1Xj5EyOvv0o/274ab6c06a6902dd2779c193a4ef72c6/Screenshot_2024-09-23_at_20.43.39.png?w=800&fm=webp alt=Comments /></li>
<li>A better way to stop spam comments. So far I&#39;ve tried manual approval of comments, and using Cloudflare&#39;s turnstile to prevent bots from posting comments. The first is too much effort, and the second appears to have an extremely high false positive rate. (The turnstile widget doesn&#39;t even get rendered with my ad blocker!)</li>
<li>Drag and drop image upload and processing pipeline for my <a href="https://johnwhiles.com/notes">personal micro twitter that no one looks at</a></li>
<li>Public read counts</li>
<li>Lots of weird deeply nested sub pages with one off styles and incomprehensible content.</li>
<li>An ARG built into the fabric of the website that no one except me realises is present.</li>
</ul>
<p><sup id="marked-fn:1">1</sup> This will require me to acquire a garden first.</p>
]]></content>
          <pubDate>Mon, 23 Sep 2024 19:40:00 GMT</pubDate>
          <link>https://johnwhiles.com/posts/feature-request</link>
          <guid isPermaLink="true">https://johnwhiles.com/posts/feature-request</guid>
        </item>
        <item>
          <title><![CDATA[John Recommends: B.P.R.D. Humble Bundle]]></title>
          <content type="html"><![CDATA[<h1>John Recommends: B.P.R.D. Humble Bundle</h1>
<p><img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/3bQx67gUCkZdinyElaI6eE/8ef9a3892080ea75c9af21b10e897d08/bprd_01.jpg?w=800&fm=webp alt=B.P.R.D. Frogs /></p>
<p>I&#39;ve recently been reading through the long-running comic series B.P.R.D. -  I&#39;ve been taking each volume out from Canada Water Library&#39;s extremely well-stocked comics section - but you can currently buy the entire series in PDF form from <a href="https://www.humblebundle.com/books/mike-mignolas-bprd-dark-horse-encore-books">Humble Bundle</a>. I&#39;m halfway through the series at the moment, and based on what I&#39;ve read I&#39;d recommend it highly!</p>
<p>(I would note that the first two volume are <em>not</em> good - you should just skip to the start of &#39;Plague of Frogs&#39;)</p>
<h2>What is B.P.R.D. and why is it worth reading?</h2>
<p>B.P.R.D. follows a government agency which is dedicated to protecting America from supernatural threats. The series follows a group of people who are not really up to the task that they&#39;ve been landed with. The series is truly apocalyptic, depicting a gradual falling apart of the protagonists as well as the fabric of the reality that they&#39;re trying to protect. In general things just get worse, trust gets eroded, and the world is slowly then rapidly destroyed.</p>
]]></content>
          <pubDate>Sun, 22 Sep 2024 10:07:00 GMT</pubDate>
          <link>https://johnwhiles.com/posts/bprd-bundle</link>
          <guid isPermaLink="true">https://johnwhiles.com/posts/bprd-bundle</guid>
        </item>
        <item>
          <title><![CDATA[My mum couldn't use WhatsApp because her font size is too large]]></title>
          <content type="html"><![CDATA[<h1>My mum couldn&#39;t use WhatsApp because her font size is too large</h1>
<p>My mum recently bought a new iPhone. She&#39;s very excited about it, mostly because it is a green colour.</p>
<p>I knew she had received it when I got the following message on iMessage:</p>
<p><img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/2pW1SWeejXXGFTtuSM8nn1/4d88bbe612379510af2c8e0bf03446a6/Screenshot_2024-06-26_at_10.05.21.png?w=800&fm=webp alt=message from mum /></p>
<p>I asked what exactly she meant when she said that WhatsApp didn&#39;t work. It turned out that she wasn&#39;t able to progress past this screen:</p>
<p><img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/3j2IG7SsHr9BDK6lHr4ulr/3678b0088bae3fa55450bef71b2fe6f4/whatsapp.jpg?w=800&fm=webp alt=Broken WhatsApp /></p>
<p>The UI is very messed up - and she couldn&#39;t press the next button because it was being overlapped by other elements. This meant that she couldn&#39;t enter her phone number to verify her account, and so could never use WhatsApp.</p>
<p>Now, I know that my mum has the font size on her phone set quite large. And having done web development, I am well aware that most products are never tested in anything but the most typical circumstances. It seemed quite possible that this UI just couldn&#39;t handle a different font size.</p>
<p>I suggested she reduce her font size temporarily and see if that fixed the issue. As soon as she did this, it worked perfectly and she was able to get into WhatsApp.</p>
<h2>Conclusion</h2>
<ul>
<li>It&#39;s disappointing that WhatsApp doesn&#39;t handle this case. There are a lot of people who change the font size on their phones for various good reasons. How many of them are going to be able to figure out that this is what&#39;s preventing them from using WhatsApp?</li>
<li>Developers will never test their work on anything but what they consider to be the most typical setups.</li>
<li>I thought Meta were supposed to be a highly optimised user acquisition engine? What happened?</li>
</ul>
]]></content>
          <pubDate>Wed, 26 Jun 2024 09:19:00 GMT</pubDate>
          <link>https://johnwhiles.com/posts/whatsapp-font-bug</link>
          <guid isPermaLink="true">https://johnwhiles.com/posts/whatsapp-font-bug</guid>
        </item>
        <item>
          <title><![CDATA[How to make Cloudflare properly cache a Remix site]]></title>
          <content type="html"><![CDATA[<h1>How to Make Cloudflare Properly Cache a Remix Site</h1>
<p>This website is built using Remix, deployed using Fly, and sits behind Cloudflare. Cloudflare provides DDoS protection and caches everything.</p>
<p>Or at least I thought it cached everything. I realised yesterday that once you had landed on the website and were navigating within it, none of the extra content you saw would be cached.</p>
<p><img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/21gmAM9yPFAS3WezIwTzxo/5215b3ea5be961c6af1e5081d18b0993/dithered-image.png?w=800&fm=webp alt=dithered-image /></p>
<p>For example, if you had landed on <code>/posts</code> - that route itself would be cached, but when you clicked onto one of the listed posts you would actually hit the server to get the data for that post, even if someone else had just viewed the same page! Disaster. I spotted this by looking at the network tab and seeing that the returned headers included the following:</p>
<pre><code>Cache-Control: public, max-age=300, s-maxage=3600
Cf-Cache-Status: DYNAMIC
</code></pre>
<p>We want to see a cache status of “HIT”; instead, we see the very ominous “DYNAMIC” - which can be translated as “not cached”.</p>
<h2>What Exactly Was Going Wrong?</h2>
<p>Why does this happen? It’s an unfortunate confluence of the way Remix works and the way Cloudflare works.</p>
<p>In Remix, when you first land on a page, your browser will make a request and receive a rendered HTML document, along with the necessary JavaScript and CSS files. Once you’re already on the site, if you click an internal link, your browser will instead just request any new JavaScript scripts required for that route, and the JSON data to render it - the HTML will be rendered locally. </p>
<p>So:</p>
<ul>
<li>if we navigate directly to <code>johnwhiles.com/posts/foo</code>, we get an HTML document.</li>
<li>If we navigate from <code>johnwhiles.com/posts</code> to <code>johnwhiles.com/posts/foo</code>, we instead request a blob of JSON.</li>
</ul>
<p>Remix lets you set the headers that will be sent along with these two possible responses seperately. In my case I was returning the same cache headers for both, but the blobs of JSON were not being cached by Cloudflare.</p>
<h2>Why Though?</h2>
<p>To understand why this happened, we need to understand a bit about how Cloudflare caches data. This is something I had neglected to do, assuming it would #JustWork.</p>
<p>Cloudflare first looks at the cache headers returned from your server. Because I returned <code>public, max-age=300, s-maxage=3600</code> from <a href="https://github.com/Jwhiles/johncom/blob/master/app/utils/headers.ts">most routes of this website</a>, I assumed Cloudflare would cache basically everything.</p>
<p>However, Cloudflare also uses their own heuristics to decide what to cache.  Even if you tell them to publicly cache a request, they may decide not to if they think the request is “dynamic”. By dynamic, they mean something that is likely to be different for each user. A request for JSON is assumed to be dynamic.</p>
<p>There have been a lot of cases where sensitive data has been revealed by improperly caching responses in public caches, so this is <em>probably</em> a sensible default for Cloudflare to have - even if it means fewer cache hits for all the people who don’t bother to learn how Cloudflare actually works.</p>
<h2>How to Fix It</h2>
<p>I found the answer to how to fix this at the bottom of a page called <a href="https://developers.cloudflare.com/cache/how-to/edge-browser-cache-ttl/create-page-rules/#cache-everything">Create Edge Cache TTL page rules</a> - essentially, we need to specifically tell Cloudflare if there are some routes, where we are happy to cache dynamic data.</p>
<p>I went to the dashboard and added a page rule like so:
<img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/6VeGoWWRWdSwa98wZLj4jJ/2dc0c3ed922c73b656524ccea4ea39fd/Screenshot_2024-02-03_at_08.13.12.png?w=800&fm=webp alt=Page Rule /></p>
<p>This page rule tells cloudflare that any route under my <code>/posts</code> can be cached. Instantly, I could see that JSON requests were indeed being cached. Hopefully, this means that my site will perform better and be cooler. Because the only private routes on my site are in the Top Secret Admin Zone (TSAZ), I am probably going to set a page rule which will cache everything <em>except</em> routes starting with /admin - but we’ll see.</p>
<h2>Warning</h2>
<p>You should be careful with this. You don’t want to accidentally cache private data! Because my site is almost entirely public, this is less risky. But remember, it’s better to have your CDN not cache things than to leak important user data.</p>
]]></content>
          <pubDate>Sat, 03 Feb 2024 07:29:00 GMT</pubDate>
          <link>https://johnwhiles.com/posts/cloudflare-remix-cache</link>
          <guid isPermaLink="true">https://johnwhiles.com/posts/cloudflare-remix-cache</guid>
        </item>
        <item>
          <title><![CDATA[Please add an RSS feed to your website]]></title>
          <content type="html"><![CDATA[<h1>Please Add an RSS Feed to Your Website</h1>
<p>When I&#39;m surfing the World Wide Web, and I find a nice website with interesting writing on it, I usually try to subscribe to it via RSS. But sometimes there is no RSS feed there, and that is very sad.</p>
<p><img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/4BZZQEKDiqjToRMjZKu5bf/5d510f41b9dd581991c9e1d88e90e5f4/Dither__1_.png?w=800&fm=webp alt=Dithered Wind Turbines /></p>
<p>I subscribe to a lot of RSS feeds, which is really nice. These feeds afford a constant deluge of interesting things that I could read, and in fact, more than I actually can read. I&#39;ve noticed that this has lessened my desire to check social media. I&#39;ve replaced an endless stream of &quot;content&quot; algorithmically optimised for engagement with an endless stream of &quot;content&quot; that isn&#39;t really optimised for anything at all. </p>
<p>This is becoming one of my main entrypoints into the internet, however this does mean that if I find a website that doesn&#39;t have an RSS feed I will probably forget that it exists and will never visit it again.</p>
<p>So please, if you don&#39;t have an RSS feed on your website, add one! They&#39;re really great. They&#39;re also relatively easy to make. You can see the implementation of this website’s RSS feed <a href="https://github.com/Jwhiles/johncom/blob/master/app/routes/%5Batom.xml%5D.tsx">here</a> - it&#39;s fairly straightforward and, in my RSS reader at least, it works :)</p>
<hr>
<p>By the way, I’m currently using the RSS reader app “Reeder”. It’s fine, but I feel like it could be better and more vibey. If you have any suggestions for other RSS readers please send them in to the usual address.</p>
]]></content>
          <pubDate>Fri, 02 Feb 2024 13:05:00 GMT</pubDate>
          <link>https://johnwhiles.com/posts/rss-feeds</link>
          <guid isPermaLink="true">https://johnwhiles.com/posts/rss-feeds</guid>
        </item>
        <item>
          <title><![CDATA[Johncom now supports webmentions]]></title>
          <content type="html"><![CDATA[<h1>Some New Features</h1>
<p>I&#39;ve just added a couple of new features to, let&#39;s say, celebrate the new year.</p>
<p><img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/5PP6rHta5qsUxZNNnqw8Xb/77a60ebe7ddc5624eea577684c146182/totoro.png?w=800&fm=webp alt=Totoro /></p>
<h2>Webmentions</h2>
<p>It&#39;s now possible to send webmentions to pages on this site. If you use a CMS that supports webmentions natively, it should pick up the link from the homepage automatically. If not, my blog posts will now contain another form which you can use to submit your webmentions.</p>
<p>Much like my comment system, nothing you post will see the light of the digital day without a nod of approval.</p>
<h2>Microblog</h2>
<p>I&#39;ve also added my own personal microblog platform—a one-person Twitter. This has two main purposes: It will allow me to easily send webmention replies, and it will let me post a pointless stream of consciousness stuff, but now on my own website.</p>
<h2>Todo</h2>
<p>I still need to automate the process of sending webmentions from my site. I also need to re-work the UI for adding comments and webmentions. Having both forms next to each other seems confusing and awkward.</p>
]]></content>
          <pubDate>Fri, 05 Jan 2024 12:04:00 GMT</pubDate>
          <link>https://johnwhiles.com/posts/webmentions</link>
          <guid isPermaLink="true">https://johnwhiles.com/posts/webmentions</guid>
        </item>
        <item>
          <title><![CDATA[The Loneliness of the Mid Level Vimmer]]></title>
          <content type="html"><![CDATA[<h1>The Loneliness of the Mid-Level Vimmer</h1>
<p>I use NeoVim. It&#39;s the professional programmer’s text editor of choice—excepting those people who write languages that weirdly only be written with a special, sometimes expensive, text editor.</p>
<p>Using NeoVim is cool because it&#39;s incredibly powerful and flexible. You can edit text much faster than in any other environment, you never have to touch a mouse, and if you&#39;re willing to learn LUA, you can program it to do pretty much anything you want. If you don&#39;t want to learn LUA, there&#39;s probably someone out there who&#39;s already made a plugin that does whatever you want anyway. Finally, using NeoVim makes you look cool.</p>
<p>But there is a downside to Vimming. It&#39;s a weird fringe interest, even amongst software developers who are already a weird fringe group. Most people who know what Vim is don&#39;t know how to use it, are scared of it, and are happy to keep it that way. People don’t want to engage with it on any level—see all the “jokes” about exiting vim—and a lot of this is because all the people who do use Vim are completely insufferable. Using Vim drives a wedge between you and everyone else you might work with.</p>
<p><img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/45NIqMAsvZ3iUG6EZf4xRi/c015ef888595f88ab7ac7348a4143310/Image_1280x720.jpg?w=800&fm=webp alt=Man running /></p>
<h2>Pair Woegramming</h2>
<p>Once you start using Vim, if you try and pair program with someone who isn&#39;t familiar with it, then they won&#39;t be able to take control of the keyboard and participate. And when you&#39;ve been Vimming for a while and have developed bizarre muscle memory, and hyper-abstract ways of navigating a codebase<sup id="marked-fnref:1"><a href="#marked-fn:1">1</a></sup>, it becomes difficult to work even with other people who use Vim. They’ll have their own ways of doing things, which won’t overlap with yours. The more interested you become in a topic, the tighter and less populated of a niche you sink into—until eventually, you are the only person in the world who can operate your text editor.</p>
<p>At the same time, when you sit down with someone who uses a normal text editor and try to work with them, you&#39;ll be utterly confused. Friction will be added where you don’t expect it. In VSCode, I feel a huge disconnect between how I expect to navigate a codebase and what is actually possible, and I spend half of my brainpower trying to prevent myself from hitting the capslock key after every line I type.</p>
<p>So by using Vim, I have, I think, increased my own productivity at the cost of alienating myself from everyone else. And while I&#39;d still encourage you to use Vim<sup id="marked-fnref:2"><a href="#marked-fn:2">2</a></sup>, this is a genuine problem that you will run into.</p>
<h2>What to do about it</h2>
<p>I have no idea. I used to think that everyone around me would see that NeoVim was “the right way,” and that they would gradually converge on using it. I hoped that I could go through life not changing my own behavior, and that the world would change to suit me. Unfortunately, this has not turned out to be true.</p>
<p>So I would like to be able to pair program with people effectively, but I want to keep using NeoVim. Maybe I need to set aside one day a week where I will only code using a very plain, boring, mouse-driven text editor. To keep my skills sharp.</p>
<hr>
<p><sup id="marked-fn:1">1</sup> I mostly don&#39;t look at a file tree view. I move around by hitting a shortcut, typing the first few letters of the file I want and then having it open. Or else I jump to definitions and references once again by hitting keyboard shortcuts. To someone who doesn&#39;t do these things, it looks like the open file is just changing at random while I tape. Baffling!</p>
<p><sup id="marked-fn:2">2</sup> If you do want to learn Vim, email me! Or maybe watch the <a href="https://frontendmasters.com/courses/vim-fundamentals/"><del>Primgean’s</del> <del>Primagean’s</del> Primeagen’s Vim course</a> - I haven’t watched it but it’s probably good.</p>
]]></content>
          <pubDate>Thu, 21 Dec 2023 14:21:00 GMT</pubDate>
          <link>https://johnwhiles.com/posts/vimming-pains</link>
          <guid isPermaLink="true">https://johnwhiles.com/posts/vimming-pains</guid>
        </item>
        <item>
          <title><![CDATA[The undisputed best songs of 2023]]></title>
          <content type="html"><![CDATA[<h1>The Undisputed Best Songs of 2023</h1>
<p>For years, I&#39;ve been meaning to join in the wild orgy of ‘Content’ that is end-of-year listicle writing - but I always end up thinking about it too much and not getting it done in time. This year I have something to promote, so here we are.</p>
<p>This is a list of my favorite songs of the year. They weren&#39;t necessarily published this year, because that would be boring. </p>
<p>Here is a Spotify playlist with them all if you just wanna click play and go </p>
<iframe style="border-radius:12px" src="https://open.spotify.com/embed/playlist/1Wpwsyu7kcnfgubVYSib94?utm_source=generator" width="100%" height="152" frameBorder="0" allowfullscreen="" allow="autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture" loading="lazy"></iframe>

<hr>
<h2>The List</h2>
<h3>My Maze - Abbey Blackwell</h3>
<iframe style="border: 0; width: 100%; height: 120px;" src="https://bandcamp.com/EmbeddedPlayer/album=2380158018/size=large/bgcol=333333/linkcol=ffffff/tracklist=false/artwork=small/track=2240392383/transparent=true/" seamless><a href="https://abbeyblackwell.bandcamp.com/album/my-maze">My Maze by Abbey Blackwell</a></iframe>

<p>Abbey Blackwell is the bassist of the greatest indie rock band in the world, Alvvays. I saw them perform this summer at Primavera Sound Porto. It had been raining all day, and as they got to the key change in “Belinda Says,” the sun broke through the clouds, and I started crying. Anyway, Abbey&#39;s non-Alvvays music is also very good. </p>
<p>Abbey writes that this song is “a love letter to my friends, a little smoke signal in the midst of separation and the interminable forward momentum of time.” </p>
<h3>Link Arms - Pile</h3>
<iframe style="border: 0; width: 100%; height: 120px;" src="https://bandcamp.com/EmbeddedPlayer/album=2243132167/size=large/bgcol=333333/linkcol=ffffff/tracklist=false/artwork=small/track=1606207184/transparent=true/" seamless><a href="https://pile.bandcamp.com/album/all-fiction">All Fiction by Pile</a></iframe>

<p>A lot of music I really love elicited a kind of disgust response when I first heard it. When I first heard this song, I thought that it sounded wrong and bad. I&#39;ve now learned that when I get that feeling, I should keep listening. Because the disgust is how you know it&#39;s an interesting song.</p>
<p>So this track sounds weirdly microtonal in places, the vocals are bitcrushed into nothingness. In general, large parts of the song sound like something went wrong in the studio and this is the remnant of something that was meant to sound normal. I like it.</p>
<h3>Slughole - Buried in the Snow (...My Mind) (Chopped and Screwed Remix)</h3>
<iframe style="border: 0; width: 100%; height: 120px;" src="https://bandcamp.com/EmbeddedPlayer/album=1570910474/size=large/bgcol=333333/linkcol=ffffff/tracklist=false/artwork=small/track=2355710329/transparent=true/" seamless><a href="https://johnwhiles.bandcamp.com/album/buried-in-the-snow-my-mind">Buried in the Snow (...My Mind) by Slughole</a></iframe>

<p>I’m biased in including this because I am part of Slughole. But oh well. 2023 is the year of shoegaze. I actually prefer this “remix” to the normal version of the song because it disguises the vocals a bit. No one likes to hear themselves sing.</p>
<h3>Crimson Enclosure - Winter</h3>
<iframe style="border: 0; width: 100%; height: 120px;" src="https://bandcamp.com/EmbeddedPlayer/album=4140540261/size=large/bgcol=ffffff/linkcol=333333/tracklist=false/artwork=small/track=3501697727/transparent=true/" seamless><a href="https://daydreamingwinter.bandcamp.com/album/what-kind-of-blue-are-you">What Kind of Blue Are You? by Winter</a></iframe>

<p>What happens in this song?</p>
<p>We start with the intro from Bowie&#39;s Station to Station, then the glide guitars start and we&#39;re immediately into the chorus. After the chorus, we get a key change (!!!) and the chorus again. Then the song ends.</p>
<p>What doesn&#39;t happen in this song?</p>
<ul>
<li>A boring verse</li>
<li>Any wasting of your time</li>
</ul>
<p>A perfect song - like Joyce Manor making of shoegaze. All the people who write five-minute songs where nothing happens should listen to this, and then regret their actions.</p>
<h3>Churchyard - Ex-Vöid</h3>
<iframe style="border: 0; width: 100%; height: 120px;" src="https://bandcamp.com/EmbeddedPlayer/album=2002767993/size=large/bgcol=333333/linkcol=ffffff/tracklist=false/artwork=small/track=473485934/transparent=true/" seamless><a href="https://ex-void.bandcamp.com/album/bigger-than-before">Bigger Than Before by Ex-Vöid</a></iframe>

<p>When I was at University, there was a student society called “Love to Make Noise.” It was largely run by <a href="https://www.selim-bulut.com/">Selim Bulut</a> and a guy who I only ever referred to as “Jevans” and whose real name I can&#39;t remember. They would hold some of the only interesting events that ever took place on our boring, isolated, campus.</p>
<p>Quite regularly they would invite bands featuring Owen Williams and their friends in various configurations, and under various names, to perform. Until at one of these events, someone from one of the bands brought their alcohol into the privately owned “Student‘s Union” where the events were hosted. This led to an altercation with one of the bouncers, and then to all of Love to Make Noise being banned from the Student&#39;s Union. </p>
<p>Anyway, Owen Williams is now in Ex-Vöid. Their album is really good. I could have picked any track from it. You should listen to the whole record. It&#39;s short, every song’s a banger.</p>
<p>I love the low harmonies on this song. They sound alien and artificial. Somehow “Formanty.” Great stuff.</p>
<h3>Pearl - Empty Country</h3>
<iframe style="border: 0; width: 100%; height: 120px;" src="https://bandcamp.com/EmbeddedPlayer/album=1593601823/size=large/bgcol=333333/linkcol=ffffff/license_id=3298/tracklist=false/artwork=small/track=3808178535/transparent=true/" seamless><a href="https://emptycountry.bandcamp.com/album/pearl">Pearl by Empty Country</a></iframe>

<p>Earlier I said that Alvvays is the world&#39;s best indie rock band. That wasn&#39;t actually true. It&#39;s Empty Country / Cymbals eat Guitars. I think this song is perfect, but I keep playing it to people, and no one seems to like it. </p>
<p>Empty Country should be huge, megastars. But according to Spotify, they have 10,573 monthly listeners a month after releasing their latest album. I will always keep listening, feeling like a member of a cult.</p>
<h3>Bein Friends&#39; - Catherine Warwick</h3>
<iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/YSshQu9rQLc?si=SrwGerfqjkc5YRyN" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>

<p>The video game Mother was released in 1989. Its release was accompanied by a CD where songs from the game’s soundtrack are reimagined as vocal-driven studio tracks. They&#39;re all great. This one especially. The production is insane - it goes from hard boppin midi bass madness to a hyper-unreal pastiche of the time that George Harrison bought a Sitar.</p>
<p>So yes, this song from 1989, which I first heard this year, is one of the songs of 2023.</p>
<h3>Slugs - Slow Pulp</h3>
<iframe style="border: 0; width: 100%; height: 120px;" src="https://bandcamp.com/EmbeddedPlayer/album=2286629708/size=large/bgcol=333333/linkcol=ffffff/tracklist=false/artwork=small/track=2827465421/transparent=true/" seamless><a href="https://slowpulp.bandcamp.com/album/yard">Yard by Slow Pulp</a></iframe>

<p>I first listened to this song because I am in a band called “Slug Hall” - and this song is called slugs. The song is good. Shoegaze has been a big thing this year I think.</p>
<h3>Crash - Sextile</h3>
<iframe style="border: 0; width: 100%; height: 120px;" src="https://bandcamp.com/EmbeddedPlayer/album=2974393527/size=large/bgcol=ffffff/linkcol=0687f5/tracklist=false/artwork=small/track=3526855760/transparent=true/" seamless><a href="https://sextile.bandcamp.com/album/push">Push by Sextile</a></iframe>

<p>This is the coolest band in the listicle. You can tell because they sell a bumbag in their Bandcamp store. Also, from the singer’s highly affected vocal delivery.</p>
<p>I&#39;m currently reading Crash by Ballard. I&#39;m choosing to assume the song is a reference to it.</p>
<h3>Heaven - Mitski</h3>
<iframe style="border: 0; width: 100%; height: 120px;" src="https://bandcamp.com/EmbeddedPlayer/album=3225838131/size=large/bgcol=333333/linkcol=ffffff/tracklist=false/artwork=small/track=2835853413/transparent=true/" seamless><a href="https://mitski.bandcamp.com/album/the-land-is-inhospitable-and-so-are-we">The Land Is Inhospitable and So Are We by Mitski</a></iframe>

<p>Mitski does 60s country ballad. Just a really gorgeous song. I like the bit where she sings about drinking someone’s leftover coffee. Relatable.</p>
<h3>Daddy - Nourished by Time</h3>
<iframe style="border: 0; width: 100%; height: 120px;" src="https://bandcamp.com/EmbeddedPlayer/album=4111242243/size=large/bgcol=333333/linkcol=0f91ff/tracklist=false/artwork=small/track=3287618742/transparent=true/" seamless><a href="https://nourishedbytime.bandcamp.com/album/erotic-probiotic-2">Erotic Probiotic 2 by Nourished By Time</a></iframe>

<p>Starts like an Arthur Russell song, but then there&#39;s a bit where someone says, “Bass bass bass bass,” and then the house stabs start. Great 10/10</p>
<hr>
<h2>Conclusion</h2>
<p>Those are some songs. Merry Christmas.</p>
]]></content>
          <pubDate>Wed, 20 Dec 2023 23:00:00 GMT</pubDate>
          <link>https://johnwhiles.com/posts/songs-of-2023</link>
          <guid isPermaLink="true">https://johnwhiles.com/posts/songs-of-2023</guid>
        </item>
        <item>
          <title><![CDATA[I have added comments to this website]]></title>
          <content type="html"><![CDATA[<h1>I have added comments to this website</h1>
<p>As of a few minutes ago you can now leave comments on my blog posts, including this one! I don&#39;t know about you, but I sure am excited!</p>
<p>I currently consider this to be an experimental feature, and it might disappear at any time as the whim takes me. If people are mean to be, for example, comments will not be long for this world.</p>
<p>I currently ask for an email when you submit a comment, and at some point will require email confirmation before the comment is published. But your email will not be otherwise shared.</p>
<p>Currently, all comments need to go through me before they&#39;ll be published. I don&#39;t expect this to change any time soon.</p>
<p>I look forward to hearing from you on the information super highway. Stay safe out there.</p>
]]></content>
          <pubDate>Mon, 11 Dec 2023 16:52:00 GMT</pubDate>
          <link>https://johnwhiles.com/posts/comments-alert</link>
          <guid isPermaLink="true">https://johnwhiles.com/posts/comments-alert</guid>
        </item>
        <item>
          <title><![CDATA[Suddenly, I Understand Software]]></title>
          <content type="html"><![CDATA[<h1>Suddenly, I Understand Software</h1>
<p>Even though I don&#39;t respect podcasts as an information delivery system, I recently listened to a podcast that felt like having an epiphany.</p>
<p>The podcast in question was <a href="https://futureofcoding.org/episodes/061">episode 61 of Future of Coding</a>. It is essentially a read-through/review of two papers with which I was unfamiliar, but which I believe are actually quite famous and influential.</p>
<p>Why did listening to this feel like an epiphany? Well, I suddenly felt like I understood what the deal is with software. Why is it that when you join a company, the engineer who&#39;s been there for years seems like an incredible genius? Why do some teams that I&#39;ve been on struggle while others manage to get everything right? Why is everyone always so keen to rewrite things?</p>
<p>The two ideas that the podcast expresses are:</p>
<ul>
<li>The concept of what a “Theory” is, according to Gilbert Ryle.</li>
<li>That being a programmer is doing “Building theories” in the Ryle sense of the word.</li>
</ul>
<p>Having these two ideas explained together was really helpful. If I had read Ryle by himself, I would have thought, “interesting and useless”. If I had read Programming as Theory Building without knowing the theory concept, I would just not have understood.</p>
<p>I recommend listening to the podcast and reading the paper. But if you don&#39;t want to do that, I&#39;m going to try and explain the two points.</p>
<p><img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/6FneKfEWuMP1Ke9omenPf2/975978d3070f8b4fa87b74882ef15804/jwhiles_httpss.mj.run55zU4CdGTuk_httpss.mj.run5FGx1NzXTpY_htt_466bc4eb-d727-45fd-8545-3bc6eb2951b6_3.png?w=800&fm=webp alt=strange figure /></p>
<hr>
<h2>What is a Theory, According to Gilbert Ryle?</h2>
<p>When Ryle says theory, he doesn&#39;t mean anything like what other people mean when they say theory. Annoying. He should have just come up with a new word.
What he means is the thought object that exists in our minds which allows us to do things.</p>
<p>I, for example, know how to cook pasta. When I cook pasta, that&#39;s a certain expression of this knowledge. When I try and explain to you how to cook pasta, that&#39;s a different expression of it. Neither of those expressions contains everything I know about cooking pasta. And in fact, there are parts of what I know that I can&#39;t really express in any way. This knowledge is what Ryle would call a theory. I have a “Theory of how to cook pasta”. This theory is not something that exists in language or action - it’s a <em>something</em> that we can never fully express. The closest we can get to transferring a theory is to demonstrate the expression of the Theory to someone over and over again until they build their own theory. That theory won&#39;t be the same as ours.</p>
<h2>What Does it Mean that Programming is Theory Building?</h2>
<p>It means that the code base we create is not the true product of our work. The real product is the mental theory of that code base which:</p>
<ul>
<li>Allowed us to create it in the first place.</li>
<li>Allows us to diagnose problems with it and fix them.</li>
<li>Allows us to modify it easily.</li>
</ul>
<p>If I think about times when I&#39;ve worked on a team that works well and gets stuff done, it&#39;s been a team where:</p>
<ul>
<li>Someone has been there for a long time, since the start of whatever code base/feature we work on.</li>
<li>Other team members have joined slowly, and had a chance to work with the people who know more.</li>
<li>The area of focus does not change. We haven&#39;t been reassigned to a random existing project, or asked to fix some other team’s work.</li>
</ul>
<p>The paper also talks about what happens when all the people who have a theory of a given program stop working on it. It <em>dies</em>. Yikes. It’s claimed that we can’t rebuild a theory from code and documentation. </p>
<p>This model explains a few curious phenomena:</p>
<ul>
<li>What “legacy code” actually is - it’s a code base which is no longer maintained by people who have a theory of it.</li>
<li>The solo engineer who can make a better product than a team of equally competent professionals. The solo engineer has spent the time to build a complete theory of their program, the professionals move between projects regularly - and only have theories of what they&#39;ve worked on.</li>
<li>Why getting up to speed with unfamiliar projects is so much harder than just rebuilding the thing. To truly build a theory, you need to mentally rebuild the existing code base anyway.</li>
<li>Why outsourcing, or hiring contractors, always seems to go so badly.</li>
</ul>
<p><img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/2jJwD4Uw8zGYBBK0CnGBw5/8e0ecf35c5cc6ef8f8931a57c3cf821e/jwhiles_a_painting_of_the_moon_attacking_the_earth_in_the_sty_1826cf7c-7415-4be2-b9af-86c1372c06ea_2.png?w=800&fm=webp alt=Moon kill sun /></p>
<hr>
<h2>What You Can Learn from This</h2>
<p>Retention of software engineers is really important!!!</p>
]]></content>
          <pubDate>Sat, 18 Nov 2023 15:57:00 GMT</pubDate>
          <link>https://johnwhiles.com/posts/programming-as-theory</link>
          <guid isPermaLink="true">https://johnwhiles.com/posts/programming-as-theory</guid>
        </item>
        <item>
          <title><![CDATA[What I talk about when I talk about Balenciaga's Trainers ]]></title>
          <content type="html"><![CDATA[<h1>What I talk about when I talk about Balenciaga&#39;s Trainers</h1>
<p>Let&#39;s talk shoes.</p>
<p>In 2015, Demna joined Balenciaga as creative director. The first trainer released under his creative direction was very ugly and disappointing. It was called</p>
<h2>Speed</h2>
<p><img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/777qTODiN1agYnnJ7wfcSE/382de00cef03a67e9849d6bf8b070f95/eCom-587280W2DBQ1015_F.jpg?w=800&fm=webp alt=Speed trainer /></p>
<p>I hate these shoes. They&#39;re super ugly. Being ugly isn&#39;t necessarily a bad thing, but these shoes are <em>not my kind of ugly</em>, and, even worse, they were wildly successful.</p>
<p>You see them everywhere, on all sorts of horribly dressed people. Seven years after their debut, they&#39;re still being released in new variations and colourways. They inspired every boring, visionless fashion company to make their own versions, which somehow look even worse.</p>
<p>I don&#39;t like this shoe, but I think it was a sort of exorcism/cynical but necessary cash grab, because ever since, Balenciaga has been on a casual footwear tear - the trainers they&#39;ve released have all been pretty sick, and they seem to have been getting better with time.</p>
<h2>Triple S</h2>
<p>The Triple S. The S stands for sole. The shoe has three soles. Get it?</p>
<p><img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/2iEpPcBX8XEoYaG4RTX9ui/9235b56e8ee17b3f52aba4ff4fa6c833/Pasted_image_20230223170839.png?w=800&fm=webp alt=Triple S />
These are pretty fun. They make for a cool silhouette, as long as they&#39;re not worn with skinny jeans. But they&#39;re not that exciting. Despite the triple sole concept, they basically just look like a big skatel shoe. They also inspired a lot of other brands to make big shoes - which over time has worn away their distinctiveness. When they were released, they may have seemed freakishly large. Now, they look almost normal.</p>
<h2>Track, Runner, and Xpander</h2>
<p>I&#39;m lumping these three together because they all feel very similar.
<img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/38LGaylI2EBlpHpOFxcNhG/37f946c9d5027b6816ff23d3c0f5784b/Screenshot_2023-02-23_at_18.28.45.png?w=800&fm=webp alt=Shoes /></p>
<p>These shoes continue in the <a href="https://youtu.be/9cB-yzhYf_c?si=FTfgq6-j-9-8aeMv&t=3">‘really big shoe’</a> vein that started with the Triple S, but they lean more into the popular dadleisure aesthetic. They look like Asics or New Balance shoes writ large, and with more detail<sup id="marked-fnref:1"><a href="#marked-fn:1">1</a></sup>.</p>
<h3>An Aside About the Oedipal Shoe</h3>
<p>Remember your youth and the chocolate bars that you ate during it. They were huge. Gigantic things that barely fit into your stretched-out palms<sup id="marked-fnref:2"><a href="#marked-fn:2">2</a></sup>. Eating one was a serious endeavor. It was an act that could take most of a car ride or fill the time you would wait to see your GP.</p>
<p>Think of how you experience those same chocolate bars now. Do they not seem somehow diminished, far smaller than they should be? Do their lights not shine less brightly than they ought?</p>
<p>If this diminishment is true of treats, then it is doubly true of shoes. As children, we were at eye level with our fathers&#39; gigantic trainers and boots, our mothers&#39; imperial red high heels. We inscribed them into our memories as titanic things. Towering objects of power and control. Now when we&#39;re shopping for our own shoes, we have a world of choice - but nothing we can buy can match up to these idealised memory objects because the only shoes that are available are of a normal size.</p>
<p>Or rather, I should say, “the only shoes that <em>were</em> available.” Demna and Balenciaga&#39;s true aim is to re-enchant the world by offering us clothes that realise our exaggerated memories in concrete reality. We can wear these shoes and become the mothers and fathers with implausibly large trainers. These shoes let us recapture halcyon days while simultaneously escaping the mental prison that we build while growing up in the shadow of our parents, who we will always imagine as much larger than we are.</p>
<p>We can step out into the world with platonic forms upon our feet.</p>
<p>Oh, and the Xpander has a heel that looks like a piece of Lego Technic, which I guess is also pretty cool. The Runner is clearly the best of the three. I&#39;d wear it.</p>
<h2>Things Get Serious</h2>
<p>Okay, so Demna has worked at Balenciaga for a good few years. 2021 is over, the Xpander was released in May. What comes next?</p>
<p><em>February 2022</em>
They release a shoe that escapes the bounds of shoeness.</p>
<p><strong>Look at these:</strong></p>
<p><img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/4PTjdg5CSWuNVgIKsvIVAv/bcce1fc41edf1440dbc8518f6da105d1/Pasted_image_20230210142428.png?w=800&fm=webp alt=Defender /></p>
<p>They&#39;re once again borrowing the design language of established dadcore brands. But now, we&#39;ve got a balloon-like tire as a sole. A bulbous shape that looks unwalkable in, barely like a shoe. You imagine rolling on these shoes rather than walking. Our references are no longer constrained to the prosaic, true history of footwear. Instead, we are mixing and matching pure concepts from within and without the world of clothing.</p>
<p>This is the shoe as monster truck. Evoking Ballard&#39;s &quot;Crash&quot; - these shoes let us step into the psychosexual fantasy that drove the western world&#39;s transition into an individualistic, atomized, car-owning polity. When you slip on a pair of Defenders, you are stepping into the rubbery soles of Dr. Richard Beeching. You have become Corbusier standing bravely astride a gorgeous world of six-lane highways and tower blocks.</p>
<p><img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/2mIeFhvTFCY7DUmUPsvrXa/ee0b27f0dae2fe9102c5ed2571fcfa46/IMG_8217.jpeg?w=800&fm=webp alt=If you&#39;re getting fits off in central London, watch out - watch out because I&#39;m photographing you from behind /></p>
<p>I recently saw a LSE student wearing these on the Strand. His gait was no longer that of a human, but instead of the new man who will turn this world into what it wants to become. Unfortunately, he had purchased the grey colourway, rather than black - so he didn&#39;t look that cool.</p>
<hr>
<h2>HD Sneaker</h2>
<p>And then, a few months later, this.</p>
<p><img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/2Z27VnHbK837qqPsVHAu1b/a04b184b9aec8285a91ec4e284bed13a/Pasted_image_20230223171917.png?w=800&fm=webp alt=HD Sneaker /></p>
<p>This is the “HD sneaker”.</p>
<p><a href="https://www.youtube.com/live/NTXbCdS5hdY?feature=share&t=564">You should see them in the context of the show where they were first presented.</a>. Worn by a model wearing only a towel, they give the aspect of a forlorn wading bird, lost in a blizzard, doomed to death. A fatal blow against anyone claiming that fashion isn&#39;t art.</p>
<p>This shoe is when the design team at Balenciaga made one of their greatest discoveries, one that was prompted by them bumping against the limits of how large a shoe can feasibly be. They realised that if, instead of focusing on simply making a large shoe, you instead skew the proportions such that they are a normal height but abnormally wide, then you can create something that steps fully into the realm of the uncanny. These shoes are a technical marvel, a purely synthetic creation which unavoidably evokes visions of human-animal hybrids. Crippled seals dying amid the rainbow iridescence of Alaskan oil spills. Flamingos, bleached white by lack of access to their traditional food source - picking their way through a cracked concrete waterway.</p>
<p>I actually own these shoes - and I love them. But weirdly, they&#39;re the only Balenciaga trainer that I&#39;ve never seen anyone else wearing. I got them quite heavily discounted, and so I think that they maybe represent the moment where this adversarial fashion brand got too adversarial for the normies. A step too far beyond good and evil and into beauty for an ugly world to come along. Or maybe people just didn&#39;t want to spend so much money on a glorified croc.</p>
<h2>3XL</h2>
<p>Doubling down on the flat and wide shoe, Balenciaga has just released the 3XL. It seems to maintain the silhouette of the HD sneaker. But it&#39;s actually a trainer.</p>
<p><img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/4XdvEdRYjVTHYbrHtEPdSo/df9142e97ce79607cde20306de7cfa4d/Pasted_image_20230223173135.png?w=800&fm=webp alt=3XL /></p>
<p>They come with an extra pair of laces, which are tied around the shoe. These laces come pre-dirtied, and there is a card in the box informing you that they are only there for display purposes and must be removed before wear.</p>
<p>I saw someone at Primavera Sound wearing these, and he looked terrible. If I wore them, I would look magnificent.</p>
<h2>To Conclude</h2>
<p>Although these shoes have been released over the course of almost a decade, they&#39;re all still actively in production. If you&#39;re wealthy and a maniac, you can just go and buy any of them now. This seems quite unusual for fashion, and especially for sneakers, which are often sold on the basis of FOMO and artificial scarcity. Luxury fashion is a pretty weird world, but I think the fact that you can buy these shoes if you want them is pretty cool. Here&#39;s my power ranking in order, split into three tiers for easy comprehension:</p>
<h4>Marry</h4>
<ul>
<li>HD Sneaker</li>
<li>Defender</li>
<li>3xl</li>
</ul>
<h4>Snog</h4>
<ul>
<li>Runner</li>
<li>Track</li>
<li>Xpander</li>
</ul>
<h4>Avoid</h4>
<ul>
<li>Speed (booooo)</li>
</ul>
<hr>
<h3>Postscript: More on the Defender</h3>
<p>I assume that most people will see them and respond with derision or contempt. They&#39;re plainly ridiculous. And they become even more absurd if you look at them top down. They&#39;re clown shoes, and they&#39;ve inspired a meme that suggested you could recreate them with Asics and a bike tire. <a href="https://www.instagram.com/reel/CcOIfcFj_he/?utm_source=ig_embed&ig_rid=733e12cd-217f-4454-878d-4c5761bdd4d5">And someone followed through on this idea</a>.</p>
<p>They&#39;re incredibly expensive and made in China out of polyamide. It&#39;s hard to get any sense of what standard of &#39;quality&#39; they&#39;re made to – but that feels almost beside the point. No one seems capable of styling the shoes nicely; most of the fit pics you see online look <em>bad</em>. They apparently weigh over 1kg per shoe, and have such a bulbous sole that walking up and down stairs, or uneven terrain is actively dangerous.</p>
<p>Nonetheless, I cannot stop thinking about these shoes. I am fully obsessed with them. I don&#39;t think I&#39;ll ever get over them.</p>
<p>I could just go out and buy them today. They&#39;re in stock in a full size range everywhere that sells them, and when I look, I always fear that my size will have been marked as &#39;sold out, and not coming back&#39;. But I don&#39;t. Why? I&#39;m not sure. Partially due to having had the value of money drilled into me as a child, and knowing that inevitably someone is going to realize how much they cost. I would struggle to justify such an undeniably expensive and impractical shoe and would always fear the social pressure of wearing them.</p>
<p>Why do I want these shoes so much? I don&#39;t think it&#39;s because of the brand name. The branding that exists is subtle. I think my lust is purely for the design. The insane, never-before-seen design. Though brave design is its own branding.</p>
<p>Balenciaga is often written off as a joke/meme brand, selling bad, ugly clothes to rich people. But they are one of the only houses that we can rely on to create novel stuff. This shoe was inconceivable, but they conceived it – and now our visual worlds are richer.</p>
<p>This shoe should be in museums, and that is why I want it. It fulfills fashion&#39;s promise of letting us be walking works of art.</p>
<p>So, in summary, I ask you, Balenciaga, please give me a pair of these shoes.</p>
<hr>
<p><sup id="marked-fn:1">1</sup> When I first saw a lot of these shoes, I would think, &#39;Oh, that looks like an ASIC,&#39; but then I look at the ASIC shoe, and it looks like a flat copy. Like looking at a PS1 asset after playing a PS2 game.</p>
<p><sup id="marked-fn:2">2</sup> For my British readers, think of creme eggs. I remember them being as big as a balled fist and still imagine them that way. When I see them in a shop now, barely a quarter of the size that I imagine – I am always disappointed.</p>
]]></content>
          <pubDate>Tue, 14 Nov 2023 21:04:00 GMT</pubDate>
          <link>https://johnwhiles.com/posts/balenciaga</link>
          <guid isPermaLink="true">https://johnwhiles.com/posts/balenciaga</guid>
        </item>
        <item>
          <title><![CDATA[On Doing Maintenance / Cataloguing the Work]]></title>
          <content type="html"><![CDATA[<h1>On Doing Maintenance / Cataloguing the Work</h1>
<p>I have lots of uncatalogued and unindexed &#39;work&#39;. I feel weird about using the art world term &#39;work&#39; in this way, but I don&#39;t know what else to call it. I&#39;m talking about thousands of unsorted photos in Dropbox, tens of hours of Ableton projects that were interesting enough that I didn&#39;t immediately delete them, and endless screenshots of weird things on the internet that seemed somehow valuable. “Content” might be the term for this stuff - but it implies an existence oriented towards consumption, which I don&#39;t think is appropriate, and also just feels icky.</p>
<p>I want to do something with all this stuff - pick out the best bits, get them into a comprehensible form, and then discard the rest. But the size of the task is daunting. And it gets more daunting every day. I sometimes am able to force myself to bite off a chunk of it. But the pile keeps growing, and so the occasional biting of chunks is not sufficient.</p>
<p>I want to try and at least stop the problem from getting any worse. So I&#39;m now trying to either catalog and index this stuff as it is created, or else store it in some sort of container, where you know it must be catalogued soon or else be deleted<sup id="marked-fnref:1"><a href="#marked-fn:1">1</a></sup>.</p>
<p><img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/1BWjLgXRVXmJXxwLljIWiS/7145aad6287215060f687b5de9dd4b3f/IMG_8517.jpeg?w=800&fm=webp alt=Maintenance /></p>
<h2>How to Stop a Buildup</h2>
<p>There are lots of ways to force yourself to do some work of cataloging and indexing. You could:</p>
<ul>
<li>When writing in Obsidian, create any new files in an inbox folder - where they must soon be moved or deleted. Surface the files that need to be reviewed in a weird dashboard.
<img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/e6nvOARcQA2ULR94GXtK0/4034ff74166ed2204d9cce1b05de383f/Screenshot_2023-11-06_at_14.00.35.png?w=800&fm=webp alt=Notes /></li>
<li>When taking screenshots or photos of interesting things, immediately add them to <a href="https://www.are.na/jhon-wihles/pictures-of-vans">the right place on are.na</a> or else throw them away. </li>
<li>When recording music - export a WAV at the end of the session - even if it&#39;s not finished. Put it somewhere that you listen to it (bring back iPods). If you don&#39;t like listening to it, delete it all.</li>
</ul>
<p>Unfortunately, most software is not built to facilitate this kind of workflow. Cloud providers are happiest when you are working in a completely integrated environment, where anything you create is saved to their cloud forever - taunting you with the possibility that something good is hidden in there - making sure that you can never leave.</p>
<p><img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/62mgWY23m0PML1bYwbVJjt/4c999fd24f3294cc6fc1e11de704920b/IMG_8513.jpeg?w=800&fm=webp alt=Maintenance 2 /></p>
<h2>Maintaining an Archive</h2>
<p>Above I described techniques to make yourself archive things. This kind of archiving, cataloguing, and indexing feels hard and is not immediately rewarding in the way that creating new things is. It is essentially maintenance.</p>
<p>We went to <a href="https://www.adk.de/de/programm/?we_objectID=65644">The Great Repair</a> at Akademie der Künste last weekend. It&#39;s an exhibition all about the value of repairing things. The exhibition opens with a reproduction of <a href="https://feldmangallery.com/exhibition/manifesto-for-maintenance-art-1969">Mierle Laderman Ukeles&#39;</a> manifesto for maintenance art. In this manifesto, she writes about the split in her life between <em>doing art</em> and the various other tasks required of her as a mother and a housewife. This was <em>doing maintenance</em>; it was unglamorous, was perceived as less valuable, and in general, happens without anyone noticing it. She wanted to try and ascribe equal value to both the creative tasks and the tasks of pure maintenance - and her approach for doing this was to make the maintenance an artwork in itself, moving it into a gallery setting to recontextualize it as creative work.</p>
<p>While calling out the imbalance in maintenance labor that existed in her own relationship - and presumably in most relationships - the manifesto is clear that “Everyone does a hell of a lot of noodling maintenance work.” Besides a few very unusual people like Stephen King (who writes thousands of words every day with no exceptions), most of us spend a lot of our time working to just keep things ticking along. Our bodies, our organizations, our homes. </p>
<h2>Random Calls to Action</h2>
<p>I think it&#39;s worth thinking about tasks you, or others around you, perform - which feel valueless in the moment, but which are actually essential maintenance. </p>
<p>Pay attention to how you feel during your days. If you are in a moment of creative energy - please don&#39;t embroil yourself in an act of maintenance. I think that&#39;s how you end your life retired, telling everyone about how you never got the chance to do the one thing you actually wanted to do, still not doing whatever that thing is.</p>
<p>Equally, there is a mood that calls for the performance of routine maintenance. If you can recognize it, you should act on it. Doing things at the right time is the best way to do them.</p>
<hr>
<p>Anyway, I&#39;m off to delete 29 of the 30 identical photos I took of a Bavarian mountain.</p>
<p><sup id="marked-fn:1">1</sup> This is the core idea of &#39;Getting Things Done&#39; I think.</p>
]]></content>
          <pubDate>Sat, 11 Nov 2023 17:57:00 GMT</pubDate>
          <link>https://johnwhiles.com/posts/maintenance</link>
          <guid isPermaLink="true">https://johnwhiles.com/posts/maintenance</guid>
        </item>
        <item>
          <title><![CDATA[I made a SaaS product]]></title>
          <content type="html"><![CDATA[<h1>I made a SaaS product</h1>
<p>For the past few months, I&#39;ve been working on <a href="https://coachtracker.net/">Coachtracker</a> in my spare time. It started off as a vague request from my mother to build a tool to help her manage her professional coaching business—and has escalated into a micro SaaS and the single biggest software project that I&#39;ve built from greenfield.</p>
<p><img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/4bLP8t09LNHLuBHZEMMFp2/35816b451be1fcf4430cefafa91a20da/Screenshot_2023-10-30_at_10.19.04.png?w=800&fm=webp alt=Coachtracker homepage /></p>
<p>This has been a really fun experience, but I think I&#39;ve been missing out on some online Klout by not writing about the process. I want to rectify that. So here, I will present a general overview of how we built Coachtracker.</p>
<p>This will be an ongoing series. If there&#39;s anything in particular you&#39;d like me to cover, please get in touch.</p>
<h2>The Tech Stack</h2>
<h3>Remix</h3>
<p>When I started building Coachtracker, I had just been learning about <a href="https://remix.run/">Remix</a>. We used it to build Contentful&#39;s internal meme platform, Memetentful, which was a great experience. So I decided to continue with it.</p>
<p>So far, I don&#39;t regret the decision at all. Some things I like about Remix are:</p>
<p><strong>It encourages you to minimize your client-side code.</strong> A lot of frontend codebases end up being extremely confusing rat&#39;s mazes, mostly because of the requirement to keep your data in sync between the backend, the frontend, and the DOM. If you start with a clear idea of how to do that, you will at some point get confused and upset. Remix helps with this by strongly encouraging you to split up your app into routes that are responsible for loading their own data. In most cases, when a user is able to edit data in Coachtracker, I am able to rely on the platform. There are a lot of forms, very few controlled components, and not too many hooks. When I do want really custom behavior, the blast radius of any complex UI code is limited to that page.</p>
<p><img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/6UFJKUaCYVObcd57f3wWfX/6fe833ca669318b8583050b6aef8daee/Screenshot_2023-10-30_at_10.15.56.png?w=800&fm=webp alt=An example of some complex UI />
<em>An example of some slightly complex UI</em></p>
<p><strong>It&#39;s very flexible.</strong> You can really do what you want. Any route of your Remix app can be a fully-fledged SPA. You can write your own server, you can change how routing is created. It gives you some core tools and lets you go wild.</p>
<p><strong>It enables monoliths, which are nice.</strong> Remix encourages you to build a monolith. And for a small project like this, a monolith is clearly the correct approach. I love that I don&#39;t have to run two projects, that I don&#39;t need to deploy a frontend and a backend, and that I don&#39;t need to worry about writing the code to load the data for most of my routes. Everything has been easy; it&#39;s what I imagine writing Ruby or PHP feels like—but I get to use TypeScript.</p>
<h3>Prisma?!</h3>
<p>I&#39;m using Prisma, mostly because the Remix template I used suggested it. I&#39;m not sure how I feel about this! It&#39;s quite nice, easy to use, and fast enough for what I&#39;m doing at the moment. However, I&#39;m concerned by a few things:</p>
<ul>
<li>Prisma is a for-profit, VC-backed company and obviously has no way to ever make money. At some point, it is going to die and probably become unmaintained.</li>
<li>It doesn&#39;t feel like Prisma gives me that much value over writing the queries myself. I&#39;m just using PSQL under the hood. I could use it.</li>
</ul>
<p>The killer feature of Prisma has been making migrations easy. But there are other tools out there that can do the same. I think it&#39;s the part of my tech stack that I am most likely to remove.</p>
<h3>Tailwind</h3>
<p>This was the first time I&#39;ve used Tailwind in anger. It&#39;s really good! There are only two ways I want to write CSS from now on, and those are CSS modules or using Tailwind.</p>
<h3>Tailscale</h3>
<p>I&#39;m using Tailscale to enable a private connection between <strong>fly.io</strong>, where I&#39;m hosting the app (love it), and <strong>AWS</strong>, where my database lives (ehhh).</p>
<p>I originally considered setting up WireGuard myself, but I&#39;m very glad that I didn&#39;t. Tailscale is nice and easy.</p>
<h2>Recent New Features</h2>
<p>Some stuff I&#39;ve added to Coachtracker very recently:</p>
<h3>A fun 404 page</h3>
<p><img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/5TOFZWp6RJZv2wFJbIFWdc/d881079cf957550e75856df24409b9d1/giphy.gif?w=800&fm=webp alt=404 GIF />
My 404 Page was a boring and demonic blank white page. I adapted a &#39;make a 3d cube&#39; codepen into this new nightmare.</p>
<h3>Timezone detection and easy updating</h3>
<p><img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/2uepxW8Z2AtsPz6yzymJRV/a1abfc0284fef1dd834a68e5784b1956/Screenshot_2023-10-30_at_09.59.59.png?w=800&fm=webp alt=Timezone />
This was a pretty essential feature for an app that is focused on scheduling. I think the messaging about this needs to be improved, and I want to surface what timezone dates are being shown in throughout the app. But it&#39;s a good first step.</p>
<h3>Better booking of sessions on mobile devices and small screens</h3>
<p>The booking flow was confusing on small screens, since you would select a time slot and then a confirmation button would appear—often off the screen. This confirmation is now shown in a modal. Quick, easy win, but this flow will get more TLC in the future.</p>
<hr>
<h2>Coming Up Next</h2>
<p>I will be writing more about how I&#39;ve built Coachtracker in the near future. Topics I want to cover include:</p>
<ul>
<li>How I&#39;m creating and running background jobs without creating a bunch of redundant extra infrastructure and complexity.</li>
<li>How I&#39;m creating nice animations when a user moves between different screens of the app.</li>
<li>Ongoing &quot;What I&#39;m Working On&quot; posts—hopefully on a weekly cadence.</li>
</ul>
<p>Thanks for reading! If you&#39;d like to get in touch please <a href="https://johnwhiles.com/contact">contact me</a></p>
]]></content>
          <pubDate>Mon, 30 Oct 2023 09:41:00 GMT</pubDate>
          <link>https://johnwhiles.com/posts/coachtracker-update-1</link>
          <guid isPermaLink="true">https://johnwhiles.com/posts/coachtracker-update-1</guid>
        </item>
        <item>
          <title><![CDATA[I made a bunch of 'retro' App Icons for MacOS]]></title>
          <content type="html"><![CDATA[<h1>Icons</h1>
<p>I recently made custom icons for all the computer programs that I regularly use<sup id="marked-fnref:1"><a href="#marked-fn:1">1</a></sup>. Now my computing experience looks like this.
<img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/5luVVg7UL1hkKT0jf1mGrA/51d9bc665a67d92a3c4a8dac30713c0a/icons.png?w=800&fm=webp alt=Icons /></p>
<h2>Why tho</h2>
<p>I was inspired to do this by seeing Nate Parrot&#39;s <a href="https://twitter.com/nateparrott/status/1564750261297496065?lang=en-GB">Arc icon</a> that is highlighted in the above image. I really liked the vibe of the icon which was somehow evocative of an older, more idealistic era of computers.</p>
<p>I eventually figured out that the icon is a pastiche of an old Netscape icon. Netscape is a browser I never used, and it&#39;s kind of weird that my computer is now full of icons that look a bit like Netscape. Oh well.</p>
<h2>What I learnt making a bunch of almost identical icons</h2>
<p>Making the icons was fun, and I learnt a few things in the process, including: </p>
<ul>
<li>The basics of how to use Photoshop. Photoshop feels very PAINFUL to use. I think it might be the Visual Studio of image editors. I&#39;m waiting for someone to introduce me to the Vim of image editors.</li>
<li><a href="https://developer.apple.com/design/human-interface-guidelines/app-icons">A bit about Apple&#39;s standards for app icons</a>. I reflected on the fact that many people have spent a lot of time thinking about the minutiae of every corner of your computing experience. I now also can&#39;t unsee or forgive the apps whose icons are not quite the right size or shape.<sup id="marked-fnref:2"><a href="#marked-fn:2">2</a></sup></li>
<li>Apple prevents you from changing the icons of built-in MacOS apps. That is sad, and I hope they reconsider.</li>
</ul>
<h2>Use the icons yourself</h2>
<p>If you would like to to use these icons you can <a href="https://imgur.com/a/AU8dURt">download them here</a>. </p>
<hr>
<p><sup id="marked-fnref:1:"><a href="#marked-fn:1:">1:</a></sup> This might be a trendy thing to do right now. My friend <a href="https://agnescameron.info/">Agnes Cameron</a> recently showed me her collection of hand-drawn icons. They are very fun and will hopefully be available on Linux package managers soon.</p>
<p><sup id="marked-fnref:2:"><a href="#marked-fn:2:">2:</a></sup> Alacritty is one of the worst offenders - look how out of place this is <img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/44qoW6MNredryQp23iktEU/27503c019e5861cd7c7552f7dc3f9bce/Screenshot_2023-10-06_at_14.02.37.png?w=800&fm=webp alt=Gross /></p>
]]></content>
          <pubDate>Sat, 07 Oct 2023 17:24:00 GMT</pubDate>
          <link>https://johnwhiles.com/posts/my-icons</link>
          <guid isPermaLink="true">https://johnwhiles.com/posts/my-icons</guid>
        </item>
        <item>
          <title><![CDATA[I made a Quotebacks plugin for Marked]]></title>
          <content type="html"><![CDATA[<h1>I made a Quotebacks plugin for Marked</h1>
<p><a href="https://quotebacks.net/">Quotebacks</a> is a combination of a chrome extension which can be used to collect quotes from websites, and a little library which renders those quotes in a particular style. I wanted to use it for this website, but I didn’t want to use the existing rendering code<sup id="marked-fnref:1"><a href="#marked-fn:1">1</a></sup>, so I built a plugin for the popular JavaScript library marked. </p>
<blockquote>
<p>The web is still a very young medium, and it has been influenced more than anything else by print media design. There is so much more that can be done with text on a screen than is being done today. Citations, drawing, chat, speech-to-text. There are opportunities everywhere, and the bar is low! If we are serious about unlocking the value of knowledge we should consider how to improve every part of the knowledge production stack, and that includes reading. As Laurel Schwulst says: “Imaginative functionality is important, even if it’s only a trace of what was, as it’s still a sketch for a more ideal world.”</p>
</blockquote>
<p>Source: <a href="https://quotebacks.net/welcome.html">Welcome to Quotebacks</a> by Tom Critchlow and Toby Shorin</p>
<p>The code is on <a href="https://github.com/Jwhiles/marked-quotebacks">github here</a> and the package is published to npm <a href="https://www.npmjs.com/package/marked-quotebacks">here</a>. It looks for markdown in the exact format exported by the browser extension, and then tries to render the quotes in the same style as the existing tool.</p>
<p>I&#39;m currently using Quotebacks to help write a blogpost where I collect the most incomprehensible quotes from Adrian Chiles’ column. So that’s something to look forward to.</p>
<p><sup id="marked-fn:1">1</sup> Why? Well, mainly I couldn&#39;t figure out how to make it work with what I had. I looked at <a href="https://github.com/Blogger-Peer-Review/quotebacks/blob/master/quoteback.js">the code</a>, when I saw it I first thought ‘wow this is totally wild’, and then I realised that by becoming a ‘professional software engineer’ I lost the ability to write and understand some types of code, then I felt a bit weird and sad. YOLO.</p>
]]></content>
          <pubDate>Sat, 29 Jul 2023 23:00:00 GMT</pubDate>
          <link>https://johnwhiles.com/posts/marked-quotebacks</link>
          <guid isPermaLink="true">https://johnwhiles.com/posts/marked-quotebacks</guid>
        </item>
        <item>
          <title><![CDATA[Golden Age of Consumer Software]]></title>
          <content type="html"><![CDATA[<h1>Golden Age of Consumer Software</h1>
<p>I&#39;ve started using ARC, the hot new browser. It&#39;s really good!</p>
<p>Under the hood it&#39;s Chromium - which means that the actual browsing is basically the same as you are used to. The UI surrounding the browser is the interesting part. Your tabs are pinned to the left of the screen. This frees up vertical space. It also reveals that the people who designed arc are super brain geniuses.</p>
<p>Why? Well, once you&#39;ve seen it, it&#39;s obvious that browsers should be laid out this way. We&#39;re constrained on vertical screen space way more than horizontal. Seeing webpages render this way gives them a new beauty. But until I saw Arc this idea, obvious in retrospect, had never occured to me.</p>
<h2>Arc looks nice</h2>
<p>Beyond making webpages look better, Arc is itself somehow quite pretty. Things are laid out well. There is an appropriate amount of space between elements. You can customise the colours it uses per profile, setting gradients with an extremely sweet colour picker. It lets you make weird custom gradients from purple to green, but it also lets you add noise! And much like in music - adding noise always makes things better. Expect to see this popping up in a lot more products soon.
<img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/7wo31FaPN6jRaSUvnIpkVr/44035da11383b51124b9d74a55bdab68/Screenshot_2023-04-05_at_14.53.09.png?w=800&fm=webp alt=Arc grainy colour picker /></p>
<h2>Kill all tabs</h2>
<p>Arc treats tabs differently to other browsers, and aims to discourage the endless accumulation of pointless &#39;things that I need to read later&#39; that plagues modern man. Your tabs are now split into two main groups - transitory ones, and permanent ones. The permanent ones have a sort of &#39;home url&#39;, to which they can easily return at any time. The transitory ones- which are the default for any new tabs you open -are automatically cleared after 12 hours. This, for me, makes working with a browser a much less brain hurting experience. I can pin the things that I actually return to, and let everything else disappear as and when.</p>
<h2>Easels</h2>
<p>Shareable moodboards which can have live webpages embedded into them?! 
This is a cool feature. Similarly to Apple&#39;s new <a href="https://www.apple.com/newsroom/2022/12/apple-launches-freeform-a-powerful-new-app-designed-for-creative-collaboration/">Freeform</a> it feels aggresively like &#39;not a thing normies would use&#39;, but maybe I&#39;ll be proven wrong here.</p>
<h2>Boosts</h2>
<p>Boosts let you change websites as you see fit. Adding new CSS, removing content, embedding other pages inside them. Really it&#39;s a nice interface around building a local chrome extension - but that alone is a beautiful idea. It feels really empowering, like a great way for people to learn what web development is, and also just <em>like what the web should be</em>.</p>
<p>This is one of their examples. Great.
<img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/3WgB9bYysCwCekuS0Qva1b/e1418f6ac461f49065d5387fb2c48f18/Screenshot_2023-04-05_at_15.19.22.png?w=800&fm=webp alt=A good extension /></p>
<h2>A golden age for software products</h2>
<p>So why am I talking about Arc? Because it made me realise that we&#39;re in a golden age for software products. </p>
<p>You sometimes hear old heads talking about <a href="https://techcrunch.com/2016/08/31/sunrise-was-the-best-calendar-app-ever-and-now-i-feel-lost/?guccounter=1&guce_referrer=aHR0cHM6Ly93d3cuZ29vZ2xlLmNvbS8&guce_referrer_sig=AQAAAFP6KXXwOgcI97MLm9-dbDdUgeT6W77PjmH9GqzXfX4RiaH5S9FDEEqGzE5rNB_VsRNHH4eQhRL5Osfrzjt3bnYz2oX-29DeRIIgJiCgyYePLsXQ5QrMTmtOSapvfWqOM8rpcxshL0Wl_tOz-8U9Qg5EGaHzUEWmzwF4PYbxryv7">weird calendar apps which have vanished from the world</a>, or how they loved Google Reader. Usually these were things I hadn&#39;t used, and these laments only ever gave me the vaguest sense of why the software in question was good. But there was a tolkeinesque sense of loss around this software. The Elves had left middle earth, their works were slowly giving way before the ravages of time and questionable aquisitions. </p>
<p>By comparison  the consumer software that I used was almost without exception ill conceived and badly executed. This is still true today, and yet suddenly something in the world has turned<sup id="marked-fnref:1"><a href="#marked-fn:1">1</a></sup>, and if you look in the right place there are really well made tools to be found. Look at the linears, arcs, and raycasts of this world, and compare them to the jankiness of most existing software. All these new things have meaningless names, and a dedication to quality.</p>
<p>What has caused this shift? I have no idea. But here are some ideas:</p>
<ul>
<li>Smaller teams can make good software products. These companies realised that and acted upon it?</li>
<li>Notion made it clear that the market will reward considered design?</li>
<li>Some new software tools- unknown to me -have made building good products easier?</li>
</ul>
<p>As I said, I have no idea. I&#39;ll probably come back to this topic. If you see other software that you think fits into this mould, please let me know - as I&#39;m keen to look at more examples.</p>
<p><sup id="marked-fn:1">1</sup> I want to note that I&#39;m specifically talking about tools that mainly target normies. There have always been great powerful bits of software made for engineers and computer geeks. But if you weren&#39;t the sort of person who wanted to use NeoVim you were, until recently, very poorly served.</p>
]]></content>
          <pubDate>Tue, 11 Apr 2023 19:23:00 GMT</pubDate>
          <link>https://johnwhiles.com/posts/golden-age</link>
          <guid isPermaLink="true">https://johnwhiles.com/posts/golden-age</guid>
        </item>
        <item>
          <title><![CDATA[I wish Chat GPT was more like chatting]]></title>
          <content type="html"><![CDATA[<h1>I wish Chat GPT was like chatting</h1>
<p>I&#39;m one of those horrible people who writes messages line by line. I&#39;ll type a sentence, hit send then start typing the next sentence. I do this because it helps build suspense in my audience, and removes any suspicions that they might have about me caring to carefully craft messages for them. I let the people drink from the firehose of my poorly formed and misspelt thoughts.</p>
<p>Anyway, I&#39;ve been chatting to GPT and you just can&#39;t do that with this slow typing fucker.</p>
<p>Look:
<img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/5KpmhcUzhwsY92HcgJgRYP/c6b486789c7c625b5c3d6389fc945b46/Screenshot_2023-03-13_at_19.25.24.png?w=800&fm=webp alt=Chat-GPT /></p>
<p>I <em>must</em> be given the ability to interrupt the AI. The current situation is intolerable.</p>
]]></content>
          <pubDate>Mon, 13 Mar 2023 18:34:00 GMT</pubDate>
          <link>https://johnwhiles.com/posts/chatty</link>
          <guid isPermaLink="true">https://johnwhiles.com/posts/chatty</guid>
        </item>
        <item>
          <title><![CDATA[Check out uBlock origins element picker]]></title>
          <content type="html"><![CDATA[<h1>Check out uBlock origins element picker</h1>
<p>Watch out, there&#39;s a <em>huge</em> lifehack ahead.</p>
<p>I assume that you already use uBlock origin, aka the extension that makes the web usable. By default it blocks most adds that you might see, and breaks Sentry&#39;s error reporting. Turns out it can do way more.</p>
<p>I discovered today that it has an element picker. This lets you select bits of web pages you don&#39;t want to see, and then gets rid of them. I think it works by saving a chunk of custom css that gets loaded for that webpage. </p>
<p><img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/OGREUPrgLxjxyMCUAQxJc/bc59e1d0a326d6c7d9c5299f0c01b4c2/Screenshot_2023-03-13_at_19.14.13.png?h=720&w=800&fm=webp alt=picker /></p>
<p>I&#39;ve used it to remove the homepage from Youtube. Why have I done this? Well, I sometimes like to watch videos of Youtube for purposes of entertainment or education. But I strongly resent being sucked into a hole of wasting time watching nonsense. And I&#39;m too weak-willed to just resist. Also Youtube has been recommending increasingly unhinged shit to me recently.</p>
<p><img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/24n9jfqvkBgDshSqIVA4pw/ce3fd78a17e2f6b20dbe9dd6d3f87b26/Screenshot_2023-03-13_at_19.19.10.png?h=720&w=800&fm=webp alt=Incrongruent recommendations /></p>
<p>I basically could just select the bits I didn&#39;t want to see, and then they were gone. And now it looks like this.</p>
<p><img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/1RgGOfoJF7mBwSiTRETS0W/272de438ee9c1f6140568920afee31aa/Screenshot_2023-03-13_at_19.21.08.png?w=800&fm=webp alt=Youtube homepage /></p>
<p>This feels like an incredible power to have. The bits of the internet that I use are going to start looking a lot more minimal right now.</p>
<hr>
<p><em>Postscript</em>
There&#39;s a lesson to take from this. It&#39;s great to just explore what the software you use can actually do. I often find that programs I use all the time can do absolutely wild shit. Yes I&#39;m talking about Vim.</p>
]]></content>
          <pubDate>Sun, 12 Mar 2023 23:00:00 GMT</pubDate>
          <link>https://johnwhiles.com/posts/block-stuff</link>
          <guid isPermaLink="true">https://johnwhiles.com/posts/block-stuff</guid>
        </item>
        <item>
          <title><![CDATA[John Reviews: Rosalía‘s coca cola]]></title>
          <content type="html"><![CDATA[<h1>Rosalía&#39;s coca cola</h1>
<p>The new coca cola flavour tastes the way that a popcorn flavoured ‘smelly gel’ pen smells.</p>
<p><img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/ntPkvCawI5fJ6Ce0tG168/e520088d33e7e5adcb445e4fa4c3dacd/snifty-popcorn-scented-pen.png?w=800&fm=webp alt=popcorn /></p>
<p>It tastes like something that you shouldn’t put into your body. If I twist my brain the right way, I can pick up hints of coconut, or cream soda. Maybe it’s almost like an artificial pina colada?</p>
<p><img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/6w0bUEiet4uXb6gnwIKS4/0d4981699f33193bbeedd7078ddbbdc6/IMG_5054.jpeg?w=800&fm=webp alt=Movement /></p>
<p>In Germany this drink is being sold under the name ‘Movement’, but weirdly it seems to be called ‘Move’ in other territories. It’s the latest in the line of ‘Coca Cola Creations’, which is a scheme where Coke release minor variations of their popular soft drink and refuse to tell you what they taste like. The previous flavours include ‘Starlight’, ‘Byte’, ‘Marshmello’s Limited Edition Coca-Cola’ and ‘Dreamworld’. </p>
<h2>Ranking the Coca Cola Creations that I have tried</h2>
<ul>
<li>Starlight - Almost indistinguishable from normal coke, but slightly fruity. Does not taste like space, unless space tastes of fruity coca cola. 4/5</li>
<li>Movement / Move - A truly foul drink. 2/5</li>
</ul>
<h2>What next</h2>
<p>I will continue to try all of the other flavours if I can find them. Let me know if you can hook me up.</p>
]]></content>
          <pubDate>Sat, 04 Mar 2023 18:00:00 GMT</pubDate>
          <link>https://johnwhiles.com/posts/rosalia-coke</link>
          <guid isPermaLink="true">https://johnwhiles.com/posts/rosalia-coke</guid>
        </item>
        <item>
          <title><![CDATA[Rust Nation UK]]></title>
          <content type="html"><![CDATA[<h1>Rust Nation UK 2023</h1>
<p>Last week I attended the inaugural Rust Nation UK. Here are some notes on the talks I saw</p>
<p><img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/3MHZPZz3N6XctFWyq4VkHu/3fc5598a77cf4c3aa53b7c05e850547f/IMG_4900.jpg?w=800&fm=webp alt=Rust Crab /></p>
<h2>Key note</h2>
<p>The keynote was delivered remotely (pre recorded?) by Nell Shamrell-Harrington and was mostly about the rust community. It was pretty celebratory talk, focusing on best parts of said community, and encouraging people to get more involved in it.</p>
<p>Some things that are apparently good about the rust community:</p>
<ul>
<li>Emotional maturity and helpfulness are valued over raw technical skills.</li>
<li>The community is very into mentoring/teaching.</li>
</ul>
<p>I&#39;m not very familiar with the rust community, so I don&#39;t know how true these claims are. It does seem true that the most famous Rust people are all quite focused on education. Which is nice.</p>
<p>Nell, the speaker, is the editor of the the newsletter &#39;This Week in Rust&#39;, which I subscribe to and sometimes read. I learned from the talk that the newsletter is managed through <a href="https://github.com/rust-lang/this-week-in-rust">a github repo</a> and that in order to submit contents to it you can make a pull request. The newsletter itself is written in markdown, and there&#39;s a draft for the upcoming issue which is cut and sent out on a weekly basis. I think this is a really cool way to run a community newsletter!</p>
<p>The talk didn&#39;t really touch on the downsides of the rust community, which I guess is fine. But based on the attendees there is much less gender diversity than you might see at a JavaScript conference, which is an already not very diverse baseline. I don&#39;t know how Rust can fix that. But it would be nice if they could!</p>
<h2>Rhai</h2>
<p>This talk was delivered by Jonathan Strong from a company called Keyrock, who are a high frequency trading company specialising in cryptocurrency markets. </p>
<p>The talk started with some discussion about why they&#39;re using Rust. HFT demands low and consistent latency. It&#39;s important to respond to new information and market moves quickly to avoid losing incredible amounts of money. The company apparently started off using JavaScript, and found that it didn&#39;t have the performance to do what they needed. Besides being quite slow, it has garbage collection, which leads to pauses occasional pauses that are completely unacceptable for their use case. They tried writing something in Rust and instantly decided that it was the future.</p>
<p>The rest of the talk was focused on Rhai, which is a scripting language that looks a bit like Rust, and has good ways to interop with Rust. For a good part of the talk I was wondering &#39;why can&#39;t you just write these scripts in Rust&#39;. Thankfully this question was answered!</p>
<p>Keyrock have a use case where they want to allow their traders to create custom indicators (an indicator being some signal that will affect their market making activity one way or another). The traders are smart, and somewhat technical - but are not full time rust developers. And they want to be able to change these indicators during trading without having to rebuild and redeploy the rust codebase. So they write these scripts, which their Rust codebase can call out to. The scripts can be changed dynamically. So their workflow seems to be:</p>
<ul>
<li>Rust program runs crunches lots of numbers, and then says &#39;I&#39;m going to call our custom Rhai scripts now!&#39;</li>
<li>These scripts get called, and can access data in the program&#39;s memory, and even call Rust functions using custom dispatching logic when expensive computation is required.</li>
<li>They get their indicators and can then act on them.</li>
<li>As the situation changes throughout the day, the Rhai scripts can be updated easily at any time.</li>
</ul>
<p>The speaker also mentioned that they have various ways of controlling what resources get used by these scripts. They can limit things like the maximum execution time, or the length of vectors that the script can create. This hopefully puts upper bounds on the performance impact of any given script, and stops their traders bringing the whole system to a halt.</p>
<p>The talk also covered a lot of details of Rhai as a language which I immediately forgot.</p>
<p>Oh and they also mentioned that in this setup NaN becomes an issue. Oh no!</p>
<p>Keyrock were sponsoring the largest stage at this conference, so presumably Rhai works pretty well for the making money use case. Nice.</p>
<h2>Async Rust from the ground up</h2>
<p>In this talk <a href="https://conradludgate.com/">Conrad Ludgate</a> from Truelayer guided the audience through how async rust works. They started from where the language was in 2016 and then built various implementations of async on this base. They showed the problems that different approaches have, and how they could be fixed. This process gradually built up to something approximating how async rust actually works. </p>
<p>There was <em>a lot</em> of code shown in this talk, and being at the back of the room I found it hard to follow. Also, this talk was just too difficult for me to follow very closely. If there&#39;s a recording, I think it could be a good resource to go through a bit more slowly in future.</p>
<p>One thing Conrad mentioned in this talk is that he made his first GitHub repository in 2016. I made my first GitHub repository in the same year. It&#39;s certainly the case that the intervening years Conrad has learnt a lot more than me about asynchronous Rust.</p>
<h2>Rust it Up</h2>
<p>This talk by <a href="https://tim.mcnamara.nz/">Tim McNamara</a> was about how to get your company to use Rust. If that&#39;s something that you want.</p>
<p>I missed the first ten minutes of this talk because I was talking to someone about concert venues in Berlin. But what I saw was very good! Tim McNamara is clearly a very good speaker. The kind of person who I would happily listen to talk about anything. I don&#39;t know if this was down to skill, natural charisma, or having a New Zealand accent. Possibly all three.</p>
<p>When I walked into this talk Tim was discussing the aspects of Rust that confuse people. String vs &amp;str was number one with a bullet, but they also complained about the number of similar but different concepts in the language, which are second nature for experienced practitioners - but which are baffling to newcomers. For example, Rust has a function called <code>clone</code> and another called <code>copy</code>. They&#39;re different in very significant ways. Good luck explaining the difference to someone who&#39;s learning programming for the first time!</p>
<p>I didn&#39;t take any notes during this talk so I don&#39;t have much else to say, other than this memorable quote/paraphrase: </p>
<blockquote>
<p>If you need a certain level of performance your choice is Rust, or shipping something that&#39;s broken.</p>
</blockquote>
<p>Source: <a href="https://tim.mcnamara.nz/">Rust it Up</a> by Tim McNamara</p>
<h2>Surreal DB / JFrog</h2>
<p>In this slot I jumped between two talks and found both of them to be basically adverts. I started off in a talk about Surreal DB - which is a new graph based database that has features like</p>
<ul>
<li>Authorization and access control</li>
<li>Graph based data</li>
<li>Documents</li>
<li>Letting clients connect diretly to the DB!</li>
</ul>
<p>It sounds like it wants to be the best database for everyone, and to offer every conceivable feature. Unfortunately the 15 minutes of the presentation I watched felt like an infomercial. I think I could have just read their marketing website and gotten the same information quicker. So I left and went to a talk in another room delivered by someone from JFrog. This was also a kind of half advert half talk - but did cover some interesting details about various supply chain attacks that they&#39;re aware of - and concrete information about how their products can help mitigate such attacks. </p>
<h2>Using rust at Fly.io</h2>
<p>I was interested in this talk because I use fly.io to host Contentful&#39;s internal meme platform, and I think it&#39;s great. The talk, which was given by <a href="https://senyosimpson.com/about/">Senyo Simpson</a> covered some details about how fly&#39;s networking works. They apparently use DNS anycasting, which as I understand it, is a way of having multiple servers in different locations with the same IP address. Doing this lets them route traffic from any client to that clients closet point of presence. It sounds pretty neat, and is something I want to learn more about.</p>
<p>My use of Fly so far has been running code on a single instance, generally in Frankfurt. It sounds like I&#39;m missing some of the real benefits of Fly, which are letting your code run on the edge. I&#39;m hoping that this year Contentful&#39;s meme platform will experience enough growth to justify moving it to an elaborate distributed setup.</p>
<p>Besides the networking details, a lot of this talk was a kind of &#39;Rust experience report&#39;. A lot of the talks at this conference had an element of this, and it was interesting to see the consistency. Basically everyone seems to agree that Rust is really good - and that the main challenges are getting started, and onboarding people into it. Senyo talked about how Rust&#39;s values lead to a language which is good for experienced users, but less approachable. The language and community value soundness and performance over approachability and ergonomics, which means that as rust develops we will always see performance and soundness improvements priorisited when they are in conflict with ease of use.</p>
<h2>Conclusion</h2>
<p>I had a nice time at Rust Nation. The talks were good, but I found that the best part of the conference were the conversations I had with random strangers. I spoke to some really interesting people about topics like:</p>
<ul>
<li>Running red team attacks on UK various parts of the UK&#39;s infrastructure. </li>
<li>Compiling LLMs to run in a webbrowser</li>
<li>How <a href="https://smarkets.com/">smarkets</a> calculate prices for their various odds they offer.</li>
</ul>
<p>If I had my time again I would try and talk to more people, even though I found the process of introducing myself to random people pretty draining. I would also have gone to more workshops instead of talks.  Watching ~7 talks in one day is too much for me. </p>
<p>In general, I want to applaud the organisers on running a really good conference. </p>
]]></content>
          <pubDate>Mon, 20 Feb 2023 23:00:00 GMT</pubDate>
          <link>https://johnwhiles.com/posts/rust-nation-uk-2023</link>
          <guid isPermaLink="true">https://johnwhiles.com/posts/rust-nation-uk-2023</guid>
        </item>
        <item>
          <title><![CDATA[Fixing a Memory Leak in a Ruby SideKiq Job]]></title>
          <content type="html"><![CDATA[<h1>Fixing a Memory Leak in a Ruby SideKiq Job</h1>
<p>I was recently tasked with finding an fixing a Ruby memory leak. Knowing nothing about Ruby, this was quite a challenge! It seems quite likely that other people will run into a similar problems in the future, and I hope that by writing this article with all the relevant buzzwords I will be able to SEO myself into those peoples laps.</p>
<p><strong>In short</strong>: we were using <a href="https://github.com/steveklabnik/request_store">RequestStore</a> in a long-running sidekiq job. During this job the store grew and grew until we ran out of memory, then the job would crash. We started clearing the RequestStore, and that fixed the problem.</p>
<h2>The setup</h2>
<p>At Contentful, where I work, we have a Ruby monolith. It is one of the oldest service that we have, with a lot of responsibilities, a lot of accumulated features. And because we are now mostly a Node.js company, it&#39;s generally seen as a &#39;scary old thing&#39;, left to specialised Ruby developers.</p>
<p>The service contains various Sidekiq jobs. The particular job we&#39;re concerned with here runs once a day, and is meant to iterate through every &#39;Space&#39; that exists in Contentful. For each of these &#39;Spaces&#39; it checks that we have correct infrastructure backing it, and if we don&#39;t, fixes the problem. The job was temporarily disabled late last year, and upon being re-enabled we noticed that it was always crashing with an Out Of Memory error before finishing. This was a problem, because we really wanted the job to finish!</p>
<p>Initially we assumed that the job just didn&#39;t have enough memory assigned, so we gave it some more memory. It keep crashing but took slightly longer. I looked at the memory usage. It looked like this: </p>
<p><img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/bnx05AtVGYqdHo4fBF8d1/d0fcb33bb6a854c6b1457954639fae9f/memory.png?w=800&fm=webp alt=memory /></p>
<p>Not good.</p>
<h2>On not knowing Ruby</h2>
<p>I am not a Ruby developer. I don&#39;t know the language, the ecosystem, or the tooling. This put me in a slightly difficult position, where I barely knew how to start debugging a Ruby program. Let alone how to find a memory leak.</p>
<p>I spent a while quizzing people and reading up on memory in Ruby, trying to understand what tooling I could use to run this job in a way that would alow me to observe how the memory usage evolved in real time. As I did this it became clearer and clearer that my lack of familiarity with the ecosystem was meant that any &#39;serious&#39; debugging attempt was going to take a lot of work. My life&#39;s ambition is not to become a Ruby developer, so this seemed like a poor use of time.</p>
<p>Instead I decided to take the traditional approach and just read all the relevant code. A technique that for me has a much higher success rate than using debugging tools, but probably only because I continually find excuses to avoid learning how to use them properly.</p>
<h2>The problem</h2>
<p>After an hour or so I had followed all the threads, and the only thing I could find that looked suspicious was one of our code paths that used something called RequestStore. It sounded suspicious because this is a cronjob, and does not deal in &#39;Requests&#39;. </p>
<p>RequestStore is, it turns out, a popular Ruby library for caching data for the duration of a request. It&#39;s built with rails in mind, and gives you a key value store on a per request basis with which you can save and access arbitrary data across your code-base. A key feature is that this store is cleared when that request ends. You can use it to, for example, cache the result of a computationally expensive query that might otherwise be made in several places during the life-cycle of one request.</p>
<p>There is one very obvious problem with using RequestStore in the context of a long running cronjob: there&#39;s no request to end. Therefore there is nothing to trigger clearing the cache.</p>
<p>So I changed our code to manually clear the RequestStore after each iteration of the job and deployed this new version to staging. Here is how the memory usage now looked:</p>
<p><img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/6ydZdgCVqRjY6jfiJ3ei4a/f2db689fa0b14c5a0b8e0635cc4b06af/Screenshot_2023-01-24_at_11.45.08.png?w=800&fm=webp alt=Screenshot 2023-01-24 at 11.45.08 /></p>
<p>Much nicer!</p>
<h2>Conclusion</h2>
<p>If you have a long running ruby process that has a big old memory leak, have a look to see if you&#39;re using RequestStore!</p>
]]></content>
          <pubDate>Wed, 25 Jan 2023 23:00:00 GMT</pubDate>
          <link>https://johnwhiles.com/posts/ruby-memory-leak</link>
          <guid isPermaLink="true">https://johnwhiles.com/posts/ruby-memory-leak</guid>
        </item>
        <item>
          <title><![CDATA[Rating the Ramen I ate in Japan]]></title>
          <content type="html"><![CDATA[<h1>Rating Ramen</h1>
<p>In Japan we ate a lot of different Ramens. Here is what I thought of them.</p>
<h2>Ichiran</h2>
<p>Ichiran is a chain. I went to two different locations, one in Shibuya - the other in Kyoto. The most exciting thing about Ichiran is that it is an almost entirely anonymous dining experience. You enter the shop, place your order at a machine which dispenses meal tickets. Then someone hands you a piece of paper where you can specify various things about how you want your ramen to Taste. For example, richness*, fishiness, amount of chilli powder, etc. </p>
<p><img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/5dFX7ZyHzBFxv0aJjKB5Mu/39e7ceaae7e351af9b9651c4ea7be088/B7231D3E-2318-4A21-8C20-BEA9BFCBF75C_1_105_c.jpeg?w=800&fm=webp alt=Ichiran Ramen /></p>
<p>After doing this you take your ticket, and your order sheet to a small booth. There are panels to either side of you blocking your view of the customers sitting next to you, and in front of you is a curtain. The curtain will briefly rise and a pair of hands will take your order. A few minutes later another pair of hands will place your order in front of you and then withdraw, closing the curtains behind themselves. You&#39;re then free to eat in as close to complete privacy as can be found in a crowded ramen bar. You can speak to your server if you wish, but there are also wooden signs provided with which you can signal that you wish to request various services, without having to speak.</p>
<p><img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/7p2Mmm9b7EIif6lypD6HTD/32204a508e1998f01a065a8e9dda23ab/4F5B98AD-3871-40D7-9727-052AB39838BD_1_105_c.jpeg?w=800&fm=webp alt=Ichiran Egg /></p>
<p>The ramen itself is a good classic ramen. Ichiran was the first bowl that I ate on arriving in Japan, so it&#39;s possible that I&#39;m overrating it due to a lack of hedonic adaptation.
<strong>Rating:</strong> 4/7</p>
<h2><a href="https://afuri.com/">Afuri</a></h2>
<p>Afuri is a chain that is known for their Yuzu Shio Ramen. This ramen has yuzu added both to the broth, and as a garnish. The broth is lighter and thinner than a lot of the other ramen chains. And the combination of chicken with a citrus fruit gives a very different feeling to other ramens. Their pork is also very different from what you generally get. It&#39;s essentially a thick crispy piece of bacon, more akin to what you&#39;d find in a good English Breakfast, than the soft, juicy pork that Ramen usually contains. This citrus burst, and crispy pork is definitely an interesting change, but I don&#39;t think it&#39;s better than more typical ramen.</p>
<p>The branch of Afuri that we went to felt a lot more airspace than most Japanese establishments. Make the seating slightly more spacious and I think this restaurant would not be particularly surprising in London. Potentially this could be the Wahaca of Ramen.
<strong>Rating:</strong> 4/7</p>
<h2><a href="https://kikanbo.co.jp/english">Kikanbo</a></h2>
<p><img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/2wViO10xhier3WLOupUDaS/9ca153be109c478a105153534cee2317/IMG_4349.jpeg?w=800&fm=webp alt=Devil&#39;s Ramen /></p>
<p>Another chain. With branches in Tokyo, Hong Kong and Taipei, Kikanbo specialises in making spicy ramen, and really leans into its Oni based branding. It&#39;s also really good!</p>
<p>When ordering you are asked to specify how spicy you want your food, out of 5. You are asked to choose this on two scales, spicy and numbing. Spicy is chilli pepper, and numbing seems like it is sichuan pepper. You then take your place at the bar.</p>
<p>While you wait for your food, you can take some time to appreciate the decor which is, as mentioned, all based around Oni. The door handles resemble Oni&#39;s clubs, there are devilish faces everywhere that they can possibly fit. Each piece of cutlery and crockery includes a devil. I don&#39;t know if this was always the case, but during our visit, there was a constant soundtrack of Taiko music - which added a somewhat combative feel to the proceedings. As if this was more like a trial by combat than a meal.</p>
<p>In short order you&#39;ll receive a very large bowl of ramen. The broth is extremely thick, the portion very generous, and there is a huge hepling of bean sprouts on top. The pork at Kikanbo was a real standout. It was amazingly succulent, and completely fell to pieces in the mouth.</p>
<p>I&#39;d chosen 3 (or medium) for both spicy and numbing, assuming that at a restaurant that is dedicated to spice this would be quite intense. For my Jalfrezi loving palette the spice was actually very mild. If I went again I would definitely take a step further up the heat scale. The flavour was very good. This was maybe the most enjoyable ramen experience.</p>
<p>We went to the Akihabara branch. Arriving at 11am, when it opened, the restaurant was already full and there was a queue of 5 or so people out the door. We didn&#39;t have to wait long, but by the time we got inside the queue had grown to cover both sides of the street, and looked terrifyingly long.</p>
<p><strong>Rating:</strong> Oni/Oni</p>
<h2><a href="https://goo.gl/maps/Xt886mQsKR2n55SU7">Ramen Mitaka</a> (AKA: The one near the Ghibli Museum)</h2>
<p>We went to this place on the way to the Studio Ghibli museum. I assume that they must get a few such visitors everyday, but still the restaurant felt very much like a local joint. Without being able to look at an online map and see all the restaurants marked - we would never have stumbled across it. It&#39;s in a nondescript basement of an equally nondescript building. You sit on a bar around the two men who make and serve all the food. You can peer into the broth and see the vegetables floating in it, you can similarly peer into the bath of boiling water where your noodles are cooking. And you can watch a very healthy dose of MSG being poured into every bowl.</p>
<p>We got wantan-men, and it was just really really nice. It&#39;s not outrageously thick, and the flavour doesn&#39;t lean too hard in any one direction. Just balanced, tasty, filling. A really lovely place to eat.</p>
<p>There&#39;s no English menu, so it&#39;s good to know what you want to order. And take some cash.</p>
<p>6/7</p>
<h2><a href="https://goo.gl/maps/q6ZnZK4QJ4DHyqab8"># らーめん三ちゃん</a> (AKA: The one in Nara)</h2>
<p>We went here after arriving in Nara. We originally wanted to go somewhere else, but we had suitcases, and it was far too small to accommodate them. So we ended up here by chance. Luckily it turned out to be a really good place! </p>
<p>From the outside it&#39;s not particularly flashy. It was really delicious though! The pork is the real stand out here. The bowl I ordered contained a huge chunk of pork, and it was seared more intensely than a lot of other places. The pork retained its softness, but with a crunchy sear.</p>
<p>They also had a really good music playlist, which I was shazaming throughout. Here are some of the songs we heard during the meal:</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/CbH2F0kXgTY" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
<iframe width="560" height="315" src="https://www.youtube.com/embed/-pStiPLVKA0" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>

<p><strong>Rating:</strong> 6/7</p>
<h2>Tatsunoya</h2>
<p><img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/3e6FeBncmCwg8YZBFeaN07/566c5269a1bbfccb026e995af088e05d/A138E44B-A26F-4A82-B8BE-E70F8FEEA261_1_105_c.jpeg?w=800&fm=webp alt=Tatsunoya /></p>
<p>Tatsunoya is a buzzy restaurant on the north side of Shinjuku. They also have a branch in California apparently. Which are presumably less good and much more expensive. This is a place where you will probably have to queue quite a while regardless of when you choose to go. It&#39;s very tasty, but nothing about it really stuck in my mind and after eating my mouth felt extremely dry.</p>
<p>Also I accidentally got two eggs, which looked wrong.</p>
<p><strong>Rating:</strong> 5/7</p>
<h2>Dormy Inn</h2>
<p>We stayed at the Dormy Inn. They offer a free ramen service in the evening. You can wander down the canteen, and grab a bowl of hot ramen with the various other people staying at the hotel. </p>
<p>Their ramen is really nothing to write home about. It&#39;s basically instant ramen, made at a larger scale.</p>
<p><strong>Rating</strong>: 2/7</p>
<h2>Instant Ramen from Nakiryu</h2>
<p>All of the convenience stores in Japan sell a huge range of instant ramen. We tried this one because it was branded &#39;Nakiryu&#39; - which is a Michellin starred ramen joint. This instant ramen is more involved than anything I&#39;d seen before. There are three separate sachets of different sauces which have to be opened and combined.</p>
<p>For an instant ramen it is very good, and manages to partially emulate the thick fatty broth that makes the meal so good. But it only partially emulates it. You&#39;ll still have a better meal going to any really ramen restaurant.</p>
<p><strong>rating:</strong> King Size Bombay Bad Boy / 7</p>
<h2><a href="https://menya-kaijin.tokyo/">Ramen Kaijin</a> (Fish ramen)</h2>
<p>Quite an unusual Ramen. The broth is more fish based than other places, and you can order your ramen with various fishy dumplings. You also get a mackerel rice ball, which you are supposed to add to the leftover broth after finishing the noodles.</p>
<p>I was slightly worried that everything would taste super fishy, but the flavours are fairly subtle and very delicious. The dumplings were the best part - and proved an interesting change from all the other ramen. </p>
<p><strong>Rating</strong>: 6/7</p>
<h2>Miso Ramen Matsumoto</h2>
<p><img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/44s7C9iFY7ef1Hjn4kP17e/56d84b662e905842b8e269d8f0f0c4e9/B988A033-1419-43FA-8D1B-6344E3C442C8_1_105_c.jpeg?w=800&fm=webp alt=Miso Ramen /></p>
<p>I don&#39;t really remember much about this one, except that</p>
<ul>
<li>The restaurant was interestingly laid out. It felt very old fashioned. </li>
<li>It was incredibly umami.</li>
</ul>
<p><strong>Rating:</strong> Good / 7</p>
<h2>Street Ramen near Fushimi Inari (new years day)</h2>
<p><img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/1eeDzrrVqDIQ88WGrO0kOh/37bac77c3d685dbcf1ec7f77c8d16d9c/IMG_3934.jpeg?w=800&fm=webp alt=Street ramen /></p>
<p>On new years day we went to Fushimi Inari. This was the one of the busiest events I&#39;ve ever attended, and getting a sit down meal nearby was hard. In the end we got a bowl of ramen from a stall in a car park. It was okay. </p>
<p><strong>Rating:</strong> 3 / 7</p>
<h2><a href="https://goo.gl/maps/8LSSrDj59ByiXGqZ9">Ipudo Kanazawa</a></h2>
<p><img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/3MbLjW3EWIHjbaiUxkoILl/1f09f7da53210559aa251f9191c6f778/3EB28CB1-CC2F-4464-9D2E-FFDE1796B607_1_105_c.jpeg?w=800&fm=webp alt=3EB28CB1-CC2F-4464-9D2E-FFDE1796B607 1 105 c /></p>
<p>We sheltered in here during an incredibly cold and snowy day. The ramen is very thick, very spicy, and very delicious. They also provide you with a slotted spoon so you can pick out all the delicious bits - if drinking all the broth proves too much.</p>
<p><strong>Rating</strong>: 5/7</p>
<h2>Conclusion</h2>
<p>Eating Ramen in Japan is a low risk activity. You can pretty much choose places at Random, and assume that they will be better and cheaper than any similar meal you could find in Europe.</p>
]]></content>
          <pubDate>Sun, 22 Jan 2023 23:00:00 GMT</pubDate>
          <link>https://johnwhiles.com/posts/rating-ramen</link>
          <guid isPermaLink="true">https://johnwhiles.com/posts/rating-ramen</guid>
        </item>
        <item>
          <title><![CDATA[GUEST POST: Japan's hottest tunes right now]]></title>
          <content type="html"><![CDATA[<h1>Japan&#39;s hottest tunes right now</h1>
<p>(Editor&#39;s note: the following article was submitted anonymously by a fan of the website. It fits nicely into our ongoing ‘Japan Month’ so we’ve chosen to publish it. If you’ve got a submission of your own, email  <a href="mailto:hi@johnwhiles.com">hi@johnwhiles.com</a> but note that no payment or exposure will be offered)</p>
<p><a href="https://open.spotify.com/track/2tX846F6lkKbjxrpPgClst?si=23c9b33a1fbe46b7">Mickie Yoshino - Ode To Joy (feat. Mummy-D)</a></p>
<p>One of the best songs I heard whilst in Japan is this phenomenal Ode To Joy funky rap. Much like the death of Diana, you&#39;ll never forget where you were when you first hear this song. For us, it was in a delicious chicken ramen joint in Nara. There was an older lady who served us and a younger man, maybe her son; the restaurant only had one other table occupied, and they were blasting out a really incongruous mix of excellent, but bizarre, tunes as if it was a perfectly normal thing for a public facing establishment to do. This song, with its influences spanning multiple genres and hundreds of years, is already a timeless classic and would be a great choice of material to beam into space to alert the universe to the genius of the human race.</p>
<p><a href="https://www.youtube.com/watch?v=DU5unyrT0YY">Fear, and Loathing in Las Vegas - Just Awake</a></p>
<p>We discovered this song whilst scrolling through songs to play on the popular drumming arcade game <a href="https://en.wikipedia.org/wiki/Taiko_no_Tatsujin#/media/File:%22Taiko_no_Tatsujin_12_increased_version%22_for_arcade_game_(Old_housing).jpg">Taiko no Tatsujin</a> and it turns out it&#39;s not only one of the best songs to drum along to (level: difficult) but it&#39;s also one of the best songs of all time. I thought I could make a comparison of the band to Linkin Park, as both have two singers - one who can belt high notes and has dyed hair, and a counterpart who sings lower and has not dyed their hair - but on reflection this is where the similarities end. </p>
<p><em>Fear, and Loathing in Las Vegas</em> make music which is hard to describe because it&#39;s screamy and metal and electronica-y and ADHD and has a whole lot of autotune, and it&#39;s done with such flawless musicianship that it somehow sounds cheesy, like a demo song on your new Yamaha keyboard, so naturally they are the perfect kind of band to soundtrack an anime (which this song does).</p>
<p>Taiko no Tasujin rating: 10/10</p>
<p><a href="https://www.youtube.com/watch?v=1FliVTcX8bQ">Ado - New Genesis</a></p>
<p>This song is also part of an anime soundtrack because Japan and we could not escape hearing it in shops, on TV, in arcades or blasted on the street. As such, it&#39;s hard to say if this is a good song or if we&#39;ve been brainwashed to believe this is a good song. What I can say is that the singer does a very excellent job singing and you probably don&#39;t want to try it at karaoke. </p>
<p>The anime it soundtracks is called One Piece Film: Red, which isn&#39;t a mistranslation, and is part of the beloved One Piece manga franchise. The plot of the film seems <a href="https://en.wikipedia.org/wiki/One_Piece_Film:_Red">incredibly convoluted</a> but I think the jist is, there&#39;s a character who&#39;s a great singer who hides her identity but there&#39;s going to be a big reveal of who she is, and would you believe it, the singer of this soundtrack song also hides her identity in real life!! She&#39;s like a Japanese Sia, or Gorillaz.</p>
<p>Taiko no Tasujin rating: 7/10</p>
<p><a href="https://www.youtube.com/watch?v=8OZDgBmehbA">Sekai No Owari - Habit</a></p>
<p>Habit was released in June 2022, meaning this was probably a summer smash, but it was still being played everywhere when we went over December/January 2023 meaning it was an autumn and winter smash too. An endless smash. &quot;A song about habit.&quot; That&#39;s the only lyric in this song that&#39;s in English so it&#39;s a bit mysterious, but the translation of Japanese Wikipedia on this song has a helpful tidbit to help explain: </p>
<blockquote>
<p>The title &quot;Habit&quot; has the meaning of &quot;habit&quot;, but in this work it is used in the sense of &quot;habit&quot;.</p>
</blockquote>
<p>Oh and it&#39;s also on a soundtrack to an anime. (Editor&#39;s note: I saw this song performed live on &#39;Kohaku Uta Gassen&#39;, which is a popular singing competition that takes place on new year&#39;s eve. It&#39;s like if Jools Holland&#39;s Hootenany, and Eurovision were combined into one. Highly recommended).</p>
<p>Taiko no Tasujin rating: 6/10</p>
<p>Music video dance rating: good</p>
]]></content>
          <pubDate>Sat, 21 Jan 2023 23:00:00 GMT</pubDate>
          <link>https://johnwhiles.com/posts/japans-hottest-tunes</link>
          <guid isPermaLink="true">https://johnwhiles.com/posts/japans-hottest-tunes</guid>
        </item>
        <item>
          <title><![CDATA[Suggestions and Observations, Japan]]></title>
          <content type="html"><![CDATA[<h1>Japan!</h1>
<p>I&#39;ve recently been in japan for several weeks. Here&#39;s some of the stuff I enjoyed, followed by some random observations.</p>
<h2>Kyoto</h2>
<p>Kyoto is an amazing city. It&#39;s full of tiny streets, which are crammed with really good restaurants. It&#39;s also got very futuristic urban areas, cool malls etc. But mostly it&#39;s full of shrines and temples. Kyoto is probably the nicest place I saw in Japan.</p>
<h3>Walk along the river</h3>
<p>There is a wide easy path on both sides of the river that runs through Kyoto. It&#39;s a lovely place to walk. You can admire the buildings that crowd the river banks, see an amazing number of Black Kites and Herons up close and personal, and you can even walk accross the river on stepping stones.</p>
<p>Be careful if you try and eat near the river, we lost a pork bun to the talons of a Black Kite.</p>
<h3>The Silver Pavillion (AKA Ginkakuji)</h3>
<p>This temple has the most beautiful garden I saw in Japan. Well worth it just to walk around the garden and look at the beautiful plants. It&#39;s also close to the philosophers path, which you can walk along and visit many other shrines and temples. The temple is definitely better than the path though.</p>
<h3>Otagi Nenbutsu-ji Temple</h3>
<p>This temple is pretty small, and out of the way. Get a train to Arashiyama station, which will be uncomfortably busy. Then walk up the hill and the crowds will rapidly thin out. In about half an hour you can get to this temple which was full of 1200 statues of a deity, all carved by people who had stayed at the temple. Most of the statues were covered in moss, and they all looked very different. It&#39;s nice.</p>
<p><img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/1SpNgMKm5q0OSaT0fdLwqg/2dd845efbb551fbfde6936c066dd3497/IMG_1992.jpg?w=800&fm=webp alt=Heads /></p>
<h3>Kiyomizu-dera</h3>
<p>This is top of most tourist lists - it&#39;s a complex on a hilltop which is a really magical place. It is also unique amongst religious sites I&#39;ve visited in that it contains a test of strength. You get to see if you can lift a really heavy piece of metal. You probably can&#39;t.</p>
<p>If you keep walking up behind the back of the shrine, you will find another smaller shrine, which is very nice and relaxing. A totally different vibe.</p>
<h3>Fushimi Inari Taisha</h3>
<p>The place with all the red gates. You&#39;ve seen photos of it. Photos can&#39;t get across how astonishingly extensive this network of red gates is though. You go through a temple up and a hill, and then circle an entire mountain. And you are walking through red gates the whole way. It&#39;s absolutely mind blowing.</p>
<h2>Matsumoto</h2>
<p>A nice, pretty quiet city. I think it&#39;s only worth visiting for a day or two as a tourist. In the summer months I think it might be good to stay longer and use as a base for hiking/biking around the surrounding mountains. But we were here in winter, so I might be wrong.</p>
<h3>Matsumoto Castle</h3>
<p>The big landmark of Matsumoto. Really amazing, and worth going inside. Absolutely impossible for people without good mobility though - because of you need to climb up the several flights of the steepest stairs I&#39;ve ever seen.</p>
<h2>Nara</h2>
<p>Nara is glorious. It&#39;s famous for having a lot of deer, which is an interesting thing to see. </p>
<h3>Shrines and Trees</h3>
<p>Nara is full of shrines and temples. You should certainly see <a href="https://goo.gl/maps/HLA4wjVPUNME7fGD8">Todai-ji</a> which is very very large. The nearby <a href="https://goo.gl/maps/Jt7Hms65Eci4kU8x6">Todai-ji Nigatsudo</a> sits on a hillside, and is perhaps more beautiful.</p>
<p>More exciting for me was the &#39;primeval forest&#39; which is full of shrines and temples (I like shrines and temples). Head towards the park and then just walk around and you&#39;ll find fun stuff. Definitely worth seeing is <a href="https://goo.gl/maps/LFaakvxZvnSW15id7">Kasuga-taisha</a> which is one of the greatest Shinto shrines in Japan.</p>
<h3>A very special toilet</h3>
<p>In Nara you should take the trails that are more off the beaten path. Doing so led us to find, next to <a href="https://goo.gl/maps/2fSWh33aE8MKGBei9">this mysterious forest police box</a> the most extravagant composting toilet I&#39;ve ever seen. It was essentially a hole above some dirt, but had a heated seat - and when you flushed a large metal paddle would stir whatever you had deposited into the dirt. Continuing up the hill  you can also see <a href="https://goo.gl/maps/trEQiJ6wNWcGp6ot8">a quite spooky semi abandoned shrine</a>. </p>
<p>There are various other paths through the forest, which with more time I would have loved to walk.</p>
<h2>Observations</h2>
<p>Here are some things I noticed whilst in Japan.</p>
<h2>Masks</h2>
<p>Almost everyone you see in Japan is wearing a mask while in public, whether they are inside or outside. I&#39;ve seen people driving cars by themselves wearing masks. This is in spite of the Japanese government telling people they don&#39;t need to wear masks outside.</p>
<p>I don&#39;t really know what to make of the situation, because despite being supportive of masks as a Covid prevention measure, I was very keen to stop wearing them. The population of Japan does not seem to share this urge. </p>
<p>A few strange things about the mask wearing</p>
<ul>
<li>Mostly people are wearing very low quality masks, so this is mostly signaling - or people are wearing masks for other reasons. Feels very disimilar to Germany where masks were required to be high quality.</li>
<li>Japanese restaurants and bars are mostly very small and push a lot of people close together. Obviously people don&#39;t wear masks when eating or drinking. But they will put their masks on again before going back outside.</li>
<li>The people you see not wearing masks are either foreigners, or cool/rebellious young people.</li>
</ul>
<h2>Bikes</h2>
<p>A lot of people cycle on the pavement in Japan, which is perfectly legal. They also cycle weirdly fast, and don&#39;t really slow down for pedestrians who appear to be responsible for not getting run over.</p>
<p>I love cycling, but this system seems completely insane. Japan please build some bike lanes.</p>
<h2>Tiny Cars</h2>
<p>Lots of people drive tiny tiny cars in Japan. For example take the Suzuki Hustler. </p>
<p><img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/P5MLgCpWWl6hwGLdLDazZ/6bc82f976bb8c2ab4f676e4317152851/x-turbo-ZVG.jpg?w=800&fm=webp alt=Suzukhi Hustler /></p>
<p>It looks like an SUV, except it&#39;s about half my height. I think these tiny cars are really cool, and I wish every other country would adopt them.</p>
]]></content>
          <pubDate>Fri, 13 Jan 2023 12:12:00 GMT</pubDate>
          <link>https://johnwhiles.com/posts/japan</link>
          <guid isPermaLink="true">https://johnwhiles.com/posts/japan</guid>
        </item>
        <item>
          <title><![CDATA[Fear and Loathing of The Terminal]]></title>
          <content type="html"><![CDATA[<h1>The Terminal</h1>
<p>Steven Spielberg&#39;s &#39;The Terminal&#39; is the worst film I&#39;ve ever watched. We rented it from the library of 64 DVDs that are available at Tokyo&#39;s Hundred Stay hotel. We chose this film because we had somehow come to believe that it was a film about a number of spies, counterspies and criminals trapped in a train terminal. That sounded fun and stupid. Unfortunately &#39;The Terminal&#39; is actually not fun, and much stupider than I&#39;d hoped. </p>
<h2>What the terminal is about</h2>
<p>&#39;The Terminal&#39; is a film about a stateless person who gets trapped in an airport departures lounge and is slowly ground to dust beneath the heels of American bureaucracy.</p>
<p>The film which is OVER TWO HOURS LONG, stars Tom Hanks who puts on an entirely incomprehensible faux Russian accent. You can never tell what he&#39;s saying, but it doesn&#39;t matter anyway because all of his lines in the film consist of the words &#39;Krakozhia&#39;, &#39;Unacceptable&#39;, or &#39;payless shoes&#39; re-arranged randomly. If the writers ever let him say anything else, it&#39;s so they can have him amusingly conjugate a verb incorrectly.</p>
<p>The film is as structureless as a deboned chicken. Our man, Tom, has a reason to visit New York - but this reason is only revealed to us in the last twenty minutes of the film, and is then immediately resolved. For the rest of the running time he just wanders around an airport because, as far as we know, he really wants to go to New York.</p>
<p>There is a subplot to the film where Tom Hanks helps one of the workers in the airport seduce another one. He does this by asking them one question every day, and eventually delivers a wedding ring for them. As far as the audience knows, the two characters involved in the romance never speak to each other until the marriage proposal - despite working in the same building every day for years. They decide to get married because it turns out they both like Star Trek.</p>
<h2>Is Tom Hanks actually bad?</h2>
<p>Before watching this film I vaguely thought that I liked Tom Hanks as an actor, but on reflection I realise that I&#39;ve not seen anything he&#39;s in besides Forest Gump, which I don&#39;t remember, and this, in which he is awful.</p>
<h2>The wider context</h2>
<p>The film is somewhat inspired by the real life of Mehran Karimi Nasseri. I knew this watching the film and having a quite disturbing story turned turned into a &#39;heartwarming romantic comedy&#39; feels somewhat icky to me. Here are some interesting things about the real events that this film was based on which I learnt from Wikipedia:</p>
<ul>
<li>The Ostensible reason that Mehran had to remain in Charles De Gaule airport for 18 years was that he was expelled from Iran. However it appears that he was never expelled from the country.</li>
<li>France and Belgium both offered Mehran residency &#39;but he refused to sign the papers as they listed him as being Iranian (rather than British) and did not show his preferred name, &quot;Sir Alfred Mehran&quot;.&#39;</li>
<li>Steven Spielberg&#39;s production company paid him something like 275,000 dollars to make a film of his life, and then decided to make this film, which is a bit like his life, instead.</li>
<li>His autobiography is called &#39;The Terminal Man&#39;. There is a 1974 novel with the same title by Michael Crichton, which Crichton described as being his &#39;least favourite work&#39;.</li>
<li>After 18 years Mehran left the airport because of a medical emergency.</li>
<li>At some point he became homeless. In 2022 he returned to living in the airport terminal, where he died.</li>
</ul>
]]></content>
          <pubDate>Thu, 12 Jan 2023 11:47:00 GMT</pubDate>
          <link>https://johnwhiles.com/posts/the-terminal</link>
          <guid isPermaLink="true">https://johnwhiles.com/posts/the-terminal</guid>
        </item>
        <item>
          <title><![CDATA[I've rebuilt this website too many times. I just did it again.]]></title>
          <content type="html"><![CDATA[<h1>No More Saber Rattling</h1>
<p>For &#39;software people&#39; who write blogs. The temptation to fiddle with the code underlying blog itself rather than just writing is constant. It&#39;s a temptation that I&#39;m not very good at resisting. </p>
<h2>A Brief History of This Website</h2>
<p>When I first built this website, which was during my time at a coding bootcamp, I wrote my own &#39;microblogging platform&#39;. I setup a Postgres DB, and made a really horrible admin interface where I could write posts. Sadly I don&#39;t have a screenshot of said admin interface, but it was just a textbox which I would write markdown into. It would then be saved directly to the database, and I would hope that it would be rendered correctly.</p>
<p>The website was a real piece of a shit, and based on wayback machine, all I wrote about was how I built it.</p>
<p>I quote:</p>
<blockquote>
<p>My next task is to enable the editing and deleting of previous posts.</p>
</blockquote>
<blockquote>
<p>[...I should] introduce some form of templating engine into the project. I am currently considering either using handlebars, or learning React and using it to render pages on the server.</p>
</blockquote>
<p>At some point I replaced that site with a static page that linked to my Github and my bandcamp. I don&#39;t remember why, but probably I accidentally deleted the database which definitely was not backed up.</p>
<p><img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/173NGQ2Q3Lcq4a049flZ9F/59af9ef1a65e232bf7a87ad1cdd418d1/Screenshot_2023-01-11_at_22.52.00.png?w=800&fm=webp alt=Nice /></p>
<h3>The Elm Days (aka my pink period)</h3>
<p>After a few months of having a website with nothing on it, I got a hankering to once more create a blog. I decided to write it in Elm. I also discovered the <code>list-style: armenian</code> CSS rule. It looked like this: 
<img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/26NfgRInY91Z034ipjK8cF/615f542def301868db8de8e2880c66e3/Screenshot_2023-01-11_at_22.48.03.png?w=800&fm=webp alt=Old website /></p>
<p>Elm is cool, but totally inappropriate for building what is essentially a static html website. I wanted to store the blog content in the github repo as markdown, and to use this to generate the site. This led to me writing horrible scripts <a href="https://github.com/Jwhiles/johncom/blob/e17df790a85d798732c9eb62196be3b88ad3782c/scripts/createBlogIndex.js">like this</a> which would embed details about my blog posts into the Elm code. This was a bad idea, and every blog post I wrote would require me to re-run the build script multiple times until I got the format of my Markdown files correct.</p>
<h3>Saber</h3>
<p>Then I decided to rebuild the blog again. This time I wisely chose to use an existing static site generator. Instead of choosing a popular and long running project, I found a project called <a href="https://github.com/saberland/saber">&#39;Saber&#39;</a> which I think is basically like Gatsby but for Vue instead of React. No one else has ever heard of, or used it. I also didn&#39;t know how to use Vue and didn&#39;t want most of the features that Saber provided. Nonetheless it basically worked, and with this setup I finally published some writing that people read and enjoyed. </p>
<p>So thanks Saber. </p>
<h3>Remix</h3>
<p>I recently tried to build a comedy crypto comments system that would ask people to pay me to write comments on my blog posts. Sadly Saber&#39;s build process scuppered my plans. I was also getting annoyed by the fact that it was in Vue. So I have once again rebuilt the website.</p>
<p>The site is now built in Remix, which is I think <em>pretty good</em>. </p>
<p>I&#39;ve also moved the markdown that actually makes up the blog outside of my github repo which means that I can write from more places more easily. Hopefully this will lead to more writing. The rewrite is still on going so if anything seems broken please tell me :)</p>
]]></content>
          <pubDate>Tue, 10 Jan 2023 15:00:00 GMT</pubDate>
          <link>https://johnwhiles.com/posts/goodbye-saber-hello-remix</link>
          <guid isPermaLink="true">https://johnwhiles.com/posts/goodbye-saber-hello-remix</guid>
        </item>
        <item>
          <title><![CDATA[Setting up my new computer, vim, and listening to Spotify in the terminal]]></title>
          <content type="html"><![CDATA[<h1>Setting up my new computer, neovim configs, and listening to Spotify in the terminal</h1>
<p>I recently got a new laptop, and I decided that this would finally be the time that I don&#39;t set it up in a completely ad hoc way.
Previously I would install every program I needed as I needed it, with no real plan of how I would replicate the setup if I needed to move to a different machine, or wipe the current one.
Tellingly, the one thing that I <em>did</em> make an effort to protect was my Vim config, which I&#39;ve been maintaining for five years at this point (I have been a software developer for 5 years).
I want more things to be like Vim, so, I should decided to setup my computer with Ansible.</p>
<p>As well as having a good name (presumably from Ursula Le Guin&#39;s interplanetary communcation macguffin), Ansible is a really cool and useful tool.
It lets you write some yaml that explain things you want doing to a computer. Then it takes this recipe and runs the specified commands.
So for example I have the following command to download the codebase of my personal website, where I wrote this post that you are now reading.</p>
<h2>Ansible</h2>
<pre><code class="language-yaml">- name: Personal Project johncom
  ansible.builtin.git:
    repo: &#39;git@github.com:Jwhiles/johncom.git&#39;
    bare: false
    dest: &quot;{{ lookup(&#39;env&#39;, &#39;HOME&#39;) }}/personal/johncom&quot;
  tags:
    - install
    - personal-project
</code></pre>
<p>This means that I can get a new computer, run ansible and the codebase will be immediately be there, ready for me to write things in it. Nice!</p>
<p>I&#39;m also using Ansible to:</p>
<ul>
<li>install all the homebrew packages I want</li>
<li>store my ssh keys</li>
<li>set up a cronjob to sync my weird and overly complicated multicomputer note taking system</li>
<li>ETC</li>
</ul>
<p>Cool! I love it.</p>
<p>Ansible seems to be the imperative equivalent to something like Nix.
In ansible I&#39;m describing the steps I want it to take to get my computer in order, whereas in Nix I would just describe the computer I wanted and it would hopefully give it to me.
One advantage of ansible is that it&#39;s slightly less likely to fill my entire hard drive storing slightly different versions of GHC. So that&#39;s nice.</p>
<h2>Stow</h2>
<p>As well as setting up a new repo to hold my Ansible config, I&#39;ve converted my beloved repo &#39;vimmy&#39; into a more general dotfiles repo.
It&#39;s now called <a href="https://github.com/Jwhiles/dotfiles-FKA-vimmy">dotfiles-FKA-vimmy</a>, and alongside my Vim config also contains some other configuration files.</p>
<p>Stow is a CLI tool for managing symlinks, that has allowed me to replace an ugly script I once wrote:</p>
<pre><code class="language-sh">echo &quot;adding the appropirate nvim init file&quot;
mkdir -p ~/.config/nvim
ln -s ~/.vim/init.lua ~/.config/nvim/init.lua
ln -s ~/.vim/lua ~/.config/nvim/lua

echo &quot;creating symlink to .tmux.conf&quot;
ln -s ~/.vim/.tmux.conf ~/.tmux.conf

echo &quot;done and done 👻 &quot;
</code></pre>
<p>With a new beautiful script that does basically the same thing but better:</p>
<pre><code>pushd $HOME/.dotfiles

echo &quot;stowing nvim&quot;
stow nvim
echo &quot;stowing tmux&quot;
stow tmux
echo &quot;stowing zsh&quot;
stow zsh
</code></pre>
<p>Stow seems really neat, but it does have a slightly weird behaviour where it places all symlinks in the folder one step up from your working directory.
So try and make sure that you run in it the right place ;)</p>
<h2>Spotifyd and spotify-tui</h2>
<p>Like most people in my demographic group, I listen to a lot of music on spotify. But I <em>hate</em> the spotify client. It&#39;s really slow and bad, and continually getting worse.
Whilst setting up all this computer stuff, I idly searched something like &#39;native spotify client&#39;, and lo I found two incredible Rust programs.</p>
<p><img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/51oVp5HzrjuX67ffYmxdwG/9d3f2db43bf243e257e66b742232800e/spotterm.png?w=800&fm=webp alt=Spotify Terminal /></p>
<p>Spotifyd is a daemon that can sit running on your computer, waiting for spotify to send music for it to play. spotify-tui is a terminal application that lets you browse music, and play it on any connected devices.
Using the two together lets me have music controlled and played through the terminal. It&#39;s much faster than the normal Spotify client, makes you look like a real hacker, and only shows a few inexplicable errors.</p>
<p>It took me a bit of a struggle to get spotifyd to actually run successfully.
It seems like it will just fail quietly unless you have a valid config, and some of the default config values aren&#39;t valid on Osx, I think (I might be wrong about this, but if I&#39;m right it seems like a nice thing to try and fix). Now it works though, and I love it.</p>
<h2>Tmuxinator</h2>
<p>Imagine you are a complete maniac and have decided to use some horrible setup where you listen to music in your terminal by using two different command line tools that both need to be running at the same time.
How do you go about actually opening and running these things in less time than it would take to open the normal Spotify client (~30seconds).
Let me introduce you to Tmuxinator. It&#39;s nice little tool that lets you write some YAML to describe a tmux session you&#39;d like to start.</p>
<p>For example:</p>
<pre><code class="language-yaml"># /Users/johnwhiles/.config/tmuxinator/music.yml

name: music
root: ~/

windows:
  - spotify: spt
  - daemon: spotifyd --no-daemon
</code></pre>
<p>This configures a TMUX session that will open with two panes, one running spotifyd, and the other running spotify-tui.
Now we can start our weird music listening setup by typing <code>tmuxinator start music</code>, this is both easy <em>and</em> is exactly the sort of thing I imagined I would be saying to computers in 2022.</p>
<h2>Conclusion</h2>
<p>Ansible is cool. You can see <a href="https://github.com/Jwhiles/ansible">my setup on Github</a>. I originally forked it from <a href="https://github.com/adamchainz/mac-ansible">this repo</a>, and also to a look of inspiration from <a href="https://github.com/ThePrimeagen/ansible">The Primeagen&#39;s setup</a>.</p>
<p>BYE!</p>
]]></content>
          <pubDate>Thu, 06 Oct 2022 23:00:00 GMT</pubDate>
          <link>https://johnwhiles.com/posts/the-new-dots</link>
          <guid isPermaLink="true">https://johnwhiles.com/posts/the-new-dots</guid>
        </item>
        <item>
          <title><![CDATA[What I Read On Holiday]]></title>
          <content type="html"><![CDATA[<h1>What I read on Holiday</h1>
<p>I went on Holiday to Greece (it&#39;s nice) which is why I didn&#39;t update this website for a while. Here are some thoughts about the books I read on holiday. Some of them I even finished!</p>
<h2>The Overstory by Richard Powers</h2>
<p>Short stories offer writers the chance to experiment with form, subject matter, narrative. They allow a writer to try ideas that won&#39;t stretch to the length of a novel, ideas that readers wouldn&#39;t tolerate for long, or even ideas that are just not that good. The best short story writers can do more in a few pages than most people can with 80,000 words, or hours. Think of Kafka, Borges, or any Russian writer.</p>
<p>Richard Powers uses the short story in order to repeat himself over and over again, each repetition increasingly boring and ridiculous. The book is a sort of boiling frog endurance test. Most readers can take the first few stories. You enjoy the first, the second is okay, the third elicits a certain queasiness. Only paid reviewers get much further. From reading the wikipedia page it appears that the Overstory isn&#39;t just a collection of short stories, but the part that I read seemed to be and I will review it as such.</p>
<p>So what is the story that we are repeatedly told in this book? We meet a character, and their family. Then we tear through decades of their life. Invariably this is a life which is <em>very</em> dramatic. Something very bad generally happens. </p>
<p>The characters in these stories come from all walks of life. They are born in disparate countries and circumstances. Mostly they immigrate to the USA. All these characters however are obviously actually middle class Americans. In fact they are all obviously the author, Richard Powers.</p>
<p>The unique selling point (USP) of the stories is that there is a theme that connects them. Not only are they all the same story, they also share a thematic bond. What is the theme? It&#39;s trees. Every story features trees. The trees will be tied into the story a bit. Maybe the trees will be a metaphor for the human characters. Maybe there will be four children, and then their dad will plant four trees (one for each kid). Maybe then another child will be born. Maybe dad will plant another tree (THE TREES ARE THE CHILDREN)! Something bad will happen to some of the trees, and also to some of the children (THE CHILDREN ARE THE TREES). The use of the theme of trees allows us to see that humanity and nature is connected. The tree theme is a very high level and powerful literary device.</p>
<p>According to the &#39;Reception&#39; section of this book&#39;s wikipedia page it has won a Pulitzer Prize and was shortlisted for the Man Booker Prize. One reviewer called it &quot;a deep meditation on the irreparable psychic damage that manifests in our unmitigated* separation from nature&quot;. In truth &#39;The Overstory&#39; is a piece of experimental writing that seeks to test how much irreparable psychic trauma can can be inflicted by having someone read the same boring story again and again forever.</p>
<p>2/5</p>
<ul>
<li>lol</li>
</ul>
<h2>The Idiot by Elif Batuman</h2>
<p>I loved this. &#39;The Idiot&#39; fits neatly into my favourite genre: &#39;plotless books where nothing much happens to a weird narrator&#39; (see Tao Lin, Tom McCarthy etc). The book follows an 18 year old through thei first year at College. They spend this year studying topics of little utility and become infatuated with an annoying and pretentious man. Then they go to Hungary for a bit, then they come back.</p>
<p>The narrator gets an email account on arriving at university, and their life quickly splits into real life and email life - where the email life is the one they care more about. Batuman said that this book was written in/near the nineties, and that time has turned it into a historical novel. The email obsession is one manifestation of this, as are the strangely abundant unix references, and the inability to easily contact people. It&#39;s strange to read modern western characters who have problems caused by not being able to get in contact with someone they want to talk to. Such difficulties are unimaginable now.</p>
<p>4/5</p>
<h2>Exhalation and Stories of Your Life and Others by Ted Chiang</h2>
<p>Short stories offer writers the chance to experiment with form, subject matter, narrative. They allow a writer to try ideas that won&#39;t stretch to the length of a novel, ideas that readers wouldn&#39;t tolerate for long, or even ideas that are just not that good. The best short story writers can do more in a few pages than most people can with 80,000 words, or hours. Think of Kafka, Borges, or any Russian writer.</p>
<p>Ted Chiang uses the short story to imagine worlds where the rules of reality and fundamentally different. He comes up with a wild concept, and then follows that concept to its conclusion, or near enough. I&#39;ve seen these stories referred to as being science fiction, but I think they tend to be more extreme than that genre generally allows for. For example one story is the idea of young earth creationism, and imagines what a universe where that could be true looks like. It is very strange. These stories often take a while to reveal their conceit, and part of the pleasure of reading them is gradually coming to understand what freaky thing Ted has come up with this time.</p>
<p>The stories in these books have won a wide variety of science fiction prizes, but nothing nearly as prestigious as those won by &#39;The Overstory&#39;. Make of that what you will.</p>
<p>4/5</p>
<h2>Dept of Speculation by Jenny Offill</h2>
<p>The story of a marriage told through the medium of semi-connected aphorisms. Every chapter exudes an oily film of misery. Like Nietzsche if he got mixed up between life affirming and life disavowing. And was married.</p>
<p>It kind of seems like the author read Renata Adler&#39;s <a href="https://en.wikipedia.org/wiki/Speedboat_(novel)">Speedboat</a> and thought &#39;what if I do that but less enjoyably&#39;.</p>
<p>I&#39;ll be honest, I didn&#39;t really read enough of this book to be able to rate it fairly. Maybe it gets better, maybe I just wasn&#39;t in the right frame of mind. Maybe I need to stop reading novels written by Americans.</p>
]]></content>
          <pubDate>Sun, 12 Jun 2022 23:00:00 GMT</pubDate>
          <link>https://johnwhiles.com/posts/what-i-read-on-holiday</link>
          <guid isPermaLink="true">https://johnwhiles.com/posts/what-i-read-on-holiday</guid>
        </item>
        <item>
          <title><![CDATA[Shaving Is Too Expensive. Also the world is out to get you]]></title>
          <content type="html"><![CDATA[<h1>Shaving is too expensive</h1>
<p>Shaving is too expensive and is a demonstrative example of how most consumer products are designed to extract more money from you rather than to improve your life, or the world, or to be in any way remotely good.</p>
<p>The razors most people use where I live look like this:</p>
<p><img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/2Yt3zTwpX2DgIaBPqsdr1h/ec639fc6e299c0ee835958fdffd90761/gilette.png?w=800&fm=webp alt=gilette /></p>
<p>A set including the razor body and some heads generally costs a little above £20<sup>1</sup> and replacement heads cost in the region of £1.75. Gillette claim that each blade can be used for 15 shaves. This sounds pretty optimistic to me. But who knows. If you shave daily this implies a cost of 87 pence weekly, or around 45 pounds annually. This also means that the razor body effectively costs about 5 pounds, and is probably a loss leader.</p>
<p><img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/5N2Pg5DV7TABGmPIFd3bvo/2bed91fbc459c747deba89fa83f0fd86/gbus.jpeg?w=800&fm=webp alt=Totally normal advert /></p>
<p>Before this style of razor became popular, most people used what is known as a double edged razor. The bodies of these razors seem to be generally more expensive: a good quality one might be around £40. Though you can pay more, or less. The blades are significantly much cheaper. Blades can be had for £0.08 pence each. These blades are probably good for something like 3 to 5 shaves. Let&#39;s say 3 to make this as generous to gilette as possible. Assuming daily shaving that gives us a cost of 18 pence weekly, or about 10 pounds annually.</p>
<p><img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/5IPDK0pnvzNN9P5SP04Z6a/8ba91fbb279c4a5f42635653cba3005b/merkur.jpeg?w=800&fm=webp alt=Merkur 34C /></p>
<p>So we see a slightly larger initial outset, which is quickly dominated by the higher ongoing cost of the typical modern razor. If you expect that you will continue shaving for a year, then it is more cost effective to use a double edged razor.</p>
<p><img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/1XXlzJxX7DDMpgYJMGQBM7/ed4c186907594356b2524bc441c98368/graph.png?w=800&fm=webp alt=Graph of shaving costs /></p>
<p>So the double edged razor is cheaper. Clearly. There are other obvious benefits of this style of razor. They produce dramatically less waste. Depending on the brand you purchase, the blades might just be packaged in waxed paper. Cartridge blades on the other hand come packaged in multiple layers of plastic, and are deliberately over packaged so that they are more visible in shops. Changing to double edged razors means a big reduction in single use plastic consumption - which is something people claim to care about. </p>
<p>It is, however, hard to find these sorts of razors. If you go into a shop to buy a razor, you will almost certainly not be able to buy one - but you will be faced with a wide range of very similar cartridge razors. The double edged razor has become a product that you can only buy on the internet, and which you will only buy if you know that it exists.</p>
<p>So, does this matter? I assume that for most of the people reading this, the sums of money involved may seem pretty trivial. But I think the changes in the razor market are obviously bad, and reflect similar changes that can be seen in many other markets. We see new products launched which promise minor benefits in convenience, and which crowd out older, cheaper, and better products. Those older products are deliberately marginalised, and more money is captured from consumers without them really gaining any value from their expenditure.</p>
<p>It is good to build the habit of skepticism in the face of consumer products. By avoiding products, like cartridge razors, you are producing less waste, saving money which you can dedicate to any purpose that is important to you, and I think that not doing the thing that the market wants you to do is probably just good.</p>
<p>Other examples of products that seem to exhibit a similar trend, where purported convenience leads to higher prices</p>
<ul>
<li>Cooking equipment: essentially indestructible Cast Iron skillets transition into teflon pans. The newer pans perform worse, and must be replaced on a shockingly regular basis. They also seem to be poisonous.</li>
<li>Shaving foam: soap pucks transition to self foaming aerosol canisters</li>
<li>Tea bags replace loose leaf tea. Allows for lower quality tea to be sold, diminishes the re-use of tea leaves. Also ludicrous  product differentiation along the lines of &#39;we have a special shaped tea bag&#39;.</li>
<li>Nespresso machines, and other coffee pod brands, replace many styles of coffee brewing. Provide much worse coffee, at a higher price but are superficially convenient.</li>
<li>Well understood mechanical bike shifting transitions to electronic shifting which requires you to <em>pay more and charge your pedal bike</em> (Not sure about this example, as in theory a bike derailleur needs not be a repeated purchased)</li>
<li>Televisions moving from being screens which accept input, to self contained &#39;smart&#39; devices that require software updates and thus have a shortened useful lifespan.</li>
<li>In many inner city shops it is now hard to buy an individual piece of fruit. </li>
<li>Subscription services like Hello Fresh, where you can pay well over the odds to have some vegetables delivered to you.</li>
</ul>
<p>I don&#39;t want to suggest that all new product developments are essentially hostile to you, but certainly a lot of them are. Pay attention to what you buy, especially when you are changing from an old well understood product to a new, more convenient, equivalent. The world is not your friend.</p>
<hr>
<p><sup id="marked-fn:1">1</sup> <a href="https://amzn.to/3ktyfmr">This gillette set is the top result for razor on amazon at time of writing, and costs 23.75</a></p>
]]></content>
          <pubDate>Fri, 06 May 2022 23:00:00 GMT</pubDate>
          <link>https://johnwhiles.com/posts/shaving</link>
          <guid isPermaLink="true">https://johnwhiles.com/posts/shaving</guid>
        </item>
        <item>
          <title><![CDATA[Six things I sort of believe about making music/art]]></title>
          <content type="html"><![CDATA[<h1>Six things I sort of believe about making music</h1>
<h2>Good beginnings</h2>
<p>I&#39;ve now been recording music at home for most of my life. I started at around 14. I would record things into audacity, sometimes with my friend Cameron, but more often by myself. I had no real idea of how to write, arrange, or record music. Besides a few covers I would mostly record incredibly abstruse &#39;experimental music&#39;. I would make &#39;field recordings&#39; then manually edit them and add random effects I could find until I got something that sounded good to me.  Here&#39;s an example (ignore that this was published in 2016, I recorded it way earlier).</p>
<iframe style="border: 0; width: 100%; height: 120px;" src="https://bandcamp.com/EmbeddedPlayer/album=3141982008/size=large/bgcol=ffffff/linkcol=0687f5/tracklist=false/artwork=small/track=4009456494/transparent=true/" seamless><a href="https://johnwhiles.bandcamp.com/album/pointless-deeds">pointless deeds by John Whiles</a></iframe>

<p>At this point I was recording using the cheapest microphone that was available at our nearest computer store. My parents got me so I could talk to strangers on the internet while playing Guild Wars.</p>
<p>When I tried to record more traditional multi tracked music I would play the existing music through my computer speakers whilst recording. After a few layers this would start to lead to huge build ups of certain frequencies - usually bass - which would make everything sound muddy, and would probably upset anyone that tried listening with a subwoofer.</p>
<p>For a while I didn&#39;t really understand why all my recordings had this issue, I would try and EQ out the bass notes - but that never worked very well. Eventually I discovered that if I monitored using headphones I didn&#39;t get the same problem. This was a huge epiphany for me, and was a massive step forward in my ability to record things. This leads to my first lesson</p>
<blockquote>
<p><em>1: Try and record the thing well in the first place. It&#39;s the best and easiest way to get a good result.</em></p>
</blockquote>
<h2>Technology</h2>
<p>As I mentioned: my microphone was awful. Eventually I bought a slightly more expensive USB microphone that could make things sound reasonably nice. At this point I realised I had horrendous latency issues.</p>
<p>I had moved from Audacity to Ableton, where I would listen back to my recordings, trying to overdub new parts, feeling like I was playing pretty tight and in time. But when I listened back my playing would sound totally off. I was always miles behind the beat, sounding incredibly sloppy and rhythmless. For months I thought this was a deficiency in my playing, until eventually I discovered some latency setting, read about what latency was and realised what was going on.</p>
<p>I tried my best to fix my latency problems, failed, put up with it for ages, and then eventually used my student loan to buy an audio interface and a shure SM57 microphone. These are two of the best buys I’ve ever made. I could suddenly record things that were pretty much in time, and also everything I recorded sounded way way better. So this leads to lesson two</p>
<blockquote>
<p><em>2: Sometimes (but not very often) your equipment actually is the issue. If you want to record audio, you should buy an audio interface.</em></p>
</blockquote>
<h2>Deadlines</h2>
<p>So at this point I had the sufficient technical skills and the equipment necessary to record basically any music that I would want to make. But I started running into what is a very common problem. I would never finish anything. I’d start pieces, make reasonable progress, and then spend hours making irrelevant changes no one would notice getting more and more confused about what I was doing, and whether the piece I was working on was any good. Finally I would give up, start something new, and leave whatever I had been working on to fester forgotten on some external harddrive. As far as I know that’s where it still remains today.</p>
<p>This was bad. I now believe that the best way to improve at anything is to finish work, put it out into the world, and see how people respond. Spending hours finessing things you will never release is a recipe for frustration and stagnation. The only time I would manage to release anything would be during weird semi manic episodes when I would have time by myself, feel full of ideas and manage to record a bunch of stuff in one day. For example, I recorded these three tracks in one morning/afternoon. They&#39;re by no means good music, but they are at least interesting - and ‘finished’, which is more than could be said for most of the things I worked on at this time.</p>
<iframe style="border: 0; width: 100%; height: 120px;" src="https://bandcamp.com/EmbeddedPlayer/album=4265090986/size=large/bgcol=ffffff/linkcol=0687f5/tracklist=false/artwork=small/transparent=true/" seamless><a href="https://johnwhiles.bandcamp.com/album/late-september">Late September by John Whiles</a></iframe>

<p>Anyway, I eventually discovered a life changing life-hack which I have now used for years to force myself to finish and release music. It’s called ‘Christmas Music’.</p>
<p>Yes, Christmas Music.</p>
<p>It&#39;s the perfect tool to force an over thinking musician to buckle up and finish something. It provides three key benefits:</p>
<p><em>A theme</em> - what to write about is always a hard question. Christmas music massively narrows your options, and gives you a world of existing references to draw on.</p>
<p><em>Low Stakes</em> - Generally people don&#39;t like Christmas music, and consider it as essentially a joke. When you release your art into the world, it always feels like the stakes are high, even when there is absolutely no risk involved. If you can tell yourself &#39;no need to worry it&#39;s just christmas music&#39;, then you have art without fear</p>
<p><em>A DEADLINE</em> - This is the real key. Christmas music needs to come  out before Christmas. So you have to finish it. Voila.</p>
<iframe style="border: 0; width: 100%; height: 120px;" src="https://bandcamp.com/EmbeddedPlayer/album=1456816301/size=large/bgcol=ffffff/linkcol=0687f5/tracklist=false/artwork=small/track=3532821321/transparent=true/" seamless><a href="https://johnwhiles.bandcamp.com/album/the-second-christmas-another-winters-evening-with-john-whiles-were-our-hearts-ever-so-cold">The Second Christmas: Another Winter&#39;s Evening with John Whiles: Were Our Hearts Ever so Cold? by John Whiles</a></iframe>

<p>I&#39;ve now released some sort of Christmas music every year since 2013. Some is good. Some is bad. But it all exists and is published.</p>
<blockquote>
<p><em>3: You need to find ways to force yourself to finish things. Arbitrary deadlines are actually sometimes good.</em></p>
</blockquote>
<h2>Technology again (benefits)</h2>
<p>At some point I started getting more involved (lurking) in online communities that focused on music production. I realised that there were lots of things that I could have learnt faster by watching tutorials. I also realised that lots of people had lots of cool equipment that let them create lots of weird sounds. This coincided with me having my first job, and thus disposable income to spend on luxuries. So I bought an Arturia MiniBrute and a Dreadbox Erebus. I love both of these synths, which I would use together and play into my recordings. They opened up a new world of sounds for me - even though I&#39;d been using their software equivalents for years. Being hands on with the controls of these things finally made me understand how subtractive synthesis worked - and pushed my music in a much more electronic direction.</p>
<blockquote>
<p><em>4: using different tools and equipment can shake up your established processes and let you create things you wouldn&#39;t have otherwise</em></p>
</blockquote>
<h2>Technology again (dangers)</h2>
<p>So this was a good time, and I was making music I was happy with. At some point I became a software engineer, had more disposable income, and had discovered the concept of modular synthesisers. Obviously this is a terrible combination. I bought some modules, built a system and really enjoyed playing it. Being able to make pretty complex music without having to look at my laptop felt like a real gift.</p>
<p>The problem was that the music I was making had changed entirely. This is the first coherent release I made with the new setup:</p>
<iframe style="border: 0; width: 100%; height: 120px;" src="https://bandcamp.com/EmbeddedPlayer/album=313933251/size=large/bgcol=ffffff/linkcol=0687f5/tracklist=false/artwork=small/transparent=true/" seamless><a href="https://johnwhiles.bandcamp.com/album/turning-to-ice">Turning to Ice by John Whiles</a></iframe>

<p>it bears no relation to my previous work which, as mentioned, I liked and enjoyed making. But now I was spending all my music time on modular music, which was not really interesting to anyone besides myself, and my ability to make the kind of music I had before melted away as I didn&#39;t use it. Which leads to my next <del>lesson</del> warning:</p>
<blockquote>
<p><em>5: Tools and equipment impose themselves on you. If you change your processes too much it is hard to built up an identity other than as someone who is inconsistent.</em></p>
</blockquote>
<h2>Affirming ending</h2>
<p>I&#39;ve more recently been moving back towards making more structured music, and integrating my various musical interests. It&#39;s exciting and I am looking forward to having something finished which I can share. Which leads me to final point:</p>
<blockquote>
<p><em>6: Making your own work is a good thing to do, even if no one else is interested in what you are making. To create is to be human</em></p>
</blockquote>
<hr>
<h3>By the way</h3>
<p>I&#39;ve been talking about music. But I think these ideas roughly track onto any other creative endeavour (including bodybuilding). If you think they don&#39;t I&#39;d love to talk about it, but I&#39;m actually quite busy right now.</p>
]]></content>
          <pubDate>Sat, 23 Apr 2022 15:00:00 GMT</pubDate>
          <link>https://johnwhiles.com/posts/music-production-lessons</link>
          <guid isPermaLink="true">https://johnwhiles.com/posts/music-production-lessons</guid>
        </item>
        <item>
          <title><![CDATA[Arnie films I’ve watched recently]]></title>
          <content type="html"><![CDATA[<h1>Arnie films I’ve watched recently</h1>
<p>I&#39;ve been watching a lot of Arnie films recently. Partially this is as body building inspiration and partially because I&#39;ve realised that he is the greatest and most charismatic actor of all time.</p>
<p>Here are some short reviews of the films I&#39;ve seen recently.</p>
<h2>Terminator 2</h2>
<p>Incredible. The best action film I’ve ever scene. This film takes the paper thin concept of the first film and runs with it in a really smart way. Sarah Connor tries to warn people about her experiences with the Terminator, naturally everyone thinks that she&#39;s mad. She&#39;s locked up in an abusive mental institute, and by the time we get to the action of the film she&#39;s completely cracked to the point that she can&#39;t trust anyone, whether human or robot.</p>
<p>Every action scene is glorious, the two chase sequences in particular are really nicely done.</p>
<p>There’s a child actor who isn’t awful. Arnie is in it. Something someting computers AI very of the moment reflects current concerns blah blah blah.</p>
<p><img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/146QFnzc4hLgkMsmTyL4Y9/da7a1c4326b9c55f99e09d434ad82521/conor.jpeg?w=800&fm=webp alt=Sarah Connor /></p>
<p>The one problem with this film is the too long and too boring final showdown. Every action film seems to have one of these. Why? I don’t know. Cut more.</p>
<p><strong>5/5</strong></p>
<hr>
<h2>Total Recall</h2>
<p>Another great film. Arnie looks great in it. I particularly enjoyed how sweaty is in the first scene when he wakes from a nightmare.
<img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/2GWYTtrjl2xgjMa9qbDcdW/96dff20fe87c3aa792cb4b394798a359/recall.jpeg?w=800&fm=webp alt=total recall /></p>
<p>This film has <em>style</em>. It&#39;s got vibes. It&#39;s a real good time, and I never stopped being shocked by how ridiculously violent it is.</p>
<p><strong>5/5</strong></p>
<hr>
<h2>Predator</h2>
<p>I really enjoyed this film up until the predator is introduced.</p>
<p>It starts with that handshake:</p>
<p><img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/5VVEUgNVwutzHVRwmMUrWk/76665f2a6a07131b37d21d362c0d6ec7/clasp.jpeg?w=800&fm=webp alt=Clasp /></p>
<p>Then there&#39;s a delightfully weird chopper flight and then a the most over the top fire fight ever put on film. Then the predator arrives, and is painfully slow and clunky and stupid looking. The rest of the film is a bit of drag from this point. It&#39;s a shame because the cast are great - and this could have been a super film if it had been almost entirely different.</p>
<p>I did enjoy how there is no attempt to explain anything that happens in after the predator is introduced. What is the predator? We don&#39;t know. Why is it there? We don&#39;t know. Why was the film made? Unclear.</p>
<p>I recommend just watching the first half a hour and then imagining the rest of the film. I like to imagine something a bit like Snake Eater. This would mean you&#39;d miss out on the scene where Carl weathers takes his top off though.</p>
<p><strong>2/5</strong></p>
<hr>
<h2>Next time</h2>
<p>The next Arnie films I hope to watch and review are Running Man, Twins and Junior. I expect that they will all be good. If you have other suggestions for films I should watch please get in touch.</p>
]]></content>
          <pubDate>Sat, 16 Apr 2022 23:00:00 GMT</pubDate>
          <link>https://johnwhiles.com/posts/arnie-films-part-one.mdx</link>
          <guid isPermaLink="true">https://johnwhiles.com/posts/arnie-films-part-one.mdx</guid>
        </item>
        <item>
          <title><![CDATA[Against moderation]]></title>
          <content type="html"><![CDATA[<p>When people want to change themselves, their habits, their lifestyles, the approach they usually take is to moderate or attenuate existing behaviour. We take what we are already doing, gently change it in the way that seems the least disruptive and painful and hope that over time we will gradually reach our desired state. We might see that we are physically unfit, and start trying to walk more instead of driving. Or we might realise that we drink too much and decide to try cut down the amount of alcohol we consume. </p>
<p>This approach sounds pretty sensible. It&#39;s easy to assume that the smaller a change is, then the easier it is to accomplish. There is a language of &#39;weaning ourselves off of things&#39;, &#39;cutting back on treats&#39;, &#39;trying to get a bit more exercise&#39;. </p>
<p>The problem with this style of moderation though, is that it lacks strong boundaries on behaviour. Any approach designed to be &#39;easy&#39; will tend to privilege existing behaviours. Think of a weight conscious person. Most people trying to lose weight will &#39;cut back&#39; on certain foods. But many diet plans contain &#39;cheat nights&#39;; the diet is survivable only because we know we will be able to eat what we really want at the end of the week. Alternatively, we start treating our previous behaviour as a reward for any successes. </p>
<p>This teaches us that our original behaviour, which we ostensibly want to outgrow, remains our default. It is what we revert to to celebrate, and when we lose willpower in the face of setbacks or peer pressure, it is what we revert to try and feel normal again.</p>
<p>If we try to moderate existing behaviour then we are really telling ourselves that whatever our previous default behaviour was, it remains just that - the default. It is the baseline we operate from, which we would happily slip back into. We are acting in a way that implies we will return to this behaviour in time.</p>
<p>Approaching behaviour change like this has never worked for me. I find it incredibly hard to do something in moderation which I am accustomed to doing <em>ad libitum</em>. </p>
<p>Instead, what has worked for me, and what I am proposing you should try - is to become extremely obsessive about whatever it is you want to do. If you want to start doing something. Do it all the time. If you don&#39;t want to do something, then <em>never do it again</em>. </p>
<p>So why does this work better? If we compare</p>
<ul>
<li>Doing something infrequently
and</li>
<li>Never doing something again</li>
</ul>
<p>The former sounds easier. But it&#39;s not. Every time you do something, you are training yourself to do that thing. Think of spaced repetition, where we repeatedly learn something we extend the amount of time that it exists in our memory. I think that there is a similar effect for behaviour, every time you do something you extend the amount of time that it will remain a thing you feel like you need to do.</p>
<p><a title="Biopresto, CC BY-SA 3.0 &lt;https://creativecommons.org/licenses/by-sa/3.0&gt;, via Wikimedia Commons" href="https://commons.wikimedia.org/wiki/File:ForgettingCurveITASRS.png"><img width="512" alt="ForgettingCurveITASRS" src="https://upload.wikimedia.org/wikipedia/commons/thumb/3/38/ForgettingCurveITASRS.png/512px-ForgettingCurveITASRS.png"></a></p>
<blockquote>
<p><em>This was the only creative commons licensed version of this diagram I could find. Sorry</em></p>
</blockquote>
<p>So what are some examples of how you might apply this? </p>
<p>If you want to stop doing something, let&#39;s say eating pizza, then don&#39;t at the end of a long work week celebrate your temporary freedom by eating a big celebratory pizza. And then simply never eat pizza again.</p>
<p>If you want to start doing something, then start doing it every day - or on set schedule which you never deviate from. So if you want to get better at painting, paint every day. If you want to stop driving to the shop, sell your car.</p>
<p>People think that moderation is an easy to get where they want. But moderation is the hardest thing in the world.</p>
<hr>
<p>There are some downsides to this approach. People will think you are weird. Because you are. Worse though, a lot of people will try and convince you to act normally, even if you explicitly tell them that you are trying to change something about yourself that is important to you. You can often see this in the case of people trying to convince friends who they know are trying not to drink, to start drinking again. Or telling someone who is dieting to not worry, and to just eat whatever boring cake they&#39;ve made. I don&#39;t know why people do this, and I think it&#39;s bad.</p>
<p>Also, to moderate my claims somewhat. I think that after you&#39;ve done something for long enough that it has become your default behaviour then it is actually fine to stop being weird and obsessive about it. You can slip up. For example, I am so used to regular exercise now, that going for a few days without it feels weird. I don&#39;t worry about missing a planned workout, because I know it won&#39;t be the start of a slippery slope. It is of course very hard to know when you have reached this point for any given behaviour.</p>
<p>There are also simple things you can do to make adopting new behaviours, like painting every day, or playing your musical instrument much easier. The easiest, and most effective thing, is to have your paints, instrument, whatever, set up and ready to go. Everyone says this, and it sounds kind of stupid, but it works.</p>
]]></content>
          <pubDate>Sat, 09 Apr 2022 23:00:00 GMT</pubDate>
          <link>https://johnwhiles.com/posts/against-moderation</link>
          <guid isPermaLink="true">https://johnwhiles.com/posts/against-moderation</guid>
        </item>
        <item>
          <title><![CDATA[Maybe you should do less “work”]]></title>
          <content type="html"><![CDATA[<h1>Maybe you should do less “work”</h1>
<p>Working in tech, I&#39;ve observed developers who work as hard as possible when they don&#39;t need to.  I’m here today to tell you that it&#39;s a bad idea and you shouldn&#39;t do it.</p>
<p>What do I mean by working as hard as possible? I mean someone who can finish all the work that is expected of them in less than the total time that they are meant to spend working and then asks for more, similar, work to do. I also mean someone who has no real sense of how much work <em>is</em> expected of them and then drives themself at an unsustainable pace trying to meet a standard which they can never meet because they already met it a long time ago and never realised and they are still worried about how others will perceive them and oops now they&#39;re burned out I guess.</p>
<p>I believe that:</p>
<ul>
<li>you should try and figure out what expectations your colleagues and managers have of you. And also what you expect of yourself.</li>
<li>If you can meet these expectations in fewer hours than you are supposed to work, then you shouldn&#39;t just find more to do. Instead you should do something different.</li>
</ul>
<h2>How do you figure out what people expect of you?</h2>
<p>If you haven’t been fired, and no one has taken you aside to ask about your performance, then probably you&#39;re meeting expectations. You can also look at what your peers are doing or you can just ask people how they perceive you.
It&#39;s also probably good to exceed expectations instead of just meeting them. But in most tech companies this is probably easier than you think.</p>
<h2>Why shouldn’t you spend as much time as possible doing &#39;work&#39; work.</h2>
<p>If you optimally fill your time at work doing &#39;work&#39; work, then this means that you are likely:</p>
<ul>
<li>Not developing other skills</li>
<li>Not building your network inside the company as well as you could</li>
<li>Probably working less efficiently than you could</li>
<li>Unable to respond to new or changing demands without working longer hours or stopping something else that you think you need to do. See the ongoing supply chain crisis for why you should have some slack in your system.</li>
</ul>
<h2>What should you do with the time that I’m suggesting you shouldn&#39;t spend doing more work?</h2>
<p>You should try and spend your time in ways that will benefit you <em>and</em> your employer.</p>
<p>How you do this will vary a lot based on where you are in your career, what you value, and what your company values.
If you&#39;re new in your career - then I think it makes sense to dedicate a good chunk of your time to learning and broadening your horizons. For example, at my first tech job, where I was a Frontend JavaScript developer, I spent about 20% of my time learning Haskell. This didn&#39;t offer any immediate value to me, or the company. But it got me outside of my box of frontend development, and I think generally made me fitter, smarter and more productive. You should choose to learn things that help you move towards the role that you want in the future.</p>
<p>If you&#39;re later in your career, and don&#39;t feel like there&#39;s anything you desperately need to learn - there might still be better ways to spend your time than just taking more tasks off a todo list. You should mentor more junior staff. You should use your experience and understanding to figure out what important things aren&#39;t being focused on. Sometimes you should just stare into space until you remember that everything is going to go catastrophically wrong once you record more than 4.29 billion events in that one table, I know five years ago we said it&#39;ll never happen and if it does, well we&#39;ll worry about it when we get to it, and anyway that&#39;s a good problem to have it means we&#39;re really racking up the users, so how about a game of table tennis.</p>
<p>Obviously I don&#39;t practise any of what I talk about here, and diligently ensure that I spend all my time at work delivering business value. </p>
<h2>references/evidence</h2>
<p><a href="https://amzn.to/3waG5E2">A Mind For Numbers</a> contains a lot of useful ideas for how to work more effectively.</p>
<p><a href="https://danluu.com/learning-to-program/#:~:text=At%20that%20point%2C%20I%20did,every%202%20or%203%20days.">Dan Luu talking about reading books at work</a></p>
<p><a href="https://thezvi.wordpress.com/2017/09/30/slack/">Ex-pro magic the gathering player on slack, no not that Slack</a></p>
<p><a href="https://jvns.ca/blog/2017/08/06/learning-at-work/#:~:text=Take%20the%20time%20at%20work%20to%20learn">Julia Evans talks about learning at work here.</a>. I remembered reading something about spending time learning while working remotely because &#39;no one knows what I&#39;m doing anyway&#39;, but now that I look it up, this article says a lot more, and I think covers everything I&#39;ve said here but better. So I guess there was no reason to write this oh well. good bye</p>
]]></content>
          <pubDate>Sat, 26 Mar 2022 23:00:00 GMT</pubDate>
          <link>https://johnwhiles.com/posts/work</link>
          <guid isPermaLink="true">https://johnwhiles.com/posts/work</guid>
        </item>
        <item>
          <title><![CDATA[Linking in to LinkedIn]]></title>
          <content type="html"><![CDATA[<h1>Linking in to LinkedIn</h1>
<p>I logged into LinkedIn today hoping to congratulate ex-colleagues on their 
new roles and pursue shadowy offers from normy recruiters. LinkedIn saw its opportunity and pounced. It informed me that I needed to improve my intentionally spare profile.
That doing so would mean more and better shadowy offers from more and better normy recruiters. </p>
<p>I hate writing about myself. Or at least I hate it when I have to write in the form of a self description, or a cover letter.
LinkedIn knows this, and had written a profile for me.
I was obviously overjoyed.
I could improve my job prospects without actually writing anything, or expending any of my precious energy.</p>
<p>Here is LinkedIn&#39;s suggestion in full:</p>
<p><img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/4cn3Vmr39G20Pb1d1Z1N1e/03d03554f8cdd57a6e2a1caafd7205dc/one.png?w=800&fm=webp alt=LinkedIn suggested description /></p>
<p>For those who are blocking images, let&#39;s have that again in plain text.</p>
<blockquote>
<p>I am a software Model currently in the Premium Models Software Development Graduate Scheme. Having gained experience in both frontend and backend development I have gained skills in JavaScript, React, Vue, Angular, Redux and Node. js which has helped me build my professional portfolio. - BSc (Hons) Computing from The University of South Wales with Upper Second Class Honours classification</p>
</blockquote>
<p>So. That is:</p>
<ul>
<li>An incorrect description of my current job, with both an incorrect employer, and an incorrect job title (this information is listed correctly in my profile).</li>
<li>A wildly incorrect description of my education history (this information is listed correctly in my profile).</li>
<li>A somewhat closer, but still substantially incorrect description of my areas of specialisation as a software engineer (this information is listed correctly in my profile).</li>
</ul>
<p>On consideration I decided to go with this profile, as I think it&#39;s better than anything I would have written for myself.</p>
<p>I hit submit</p>
<p><img loading='lazy' src=https://images.ctfassets.net/wc253zohgsra/3CqGSA3LcmW5G9UrGBuu6S/f4d993fdc240775dd3d5dc844601d630/two.png?w=800&fm=webp alt=Linkedin Failure /></p>
<p>I tried again. It didn&#39;t work.</p>
]]></content>
          <pubDate>Thu, 20 Jan 2022 15:00:00 GMT</pubDate>
          <link>https://johnwhiles.com/posts/linking-in</link>
          <guid isPermaLink="true">https://johnwhiles.com/posts/linking-in</guid>
        </item>
        <item>
          <title><![CDATA[YikesScript]]></title>
          <content type="html"><![CDATA[<p>Recently at work an seemingly innocuous dependecy bump caused a rash of typescript errors to appear throughout our code base. The changes seemed benign -  a new method in an internal library and a few dependabot updates to go with it. Nothing, it seemed, that should cause <em>these</em> errors:</p>
<pre><code>src/****************.tsx:94:17 - error TS2550: Property &#39;allSettled&#39;
does not exist on type &#39;PromiseConstructor&#39;. 
Do you need to change your target library?
Try changing the &#39;lib&#39; compiler option to &#39;es2020&#39; or later.

94   await Promise.allSettled(
</code></pre>
<p>and</p>
<pre><code>
src/****************.ts:105:31 - error TS2550: Property &#39;flatMap&#39;
does not exist on type &#39;{ [key: string]: { [quay: string]: Value;
}; }[]&#39;. 
Do you need to change your target library? 
Try changing the &#39;lib&#39; compiler option to &#39;es2019&#39; or later.

105   return Object.values(cache).flatMap((value) =&gt;
                                  ~~~~~~~
</code></pre>
<p>We went through the new code with a fine tooth comb - there was
nothing that explained the appearance of there errors, and TypeScript&#39;s suggestion
to &quot;Try changing the &#39;lib&#39; compiler option to &#39;es2020&#39; or later.&quot;
instantly fixed all our compilation woes. This was unsatisfying - these changes didn&#39;t
touch our typescript config. It made no sense.</p>
<p>Clearly something was amiss, the code was compiling before even
though it used features that our tsconfig did not support.
Really it seemed like we were just seeing errors that should 
already have been spotted.</p>
<p>At a loss, I did what I always do when looking for inspiration - I
start scanning through the diff of our package.lock file. I noted
which packages had changed. One jumped out - type-fest, a dependecny
of a dependency of a dependency. It provides random utility types
and it had been upgraded from <code>v0.20.2</code> to <code>0.21.3</code>. Why did it
jump out at me? I guess because we were seeing type errors, and it
contained the word type. I had no other reason to think it was
responsible as the effected code didn&#39;t use type-fest.</p>
<p>I navigated to github dot com - and felt slightly sick when I saw
that the latest version of type fest was <code>v2.3.2</code>. I started reading
through the changelog. I could taste copper in my mouth, and there
was an ozone smell in the air. It was a slog through boring
descriptions like &quot;Fix export for <code>Get</code> type
(<a href="https://github.com/sindresorhus/type-fest/pull/181">#181</a>)
<a href="https://github.com/sindresorhus/type-fest/commit/a65377be2fba48165c9514301b679d1f21171dbd">a65377b</a>&quot;
and &quot;Reticulate Splines
(<a href="https://github.com/sindresorhus/type-fest/pull/181">#184</a>) <a href="https://github.com/sindresorhus/type-fest/commit/g87244nbe2fba48165c9514301b679d1f21171dbd">g87244n</a>&quot;.
I wondered what the point of this library was. Then I noticed it.
Sticking out, a strange a warped PR title. &quot;Fix TS type reference
(<a href="https://github.com/sindresorhus/type-fest/pull/187">#187</a>)
<a href="https://github.com/sindresorhus/type-fest/commit/ed5f3d360fc9e9275dfc193cfc3992f11e192c3c">ed5f3d3</a>&quot;.
With a growing sense of unease I clicked the link, and through half narrowed eyes peered into the the diff. I saw this.</p>
<pre><code>- /// &lt;reference lib=&quot;esnext&quot;/&gt;
+ /// &lt;reference lib=&quot;es2020.bigint&quot;/&gt;
</code></pre>
<p>Strange - I thought. This is TypeScript related. But surely this wouldn&#39;t effect how completely unrelated code was compiled? I relaxed a little. Still not entirely reassured I decided to do a test to confirm that these changes weren&#39;t responsible. I perfomed some manual node_module surgery and reverted the change. To my utter horror everything instantly compiled. The acrid stench of chemicals in the air grew stronger. Black specks appeared in the corners of my vision. Somehow this tiny change was the root of my problems.</p>
<p>I had to understand what was going on. I read the <a href="https://github.com/sindresorhus/type-fest/pull/187">PR related to this change</a> which led me to <a href="https://github.com/microsoft/TypeScript/issues/33901">this typescript issue</a>. The awful words I read swam and wavered under my eyes.</p>
<blockquote>
<p><strong>Expected behavior</strong>: should produce a compile error</p>
</blockquote>
<blockquote>
<p><strong>Actual behavior:</strong><br>It just compiles.</p>
</blockquote>
<p>Yet then there was worse to come. The increasingly illegible monospace
font  explained how any typescript dependency could accidentally
or maliciously subvert the expectations of the poor fool that choose
to use it.</p>
<blockquote>
<p>This is what a lib reference <em>does</em>.</p>
</blockquote>
<blockquote>
<p>This issue has been marked &#39;Working as Intended&#39; and has seen no recent activity. It has been automatically closed for house-keeping purposes.</p>
</blockquote>
<p>I slammed shut the accursed tome - it dropped from my hands and hit
the floor with a crash that seemed impossible given it&#39;s relatively
light weight. It sat inert on the floor, powerless I thought, yet
still I felt almost like it was watching me. Now I understand what
the scorch marks on the cover meant - whoever was here before me
had tried to destroy this awful knowledge - before it could it drive
another to madness. It&#39;s too late for me now - but surely I can
finish my precursors work and destroy the cursed thing before I
lose my grasp entirely. Tonight  before they come for me I&#39;ll sink it
in in the lake. I can here them approaching now - it&#39;s not too late
though. If I can just</p>
]]></content>
          <pubDate>Sun, 24 Oct 2021 23:00:00 GMT</pubDate>
          <link>https://johnwhiles.com/posts/yikesscript</link>
          <guid isPermaLink="true">https://johnwhiles.com/posts/yikesscript</guid>
        </item>
        <item>
          <title><![CDATA[A Second Solaris]]></title>
          <content type="html"><![CDATA[<h1>Second Solaris</h1>
<p>For the second evening in a row, we watched Solaris. If you read
my previous psot, you&#39;ll that there was some confusion about whether
or not George Clooney would appear in the 1972 Russian masterpiece.
This time it was immediately clear that George Clooney would be
appearing because we were watching the 2002 adaption of Solaris
from acclaimed director of Magic Mike and The Ocean&#39;s 11 franchise
Steven Soderbergh.</p>
<p>Solaris 2 (002) is unusual in that it doesn&#39;t flounder under the
weight of it&#39;s hugely successful predecessor. It manages to stand
by itself, and provides a very different, but still enjoyable,
cinematic experience.</p>
<p>But first things first, Solaris 2 lacks the visual splendour of the
original, it&#39;s cinematography is workmanlike. Everyone on earth
looks like they&#39;re in a music video made by David Bowie and Trent
Reznor. The film is weirdly rushed, George Clooney doesn&#39;t even
agree to go to space - someone just suggests it and then he&#39;s there.
The film just hasn&#39;t stuck in my thoughts in anything like the same
way as the Tarkovsky flick. But it&#39;s stll good! It has some interesting
twists, and brings different elements of the Solaris experience to
the fore.</p>
<p>The best thing about the film is, I think, that the only piece of
licensed music in it is an Insane Clown Posse song. When Clooney
first arrives on the space station, he meets Dr. Snow, who is messing
with computers and listening to the ICP. We later find out that he
is a Solarian replica, not a real human. I absolutely adore the
idea that after being constructed from memories, with no real
understanding of humanity, totally isolated on a space station,
this alien being would decide to listen to ICP. Is Sonderbergh
trying to tell us something about which of our cultural artifacts
are truly valuable?</p>
]]></content>
          <pubDate>Mon, 19 Jul 2021 23:00:00 GMT</pubDate>
          <link>https://johnwhiles.com/posts/second-solaris</link>
          <guid isPermaLink="true">https://johnwhiles.com/posts/second-solaris</guid>
        </item>
        <item>
          <title><![CDATA[Seeing Solaris]]></title>
          <content type="html"><![CDATA[<h1>Seeing Solaris</h1>
<p>Every year the Arsenal Kino in Berlin holds a Tarkovsky retrospective... Except
last year when they didn&#39;t. This year they&#39;re back with a bang!
By which I mean they are showing Tarkovsky&#39;s films again.</p>
<p>I&#39;d never seen a Tarkovsky film before and all my knowledge of his work comes from
reading a review of the video game adaption of Stalker. I didn&#39;t even know what
era these films dated. So when A told me that this film starred
George Clooney, it seemed totally plausible. I was very excited to see an
acclaimed sci fi film by a Russian director starring George Clooney.</p>
<p>About 5 seconds into the opening credits, where cyrillic characters
sway on crackly old film stock accompanied by a droning organ, it
became apparent that George Clooney would not be appearing in this
film. From the credits (which felt like they might be from a vampire
film from 1920) we go straight to some startlingly colorful shots
of the watery folliage, and a sorrowful blue coated man holding a
metal lunchbox. Perhaps it was the screenshots
accompanying that Stalker review in PC Gamer Magazine, but one thing
I really didn&#39;t expect from this film was vivid colours, and verdant plant life. It was a pleasant
surprise.</p>
<p>Equally surprising was the scene to scene shift from color to a
blue tinged monotone. A wondered if this shift might represent dream
sequences, it could also reflect the viewpoint of the
ocean of solaris. I also wouldn&#39;t be surprised to find out that the
truth is more to do with the availability of materials.</p>
<p>Eventually our hero (who is not Geroge Clooney) goes to space, meets an alien
version of his dead wife, traps her in a rocket, meets another version of the
dead wife, falls in love with her, becomes increasingly strange, then eventually
decides to live in a memory on the watery planet of Solaris.</p>
<p>The film raises questions about what it means to be human, and whether asking
questions like that is worth while. One character claims that the happiest
people never think about the &#39;eternal themes&#39;. The protaganist&#39;s behaviour
towards the fake version of his wife, and eventual fate, seem to be the actions
of someone who&#39;s more interested in being happy than thinking about the meaning
of his wife&#39;s ressurection. But is the purpose of life being
happy, or is it instead more important to understand why you are having a
horrible time in space?</p>
<p>Open questions</p>
<ul>
<li>what&#39;s the deal with the horse that the child is scared of? Why are there so
many pictures of horses on the space station?</li>
<li>Why all the references to Don Quixote and Faustus?</li>
<li>Why is the scene of Burton driving home so incredibly long?</li>
</ul>
<p>Solaris was very good and you should watch it.</p>
]]></content>
          <pubDate>Sat, 17 Jul 2021 23:00:00 GMT</pubDate>
          <link>https://johnwhiles.com/posts/seeing_solaris</link>
          <guid isPermaLink="true">https://johnwhiles.com/posts/seeing_solaris</guid>
        </item>
        <item>
          <title><![CDATA[Start Small, Stay Small]]></title>
          <content type="html"><![CDATA[<h1>Start Small, Stay Schmall</h1>
<p>I&#39;ve recently been thinking about starting a small startup of my
own, not with any intention of doing anything big, but instead of
having some stupid little product that I can tinker with. I want
to do this in order to learn some new skills, system design, customer
management, design design, etc. So Start Stall, Stay Small by Rob
Walling seemed like a useful thing to read.</p>
<p>When I started this book I felt quite excited. But the book became
a bit of a drag. It&#39;s full of useful advice about figuring out if
a market is worth investigating, how to choose a price point etc.
This laser focus on profit, and minimising time investment was not
really what I was after though. This book will tell you that it&#39;s
preferable to contract out development work, copy writing etc. It&#39;s
really aimed at people who want to know how to make a micro business
profitable, whereas I was probably just looking for something to
get me excited about making a stupid little website.</p>
<p>If I go ahead with &quot;microentrepreneurship&quot; I will probably return
to this book, and I&#39;m think some of its lessons will be useful. But
I worry that reading it might make you less likely to start a tiny
business.</p>
]]></content>
          <pubDate>Wed, 14 Jul 2021 23:00:00 GMT</pubDate>
          <link>https://johnwhiles.com/posts/start_small_stay_small</link>
          <guid isPermaLink="true">https://johnwhiles.com/posts/start_small_stay_small</guid>
        </item>
        <item>
          <title><![CDATA[Local development with DynamoDB and JavaScript]]></title>
          <content type="html"><![CDATA[<p>(Update from future John: god this is boring. I hope it&#39;s helped someone somewhere somehow)</p>
<h1>Local development with DynamoDB and JavaScript</h1>
<p>I was interested in learning how use DynamoDB, but didn&#39;t want to set
it up on AWS personally because I&#39;m lazy, and scared of accidentally getting
billed for 10,000 euros.</p>
<p>Instead I decided to run it locally in a docker-container.</p>
<p>This article is going to walk through the process that I followed, in case you
want to do something similar.</p>
<h2>Creating the DynamoDB container</h2>
<p>The first step is to create a <code>docker-compose.yaml</code>.
Docker Compose let&#39;s us define containers that we want to run to support our
project. It&#39;s a pretty neat way to set up a development environment.</p>
<p>Here&#39;s the file I created</p>
<pre><code class="language-yaml">version: &#39;3&#39; # The version of docker-compose syntax we&#39;re using. Just pick 3 I guess

services: # We define the containers we want to create under this header
  dynamodb:
    image: amazon/dynamodb-local # The image we&#39;re using. Thanks Amazon.
    container_name: dynamodb-local
    ports:
      - &quot;8042:8000&quot; # binds the localhost port on the left, to the container port on the right
</code></pre>
<h3>Running the container</h3>
<p>You&#39;ll need docker installed for this step.</p>
<p>Run this command
<code>docker-compose -f docker-compose.yaml up -d</code></p>
<p><code>-f</code> allows us specify the file to use, in our case this is the
docker-compose.yaml we just created</p>
<p><code>up</code> tells docker-compose to “build, (re)create, start, and attache to containers for a service.”
<code>-d</code> specifies that we want to run the container in &#39;detached&#39; mode.</p>
<p>Now our container should be running. Running <code>docker ps</code> in the command line
should show that the container is alive and kicking.</p>
<h2>The JavaScript stuff</h2>
<h3>Making our first table</h3>
<p>To use DynamoDB in JavaScript, we&#39;re going to rely on the aws-sdk. So let&#39;s
install it!</p>
<p><code>yarn add aws-sdk</code></p>
<p>And then let&#39;s use it to make a table!</p>
<pre><code class="language-javascript">const AWS = require(&#39;aws-sdk&#39;);

async function main() {
  // Even though we&#39;re using the SDK locally the SDK will throw an error 
  // if these items are missing. We don&#39;t need to use real keys for local
  // development however.
  AWS.config.update({
    region: &#39;local&#39;,
    accessKeyId: &#39;random-not-real-id&#39;,
    secretAccessKey: &#39;random-not-real-key&#39;,
  })

  // Now we create our Client!
  const dynamoClient = new AWS.DynamoDB({ endpoint: &#39;http://localhost:8042&#39; })

  // And we can start making tables

  try {
    await dynamoClient.createTable({
      // The name  of our table
      TableName: &#39;user-info&#39;,

      // The attributes that our needed to create our primary key.
      // We can still store other data as part of each item, but we don&#39;t need
      // to define it as part of the table
      AttributeDefinitions: [
        {
          AttributeName: &#39;name&#39;,
          AttributeType: &#39;S&#39;,
        }
      ],

      // How the primary keys for our table are generated.
      // In our case we are simply going to hash the attribute &#39;name&#39;
      KeySchema: [
        {
          AttributeName: &#39;name&#39;,
          KeyType: &#39;HASH&#39;,
        },
      ],

      // Some Config stuff. Ask your ops team about this I guess.
      ProvisionedThroughput: {
        ReadCapacityUnits: 5,
        WriteCapacityUnits: 5,
      },
    }).promise()

    console.log(&#39;create table user-info&#39;)

  } catch (e) {
    console.error(error)
    process.exit(1)
  }
}
</code></pre>
<p>Although we only specified the attributes that are required to make each items
primary key, we can store other data in each item.</p>
<h3>Data in the base</h3>
<p>A thing that puzzled me when looking at the DynamoDB sdk was the difference between a  <code>DynamoClient</code> and a <code>DocumentClient</code>. We used the <code>DynamoClient</code> to create our table above, but using that to add data actually becomes quite tricky. We have to painstakingly describe the different keys we&#39;ll be adding.</p>
<p>The document client seems to have been added to the SDK to make life easier for JavasScript developers. It gives us some methods that let us interact with our DB using normal JavaScript objects that match the shape of the data we want to store. More details can be seen in <a href="https://aws.amazon.com/blogs/developer/announcing-the-amazon-dynamodb-document-client-in-the-aws-sdk-for-javascript/">this announcement post</a>.</p>
<p>Long story short, we&#39;re going to use the <code>DocumentClient</code> to store data in our
table.</p>
<pre><code>const docClient = new AWS.DynamoDB.DocumentClient({ endpoint: &#39;http://localhost:8042&#39; })
</code></pre>
<p>Now to make our lives easier let&#39;s define a function that adds users to our
table.</p>
<pre><code class="language-javascript">const addUser = async (name, email) =&gt; {
  return docClient.put({
    Item: {
      name,
      email
    },
    TableName: &#39;user-info&#39;
  }).promise()
}
</code></pre>
<p>and one to list all of our users</p>
<pre><code class="language-javascript">const listUsers = async () =&gt; {
  return docClient.scan({
    TableName: &#39;user-info&#39;
  }).promise()
}
</code></pre>
<p>We can then use these functions to add some users to our table, and then print
them out again.</p>
<pre><code class="language-javascript">const addUsers = async () =&gt; {
  await addUser(&#39;bobby&#39;, &#39;bobby@bob.com&#39;)
  await addUser(&#39;tomboy&#39;, &#39;tom@boy.com&#39;)
  await addUser(&#39;blobby&#39;, &#39;mr@blobby.com&#39;)
  console.log(await listUsers())
}

addUsers()
</code></pre>
<p>If we run this code we&#39;ll see the following output in our terminal</p>
<pre><code>{
  Items: [
    { name: &#39;bobby&#39;, email: &#39;bobby@bob.com&#39; },
    { name: &#39;blobby&#39;, email: &#39;mr@blobby.com&#39; },
    { name: &#39;tomboy&#39;, email: &#39;tom@boy.com&#39; }
  ],
  Count: 3,
  ScannedCount: 3
}
</code></pre>
<h2>Conclusion</h2>
<p>You&#39;se now seen how to set up a local DynamoDB - and how to do some basic
interaction with it in JavaScript. A runnable version of the code in this
article can be <a href="https://github.com/Jwhiles/dynamo-something">found here</a>.</p>
]]></content>
          <pubDate>Sat, 31 Oct 2020 23:00:00 GMT</pubDate>
          <link>https://johnwhiles.com/posts/javascript-and-dynamodb</link>
          <guid isPermaLink="true">https://johnwhiles.com/posts/javascript-and-dynamodb</guid>
        </item>
        <item>
          <title><![CDATA[Tries Company]]></title>
          <content type="html"><![CDATA[<h1>Implementing a Trie in Haskell</h1>
<p>Once upon a time (five months ago) I was doing a phone screening for a <em>tech job</em>. To my horror, I was asked to
name a Tree that wasn&#39;t a binary search Tree. Being a complete philistine, I had no answer. I was rejected on
the spot. From that day on I have made it my mission to learn about every variation of a Tree that can be
implemented with a small amount of effort in Haskell.</p>
<p>Today we take on <em>The Trie</em></p>
<p>This article is mostly meant as a demonstration of what a Trie is. This is a totally
naive implementation, which is based on skimming the <a href="https://en.wikipedia.org/wiki/Trie">wikipedia article about Tries</a>.
As such you probably shouldn&#39;t use this code anywhere.</p>
<p>Although this is written in haskell, I&#39;ve tried to avoid anything too weird.
Hopefully this code will be comprehensible for someone who has written Elm.</p>
<p>We&#39;ll start by watching me implementing a Trie incorrectly, realising my
mistake, and then correcting it.</p>
<h2>What is a Trie?</h2>
<p>A Trie (AKA a Prefix Tree) is a Tree where each node is labelled by some
value. When we traverse the tree these labels can be concatenanted together to find the 
value represented by a leaf node.</p>
<p>For example I might store my friends names in a Trie like this:</p>
<pre><code>      B
      |
   ______
  |   |  |
  O   I  A __
  |   |  |   |
  B   L  Z   R
      |      |
      L      B

-- This Trie contains the names Bob, Bill, Baz, and Barb. All my friends.
</code></pre>
<p>Tries are useful for things like creating an autocompleting
searchbox on your Web 2.0 App. They can really deliver a lot of business value and help you meet your KPIs.</p>
<h2>How to implement a Trie?</h2>
<h3>A Tree</h3>
<p>A typical binary tree in Haskell can be implemented as follows</p>
<pre><code class="language-haskell">data Tree a = Node a (Tree a) (Tree a) | Leaf
</code></pre>
<h3>A Trie</h3>
<p>But in the case of a Trie, we aren&#39;t certain how many children a given Node will
have. We also want to be able to access a Node&#39;s children based on the value
they contain.</p>
<p>That sounds an awful lot like a Map (AKA a Dictionary)...</p>
<p>So let&#39;s represent the children using a Map</p>
<pre><code class="language-haskell">import qualified Data.Map.Strict as M
-- We import a Data.Map, to act as our Dictionary

data Trie = Node (M.Map Char Trie) 
  deriving (Eq, Show)
</code></pre>
<p>A really simple Trie with just two words, &#39;hi&#39; and &#39;hey&#39; using this structure would
look something like this.</p>
<pre><code class="language-haskell">Node { h = Node { i = Node { }, e = Node { y = Node { } } } }
</code></pre>
<p>Writing out nodes by hand is no fun. So let&#39;s write a function to insert a word.</p>
<pre><code class="language-haskell">-- First we make a helpful &#39;empty Trie&#39; constant
empty :: Trie
empty = Node M.empty

-- Then we define the type of our insert function
insert :: String -&gt; Trie -&gt; Trie

-- If the String is empty, we return the Trie as it was
insert &quot;&quot; t = t  

-- Otherwise we split the first character out of the string
-- and check if that character already exists as a child of the Node we&#39;re
-- looking at
insert (c:rest) (Node children) =
  case M.lookup c children of

    -- If the character wasn&#39;t already there, then we add an empty Trie
    -- under that character to our Map, and then add the rest of the string to 
    -- that new subTrie!
    Nothing -&gt;
      Node $ M.insert c (insert rest empty) children

    -- If the character is already in the Trie then we can recursively call 
    -- insert on that SubTrie with the rest of our string
    Just matchingChildNode -&gt;
      Node (M.insert c (insert rest matchingChildNode) children)
</code></pre>
<p>Now we can construct the same Trie we saw previously, <em>but this time with code</em></p>
<pre><code class="language-haskell">ourTrie = insert &quot;hi&quot; $ insert &quot;hey&quot; empty
</code></pre>
<p>If we run this in our Repl we get</p>
<pre><code>Node (fromList
  [ (&#39;h&#39;, Node (fromList
    [ (&#39;e&#39;,Node (fromList
      [ (&#39;y&#39;,Node (fromList [] )) ]))
  , (&#39;i&#39;,Node (fromList [])) ])) ])
</code></pre>
<p>Cool!</p>
<h2>My Biggest mistake</h2>
<p>An observant reader might noticed that this Trie implementation is WRONG and BAD</p>
<p>What happens to our Trie if, for KPI related reasons, we need to insert the words &quot;hello&quot; and &quot;hell&quot;?</p>
<p>We can add them both, but there is no possible way us to tell looking at the resulting Trie that the word hell was ever there. It&#39;s gone. Vanished. Verschwunden.</p>
<p>We have no way of to distinguish between words that were intentionally added
to the Trie, and random prefixes that have no meaning by themselves.</p>
<h2>Fixing my biggest mistake</h2>
<p>This is all fine of course. We can change our Trie defintion such that each node
can either hold onto a specific value, or be empty. An empty node meaning that
the it is simply a step on the path to a node that <em>does</em> represent some
specific word.</p>
<pre><code class="language-haskell">data Trie 
  = Node String (M.Map Char Trie) 
  | Empty (M.Map Char Trie)
      deriving (Eq, Show)

empty :: Trie
empty = Empty M.empty
</code></pre>
<p>Let&#39; also make some helper functions for working with our new structure</p>
<pre><code class="language-haskell">getChildren :: Trie -&gt; M.Map Char Trie
getChildren (Node _ c) = c
getChildren (Empty c) = c

setChildren :: Trie -&gt; M.Map Char Trie -&gt; Trie
setChildren (Node s _) newChildren = Node s newChildren
setChildren (Empty _) newChildren = Empty newChildren
</code></pre>
<p>Now we need to update our insert function to save the word that we are inserting at 
the end of the Trie branch it is added to</p>
<pre><code class="language-haskell">insert :: String -&gt; Trie -&gt; Trie
insert word trie = recurse word trie
  where
    recurse :: String -&gt; Trie -&gt; Trie
</code></pre>
<p>we use an internal helper function, that I&#39;ve called <code>recurse</code> so we can keep hold of the word we are adding - even while recursing.</p>
<pre><code class="language-haskell">    recurse &quot;&quot; t = Node word (getChildren t)
</code></pre>
<p>If our string is empty, it means we&#39;ve finished adding all the characters that make up our word
to the trie - so we can save the full word at this Node and then stop. Phew</p>
<pre><code class="language-haskell">    recurse (c:rest) t = 
      let children = (getChildren t)
      in case M.lookup c children of
        Just matchingChildNode -&gt;
          setChildren t (M.insert c (recurse rest matchingChildNode) children)
        Nothing -&gt;
          setChildren t $ M.insert c (recurse rest empty) children
</code></pre>
<p>If there are still characters to add to the Trie, we can recursively add them in much the same way we did before.
We just need to adjust this function a bit to avoid destroying other words that we&#39;ve already saved in our Trie.</p>
<p>Nice!</p>
<h2>What&#39;s in it?</h2>
<p>The really useful feature of a Trie, it seems, is to be able to tell us all the
suffixes for a given Node. In our example above, I might start with the letter &#39;h&#39;
and be told that the possible endings of the word are &#39;i&#39; and &#39;ey&#39;. Very useful.</p>
<p>It turns out that writing this function for our Trie is <em>really</em> easy.</p>
<p>first we write a function that can help us get a value out of a given node of a Trie.</p>
<pre><code class="language-haskell">getValue :: (Applicative m, Monoid (m String)) =&gt; Trie -&gt; m String
getValue (Empty _) = mempty
getValue (Node nodeValue _) = pure nodeValue
</code></pre>
<p>The cool thing about this function is that it will return a different type
depending on the context we use it in. For example if we used it in a context where we expected a Maybe. We&#39;ll get a Maybe String. </p>
<p>In this case we actually want to build a list of values, and this function will helpfully also return values in that format. To get all the words in our Trie we can write a function that recursively get&#39;s the values at each node in our Trie, and returns them all in one big list</p>
<pre><code class="language-haskell">getWords :: Trie -&gt; [ String ]
getWords t = getValue t &lt;&gt; 
               foldMap getWords (getChildren t)
</code></pre>
<p>Tidy</p>
<p>If we test this like so</p>
<pre><code class="language-haskell">main = do
  print $
    getWords $ insert &quot;hey&quot; $ insert &quot;hello&quot; $ insert &quot;egg&quot; empty
</code></pre>
<p>We&#39;ll see </p>
<pre><code class="language-haskell">[&quot;egg&quot;, &quot;hello&quot;, &quot;hey&quot;]
</code></pre>
<p>Nice!</p>
<h2>Conclusion</h2>
<p>wow. What a journey.
I hope this was in some way useful. It certainly was for me! Next time a phone interviewer asks me to name 
&#39;<em>any one data structure that isn&#39;t a binary search Tree</em>&#39; I&#39;ll have an answer for them!</p>
<p>Below you&#39;ll find the complete code, which you can play around with. It&#39;s been edited slightly to be more generic. Allowing us to store any lists of values, rather than just Strings (aka lists of characters).</p>
<p>Suggested exercise for the reader</p>
<ul>
<li>Write an autocomplete function that takes the start of a word and a trie, and tells us the possible complete words we could make!</li>
<li>Write a function to delete words from the Trie!</li>
<li>Think of an application for a Trie that isn&#39;t building autocomplete functionality</li>
<li>Try implementing this in C (jk)</li>
</ul>
<pre><code class="language-haskell">{-# Language ScopedTypeVariables #-}

module GenTree where

import qualified Data.Map.Strict as M

data Trie a = Node [a] (M.Map a (Trie a)) | Empty (M.Map a (Trie a))
  deriving (Eq, Show)

empty :: Trie a
empty = Empty M.empty

getValue :: (Applicative m, Monoid (m [a])) =&gt; Trie a -&gt; m [a]
getValue (Empty _) = mempty
getValue (Node nodeValue _) = pure nodeValue

getChildren :: Trie a -&gt; M.Map a (Trie a)
getChildren (Node _ c) = c
getChildren (Empty c) = c

setChildren :: Trie a -&gt; M.Map a (Trie a) -&gt; Trie a
setChildren (Node s _) newChildren = Node s newChildren
setChildren (Empty _) newChildren = Empty newChildren

insert :: forall a. (Ord a) =&gt; [a] -&gt; Trie a -&gt; Trie a
insert word trie = recurse word trie
  where
    recurse :: [a] -&gt; Trie a -&gt; Trie a
    recurse [] t = Node word (getChildren t)

    recurse (c:rest) t = 
      let children = (getChildren t)
      in case M.lookup c children of
        Just matchingChildNode -&gt;
          setChildren t (M.insert c (recurse rest matchingChildNode) children)
        Nothing -&gt;
          setChildren t $ M.insert c (recurse rest (empty)) children

getWords :: Trie a -&gt; [ [ a ] ]
getWords t = getValue t &lt;&gt; 
               foldMap getWords (getChildren t)

main = do
  print $
    getWords $ insert &quot;hey&quot; $ insert &quot;hello&quot; $ insert &quot;egg&quot; empty
  print $
    getWords $ insert [1, 2, 3] $ insert [1, 4, 5] $ insert [1, 50, 2] empty
</code></pre>
]]></content>
          <pubDate>Wed, 20 Nov 2019 23:00:00 GMT</pubDate>
          <link>https://johnwhiles.com/posts/implementing-a-trie</link>
          <guid isPermaLink="true">https://johnwhiles.com/posts/implementing-a-trie</guid>
        </item>
    </channel>
  </rss>