<?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>DEV Community: Aaron Rose</title>
    <description>The latest articles on DEV Community by Aaron Rose (@aaron_rose_0787cc8b4775a0).</description>
    <link>https://dev.to/aaron_rose_0787cc8b4775a0</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%2F1971914%2F91ca9e4e-b9c7-47d0-89f8-7cf92bc13268.jpg</url>
      <title>DEV Community: Aaron Rose</title>
      <link>https://dev.to/aaron_rose_0787cc8b4775a0</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/aaron_rose_0787cc8b4775a0"/>
    <language>en</language>
    <item>
      <title>The Secret Life of Go: Error Handling (Part 2)</title>
      <dc:creator>Aaron Rose</dc:creator>
      <pubDate>Fri, 20 Mar 2026 07:31:47 +0000</pubDate>
      <link>https://dev.to/aaron_rose_0787cc8b4775a0/the-secret-life-of-go-error-handling-part-2-5eo1</link>
      <guid>https://dev.to/aaron_rose_0787cc8b4775a0/the-secret-life-of-go-error-handling-part-2-5eo1</guid>
      <description>&lt;p&gt;&lt;em&gt;Data-Rich Errors, Custom Structs, and &lt;code&gt;errors.As&lt;/code&gt;&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Eleanor is a senior software engineer. Ethan is her junior colleague. They work in a beautiful beaux arts library in Lower Manhattan — the kind of place where coding languages are discussed like poetry.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Episode 31&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Ethan was building a user registration endpoint. He had learned his lesson from the previous day and was dutifully avoiding string matching. &lt;/p&gt;

&lt;p&gt;"I have a problem with Sentinel errors," Ethan said, turning his monitor toward Eleanor. "They are great for simple states like &lt;code&gt;ErrNotFound&lt;/code&gt;. But what if the error is a validation failure? I need to tell the frontend exactly &lt;em&gt;which&lt;/em&gt; field failed and &lt;em&gt;why&lt;/em&gt;. I can't write a Sentinel variable for every possible bad email address."&lt;/p&gt;

&lt;p&gt;He showed her his workaround:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Ethan's attempt to return data&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;validateUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"@"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"missing @ symbol"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"validation failed"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Eleanor winced slightly. "You are returning the error details separately from the error itself. That breaks the standard Go function signature. What if this error needs to bubble up through three different functions before the HTTP handler catches it? Do they all have to return &lt;code&gt;(string, string, error)&lt;/code&gt;?"&lt;/p&gt;

&lt;p&gt;"That's exactly why I'm stuck," Ethan admitted. "An &lt;code&gt;error&lt;/code&gt; in Go is just a string interface. How do I put structured data inside it?"&lt;/p&gt;

&lt;h2&gt;
  
  
  The Custom Error Struct
&lt;/h2&gt;

&lt;p&gt;"An error in Go is &lt;em&gt;not&lt;/em&gt; just a string," Eleanor corrected gently. "It is an interface with a single method: &lt;code&gt;Error() string&lt;/code&gt;. That means &lt;em&gt;any&lt;/em&gt; struct can become an error, as long as it implements that method."&lt;/p&gt;

&lt;p&gt;She opened a new file and defined a custom struct:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// ValidationError holds structured data about what went wrong.&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;ValidationError&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Field&lt;/span&gt;  &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;Reason&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;Err&lt;/span&gt;    &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="c"&gt;// The underlying wrapped error (optional, but good practice)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// Implement the error interface&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ValidationError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"validation failed on %s: %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reason&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// Implement the Unwrap interface so errors.Is and errors.As can look inside it&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ValidationError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Unwrap&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Err&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;"Now," Eleanor said, "your validation function can just return a standard &lt;code&gt;error&lt;/code&gt;, but underneath, it is secretly passing a rich data structure."&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;validateUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"@"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;// We return a pointer to our custom struct&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;ValidationError&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Field&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="s"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;Reason&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"missing @ symbol"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Extraction (&lt;code&gt;errors.As&lt;/code&gt;)
&lt;/h2&gt;

&lt;p&gt;Ethan looked at the calling code in his HTTP handler. "Okay, so &lt;code&gt;validateUser&lt;/code&gt; returns an &lt;code&gt;error&lt;/code&gt; interface. How do I get my &lt;code&gt;Field&lt;/code&gt; and &lt;code&gt;Reason&lt;/code&gt; back out of it? &lt;code&gt;errors.Is&lt;/code&gt; just returns a boolean."&lt;/p&gt;

&lt;p&gt;"If &lt;code&gt;errors.Is&lt;/code&gt; is for checking &lt;em&gt;identity&lt;/em&gt;, &lt;code&gt;errors.As&lt;/code&gt; is for extracting &lt;em&gt;data&lt;/em&gt;," Eleanor explained. &lt;/p&gt;

&lt;p&gt;She wrote the extraction logic in his HTTP handler:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;validateUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newUser&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// 1. Create an empty pointer of your custom error type&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;valErr&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ValidationError&lt;/span&gt;

    &lt;span class="c"&gt;// 2. Ask Go: "Is there a *ValidationError anywhere inside this error chain? &lt;/span&gt;
    &lt;span class="c"&gt;// If so, unpack its data into my valErr variable."&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;As&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;valErr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;// 3. We now have fully typed access to the struct's fields!&lt;/span&gt;
        &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="s"&gt;"error"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="s"&gt;"invalid input"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"field"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;valErr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"reason"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;valErr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reason&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;sendJSON&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Fallback for unexpected errors&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;sendJSON&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"internal server error"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ethan stared at the &lt;code&gt;errors.As(err, &amp;amp;valErr)&lt;/code&gt; line. "It's like a type assertion, but better. If I used a standard type assertion like &lt;code&gt;err.(*ValidationError)&lt;/code&gt;, it would fail if the error had been wrapped with &lt;code&gt;%w&lt;/code&gt; somewhere along the way."&lt;/p&gt;

&lt;p&gt;"Exactly," Eleanor smiled. "Because of the Matryoshka doll wrapping we learned yesterday, a simple type assertion only looks at the outermost doll. &lt;code&gt;errors.As&lt;/code&gt; opens up every single doll in the chain until it finds a struct that matches the type of &lt;code&gt;valErr&lt;/code&gt;. If it finds one, it populates your variable and returns &lt;code&gt;true&lt;/code&gt;."&lt;/p&gt;

&lt;h2&gt;
  
  
  The Architect's Rule
&lt;/h2&gt;

&lt;p&gt;Ethan leaned back, looking at his clean, structured HTTP handler. "This is a game-changer. I can pass HTTP status codes, retry hints, and validation fields right inside the error itself."&lt;/p&gt;

&lt;p&gt;"You can," Eleanor agreed. "But remember the distinction. Use &lt;strong&gt;Sentinel Errors&lt;/strong&gt; (with &lt;code&gt;errors.Is&lt;/code&gt;) for &lt;em&gt;state&lt;/em&gt;—answering the question 'What happened?'. Use &lt;strong&gt;Custom Error Structs&lt;/strong&gt; (with &lt;code&gt;errors.As&lt;/code&gt;) for &lt;em&gt;data&lt;/em&gt;—answering the question 'What are the details?'."&lt;/p&gt;

&lt;p&gt;Ethan deleted his messy &lt;code&gt;(string, string, error)&lt;/code&gt; return values. The Go error interface wasn't a limitation anymore; it was a carrier pigeon, perfectly capable of delivering whatever payload he needed, safely and strictly typed.&lt;/p&gt;




