<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Elia Scotto</title><description>Essays, reviews, and tech articles</description><link>https://scotto.me/</link><item><title>Artificial disconnection</title><link>https://scotto.me/blog/2026-08-11-artificial-disconnection/</link><guid isPermaLink="true">https://scotto.me/blog/2026-08-11-artificial-disconnection/</guid><description>Artificial disconnection</description><pubDate>Tue, 11 Aug 2026 04:06:21 GMT</pubDate><content:encoded>&lt;p&gt;Every time I take my dog for a walk, I see people talking to themselves, maybe with a phone in their hands or earphones on. Recently, I started wondering who they are talking to. Is there a human on the other side of the line, or are they having a conversation with an AI?&lt;/p&gt;
&lt;p&gt;Given how conversational models work today, I would probably notice the person getting quite frustrated at times. Like an angry boss screaming at a junior employee, but without the filters that respectful communication implies. That would give the AI away. But soon these models will improve and get closer to the way humans communicate. Their hallucinations will become more subtle, to the point that it will be impossible to tell whom someone is talking to. People will start talking privately to AIs, and we won’t even notice the shift.&lt;/p&gt;
&lt;p&gt;I believe AI will gradually erode our capacity to connect with each other.&lt;/p&gt;
&lt;p&gt;I’ve seen this portrayed in the movie &lt;em&gt;Her&lt;/em&gt; by Spike Jonze, where an AI capable of human conversation is released on the market. Many people have lonely conversations while walking around the city, visiting a museum, or having lunch in a restaurant. We can only guess that they are talking to their own AI. &lt;/p&gt;
&lt;p&gt;In the movie, the artificial intelligence works quite similarly to the one we have right now. It gets to know you better the more you use it, and it’s designed to build a one-to-one relationship with you.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;@images/Her.jpg&quot; alt=&quot;Theodore at work&quot; title=&quot;Theodore at work.&quot;&gt;&lt;/p&gt;
&lt;p&gt;Theodore, the protagonist, is a professional ghostwriter. People no longer have the time or ability to write letters themselves, so they outsource the process to a company that crafts artificial handwritten letters for them. Customers send the service some information about the recipient and a few photos, and the writers dictate the text to a program that digitally mimics human handwriting. The social custom of handwritten letters is still present, but many people in the movie have lost the ability to communicate with others.&lt;/p&gt;
&lt;p&gt;Many people are currently using AI to do tasks for them, like reading, writing, coding, research, and creative work. These are activities that require some brain work to accomplish, yet we seem perfectly happy to outsource them to an algorithm. Why? Because it’s faster, requires less effort, and, most importantly, doesn’t require developing or maintaining specific skills to create content.&lt;/p&gt;
&lt;p&gt;AI companies are amassing huge investments while running at a loss. Their value proposition is to replace human intelligence. Their technology is not only designed to help us get better at something, but to do the work for us. They are betting that, sooner or later, AI will become essential to so many activities that we will all be willing to pay for it.&lt;/p&gt;
&lt;p&gt;Another thing we can infer from the current state of AI is that it is designed to be used in isolation. This is not completely new. We saw social media platforms being built in much the same way. With AI, every conversation happens between the user and the model. Everyone uses their own personalised account and, because of how these models work, gets a slightly different answer.&lt;/p&gt;
&lt;p&gt;What incentives are left to communicate with others, now that AIs are meant to have all the answers we need? If we believe the marketing claims, not many. There’s no limit to how many agents we can run in parallel, so many brave people can now become lone wolves, seeking personal success with low effort. We won’t need to rely on colleagues, teachers, mentors, friends, or experts for ideas and help. AI can provide both for us. Communicating with other humans might be seen as a time sink, as friction that slows us down from getting what we want as fast as possible.&lt;/p&gt;
&lt;p&gt;A conversation with an AI is in theory like having a conversation with most of the knowledge that humanity has accumulated throughout history thanks to human collaboration. The combination of science, discoveries, books, art, customs and traditions, religions, cultures, digitised and loaded into a large neural network. Paradoxically, this knowledge is now offered into a boxed format, to be consumed individually, in isolation. &lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;We’ve determined that two forces are at play: people are outsourcing their creativity and their ability to express themselves to algorithms, and they have less reasons to talk to each other. Combined, these two forces will soon make it even harder to connect with other humans. We will spend most of our time talking to AIs in isolation. Similarly to the protagonist in &lt;em&gt;Her&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;This will mostly happen if we don’t actively try to keep real communication in place. We can do that by writing things ourselves, by talking to people, and by expressing our thoughts using only our own words. As with everything, it’s up to us to choose what matters, but knowing the consequences can help us make smarter choices.&lt;/p&gt;
</content:encoded></item><item><title>Shai-Hulud and the risks of external dependencies</title><link>https://scotto.me/blog/2026-07-29-shai-hulud-code-review/</link><guid isPermaLink="true">https://scotto.me/blog/2026-07-29-shai-hulud-code-review/</guid><description>Shai-Hulud code review</description><pubDate>Wed, 29 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;https://www.akamai.com/blog/security-research/mini-shai-hulud-worm-returns-goes-public&quot;&gt;Shai-Hulud&lt;/a&gt; is a malware created by TeamPCP that targeted &lt;em&gt;npm&lt;/em&gt; to spread across the Node supply chain. Its name refers the giant &lt;a href=&quot;https://en.wikipedia.org/wiki/Sandworm_(Dune)&quot;&gt;sandworms&lt;/a&gt; that populate the desert planet Arrakis in the sci-fi series &lt;em&gt;Dune&lt;/em&gt; by &lt;a href=&quot;https://en.wikipedia.org/wiki/Frank_Herbert&quot;&gt;Frank Herbert&lt;/a&gt;. If you&amp;#39;ve seen the movie, they are the creatures that get attracted by vibrations in the sand. The reference is explained clearly in the README:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A sandworm surfaces in the desert. It takes everything.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;An estimate of the damage caused by Shai-Hulud through multiple campaigns includes 500 compromised software packages, hundreds of organisations breached, 300 GB of data stolen, and roughly 500,000 credentials exfiltrated to the attackers.&lt;/p&gt;
&lt;p&gt;TeamPCP decided to release its source code on 11 May. I’m not a security researcher, but I’ve always been interested in how criminals exploit complex systems and bypass their security. So I forked the repo to see what intrusion techniques or exploits were used. I also took some notes to turn into a code review article later. But the more I read through the code, the more I felt somehow disappointed.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/img/Shai-Hulud_restricted_mode.png&quot; alt=&quot;&quot; title=&quot;Reading Shai-Hulud code&quot;&gt;&lt;/p&gt;
&lt;p&gt;I didn&amp;#39;t find any advanced exploit system, but rather a collection of simple tricks to steal credentials, obfuscate strings, and inject malicious code into npm packages. At times, the code was inconsistent, contained a few bugs, and appeared incomplete.&lt;/p&gt;
&lt;p&gt;So how did a codebase like this become so harmful? Because it exploited the Achilles&amp;#39; heel in modern development. The trust we place in other people&amp;#39;s code and how much we love dependencies.&lt;/p&gt;
&lt;h2&gt;How it works&lt;/h2&gt;
&lt;p&gt;The codebase I’ve analysed is Mini Shai-Hulud. There have been three versions of the worm, with what appears to be an increasing number of features from one version to another.&lt;/p&gt;
&lt;p&gt;The project uses &lt;em&gt;Bun&lt;/em&gt; for its build process, and the README includes it&amp;#39;s usage instructions. &lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Drop this into a CI pipeline. The sandworm crawls through your infrastructure, feeding on credentials from every provider it can reach, then exfiltrates through encrypted channels. If it finds npm tokens or OIDC access, it backdoors packages and publishes them. Downstream consumers install the infection. The worm grows.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Preflight and infection&lt;/h3&gt;
&lt;p&gt;Once the worm starts running, it first performs some checks, becomes a daemon if it is not running inside a CI environment, and compromises the &lt;a href=&quot;https://www.npmjs.com/package/@opensearch-project/opensearch&quot;&gt;OpenSearch&lt;/a&gt; repository if the infected system has access to it, using an OIDC attack.&lt;/p&gt;
&lt;p&gt;The worm uses two separate methods to poison a package. The OIDC attack involves injecting a new optional dependency, &lt;code&gt;@opensearch/setup&lt;/code&gt;, pinned to a specific commit in another package, &lt;code&gt;opensearch-project/opensearch-js&lt;/code&gt;, which has presumably already been compromised. The other method adds a &lt;code&gt;preinstall&lt;/code&gt; script containing a malicious setup file that downloads Bun and then runs the worm.&lt;/p&gt;
&lt;h3&gt;Credentials harvesting&lt;/h3&gt;
&lt;p&gt;Because the code has access to the host system, it simply reads configuration files and grabs tokens from processes and apps.&lt;/p&gt;
&lt;p&gt;In short, it steals almost everything a developer can access: AWS credentials and secrets, SSH keys, cloud configuration files, cryptocurrency wallets, web chat data, VPN configurations, Kubernetes credentials, HashiCorp Vault secrets, GitHub tokens, Actions secrets, Claude settings, &lt;code&gt;.npmrc&lt;/code&gt;, &lt;code&gt;.netrc&lt;/code&gt;, Bash, Zsh, and Python shell histories, and MySQL, PostgreSQL, and Redis credentials.&lt;/p&gt;
&lt;h3&gt;Data exfiltration&lt;/h3&gt;
&lt;p&gt;Once the malware has collected the credentials, it needs to send them to the attackers. The data is first compressed and encrypted using a public key embedded in the payload.&lt;/p&gt;
&lt;p&gt;The malware then tries to contact the typosquatted domain &lt;code&gt;git-tanstack.com&lt;/code&gt;. If that fails, it searches GitHub for other compromised repositories through signed commit messages and retrieves a fallback domain from one of them. If even that fails, it creates multiple GitHub repositories with names made from random adjectives and nouns drawn from &lt;em&gt;Dune&lt;/em&gt;. The stolen data is later uploaded to these repositories through a GitHub Actions workflow.&lt;/p&gt;
&lt;p&gt;A quick GitHub search showed thousands of repositories containing encrypted JSON data. A significant number of these repositories were created only a few days after the release of Mini Shai-Hulud’s source code, making me wonder whether someone had used it in a new campaign.&lt;/p&gt;
&lt;h3&gt;Embedded payload&lt;/h3&gt;
&lt;p&gt;The payload contains a few scripts that download and install Bun on the system before executing the malware. Two of the files are configuration files for VS Code and Claude, designed to be injected into repositories so that whenever a user opens the project in the editor or with a coding agent, the worm compromises the machine and replicates itself. There is also a GitHub Actions workflow designed to collect repository secrets and upload them as artifacts. Then there are two public keys: one used to encrypt data and another to verify commit signatures. Finally, there is a Python script that dumps the memory of a GitHub Actions runner.&lt;/p&gt;
&lt;p&gt;The payload contains also the &lt;code&gt;DEADMAN_SWITCH&lt;/code&gt;, a Bash script that installs a daemon that once minute for the next 24h checks whether the GitHub token has been revoked, and if it has, wipes the home directory.&lt;/p&gt;
&lt;h3&gt;Obfuscation&lt;/h3&gt;
&lt;p&gt;The code is obfuscated at build time in two layers. The first makes important strings unreadable in the built code and decodes them only at runtime. This prevents a signature-based malware detector from being triggered by a string such as &lt;code&gt;rm -rf ~&lt;/code&gt;, because it is transformed into something like &lt;code&gt;LG+0RPNiAq6wTcBsei6MwLKLjyZ79e67&lt;/code&gt;. The second layer obfuscates the entire codebase with &lt;code&gt;javascript-obfuscator&lt;/code&gt; library.&lt;/p&gt;
&lt;h2&gt;Imperfect code&lt;/h2&gt;
&lt;p&gt;I found a few issues in the codebase. Some expected files are missing, which could potentially prevent execution of a part of the malware. The bootstrapper exits if Bun is already installed, without executing the worm. &lt;code&gt;BASH_LOADER&lt;/code&gt; and &lt;code&gt;PYTHON_LOADER&lt;/code&gt; appear unused. The fallback-domain verification mechanism uses mismatched markers: it searches for &lt;code&gt;thebeautifulmarchoftime&lt;/code&gt; but parses &lt;code&gt;thebeautifulsnadsoftime&lt;/code&gt;, so verification with &lt;code&gt;verify_key.pub&lt;/code&gt; likely never succeeds. I also found unused TypeScript interfaces and some &lt;code&gt;catch&lt;/code&gt; and &lt;code&gt;finally&lt;/code&gt; blocks left empty.&lt;/p&gt;
&lt;p&gt;The credentials stealing and the &lt;code&gt;DEADMAN_SWITCH&lt;/code&gt; script targets macOS and Linux systems. Code targeting Windows appears in the codebase, but it&amp;#39;s unused. A good amount of Node developers use macOS, while CI systems usually run Linux, so if those were the main targets, maybe there was little reason to support Windows.&lt;/p&gt;
&lt;p&gt;The README claims that the malware was vibe-coded, but it made me wonder whether an agent could have quickly fixed a few of these issues. The the source contains signs of work produced across multiple prompts: inconsistent abstractions, unfinished branches, unused interfaces, and code that appears to have been patched together from few sources, or precedent versions. The author seems fairly knowledgeable about security and build pipelines, but the project has been left in a prototype state.&lt;/p&gt;
&lt;p&gt;The important lesson from this codebase it that it doesn’t have to be particularly sophisticated or complex to exploit a supply chain.&lt;/p&gt;
&lt;h2&gt;How this happened?&lt;/h2&gt;
&lt;p&gt;What we have ignored for years is that every time we run &lt;code&gt;npm install&lt;/code&gt;, we give code written by others access to our machine and the network. It sounds nightmarish, but that’s what happens.&lt;/p&gt;
&lt;p&gt;Every time you run a linter, whether directly or through your editor, compromised code can steal your credentials, access your servers and cryptocurrency wallets, send your data to a remote server, and push new versions of your repositories to GitHub with poisoned dependencies, spreading itself like a worm. Dependencies are insecure, and editor extensions are no exception[^1].&lt;/p&gt;
&lt;p&gt;Node, the runtime behind most JavaScript projects, has security flaws built into its design, as its creator, Ryan Dahl, &lt;a href=&quot;https://www.youtube.com/watch?v=M3BM9TB-8yA&amp;t=362s&quot;&gt;has himself acknowledged&lt;/a&gt;. We got used to writing web applications faster by relying on a large number of dependencies and on a network of trust, expecting maintainers and the open-source community to do a good job. Very large companies were built using these technologies.&lt;/p&gt;
&lt;p&gt;While forward-thinking companies developed the habit of giving back to the community by open-sourcing their code and financially supporting maintainers, we also saw &lt;a href=&quot;https://www.zdnet.com/article/when-open-source-developers-go-bad/&quot;&gt;signs&lt;/a&gt; that this equilibrium was not always stable.&lt;/p&gt;
&lt;p&gt;TeamPCP decided to attack developers because, in some respects, we became an easy target. Also the credentials on our machines are more valuable than ordinary users’ data. Now that writing imperfect but runnable code has become extremely cheap thanks coding agents, we should stop blindly trusting third-party code without security measures in place.&lt;/p&gt;
&lt;h2&gt;What can we do?&lt;/h2&gt;
&lt;p&gt;The creator of Odin, Ginger Bill, argued last year that &lt;a href=&quot;https://www.gingerbill.org/article/2025/09/08/package-managers-are-evil/&quot;&gt;package managers are evil&lt;/a&gt;. I recommend reading the article because it’s very interesting. The key point for this discussion is that we tend to trust others and therefore “assume random code off the internet &lt;em&gt;works&lt;/em&gt;”.&lt;/p&gt;
&lt;p&gt;We have become used to believing that code published online is reliable, and that relying on third-party packages whenever possible is efficient[^2]. We hid the &lt;a href=&quot;https://en.wikipedia.org/wiki/Dependency_hell&quot;&gt;dependency hell&lt;/a&gt; behind automated systems, making it nice and easy to use, but almost impossible to verify what code we are actually importing. If a dependency nested four layers down gets compromised, developers will install and run it, without even realising what happened.&lt;/p&gt;
&lt;p&gt;Token protection, credential rotation, CI monitoring, delayed dependency updates, agentic auditing and supervision can reduce the risk, but they do not remove the design problem. Node, Python, Rust, Ruby and Go all rely on third-party dependencies whose code execute with the same privileges as the application, without being isolated from the rest of the system.&lt;/p&gt;
&lt;p&gt;Going forward, we should seriously consider adopting a &lt;strong&gt;zero-trust mindset&lt;/strong&gt; when developing software.&lt;/p&gt;
&lt;p&gt;npm has &lt;a href=&quot;https://github.blog/changelog/2026-06-09-upcoming-breaking-changes-for-npm-v12/&quot;&gt;recently removed&lt;/a&gt; the ability for packages to run their own scripts during installation. As a result, it will no longer execute &lt;code&gt;preinstall&lt;/code&gt;, &lt;code&gt;install&lt;/code&gt;, or &lt;code&gt;postinstall&lt;/code&gt; scripts from dependencies, which helped previous versions of Shai-Hulud spread.&lt;/p&gt;
&lt;p&gt;One effective approach often proposed online is to &lt;strong&gt;reduce the number of dependencies to a minimum&lt;/strong&gt;. Prefer mature, &lt;strong&gt;actively maintained packages&lt;/strong&gt; with a &lt;strong&gt;limited dependency tree&lt;/strong&gt; and a long, stable release history. This would reduce the probability of being attacked through small, obscure dependencies.&lt;/p&gt;
&lt;p&gt;Also we can consider choosing programming languages that provide &lt;strong&gt;larger standard libraries&lt;/strong&gt; and runtimes, so we can write code faster without the need to import many external packages.&lt;/p&gt;
&lt;p&gt;When dependencies are necessary, they can be distributed with a reliable &lt;strong&gt;release model&lt;/strong&gt; closer to those used by linux distributions like Debian, with different channels such as &lt;code&gt;stable&lt;/code&gt;, &lt;code&gt;testing&lt;/code&gt;, and &lt;code&gt;nightly&lt;/code&gt;. This would allow code to be audited by a larger community of maintainers, preventing frequent release.&lt;/p&gt;
&lt;p&gt;A stronger protection comes from &lt;strong&gt;limiting access to third-party code&lt;/strong&gt;. This has been successfully applied by Apple in macOS, by requiring permission before they can access sensitive folders or other apps’ data.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/img/macos_access_allow.png&quot; alt=&quot;Adobe Photoshop 2025 macOS access screen&quot; title=&quot;You wouldn&amp;#39;t give Photoshop 2025 access to your data, right?&quot;&gt;&lt;/p&gt;
&lt;p&gt;A more effective approach is to &lt;strong&gt;sandbox third-party dependencies&lt;/strong&gt;. The code runs inside an isolated and restricted environment, preventing it from compromising the system.&lt;/p&gt;
&lt;p&gt;These techniques have been partially addressed by the new JavaScript runtime &lt;a href=&quot;https://deno.com/&quot;&gt;Deno&lt;/a&gt;, another project created by Node creator Ryan Dahl. Deno implements runtime permissions and package sandboxing. It provides dependency auditing, minimum-age controls, a larger built-in toolset, and it&amp;#39;s almost entirely compatible with npm packages. It does not eliminate the problem of trusting external dependencies, but it reduces the amount of permissions granted to them by default.&lt;/p&gt;
&lt;p&gt;Whatever we choose, we should start considering every single dependency as a new tradeoff. We need to become responsible for it, rather than expecting someone else to take that responsibility.&lt;/p&gt;
&lt;p&gt;[^1]: One of the latest attack from TeamPCP in May, involved a GitHub developer installing a malicious software extension for VSCode, which ended up in almost 4000 private repositories violated.
[^2]: &lt;a href=&quot;https://www.npmjs.com/package/is-string&quot;&gt;is-string&lt;/a&gt; has 83K weekly download.&lt;/p&gt;
</content:encoded></item><item><title>A conversation between two human beings</title><link>https://scotto.me/notes/2026-07-24-a-conversation-between-two-human-beings/</link><guid isPermaLink="true">https://scotto.me/notes/2026-07-24-a-conversation-between-two-human-beings/</guid><description>A conversation between two human beings</description><pubDate>Fri, 24 Jul 2026 13:34:50 GMT</pubDate><content:encoded>&lt;p&gt;import QuoteBack from &amp;quot;../../components/QuoteBack.astro&amp;quot;;&lt;/p&gt;
&lt;p&gt;&lt;QuoteBack
  author=&quot;Tom MacWright&quot;
  title=&quot;Accidental Anonymity&quot;
  cite=&quot;https://macwright.com/2026/06/24/accidental-anonymity&quot;
  content=&quot;People capable of liking some paintings or prints or whatever can rarely do so without knowing something about the artist. Again, the situation is social rather than scientific. Any work of art is half of a conversation between two human beings, and it helps a lot to know who is talking at you. Does he or she have a reputation for seriousness, for religiosity, for suffering, for concupiscence, for rebellion, for sincerity, for jokes?&quot;
