<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Han</title>
    <description>The latest articles on Forem by Han (@han).</description>
    <link>https://forem.com/han</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F746993%2F37554ff8-e2b8-4c14-80c0-67992fd8b1b4.jpeg</url>
      <title>Forem: Han</title>
      <link>https://forem.com/han</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/han"/>
    <language>en</language>
    <item>
      <title>The Current State of Software: From Builders to Burnt-Out AI Evangelists</title>
      <dc:creator>Han</dc:creator>
      <pubDate>Wed, 12 Nov 2025 19:40:45 +0000</pubDate>
      <link>https://forem.com/han/the-current-state-of-software-from-builders-to-burnt-out-ai-evangelists-2p6i</link>
      <guid>https://forem.com/han/the-current-state-of-software-from-builders-to-burnt-out-ai-evangelists-2p6i</guid>
      <description>&lt;p&gt;We live in exciting times. Artificial Intelligence has made programming more accessible than ever before. What once required deep focus and late-night debugging sessions can now be generated with a few prompts and some optimism. It’s revolutionary — and somehow, also, a little depressing.&lt;/p&gt;

&lt;p&gt;Those of us who started coding because we loved building things are starting to feel tired. Not the &lt;em&gt;“I need a vacation”&lt;/em&gt; kind of tired. The existential kind.&lt;br&gt;
A while ago, I read that many experienced developers — especially those working in agencies, consultancies, and digital factories — are living in a state of &lt;strong&gt;permanent burnout.&lt;/strong&gt; It’s not surprising. We stopped being &lt;strong&gt;builders&lt;/strong&gt; and became &lt;strong&gt;feature delivery units.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Instead of creating, we deliver. Instead of exploring, we execute. Every decision must fit neatly into a Jira ticket, wrapped in &lt;em&gt;“agile”&lt;/em&gt; terminology that somehow manages to remove all agility from the process. We measure velocity, not value. We chase deadlines, not delight.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Rise of the Architecture Astronauts (and Their AI Descendants)
&lt;/h3&gt;

&lt;p&gt;A long time ago, I read Joel Spolsky’s classic piece: &lt;a href="https://www.joelonsoftware.com/2001/04/21/dont-let-architecture-astronauts-scare-you/" rel="noopener noreferrer"&gt;Don’t Let Architecture Astronauts Scare You.&lt;/a&gt;&lt;br&gt;
He described a certain kind of engineer who’s so disconnected from actual implementation that they float into orbit — talking about abstract architectures, grand strategies, and futuristic patterns no one can actually ship.&lt;/p&gt;

&lt;p&gt;We’ve all met one. Maybe we’ve even &lt;em&gt;been&lt;/em&gt; one, briefly. It happens.&lt;br&gt;
But lately, I think we need a new term — because the &lt;strong&gt;AI era has birthed a new archetype.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;AI Astronaut.&lt;/strong&gt;&lt;br&gt;
This is the person who believes that large language models are the ultimate truth, that prompting is the new programming, and that soon all human creativity will be automated away (preferably by a tool they just demoed at the last all-hands).&lt;/p&gt;

&lt;p&gt;They don’t write code — they &lt;em&gt;declare intentions.&lt;/em&gt; They don’t understand systems — they &lt;em&gt;orchestrate miracles&lt;/em&gt;. And if you dare to ask how something actually works, they’ll send you a link to an article.&lt;/p&gt;

&lt;p&gt;Sometimes, they’ll even say things like &lt;em&gt;“we’ll have this feature shipped with AI in a couple of weeks”&lt;/em&gt; — without realizing that real systems have dependencies, side effects, and constraints that no prompt can handwave away.&lt;br&gt;
And that’s where the danger lies — not in the tools themselves, but in the illusion that complexity can be wished away.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Craft Is Still Worth Defending
&lt;/h3&gt;

&lt;p&gt;Don’t get me wrong: AI is incredible. It amplifies what we can do, accelerates our workflows, and makes the entry barrier to programming almost nonexistent. That’s progress.&lt;br&gt;
But it’s also creating a generation of developers who no longer want to understand how things work — just how to &lt;em&gt;get things done.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;And maybe that’s fine. Maybe software is supposed to become more like plumbing — efficient, invisible, reliable. But for some of us, the joy was never in shipping the feature. It was in understanding &lt;em&gt;why&lt;/em&gt; the feature worked.&lt;/p&gt;

&lt;p&gt;So yes, celebrate the AI revolution. Use the tools. Automate the boring stuff.&lt;br&gt;
But keep your feet on the ground. Don’t float away with the AI Astronauts.&lt;br&gt;
We already have enough of those in orbit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Because underneath all the frameworks, prompts, and plugins, there’s still a craft worth protecting — the quiet satisfaction of understanding a system deeply enough to make it dance. AI can assist, but it can’t care. That part is still up to us.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>ai</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Render and Response: The Case for Pure React Server Components</title>
      <dc:creator>Han</dc:creator>
      <pubDate>Thu, 06 Nov 2025 23:21:19 +0000</pubDate>
      <link>https://forem.com/han/render-response-the-case-for-pure-react-server-components-430n</link>
      <guid>https://forem.com/han/render-response-the-case-for-pure-react-server-components-430n</guid>
      <description>&lt;p&gt;You can call &lt;code&gt;cookies()&lt;/code&gt; in a React Server Component today.&lt;br&gt;
But if you try to &lt;em&gt;set&lt;/em&gt; a cookie, nothing happens.&lt;/p&gt;

