<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>My Blog</title><description>Notes on software, systems, and the web.</description><link>https://blog.joonsunn.com/</link><language>en-us</language><item><title>Cloudflare Pages</title><link>https://blog.joonsunn.com/posts/cloudflare-pages/</link><guid isPermaLink="true">https://blog.joonsunn.com/posts/cloudflare-pages/</guid><description>First post after deploying to Cloudflare Pages</description><pubDate>Tue, 25 Aug 2026 19:46:08 GMT</pubDate><content:encoded>&lt;p&gt;This is the first blog entry after migrating from GH pages to Cloudflare Pages. Hopefully this page gets displayed without additional intervention from me.&lt;/p&gt;
</content:encoded></item><item><title>Learning Go</title><link>https://blog.joonsunn.com/posts/learning-go/</link><guid isPermaLink="true">https://blog.joonsunn.com/posts/learning-go/</guid><description>Notes from learning Go after working primarily with Node.js.</description><pubDate>Tue, 25 Aug 2026 15:01:19 GMT</pubDate><content:encoded>&lt;p&gt;After years of writing Node.js professionally, I spent a few weeks building small tools in Go.
This post is a running list of things that surprised me, annoyed me, and eventually won me over.&lt;/p&gt;
&lt;h2 id=&quot;goroutines&quot;&gt;Goroutines&lt;/h2&gt;
&lt;p&gt;Goroutines are Go’s unit of concurrency. They are cheap enough that spawning thousands of them
is unremarkable, and the runtime multiplexes them onto a small pool of OS threads.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;The mental model is close to &lt;code&gt;async&lt;/code&gt;/&lt;code&gt;await&lt;/code&gt;, except there is no colored function problem:
&lt;em&gt;any&lt;/em&gt; function can block without holding up a thread.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Channels are typed pipes through which goroutines communicate. Do not communicate by sharing
memory; share memory by communicating.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;error-handling&quot;&gt;Error handling&lt;/h2&gt;
&lt;p&gt;Errors are values. There are no exceptions to catch — functions return an &lt;code&gt;error&lt;/code&gt; and you deal
with it immediately:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;go&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; fetch&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;url&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) ([]&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;byte&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; resp, err &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; http.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Get&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(url)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt; if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; err &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;!=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; nil&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; nil&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, fmt.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Errorf&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;fetch &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;%s&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;%w&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, url, err)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt; defer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; resp.Body.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Close&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; body, err &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; io.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ReadAll&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(resp.Body)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt; if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; err &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;!=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; nil&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; nil&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, fmt.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Errorf&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;read &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;%s&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;%w&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, url, err)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt; return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; body, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;nil&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Verbose? Sometimes. Explicit? Always.&lt;/p&gt;
&lt;h2 id=&quot;what-i-like-so-far&quot;&gt;What I like so far&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Single static binaries — &lt;code&gt;go build&lt;/code&gt; and copy the file.&lt;/li&gt;
&lt;li&gt;The standard library covers most of what I used to reach for packages to get.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;go test ./...&lt;/code&gt; needs no configuration.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;And a short list of things I miss from JavaScript:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The npm ecosystem&lt;/li&gt;
&lt;li&gt;Destructuring everywhere&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Array.prototype.map&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;comparing-defaults&quot;&gt;Comparing defaults&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concern&lt;/th&gt;
&lt;th&gt;Node.js&lt;/th&gt;
&lt;th&gt;Go&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Concurrency&lt;/td&gt;
&lt;td&gt;Event loop&lt;/td&gt;
&lt;td&gt;Goroutines&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Typing&lt;/td&gt;
&lt;td&gt;TypeScript (opt-in)&lt;/td&gt;
&lt;td&gt;Static (built-in)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deployment&lt;/td&gt;
&lt;td&gt;&lt;code&gt;node_modules&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Static binary&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Overall: still early, but &lt;a href=&quot;https://go.dev/ref/spec&quot;&gt;the language spec&lt;/a&gt; is surprisingly readable.&lt;/p&gt;
</content:encoded></item><item><title>React Server Components, One Month Later</title><link>https://blog.joonsunn.com/posts/react-server-components/</link><guid isPermaLink="true">https://blog.joonsunn.com/posts/react-server-components/</guid><description>First impressions after shipping a feature built on React Server Components.</description><pubDate>Sun, 12 Jul 2026 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;We shipped our first production feature using React Server Components last month. These are my
notes on what actually changed, for better and worse, once real users hit it.&lt;/p&gt;
&lt;h2 id=&quot;the-model&quot;&gt;The model&lt;/h2&gt;
&lt;p&gt;In RSC, components run on the server by default. Client components are the exception, marked
with the &lt;code&gt;&quot;use client&quot;&lt;/code&gt; directive:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;tsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ProductPage&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({ &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; }) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt; const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; product&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; db.products.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;find&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(id);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt; return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  &amp;lt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;   &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;h1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;gt;{product.name}&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;h1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;   &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;AddToCartButton&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; productId&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{product.id} /&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  &amp;lt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The data fetching happens on the server; only the interactive island ships to the browser.&lt;/p&gt;
&lt;h2 id=&quot;what-worked&quot;&gt;What worked&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;No client-side waterfalls — queries start on the server.&lt;/li&gt;
&lt;li&gt;Bundle size dropped noticeably once data-fetching code stopped shipping to clients.&lt;/li&gt;
&lt;li&gt;Composing server-rendered content with small interactive pieces felt natural.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;what-hurt&quot;&gt;What hurt&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Debugging serialization errors across the server/client boundary is unpleasant.&lt;/li&gt;
&lt;li&gt;Every state library needed rethinking.&lt;/li&gt;
&lt;li&gt;The mental model shift was bigger than the docs suggest:&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;It’s not “React but faster”. It’s a different split of responsibilities between server and
browser.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;/p&gt;
&lt;h2 id=&quot;verdict&quot;&gt;Verdict&lt;/h2&gt;
&lt;p&gt;Promising, but treat the migration as an architecture change rather than an upgrade. For this
blog, incidentally, plain static HTML remains entirely sufficient — which is exactly why this
site is just Markdown files.&lt;/p&gt;
</content:encoded></item></channel></rss>