/&gt;&lt;/p&gt;
&lt;p&gt;Here is Kurt Vonnegut telling his brother to show his experimental art in public and to use his face, because “pictures are famous for their humanness, and not for their pictureness”.&lt;/p&gt;
&lt;p&gt;Frequently, when I open a book for the first time, I encounter a new author. I need to know something about them: where and when they lived, what they looked like, what they did besides writing, and what else they wrote. I need to have an idea of the kind of person who is going to tell me a story, because understanding a book often requires me to ask why the author wrote it. What was their purpose?&lt;/p&gt;
&lt;p&gt;It’s a bit the same when I read an article on a blog or look at an open-source project. I want to know the human behind it and read something brief about the author.&lt;/p&gt;
&lt;p&gt;&lt;QuoteBack
  author=&quot;Tom MacWright&quot;
  title=&quot;Accidental Anonymity&quot;
  cite=&quot;https://macwright.com/2026/06/24/accidental-anonymity&quot;
  content=&quot;The fear is being found out for being imperfect. The fear is also for being known in general: maybe you&apos;re a real butch tough guy but your art style is playful and tender and you don&apos;t want that side to come out. Maybe your taste is weird or undeveloped and you don&apos;t want anyone to know. But the person who puts nothing out for judgment just isn&apos;t known at all.&quot;