&lt;p&gt;This behavior is intentional.&lt;/p&gt;

&lt;p&gt;React Server Components (RSC) do not participate in the HTTP response lifecycle. They execute during rendering — a phase that can be repeated, restarted, speculated, aborted, cached, or occur without a corresponding client request. This is a fundamental constraint of the RSC model, not a missing feature.&lt;/p&gt;

&lt;p&gt;Rendering produces &lt;em&gt;descriptions&lt;/em&gt; of UI.&lt;br&gt;
Responses produce &lt;em&gt;effects&lt;/em&gt; on the outside world.&lt;/p&gt;

&lt;p&gt;These concerns are separated for correctness.&lt;/p&gt;
&lt;h2&gt;
  
  
  Renders May Replay
&lt;/h2&gt;

&lt;p&gt;A render is not guaranteed to correspond to a user event or to a single network response. Frameworks are free to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Replay renders after suspending&lt;/li&gt;
&lt;li&gt;  Retry renders after errors&lt;/li&gt;
&lt;li&gt;  Run renders for background revalidation&lt;/li&gt;
&lt;li&gt;  Perform partial renders during streaming&lt;/li&gt;
&lt;li&gt;  Cancel renders before they reach the client&lt;/li&gt;
&lt;li&gt;  Execute renders in different environments (edge, regional worker, etc.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;From the perspective of React, a render is a &lt;strong&gt;pure computation&lt;/strong&gt;.&lt;br&gt;
From the perspective of HTTP, the response is a &lt;strong&gt;side-effect&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If a render were allowed to mutate the response, any of the behaviors above could trigger multiple or mis-timed effects. The result would be non-deterministic.&lt;/p&gt;

&lt;p&gt;We would no longer be able to rely on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Caching&lt;/li&gt;
&lt;li&gt;  Correct concurrency&lt;/li&gt;
&lt;li&gt;  Streaming behavior&lt;/li&gt;
&lt;li&gt;  Stable error recovery&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In short: purity enables the RSC model.&lt;/p&gt;
&lt;h2&gt;
  
  
  Snapshots, Not Mutations
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;cookies()&lt;/code&gt; and &lt;code&gt;headers()&lt;/code&gt; exist in RSCs only as &lt;strong&gt;read-only snapshots&lt;/strong&gt; of the incoming request. They are asynchronous because the framework may suspend to produce a consistent view during streaming.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { cookies, headers } from 'next/headers';

export default async function Page() {
  const c = await cookies();
  const h = await headers();

  const theme = c.get('theme')?.value ?? 'light';
  const ua = h.get('user-agent') ?? 'n/a';

  return &amp;lt;main data-theme={theme}&amp;gt;{ua}&amp;lt;/main&amp;gt;;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These reads are pure. They do not cause effects.&lt;br&gt;
They do not depend on timing.&lt;br&gt;
They can be replayed safely.&lt;/p&gt;

&lt;p&gt;Writes cannot satisfy these properties, so they are prohibited.&lt;/p&gt;

&lt;h2&gt;
  
  
  Purity as a Design Requirement
&lt;/h2&gt;

&lt;p&gt;The idempotence requirement can be stated simply:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;“The result of rendering must not depend on whether rendering has been performed once or many times.”&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;More formally:&lt;/p&gt;

&lt;p&gt;Let &lt;code&gt;R&lt;/code&gt; be a render function producing output &lt;code&gt;U&lt;/code&gt; from state &lt;code&gt;S&lt;/code&gt;.&lt;br&gt;
The function &lt;code&gt;R&lt;/code&gt; must satisfy:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;R(S) = U&lt;br&gt;
R(R(S)) = U&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If a render performs side effects — writing to a database, emitting network logs, modifying headers or cookies — this property is violated. Any concurrency model depending on retries or cancellation would break.&lt;/p&gt;

&lt;p&gt;Purity is not a recommendation.&lt;br&gt;
It is the only model that keeps the semantics sound.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foog7axybm8iyjttt76k8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foog7axybm8iyjttt76k8.png" alt="captionless image" width="800" height="312"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Effects Belong
&lt;/h2&gt;

&lt;p&gt;When mutations &lt;em&gt;do&lt;/em&gt; need to occur, they must be tied to &lt;strong&gt;a specific HTTP response&lt;/strong&gt; or &lt;strong&gt;a user-triggered transition&lt;/strong&gt;, where exactly-once semantics are controlled.&lt;/p&gt;

&lt;p&gt;Two places provide those guarantees:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Route Handlers&lt;/strong&gt;&lt;br&gt;
Full response construction: status, headers, cookies.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Server Actions&lt;/strong&gt;&lt;br&gt;
User-driven mutations; the framework binds effects to the resulting response.&lt;/p&gt;

&lt;p&gt;Everything else — including Server Components — must remain pure.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Model in One Sentence
&lt;/h2&gt;

&lt;p&gt;Rendering is a computation.&lt;br&gt;
Response is an effect.&lt;br&gt;
Only one of them can safely replay.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;React Server Components expand what is possible for server-driven UI.&lt;br&gt;
But they do so by imposing a strict invariant:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;“Rendering must be pure.”&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you need to modify the outside world, do not do it in an RSC.&lt;br&gt;
Render the UI.&lt;br&gt;
Perform effects in handlers or actions.&lt;br&gt;
Let the system retry safely.&lt;/p&gt;

&lt;p&gt;You can think more than once.&lt;br&gt;
You can only act once.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>architecture</category>
      <category>nextjs</category>
    </item>
  </channel>
</rss>