&lt;h2&gt;
  
  
  Key Concepts Introduced:
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The &lt;code&gt;error&lt;/code&gt; Interface&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In Go, an error is any type that implements &lt;code&gt;Error() string&lt;/code&gt;. By creating a custom struct and attaching this method, you can build errors that carry rich, structured data (like HTTP status codes or validation fields).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The &lt;code&gt;Unwrap&lt;/code&gt; Method&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If your custom error struct wraps another error, you should implement &lt;code&gt;Unwrap() error&lt;/code&gt;. This allows Go's standard library functions to look "inside" your struct when searching the error chain.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;errors.As&lt;/code&gt; vs. Type Assertions&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A standard type assertion &lt;code&gt;err.(*MyError)&lt;/code&gt; will fail if the error was wrapped (e.g., using &lt;code&gt;fmt.Errorf("... %w", err)&lt;/code&gt;). &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;errors.As(err, &amp;amp;myErr)&lt;/code&gt; traverses the entire error chain, unwrapping each layer. If it finds a type match anywhere in the chain, it populates your target variable and returns &lt;code&gt;true&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The Architect's Rule of Error Handling&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Identity:&lt;/strong&gt; Use Sentinel variables and &lt;code&gt;errors.Is&lt;/code&gt; when you only need to know &lt;em&gt;what&lt;/em&gt; happened (e.g., &lt;code&gt;ErrNotFound&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data:&lt;/strong&gt; Use Custom Structs and &lt;code&gt;errors.As&lt;/code&gt; when you need to know the &lt;em&gt;details&lt;/em&gt; of what happened (e.g., &lt;code&gt;ValidationError{Field: "email"}&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Aaron Rose is a software engineer and technology writer at &lt;a href="https://www.tech-reader.blog" rel="noopener noreferrer"&gt;tech-reader.blog&lt;/a&gt;. For explainer videos and podcasts, check out &lt;a href="https://www.youtube.com/@tech-reader2007" rel="noopener noreferrer"&gt;Tech-Reader YouTube channel&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>coding</category>
      <category>programming</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>The Secret Life of Go: Error Handling</title>
      <dc:creator>Aaron Rose</dc:creator>
      <pubDate>Thu, 19 Mar 2026 05:15:45 +0000</pubDate>
      <link>https://dev.to/aaron_rose_0787cc8b4775a0/the-secret-life-of-go-error-handling-g5f</link>
      <guid>https://dev.to/aaron_rose_0787cc8b4775a0/the-secret-life-of-go-error-handling-g5f</guid>
      <description>&lt;p&gt;&lt;em&gt;Sentinel Errors, Wrapping, and The String Trap&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Eleanor is a senior software engineer. Ethan is her junior colleague. They work in a beautiful beaux arts library in Lower Manhattan — the kind of place where coding languages are discussed like poetry.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Episode 30&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Ethan was reviewing an HTTP handler he had just written. He wanted to return a &lt;code&gt;404 Not Found&lt;/code&gt; if a database query failed, and a &lt;code&gt;500 Internal Server Error&lt;/code&gt; for anything else.&lt;/p&gt;

&lt;p&gt;"How does this look?" he asked, pointing to his screen.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// If the error message contains the words "not found", it's a 404&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="s"&gt;"not found"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;respondWithError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;404&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"User not found"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Otherwise, it's a real server error&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;respondWithError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Internal server error"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Eleanor leaned in, her eyes scanning the &lt;code&gt;strings.Contains&lt;/code&gt; line. "That," she said softly, "is a ticking time bomb."&lt;/p&gt;

&lt;p&gt;"Why?" Ethan asked. "It works perfectly in my tests."&lt;/p&gt;

&lt;p&gt;"It works today," Eleanor corrected. "But what happens next month when we update our database driver, and the library authors change their error message from &lt;em&gt;'record not found'&lt;/em&gt; to &lt;em&gt;'no rows in result set'&lt;/em&gt;?"&lt;/p&gt;

&lt;p&gt;Ethan blinked. "My &lt;code&gt;strings.Contains&lt;/code&gt; would fail. The app would start returning 500s instead of 404s, and pager alerts would go off at 3 AM."&lt;/p&gt;

&lt;p&gt;"Exactly. Checking an error's string value is incredibly brittle," Eleanor explained. "In Go, an error isn't just a string for a human to read. It is a piece of state for your program to inspect."&lt;/p&gt;

&lt;h2&gt;
  
  
  The Sentinel Error
&lt;/h2&gt;

&lt;p&gt;Eleanor opened the database package file. "Instead of relying on random text, a package should declare its specific failure states as exported variables. We call these &lt;strong&gt;Sentinel Errors&lt;/strong&gt;—they stand guard, representing a specific, known failure."&lt;/p&gt;

&lt;p&gt;She typed at the top of the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"errors"&lt;/span&gt;

&lt;span class="c"&gt;// ErrNotFound is a Sentinel Error. &lt;/span&gt;
&lt;span class="c"&gt;// It is exported (capitalized) so other packages can check against it.&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;ErrNotFound&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"record not found"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;"Now," she said, switching back to the HTTP handler, "we check against the Sentinel using &lt;code&gt;errors.Is&lt;/code&gt;."&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// We ask Go: "Is this specific error inside the chain?"&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Is&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;database&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ErrNotFound&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;respondWithError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;404&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"User not found"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;respondWithError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Internal server error"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ethan nodded. "That's much safer. If they change the text inside &lt;code&gt;ErrNotFound&lt;/code&gt; later, my &lt;code&gt;if&lt;/code&gt; statement still works because it's checking the memory address of the variable, not the string."&lt;/p&gt;

&lt;h3&gt;
  
  
  The Wrapping Problem (&lt;code&gt;%v&lt;/code&gt; vs &lt;code&gt;%w&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;Ethan frowned at the screen. "But wait. If the database layer just returns &lt;code&gt;ErrNotFound&lt;/code&gt;, the HTTP handler won't know &lt;em&gt;which&lt;/em&gt; user ID failed. I need to add context to the error before I return it up the stack."&lt;/p&gt;

&lt;p&gt;He quickly typed out a solution:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;GetUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// ... db lookup fails ...&lt;/span&gt;

    &lt;span class="c"&gt;// Add context to the Sentinel error using fmt.Errorf and %v (value)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"failed to fetch user %d: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ErrNotFound&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;"Don't do that!" Eleanor warned, catching his hand before he hit save. &lt;/p&gt;

&lt;p&gt;"If you use &lt;code&gt;%v&lt;/code&gt; (value) or &lt;code&gt;%s&lt;/code&gt; (string), &lt;code&gt;fmt.Errorf&lt;/code&gt; creates a brand new, flattened string. It destroys the original Sentinel Error. When your HTTP handler calls &lt;code&gt;errors.Is(err, ErrNotFound)&lt;/code&gt;, it will return &lt;code&gt;false&lt;/code&gt;. The Sentinel is gone."&lt;/p&gt;

&lt;p&gt;"So how do I add context without destroying the Sentinel?"&lt;/p&gt;

&lt;p&gt;"You &lt;strong&gt;wrap&lt;/strong&gt; it," Eleanor said, smiling. "Go 1.13 gave us a superpower. We use the &lt;code&gt;%w&lt;/code&gt; verb."&lt;/p&gt;

&lt;p&gt;She changed one character in his code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;GetUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// ... db lookup fails ...&lt;/span&gt;

    &lt;span class="c"&gt;// Use %w to WRAP the error&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"failed to fetch user %d: %w"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ErrNotFound&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;"Think of &lt;code&gt;%w&lt;/code&gt; like a Matryoshka doll," Eleanor explained. "It creates a new error with your helpful context (&lt;em&gt;'failed to fetch user 42'&lt;/em&gt;), but it hides the original &lt;code&gt;ErrNotFound&lt;/code&gt; securely inside it. It creates a linked list of errors."&lt;/p&gt;

&lt;p&gt;"And &lt;code&gt;errors.Is&lt;/code&gt; knows how to open the dolls?" Ethan asked.&lt;/p&gt;

&lt;p&gt;"Exactly," Eleanor said. "When you call &lt;code&gt;errors.Is(err, ErrNotFound)&lt;/code&gt;, Go automatically unwraps the dolls, layer by layer, checking each one to see if it matches the Sentinel you are looking for."&lt;/p&gt;

&lt;p&gt;Ethan looked at his refactored code. It was clean, type-safe, and completely immune to string-formatting bugs. &lt;/p&gt;

&lt;p&gt;"I was treating errors like console logs," Ethan realized. "I was just formatting text."&lt;/p&gt;

&lt;p&gt;"It's the most common mistake in Go," Eleanor agreed. "An error is an API. You are designing a programmable interface of failure states. Build it so the machine can read it, and the humans will be fine."&lt;/p&gt;




&lt;h2&gt;
  
  
  Key Concepts
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The String Trap&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Never use &lt;code&gt;strings.Contains(err.Error(), "...")&lt;/code&gt; to determine your application's control flow. Error strings are meant for humans and logging; they are subject to change and will break your logic silently.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Sentinel Errors&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A package-level, exported error variable (e.g., &lt;code&gt;var ErrNotFound = errors.New("...")&lt;/code&gt;) used to indicate a specific, expected failure state.&lt;/li&gt;
&lt;li&gt;Callers can use these variables to make decisions without relying on strings.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Error Wrapping (&lt;code&gt;%w&lt;/code&gt;)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When returning an error up the stack, you often want to add context (e.g., "failed to open config file").&lt;/li&gt;
&lt;li&gt;Using &lt;code&gt;fmt.Errorf("... %v", err)&lt;/code&gt; destroys the original error type.&lt;/li&gt;
&lt;li&gt;Using &lt;code&gt;fmt.Errorf("... %w", err)&lt;/code&gt; &lt;strong&gt;wraps&lt;/strong&gt; the error, creating a chain. The context is added, but the original error is preserved inside.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;errors.Is&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Replaces the old &lt;code&gt;if err == ErrNotFound&lt;/code&gt; pattern.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;errors.Is&lt;/code&gt; automatically unwraps the error chain (the Russian nesting dolls) and checks if the target Sentinel error exists &lt;em&gt;anywhere&lt;/em&gt; in the chain.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Aaron Rose is a software engineer and technology writer at &lt;a href="https://www.tech-reader.blog" rel="noopener noreferrer"&gt;tech-reader.blog&lt;/a&gt;. For explainer videos and podcasts, check out &lt;a href="https://www.youtube.com/@tech-reader2007" rel="noopener noreferrer"&gt;Tech-Reader YouTube channel&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>coding</category>
      <category>programming</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>The Secret Life of Claude Code — The Language You Don't Know</title>
      <dc:creator>Aaron Rose</dc:creator>
      <pubDate>Wed, 18 Mar 2026 03:23:30 +0000</pubDate>
      <link>https://dev.to/aaron_rose_0787cc8b4775a0/the-secret-life-of-claude-code-the-language-you-dont-know-1pmp</link>
      <guid>https://dev.to/aaron_rose_0787cc8b4775a0/the-secret-life-of-claude-code-the-language-you-dont-know-1pmp</guid>
      <description>&lt;p&gt;&lt;em&gt;How to work in an unfamiliar language with Claude Code — and where the limits of that partnership actually lie&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Margaret is a senior software engineer. Timothy is her junior colleague. They work in a grand Victorian library in London — the kind of place where no one is expected to know everything, but everyone is expected to know what they don't know. Timothy has arrived today carrying a file he has never seen the like of before.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Episode 7&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The File
&lt;/h2&gt;

&lt;p&gt;He set the laptop on the table and turned it toward her without preamble. This, Margaret had learned, meant he wanted her to see something before he had fully decided what he thought about it.&lt;/p&gt;

&lt;p&gt;She looked.&lt;/p&gt;

&lt;p&gt;The file was Go. Thirty-eight lines, clean structure, a concurrency pattern using goroutines and channels. Well written, by the look of it.&lt;/p&gt;

&lt;p&gt;"Yours?" she said.&lt;/p&gt;

&lt;p&gt;"The platform team's. They want me to add retry logic to this service. Apparently I'm the only one available who isn't already overloaded." He paused. "I don't know Go."&lt;/p&gt;

&lt;p&gt;Margaret looked at the file again. Then she looked at him.&lt;/p&gt;

&lt;p&gt;"How much don't you know?"&lt;/p&gt;

&lt;p&gt;"I mean — I can read the broad shape of it. It's clearly doing something with concurrent workers. But the channel syntax, the goroutine lifecycle, what happens when something panics — I don't know any of that with any confidence."&lt;/p&gt;

&lt;p&gt;"And what did you do first?"&lt;/p&gt;

&lt;p&gt;"I asked Claude Code to explain it to me."&lt;/p&gt;

&lt;p&gt;"Good," Margaret said. "And what did it tell you?"&lt;/p&gt;

&lt;p&gt;He turned the laptop back toward himself. "It explained the pattern clearly. Worker pool, jobs channel, results channel, WaitGroup for synchronisation. It said the retry logic should probably wrap the worker function and use a loop with a backoff." He looked up. "It made sense when I read it. But I don't know if I trust myself to implement it correctly in a language I've never written."&lt;/p&gt;

&lt;p&gt;"That," Margaret said, "is exactly the right concern to have."&lt;/p&gt;




&lt;h2&gt;
  
  
  What Claude Code Can Do in a Language You Don't Know
&lt;/h2&gt;

&lt;p&gt;"Let me be precise about what you have," Margaret said. "When you used Claude Code to explain that file, it gave you something genuinely valuable — a model of what the code does. The concepts, the pattern, the intent. That is real. You now understand the worker pool pattern in a way you didn't thirty minutes ago."&lt;/p&gt;

&lt;p&gt;"It felt reliable," Timothy said. "The explanation matched what I could read."&lt;/p&gt;

&lt;p&gt;"For well-established patterns in mature languages, Claude Code is very good at this. Go's concurrency model is not obscure — it is well documented, widely used, extensively written about. The explanation you received is likely accurate." She paused. "But there is a difference between understanding a pattern and being able to implement it correctly in a language you have never written. And that difference matters."&lt;/p&gt;

&lt;p&gt;"Because I don't have the instincts yet."&lt;/p&gt;

&lt;p&gt;"Because you don't have the instincts yet," she confirmed. "In your own language, when something feels wrong, you feel it. A variable name that's off. A pattern that doesn't fit. A return value being silently ignored. You have developed a sensitivity to the grain of the language over years of use. In Go, you have none of that. Everything feels equally plausible."&lt;/p&gt;

&lt;p&gt;Timothy was quiet for a moment. Outside, London was doing what it does on a grey Tuesday — carrying on regardless.&lt;/p&gt;

&lt;p&gt;"So Claude Code's output in Go looks the same to me whether it's right or wrong."&lt;/p&gt;

&lt;p&gt;"Precisely," Margaret said. "That is the core problem of working in a language you don't know. You cannot calibrate confidence. In your own language, you review code and catch things. In an unfamiliar language, you review code and see shapes."&lt;/p&gt;




&lt;h2&gt;
  
  
  The Three Things You Actually Have
&lt;/h2&gt;

&lt;p&gt;"You are not without resources," Margaret said. "Let me tell you what you actually have."&lt;/p&gt;

&lt;p&gt;She picked up her pen.&lt;/p&gt;

&lt;p&gt;"First — you have the compiler. Go is a statically typed, compiled language. It will not run code that is structurally wrong. If Claude Code produces something that gets a type wrong, misuses a channel in ways the type system can detect, or makes a structural error — the compiler will tell you." She looked at him carefully. "But I want to be precise about what the compiler does and does not catch. It catches type errors. It catches certain misuses of channels. What it does not catch is a goroutine that is started and never terminates — a leak that compiles cleanly, runs without complaint, and quietly consumes memory until something in production starts behaving strangely under load. The compiler is a safety net for structural errors. It is not a safety net for lifecycle errors. Keep that distinction."&lt;/p&gt;

&lt;p&gt;She paused. "Go gives you two more tools that are worth knowing. The first is &lt;code&gt;go vet&lt;/code&gt; — a static analyser that catches a class of common mistakes the compiler deliberately ignores, including certain channel misuses and suspicious constructs. Run it as a matter of habit. The second is the race detector — run your tests with &lt;code&gt;go test -race&lt;/code&gt; and Go's runtime will instrument your code and flag concurrent access patterns that could produce race conditions. It will not catch every possible race, but it catches many of the common ones, and in a concurrency-heavy codebase you are not yet fluent in, it is an invaluable second pair of eyes."&lt;/p&gt;

&lt;p&gt;Timothy wrote both down carefully.&lt;/p&gt;

&lt;p&gt;"Run the compiler constantly. Every small addition. Don't accumulate unverified changes — you have no instinct for which ones are safe." She wrote on the notepad. "Second — you have the tests. The platform team has tests for this service, I assume?"&lt;/p&gt;

&lt;p&gt;"They do."&lt;/p&gt;

&lt;p&gt;"Then you have a specification in executable form. Before you write a line of retry logic, run the existing tests. They should all pass. After every change, run them again. The tests are your early warning system in territory where your own judgment cannot yet be trusted."&lt;/p&gt;

&lt;p&gt;"And the third thing?"&lt;/p&gt;

&lt;p&gt;"The third thing," Margaret said, "is the most important, and the most commonly skipped." She set down her pen. "Before you write anything, ask Claude Code to teach you the language feature you are about to use. Not to write the code. To explain the concept."&lt;/p&gt;

&lt;p&gt;Timothy looked at her.&lt;/p&gt;

&lt;p&gt;"For the retry logic — before you touch the worker function, ask: &lt;em&gt;how does error handling work in Go, and what are the common mistakes developers make when implementing retry logic with goroutines? Show me a minimal, executable example.&lt;/em&gt; You are not asking for the full solution. You are asking to be taught. A working snippet you can run immediately is worth more than a paragraph of theory — it gives you something to observe, something to break deliberately, something to learn from before you touch the real code." She paused. "Then, when you do ask for the full implementation, you have enough vocabulary to evaluate what you receive."&lt;/p&gt;




&lt;h2&gt;
  
  
  The Honest Limits
&lt;/h2&gt;

&lt;p&gt;"I want to be honest with you about something," Margaret said. "There are limits to what Claude Code can do for you here, and they are worth knowing."&lt;/p&gt;

&lt;p&gt;"Tell me."&lt;/p&gt;

&lt;p&gt;"Claude Code can give you correct Go. It can explain patterns, generate idiomatic implementations, catch common mistakes before you make them. For well-documented features of a mature language, it is a reliable guide." She looked at him steadily. "But it cannot give you judgment. And in a language you don't know, judgment is precisely what you are missing."&lt;/p&gt;

&lt;p&gt;"What kind of judgment?"&lt;/p&gt;

&lt;p&gt;"The kind that says — this implementation is technically correct, but it is not how Go programmers actually write this. The kind that says — this pattern works in a small service but will cause problems at scale. The kind that says — the platform team has conventions I haven't seen yet, and this solution will be rejected in code review not because it is wrong but because it doesn't fit." She paused. "Claude Code does not know your platform team's conventions. It does not know the unwritten rules of the codebase you are entering. It produces good Go. It does not produce &lt;em&gt;their&lt;/em&gt; Go."&lt;/p&gt;

&lt;p&gt;Timothy was writing quickly.&lt;/p&gt;

&lt;p&gt;"There is one more limit," Margaret said. "Concurrency is hard. Not hard in the sense of complex syntax — hard in the sense that the mistakes it produces are subtle, timing-dependent, and sometimes invisible until production. A race condition in a worker pool does not always manifest in tests. It manifests when load increases, when timing shifts, when two goroutines reach the same point at the same moment for the first time." She looked at him. "For concurrency specifically — in a language you don't know — I would ask Claude Code to review the implementation for race conditions explicitly. Not as part of a general review. As a specific, targeted question: &lt;em&gt;are there any race conditions in this implementation, and have I handled channel closure and goroutine lifecycle correctly?&lt;/em&gt;"&lt;/p&gt;

&lt;p&gt;"Ask about the hard thing directly."&lt;/p&gt;

&lt;p&gt;"Always ask about the hard thing directly," Margaret said. "Vague review requests get vague answers. Specific concerns get specific analysis."&lt;/p&gt;




&lt;h2&gt;
  
  
  The Right Way to Ask
&lt;/h2&gt;

&lt;p&gt;"Show me how you would ask for the retry implementation," Margaret said. "Not the message you would send — the thinking behind it."&lt;/p&gt;

&lt;p&gt;Timothy considered. "I need to tell it what the worker function currently does. What retry means in this context — how many attempts, what kind of backoff, what counts as a retriable error versus a permanent failure."&lt;/p&gt;

&lt;p&gt;"Good. And on the backoff — be specific about what you need. A simple exponential backoff doubles the wait on each attempt, which is correct as far as it goes. But if you have many workers all failing and retrying simultaneously, they will all back off by the same intervals and hit the downstream service in waves. Production retry logic almost always adds jitter — a small random variation to the backoff interval — so the retries spread out rather than synchronise. Ask Claude Code about jitter explicitly if this service runs at any meaningful scale."&lt;/p&gt;

&lt;p&gt;Timothy looked up. "I wouldn't have known to ask that."&lt;/p&gt;

&lt;p&gt;"Which is precisely why you ask about the hard thing directly," Margaret said, "and why you tell Claude Code the context — how many workers, what the downstream service is, what the expected load looks like. The right implementation depends on the answers."&lt;/p&gt;

&lt;p&gt;"And I should ask it to explain the retry implementation as it writes it — not just give me code, but tell me what each part does and why, so I can actually learn the language while I'm solving the problem."&lt;/p&gt;

&lt;p&gt;Margaret set down her pen. "That last part," she said, "is the thing most developers never think to ask. They want the solution. They accept the code, they paste it in, the tests pass, they move on. They have learned nothing about Go. The next time they encounter a goroutine they are in exactly the same position." She looked at him. "You are going to be in Go codebases again. The platform team is not going away. Use this as the first lesson, not a one-time workaround."&lt;/p&gt;

&lt;p&gt;He nodded slowly. "Ask it to teach while it solves."&lt;/p&gt;

&lt;p&gt;"Ask it to teach while it solves," she said. "That is a different relationship with the tool than most people have. Most people use Claude Code as a vending machine. Put in a problem, receive a solution. You can use it as something closer to a patient tutor who happens to also write the code."&lt;/p&gt;




&lt;h2&gt;
  
  
  Before He Left
&lt;/h2&gt;

&lt;p&gt;The library had settled into its late afternoon quiet. Somewhere in the stacks, a trolley moved unhurriedly between shelves.&lt;/p&gt;

&lt;p&gt;"One more thing," Margaret said. "When you submit this to the platform team for review — tell them you're not a Go developer. Don't hide it."&lt;/p&gt;

&lt;p&gt;Timothy looked surprised. "Won't that undermine confidence in the implementation?"&lt;/p&gt;

&lt;p&gt;"It will invite the right kind of review," Margaret said. "A reviewer who knows you're unfamiliar with the language will look at the concurrency carefully. A reviewer who assumes you know Go will skim it. You want the careful review. You want someone who knows the codebase to tell you what you got wrong." She paused. "This assumes, of course, that you are working in a team where honesty about what you don't know is treated as professionalism rather than weakness. In a healthy engineering culture, it is. If yours isn't — that is a different problem, and a more serious one." She looked at him steadily. "But pretending to expertise you don't have is how subtle bugs survive code review. It is not a career strategy. It is a liability."&lt;/p&gt;

&lt;p&gt;He closed the laptop.&lt;/p&gt;

&lt;p&gt;Outside, London had shifted almost imperceptibly toward evening. Inside the library, a developer had just understood something that would stay with him — that working in a language you don't know is not a problem to be hidden. It is a condition to be managed. Honestly, carefully, and with the right help.&lt;/p&gt;

&lt;p&gt;Claude Code could give him the Go. Only time and attention would give him the instincts.&lt;/p&gt;

&lt;p&gt;And knowing the difference was how you stayed out of trouble until they arrived.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Next episode: Margaret and Timothy explore context — why Claude Code's output changes dramatically depending on what you tell it, and how to build the habit of providing the right information before you ask the question.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If this series is useful to you, share it with a developer who's ever been handed a codebase in a language they've never written.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Aaron Rose is a software engineer and technology writer at &lt;a href="https://www.tech-reader.blog" rel="noopener noreferrer"&gt;tech-reader.blog&lt;/a&gt;. For explainer videos and podcasts, check out &lt;a href="https://www.youtube.com/@tech-reader2007" rel="noopener noreferrer"&gt;Tech-Reader YouTube channel&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>claudecode</category>
      <category>programming</category>
      <category>codingwithai</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>The Secret Life of Go: Generics</title>
      <dc:creator>Aaron Rose</dc:creator>
      <pubDate>Tue, 17 Mar 2026 02:10:57 +0000</pubDate>
      <link>https://dev.to/aaron_rose_0787cc8b4775a0/the-secret-life-of-go-generics-1b9b</link>
      <guid>https://dev.to/aaron_rose_0787cc8b4775a0/the-secret-life-of-go-generics-1b9b</guid>
      <description>&lt;p&gt;&lt;em&gt;Compile-Time Safety, Type Constraints, and When to Write Code Twice&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Eleanor is a senior software engineer. Ethan is her junior colleague. They work in a beautiful beaux arts library in Lower Manhattan — the kind of place where coding languages are discussed like poetry.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Episode 29&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Ethan was staring at a stack trace that had just crashed his local testing environment. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;panic: interface conversion: interface {} is string, not main.UserStruct&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Eleanor walked by, pausing behind his chair. "A runtime panic. Let me guess: you pulled something out of the &lt;code&gt;sync.Map&lt;/code&gt; we built yesterday and tried to cast it to the wrong type."&lt;/p&gt;

&lt;p&gt;"I thought I was saving a &lt;code&gt;User&lt;/code&gt; struct," Ethan sighed, rubbing his temples. "But somewhere else in the code, I accidentally saved the user's ID as a &lt;code&gt;string&lt;/code&gt; under the same key. When I tried to pull it out and assert it as a &lt;code&gt;User&lt;/code&gt;, the program blew up."&lt;/p&gt;

&lt;p&gt;He leaned back. "You warned me that &lt;code&gt;sync.Map&lt;/code&gt; uses &lt;code&gt;any&lt;/code&gt; and drops type safety. But this feels like a step backward. Am I really supposed to just cross my fingers and hope I don't typo an interface assertion?"&lt;/p&gt;

&lt;p&gt;"Before Go 1.18, yes. You had to rely on strict discipline and unit tests," Eleanor said, taking the seat next to him. "But today, we have a way to get the performance of a concurrent map &lt;em&gt;and&lt;/em&gt; the safety of compile-time checks. We use Type Parameters. We use &lt;strong&gt;Generics&lt;/strong&gt;."&lt;/p&gt;

&lt;h3&gt;
  
  
  The Type Parameter (&lt;code&gt;[K, V]&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;"Generics allow us to write code that works with multiple types, without sacrificing the compiler's ability to check our work," Eleanor explained. "We are going to wrap the &lt;code&gt;sync.Map&lt;/code&gt; in a custom struct."&lt;/p&gt;

&lt;p&gt;She opened a new file and typed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// SafeCache wraps a sync.Map to provide compile-time type safety.&lt;/span&gt;
&lt;span class="c"&gt;// We define two Type Parameters: K for the key, V for the value.&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;SafeCache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;K&lt;/span&gt; &lt;span class="n"&gt;comparable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;V&lt;/span&gt; &lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;internal&lt;/span&gt; &lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Map&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ethan pointed at the square brackets. "What is &lt;code&gt;comparable&lt;/code&gt;? Why isn't &lt;code&gt;K&lt;/code&gt; just &lt;code&gt;any&lt;/code&gt;?"&lt;/p&gt;

&lt;p&gt;"A map key must be hashable so the map can look it up," Eleanor said. "You can't use a slice or a function as a map key. &lt;code&gt;comparable&lt;/code&gt; is a built-in constraint. It tells the compiler: 'Only allow types here that can be compared using &lt;code&gt;==&lt;/code&gt; and &lt;code&gt;!=&lt;/code&gt;'. The value &lt;code&gt;V&lt;/code&gt;, however, can be absolutely &lt;code&gt;any&lt;/code&gt;thing."&lt;/p&gt;

&lt;h3&gt;
  
  
  The Generic Methods
&lt;/h3&gt;

&lt;p&gt;Eleanor proceeded to write the methods for their new struct.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Store saves a typed key and value into the internal map.&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;SafeCache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;K&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;V&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="n"&gt;Store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="n"&gt;K&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="n"&gt;V&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;internal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// Load retrieves a typed value.&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;SafeCache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;K&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;V&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="n"&gt;Load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="n"&gt;K&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;V&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;internal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;zero&lt;/span&gt; &lt;span class="n"&gt;V&lt;/span&gt; &lt;span class="c"&gt;// Create a zero-value of type V to return safely&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;zero&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// We can safely type assert to V because Store() guarantees &lt;/span&gt;
    &lt;span class="c"&gt;// nothing else could have been saved!&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;V&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ethan's eyes lit up. He immediately refactored his calling code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// We instantiate the generic struct with concrete types&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;userCache&lt;/span&gt; &lt;span class="n"&gt;SafeCache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;UserStruct&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="n"&gt;userCache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"user_1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;UserStruct&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Alice"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="c"&gt;// ERROR: The compiler stops this immediately! &lt;/span&gt;
    &lt;span class="c"&gt;// userCache.Store("user_2", "just a string") &lt;/span&gt;

    &lt;span class="c"&gt;// No type assertion needed when loading!&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;found&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;userCache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"user_1"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;found&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;"Look at that," Ethan marveled. "I tried to save a string, and my IDE threw a red squiggly line before I even compiled. No more runtime panics. It caught the bug instantly."&lt;/p&gt;

&lt;p&gt;"Exactly," Eleanor smiled. "You've hidden the dangerous &lt;code&gt;any&lt;/code&gt; interface inside a strictly typed, generic wrapper."&lt;/p&gt;

&lt;h3&gt;
  
  
  The Architect's Constraint
&lt;/h3&gt;

&lt;p&gt;Empowered by his new tool, Ethan opened up a utility file. &lt;/p&gt;

&lt;p&gt;"I have this simple &lt;code&gt;Add&lt;/code&gt; function," he said rapidly. "Right now, I have an &lt;code&gt;AddInts(a, b int)&lt;/code&gt; and an &lt;code&gt;AddFloats(a, b float64)&lt;/code&gt;. It's so repetitive. I'm going to use Generics to combine them into one!"&lt;/p&gt;

&lt;p&gt;He started typing out constraints, importing &lt;code&gt;golang.org/x/exp/constraints&lt;/code&gt; to support mathematical operators.&lt;/p&gt;

&lt;p&gt;"Stop," Eleanor said gently but firmly. &lt;/p&gt;

&lt;p&gt;Ethan paused.&lt;/p&gt;

&lt;p&gt;"Generics are a powerful architectural tool," Eleanor explained. "They are brilliant for data structures—like caches, trees, queues, and linked lists—where the logic of the structure has nothing to do with the data it holds. But they come with a cost. They make your code harder to read, and they increase compile times."&lt;/p&gt;

&lt;p&gt;"But I have to write the same three-line function twice," Ethan argued.&lt;/p&gt;

&lt;p&gt;"Yes. And you should," Eleanor replied. "There is a famous Go proverb: &lt;em&gt;A little copying is better than a little dependency.&lt;/em&gt; Do not use Generics just to save yourself a few keystrokes. If the function is short, write it twice. Embrace the simplicity."&lt;/p&gt;

&lt;p&gt;Ethan deleted his generic math function and looked back at his &lt;code&gt;SafeCache&lt;/code&gt;. "Use Generics for complex data structures and algorithms. Use copy-paste for simple logic."&lt;/p&gt;

&lt;p&gt;"Precisely," Eleanor said, closing her laptop. "Safety where you need it. Simplicity everywhere else."&lt;/p&gt;




&lt;h2&gt;
  
  
  Key Concepts from Episode 29
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Type Parameters (&lt;code&gt;[T any]&lt;/code&gt;)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Generics use square brackets &lt;code&gt;[]&lt;/code&gt; to declare type parameters, allowing functions and structs to operate on abstract types that are defined at instantiation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Type Constraints&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;any&lt;/code&gt;&lt;/strong&gt;: An alias for &lt;code&gt;interface{}&lt;/code&gt;. Accepts any type.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;comparable&lt;/code&gt;&lt;/strong&gt;: A built-in constraint that restricts the type parameter to types that support the &lt;code&gt;==&lt;/code&gt; and &lt;code&gt;!=&lt;/code&gt; operators (required for map keys).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The Generic Wrapper Pattern&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A standard Go pattern for providing type safety over standard library tools that rely on &lt;code&gt;any&lt;/code&gt; (like &lt;code&gt;sync.Map&lt;/code&gt; or &lt;code&gt;sync.Pool&lt;/code&gt;). The wrapper handles the dangerous type assertions internally, exposing a strictly typed API to the caller.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The Zero-Value Trick&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When returning from a generic function upon failure, you cannot return &lt;code&gt;nil&lt;/code&gt; because &lt;code&gt;V&lt;/code&gt; might be a value type (like &lt;code&gt;int&lt;/code&gt;). Instead, declare &lt;code&gt;var zero V&lt;/code&gt; and return &lt;code&gt;zero&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The Architectural Limit&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Generics add cognitive load. They should be reserved for data structures (Lists, Sets, generic Caches) and complex algorithms (Sorting, Filtering). They should not be used merely to deduplicate trivial, three-line functions.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Aaron Rose is a software engineer and technology writer at &lt;a href="https://www.tech-reader.blog" rel="noopener noreferrer"&gt;tech-reader.blog&lt;/a&gt;. For explainer videos and podcasts, check out &lt;a href="https://www.youtube.com/@tech-reader2007" rel="noopener noreferrer"&gt;Tech-Reader YouTube channel&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>coding</category>
      <category>programming</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>The Secret Life of Claude Code: Reading Code You Didn't Write</title>
      <dc:creator>Aaron Rose</dc:creator>
      <pubDate>Sun, 15 Mar 2026 23:12:17 +0000</pubDate>
      <link>https://dev.to/aaron_rose_0787cc8b4775a0/the-secret-life-of-claude-code-reading-code-you-didnt-write-1ljb</link>
      <guid>https://dev.to/aaron_rose_0787cc8b4775a0/the-secret-life-of-claude-code-reading-code-you-didnt-write-1ljb</guid>
      <description>&lt;p&gt;&lt;em&gt;How to orient yourself in an unfamiliar codebase — and how Claude Code can help you find your footing without losing your judgment&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Margaret is a senior software engineer. Timothy is her junior colleague. They work in a grand Victorian library in London — the kind of place where inherited collections are treated with respect, and where no one pretends to have read something they haven't. Timothy has arrived today with someone else's problem.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Episode 6&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Inheritance
&lt;/h2&gt;

&lt;p&gt;He set the printed file listing on the table without saying anything. Margaret looked at it the way she sometimes looked at things — unhurried, reading from the top.&lt;/p&gt;

&lt;p&gt;It was long.&lt;/p&gt;

&lt;p&gt;"Whose is it?" she said.&lt;/p&gt;

&lt;p&gt;"It was Marcus's. He left in February. It's a billing integration — handles subscription renewals, proration calculations, payment retries, webhook processing." He paused. "There's no documentation. There are comments, but most of them describe what the code does, not why it does it."&lt;/p&gt;

&lt;p&gt;"And you need to do what with it?"&lt;/p&gt;

&lt;p&gt;"Add support for a new payment provider. The product team wants it by end of month."&lt;/p&gt;

&lt;p&gt;Margaret was still looking at the file listing. "How long have you been staring at it?"&lt;/p&gt;

&lt;p&gt;"Since Monday."&lt;/p&gt;

&lt;p&gt;"And today is Thursday."&lt;/p&gt;

&lt;p&gt;"Yes."&lt;/p&gt;

&lt;p&gt;She set the paper down. "Tell me what you've understood so far."&lt;/p&gt;

&lt;p&gt;"The entry point is clear. The webhook handler is clear. But somewhere in the middle there's a proration engine that I genuinely cannot follow. The variable names are... interpretive. There are functions that call other functions that seem to call back into the first ones." He looked at her. "I don't know where to start."&lt;/p&gt;

&lt;p&gt;"You started in the wrong place," Margaret said. "That is what we are going to talk about today."&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Unfamiliar Code Resists Reading
&lt;/h2&gt;

&lt;p&gt;"Most developers," Margaret said, "approach unfamiliar code the way they approach a novel someone has left open to page 200. They try to understand the page they're on. They get confused because they lack context. They flip back a few pages, get more confused, and conclude that the code is badly written."&lt;/p&gt;

&lt;p&gt;"It might be badly written."&lt;/p&gt;

&lt;p&gt;"It might be," she allowed. "But that conclusion comes later. First you need to read it properly." She picked up her pen. "There are two fundamental mistakes people make with unfamiliar code. The first is starting in the middle. The second is trying to understand everything before understanding anything."&lt;/p&gt;

&lt;p&gt;Timothy looked at the file listing. "I did both."&lt;/p&gt;

&lt;p&gt;"Most people do. The proration engine that's confusing you — do you know yet whether it's actually complex, or whether it only feels complex because you don't know what it's supposed to do?"&lt;/p&gt;

&lt;p&gt;He was quiet for a moment. "I don't know."&lt;/p&gt;

&lt;p&gt;"That is the correct answer," Margaret said. "And it tells you something important. You cannot evaluate code you don't yet have a model for. Before you try to read the proration logic, you need to understand what proration is doing in the context of this system. Not the code. The behaviour."&lt;/p&gt;




&lt;h2&gt;
  
  
  The Two Passes
&lt;/h2&gt;

&lt;p&gt;"Before you open the code," Margaret said, "you make two passes. Most developers skip both of them and pay for it."&lt;/p&gt;

&lt;p&gt;She turned the notepad toward him.&lt;/p&gt;

&lt;p&gt;"The first pass is the map pass. You are not reading code. You are reading &lt;em&gt;structure&lt;/em&gt;. File names. Directory organisation. The top-level shape of things. Function names — not their bodies, just their names. What does this codebase think is important? What are its concepts? What are the things it has chosen to name?"&lt;/p&gt;

&lt;p&gt;"I did look at the file names."&lt;/p&gt;

&lt;p&gt;"Did you write them down?"&lt;/p&gt;

&lt;p&gt;He hadn't.&lt;/p&gt;

&lt;p&gt;"Write them down," Margaret said. "Build a vocabulary. If you see &lt;code&gt;prorateCharges&lt;/code&gt;, &lt;code&gt;applyCredit&lt;/code&gt;, &lt;code&gt;calculateMidCycleDelta&lt;/code&gt; — those are concepts. Before you read a single line of implementation, you should be able to describe the system in its own language." She paused. "This is where Claude Code becomes genuinely useful. Not to read the code for you. To help you build the map."&lt;/p&gt;

&lt;p&gt;"How?"&lt;/p&gt;

&lt;p&gt;"You paste in the structure. The file names, the function signatures, the class names. You say: &lt;em&gt;based on these names and the organisation of this codebase, describe what you think this system does, what its main concepts are, and what questions you would want to answer before adding a feature to it.&lt;/em&gt; What you get back is not a definitive answer. It is a hypothesis — a starting model that you will test and refine as you read."&lt;/p&gt;

&lt;p&gt;Timothy wrote this down carefully.&lt;/p&gt;

&lt;p&gt;"The second pass is the flow pass. You pick one complete path through the system — one transaction, one webhook event, one renewal — and you follow it from entry to exit. Not everything. One thing. You are tracing a thread, not reading a book."&lt;/p&gt;

&lt;p&gt;"And Claude Code?"&lt;/p&gt;

&lt;p&gt;"The same way. Paste in the relevant files, describe the path you are trying to follow, and ask: &lt;em&gt;what is this code doing along this path, and where does the path go?&lt;/em&gt; Again — a hypothesis. You are building a model, not receiving a verdict."&lt;/p&gt;




&lt;h2&gt;
  
  
  The Hypothesis Model
&lt;/h2&gt;

&lt;p&gt;"I want to be precise about something," Margaret said. "When you use Claude Code to read unfamiliar code, it is giving you a hypothesis, not a fact. It reads what is there. It does not know why decisions were made. It does not know what requirements existed that no longer exist. It does not know what the comment &lt;em&gt;above&lt;/em&gt; the function originally said before someone updated the code without updating the comment."&lt;/p&gt;

&lt;p&gt;"It reads the code as it is."&lt;/p&gt;

&lt;p&gt;"Exactly. Which is more than you have right now, but less than the full picture." She looked at him steadily. "This is the discipline. You take what Claude Code gives you, and you treat it as a starting point for questions, not as answers. If it says &lt;em&gt;this function calculates proration by comparing the days remaining in the billing cycle to the total days&lt;/em&gt;, your response should not be &lt;em&gt;great, I understand proration now&lt;/em&gt;. Your response should be: &lt;em&gt;is that the right way to calculate proration for this product's billing model, and does the code actually do that consistently?&lt;/em&gt;"&lt;/p&gt;

&lt;p&gt;"Test it against the actual code. Run it with real inputs. Find the edge cases the reading doesn't reveal. Claude Code can help you generate those tests — &lt;em&gt;given this proration logic, what inputs would expose incorrect behaviour?&lt;/em&gt; But you are the one who decides whether the tests are asking the right questions."&lt;/p&gt;




&lt;h2&gt;
  
  
  What to Do With the Middle
&lt;/h2&gt;

&lt;p&gt;"The middle," Timothy said. "The part I can't follow. What do I do with that specifically?"&lt;/p&gt;

&lt;p&gt;"The middle is always the hardest part," Margaret said, "because by the time you get there, the code assumes you have context you don't have. You are missing the vocabulary of decisions — why things were done the way they were done." She set down her pen. "There are three things you can do."&lt;/p&gt;

&lt;p&gt;"First — trace from the known. You said the webhook handler is clear to you. Start there. What does the webhook handler call? Follow that one call. Not where it leads eventually — just the immediate next step. Build the understanding one function at a time from a place of stability."&lt;/p&gt;

&lt;p&gt;Timothy was nodding slowly. He had been trying to understand the middle in isolation.&lt;/p&gt;

&lt;p&gt;"Second — read the tests. If there are tests — and Marcus, to his credit, wrote tests — they are documentation. They describe behaviour from the outside. A test that says &lt;em&gt;when a subscription upgrades mid-cycle, the prorated charge should equal the per-day difference times the remaining days&lt;/em&gt; tells you more about the intention than the implementation does."&lt;/p&gt;

&lt;p&gt;"Marcus did write tests," Timothy said. "I glanced at them."&lt;/p&gt;

&lt;p&gt;"Don't glance at them. Read them. They are the clearest statement of what the code was meant to do." She allowed a brief pause. "And when you take those tests to Claude Code — not the implementation, the tests — and ask: &lt;em&gt;what behaviour do these tests define, and are there cases they don't cover?&lt;/em&gt; — you get something valuable. You get an independent read of the specification."&lt;/p&gt;

&lt;p&gt;"And the third thing?"&lt;/p&gt;

&lt;p&gt;"Accept that some parts of the middle will not be clear until you have changed something." She looked at him. "There is a limit to understanding from reading. At some point you have to make a small, reversible change in a local environment with the test suite running, watch what breaks, and let the breakage teach you what the reading couldn't. This is not guessing. It is disciplined experimentation — but only ever against a test harness, never against code whose effects you cannot roll back. In a billing system especially, the cost of an uncontrolled experiment is not a failed build. It is a customer's incorrect charge."&lt;/p&gt;

&lt;p&gt;He wrote that down without being asked.&lt;/p&gt;

&lt;p&gt;"You form a hypothesis — &lt;em&gt;this function is responsible for x&lt;/em&gt; — you make a change that would expose whether that hypothesis is correct, and you observe the result. The test suite is your safety net. Do not experiment without it."&lt;/p&gt;




&lt;h2&gt;
  
  
  The Question of Trust
&lt;/h2&gt;

&lt;p&gt;"How much do I trust the code?" Timothy asked. It was the question that had been sitting under everything else.&lt;/p&gt;

&lt;p&gt;Margaret considered it. "You trust it the way you trust a map of a city you've never visited. It is likely to be mostly accurate. It may be out of date in places. There may be roads that exist that aren't on the map, and roads on the map that no longer exist. You use it to navigate, but you look up from it."&lt;/p&gt;

&lt;p&gt;"And Claude Code's reading of the code?"&lt;/p&gt;

&lt;p&gt;"The same. More useful than nothing. Less authoritative than understanding you've built yourself." She picked up her tea. "Here is what I would say to you about trust, specifically. The code that is easy to follow — trust it provisionally and verify the edge cases. The code that is hard to follow — do not trust it at all until you understand &lt;em&gt;why&lt;/em&gt; it's hard to follow."&lt;/p&gt;

&lt;p&gt;She set the cup down carefully.&lt;/p&gt;

&lt;p&gt;"Hard to follow code is sometimes cleverness — a developer who knew the language very well and optimised for terseness. It is sometimes the accumulated residue of decisions that made sense at the time, layered over years until the original shape is no longer visible. It is occasionally a genuine mistake that no one caught because no one wanted to look at it too closely." She paused. "And in billing systems specifically, it is sometimes none of those things. It is compliance. Tax law varies by jurisdiction. Payment processors impose constraints that have no business logic explanation. PCI requirements leave fingerprints in code that look arbitrary until you know what they're protecting against. Before you decide that something strange is a mistake and should be refactored — find out whether it was strange for a reason."&lt;/p&gt;

&lt;p&gt;"How do I find that out?"&lt;/p&gt;

&lt;p&gt;"The commit history," Margaret said. "Which brings me to something I should have said earlier."&lt;/p&gt;




&lt;h2&gt;
  
  
  Before He Left
&lt;/h2&gt;

&lt;p&gt;Outside, a London afternoon was doing what London afternoons often do — persisting with determined neutrality, neither quite grey nor quite clear.&lt;/p&gt;

&lt;p&gt;"You said I started in the wrong place," Timothy said. "Where should I have started?"&lt;/p&gt;

&lt;p&gt;"At the beginning," Margaret said. "Not the beginning of the file. The beginning of your understanding." She looked at him. "You should have spent the first day not reading the code at all. Reading what the system does. The product documentation, if there is any. Then the commit history — not just the messages, but the pattern of them. Which files change together. Which functions have been touched repeatedly. A file that has been modified fifteen times in two years is trying to tell you something. A function whose commit message says &lt;em&gt;hotfix: edge case for annual subscribers in EU&lt;/em&gt; is carrying context that the code itself cannot."&lt;/p&gt;

&lt;p&gt;"I didn't look at any of that."&lt;/p&gt;

&lt;p&gt;"Pull requests are the same. When Marcus opened a PR for a change to the proration engine, the conversation in that PR — the questions the reviewers asked, the justifications Marcus gave, the back-and-forth before it was merged — that is the documentation that never made it into the comments. Most developers never read it. It is the closest thing to sitting next to the person who wrote the code."&lt;/p&gt;

&lt;p&gt;"That's all there, in the repository."&lt;/p&gt;

&lt;p&gt;"All of it," Margaret said. "And Claude Code can help you make sense of it — paste in a commit thread or a PR description and ask: &lt;em&gt;what problem was this change trying to solve, and what assumptions does it make?&lt;/em&gt; The history is a record of decisions. Decisions have reasons. The reasons are what you need."&lt;/p&gt;

&lt;p&gt;He gathered his things slowly, the way he did when he was still processing something.&lt;/p&gt;

&lt;p&gt;"One more thing," Margaret said. "When you do understand it — when you've built the model and tested it and you feel confident — write it down. Not for Marcus, and not for yourself. For the person who inherits this code from you."&lt;/p&gt;

&lt;p&gt;She looked at him steadily.&lt;/p&gt;

&lt;p&gt;"Because they will be standing exactly where you are standing now. And they will deserve better than three days of confusion before they find their footing."&lt;/p&gt;

&lt;p&gt;He closed his notebook.&lt;/p&gt;

&lt;p&gt;Outside, the London afternoon persisted. Inside the library, a developer had just learned that reading code you didn't write is less about cleverness than about patience — and that the map you build before you start walking is the thing that makes the rest of the journey possible.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Next episode: Margaret and Timothy turn to the language you don't know — how to approach a codebase written in an unfamiliar language, and what Claude Code can and cannot do when you're outside your expertise.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The Secret Life of Claude Code publishes on tech-reader.blog every other day.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If this series is useful to you, share it with a developer who needs to inherit someone else's code.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Aaron Rose is a software engineer and technology writer at &lt;a href="https://www.tech-reader.blog" rel="noopener noreferrer"&gt;tech-reader.blog&lt;/a&gt;. For explainer videos and podcasts, check out &lt;a href="https://www.youtube.com/@tech-reader2007" rel="noopener noreferrer"&gt;Tech-Reader YouTube channel&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>claudecode</category>
      <category>codingwithai</category>
      <category>softwareengineering</category>
      <category>developerlife</category>
    </item>
    <item>
      <title>Happy Pi Day!</title>
      <dc:creator>Aaron Rose</dc:creator>
      <pubDate>Fri, 13 Mar 2026 01:38:17 +0000</pubDate>
      <link>https://dev.to/aaron_rose_0787cc8b4775a0/happy-pi-day-10df</link>
      <guid>https://dev.to/aaron_rose_0787cc8b4775a0/happy-pi-day-10df</guid>
      <description>&lt;p&gt;3.14159265358979323846264338327950288419716939937510...&lt;/p&gt;

</description>
      <category>pi</category>
      <category>python</category>
      <category>math</category>
    </item>
    <item>
      <title>The Secret Life of Claude Code: The Art of the Follow-Up</title>
      <dc:creator>Aaron Rose</dc:creator>
      <pubDate>Wed, 11 Mar 2026 01:29:07 +0000</pubDate>
      <link>https://dev.to/aaron_rose_0787cc8b4775a0/the-secret-life-of-claude-code-the-art-of-the-follow-up-27no</link>
      <guid>https://dev.to/aaron_rose_0787cc8b4775a0/the-secret-life-of-claude-code-the-art-of-the-follow-up-27no</guid>
      <description>&lt;p&gt;&lt;em&gt;What to do when Claude Code gets it almost right — and how one disciplined follow-up gets you the rest of the way there&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Margaret is a senior software engineer. Timothy is her junior colleague. They work in a grand Victorian library in London — the kind of place where conversations are finished properly, and where almost right is understood to be a different thing entirely from right. Timothy has arrived today with something he is not sure what to do with.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Almost
&lt;/h2&gt;

&lt;p&gt;He sat down without his usual preamble and turned the laptop toward her immediately. This, Margaret had learned, meant he wanted her to look before he explained. He was uncertain about something and did not yet have the words for it.&lt;/p&gt;

&lt;p&gt;She looked.&lt;/p&gt;

&lt;p&gt;On the screen was a function — a data export utility, clean and reasonably structured. She read it the way she always read code: slowly, without expression, beginning to end.&lt;/p&gt;

&lt;p&gt;"Claude Code?" she said.&lt;/p&gt;

&lt;p&gt;"Yes. Second attempt, actually. The first one was completely off. This one is..." He paused. "Close."&lt;/p&gt;

&lt;p&gt;"Close," she repeated.&lt;/p&gt;

&lt;p&gt;"It handles the main cases. The CSV export works. The date formatting is correct. But it doesn't handle empty datasets — it just throws an error instead of returning an empty file. And the column headers are hardcoded when they should come from the data schema."&lt;/p&gt;

&lt;p&gt;Margaret looked at the code again. "And what did you do when you noticed this?"&lt;/p&gt;

&lt;p&gt;Timothy hesitated. "I'm not sure whether to fix it myself, start over with a new prompt, or..." He trailed off.&lt;/p&gt;

&lt;p&gt;"Or what?"&lt;/p&gt;

&lt;p&gt;"Or tell Claude Code what's wrong and ask it to fix it."&lt;/p&gt;

&lt;p&gt;Margaret set the laptop down between them. "That third option," she said. "That is what we are going to talk about today."&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Developers Don't Follow Up
&lt;/h2&gt;

&lt;p&gt;"Most developers," Margaret said, "when they receive output that is almost right, do one of three things. They accept it and patch it manually. They discard it and start over from the beginning. Or they send a vague correction and hope for the better."&lt;/p&gt;

&lt;p&gt;"I've done all three," Timothy admitted.&lt;/p&gt;

&lt;p&gt;"Most people have. None of them are wrong exactly — but none of them are the most effective approach either." She picked up her pen. "Patching manually makes sense for a trivial fix. Starting over makes sense if the output is fundamentally misconceived. But when the output is &lt;em&gt;close&lt;/em&gt; — when the structure is sound and only specific behaviours are wrong — there is a better path."&lt;/p&gt;

&lt;p&gt;"The follow-up."&lt;/p&gt;

&lt;p&gt;"The follow-up," she confirmed. "Which is not simply sending another message. It is a skill. And like the first prompt, it requires thinking before typing."&lt;/p&gt;




&lt;h2&gt;
  
  
  What a Follow-Up Actually Is
&lt;/h2&gt;

&lt;p&gt;"Think about what Claude Code knows at this point," Margaret said. "It has your original prompt. It has the solution it produced. It has no idea what you think of that solution — what worked, what didn't, what you expected that you didn't get."&lt;/p&gt;

&lt;p&gt;"So I need to tell it."&lt;/p&gt;

&lt;p&gt;"Precisely. But &lt;em&gt;how&lt;/em&gt; you tell it matters enormously." She turned the notepad toward him. "A poor follow-up says: &lt;em&gt;this doesn't work, try again.&lt;/em&gt; It gives no information. Claude Code will produce another attempt — possibly better, possibly worse, almost certainly not targeted at the actual problem."&lt;/p&gt;

&lt;p&gt;Timothy was already nodding. He had sent that message before, in different words.&lt;/p&gt;

&lt;p&gt;"A good follow-up," Margaret continued, "does three things. It acknowledges what worked. It identifies precisely what didn't. And it adds any context that was missing from the original prompt — because if the first output was wrong in a specific way, that wrongness often reveals a gap in what you originally provided."&lt;/p&gt;

&lt;p&gt;She wrote three short phrases on the notepad:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;What worked.&lt;/em&gt;&lt;br&gt;
&lt;em&gt;What didn't, and exactly how.&lt;/em&gt;&lt;br&gt;
&lt;em&gt;What I should have told you the first time.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;"That third one," Timothy said. "That's the one people skip."&lt;/p&gt;

&lt;p&gt;"Always," Margaret said. "Because it requires admitting that the original prompt was incomplete. Which it almost always is. The first output is not just a solution — it is a diagnostic. It shows you what Claude Code understood from what you gave it. When the output is wrong in a particular way, that wrongness is information about your prompt."&lt;/p&gt;




&lt;h2&gt;
  
  
  The Diagnostic Read
&lt;/h2&gt;

&lt;p&gt;"Show me the error," Margaret said. "When the empty dataset is passed."&lt;/p&gt;

&lt;p&gt;Timothy pulled up the output. The function threw a TypeError — it attempted to access the first row of the data to infer column structure, and when there was no first row, it failed.&lt;/p&gt;

&lt;p&gt;"What does that tell you?" Margaret asked.&lt;/p&gt;

&lt;p&gt;"That it assumed there would always be data."&lt;/p&gt;

&lt;p&gt;"Yes. And why did it assume that?"&lt;/p&gt;

&lt;p&gt;Timothy thought for a moment. "Because I didn't mention empty datasets in the prompt."&lt;/p&gt;

&lt;p&gt;"Correct. The error is not a failure of Claude Code's ability. It is a reflection of your prompt's silence on edge cases." She looked at him steadily. "This is the diagnostic read. Before you write your follow-up, you ask: what did this output assume that I never specified? The answer to that question tells you exactly what to add."&lt;/p&gt;

&lt;p&gt;He turned back to the laptop. "The column headers being hardcoded — that's the same thing. I said 'export to CSV' but I never said the headers should be dynamic."&lt;/p&gt;

&lt;p&gt;"You assumed it would infer that from context. It did not." She allowed a small pause. "This is not a criticism of your original prompt. It is almost impossible to specify everything in advance. The follow-up exists precisely because the first exchange is a dialogue, not a transaction."&lt;/p&gt;




&lt;h2&gt;
  
  
  The Follow-Up Prompt
&lt;/h2&gt;

&lt;p&gt;"Now write it," Margaret said. "The follow-up. Not yet — think first."&lt;/p&gt;

&lt;p&gt;Timothy was quiet for a moment. Outside, London was doing what London does in the early evening — settling into itself, lights coming on in the buildings across the way.&lt;/p&gt;

&lt;p&gt;"I need to acknowledge that the main export logic is correct," he said slowly. "So it doesn't throw that away and start over."&lt;/p&gt;

&lt;p&gt;"Good."&lt;/p&gt;

&lt;p&gt;"Then I need to describe the two specific problems. Not just name them — describe them. The empty dataset case should return an empty CSV with headers but no rows. The column headers should be derived from the schema object, not hardcoded."&lt;/p&gt;

&lt;p&gt;"Better. And the third part?"&lt;/p&gt;

&lt;p&gt;He thought. "I should tell it about the schema object. I don't think I mentioned it in the original prompt at all."&lt;/p&gt;

&lt;p&gt;"You did not."&lt;/p&gt;

&lt;p&gt;"So Claude Code invented the hardcoded headers because it had no idea the schema existed." He sat back. "The bug was in my prompt."&lt;/p&gt;

&lt;p&gt;"The gap was in your prompt," Margaret said, not unkindly. "There is a difference. A bug implies carelessness. A gap implies incompleteness. The first prompt is rarely complete. That is why the follow-up exists."&lt;/p&gt;

&lt;p&gt;Timothy wrote the follow-up carefully. He began by saying that the core export logic was working correctly and should be preserved. He then described each problem specifically — what was happening, what should happen instead, and under what conditions. Finally, he introduced the schema object he had omitted, describing its structure and how the headers should be derived from it.&lt;/p&gt;

&lt;p&gt;He read it back aloud — the habit Margaret had taught him — and caught one imprecision. He corrected it before sending.&lt;/p&gt;

&lt;p&gt;The response came back targeted and specific. The core logic was untouched. The empty dataset case now returned a header row with no data rows. The column headers were drawn cleanly from the schema.&lt;/p&gt;

&lt;p&gt;"It didn't start over," Timothy said.&lt;/p&gt;

&lt;p&gt;"Because you told it not to," Margaret said. "By describing what worked, you gave it permission to build on what already existed rather than replace it. That is not a small thing. A follow-up that begins with what is wrong invites a complete rewrite. A follow-up that begins with what is right invites a precise correction."&lt;/p&gt;




&lt;h2&gt;
  
  
  The Conversation, Not the Transaction
&lt;/h2&gt;

&lt;p&gt;"I've been thinking of each prompt as a separate request," Timothy said. "Like placing an order."&lt;/p&gt;

&lt;p&gt;"Most people do," Margaret said. "But that is not what it is. Claude Code holds the context of your conversation. It knows what you asked, what it produced, what you said in response. You are not placing a series of independent orders — you are having a conversation with a very capable colleague who happens to have no memory beyond the current session."&lt;/p&gt;

&lt;p&gt;"So the follow-up is just... the next thing I would say in a conversation."&lt;/p&gt;

&lt;p&gt;"Exactly that. If a colleague had built you this function and you found two problems with it, you would not hand it back and say &lt;em&gt;this is wrong, do it again.&lt;/em&gt; You would say — the main logic is good, there are two things to address, and I should have mentioned this third thing earlier. That is a professional exchange. That is what a good follow-up sounds like."&lt;/p&gt;

&lt;p&gt;Timothy looked at the corrected function on the screen. Clean, complete, handling every case he needed.&lt;/p&gt;

&lt;p&gt;"How many follow-ups is too many?" he asked.&lt;/p&gt;

&lt;p&gt;"That depends on what each one achieves," Margaret said. "If each follow-up produces meaningful progress toward the right answer, continue. If you find yourself sending the same correction and receiving the same gap in return — that is the signal to step back. Not to abandon the conversation, but to reconsider whether the context you have provided is sufficient." She paused. "Sometimes the right move is to start fresh with a prompt that incorporates everything you have learned from the previous exchange. The conversation was not wasted. It taught you what the prompt needed to contain."&lt;/p&gt;




&lt;h2&gt;
  
  
  Before He Left
&lt;/h2&gt;

&lt;p&gt;The library was quieter now. The afternoon had become evening without either of them particularly noticing.&lt;/p&gt;

&lt;p&gt;"There is one more thing," Margaret said. "When Claude Code produces something that is almost right — resist the urge to feel that almost right is good enough. It is not impatience or perfectionism to want the right answer. It is professional standards."&lt;/p&gt;

&lt;p&gt;"I nearly accepted the hardcoded headers," Timothy said. "I thought — close enough, I can deal with it later."&lt;/p&gt;

&lt;p&gt;"Later has a way of becoming never," Margaret said. "And a function with hardcoded headers will cause someone a problem at some point — possibly you, possibly someone who inherits your code, possibly a user. The follow-up costs five minutes. The fix costs considerably more when it arrives at the wrong time."&lt;/p&gt;

&lt;p&gt;She picked up her tea.&lt;/p&gt;

&lt;p&gt;"Claude Code is a patient correspondent. It does not tire of the conversation. It does not take corrections personally. It does not resent being asked to do better. Use that. The follow-up is not an admission that the first attempt failed — it is the natural continuation of a dialogue that was always going to take more than one exchange to get right."&lt;/p&gt;

&lt;p&gt;He closed the laptop.&lt;/p&gt;

&lt;p&gt;Outside, the lights of London had come fully on. Inside the library, a developer had just understood something that would change how he worked every day — that the first response is not the destination. It is the beginning of the conversation.&lt;/p&gt;

&lt;p&gt;And knowing how to continue that conversation is a skill worth building.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Next episode: Margaret and Timothy turn to a different kind of challenge — reading code you didn't write. How to orient yourself in an unfamiliar codebase, and how Claude Code can help you find your footing without losing your judgment.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The Secret Life of Claude Code publishes every other day.&lt;/em&gt;&lt;br&gt;
&lt;em&gt;If this series is useful to you, share it with a developer who needs to hear it.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Aaron Rose is a software engineer and technology writer at &lt;a href="https://www.tech-reader.blog" rel="noopener noreferrer"&gt;tech-reader.blog&lt;/a&gt;. For explainer videos and podcasts, check out &lt;a href="https://www.youtube.com/@tech-reader2007" rel="noopener noreferrer"&gt;Tech-Reader YouTube channel&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>claudecode</category>
      <category>codingwithai</category>
      <category>programming</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>The Secret Life of JavaScript: The Observer</title>
      <dc:creator>Aaron Rose</dc:creator>
      <pubDate>Tue, 10 Mar 2026 04:45:48 +0000</pubDate>
      <link>https://dev.to/aaron_rose_0787cc8b4775a0/the-secret-life-of-javascript-the-observer-53n4</link>
      <guid>https://dev.to/aaron_rose_0787cc8b4775a0/the-secret-life-of-javascript-the-observer-53n4</guid>
      <description>&lt;p&gt;&lt;em&gt;Stop Polling the DOM: Mastering the Intersection Observer API&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Timothy leaned back in his chair, listening to the sudden, aggressive whir of his laptop fan. He had just finished implementing a lazy-loading feature for a massive grid of user profile pictures.&lt;/p&gt;

&lt;p&gt;"The scroll is perfectly smooth," Timothy said, tapping his screen. "I used the &lt;code&gt;{ passive: true }&lt;/code&gt; flag we talked about yesterday. The Compositor Thread is completely unblocked. But my CPU usage just spiked to ninety percent, and my laptop sounds like it is preparing for takeoff."&lt;/p&gt;

&lt;p&gt;Margaret strolled over, her dark roast coffee in hand, and peered at the performance monitor on his secondary display.&lt;/p&gt;

&lt;p&gt;"You successfully unblocked the train," Margaret said, nodding at the screen. "But you are torturing the dispatcher."&lt;/p&gt;

&lt;p&gt;She pointed to the block of code responsible for the lazy loading.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;images&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;img[data-src]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;scroll&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;images&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Calculate exact geometry on every scroll tick&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getBoundingClientRect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// If the image enters the viewport, load it&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;top&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHeight&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;passive&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;"You remembered our lesson on Layout Thrashing," Margaret explained. "Every time you call &lt;code&gt;getBoundingClientRect()&lt;/code&gt;, you force the browser to calculate the exact, pixel-perfect geometry of the DOM. Doing that is expensive."&lt;/p&gt;

&lt;p&gt;Timothy defended his code. "But I have to know where the images are so I can load them before the user sees blank spaces."&lt;/p&gt;

&lt;p&gt;"Yes, but look at &lt;em&gt;when&lt;/em&gt; you are asking," Margaret said. "You tied that heavy mathematical calculation to the scroll event. Even though it is a passive listener, that event fires dozens of times a second. You are forcing the Main Thread to frantically calculate the exact GPS coordinates of every single passenger, every time the train moves an inch. You are essentially sitting in the backseat of a car, poking the driver fifty times a second, screaming, &lt;em&gt;'Are we there yet? Are we there yet?'&lt;/em&gt;"&lt;/p&gt;

&lt;p&gt;"So how do I know when the image enters the screen without asking?" Timothy asked.&lt;/p&gt;

&lt;p&gt;"You stop polling, and you set a tripwire," Margaret smiled. She introduced a new concept to the whiteboard. "You use the &lt;code&gt;IntersectionObserver&lt;/code&gt; API."&lt;/p&gt;

&lt;p&gt;"An Observer flips the entire architecture," Margaret continued. "Instead of using JavaScript to constantly ask the browser for geometric coordinates, you hand a list of elements over to the browser's highly optimized, internal C++ engine. The browser engine natively understands the viewport. It handles all the spatial mathematics quietly in the background. The Main Thread goes completely to sleep, and the browser simply taps your JavaScript on the shoulder exactly when an element crosses the threshold."&lt;/p&gt;

&lt;p&gt;"And you can configure exactly where that tripwire sits," she added. "By setting a &lt;code&gt;rootMargin&lt;/code&gt; of, say, &lt;code&gt;100px&lt;/code&gt;, you tell the browser to tap your shoulder just &lt;em&gt;before&lt;/em&gt; the image enters the screen, completely eliminating that split-second white flash. You can even use the &lt;code&gt;threshold&lt;/code&gt; option to wait until exactly 50% or 100% of the element is visible."&lt;/p&gt;

&lt;p&gt;Timothy deleted his scroll listener and his &lt;code&gt;getBoundingClientRect()&lt;/code&gt; loop entirely. He created an options object and instantiated a new &lt;code&gt;IntersectionObserver&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;images&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;img[data-src]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;rootMargin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;100px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// The tripwire: fire 100px before entering the viewport&lt;/span&gt;
  &lt;span class="na"&gt;threshold&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;         &lt;span class="c1"&gt;// Fire as soon as 1 pixel crosses the line&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// 1. Create the tripwire&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;observer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;IntersectionObserver&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// 2. The browser taps JavaScript on the shoulder&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isIntersecting&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;img&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Load the image&lt;/span&gt;

      &lt;span class="c1"&gt;// 3. Stop watching this specific image once it loads&lt;/span&gt;
      &lt;span class="nx"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unobserve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// 4. Register all images with the internal C++ engine&lt;/span&gt;
&lt;span class="nx"&gt;images&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;observe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;"Look at the elegance of that," Margaret said, watching him save the file. "There is zero math on the Main Thread. Modern frameworks like React actually wrap this entire C++ engine interaction into simple hooks like &lt;code&gt;useInView()&lt;/code&gt;, giving you this performance benefit with even less code. But underneath, the architecture is exactly what you just wrote: The JavaScript only wakes up when an image actually triggers the tripwire, it does exactly one job, and then it immediately unobserves the element so it never fires again."&lt;/p&gt;

&lt;p&gt;Timothy refreshed the page and began scrolling furiously down the massive grid of profiles.&lt;/p&gt;

&lt;p&gt;The scrolling remained buttery smooth. The images popped into existence perfectly just before they crossed into view. The dispatcher was no longer being poked constantly; he was waiting patiently, and the browser itself was sending a signal only when a passenger actually needed to get off.&lt;/p&gt;

&lt;p&gt;Best of all, the frantic whirring of his laptop fan slowly spun down into complete silence.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Aaron Rose is a software engineer and technology writer at &lt;a href="https://www.tech-reader.blog" rel="noopener noreferrer"&gt;tech-reader.blog&lt;/a&gt;. For explainer videos and podcasts, check out &lt;a href="https://www.youtube.com/@tech-reader2007" rel="noopener noreferrer"&gt;Tech-Reader YouTube channel&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>coding</category>
      <category>programming</category>
    </item>
    <item>
      <title>The Secret Life of Claude Code: When Claude Code Gets It Wrong</title>
      <dc:creator>Aaron Rose</dc:creator>
      <pubDate>Mon, 09 Mar 2026 01:05:16 +0000</pubDate>
      <link>https://dev.to/aaron_rose_0787cc8b4775a0/the-secret-life-of-claude-code-when-claude-code-gets-it-wrong-1ljn</link>
      <guid>https://dev.to/aaron_rose_0787cc8b4775a0/the-secret-life-of-claude-code-when-claude-code-gets-it-wrong-1ljn</guid>
      <description>&lt;p&gt;&lt;em&gt;Three ways Claude Code gets it wrong — and the discipline that catches all of them before they ship&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Margaret is a senior software engineer. Timothy is her junior colleague. They work in a grand Victorian library in London — the kind of place where precision matters and confidence is not the same thing as correctness. Timothy has arrived today in unusually good spirits. This, Margaret has learned, is sometimes cause for concern.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What Timothy Was Proud Of
&lt;/h2&gt;

&lt;p&gt;He came through the door with the particular energy of someone who had solved something.&lt;/p&gt;

&lt;p&gt;"I fixed it," he said, settling into his chair with the satisfaction of a man who had earned his tea. "The user authentication bug. The one that's been sitting in the backlog for two weeks."&lt;/p&gt;

&lt;p&gt;"Tell me," Margaret said.&lt;/p&gt;

&lt;p&gt;"I described the problem to Claude Code — properly this time, the way we talked about. Context, specific behaviour, constraints. It gave me a solution, I reviewed it, it looked right, I tested it, it passed. Deployed this morning."&lt;/p&gt;

&lt;p&gt;"And it worked?"&lt;/p&gt;

&lt;p&gt;"Perfectly. Users can log in, sessions are handled correctly, no errors in the logs." He opened his laptop. "I wanted to show you the code."&lt;/p&gt;

&lt;p&gt;Margaret looked at it. She read slowly, as she always did — not skimming, not nodding along, but actually reading. Timothy had learned not to fill this silence.&lt;/p&gt;

&lt;p&gt;After a moment she said, "Walk me through the session expiry logic."&lt;/p&gt;

&lt;p&gt;"It resets the session token on each login. Clears the old one, generates a new one, stores it with a timestamp."&lt;/p&gt;

&lt;p&gt;"And when does the session expire?"&lt;/p&gt;

&lt;p&gt;"Twenty-four hours after the timestamp."&lt;/p&gt;

&lt;p&gt;"After which timestamp?"&lt;/p&gt;

&lt;p&gt;Timothy looked at the screen. Then he looked at it more carefully.&lt;/p&gt;

&lt;p&gt;"After the..." He stopped.&lt;/p&gt;

&lt;p&gt;Margaret waited.&lt;/p&gt;

&lt;p&gt;"After the &lt;em&gt;creation&lt;/em&gt; timestamp," he said slowly. "Not the last activity timestamp."&lt;/p&gt;

&lt;p&gt;"No."&lt;/p&gt;

&lt;p&gt;The good spirits left the room quietly, the way warmth does when a window is opened in winter.&lt;/p&gt;

&lt;p&gt;"So a user who logs in and stays active," Timothy said, "will still be logged out after twenty-four hours regardless."&lt;/p&gt;

&lt;p&gt;"Yes."&lt;/p&gt;

&lt;p&gt;"Even if they were active thirty seconds ago."&lt;/p&gt;

&lt;p&gt;"Yes."&lt;/p&gt;

&lt;p&gt;He sat back. "That's going to be a terrible experience."&lt;/p&gt;

&lt;p&gt;"It is going to be a very frustrating experience," Margaret agreed, "for any user who is in the middle of something when the clock runs out." She looked at him steadily. "The code is not broken, Timothy. It does exactly what it was written to do. It simply does not do what you needed it to do."&lt;/p&gt;




&lt;h2&gt;
  
  
  The Shape of the Problem
&lt;/h2&gt;

&lt;p&gt;He stared at the screen for a moment. "But I tested it."&lt;/p&gt;

&lt;p&gt;"What did you test?"&lt;/p&gt;

&lt;p&gt;"I logged in. The session worked. I logged out, logged back in. New token, no errors."&lt;/p&gt;

&lt;p&gt;"Did you test a session that had been active for twenty-three hours and fifty-nine minutes?"&lt;/p&gt;

&lt;p&gt;"No," he admitted. "Obviously not."&lt;/p&gt;

&lt;p&gt;"Did you test what happens to an active user when their session expires mid-task?"&lt;/p&gt;

&lt;p&gt;"No."&lt;/p&gt;

&lt;p&gt;"Did you consider that the requirement might be &lt;em&gt;sliding expiry&lt;/em&gt; — resetting the clock on activity — rather than &lt;em&gt;fixed expiry&lt;/em&gt; from login?"&lt;/p&gt;

&lt;p&gt;A pause. "I didn't think about it in those terms."&lt;/p&gt;

&lt;p&gt;"Claude Code did not think about it in those terms either," Margaret said. "Because you did not ask it to. You described a bug — sessions not being cleared correctly — and it fixed that bug. Cleanly and correctly. But the behaviour you actually needed was never specified, so it was never built."&lt;/p&gt;

&lt;p&gt;She picked up her pen.&lt;/p&gt;

&lt;p&gt;"This is the shape of the problem. Claude Code gave you a confident, well-structured, functional solution to the problem you described. It was not the solution to the problem you had."&lt;/p&gt;




&lt;h2&gt;
  
  
  Confidence Is Not a Signal
&lt;/h2&gt;

&lt;p&gt;"That's what bothers me most," Timothy said. "The code looked right. It read like something I would have written on a good day — clean, commented, sensible variable names. There was nothing in it that said &lt;em&gt;this might not be what you need.&lt;/em&gt;"&lt;/p&gt;

&lt;p&gt;"There never is," Margaret said. "This is the important thing to understand. Claude Code cannot reliably flag gaps in your requirements. When something is ambiguous or unspecified, it does not stop and ask — it fills the gap with a reasonable assumption and continues. It will tell you if a function does not exist, or if a pattern is deprecated, or if there is a type mismatch. But it cannot tell you if the behaviour it has implemented matches the behaviour your users actually need. That knowledge lives only in your head. And in the heads of your users."&lt;/p&gt;

&lt;p&gt;"So the confidence of the output is meaningless."&lt;/p&gt;

&lt;p&gt;"The confidence of the output is a measure of technical coherence," Margaret said carefully. "The code is consistent. The logic follows. The syntax is correct. Those things Claude Code can assess, and it is very good at them. But &lt;em&gt;correctness&lt;/em&gt; in the deeper sense — does this do what the business needs, does this serve the user well, does this handle the edge cases that matter — that is yours to verify. Always."&lt;/p&gt;

&lt;p&gt;Timothy looked at the code again with different eyes. It had not changed. But he had.&lt;/p&gt;

&lt;p&gt;"It's like getting directions to the wrong address," he said. "Delivered with complete confidence."&lt;/p&gt;

&lt;p&gt;"That is an excellent description," Margaret said. "And the directions may be perfect. Every turn correct. Arrive precisely where you were told to go. The question is whether that was where you needed to be."&lt;/p&gt;




&lt;h2&gt;
  
  
  The Three Failure Modes
&lt;/h2&gt;

&lt;p&gt;She drew three short lines on her notepad, the way she sometimes did when organising a thought.&lt;/p&gt;

&lt;p&gt;"When Claude Code gets it wrong," she said, "it tends to do so in one of three ways. It is worth knowing all three."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;First — *the wrong problem.&lt;/strong&gt;* This is what happened today. You described a problem, Claude Code solved that problem, but the problem you described was not the whole problem. The output is technically correct and functionally incomplete. This is the most common failure mode, and the most insidious, because the code works. It just does not work &lt;em&gt;enough.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Timothy was writing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Second — *the outdated answer.&lt;/strong&gt;* Claude Code's knowledge has a boundary in time. For well-established patterns it is reliable. But for libraries that move quickly, for APIs that change, for security practices that have evolved — it may give you an answer that was correct some time ago and is subtly wrong today. A hashing algorithm that was once acceptable. An authentication library that has since been superseded. A configuration pattern that newer versions have deprecated. The code will look reasonable. It will often run. And it will carry a flaw you did not know to look for. Always check the version. Always verify against current documentation for anything where recency matters.&lt;/p&gt;

&lt;p&gt;"And third?"&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Third — *the plausible fabrication.&lt;/strong&gt;* Occasionally — not often, but occasionally — Claude Code will produce something that looks authoritative but is simply invented. A function that does not exist. A parameter that was never part of the API. A configuration option that sounds reasonable but cannot be found in any documentation. It will not announce this. It will present the fabrication with the same tone as everything else.&lt;/p&gt;

&lt;p&gt;Timothy looked up. "How do you catch that one?"&lt;/p&gt;

&lt;p&gt;"You run the code," Margaret said. "And you read the error message carefully. A plausible fabrication almost always fails at runtime, because the thing it invented does not exist in the actual system. The code looks right. Then it breaks in a very specific way — a missing attribute, an unknown method, a module that cannot be found." She looked at him. "When you see an error that suggests something simply does not exist — resist the urge to assume you have made a mistake. Consider that the solution may have invented something."&lt;/p&gt;




&lt;h2&gt;
  
  
  What Review Actually Means
&lt;/h2&gt;

&lt;p&gt;"I did review the code," Timothy said. There was a defensiveness in it — not hostile, but genuine. He wanted to understand where he had gone wrong.&lt;/p&gt;

&lt;p&gt;"I know you did," Margaret said, without any edge. "And the review was not useless. You would have caught a syntax error, a missing import, an obvious logic flaw. Code review has real value." She paused. "But there is a difference between reviewing code for technical correctness and reviewing code for &lt;em&gt;behavioural completeness.&lt;/em&gt; Most developers only do the first. It is what we were trained to do — read the code, understand the code, verify the code does what it appears to do."&lt;/p&gt;

&lt;p&gt;"But not whether it does what it &lt;em&gt;should&lt;/em&gt; do."&lt;/p&gt;

&lt;p&gt;"Exactly. That second question requires you to step outside the code entirely and ask: what are the real requirements here? Not what did I ask Claude Code to build. What does this feature actually need to do for a real user in a real situation?" She set down her pen. "Write those requirements down before you look at the solution. Even briefly. Even just three or four bullet points. Then compare what you wrote to what was built."&lt;/p&gt;

&lt;p&gt;"I didn't write any requirements."&lt;/p&gt;

&lt;p&gt;"No. You had them in your head — loosely — and you assumed the output would match them. This is a very human thing to do. We are pattern-matchers. The code looked like the right shape, so we accepted it as the right answer."&lt;/p&gt;

&lt;p&gt;Timothy was quiet for a moment. Outside, the sounds of the city continued without interest in the conversation.&lt;/p&gt;

&lt;p&gt;"If I had written down that sessions should expire on inactivity," he said, "I would have caught it immediately."&lt;/p&gt;

&lt;p&gt;"Before you sent the prompt," Margaret said. "And the prompt itself would have been better — because it would have contained the actual requirement." She allowed a small pause. "The preparation we discussed last time protects you here as well. A precise prompt is harder to misanswer. A vague prompt can be answered correctly in ways that do not help you at all."&lt;/p&gt;




&lt;h2&gt;
  
  
  Before He Closed the Laptop
&lt;/h2&gt;

&lt;p&gt;"I need to fix this today," Timothy said.&lt;/p&gt;

&lt;p&gt;"You do," Margaret agreed. "It is a minor fix — update the expiry logic to track last activity rather than creation time. Claude Code will handle it well if you describe the requirement precisely."&lt;/p&gt;

&lt;p&gt;"And this time I know what the requirement actually is."&lt;/p&gt;

&lt;p&gt;"Yes. That is the difference." She looked at him. "Do not be discouraged by this, Timothy. What happened today is not a failure of your abilities. It is a failure of a habit you have not yet built — the habit of separating what you asked for from what you needed. That habit takes time. You are building it now."&lt;/p&gt;

&lt;p&gt;He nodded slowly. "The code was good. The requirement was incomplete."&lt;/p&gt;

&lt;p&gt;"And that distinction matters enormously," Margaret said. "Because it tells you where to look. Not at the tool. At the thinking before the tool."&lt;/p&gt;

&lt;p&gt;She picked up her tea.&lt;/p&gt;

&lt;p&gt;"Claude Code did not deceive you. It answered the question you asked. The discipline — and it is a discipline — is learning to ask questions complete enough that the answer cannot mislead you, even when it is technically correct."&lt;/p&gt;

&lt;p&gt;He closed the laptop.&lt;/p&gt;

&lt;p&gt;Outside, London was carrying on in its unhurried way. Inside the library, a developer had just learned something that could not be learned from documentation — the difference between code that works and code that is right.&lt;/p&gt;

&lt;p&gt;They are not always the same thing.&lt;/p&gt;

&lt;p&gt;And knowing that is half the work.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Next episode: Margaret and Timothy explore the art of the follow-up — what to do after Claude Code gives you something that is almost right, and how to guide the conversation toward what you actually need.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If this series is useful to you, share it with a developer who needs to hear it.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Aaron Rose is a software engineer and technology writer at &lt;a href="https://www.tech-reader.blog" rel="noopener noreferrer"&gt;tech-reader.blog&lt;/a&gt;. For explainer videos and podcasts, check out &lt;a href="https://www.youtube.com/@tech-reader2007" rel="noopener noreferrer"&gt;Tech-Reader YouTube channel&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>claudecode</category>
      <category>codingwithai</category>
      <category>programming</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>The Secret Life of JavaScript: The Scroll</title>
      <dc:creator>Aaron Rose</dc:creator>
      <pubDate>Sun, 08 Mar 2026 19:16:33 +0000</pubDate>
      <link>https://dev.to/aaron_rose_0787cc8b4775a0/the-secret-life-of-javascript-the-scroll-58jf</link>
      <guid>https://dev.to/aaron_rose_0787cc8b4775a0/the-secret-life-of-javascript-the-scroll-58jf</guid>
      <description>&lt;p&gt;&lt;em&gt;Unblocking the Compositor: How to Fix Mobile Scroll Lag&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Frozen
&lt;/h2&gt;

&lt;p&gt;Timothy swiped his thumb across his Android screen. The parallax dashboard he had spent all morning building lurched forward, froze for a fraction of a second, and then snapped to a new position. It felt like dragging a brick through mud. He dropped the phone on his desk and glared at his desktop monitor, where the exact same code was running flawlessly in his dark-themed IDE.&lt;/p&gt;

&lt;p&gt;"I don't understand," Timothy muttered. "I batched my DOM reads and writes. I used &lt;code&gt;requestAnimationFrame&lt;/code&gt;. The Main Thread is completely optimized, but the mobile experience is completely unusable."&lt;/p&gt;

&lt;p&gt;Margaret leaned against his cubicle wall, her signature dark roast coffee in hand. She picked up his phone, swiped the screen, and watched the UI stutter.&lt;/p&gt;

&lt;p&gt;"Your Main Thread might be optimized, but you are still forcing the browser to use it for something it shouldn't," Margaret said. She set the phone down and pointed to a single line of code on his screen.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;scroll&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Complex parallax math and DOM updates&lt;/span&gt;
  &lt;span class="nf"&gt;updateParallaxPositions&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Compositor Thread
&lt;/h2&gt;

&lt;p&gt;"Scrolling is so fundamental to the web experience that modern browsers created a dedicated, hardware-accelerated lane just for it," Margaret explained. "It is called the Compositor Thread.  It runs directly on the GPU, completely separate from the Main Thread where your JavaScript lives. When a user swipes their screen, the Compositor Thread wants to instantly slide the page up or down at a perfect sixty frames per second."&lt;/p&gt;

&lt;p&gt;Timothy frowned. "If it has its own dedicated thread, why is my scroll lagging?"&lt;/p&gt;

&lt;p&gt;"Because you attached a standard event listener to the window," Margaret said. "And this is especially critical for &lt;code&gt;touchstart&lt;/code&gt; and &lt;code&gt;touchmove&lt;/code&gt; events on mobile devices, where every millisecond of delay ruins the feel of the app. By listening to those events, you forced the lightning-fast Compositor Thread to hit the brakes. Before the browser can move the page even a single pixel, the Compositor has to pause, look over at the Main Thread, and ask, 'Hey, did Timothy write &lt;code&gt;event.preventDefault()&lt;/code&gt; in his JavaScript? Is he trying to cancel this scroll?'"&lt;/p&gt;

&lt;h2&gt;
  
  
  A High-Speed Train
&lt;/h2&gt;

&lt;p&gt;She grabbed a marker and drew a quick diagram on the whiteboard. It showed a high-speed train representing the Compositor Thread, forced to stop at a railroad crossing every few feet to ask a busy dispatcher for permission to proceed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Without passive:  🚂---🚦---🚂---🚦 (Waiting for Main Thread)
With passive:     🚂🚂🚂🚂🚂🚂🚂🚂 (Clear track on GPU)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;"The browser engine is incredibly cautious," Margaret continued, pointing to the stoplights. "It assumes that because you are listening to the event, you might want to intercept and cancel it. So, it waits for your JavaScript to execute on every single pixel of movement. If the Main Thread is busy fetching data or parsing a script, the Compositor Thread just sits there, waiting at the red light. That waiting is the stutter you feel on your phone."&lt;/p&gt;

&lt;p&gt;Timothy looked at his code. "But I am not canceling the scroll. I just want to know where the scroll position is so I can update my parallax elements. How do I tell the browser to stop waiting for me?"&lt;/p&gt;

&lt;h2&gt;
  
  
  A Contract With the Browser
&lt;/h2&gt;

&lt;p&gt;"You sign a contract," Margaret smiled. "You give the browser a legally binding promise that you will not call &lt;code&gt;event.preventDefault()&lt;/code&gt;. You do this by passing a configuration object to your event listener."&lt;/p&gt;

&lt;p&gt;Timothy updated his code, adding the third argument to the event listener.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;scroll&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Complex parallax math and DOM updates&lt;/span&gt;
  &lt;span class="nf"&gt;updateParallaxPositions&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;passive&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;"Modern browsers actually default &lt;code&gt;scroll&lt;/code&gt;, &lt;code&gt;touchstart&lt;/code&gt;, and &lt;code&gt;wheel&lt;/code&gt; events to &lt;code&gt;passive: true&lt;/code&gt; to try and save developers from themselves," Margaret noted. "But explicitly setting it guarantees the behavior across all environments and proves you actually understand the architecture underneath your code."&lt;/p&gt;

&lt;p&gt;"That single flag changes the entire dynamic. You just told the browser engine, 'I am watching the scroll, but I promise I will not interfere with it.' Instantly, the Compositor Thread is untethered. It handles the scrolling on the GPU without ever waiting for the Main Thread, and your JavaScript simply receives the updates asynchronously."&lt;/p&gt;

&lt;p&gt;"And if I actually need to stop the scroll?" Timothy asked.&lt;/p&gt;

&lt;p&gt;"Then you cannot use the flag," Margaret replied. "If you are building a custom swipe carousel or a sliding drawer where you &lt;em&gt;do&lt;/em&gt; need to call &lt;code&gt;preventDefault()&lt;/code&gt; to stop the native scrolling, you have to use an active listener. The contract requires absolute honesty."&lt;/p&gt;

&lt;h2&gt;
  
  
  Running Fast
&lt;/h2&gt;

&lt;p&gt;Timothy saved the file and picked up his Android phone. He placed his thumb on the glass and swiped.&lt;/p&gt;

&lt;p&gt;The dashboard flew up the screen. The parallax elements drifted perfectly in the background. There was no hesitation, no stutter, and no lag. The high-speed train was finally running on a clear track.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Aaron Rose is a software engineer and technology writer at &lt;a href="https://www.tech-reader.blog" rel="noopener noreferrer"&gt;tech-reader.blog&lt;/a&gt;. For explainer videos and podcasts, check out &lt;a href="https://www.youtube.com/@tech-reader2007" rel="noopener noreferrer"&gt;Tech-Reader YouTube channel&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>coding</category>
      <category>programming</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>The Secret Life of Claude Code: The First Prompt</title>
      <dc:creator>Aaron Rose</dc:creator>
      <pubDate>Sat, 07 Mar 2026 01:52:11 +0000</pubDate>
      <link>https://dev.to/aaron_rose_0787cc8b4775a0/the-secret-life-of-claude-code-the-first-prompt-3e0e</link>
      <guid>https://dev.to/aaron_rose_0787cc8b4775a0/the-secret-life-of-claude-code-the-first-prompt-3e0e</guid>
      <description>&lt;p&gt;&lt;em&gt;Why the quality of your prompt is really the quality of your thinking&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Margaret is a senior software engineer. Timothy is her junior colleague. They work in a grand Victorian library in London — the kind of place where precision is valued and vagueness is gently corrected. Timothy has arrived with a real problem and a prompt he is rather proud of.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Episode 3: The Craft of the First Prompt&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What Timothy Brought In
&lt;/h2&gt;

&lt;p&gt;He arrived with his laptop already open, which Margaret took as a good sign. It meant he had been thinking before he walked through the door.&lt;/p&gt;

&lt;p&gt;"I have a real one today," he said, settling into his chair. "Not a toy example. An actual problem from the codebase."&lt;/p&gt;

&lt;p&gt;"Good," Margaret said. "Show me what you've written."&lt;/p&gt;

&lt;p&gt;He turned the laptop toward her. On the screen was a prompt he had prepared:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Fix the performance issue in my data processing pipeline."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Margaret read it. Then she looked at him over her glasses with the particular expression she reserved for moments that required patience.&lt;/p&gt;

&lt;p&gt;"Timothy," she said. "What is wrong with this prompt?"&lt;/p&gt;

&lt;p&gt;He shifted slightly. "I thought it was fairly clear."&lt;/p&gt;

&lt;p&gt;"It is not clear at all," she said, not unkindly. "It is the prompt of someone who knows what they want but has not yet done the work of describing it."&lt;/p&gt;




&lt;h2&gt;
  
  
  The Interrogation
&lt;/h2&gt;

&lt;p&gt;She turned the laptop back toward him and folded her hands.&lt;/p&gt;

&lt;p&gt;"Tell me about the pipeline. What does it do?"&lt;/p&gt;

&lt;p&gt;"It processes customer transaction records. Reads from a database, applies some business logic, writes results to a reporting table."&lt;/p&gt;

&lt;p&gt;"How many records?"&lt;/p&gt;

&lt;p&gt;"On small runs, a few thousand. On the monthly batch — around four million."&lt;/p&gt;

&lt;p&gt;"And the performance issue. What exactly is happening?"&lt;/p&gt;

&lt;p&gt;"The monthly batch is timing out. It used to complete in about forty minutes. Now it's taking over three hours and failing halfway through."&lt;/p&gt;

&lt;p&gt;"When did this change?"&lt;/p&gt;

&lt;p&gt;Timothy paused. "About three weeks ago."&lt;/p&gt;

&lt;p&gt;"What changed three weeks ago?"&lt;/p&gt;

&lt;p&gt;Another pause — longer this time. "We added a new validation step. For regulatory compliance."&lt;/p&gt;

&lt;p&gt;Margaret looked at him steadily. "And you gave Claude Code the prompt: &lt;em&gt;fix the performance issue in my data processing pipeline.&lt;/em&gt;"&lt;/p&gt;

&lt;p&gt;He had the grace to look slightly embarrassed. "When you say it like that—"&lt;/p&gt;

&lt;p&gt;"I say it like that because that is what you wrote." She picked up her pen. "Claude Code is not a mind reader. It does not know about your four million records, your regulatory validation, your three-hour timeout, or the fact that this began three weeks ago. You handed it a problem with no context, no constraints, and no indication of what success looks like. What do you imagine it would produce?"&lt;/p&gt;

&lt;p&gt;"Something generic," he admitted.&lt;/p&gt;

&lt;p&gt;"Something generic," she confirmed. "Possibly something plausible-sounding but entirely wrong for your specific situation. And you would have to spend an hour discovering that, when five minutes of careful thinking at the start would have prevented it entirely."&lt;/p&gt;




&lt;h2&gt;
  
  
  The Four Questions
&lt;/h2&gt;

&lt;p&gt;She drew a small grid on her notepad — four boxes.&lt;/p&gt;

&lt;p&gt;"Before you write any prompt for a real engineering problem," she said, "you answer four questions. Not in the prompt itself necessarily — but in your own mind first, and then reflected in what you write."&lt;/p&gt;

&lt;p&gt;She filled in the boxes as she spoke.&lt;/p&gt;

&lt;p&gt;"First — &lt;em&gt;what is the context?&lt;/em&gt; What system are we working in, what does it do, what are its constraints? Claude Code needs to understand the world the problem lives in."&lt;/p&gt;

&lt;p&gt;"Second — &lt;em&gt;what is the specific problem?&lt;/em&gt; Not 'performance issue.' The pipeline processes four million records monthly, recently began timing out after three hours, previously completed in forty minutes, change coincided with addition of a validation step."&lt;/p&gt;

&lt;p&gt;"Third — &lt;em&gt;what have you already tried or considered?&lt;/em&gt; This is the question most developers skip. If you have already ruled out certain approaches, say so. If you have a theory, share it. You are not asking Claude Code to think from scratch — you are asking it to think alongside you."&lt;/p&gt;

&lt;p&gt;Timothy was writing now. Margaret continued.&lt;/p&gt;

&lt;p&gt;"Fourth — &lt;em&gt;what does a good solution look like?&lt;/em&gt; What are the constraints? Must it complete within a certain time? Must it not change the output format? Are there parts of the codebase it must not touch? Define success before you start, or you will not recognise it when you see it."&lt;/p&gt;

&lt;p&gt;She set down her pen. "Now rewrite your prompt."&lt;/p&gt;




&lt;h2&gt;
  
  
  The Rewrite
&lt;/h2&gt;

&lt;p&gt;Timothy was quiet for several minutes. Margaret drank her tea and did not hurry him. Good thinking could not be rushed, and she had learned long ago that silence was often more productive than assistance.&lt;/p&gt;

&lt;p&gt;He turned the laptop toward her.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"I have a data processing pipeline in Python that reads customer transaction records from a PostgreSQL database, applies business logic validation, and writes results to a reporting table. On monthly batch runs of approximately four million records, the pipeline recently began timing out after three hours — it previously completed in forty minutes. The change coincided with the addition of a new regulatory validation step three weeks ago. I suspect the validation logic may be running a database query inside a loop, but I have not confirmed this. The solution must not change the output format or the table schema. Can you help me identify the likely bottleneck and suggest an approach to fix it?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Margaret read it carefully. All the way through, twice.&lt;/p&gt;

&lt;p&gt;"Better," she said. "Much better."&lt;/p&gt;

&lt;p&gt;"Just better?"&lt;/p&gt;

&lt;p&gt;"Significantly better," she allowed. "You have given it context, a specific problem, a timeline, a hypothesis, and a constraint. Claude Code can now do something genuinely useful with this." She paused. "One addition I would suggest — tell it what you want first. Not at the end."&lt;/p&gt;

&lt;p&gt;"What do you mean?"&lt;/p&gt;

&lt;p&gt;"You buried the actual request in the last sentence. Lead with the outcome you want, then provide the context. Something like: &lt;em&gt;I need to diagnose and fix a performance regression in a Python data pipeline&lt;/em&gt; — then everything else follows. The tool reads from the beginning. Give it direction before you give it detail."&lt;/p&gt;

&lt;p&gt;Timothy made the adjustment. The prompt now opened with a clear statement of intent, followed by everything he had already written.&lt;/p&gt;

&lt;p&gt;"There," Margaret said. "Now you have a prompt worth sending."&lt;/p&gt;




&lt;h2&gt;
  
  
  What Changed
&lt;/h2&gt;

&lt;p&gt;"Can I ask something?" Timothy said. "The second prompt is so much longer. Is longer always better?"&lt;/p&gt;

&lt;p&gt;"No," Margaret said immediately. "Length is not the virtue. &lt;em&gt;Precision&lt;/em&gt; is the virtue. Your second prompt is longer because your first prompt was missing essential information. If your first prompt had been precise and complete, it would have been the right length." She looked at him steadily. "The question to ask is not &lt;em&gt;have I written enough?&lt;/em&gt; It is &lt;em&gt;does this contain everything Claude Code needs to help me?&lt;/em&gt; Sometimes that is two sentences. Sometimes it is a paragraph. The problem determines the length, not the other way around."&lt;/p&gt;

&lt;p&gt;Timothy nodded slowly. "So the prompt is really just... clear thinking written down."&lt;/p&gt;

&lt;p&gt;"Exactly that," Margaret said. "That is all it has ever been. The developers who struggle with Claude Code are very often not struggling with the tool — they are struggling with the thinking that should come before the tool. The prompt reveals the quality of your understanding. If your understanding is vague, the prompt will be vague, and the output will be vague."&lt;/p&gt;

&lt;p&gt;"And if my understanding is clear—"&lt;/p&gt;

&lt;p&gt;"The prompt will be clear, and Claude Code will do remarkable work." She closed her notepad. "This is why I said in our first conversation that the tool amplifies what you bring to it. Nowhere is that more visible than in the prompt."&lt;/p&gt;




&lt;h2&gt;
  
  
  The Hypothesis Worth Sharing
&lt;/h2&gt;

&lt;p&gt;"You mentioned a hypothesis," Margaret said. "That the validation logic might be running a database query inside a loop. Do you actually believe that?"&lt;/p&gt;

&lt;p&gt;"It's the most likely thing," Timothy said. "The validation step checks each transaction against a reference table. If it's doing that one record at a time instead of batching—"&lt;/p&gt;

&lt;p&gt;"Then you have an N+1 query problem," Margaret said. "Four million individual database calls instead of a small number of efficient batched queries."&lt;/p&gt;

&lt;p&gt;"Which would explain everything."&lt;/p&gt;

&lt;p&gt;"It would explain a great deal, yes." She looked at him. "When you have a hypothesis, share it. Not because Claude Code needs your permission to think — but because your hypothesis is information. It tells the tool where to look first, which approaches are worth exploring, and which are likely dead ends. A shared hypothesis is not a constraint. It is a gift."&lt;/p&gt;

&lt;p&gt;Timothy looked at the revised prompt on his screen. "I gave it the gift."&lt;/p&gt;

&lt;p&gt;"You did." Margaret allowed herself a small smile. "And if your hypothesis is wrong, Claude Code will likely tell you why — which is also useful. You do not lose anything by sharing your thinking. You only gain."&lt;/p&gt;




&lt;h2&gt;
  
  
  Before He Sent It
&lt;/h2&gt;

&lt;p&gt;"One more thing," Margaret said, just as Timothy was about to hit enter. "Read it aloud."&lt;/p&gt;

&lt;p&gt;He looked up. "I beg your pardon?"&lt;/p&gt;

&lt;p&gt;"Read the prompt aloud. Before you send it."&lt;/p&gt;

&lt;p&gt;He did — slightly self-consciously, but thoroughly. Halfway through, he stopped.&lt;/p&gt;

&lt;p&gt;"I said &lt;em&gt;recently&lt;/em&gt; twice," he said.&lt;/p&gt;

&lt;p&gt;"You did."&lt;/p&gt;

&lt;p&gt;"And I never specified which table the results are written to."&lt;/p&gt;

&lt;p&gt;"No."&lt;/p&gt;

&lt;p&gt;He made both corrections without being asked. Margaret said nothing. She did not need to.&lt;/p&gt;

&lt;p&gt;When he sent it, the prompt was clean, precise, and complete. Claude Code's response came back detailed, specific, and directly useful — identifying the likely N+1 pattern, suggesting a batched lookup approach, and flagging two other areas worth investigating.&lt;/p&gt;

&lt;p&gt;Timothy read it with the focused expression of someone who understood what they were looking at.&lt;/p&gt;

&lt;p&gt;"It knew exactly where to look," he said quietly.&lt;/p&gt;

&lt;p&gt;"Because you told it exactly where to look," Margaret said. "That is the partnership. You bring the context and the thinking. It brings the breadth and the speed. Neither is sufficient alone."&lt;/p&gt;

&lt;p&gt;She picked up her tea.&lt;/p&gt;

&lt;p&gt;"The first prompt is not the beginning of the work, Timothy. It is the end of the thinking. Get the thinking right first, and everything that follows will be better for it."&lt;/p&gt;

&lt;p&gt;Outside, London was going about its afternoon. Inside the library, a developer had just learned something that would serve him for the rest of his career — not a trick, not a shortcut, but a discipline.&lt;/p&gt;

&lt;p&gt;The discipline of thinking clearly before asking.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Next episode: Margaret and Timothy explore what happens when Claude Code gets it wrong — confidently, convincingly, and completely. How to catch the errors that look like answers.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The Secret Life of Claude Code publishes on &lt;a href="https://www.tech-reader.blog" rel="noopener noreferrer"&gt;tech-reader.blog&lt;/a&gt; every other day.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If this series is useful to you, share it with a developer who needs to hear it.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Aaron Rose is a software engineer and technology writer at &lt;a href="https://www.tech-reader.blog" rel="noopener noreferrer"&gt;tech-reader.blog&lt;/a&gt;. For explainer videos and podcasts, check out &lt;a href="https://www.youtube.com/@tech-reader2007" rel="noopener noreferrer"&gt;Tech-Reader YouTube channel&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>claudecode</category>
      <category>codingwithai</category>
      <category>softwaredevelopment</category>
      <category>programming</category>
    </item>
    <item>
      <title>Happy Pi Day</title>
      <dc:creator>Aaron Rose</dc:creator>
      <pubDate>Fri, 06 Mar 2026 02:43:22 +0000</pubDate>
      <link>https://dev.to/aaron_rose_0787cc8b4775a0/happy-pi-day-20n0</link>
      <guid>https://dev.to/aaron_rose_0787cc8b4775a0/happy-pi-day-20n0</guid>
      <description>&lt;p&gt;&lt;em&gt;A Pi Day Celebration with Margaret and Timothy from The Secret Life of Pi&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  March 14th — 3.14159...
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Margaret is a senior software engineer. Timothy is her junior colleague. They work in a grand Victorian library in London — the kind of place where old mysteries and new discoveries share the same shelves. Today is the 14th of March. Margaret has been waiting for it.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Number on the Chalkboard
&lt;/h2&gt;

&lt;p&gt;Timothy arrived to find something unusual. Margaret had pulled a small chalkboard from the storage room — the kind with a wooden frame and a little groove for chalk dust — and propped it against the fireplace. On it, in her precise handwriting, was a single symbol.&lt;/p&gt;

&lt;p&gt;π&lt;/p&gt;

&lt;p&gt;"You've decorated," he said.&lt;/p&gt;

&lt;p&gt;"I have marked the occasion," she said, pouring tea without looking up. "Sit down, Timothy. Today we are not talking about code."&lt;/p&gt;

&lt;p&gt;He sat. "What are we talking about?"&lt;/p&gt;

&lt;p&gt;She set a cup in front of him and looked at the chalkboard with something that could only be described as fondness.&lt;/p&gt;

&lt;p&gt;"The most remarkable number in the universe," she said.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Pi Actually Is
&lt;/h2&gt;

&lt;p&gt;"I know what pi is," Timothy said, a little defensively. "Three point one four one five nine. Circles. Circumference divided by diameter."&lt;/p&gt;

&lt;p&gt;"You know what pi &lt;em&gt;does&lt;/em&gt;," Margaret said. "That is not the same as knowing what it &lt;em&gt;is&lt;/em&gt;."&lt;/p&gt;

&lt;p&gt;He opened his mouth and closed it again.&lt;/p&gt;

&lt;p&gt;"Pi is the ratio of a circle's circumference to its diameter," she continued. "Every circle that has ever existed, from a ripple in a pond to the orbit of a planet, obeys this ratio exactly. You cannot draw a circle — in sand, in code, in the fabric of space — without pi being present. It was there before we discovered it. It will be there long after we are gone."&lt;/p&gt;

&lt;p&gt;Timothy looked at the symbol on the chalkboard with fresh eyes. "It's a constant."&lt;/p&gt;

&lt;p&gt;"It is &lt;em&gt;the&lt;/em&gt; constant. Or one of them." She settled back. "But here is where it gets interesting. Pi is not a tidy number. It is not three. It is not three and a bit. It is 3.14159265358979... and it continues forever, without repetition, without pattern, without end."&lt;/p&gt;

&lt;p&gt;"Forever," Timothy repeated. "How do we know?"&lt;/p&gt;

&lt;p&gt;"Because mathematicians have proven it. Pi is what we call &lt;em&gt;irrational&lt;/em&gt; — it cannot be expressed as a simple fraction. And it is &lt;em&gt;transcendental&lt;/em&gt; — it cannot be the solution to any ordinary algebraic equation. It exists outside the neat categories we try to impose on numbers. It simply &lt;em&gt;is&lt;/em&gt;."&lt;/p&gt;




&lt;h2&gt;
  
  
  The Long Hunt
&lt;/h2&gt;

&lt;p&gt;Timothy wrapped his hands around his teacup. "How long have we known about pi?"&lt;/p&gt;

&lt;p&gt;Margaret smiled. This was her favourite part.&lt;/p&gt;

&lt;p&gt;"Babylonian mathematicians were using approximations of pi nearly four thousand years ago. The ancient Egyptians got remarkably close. Archimedes, working in Syracuse around 250 BCE, was the first to calculate it rigorously — he drew polygons inside and outside a circle, with more and more sides, and squeezed pi between them like a vice until he had it to two decimal places." She paused. "He did this by hand. With geometry. No calculator. No computer. Just a brilliant mind and an obsession with precision."&lt;/p&gt;

&lt;p&gt;"Two decimal places by hand," Timothy said quietly. "That's extraordinary."&lt;/p&gt;

&lt;p&gt;"It gets better. In the fifth century, a Chinese mathematician named Zu Chongzhi calculated pi to seven decimal places — a record that stood for nearly a thousand years. Seven decimal places. By hand." She shook her head slowly, not in disbelief but in admiration. "These were people who understood that precision mattered. That the universe deserved to be measured carefully."&lt;/p&gt;




&lt;h2&gt;
  
  
  Why It Shows Up Everywhere
&lt;/h2&gt;

&lt;p&gt;"Here's what I've never understood," Timothy said, leaning forward. "Why does pi appear everywhere? Not just in circles. I've seen it in physics, in probability, in statistics. It turns up in the most unexpected places."&lt;/p&gt;

&lt;p&gt;"Ah," Margaret said, and her eyes lit up. "Now you are asking the right question."&lt;/p&gt;

&lt;p&gt;She stood and went to the window, looking out at the London street below — the curve of the road, the arc of a gas lamp, the circular face of a clock tower in the distance.&lt;/p&gt;

&lt;p&gt;"Pi is not merely about circles. Pi is about the deep structure of curves, waves, and cycles. Wherever something in nature oscillates — a pendulum, a sound wave, a light wave, the orbit of a moon — pi is embedded in the mathematics that describes it." She turned back to face him. "When you calculate the probability of certain random events, pi appears. When you analyse the distribution of prime numbers, pi appears. It is as if the universe has a favourite number and keeps writing it into everything."&lt;/p&gt;

&lt;p&gt;"That's almost unsettling," Timothy said.&lt;/p&gt;

&lt;p&gt;"It is &lt;em&gt;beautiful&lt;/em&gt;," Margaret corrected gently. "It suggests that reality has an underlying coherence — that the same mathematical truths appear across wildly different phenomena because they share a common deep structure. Pi is one of the threads that runs through everything."&lt;/p&gt;




&lt;h2&gt;
  
  
  The Infinite Decimal
&lt;/h2&gt;

&lt;p&gt;Timothy stared into his tea for a moment. "The fact that it never ends and never repeats. Does that bother you?"&lt;/p&gt;

&lt;p&gt;Margaret considered this seriously, the way she considered everything.&lt;/p&gt;

&lt;p&gt;"It used to," she said. "When I was young, I wanted mathematics to be tidy. Finite. Resolved. Pi offended my sense of order." She smiled at the memory. "Then I came to understand that the infinite decimal is not a flaw. It is a feature. It means that no finite description can fully capture pi. It always has more to say. There is always another digit, another layer of precision available to anyone willing to look for it."&lt;/p&gt;

&lt;p&gt;"How many digits have we calculated?"&lt;/p&gt;

&lt;p&gt;"As of recent years, over one hundred trillion digits." She let that settle. "One hundred trillion. Supercomputers running for months. And pi has not repeated. It has not resolved into a pattern. It simply continues, indifferent to our curiosity, offering up new digits one at a time like a book that never ends."&lt;/p&gt;

&lt;p&gt;Timothy was quiet for a long moment.&lt;/p&gt;

&lt;p&gt;"And we celebrate this," he said finally, "on March fourteenth."&lt;/p&gt;

&lt;p&gt;"Three, fourteen," Margaret said. "3.14. The mathematician William Jones first used the Greek letter π to represent it in 1706. The physicist Larry Shaw organised the first proper Pi Day celebration in 1988 at the San Francisco Exploratorium." She glanced at the chalkboard. "It has been a tradition worth keeping ever since."&lt;/p&gt;




&lt;h2&gt;
  
  
  What Pi Teaches Us
&lt;/h2&gt;

&lt;p&gt;"Can I ask something that might sound strange?" Timothy said.&lt;/p&gt;

&lt;p&gt;"Those are usually the best questions."&lt;/p&gt;

&lt;p&gt;"What does pi actually &lt;em&gt;teach&lt;/em&gt; us? As developers, as engineers, as people?"&lt;/p&gt;

&lt;p&gt;Margaret thought about this for longer than usual. Outside, a light rain had begun to fall, and the sound of it against the library windows was the only sound in the room.&lt;/p&gt;

&lt;p&gt;"Pi teaches us that some things are inexhaustible," she said finally. "That precision has no ceiling — you can always know more, measure more carefully, compute more digits. It teaches us that beauty and utility are not opposites — pi is both achingly beautiful and relentlessly practical. It turns up in the code we write, the signals we process, the graphics we render."&lt;/p&gt;

&lt;p&gt;She looked at the symbol on the chalkboard one more time.&lt;/p&gt;

&lt;p&gt;"And perhaps most importantly — pi teaches us humility. Here is a number that humanity has pursued for four thousand years with everything we have. Our sharpest minds. Our fastest machines. And it remains infinite, irrational, transcendental, and inexhaustible." She picked up her tea. "Some things are larger than our ability to contain them. That is not a reason for despair. It is a reason for wonder."&lt;/p&gt;

&lt;p&gt;Timothy looked at the chalkboard for a long time.&lt;/p&gt;

&lt;p&gt;"Happy Pi Day, Margaret," he said quietly.&lt;/p&gt;

&lt;p&gt;She raised her cup.&lt;/p&gt;

&lt;p&gt;"Happy Pi Day, Timothy."&lt;/p&gt;

&lt;p&gt;Outside, London went about its day, quite unaware that in one particular library, two developers had spent the morning with the most beautiful number in the universe — and were both, in their own ways, the better for it.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;π = 3.14159265358979323846264338327950288...&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;...and counting. Always counting.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;From the Victorian library, with wonder. Happy Pi Day — March 14th.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Aaron Rose is a software engineer and technology writer at &lt;a href="https://www.tech-reader.blog" rel="noopener noreferrer"&gt;tech-reader.blog&lt;/a&gt;. For explainer videos and podcasts, check out &lt;a href="https://www.youtube.com/@tech-reader2007" rel="noopener noreferrer"&gt;Tech-Reader YouTube channel&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>pi</category>
      <category>math</category>
      <category>numbers</category>
      <category>stem</category>
    </item>
  </channel>
</rss>