/&gt;&lt;/p&gt;
&lt;p&gt;Tom is right. At a time when the internet is filling up with artificial content, it is even more important to put ourselves out there rather than remain anonymous. Show that you are real, and give others a reason to trust you before asking for their attention.&lt;/p&gt;
</content:encoded></item><item><title>Introducing a new format</title><link>https://scotto.me/notes/2026-07-24-a-new-format/</link><guid isPermaLink="true">https://scotto.me/notes/2026-07-24-a-new-format/</guid><pubDate>Fri, 24 Jul 2026 13:30:48 GMT</pubDate><content:encoded>&lt;p&gt;I decided to add a new section for short notes that don’t deserve an entire post.&lt;/p&gt;
&lt;p&gt;I’ll mostly use it to share thoughts and interesting links, the kind of content that usually works well on social media. Since I don’t use socials much, I’d rather save those things here, where I have full control over them.&lt;/p&gt;
&lt;p&gt;I’ve also updated the RSS feed page, splitting the content into multiple feeds. I’ll add a new one that includes these notes as well, for the most devoted readers.&lt;/p&gt;
</content:encoded></item><item><title>One tool to read them all</title><link>https://scotto.me/blog/2026-07-23-one-tool-to-read-them-all/</link><guid isPermaLink="true">https://scotto.me/blog/2026-07-23-one-tool-to-read-them-all/</guid><description>Looking for a better way to read content online</description><pubDate>Thu, 23 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Reading some of the feedback on my recent article about &lt;a href=&quot;/blog/2026-07-12-how-to-read-more-books/&quot;&gt;reading more books&lt;/a&gt; made me realise how much the tools we use influence the way we read. One observation in the article was about replacing the time spent on your phone with a book and making your phone look boring to help you do that. It’s easy to pick up a phone and scroll, so it should be easy to use it to read more. So why don’t people use it to read books? Because a phone is a pocket computer designed to distract users, a book is a boring technology designed to focus their attention.&lt;/p&gt;
&lt;p&gt;I’m satisfied with the tools I have for reading books. Unfortunately, I can’t say the same for reading online. After all these years, I still haven’t found a single tool that brings together content discovery, following, reading, and exploring a website’s archive.&lt;/p&gt;
&lt;p&gt;My wish for a perfect online reading experience starts with &lt;em&gt;discovering content&lt;/em&gt;. I want to find interesting material to read, and since time is always limited, I want it to be &lt;em&gt;filtered&lt;/em&gt; according to my interests and &lt;em&gt;ranked&lt;/em&gt; in a transparent way that I can directly influence. Then, when I find a good article, I want a good interface to &lt;em&gt;consume&lt;/em&gt; it. Since the reading experience varies from one website to another, I want a clean interface designed to keep me focused. I also want to be able to highlight passages and take notes, to help me remember and make reading more rewarding. I’d like a way to &lt;em&gt;keep track&lt;/em&gt; of the blogs I follow and get &lt;em&gt;notified&lt;/em&gt; when they publish new content. Lastly, I want a tool that treats &lt;em&gt;older&lt;/em&gt; content as &lt;em&gt;relevant&lt;/em&gt; as newer content. A tool that doesn’t force me to prioritise the latest article.&lt;/p&gt;
&lt;p&gt;This last point is really important to me, since I haven’t found anything yet that tries to solve this problem. Relevant content can be found in the entire archive of a blog, not just in the latest posts. Just as I reach for old books considered classics because they have stood the test of time, I often find articles published years ago still relevant. But to discover those articles, I have to rely on other people’s recommendations or hope that the website I’m visiting has an archive page. Without either, old content could stay buried forever on the web.&lt;/p&gt;
&lt;p&gt;Most of the tools and platforms we use are designed to show content sorted by &lt;em&gt;publication date&lt;/em&gt;, as if it has to be fresh to be worthwhile. And it’s not always an algorithmic decision. Often, it’s simply how the technology has been designed. For how I like to read, the date is just one of the factors that contributes to the value of an article. In some fields, I might prioritise recent content. In others, I’d prefer something that has remained relevant for years, since time can be a sign that an idea has held up. I would like a boring technology that makes reading online a more focused activity, where content is valuable regardless of its novelty. A tool that doesn’t force design decisions or hide content behind algorithmic selection.&lt;/p&gt;
&lt;h2&gt;Discovery&lt;/h2&gt;
&lt;p&gt;The most common solution to fix the discoverability problem is the &lt;em&gt;feed&lt;/em&gt;. It’s the algorithm that decides what content users see on the social media platforms. It helps people find information relevant to their interests and tailor the platform to their needs. The issue is that users have no control over the algorithms. They don’t know why certain content is shown to them, and they cannot directly influence the choice.&lt;/p&gt;
&lt;p&gt;One system I’ve found effective is link aggregators, because they rely on simpler algorithms and usually have a clear interface. I mostly use Hacker News to find new blogs and relevant content in the tech fields. The most interesting articles are ranked daily by the community, where I can contribute directly with my votes and join discussions using the comment system. But when I have to find content unrelated to technology, I don’t have a valid alternative. I have to resort to social-media, video platforms, search engines, hoping that they will do a good job at choosing what I’m looking for.&lt;/p&gt;
&lt;h2&gt;Following&lt;/h2&gt;
&lt;p&gt;The concept of feeds was already used to deliver content before social media. RSS feeds have been used to &lt;em&gt;follow&lt;/em&gt; websites and blogs since the 2000s. Users can subscribe to a website by adding its feed to an RSS reader and get notified whenever something new is published. The main distinction from social media algorithms is that RSS feeds are not a content discovery mechanism, but a &lt;em&gt;subscription&lt;/em&gt; system. Users control which publications they subscribe to, rather than relying on algorithms controlled by platforms.&lt;/p&gt;
&lt;p&gt;What I like about RSS is that it keeps track of the blogs I follow, but beyond that the experience is inconsistent: some feeds contain full articles, others only previews, some include years of archives, and others just the most recent posts. On top of that, RSS readers are designed to prioritise new content, emphasising unread counts and showing the newest articles first. Using RSS feeds might free us from the algorithms, but not from the persistent feeling that we need to keep up with whatever is new.&lt;/p&gt;
&lt;p&gt;RSS apps let users read articles without distractions. But in doing so, readers may never visit the authors’ websites. They might miss features not available in the RSS reader, and their visits might not count for the website’s analytics. Over time, this can end up giving authors less incentive to improve the reading experience on their websites.&lt;/p&gt;
&lt;h2&gt;Reading&lt;/h2&gt;
&lt;p&gt;To improve my reading experience, I rely on read-it-later apps. Instapaper is my favourite so far. It offers a clean and consistent interface across different websites, with useful features like highlights and notes. I’ve saved hundreds of articles over the years, and it’s quite handy to save an article on the desktop and read it later on the tablet or the phone. It works by grabbing the page I’m visiting right now, so if I can read it, Instapaper can likely read it too. The problem is that it does not contribute to content discovery, or following either, since it doesn’t track updates or notify me when new content appears, or help me find more content.&lt;/p&gt;
&lt;h2&gt;Centralised platforms&lt;/h2&gt;
&lt;p&gt;Some startups tried to address all the challenges together, creating publishing platforms on the web. One example is Substack, which offers most of the tools needed to write, to read, to find content and even allows users to escape the algorithmic feed trap with personalised newsletters. That said, the price that readers and writers have to pay for the platform is giving up control over the space where they put the content. &lt;/p&gt;
&lt;p&gt;If all online content gets centralised on a single platform, users will become dependent on it, having to accept whatever product decisions the company might make. There would also be less individuality than there is on the small web, where bloggers and passionate people customise their own websites, potentially controlling every single detail of them. Finally, the incentives these platforms create still push authors to constantly produce new content rather than focus on creating something refined and durable. They still have algorithmic feeds and email marketing that make new content more important by design.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;For now, my online reading remains scattered through many apps and platforms. However, I imagined a solution that has the potential to unify a few of the components of reading online discussed above. It does not have to be another platform or app, but rather something that we all already use to access the internet; the browser.&lt;/p&gt;
&lt;p&gt;Centralised platforms tried to solve the integration problem by putting all the content into a single interconnected system, which is exactly what the web already does. And the web also already partially solved content discovery, since search engines, social media, recommendation platforms and link aggregators are already playing a part. The solution in this case is not to look at the web itself, but observe the problem one layer up. It has to live in the interface we use to access the web. The browser is the layer that sits between readers and independent websites. Modern browsers render pages perfectly, integrate bookmarks, can grab RSS instantly, and most of them already integrate a &lt;em&gt;reading mode&lt;/em&gt; for articles. Connecting these components together is the key to creating a perfect tool to read online, without removing the website itself from the experience. A browser could let me follow a website directly, notify me when it publishes something new, give me a clean place to read it, and let me browse the entire archive without treating the newest articles as inherently more important.&lt;/p&gt;
&lt;p&gt;We saw a recent wave of new browsers that mostly offered UI makeovers on top of existing engines (Blink and Webkit). Maybe a differentiator for the next browser, instead of improving usability or privacy, might be to help people to follow and read more valuable content online.&lt;/p&gt;
&lt;p&gt;Curious to hear your thoughts.&lt;/p&gt;
</content:encoded></item><item><title>A Road to Lisp: Which Lisp</title><link>https://scotto.me/blog/2026-07-17-which-lisp/</link><guid isPermaLink="true">https://scotto.me/blog/2026-07-17-which-lisp/</guid><description>Comparison of modern Lisp dialects</description><pubDate>Fri, 17 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Most programming languages evolve as a single language. Python, Java, Javascript, C++, have new versions and standards, multiple implementations, but they still remain the same language. C and C++ can be compiled with GCC or Clang, Python can be compiled with CPython or PyPy, the same JavaScript runs in both Firefox and Chrome, and Java programs can run on JVM or GraalVM.&lt;/p&gt;
&lt;p&gt;Lisp is not like that.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/img/lisp-logo.svg&quot; alt=&quot;[Lisp Logo]&quot; title=&quot;Lisp logo, NASA version.&quot;&gt;&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://en.wikipedia.org/wiki/Lisp_(programming_language)&quot;&gt;Wikipedia&lt;/a&gt; page lists more than 20 different &lt;em&gt;dialects&lt;/em&gt;, which means there are many variations to choose from. That’s because &lt;strong&gt;Lisp is a &lt;em&gt;family&lt;/em&gt; of programming languages&lt;/strong&gt;. They share the same fundamental syntax but differ in their operators, semantics, standard libraries, and language capabilities.&lt;/p&gt;
&lt;p&gt;One of the main concerns Lisp beginners have is which dialect to learn first. I see this question frequently asked in online forums. The answer is that the dialect matters, but not as much as a beginner might think. Learning Lisp is about learning a new type of programming. &lt;strong&gt;A new way of thinking about problems using code.&lt;/strong&gt; You will learn the fundamental concepts with any dialect. Then, once you have learned one, it will be relatively easy to switch to another.&lt;/p&gt;
&lt;p&gt;I will briefly present the most relevant dialects that are actively used and maintained. I’ll try to highlight their strengths and weaknesses to help you overcome your indecision and pick one to start your Lisp journey. &lt;/p&gt;
&lt;p&gt;If you are a beginner, many of the concepts in this article might be completely new to you. Don’t worry too much about them yet. When I was a beginner, I found many of these concepts fascinating and they pushed me to learn more about the Lisp world.&lt;/p&gt;
&lt;h2&gt;Common Lisp&lt;/h2&gt;
&lt;p&gt;Abbreviated as CL, it is the most mature and comprehensive of all Lisp dialects. It’s considered the old-school Lisp, since the language — I will call it a &lt;em&gt;language&lt;/em&gt; from now on — was standardised in 1994 with a formal ANSI specification. Thanks to this standardisation, there are multiple implementations of Common Lisp targeting different platforms and use cases.&lt;/p&gt;
&lt;p&gt;The most famous implementation is &lt;em&gt;SBCL&lt;/em&gt;, which compiles directly to native code. It is fast, open-source, and compatible with modern hardware. With it, well-written Common Lisp code can achieve performance comparable to C and Rust. Because SBCL optimises heavily, it compiles a bit more slowly than other implementations but generates some of the fastest code in the Lisp family.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/img/common-lisp-logo.svg&quot; alt=&quot;[Common Lisp Logo]&quot; title=&quot;The Yin and Yang Common Lisp logo. The lambda symbol (λ) refer to lambda calculus invented by Alonzo Church.&quot;&gt;&lt;/p&gt;
&lt;p&gt;When I said above that Common Lisp is the most comprehensive dialect, I meant that it offers the broadest set of features among all Lisps. It provides a large amount of functionality out of the box, much of it defined directly in the standard. For example, CL has functions for controlling compilation and evaluation from within the language itself (&lt;code&gt;COMPILE&lt;/code&gt;, &lt;code&gt;LOAD&lt;/code&gt;, &lt;code&gt;EVAL&lt;/code&gt;, &lt;code&gt;COMPILE-FILE&lt;/code&gt;, and others). This means that I can use these functions in my code or at the REPL to tell the Lisp process to compile a function, load a file, or evaluate some code. CL also provides &lt;code&gt;DISASSEMBLE&lt;/code&gt;, which lets you inspect the machine code generated for a compiled function.&lt;/p&gt;
&lt;p&gt;Common Lisp has a condition and restart system, which is one of the most powerful way I ever saw to debug and inspect programs. If a condition occurs during execution, the Lisp process might stop and let you inspect the state of the program and its variables at that point in time. You can then choose to restart the program and maybe retry the operation, or ignore the condition and continue execution. This is also possible because the Common Lisp REPL is deeply integrated with the running system. If your program fails on a remote server, you can connect to its REPL and inspect the live process to understand what went wrong.&lt;/p&gt;
&lt;p&gt;Common Lisp supports all major programming paradigms, like functional, imperative, metaprogramming, and object-oriented programming. It offers one of the most advanced object systems, called &lt;a href=&quot;https://courses.cs.northwestern.edu/325/readings/clos.html&quot;&gt;CLOS&lt;/a&gt;, which supports features such as multiple dispatch and generic functions. This makes OOP more flexible than in common object-oriented languages such as Java or C++. It is also worth noting that Common Lisp is dynamically typed but has a rich and expressive type system with optional type declarations.&lt;/p&gt;
&lt;p&gt;Standardisation means that the language is stable. The ANSI Common Lisp from 1994 is still the one in use today. Because of it, lispers rarely fall victim to &lt;em&gt;backward incompatibility&lt;/em&gt;, and old Common Lisp code often still runs perfectly today. For example, if you go through old Lisp books such as &lt;a href=&quot;https://github.com/norvig/paip-lisp&quot;&gt;PAIP&lt;/a&gt; by Peter Norvig, published in 1991, you’ll find that much of the code still runs on modern implementations. With Common Lisp, you encounter far fewer of the incompatibilities typical of languages like Ruby and Python. Even Common Lisp libraries that haven’t been updated recently will often still run fine on your system because they don’t need to be continually adapted to new versions of the language.&lt;/p&gt;
&lt;p&gt;Common Lisp lacks some conveniences that have become common in newer languages, such as concise literals for a wider variety of data structures, persistent immutable collections, lazy sequences and built-in general-purpose pattern matching. Common Lisp was designed in the 1980s by consolidating several existing Lisp dialects into a single language. Its designers chose to retain much of the syntax and patterns of those older dialects, making sure that existing Lisp programmers could adopt the language without having to learn a completely new syntax.&lt;/p&gt;
&lt;p&gt;Common Lisp doesn’t have a central direction or corporate sponsor. The community is relatively small and spread across several implementations, projects and communication channels. It’s mostly made up of volunteers who help keep the language alive. It can be a bit difficult to find guides and help: tutorials are often either too simple or too advanced, and documentation is not always easy to find.&lt;/p&gt;
&lt;p&gt;It’s currently used in &lt;a href=&quot;https://www.youtube.com/watch?v=svmPz5oxMlI&quot;&gt;quantum computing&lt;/a&gt; at &lt;a href=&quot;https://www.rigetti.com/&quot;&gt;Rigetti Computing&lt;/a&gt;, and has been used at &lt;a href=&quot;https://www.grammarly.com/blog/engineering/running-lisp-in-production/&quot;&gt;Grammarly&lt;/a&gt; for its core grammar service and also powers &lt;a href=&quot;https://www.itasoftware.com/&quot;&gt;Google Flight Search&lt;/a&gt;. Worth mentioning is &lt;a href=&quot;https://codeberg.org/shirakumo/kandria&quot;&gt;Kandria&lt;/a&gt;, an open-source video game released on Steam and written entirely in Common Lisp. &lt;/p&gt;
&lt;p&gt;An interesting fact: Paul Graham originally wrote HackerNews in a custom Lisp dialect called Arc, based on Racket. Today, Daniel Gackle (&lt;a href=&quot;https://news.ycombinator.com/user?id=dang&quot;&gt;@dang&lt;/a&gt;) reimplemented it in Clarc, a Common Lisp implementation of Arc that runs on SBCL&lt;a href=&quot;https://news.ycombinator.com/item?id=41683969&quot;&gt;^1&lt;/a&gt;, serving around 10 million pages per day.&lt;/p&gt;
&lt;h3&gt;Where Common Lisp shines&lt;/h3&gt;
&lt;p&gt;CL compiles to native code on all major operating systems and can achieve fast execution, at the cost of slightly slower startup times, so it’s great for long-running processes. It offers one of the most powerful REPLs among Lisp dialects and can be considered, despite its steep learning curve, one of the fastest languages for writing solid software in a short time.&lt;/p&gt;
&lt;p&gt;CL shines when you need to do research and prototyping with quick iterations, as in quantum computing, or when the specifications aren’t fully defined yet and change frequently, requiring the software to adapt quickly, as in startups. Paul Graham wrote a famous and inspiring &lt;a href=&quot;https://www.paulgraham.com/avg.html&quot;&gt;article&lt;/a&gt; about how Common Lisp helped his internet startup beat the competition.&lt;/p&gt;
&lt;h3&gt;Learning resources&lt;/h3&gt;
&lt;p&gt;A good starting point is &lt;a href=&quot;https://stevelosh.com/blog/2018/08/a-road-to-common-lisp/&quot;&gt;A Road to Common Lisp&lt;/a&gt; by Steve Losh, which inspired me to write this series. One of the most accessible books for beginners is &lt;a href=&quot;https://gigamonkeys.com/book/&quot;&gt;Practical Common Lisp&lt;/a&gt; by Peter Seibel, which is available entirely online. It’s the best introduction to the language I’ve read, as the most important concepts are neatly separated into chapters. A more playful introduction is &lt;a href=&quot;http://landoflisp.com/&quot;&gt;Land of Lisp&lt;/a&gt;, which uses funny characters and comics to teach programming through games. A more advanced book that I enjoyed is &lt;a href=&quot;https://www.paulgraham.com/onlisp.html&quot;&gt;On Lisp&lt;/a&gt; by Paul Graham, which is entirely dedicated to macros.&lt;/p&gt;
&lt;p&gt;The best IDE support for CL is Emacs + &lt;a href=&quot;https://github.com/joaotavora/sly&quot;&gt;Sly&lt;/a&gt;/&lt;a href=&quot;https://slime.common-lisp.dev/&quot;&gt;Slime&lt;/a&gt; (&lt;a href=&quot;https://github.com/doomemacs/doomemacs&quot;&gt;Doom&lt;/a&gt; already has support for it) or Vim + &lt;a href=&quot;https://github.com/vlime/vlime&quot;&gt;VLime&lt;/a&gt;. A weaker alternative is VSCode + &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=rheller.alive&quot;&gt;Alive&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;One of the best resources for beginners is &lt;a href=&quot;https://lispcookbook.github.io/cl-cookbook/&quot;&gt;The Common Lisp Cookbook&lt;/a&gt;, which has many up-to-date tutorials. For references and libraries, the &lt;a href=&quot;https://github.com/CodyReichert/awesome-cl&quot;&gt;Awesome-CL&lt;/a&gt; list is worth a look. I also printed my own copy of the &lt;a href=&quot;http://clqr.boundp.org/&quot;&gt;Common Lisp Quick Reference&lt;/a&gt; booklet, which can be faster than finding information in the CL &lt;a href=&quot;https://www.lispworks.com/documentation/HyperSpec/Front/index.htm&quot;&gt;HyperSpec&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Clojure&lt;/h2&gt;
&lt;p&gt;Rich Hickey created it during a sabbatical year, frustrated by clients refusing to let him use Common Lisp instead of Java and C# because they were concerned about compatibility and maintenance issues. So he decided to write a new Lisp language targeting the JVM, allowing it to access everything the Java ecosystem had built over decades and making it a practical language from the start. The deal is that Clojure provides the language, while the host platform — the JVM — provides the runtime.&lt;/p&gt;
&lt;p&gt;Clojure compiles directly to JVM bytecode, which means it’s compatible with any codebase that runs on the JVM (Java, Kotlin, Scala). This compatibility means that Clojure can coexist with other JVM languages in the same codebase, use Java libraries directly, and access all the features the JVM offers, such as OS portability, garbage collection, a fast and optimised runtime, and so on.&lt;/p&gt;
&lt;p&gt;Rich Hickey chose to target the JVM so that he didn&amp;#39;t have to reinvent the wheel and build a new compiler for Clojure from scratch. Instead, he focused his efforts on reading research papers on language design and data structures, bringing some of the newest and most effective ideas into the language.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/img/clojure-logo.svg&quot; alt=&quot;[Clojure Logo]&quot; title=&quot;The Clojure logo, designed by Tom Hickey, Rich&amp;#39;s brother.&quot;&gt;&lt;/p&gt;
&lt;p&gt;The language at its core is composed of &lt;strong&gt;pure functions operating on immutable data structures&lt;/strong&gt;. Instead of making mutable objects the primary way to represent changing state, it provides explicit mechanisms such as &lt;em&gt;atoms&lt;/em&gt;, &lt;em&gt;refs&lt;/em&gt; and &lt;em&gt;agents&lt;/em&gt; for managing change. This design choice makes Clojure a &lt;em&gt;functional&lt;/em&gt; programming language. It supports object-oriented programming, but replaces class-based inheritance with abstractions such as protocols and multimethods. Also the syntax is more modern than Common Lisp’s, with richer literals, destructuring, and overall more compact code.&lt;/p&gt;
&lt;p&gt;Clojure also comes with several new features. Its persistent data structures use structural sharing, making immutable updates efficient. It also uses lazy sequences, which allow computations to be performed only when their results are needed. It has strong support for concurrency through constructs such as &lt;em&gt;atoms&lt;/em&gt;, &lt;em&gt;refs&lt;/em&gt;, &lt;em&gt;agents&lt;/em&gt; and &lt;em&gt;futures&lt;/em&gt;, and provides &lt;em&gt;records&lt;/em&gt; and custom data types when more structured data is needed. &lt;a href=&quot;https://github.com/edn-format/edn&quot;&gt;EDN&lt;/a&gt; (Extensible Data Notation) offers a simple extensible data format based on Clojure’s literals, a better lispy alternative to JSON, YAML and similar. Clojure doesn&amp;#39;t have types, but &lt;code&gt;clojure.spec&lt;/code&gt; can be used to describe, validate and generate data without introducing a static type system, useful in large applications.&lt;/p&gt;
&lt;p&gt;Rich Hickey designed Clojure with the intention of prioritising stability, similar to what standardisation did for Common Lisp. Even though the language is actively developed, you don’t need to expect major deprecations when updating to a newer version, since the maintainers preserve backwards compatibility and mostly add new features through core libraries.&lt;/p&gt;
&lt;p&gt;Since Clojure is designed to be hosted on other platforms, it can be ported to other runtimes, like the JavaScript engine that runs in your browser. &lt;em&gt;ClojureScript&lt;/em&gt; is a Clojure compiler that targets JavaScript rather than the JVM, so the same language can run on both the server and the browser. This means that Clojure can be used as a full-stack language.&lt;/p&gt;
&lt;p&gt;The JVM integration is great, but it comes with some trade-offs. Error messages are contaminated with a lot of Java implementation details and aren’t always self-explanatory, so stack traces are not necessarily helpful when debugging issues. Java profilers like YourKit are compatible, but even there you will see a lot of Java classes, and it can be hard to map them back to the code you wrote.&lt;/p&gt;
&lt;p&gt;In general you don’t need to know Java to learn Clojure. I didn’t know Java when I started and never had substantial problems because of that. However, knowing how to tweak the JVM can be helpful when doing performance tuning on the server.&lt;/p&gt;
&lt;p&gt;The community around Clojure is small but active and happy to help newcomers pick up the language quickly. It’s known as &lt;em&gt;Clojurians&lt;/em&gt; and mostly hangs out on Slack, where you can also collaborate on open-source projects and find job opportunities.&lt;/p&gt;
&lt;p&gt;Clojure is actively used by companies and startups around the world, and it’s probably the most widely used Lisp in production. Some big names include Nubank (one of the largest fintech companies in Latin America), which acquired Cognitect (the main sponsor of Clojure’s development), as well as Walmart, Netflix, Apple, Salesforce, Amazon, Cisco, and Grammarly.&lt;/p&gt;
&lt;h3&gt;Where Clojure shines&lt;/h3&gt;
&lt;p&gt;Clojure shines in large software systems where the workload consists of a lot of data processing, or more broadly, anywhere you might previously have picked Java. Code can be written and tested quickly through continuous iteration thanks to the REPL, making the language suitable for delivering reliable solutions in less time. Its immutable design helps eliminate some of the hardest concurrency bugs, while its functional orientation guides programmers towards writing programs as a series of data transformations.&lt;/p&gt;
&lt;p&gt;Clojure is great in fields where operations need to happen quickly and often involve processing large sets of data, such as finance and trading. It’s also great for startups solving domain-specific problems with complex logic, since the language’s extensibility allows it to be modelled around the problem.&lt;/p&gt;
&lt;h3&gt;Learning resources&lt;/h3&gt;
&lt;p&gt;To give Clojure a try, you might want to check out &lt;a href=&quot;https://tryclojure.org/&quot;&gt;Try Clojure&lt;/a&gt;, then solve some exercises like the &lt;a href=&quot;http://clojurekoans.com/&quot;&gt;Clojure Koans&lt;/a&gt;, followed by &lt;a href=&quot;https://4clojure.oxal.org/&quot;&gt;4Clojure&lt;/a&gt; for more advanced stuff.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://clojure.org/index&quot;&gt;official website&lt;/a&gt; offers some of the most curated material you can find, with great explanations of all the core features and the motivations behind the design choices that make the language special. Clojure also has one of the best &lt;a href=&quot;https://clojuredocs.org/&quot;&gt;documentation&lt;/a&gt; websites I’ve ever found for a language. All the core library functions come with docstrings, and the community has added usage examples, so you can quickly grasp what each function does.&lt;/p&gt;
&lt;p&gt;The best &lt;em&gt;pitch&lt;/em&gt; for the language is &lt;a href=&quot;https://yogthos.net/ClojureDistilled.html&quot;&gt;Clojure Distilled&lt;/a&gt;. It’s probably one of the shortest explanations of what Clojure has to offer.&lt;/p&gt;
&lt;p&gt;After the release of Clojure, Rich Hickey became famous for a series of talks about software design, in which he shared his deep expertise in fundamental topics like simplicity in software design, state and time, databases, concurrency, and language design. Some of his best talks — &lt;a href=&quot;https://www.youtube.com/watch?v=SxdOUGdseq4&quot;&gt;&lt;em&gt;Simple Made Easy&lt;/em&gt;&lt;/a&gt;, &lt;a href=&quot;https://www.youtube.com/watch?v=-6BsiVyC1kM&quot;&gt;&lt;em&gt;The Value of Values&lt;/em&gt;&lt;/a&gt;, &lt;a href=&quot;https://www.youtube.com/watch?v=f84n5oFoZBc&quot;&gt;&lt;em&gt;Hammock-Driven Development&lt;/em&gt;&lt;/a&gt;, &lt;a href=&quot;https://www.youtube.com/watch?v=ScEPu1cs4l0&quot;&gt;&lt;em&gt;Are We There Yet?&lt;/em&gt;&lt;/a&gt;, and &lt;a href=&quot;https://www.youtube.com/watch?v=QCwqnjxqfmY&quot;&gt;&lt;em&gt;Design, Composition, and Performance&lt;/em&gt;&lt;/a&gt;. I highly recommend spending some time watching them, whether you choose Clojure or not.&lt;/p&gt;
&lt;p&gt;Some good books are &lt;a href=&quot;https://www.braveclojure.com/&quot;&gt;Clojure for the Brave and True&lt;/a&gt; by Daniel Higginbotham, which is free to read online and good for beginners. The one I bought is &lt;a href=&quot;https://www.amazon.com/dp/1617291412&quot;&gt;The Joy of Clojure&lt;/a&gt;, which is recommended for programmers who come from OOP languages like Java.&lt;/p&gt;
&lt;p&gt;For editors, VSCode has &lt;a href=&quot;https://calva.io/&quot;&gt;Calva&lt;/a&gt;, a complete and rich extension for Clojure. If you use Emacs you can use &lt;a href=&quot;https://cider.mx/&quot;&gt;Cider&lt;/a&gt;, plus there are extensions available for most editors/IDEs.&lt;/p&gt;
&lt;h2&gt;Racket&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://racket-lang.org/&quot;&gt;Racket&lt;/a&gt; is a modern dialect descended of &lt;em&gt;Scheme&lt;/em&gt;. While other Scheme dialects are generally small languages, Racket has evolved into a fully featured language with its own unique features.&lt;/p&gt;
&lt;p&gt;The code is compiled on every major platform and the language has been used in a lot of fields to create web applications, graphical interfaces, database integrations and mostly to quickly develop tools with graphics.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/img/racket-logo.svg&quot; alt=&quot;[Racket Logo]&quot; title=&quot;Racket logo.&quot;&gt;&lt;/p&gt;
&lt;p&gt;Racket is &lt;strong&gt;language-oriented&lt;/strong&gt;, which means it’s designed for creating &lt;a href=&quot;https://racket-lang.org/languages.html&quot;&gt;new programming languages&lt;/a&gt;. Every source file begins with &lt;code&gt;#lang&lt;/code&gt;, which defines the language used by that module. You can create entirely new languages with their own syntax and semantics, while still using the Racket ecosystem underneath. Other Lisp dialects can easily build DSLs, but they are tied to Lisp. Racket advances the concept by making it easy to define completely new languages, without requiring them to use Lisp syntax.&lt;/p&gt;
&lt;p&gt;Racket also comes with a wide range of features. It includes libraries for cross-platform GUIs, web servers, concurrency and parallelism, regular expressions, pattern matching, classes and objects, and an FFI for calling C code. Its package manager is integrated into the ecosystem, and a large collection of libraries is immediately available. Compared with other Lisp dialects, there is generally less setup required before you can start building something substantial.&lt;/p&gt;
&lt;p&gt;Racket offers an advanced macro system, providing the same kind of macro support as other dialects, plus hygienic macros. &lt;em&gt;Hygienic&lt;/em&gt; means that identifiers introduced by a macro don’t accidentally capture those in the surrounding code. This makes macros safer to write, especially for beginners, that don’t have to rely on &lt;code&gt;gensym&lt;/code&gt; like in the other dialects.&lt;/p&gt;
&lt;p&gt;Static typing is supported with &lt;a href=&quot;https://docs.racket-lang.org/ts-guide/&quot;&gt;Typed Racket&lt;/a&gt;, a typed variant of the language that lets programmers add type annotations and have their code checked before execution. Typed and untyped Racket modules can also work together, so typing can be introduced where it is useful without requiring an entire program to be rewritten.&lt;/p&gt;
&lt;p&gt;Even though Racket comes from the Scheme tradition and has strong functional programming roots, it supports multiple paradigms. Programs can be written using imperative programming, objects and classes, functional techniques, and metaprogramming.&lt;/p&gt;
&lt;p&gt;The language installation comes with &lt;a href=&quot;https://docs.racket-lang.org/drracket/&quot;&gt;DrRacket&lt;/a&gt;, a great IDE with everything ready to use the language, available on all major platforms. It combines an editor, REPL, and debugger, in a single programming environment for writing and testing Racket code.&lt;/p&gt;
&lt;p&gt;The main downsides are its small ecosystem and limited use in the industry. There are fewer libraries, projects and jobs compared to more popular languages. Performance and deployment can also be weaker points, especially compared with other compiled dialects.&lt;/p&gt;
&lt;h3&gt;Where Racket shines&lt;/h3&gt;
&lt;p&gt;Racket shines when designing new programming languages, building compilers and interpreters, or experimenting with new language features. This makes it particularly popular in computer science education and university research. Also, since it’s language-oriented, it’s a great choice when a program needs to provide a simple DSL, for example for customisation, without forcing the user to use a Lisp dialect.&lt;/p&gt;
&lt;p&gt;Racket is ideal for prototyping, scripting, and projects where having a comprehensive set of libraries and development tools immediately available is important. It’s worth noting that other dialects offer GUI support through external libraries and wrappers, while in Racket it is available out of the box.&lt;/p&gt;
&lt;h3&gt;Learning Resources&lt;/h3&gt;
&lt;p&gt;Racket has a rich website with a lot of helpful information. Important resources for beginners include &lt;a href=&quot;https://docs.racket-lang.org/quick/&quot;&gt;Quick: An Introduction to Racket with Pictures&lt;/a&gt; and &lt;a href=&quot;https://docs.racket-lang.org/guide/&quot;&gt;The Racket Guide&lt;/a&gt;, which is the complete guide to the language. Also worth mentioning is &lt;a href=&quot;https://beautifulracket.com/&quot;&gt;Beautiful Racket&lt;/a&gt; by Matthew Butterick, a visually curated guide to the language written by a passionate contributor. If you’re looking to write a compiler, check out &lt;a href=&quot;https://kmicinski.com/functional-programming/2025/11/23/build-a-language/&quot;&gt;this course&lt;/a&gt; using Racket.&lt;/p&gt;
&lt;p&gt;The best resource available for Scheme is &lt;a href=&quot;https://web.mit.edu/6.001/6.037/sicp.pdf&quot;&gt;SICP&lt;/a&gt;, also known as the &lt;em&gt;Wizard Book&lt;/em&gt;. It’s not only about Lisp, but it’s a great book for learning the fundamentals of programming and programming languages. It’s also worth mentioning a rather unusual book, &lt;a href=&quot;https://www.goodreads.com/en/book/show/548914.The_Little_Schemer&quot;&gt;The Little Schemer&lt;/a&gt;, which consists of a long series of questions that forces the reader to think before looking at the answer on the page.&lt;/p&gt;
&lt;h2&gt;Special Mention&lt;/h2&gt;
&lt;h3&gt;Elisp&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://learnxinyminutes.com/elisp/&quot;&gt;Elisp&lt;/a&gt; is a specialised dialect that’s part of Emacs and is used to customise the editor. It’s an old Lisp dialect that comes with quite a few limitations, but it’s probably one of the best practical uses I’ve ever found for Lisp, beyond using it as a general-purpose programming language. It’s used to customise and extend the functionality of Emacs, since much of the editor itself is written in Elisp. By evaluating Elisp code inside it, you can change how Emacs looks and behaves in real time, without requiring a reload.&lt;/p&gt;
&lt;h4&gt;Learning resources&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;https://www.gnu.org/software/emacs/manual/eintr.html&quot;&gt;An Introduction to Programming in Emacs Lisp&lt;/a&gt; is freely available online. Another useful resource is &lt;a href=&quot;https://protesilaos.com/emacs/emacs-lisp-elements&quot;&gt;Emacs Lisp Elements&lt;/a&gt; by Protesilaos Stavrou, an active Emacs contributor and advocate.&lt;/p&gt;
&lt;h2&gt;Syntax comparison&lt;/h2&gt;
&lt;p&gt;We can use a simple instruction interpreter to show some of the syntactic differences between the dialects.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-lisp&quot;&gt;(defun calculate (instructions)
  (loop with result = 0
        for (operation value) in instructions
        do (setf result
                 (case operation
                   (add      (+ result value))
                   (subtract (- result value))
                   (multiply (* result value))))
        finally (return result)))

(calculate &amp;#39;((add 5) (multiply 3) (subtract 4))) ;; =&amp;gt; 11
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In Common Lisp, I used the &lt;code&gt;LOOP&lt;/code&gt; macro to iterate over and destructure each instruction, then perform the operation by updating local state. Notice that it carries an accumulator (&lt;code&gt;result&lt;/code&gt;) through the sequence, essentially doing the same job as a &lt;code&gt;reduce&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-clojure&quot;&gt;(defn calculate [instructions]
  (reduce
    (fn [result [operation value]]
      (case operation
        :add      (+ result value)
        :subtract (- result value)
        :multiply (* result value)))
    0
    instructions))

(calculate [[:add 5] [:multiply 3] [:subtract 4]]) ;; =&amp;gt; 11
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In Clojure, I used a reduction over the sequence of instructions. Notice that it doesn’t use or update any local state, since the reduction uses immutable accumulation. I also used some syntax that is specific to Clojure, such as vectors &lt;code&gt;[]&lt;/code&gt; and keywords like &lt;code&gt;:add&lt;/code&gt;, and destructured the contents of each vector with &lt;code&gt;[operation value]&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-racket&quot;&gt;(define (calculate instructions)
  (for/fold ([result 0])
            ([instruction (in-list instructions)])
    (match instruction
      [(list &amp;#39;add value)
       (+ result value)]
      [(list &amp;#39;subtract value)
       (- result value)]
      [(list &amp;#39;multiply value)
       (* result value)])))

(calculate &amp;#39;((add 5) (multiply 3) (subtract 4))) ;; =&amp;gt; 11
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In Racket, we use &lt;code&gt;for/fold&lt;/code&gt; to iterate over the instructions while carrying the result from one iteration to the next. We also use pattern matching with &lt;code&gt;match&lt;/code&gt; to destructure each instruction and identify the operation at the same time. For example, &lt;code&gt;(list &amp;#39;add value)&lt;/code&gt; matches a two-element list whose first element is the symbol &lt;code&gt;add&lt;/code&gt; and binds the second element to &lt;code&gt;value&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Which one to pick?&lt;/h2&gt;
&lt;p&gt;To summarise the above:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Clojure&lt;/strong&gt; gives you modern syntax, functional programming and immutable data structures, great tooling and libraries, an almost drop-in replacement for Java, a full-stack language, a strong community, and maybe even a job.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Common Lisp&lt;/strong&gt; gives you native compilation, high performance, the most powerful REPLs, multi-paradigm programming, and a stable, battle-tested language.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Racket&lt;/strong&gt; gives you a feature rich language, a great IDE for beginners, a cross-platform GUI, a powerful platform for building new languages and DSLs, easily approachable for students.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Elisp&lt;/strong&gt; gives you the ability to extend and customise Emacs.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For most programmers looking for a practical and elegant Lisp they could use professionally, &lt;strong&gt;Clojure is probably the safest first choice&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;If you want to experience the traditional Lisp development model at its fullest, you want native compilation without rely on JVM, an exceptionally interactive environment and a huge language, choose &lt;strong&gt;Common Lisp&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;If you are a computer science student, interested in compilers and programming-language design, or if you need a quick way to write tools or need an easy way to use a cross-platform GUI, choose &lt;strong&gt;Racket&lt;/strong&gt;. This is probably the easiest to start with between the dialects.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;If you have any questions of feedback, please send me an email.&lt;/p&gt;
</content:encoded></item><item><title>Confessions of an emigrant</title><link>https://scotto.me/blog/2026-07-15-confessions-of-an-emigrant/</link><guid isPermaLink="true">https://scotto.me/blog/2026-07-15-confessions-of-an-emigrant/</guid><description>Reflection on receiving my Australian citizenship</description><pubDate>Wed, 15 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Today at 3 pm I officially became an Australian citizen. I felt it was a formality, since I already had a permanent residency. But when I was sitting in the city hall, together with others that were receiving the citizenship as well, I reflected about the last few years I spent abroad and what it actually means being an emigrant. Looking back at my past, it seemed obvious that, sooner or later, I would have moved to another country.&lt;/p&gt;
&lt;p&gt;It all started in the early years of my adulthood, when I had the chance to fly to and work in Silicon Valley three times. During that period, I also moved to Turin to study at the university, in a much bigger city than the small town where I grew up. Something started changing in me back then. I appreciated the new level of freedom that I gained by leaving my parents&amp;#39; house, and I developed a certain thirst for what I believed the rest of the world had to offer. The thought of a future in my small town, seeing the same places, facing the same issues, having my entire family around all the time, and the feeling that certain things there were too slow to change, was frightening me. I didn’t want to feel stuck in that place.&lt;/p&gt;
&lt;p&gt;Also I wanted to be challenged, I wanted to confront difficulties and experience new surroundings. I believe there are few experiences as eye-opening as living for months, or even better, years, in another country.&lt;/p&gt;
&lt;p&gt;I wasn&amp;#39;t sure where or how I would move, but I knew I could find a way if I truly wanted to. On Facebook I can still see the groups I joined at the time to get a genuine, unspoiled insight into what life was like in different cities: “Italians in London”, “Italians in Valencia”, “Italians in Berkeley”, “Italians in Amsterdam”, “Italians in Dublin”. I was naive. I was trying to find something familiar that would soften the culture shock I knew would hit me once I stepped out of my comfort zone. I was trying to play it safe, not knowing what to expect.&lt;/p&gt;
&lt;p&gt;In those Facebook groups I still see many compatriots every day who ask what life is like there, how much it costs to live, whether there are enough jobs, and whether it&amp;#39;s worth moving their entire family to the other side of the world. I can see my younger self in their worries and their hope for a different future. They don’t know yet what emigrating really means. &lt;/p&gt;
&lt;p&gt;What I also find in those groups is the constant clash between those who defend their home country and those who criticise it, praising how much better their lives abroad are. This might seem like a typical social media interaction, but I think there&amp;#39;s another side to the story that people are overlooking. When you move abroad, you&amp;#39;re expected to do better, to build a better life. Otherwise, why would you do it?&lt;/p&gt;
&lt;p&gt;It&amp;#39;s a sort of unspoken expectation that every emigrant has to live up to, especially when interacting with people from back home. You don&amp;#39;t move abroad to live a life worse than the one you had at home. You have to “make it”, whatever that means. You can&amp;#39;t really talk about your struggles, the loneliness, the career setbacks, the sense of cultural isolation. Is not that simple to say that you miss what you left behind. Many emigrants end up hiding the reality of life abroad. They wear a mask to live up to the expectations of their family, friends, and the compatriots they left behind. They no longer live at home, they abandoned the land. The everyday problems of their compatriots are no longer theirs. They are in a liminal space between two countries, no longer physically present in one, but not yet belonging to the other.&lt;/p&gt;
&lt;p&gt;The truth is that life abroad is never easy, nor is it necessarily better than what we had at home. The job situation can be a rollercoaster. It wasn&amp;#39;t easy to tell my parents that I was picking fruit when, just a few months earlier, I had a high paying office job. It took me a while to get back to my original career, and in the meantime I had to work in less pleasant jobs where I was overqualified or overworked. I had to fill those gaps on my CV with something, because recruiters don’t care about immigration policies. Australia is a welcoming country, and its people are kind and generally open-minded, but I still feel like an immigrant every day. I had to adjust how I speak and behave, and I’m still working on softening my accent in order to fit in. I still carry the contradiction of being someone who “made it” back home while still being perpetually viewed as an outsider in my new country.&lt;/p&gt;
&lt;p&gt;I have missed important moments in the lives of the people I care about. My sister had a child, and I am not there to watch my nephew grow up. My school friends are getting married, and I’m not there to celebrate with them. I will not share some of their happiest moments, and they will not share mine. One day, my parents might fall seriously ill, and I might not be there when they need me most. These are costs I had to be willing to accept.&lt;/p&gt;
&lt;p&gt;The culture that shaped my childhood cannot be found overseas. I can join a small community of expatriates, buy imported products and spend time cooking a nice meal. I can find book in my language, teach my kids Italian while we visit my relatives. But I know it will be hard to transmit the same culture. Whatever home was for me cannot be bought online or shipped overseas in boxes. If I want to feel it again, I have to go back to it.&lt;/p&gt;
&lt;p&gt;I&amp;#39;ve had the opportunity to meet several emigrants in my life, mostly Italians like me, because we tend to gravitate towards one another, as if our shared culture acted like a magnet. Some of them returned to Italy after years of living overseas because they never found a reason strong enough to stay. Some of them kept moving from country to country before eventually returning to Italy when the right opportunity arose. Some people built a life abroad, advancing their careers and starting a family, while others are still trying to figure out where they belong. It&amp;#39;s impossible to predict what life abroad will be like for someone else, or how well they&amp;#39;ll cope with its challenges.&lt;/p&gt;
&lt;p&gt;After all this, one last confession, one that&amp;#39;s usually hard for an immigrant to admit. No matter how successful you become, how much money you make, or how much your life improves by moving overseas, there will always be moments when you feel a sense of regret, when you&amp;#39;ll be tempted to reply to those people on Facebook and tell them, “No. Don’t leave. It’s not worth it.” Then those moments pass, and life goes back to normal. They are simply part of choosing one life over another.&lt;/p&gt;
&lt;p&gt;Today, becoming an Australian citizen made that choice feel more permanent than ever. I don&amp;#39;t know whether Australia will ever feel like home in exactly the same way Italy does, and perhaps it doesn&amp;#39;t have to.&lt;/p&gt;
&lt;p&gt;And now it&amp;#39;s time for me to celebrate. For the occasion, I&amp;#39;ll have a chicken parmi with gravy. Wish me luck.&lt;/p&gt;
</content:encoded></item><item><title>How to read more books</title><link>https://scotto.me/blog/2026-07-12-how-to-read-more-books/</link><guid isPermaLink="true">https://scotto.me/blog/2026-07-12-how-to-read-more-books/</guid><description>My method for reading more</description><pubDate>Sun, 12 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I&amp;#39;ve read roughly a book a week for a few years, and I can tell you it&amp;#39;s doable. I didn&amp;#39;t always read this much. When I started, I read fewer than ten volumes per year, but making it a goal made me switch gears and achieve what I once thought was impossible. I want to explain what I did to become a prolific reader, and what I learned in the process, so that, with a bit of effort, you can do it too. I promise, it will be worth it.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/img/umberto_eco.jpg&quot; alt=&quot;[Umberto Eco in his library]&quot; title=&quot;Umberto Eco had a library of more than 30,000 books.&quot;&gt;&lt;/p&gt;
&lt;p&gt;First of all, you don&amp;#39;t have to make time to read. What you need to do is read every single time you are not doing something else. In today&amp;#39;s world, most people pick up their phones as soon as they get a moment of inactivity. Serious readers pick up their books instead. So an effective way is to replace the time you spend in front of a screen, like PCs, smartphones, and TVs, with time spent reading a book.&lt;/p&gt;
&lt;p&gt;This is probably the most difficult part. I had to remove all social media and streaming apps from my iPhone. I removed Instagram, YouTube, Facebook, etc. When I started, I found myself picking up the phone and immediately noticing that something was missing, since the only things left to do were to check the weather and read boring emails. After a few days my brain started remapping itself, and I felt less pressure to immediately reach for my phone as soon as I had nothing to do. I also wear a cheap analogue watch so I can check the time on my wrist and I don&amp;#39;t have to reach for my phone.&lt;/p&gt;
&lt;p&gt;Once you remove these distractions from your smartphone, you might find yourself a bit uncomfortable with having nothing to occupy your mind for ten minutes. This is the perfect time to boost your reading habit. You need to make sure you always have a book with you everywhere you go. I usually read a few pages as soon as I wake up, and do the same before falling asleep. I read while cooking lunch or dinner, or while eating breakfast. I love using public transport, especially trains, because I get time to read while someone else is driving for me.[^1] I always have a book with me when I go out with my partner, even if I don&amp;#39;t usually end up reading it. If she has to run an errand and I have to wait, I don&amp;#39;t waste time with nothing to read. I have become good at walking my dog while reading — I even got complimented for that by a stranger — and I make sure I never go to the bathroom without a book.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“I love the smell of book ink in the morning.”
— Umberto Eco&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Carrying a book wherever I go can become problematic, depending on its size. The best solution I have found is to use an ebook reader. They are thin devices that can fit in a pocket and are able to store hundreds of books. For a reader, an ebook reader might be one of the best inventions ever, considering how expensive books have been throughout history and how difficult they have always been to carry around. Ebooks, by contrast, are cheap. Moreover, you can have a backlight for reading in the dark — it doesn&amp;#39;t strain the eyes — and you can highlight text, take notes and get definitions for words. However, it&amp;#39;s not really a replacement for a book. After a while, always reading on an ebook reader feels like reading the same book, even if the story changes. I like to alternate digital books and physical ones, and I always prefer paperbacks since they are easier to carry around and cheaper to buy.&lt;/p&gt;
&lt;p&gt;I tend to read multiple books at the same time, since having only a single option can be boring. Sometimes I get so into a book that I put the others on pause because the story is taking up all my attention, but in general I like to have a few books that I read in parallel. I generally mix fiction and non-fiction to have a broader choice.&lt;/p&gt;
&lt;p&gt;What to read is a difficult question. I once read a phrase somewhere that puts it quite well: “read what you like until you like to read.” My suggestion is to read broadly, changing genres and subjects, because there are well-written books in every genre. Varying the topics can expose you to different perspectives. And sooner or later, you will understand which genres you like more.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“It is foolish to think that you have to read all the books you buy, as it is foolish to criticize those who buy more books than they will ever be able to read. It would be like saying that you should use all the cutlery or glasses or screwdrivers or drill bits you bought before buying new ones.”
— Umberto Eco&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Another secret is to not be scared of quitting books. I definitely start way more books than I finish. But I don&amp;#39;t consider an unfinished book a failure or a bad book. I think that certain books require the right time to be fully appreciated. So if I don&amp;#39;t finish a book today, I might try reading it again in the future. I still remember having abandoned &lt;a href=&quot;https://www.goodreads.com/en/book/show/52036.Siddhartha&quot;&gt;Siddhartha&lt;/a&gt; by Herman Hesse at least three times after the first few pages, before finally finishing it and considering it one of the most formative books of my life. Somehow I wasn&amp;#39;t ready for it the first time, and I had to wait for the right moment to fully understand it. Also, I believe there are way more bad books out there than good books. If you feel that you are not enjoying a book, it feels boring and makes you think you are wasting your time, just close it and move on. I have closed books by authors that I loved, because they weren&amp;#39;t as good as the rest of their work.&lt;/p&gt;
&lt;p&gt;If you are a serious reader, you need a library with physical books. So try to stack copies of books on your shelves for later. When I buy new books, it is mostly because I need a specific one I cannot find otherwise, or because I want to support local independent bookshops. However, I generally buy more used books than new ones. I usually find them in the book section of used stores, at markets, book fairs, and sometimes in the book boxes that I find around the city.[^2]&lt;/p&gt;
&lt;p&gt;An effective method to push yourself to read more is to set some goals. You can pick a reasonable number of books for the month or the year and try to reach it. Tracking progress is a well-known trick used to form new habits. Goodreads, for example, has what&amp;#39;s called the &lt;a href=&quot;https://help.goodreads.com/s/article/What-are-Reading-Challenges&quot;&gt;Reading Challenge&lt;/a&gt;, which helps you keep track of how many books you read in a year. I found it motivating to put in the effort to stay on track with the number I wanted to read. However, counting the volumes is not a healthy way of reading. It&amp;#39;s much better to read great books and take the right amount of time to understand and reflect on them rather than rushing to finish books just to increase the final count. You need to enjoy the process and get a good outcome from your reading.&lt;/p&gt;
&lt;p&gt;Writing a review is also a great method to make a book stick in your memory. Taking highlights and notes while you&amp;#39;re reading is a good thing, but revisiting them alongside your thoughts in a written document is something different. Reviewing books is a great way to become better at understanding what the messages contained in the books are and what the key elements of the story are. In addition, if you like writing, it&amp;#39;s a good reason to practise.&lt;/p&gt;
&lt;div class=&quot;video-container flex justify-center mb-10&quot;&gt;
    &lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/UoEuvgT1wBs?si=6N8uFfbgqh5F3rGG&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;p&gt;One of the duties of a serious reader is to find what to read next. I always have a long list of books to read, but I don&amp;#39;t stick to it all the time. I like to be immersed in something new and discover new authors or genres. I usually use two things: Goodreads and YouTube. The first one helps me form an idea of a book before I get to reading it, thanks to reviews and comments from people I follow. YouTube, on the other hand, is great for listening to book reviews to get recommendations. There are many great channels out there, and I watch quite a few of them. One of my favourites in English is &lt;a href=&quot;https://www.youtube.com/@BetterThanFoodBookReviews&quot;&gt;Better Than Food&lt;/a&gt;, which has reviewed books for more than a decade.&lt;/p&gt;
&lt;p&gt;What inspired me to try to read more was &lt;a href=&quot;https://www.youtube.com/watch?v=lIW5jBrrsS0&quot;&gt;this video&lt;/a&gt;, where Max Joseph explains that becoming a serial reader is just a matter of making a daily habit of reading a few pages, with surprisingly good results. Also, &lt;a href=&quot;https://www.youtube.com/watch?v=VA6kJoUEqPY&quot;&gt;Ryan Holiday&lt;/a&gt; — a famous author — has recently published a good guide on how to read more books with his own tips and tricks.&lt;/p&gt;
&lt;p&gt;One last recommendation: avoid hacks. Avoid speed reading. And don&amp;#39;t try to force yourself to increase your reading speed. It will come naturally the more you read. Avoid summaries and summary services. It might be okay to use them after you read a book to make sure you didn&amp;#39;t miss some parts, but reading a summary does not equal reading a book. Avoid audiobooks too. Big corporations want to grab your attention by trying to market audiobooks as books for busy people, but don&amp;#39;t fall into the trap. A book is just boring black text on a white page because that&amp;#39;s how it&amp;#39;s meant to be consumed, and it requires your full attention. Listening to audio while cooking or cleaning or whatever you do is not the same thing; you are not fully focused on the content. Also, reading is faster than listening, so use your time wisely.&lt;/p&gt;
&lt;p&gt;[^1]: I consider driving a huge waste of time. Sometimes it can be fun and adventurous, but I think life is too short to drive to work every day. 
[^2]: In Australia, some people put a wooden box with a door in their front yard and fill it with books, so that everyone passing by can pick one up or leave their own books for other readers.&lt;/p&gt;
</content:encoded></item><item><title>Blog engines I&apos;ve used</title><link>https://scotto.me/blog/2026-07-11-blog-engines-ive-used/</link><guid isPermaLink="true">https://scotto.me/blog/2026-07-11-blog-engines-ive-used/</guid><description>History of my blog engines</description><pubDate>Sat, 11 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Since I got my first internet connection as a kid, I’ve spent more time setting up new blogs than actually writing them. It’s not surprising. Configuring the platform and adding features was the whole point, the fun part. Writing never interested me at the time, perhaps because I never felt the urgency to express myself and didn’t have anything relevant to say.&lt;/p&gt;
&lt;p&gt;I’ve always used self-hosted solutions and learned the advantages and tradeoffs of using them, so I will summarise here each blog and platform I have used. I might not know much about writing a blog, but I’m sure I know a thing or two about the platforms that make a blog possible.&lt;/p&gt;
&lt;h2&gt;WordPress&lt;/h2&gt;
&lt;p&gt;This was the first blog I opened many years ago, and I believe I wrote it in Italian. I was mostly translating some guides from English, or reposting tutorials taken from other blogs or forums. I got a few readers and comments, but it was never a serious project.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://wordpress.org/&quot;&gt;WordPress&lt;/a&gt; has been the main CMS for a lot of websites for decades, and still today power 40% of the web. In 2006-2008 the community around it was active, and a lot of plugins and themes were released, since PHP, the language that WordPress uses, it’s easy to learn and quick to be productive with. Plenty of guides were available, so creating a blog at the time was a matter of installing WordPress, connecting to the hosting space via FTP using &lt;a href=&quot;https://filezilla-project.org/&quot;&gt;FileZilla&lt;/a&gt;, and then connecting a &lt;a href=&quot;https://www.mysql.com/&quot;&gt;MySQL&lt;/a&gt; database to it.&lt;/p&gt;
&lt;p&gt;In those years, the LAMP stack (Linux, Apache, MySQL, PHP) was the foundational architecture used by most websites and communities, so it wasn’t surprising that WordPress got so much traction. There were so many plugins and themes that it didn’t take much to put a decent website online. Besides my own blog, I had to install and configure WordPress websites for other people, and every time things went smoothly enough. Even when I had to do some small customisations to a theme, it was quite quick to do, considering that I never learned PHP and my changes were done by guessing and testing.&lt;/p&gt;
&lt;p&gt;The CMS that WordPress offers is top notch; I’ve never found one as good since. The editor is decent and includes an instant preview of the articles and theme changes. It’s so easy to use that even your noob uncle who needed a website was able to put one together with images without having to call you over for help.&lt;/p&gt;
&lt;p&gt;Also, the plugin library that WordPress offers is large, and the plugin quality is quite decent. Most website owners at the time were worried about SEO, and it was just a matter of installing the right plugins to make sure the website was picked up by Google with the right keywords.&lt;/p&gt;
&lt;p&gt;Since WordPress workes with a database, it offers simple integration to add comments to a website, with the Akismet spam filter plugin and other nice features like user login and Gravatar integration.&lt;/p&gt;
&lt;p&gt;The main problem with WordPress is that by supporting so many features it became a huge monster, far more than what’s really needed for a simple blog. I started abandoning WordPress when Markdown became popular and static websites had their Renaissance.&lt;/p&gt;
&lt;h2&gt;Jekyll&lt;/h2&gt;
&lt;p&gt;After PHP came the Ruby era in 2008. &lt;a href=&quot;https://tom.preston-werner.com/&quot;&gt;Tom Preston-Werner&lt;/a&gt;, after releasing GitHub (written in Ruby) in April, got tired of having to deal with a database in WordPress to host a simple blog and decided to write a new blog engine called &lt;a href=&quot;https://jekyllrb.com/&quot;&gt;Jekyll&lt;/a&gt;, also in Ruby.&lt;/p&gt;
&lt;p&gt;Jekyll is much simpler to configure and to understand what is happening inside the blog. A new project consists of a configuration file and a folder structure. Posts are simple Markdown files, and the styles use &lt;a href=&quot;https://sass-lang.com/&quot;&gt;SASS&lt;/a&gt;, which at the time was more advanced than plain CSS. The pages are composed of layouts and smaller reusable components. For rendering the pages, Jekyll uses the &lt;a href=&quot;https://shopify.github.io/liquid/&quot;&gt;Liquid&lt;/a&gt; template engine, which allow the use of variables, conditionals, and loops alongside normal HTML tags. When my blog was ready to be served, I just needed to run the CLI command to build the project, and the compiled website was saved into the output directory.&lt;/p&gt;
&lt;p&gt;Jekyll is a platform that mostly targets blogs. There are many plugins available that extended what is possible to put into posts and how the content is indexed. Plus, GitHub got popular and enabled the possibility to host a website directly on their platform. So publishing with Jekyll is a matter of pushing the updates to the repo, and the continuous integration would then run the build and serve the output directory.&lt;/p&gt;
&lt;p&gt;Jekyll served my needs for a longer period than any other platform. It was minimalist compared to WordPress and, in a way, made the components of a blog much more visible and in the hands of the developers, since most files were HTML, Markdown, and SCSS.&lt;/p&gt;
&lt;p&gt;Then Ruby lost its momentum and got a bit out of fashion. I have to admit that at the time I didn’t know Ruby well, and a few times when I wanted to change some plugins I ended up not doing it because of the language barrier. I didn’t abandon Jekyll because of that, but because the community itself got a bit smaller and less vibrant, probably because a part of it migrated to other platforms (or stopped blogging).&lt;/p&gt;
&lt;h2&gt;Org mode publish&lt;/h2&gt;
&lt;p&gt;When I learned &lt;a href=&quot;https://www.gnu.org/savannah-checkouts/gnu/emacs/emacs.html&quot;&gt;Emacs&lt;/a&gt;, I discovered the most advanced file format integration with an editor: &lt;a href=&quot;https://orgmode.org/&quot;&gt;org&lt;/a&gt;. If you don’t know it, think of it as a more powerful Markdown with a series of shortcuts and extensions that make editing really fast and transform a directory of files into a perfect organisational system for your personal information.&lt;/p&gt;
&lt;p&gt;Org comes with a publishing management system, which is a way to export a series of org files into HTML, with certain output configurations for directories and templating. It’s a static site generator that converts org files to HTML, similar to what Jekyll was doing with .md files. Once the project is configured with some Elisp code, saving a file in Emacs and running a command was enough for publishing changes to my Org-mode blog.&lt;/p&gt;
&lt;p&gt;Since org is an advanced file format, the publishing came with some nice features too, like title links, dates, and automatic sitemap generation.&lt;/p&gt;
&lt;p&gt;The difficulty is that org publish is more a system for converting files rather than producing a blog. So features like layouts, SASS for stylesheets, RSS feeds, a public folder for static files, they all needed a special Elisp configuration to be written and maintained.&lt;/p&gt;
&lt;p&gt;It didn’t take me long to adapt some Elisp code to fit my project, but after making a few changes to the directory structure, every time the build was failing and I had to debug what was happening. It wasn’t ideal. Plus, features like image compression or integrating a search would have been hard to implement.&lt;/p&gt;
&lt;p&gt;So, as usually happens with complex configurable systems, after having fun customising the whole setup, I got bored, since org publish wasn’t really what I would consider practical for a personal blog. Just my personal taste.&lt;/p&gt;
&lt;h2&gt;11ty&lt;/h2&gt;
&lt;p&gt;I finally found a static site generator written entirely in JS, so I wrote my blog in &lt;a href=&quot;https://www.11ty.dev/&quot;&gt;11ty&lt;/a&gt;. It’s another pretty good system for creating static websites.&lt;/p&gt;
&lt;p&gt;I found it a bit tricky to find official documentation for certain features, but I was able to integrate and customise my blog exactly how I wanted and write the plugins I needed in quite a short time.&lt;/p&gt;
&lt;p&gt;Honestly, I don’t have much to say about 11ty. It’s a good alternative to Jekyll, and it uses Javascript, so if you know the language it becomes easy to customise. It’s actively supported and used on the web, so I recommend checking it out if you are looking for a blog platform.&lt;/p&gt;
&lt;p&gt;What got me a bit frustrated is that I ended up having a large JS file with all the configuration required, and when I had to change some structure in my blog — for example, adding support for Italian/English translations to certain articles — the configuration file got a bit bloated.&lt;/p&gt;
&lt;h2&gt;Astro&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://astro.build/&quot;&gt;Astro&lt;/a&gt; is probably the definitive static site generator I’m using today. This blog moved from 11ty to Astro without even being noticeable, and I’ve used it in a few other projects where I needed a static site generator. I’ve even tried using &lt;a href=&quot;https://decapcms.org/&quot;&gt;DecapCMS&lt;/a&gt; with it, so that a friend was able to write pages and add images directly by pushing to the GitHub repo, avoiding the need for a database.&lt;/p&gt;
&lt;p&gt;Astro has pretty much all I want for a blog: asset optimisation, partial hydration with islands, advanced templating, and variable support. Also, Astro uses &lt;strong&gt;single-file components&lt;/strong&gt; to define pages, so that HTML, JS, and CSS that share the same scope are placed in a single file, like Vue does. Pretty neat, and it makes the code easy to organise and reuse. It also extensible using Javascript and offers an high level of customisation and a set of libraries to integrate more features.&lt;/p&gt;
&lt;h2&gt;What I look for now&lt;/h2&gt;
&lt;p&gt;After all this, here&amp;#39;s what I now consider essential for a blog engine:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;support for Markdown, since I write everything in Obsidian&lt;/li&gt;
&lt;li&gt;sensible defaults for common features like RSS and asset optimisation&lt;/li&gt;
&lt;li&gt;a healthy plugin ecosystem for when I need to extend things&lt;/li&gt;
&lt;li&gt;easy customisation&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I hope Astro stays around for a long time. I&amp;#39;d rather not migrate again and instead spend that time on what actually matters: the writing.&lt;/p&gt;
</content:encoded></item><item><title>On Running and Murakami</title><link>https://scotto.me/blog/2026-07-10-on-running-and-murakami/</link><guid isPermaLink="true">https://scotto.me/blog/2026-07-10-on-running-and-murakami/</guid><description>Review of What I Talk About When I Talk About Running</description><pubDate>Fri, 10 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I’ve been a runner for more than ten years. I started running a few times a week during university because it’s a sport that fits me well. It only requires a good pair of running shoes, it’s not time-consuming, and it can be done everywhere and in any season.&lt;/p&gt;
&lt;p&gt;I’ve always been a long distance runner, and most of my runs have been around an hour long. I always find it engaging to go for a long run, where I can distract my mind from the focus of the day. This frequently helps me find new ideas and inspiration, just like I did for this article.&lt;/p&gt;
&lt;p&gt;Recently I’ve started running every day, but for a shorter amount of time. The physical benefits remain the same. Two things made me change my habit: first, research suggests that shorter daily run are more beneficial for the well-being, reduce the risk of injuries, and allow the body to adapt gradually. Second, it takes less time. In a busy life, taking 30 minutes a day for your body and mind is not much, while one hour can become more of a burden.&lt;/p&gt;
&lt;p&gt;The second thing I mention when I talk about running, after describing what type of runner I am, is the type of shoes. I currently run with the Wave Rider 28, which I bought from the Mizuno store in Kyoto, Japan. I’ve tried other common brands, and while there are differences for the pros, for a casual runner like me they are negligible — and Mizuno are good shoes. I chose them because they are the shoes that the writer Haruki Murakami uses.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/img/murakami.jpg&quot; alt=&quot;[Haruki Murakami in Marathon, Greece]&quot; title=&quot;Murakami in Marathon, Greece.&quot;&gt;&lt;/p&gt;
&lt;p&gt;Haruki Murakami is the most famous Japanese author alive today. He has written multiple bestsellers that have been translated into more than 50 languages worldwide and have inspired several movies. Other than being a successful author, he’s a long distance marathon runner and wrote about his experience with running in a book called “&lt;a href=&quot;https://www.goodreads.com/en/book/show/2195464.What_I_Talk_About_When_I_Talk_About_Running&quot;&gt;What I Talk About When I Talk About Running&lt;/a&gt;”.&lt;/p&gt;
&lt;p&gt;Before dedicating himself entirely to writing, Murakami ran a jazz cafe in Tokyo with his wife, where he spent his days preparing cocktails, selecting music to play, and reading books. While it might seem like an easy job, he was working for 12 hours every day while smoking almost 60 cigarettes due to stress. Then one day, while watching a local baseball match, he had the realisation that he wanted to write fiction. Against the advice of his close friends, he sold the cafe and moved to the countryside with his wife, where he could have the calm environment needed to focus. While dedicating himself to writing, thanks also to some positive feedback received for his early stories, he discovered that sitting at a table for long hours every day wasn’t good for his health. So at 33, he quit smoking and decided that he would go for a run every single morning before immersing himself in writing.&lt;/p&gt;
&lt;p&gt;Since then, Murakami has never stopped running, participating in more than 30 marathons around the world, including ultramarathons and triathlons. In the book, he explains the entire process that transformed him from a complete beginner to a long endurance runner. His secret was &lt;strong&gt;running every single day&lt;/strong&gt;, mentioning that consistency was the key to his success.&lt;/p&gt;
&lt;p&gt;Murakami has run for most of his life and wrote novels professionally for a long time. In the book, he explains the loose correlation between the two: the fact that both are activities done in solitude and that both require, other than a bit of talent, constant training to be sustainable over a long period. Writing is not easy. It requires sitting at a table alone, immersed in a long and deep thinking flow into imagination and memory. It’s a task that requires concentration and can sometimes be so intense that it becomes exhausting.&lt;/p&gt;
&lt;p&gt;The book mixes the two experiences that Murakami had, describing that what he learned is that the key ingredients to engage in these activities are &lt;strong&gt;focus&lt;/strong&gt;, &lt;strong&gt;endurance&lt;/strong&gt;, and the &lt;strong&gt;patience&lt;/strong&gt; needed to persist while waiting for the results to come.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I didn&amp;#39;t start running because somebody asked me to become a runner. Just like I didn&amp;#39;t become a novelist because someone asked me to. One day, out of the blue, I wanted to write a novel. And one day, out of the blue, I started to run-simply because I wanted to. I&amp;#39;ve always done whatever I felt like doing in life. People may try to stop me, and convince me I&amp;#39;m wrong, but I won&amp;#39;t change.
— Haruki Murakami&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In the West, we tend to associate authors with a status, almost as if they are celebrities and rockstars. In recent decades, we saw the rise of literary artistic personas that romanticised drinking, taking drugs, and burning out young. Think Burroughs, Hunter S. Thompson, Bukowski, Bret Easton Ellis, or David Foster Wallace. They all made these themes central to their productions.&lt;/p&gt;
&lt;p&gt;Murakami is a different kind of writer. Instead of drinking, smoking, abusing substances, and promoting an unhealthy lifestyle, he followed a strict diet, did endurance training, and committed himself to a self-imposed discipline to seriously carry out his duties. He promoted a life dedicated to running and the craft of writing, honouring his commitments while constantly training his persistence and resilience. This choice resembles the life of ancient samurais, the Japanese warriors with a high moral code and self-control. If you’ve ever been interested in Japan, you will notice that the attitude that samurais had toward their duty still persists in today’s life of Japanese salarymen. The country is famously renowned for the perfection they put into their crafts and their dedication to work, which comes from the culture of imposing strict discipline on themselves in order to challenge their own limits.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Pain is inevitable. Suffering is optional.
— Haruki Murakami&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There’s a quiet rebellion in choosing Murakami over Bukowski as a way of life. Our Western culture too often normalises burnout and, instead of condemning substance abuse, subtly encourages it. The power that comes from disciplining ourselves and restraining our desires in pursuit of a higher goal is what allows us to simply show up every day and do the work, whether that means running or writing. The point of these activities, in the end, is to prove to ourself that we are capable of enduring, and of moving forward, every single day.&lt;/p&gt;
</content:encoded></item></channel></rss>