<?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: Edgar Nahama Alochi</title>
    <description>The latest articles on DEV Community by Edgar Nahama Alochi (@nahamaalochi).</description>
    <link>https://dev.to/nahamaalochi</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4017885%2F79abbb49-c4c8-4a4c-96ca-82feca0d1ffd.jpg</url>
      <title>DEV Community: Edgar Nahama Alochi</title>
      <link>https://dev.to/nahamaalochi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nahamaalochi"/>
    <language>en</language>
    <item>
      <title>NASA's Rule of 10: The rules of programing that put flying metal in orbit</title>
      <dc:creator>Edgar Nahama Alochi</dc:creator>
      <pubDate>Sun, 26 Jul 2026 14:00:28 +0000</pubDate>
      <link>https://dev.to/nahamaalochi/nasas-rule-of-10-the-rules-of-programing-that-put-flying-metal-in-orbit-34lb</link>
      <guid>https://dev.to/nahamaalochi/nasas-rule-of-10-the-rules-of-programing-that-put-flying-metal-in-orbit-34lb</guid>
      <description>&lt;h2&gt;
  
  
  The NASA Ten Rules of Programming
&lt;/h2&gt;

&lt;p&gt;My interpretation of these rules with &lt;strong&gt;Golang&lt;/strong&gt; examples.&lt;/p&gt;

&lt;p&gt;NASA did not write these rules to win arguments on the internet.&lt;br&gt;
They wrote them because software failed in ways that were expensive frightening and sometimes irreversible.&lt;/p&gt;

&lt;p&gt;The rules are short. Almost annoyingly so.&lt;br&gt;
That is intentional.&lt;/p&gt;

&lt;p&gt;Each rule is a reminder that complexity is not free and that computers are fast but humans are fragile.&lt;/p&gt;

&lt;p&gt;They helped put flying metals in orbit and manage Voyager 1, the most distant human made object.&lt;/p&gt;

&lt;p&gt;Let’s walk through all ten using Go not because Go is perfect but because it makes these ideas painfully obvious.&lt;/p&gt;

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


&lt;h3&gt;
  
  
  Rule 1
&lt;/h3&gt;

&lt;p&gt;Restrict all code to very simple control flow&lt;/p&gt;

&lt;p&gt;If your logic requires a mental stack trace to understand it will fail at the worst possible moment.&lt;/p&gt;

&lt;p&gt;Go helps here by being boring on purpose.&lt;/p&gt;

&lt;p&gt;Bad&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;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;int&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;x&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;100&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;x&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="m"&gt;0&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;x&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="m"&gt;7&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;break&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="n"&gt;x&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Good&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;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;int&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;x&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="m"&gt;0&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;x&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;100&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;x&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="m"&gt;0&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;x&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nextValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&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;x&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;nextValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;int&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;x&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="m"&gt;0&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;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="m"&gt;7&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;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Simple flow is not about fewer lines.&lt;br&gt;
It is about fewer thoughts.&lt;/p&gt;


&lt;h3&gt;
  
  
  Rule 2
&lt;/h3&gt;

&lt;p&gt;Give all loops a fixed upper bound&lt;/p&gt;

&lt;p&gt;Unbounded loops are promises you cannot keep.&lt;/p&gt;

&lt;p&gt;They say trust me this will eventually stop.&lt;br&gt;
NASA does not trust that. Neither should you.&lt;/p&gt;

&lt;p&gt;Bad&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;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;read&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;data&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="k"&gt;break&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&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;Better&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;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;maxReads&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;read&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;data&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="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&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;Even when reading streams you can still impose limits.&lt;br&gt;
Timeouts retries counters budgets.&lt;/p&gt;

&lt;p&gt;Infinite loops belong in theory not production.&lt;/p&gt;


&lt;h3&gt;
  
  
  Rule 3
&lt;/h3&gt;

&lt;p&gt;Avoid heap memory allocation after initialization&lt;/p&gt;

&lt;p&gt;This rule scares people because it sounds extreme.&lt;/p&gt;

&lt;p&gt;What it really says is do not allocate memory unpredictably while running critical logic.&lt;/p&gt;

&lt;p&gt;In Go you do not control the heap but you can control when and how you allocate.&lt;/p&gt;

&lt;p&gt;Bad&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;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;buf&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf&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;Better&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;type&lt;/span&gt; &lt;span class="n"&gt;Handler&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;buf&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;NewHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;maxSize&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Handler&lt;/span&gt; &lt;span class="p"&gt;{&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;Handler&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;maxSize&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;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Handler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Size&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;This is not about micro optimization.&lt;br&gt;
It is about predictability.&lt;/p&gt;

&lt;p&gt;The garbage collector is helpful.&lt;br&gt;
It is not magic.&lt;/p&gt;


&lt;h3&gt;
  
  
  Rule 4
&lt;/h3&gt;

&lt;p&gt;Restrict functions to a single purpose&lt;/p&gt;

&lt;p&gt;If a function does more than one thing it lies about its name.&lt;/p&gt;

&lt;p&gt;Bad&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;SaveUser&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="n"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&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;Save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"saved user %s"&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;ID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;sendEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&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;p&gt;Better&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;SaveUser&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="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&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="no"&gt;nil&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;err&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;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&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;Side effects should be explicit and separate.&lt;/p&gt;

&lt;p&gt;Small functions fail smaller.&lt;/p&gt;




&lt;h3&gt;
  
  
  Rule 5
&lt;/h3&gt;

&lt;p&gt;Use a minimum of two runtime assertions per function&lt;/p&gt;

&lt;p&gt;This rule is about defending assumptions.&lt;/p&gt;

&lt;p&gt;In Go assertions usually look like early checks.&lt;/p&gt;

&lt;p&gt;Bad&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;divide&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;int&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;a&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Better&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;divide&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;b&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="kt"&gt;int&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="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="m"&gt;0&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;"division by zero"&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;a&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;b&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;Assertions are kindness to future readers.&lt;br&gt;
Especially future you at 2am.&lt;/p&gt;


&lt;h3&gt;
  
  
  Rule 6
&lt;/h3&gt;

&lt;p&gt;Declare data objects at the smallest possible scope&lt;/p&gt;

&lt;p&gt;The longer a variable lives the more places it can hurt you.&lt;/p&gt;

&lt;p&gt;Bad&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;var&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;compute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Better&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;compute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Short lifetimes mean fewer ghosts in the system.&lt;/p&gt;




&lt;h3&gt;
  
  
  Rule 7
&lt;/h3&gt;

&lt;p&gt;Check the return value of all non void functions&lt;/p&gt;

&lt;p&gt;This is the rule Go takes personally.&lt;/p&gt;

&lt;p&gt;Ignoring errors is lying to yourself.&lt;/p&gt;

&lt;p&gt;Bad&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;file&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"data.txt"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Better&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;file&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;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"data.txt"&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="k"&gt;return&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;Errors are information.&lt;br&gt;
Discarding them does not make them go away.&lt;/p&gt;


&lt;h3&gt;
  
  
  Rule 8
&lt;/h3&gt;

&lt;p&gt;Limit pointer use&lt;/p&gt;

&lt;p&gt;Pointers increase the number of possible states your program can be in.&lt;/p&gt;

&lt;p&gt;Go uses pointers but discourages pointer gymnastics.&lt;/p&gt;

&lt;p&gt;Bad&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;update&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;User&lt;/span&gt;&lt;span class="p"&gt;)&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;Name&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;ToUpper&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;Name&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;Better&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;update&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="n"&gt;User&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;Name&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;ToUpper&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;Name&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;u&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use pointers when you must not because you can.&lt;/p&gt;




&lt;h3&gt;
  
  
  Rule 9
&lt;/h3&gt;

&lt;p&gt;Compile with all warnings enabled and treat them as errors&lt;/p&gt;

&lt;p&gt;Go does not have warnings.&lt;br&gt;
It simply refuses to compile nonsense.&lt;/p&gt;

&lt;p&gt;Unused variables unused imports unreachable code.&lt;br&gt;
All dead on arrival.&lt;/p&gt;

&lt;p&gt;That is a feature not a limitation.&lt;/p&gt;

&lt;p&gt;If your language allows warnings treat them like failures.&lt;br&gt;
Your future stability depends on it.&lt;/p&gt;


&lt;h3&gt;
  
  
  Rule 10
&lt;/h3&gt;

&lt;p&gt;Use static analysis tools&lt;/p&gt;

&lt;p&gt;Humans miss patterns.&lt;br&gt;
Machines do not get tired.&lt;/p&gt;

&lt;p&gt;In Go this means tools like&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;go vet&lt;/li&gt;
&lt;li&gt;staticcheck&lt;/li&gt;
&lt;li&gt;race detector&lt;/li&gt;
&lt;/ul&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;-race&lt;/span&gt; ./...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These tools are not optional extras.&lt;br&gt;
They are part of the engineering system.&lt;/p&gt;

&lt;p&gt;NASA trusted them with spacecraft.&lt;br&gt;
You can trust them with your backend.&lt;/p&gt;




&lt;h2&gt;
  
  
  The quiet lesson behind the rules
&lt;/h2&gt;

&lt;p&gt;The NASA rules are not about cleverness.&lt;br&gt;
They are about humility.&lt;/p&gt;

&lt;p&gt;They assume that you will forget.&lt;br&gt;
That you will misread.&lt;br&gt;
That you will be interrupted.&lt;/p&gt;

&lt;p&gt;They are written for humans under pressure.&lt;/p&gt;

&lt;p&gt;Go as a language aligns with this philosophy almost accidentally.&lt;br&gt;
Simple syntax explicit errors limited abstraction boring defaults.&lt;/p&gt;

&lt;p&gt;The rules remind us that reliability is not achieved by brilliance.&lt;br&gt;
It is achieved by restraint.&lt;/p&gt;

&lt;p&gt;And restraint scales better than genius ever will.&lt;/p&gt;

</description>
      <category>bestpractices</category>
      <category>go</category>
      <category>webdev</category>
      <category>productivity</category>
    </item>
    <item>
      <title>A Small, Annoying Reminder About MySQL, Next.js, and Reality</title>
      <dc:creator>Edgar Nahama Alochi</dc:creator>
      <pubDate>Sat, 25 Jul 2026 20:01:24 +0000</pubDate>
      <link>https://dev.to/nahamaalochi/a-small-annoying-reminder-about-mysql-nextjs-and-reality-2aln</link>
      <guid>https://dev.to/nahamaalochi/a-small-annoying-reminder-about-mysql-nextjs-and-reality-2aln</guid>
      <description>&lt;p&gt;Today's reminder that MySQL will happily let you believe you're doing everything "right" right up until it doesn't.&lt;/p&gt;

&lt;p&gt;I was wiring up a perfectly ordinary paginated query in a Next.js service. Nothing exotic. Prepared statements, placeholders, clean parameter handling. The kind of code you write on autopilot because you've written it a hundred times before.&lt;/p&gt;

&lt;p&gt;And then MySQL reminded me again that it is not PostgreSQL.&lt;/p&gt;

&lt;p&gt;The offending query looked harmless:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;writings&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;created_at&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;
&lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="k"&gt;OFFSET&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The parameters were validated. Integers only. Floored. Bounded. Safe. Sensible.&lt;/p&gt;

&lt;p&gt;And still: runtime error.&lt;/p&gt;

&lt;p&gt;The cause, as always, is not obvious until you already know it:&lt;/p&gt;

&lt;p&gt;MySQL does not support placeholders for&lt;code&gt;LIMIT&lt;/code&gt; and &lt;code&gt;OFFSET&lt;/code&gt; in prepared statements.&lt;/p&gt;

&lt;p&gt;Not partially. Not "sometimes." Just no.&lt;/p&gt;

&lt;p&gt;This is one of those behaviors that lives in the uncanny valley between "documented" and "constantly forgotten." Every time I switch contexts PostgreSQL to MySQL, ORM generated queries to raw SQL I relearn this the hard way.&lt;/p&gt;

&lt;p&gt;The fix is simple, but mildly infuriating.&lt;/p&gt;

&lt;p&gt;Instead of placeholders, you must interpolate the integers directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;limitInt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;limitNum&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;offsetInt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;offset&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;dataQuery&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
  SELECT *
  FROM writings
  &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;whereClause&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;
  ORDER BY created_at DESC
  LIMIT &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;limitInt&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; OFFSET &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;offsetInt&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;
`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And yes, this is safe because:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;limitNum&lt;/code&gt; and&lt;code&gt;offset&lt;/code&gt;are validated&lt;br&gt;
Values are clamped and floored&lt;br&gt;
They cannot contain user controlled strings&lt;br&gt;
Only &lt;code&gt;WHERE&lt;/code&gt; clause values remain parameterized&lt;/p&gt;

&lt;p&gt;The resulting query is exactly what MySQL expects:&lt;/p&gt;

&lt;p&gt;text&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;writings&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;created_at&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;
&lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt; &lt;span class="k"&gt;OFFSET&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of the version MySQL silently refuses to support:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;writings&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;created_at&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;
&lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="k"&gt;OFFSET&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is not a Next.js problem.&lt;br&gt;
It is not a driver bug.&lt;br&gt;
It is not a configuration issue.&lt;/p&gt;

&lt;p&gt;It is simply one of those MySQL constraints that leaks through abstraction layers and reminds you that SQL dialects are not interchangeable, no matter how much tooling tries to pretend they are.&lt;/p&gt;

&lt;p&gt;The frustrating part isn't the workaround.&lt;br&gt;
The frustrating part is that this failure happens after you've already done the "right" things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Prepared statements&lt;/li&gt;
&lt;li&gt;Parameterized queries&lt;/li&gt;
&lt;li&gt;Defensive validation&lt;/li&gt;
&lt;li&gt;Boring, careful code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And yet, you still have to break the pattern carefully, deliberately to satisfy the database.&lt;/p&gt;

&lt;p&gt;The takeaway is not "don't use MySQL."&lt;br&gt;
The takeaway is simpler, and more annoying:&lt;/p&gt;

&lt;p&gt;Always remember which database you are talking to.&lt;/p&gt;

&lt;p&gt;Because the moment you assume uniform behavior across SQL engines, reality will correct you usually in production.&lt;/p&gt;

&lt;p&gt;Fixed.&lt;br&gt;
Again.&lt;/p&gt;

</description>
      <category>database</category>
      <category>sql</category>
      <category>typescript</category>
      <category>nextjs</category>
    </item>
    <item>
      <title>Understanding Next.js Page Caching (with a real example)</title>
      <dc:creator>Edgar Nahama Alochi</dc:creator>
      <pubDate>Wed, 22 Jul 2026 23:12:10 +0000</pubDate>
      <link>https://dev.to/nahamaalochi/understanding-nextjs-page-caching-with-a-real-example-10io</link>
      <guid>https://dev.to/nahamaalochi/understanding-nextjs-page-caching-with-a-real-example-10io</guid>
      <description>&lt;p&gt;Caching can be a tricky topic, especially when pages don’t update the way you expect.&lt;br&gt;
I recently ran into an interesting issue while working on the &lt;strong&gt;/writing&lt;/strong&gt; page of my site. Whenever I added or updated articles, the changes did not show immediately. Oddly enough, the individual article pages updated as expected, but the listing page stayed stale.&lt;/p&gt;

&lt;p&gt;After some digging, I realized this was not a bug. It was &lt;strong&gt;Next.js doing exactly what it is supposed to&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  How Next.js caching works
&lt;/h3&gt;

&lt;p&gt;Next.js (App Router) handles &lt;strong&gt;HTML caching at the edge&lt;/strong&gt; in production. For statically prerendered pages, it sets &lt;code&gt;Cache-Control: s-maxage=31536000&lt;/code&gt;, which is one year. This header tells &lt;strong&gt;CDNs and edge caches&lt;/strong&gt; that they can serve the page without re-fetching for a long time. Browser cache headers such as &lt;code&gt;no-cache&lt;/code&gt; do not override this because &lt;code&gt;s-maxage&lt;/code&gt; takes priority for shared caches.&lt;/p&gt;

&lt;p&gt;This explains why the listing page showed stale content while individual article pages, which are either dynamic or use revalidation, updated immediately.&lt;/p&gt;
&lt;h3&gt;
  
  
  How to control caching
&lt;/h3&gt;

&lt;p&gt;Next.js provides a clean way to manage page freshness.&lt;/p&gt;

&lt;p&gt;First, set revalidation for a page. In the page file, for example &lt;code&gt;app/writing/page.tsx&lt;/code&gt;, add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;revalidate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// seconds&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The page is served from cache for 60 seconds. After 60 seconds, the next visitor triggers &lt;strong&gt;background regeneration&lt;/strong&gt;. Visitors continue to get a fast response while the page updates.&lt;/p&gt;

&lt;p&gt;For instant updates after saving content, use on-demand revalidation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;revalidatePath&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/cache&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nf"&gt;revalidatePath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/writing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Call this in your article save logic, whether that is a CMS, API route, or webhook, to invalidate the cached page immediately.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key lessons from my experience
&lt;/h3&gt;

&lt;p&gt;Edge caching is powerful, but it can make pages seem stale if revalidation is not configured. Browser cache clearing or changing Nginx headers does not affect HTML caching for statically prerendered pages. The correct place to control page freshness is in the Next.js route itself, not the server or CDN alone.&lt;/p&gt;

&lt;p&gt;By adding a single line of code to the route, I now get the perfect balance: fast cached pages that still update reliably when I add or edit content.&lt;/p&gt;

&lt;h3&gt;
  
  
  References
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://nextjs.org/docs/app/guides/self-hosting" rel="noopener noreferrer"&gt;Next.js ISR and Self-hosting&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://nextjs.org/docs/app/getting-started/caching-and-revalidating" rel="noopener noreferrer"&gt;Next.js Caching and Revalidation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://nextjs.org/docs/pages/api-reference/config-next-config-js/headers" rel="noopener noreferrer"&gt;Next.js Config and Headers&lt;/a&gt;&lt;/p&gt;

</description>
      <category>note</category>
      <category>caching</category>
      <category>frontend</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Making Next.js Behave: Practical Notes on Performance, Architecture, and Not Shooting Yourself</title>
      <dc:creator>Edgar Nahama Alochi</dc:creator>
      <pubDate>Wed, 22 Jul 2026 06:33:08 +0000</pubDate>
      <link>https://dev.to/nahamaalochi/making-nextjs-behave-practical-notes-on-performance-architecture-and-not-shooting-yourself-5h3k</link>
      <guid>https://dev.to/nahamaalochi/making-nextjs-behave-practical-notes-on-performance-architecture-and-not-shooting-yourself-5h3k</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4f17rivfuzw6gzdcbf9d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4f17rivfuzw6gzdcbf9d.png" alt=" " width="598" height="262"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next.js is fast by default.&lt;br&gt;
It is also very easy to make slow by accident.&lt;/p&gt;

&lt;p&gt;Most performance problems I see in Next apps are not about React being slow or Vercel being expensive. They come from unclear boundaries, duplicated work, and letting “temporary” decisions live forever.&lt;/p&gt;

&lt;p&gt;These are notes on how to keep a Next.js codebase fast to build, predictable to run, and pleasant to work in.&lt;/p&gt;
&lt;h4&gt;
  
  
  Start by making the codebase legible
&lt;/h4&gt;

&lt;p&gt;Before touching performance tools, make the project understandable.&lt;/p&gt;

&lt;p&gt;If a new developer cannot tell where hooks live, where API logic lives, or where page copy lives within a few minutes, you will pay for that confusion forever.&lt;/p&gt;

&lt;p&gt;A boring structure wins.&lt;/p&gt;

&lt;p&gt;Keep one place for hooks.&lt;br&gt;
One place for shared UI components.&lt;br&gt;
One place for content and metadata.&lt;br&gt;
Thin pages that mostly wire things together.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
  &lt;span class="nx"&gt;dashboard&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
  &lt;span class="nx"&gt;solutions&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
  &lt;span class="nx"&gt;foo&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
  &lt;span class="nx"&gt;bar&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="nx"&gt;components&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="nx"&gt;hooks&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="nx"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This does not make the app faster at runtime. It makes humans faster. That compounds.&lt;/p&gt;

&lt;h4&gt;
  
  
  DRY is about removing decisions, not saving lines
&lt;/h4&gt;

&lt;p&gt;Duplicated logic forces the reader to make choices.&lt;/p&gt;

&lt;p&gt;Which metadata file is correct.&lt;br&gt;
Which SEO description was updated.&lt;br&gt;
Which API client variation should I use.&lt;/p&gt;

&lt;p&gt;Centralize anything that changes together.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;buildMetadata&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MetadataInput&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;Metadata&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;openGraph&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;twitter&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When every page uses the same builder, you stop worrying about consistency. You trust the system again.&lt;/p&gt;

&lt;p&gt;Trust is performance.&lt;/p&gt;

&lt;h4&gt;
  
  
  Prefer server components until proven otherwise
&lt;/h4&gt;

&lt;p&gt;Client components are easy. They are also expensive.&lt;/p&gt;

&lt;p&gt;Every client component ships JavaScript, runs hydration, and increases build and bundle cost. Use them only when you actually need interactivity.&lt;/p&gt;

&lt;p&gt;If a component does not use state, effects, or browser APIs, keep it on the server.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Page&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;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getData&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;View&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No use client. No hydration. Less work.&lt;/p&gt;

&lt;p&gt;You can always move logic client side later. Moving it back is harder.&lt;/p&gt;

&lt;h4&gt;
  
  
  Cache aggressively, but intentionally
&lt;/h4&gt;

&lt;p&gt;Next gives you caching for free, but only if you let it.&lt;/p&gt;

&lt;p&gt;Use fetch with caching semantics instead of rolling your own.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;next&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;revalidate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;60&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;Avoid wrapping everything in dynamic just because something broke once. That turns your app into an expensive SPA with extra steps.&lt;/p&gt;

&lt;p&gt;If something must be dynamic, isolate it. Do not poison the whole page.&lt;/p&gt;

&lt;h4&gt;
  
  
  Keep API clients dumb
&lt;/h4&gt;

&lt;p&gt;Your API client should not know about routing, auth state, or UI behavior. It should send requests and return data.&lt;/p&gt;

&lt;p&gt;Once we added a server proxy, the client became simpler instead of more complex.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/backend/payments&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="na"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;include&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No tokens.&lt;br&gt;
No headers.&lt;br&gt;
No branching logic.&lt;/p&gt;

&lt;p&gt;The server handles auth. The client just asks for data.&lt;/p&gt;

&lt;p&gt;This improves security and reduces mental load.&lt;/p&gt;
&lt;h4&gt;
  
  
  Never store tokens in localStorage
&lt;/h4&gt;

&lt;p&gt;It is convenient.&lt;br&gt;
It is also unsafe.&lt;/p&gt;

&lt;p&gt;LocalStorage is readable by any injected script. There is no mitigation once it is compromised.&lt;/p&gt;

&lt;p&gt;If you care about security, use httpOnly cookies and move auth to the server.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;cookies&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;access_token&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;httpOnly&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;span class="na"&gt;secure&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;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Yes, it requires more setup. Yes, it is worth it.&lt;/p&gt;

&lt;h4&gt;
  
  
  Reduce build work by deleting code
&lt;/h4&gt;

&lt;p&gt;Most build optimizations come from removing work, not adding tools.&lt;/p&gt;

&lt;p&gt;Things that slow builds quietly:&lt;br&gt;
Duplicated imports&lt;br&gt;
Large client components&lt;br&gt;
Overused dynamic rendering&lt;br&gt;
Unused dependencies&lt;br&gt;
Copy pasted config&lt;/p&gt;

&lt;p&gt;Before reaching for caching layers, ask what the compiler is doing repeatedly that it should not be doing at all.&lt;/p&gt;
&lt;h4&gt;
  
  
  Treat DX issues as real bugs
&lt;/h4&gt;

&lt;p&gt;If a fresh clone does not boot cleanly, that is a bug.&lt;br&gt;
If formatting changes every commit, that is a bug.&lt;br&gt;
If Node versions drift, that is a bug.&lt;/p&gt;

&lt;p&gt;Pin your environment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# .nvmrc
20
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Commit generated files that tools expect.&lt;br&gt;
Pick one package manager.&lt;br&gt;
Make the happy path obvious.&lt;/p&gt;

&lt;p&gt;The goal is that nothing surprising happens on day one.&lt;/p&gt;

&lt;h4&gt;
  
  
  Make failures explicit
&lt;/h4&gt;

&lt;p&gt;If the backend is down, fail clearly.&lt;br&gt;
If an image format is unsafe, opt into it intentionally.&lt;br&gt;
If something is deprecated, address it early.&lt;/p&gt;

&lt;p&gt;Silent failures turn into folklore. Loud failures turn into fixes.&lt;/p&gt;

&lt;h4&gt;
  
  
  The real optimization
&lt;/h4&gt;

&lt;p&gt;A fast Next.js app is not one with the most tricks.&lt;br&gt;
It is one that does the least unnecessary work.&lt;br&gt;
For the browser.&lt;br&gt;
For the server.&lt;br&gt;
For the developer.&lt;/p&gt;

&lt;p&gt;When the structure is clear, the build gets faster.&lt;br&gt;
When the security model is clean, the code gets simpler.&lt;br&gt;
When the project explains itself, people stop being afraid to change it.&lt;/p&gt;

&lt;p&gt;That is when Next.js starts to feel boring again.&lt;/p&gt;

&lt;p&gt;And boring is exactly what you want.&lt;/p&gt;

</description>
      <category>note</category>
      <category>caching</category>
      <category>frontend</category>
      <category>mistakes</category>
    </item>
    <item>
      <title>Open Source in the Age of AI: When Slop Floods the Swamp</title>
      <dc:creator>Edgar Nahama Alochi</dc:creator>
      <pubDate>Tue, 21 Jul 2026 09:21:04 +0000</pubDate>
      <link>https://dev.to/nahamaalochi/open-source-in-the-age-of-ai-when-slop-floods-the-swamp-3dp3</link>
      <guid>https://dev.to/nahamaalochi/open-source-in-the-age-of-ai-when-slop-floods-the-swamp-3dp3</guid>
      <description>&lt;p&gt;I like open source for the same reason I like well designed systems.&lt;br&gt;
Clear inputs. Honest outputs. Humans in the loop.&lt;/p&gt;

&lt;p&gt;Lately that loop feels clogged.&lt;/p&gt;

&lt;p&gt;Over the last few weeks something strange has happened. Pull requests multiplied. Bug reports exploded. Security issues appeared out of thin air. Everything looked serious. Everything looked formatted. Everything looked wrong.&lt;/p&gt;

&lt;p&gt;This is not enthusiasm.&lt;br&gt;
This is industrial scale contribution theater.&lt;/p&gt;

&lt;p&gt;We taught machines to talk. Some people decided that talking counts as contributing.&lt;/p&gt;

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




&lt;h2&gt;
  
  
  The Inbox as a Crime Scene
&lt;/h2&gt;

&lt;p&gt;If you maintain a project today your inbox looks like a crime scene.&lt;/p&gt;

&lt;p&gt;There are fingerprints everywhere. None of them match reality.&lt;/p&gt;

&lt;p&gt;You open a pull request. It compiles on paper. It fails in practice.&lt;br&gt;
You read a security report. It references functions that do not exist.&lt;br&gt;
You scan the explanation. Confident tone. Wrong universe.&lt;/p&gt;

&lt;p&gt;The tragedy is not that the code is bad. Bad code has always existed.&lt;br&gt;
The tragedy is volume.&lt;/p&gt;

&lt;p&gt;One thoughtful contribution costs minutes to review.&lt;br&gt;
One careless AI generated contribution costs context. Attention. Energy.&lt;/p&gt;

&lt;p&gt;Multiply that by a hundred. By a thousand.&lt;/p&gt;

&lt;p&gt;This is not collaboration. This is a denial of service attack on human judgment.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Slop Factory Model
&lt;/h2&gt;

&lt;p&gt;Here is the new workflow.&lt;/p&gt;

&lt;p&gt;Prompt the model&lt;br&gt;
Generate something plausible&lt;br&gt;
Submit it everywhere&lt;br&gt;
Hope something sticks&lt;/p&gt;

&lt;p&gt;No understanding required. No ownership. No follow up.&lt;/p&gt;

&lt;p&gt;It is the software equivalent of throwing spaghetti at a wall and calling yourself a chef.&lt;/p&gt;

&lt;p&gt;The machine does not care.&lt;br&gt;
The submitter often does not either.&lt;br&gt;
The maintainer pays the bill.&lt;/p&gt;

&lt;p&gt;Open source was built on learning in public.&lt;br&gt;
This is guessing in bulk.&lt;/p&gt;




&lt;h2&gt;
  
  
  When Everything Looks Like Work
&lt;/h2&gt;

&lt;p&gt;AI slop is dangerous because it looks like effort.&lt;/p&gt;

&lt;p&gt;There are tests. There are comments. There are long explanations written in a polite tone.&lt;br&gt;
There is just one missing ingredient.&lt;/p&gt;

&lt;p&gt;Reality.&lt;/p&gt;

&lt;p&gt;The model does not know your codebase.&lt;br&gt;
It does not know your constraints.&lt;br&gt;
It does not know why that weird edge case exists.&lt;/p&gt;

&lt;p&gt;It only knows how code usually looks.&lt;br&gt;
And that is not enough.&lt;/p&gt;

&lt;p&gt;A map of a city is not the city.&lt;br&gt;
Generated code is not understanding.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Maintainer as the Bottleneck
&lt;/h2&gt;

&lt;p&gt;Here is the uncomfortable truth.&lt;/p&gt;

&lt;p&gt;Open source does not scale on code.&lt;br&gt;
It scales on trust.&lt;/p&gt;

&lt;p&gt;Maintainers are not compute. They do not autoscale.&lt;br&gt;
They get tired. They burn out. They leave.&lt;/p&gt;

&lt;p&gt;When you flood a project with low quality contributions you are not helping.&lt;br&gt;
You are converting goodwill into unpaid labor.&lt;/p&gt;

&lt;p&gt;That is why some projects are closing pull requests.&lt;br&gt;
Ending bug bounties.&lt;br&gt;
Banning AI generated submissions outright.&lt;/p&gt;

&lt;p&gt;Not because they hate tools.&lt;br&gt;
Because they value their time.&lt;/p&gt;




&lt;h2&gt;
  
  
  Tools Are Not the Enemy
&lt;/h2&gt;

&lt;p&gt;This is important.&lt;/p&gt;

&lt;p&gt;AI is not the villain.&lt;br&gt;
Misaligned incentives are.&lt;/p&gt;

&lt;p&gt;Used well AI is a sharp knife.&lt;br&gt;
Used badly it is a confetti cannon pointed at a codebase.&lt;/p&gt;

&lt;p&gt;The difference is intent.&lt;/p&gt;

&lt;p&gt;Did you read the code&lt;br&gt;
Did you run it&lt;br&gt;
Do you understand the change&lt;br&gt;
Are you willing to maintain it&lt;/p&gt;

&lt;p&gt;If the answer is no then the contribution is noise regardless of how it was produced.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Open Source Actually Needs
&lt;/h2&gt;

&lt;p&gt;Less volume.&lt;br&gt;
More care.&lt;/p&gt;

&lt;p&gt;Fewer drive by contributions.&lt;br&gt;
More long term thinking.&lt;/p&gt;

&lt;p&gt;AI that helps people understand systems instead of impersonating them.&lt;br&gt;
Contribution guidelines that reward clarity not quantity.&lt;br&gt;
Platforms that protect maintainers instead of optimizing for activity graphs.&lt;/p&gt;

&lt;p&gt;Open source survives on meaning not motion.&lt;/p&gt;




&lt;h2&gt;
  
  
  A Quiet Ending
&lt;/h2&gt;

&lt;p&gt;If we are not careful we will build a future where bots submit to bots and humans quietly walk away.&lt;/p&gt;

&lt;p&gt;Not with anger.&lt;br&gt;
With exhaustion.&lt;/p&gt;

&lt;p&gt;The fix is not dramatic.&lt;br&gt;
It is boring.&lt;br&gt;
It is human.&lt;/p&gt;

&lt;p&gt;Slow down.&lt;br&gt;
Read before you write.&lt;br&gt;
Understand before you submit.&lt;/p&gt;

&lt;p&gt;Because open source was never about how much code you can generate.&lt;/p&gt;

&lt;p&gt;It was about caring enough to make it right.&lt;/p&gt;

</description>
      <category>note</category>
      <category>ai</category>
      <category>bestpractices</category>
      <category>casestudy</category>
    </item>
    <item>
      <title>The Best Line of Code Is the One You Never Write</title>
      <dc:creator>Edgar Nahama Alochi</dc:creator>
      <pubDate>Mon, 20 Jul 2026 22:47:37 +0000</pubDate>
      <link>https://dev.to/nahamaalochi/the-best-line-of-code-is-the-one-you-never-write-1ola</link>
      <guid>https://dev.to/nahamaalochi/the-best-line-of-code-is-the-one-you-never-write-1ola</guid>
      <description>&lt;p&gt;The best line of code is the one you never write.&lt;br&gt;
The second best is the one you delete.&lt;/p&gt;

&lt;p&gt;This isn’t laziness. It’s restraint.&lt;/p&gt;

&lt;p&gt;Every line of code is a liability: something to read, understand, test, debug, maintain, migrate, and eventually explain to someone who didn’t write it, often future you, who will be far less charitable. Less code doesn’t just mean fewer bugs. It means fewer assumptions, fewer hidden contracts, and fewer places for complexity to quietly rot.&lt;/p&gt;

&lt;p&gt;Simple code beats clever code almost every time. Clever code impresses in the moment. Simple code survives. The goal isn’t to be smart. It’s to be clear. Code should explain itself without requiring interpretation or bravado.&lt;/p&gt;

&lt;p&gt;Consider a small example.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Clever:&lt;/strong&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;total&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;lo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SumBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;lo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;,&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;o&lt;/span&gt; &lt;span class="n"&gt;Order&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Paid&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Refunded&lt;/span&gt;
    &lt;span class="p"&gt;}),&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;o&lt;/span&gt; &lt;span class="n"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;float64&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;o&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Amount&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Discount&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;It works. It is concise. It is also doing filtering, business rules, and calculation in a single expression. Understanding it requires knowing the helper library, the order of operations, and the embedded business logic all at once.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Simple:&lt;/strong&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="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="kt"&gt;float64&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;orders&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;order&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Paid&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Refunded&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;continue&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NetAmount&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;More lines. Less code.&lt;/p&gt;

&lt;p&gt;The intent is obvious. The loop reads top to bottom. The business rule has a name. There is a clear place to add logging, debugging, or a new condition without fear.&lt;/p&gt;

&lt;p&gt;This is not accidental. Go’s design nudges you toward this style. It makes cleverness slightly uncomfortable and simplicity feel natural, because boring, readable code scales better than impressive code ever will.&lt;/p&gt;

&lt;p&gt;The same principle applies at the system level. Well-designed systems outperform clever ones. Clever systems depend on sustained brilliance and discipline to keep functioning. Well-designed systems depend on structure, constraints, and unremarkable correctness. They do not need heroics to stay stable.&lt;/p&gt;

&lt;p&gt;AI makes this lesson more urgent, not less. Modern tools are extremely good at generating code quickly and confidently. They will happily produce large, intricate solutions to problems that would have been better solved by a simpler model, a tighter constraint, or a deleted requirement. AI optimizes locally. Humans must optimize globally.&lt;/p&gt;

&lt;p&gt;Without global understanding of the domain, the trade-offs, and the long-term cost, code generation turns into code inflation. The risk is not that AI writes bad code. It is that it writes reasonable-looking code that no one fully understands or truly owns.&lt;/p&gt;

&lt;p&gt;Great engineers do not win by typing faster. They win by choosing simplicity over cleverness, design over tricks, and deletion over accumulation.&lt;/p&gt;

&lt;p&gt;Deletion is a design skill.&lt;br&gt;
Omission is an architectural decision.&lt;/p&gt;

&lt;p&gt;In an era where code is cheap, clarity is expensive. That is where real engineering lives.&lt;/p&gt;

&lt;p&gt;Write less. Delete more. Design simply.&lt;/p&gt;

</description>
      <category>note</category>
      <category>ai</category>
      <category>architecture</category>
      <category>bestpractices</category>
    </item>
    <item>
      <title>A Practical Critique of Service Meshes: Trade-offs, Pitfalls, and When *Not* to Use One</title>
      <dc:creator>Edgar Nahama Alochi</dc:creator>
      <pubDate>Mon, 20 Jul 2026 22:45:47 +0000</pubDate>
      <link>https://dev.to/nahamaalochi/a-practical-critique-of-service-meshes-trade-offs-pitfalls-and-when-not-to-use-one-8ah</link>
      <guid>https://dev.to/nahamaalochi/a-practical-critique-of-service-meshes-trade-offs-pitfalls-and-when-not-to-use-one-8ah</guid>
      <description>&lt;h3&gt;
  
  
  Why Service Meshes Sound Inevitable
&lt;/h3&gt;

&lt;p&gt;Every sufficiently large system eventually hears the phrase:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;We should probably add a service mesh.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It sounds reasonable.&lt;/p&gt;

&lt;p&gt;Traffic is complex.&lt;br&gt;
Security is hard.&lt;br&gt;
Observability feels fragmented.&lt;/p&gt;

&lt;p&gt;A service mesh promises to standardize all of this&lt;br&gt;
without touching application code.&lt;br&gt;
Just install it and let the platform handle the mess.&lt;/p&gt;

&lt;p&gt;That promise is not a lie.&lt;br&gt;
But it is incomplete.&lt;/p&gt;

&lt;p&gt;This note is about the cost of that promise.&lt;br&gt;
What you gain.&lt;br&gt;
What you lose.&lt;br&gt;
And when the right answer is still:&lt;/p&gt;

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

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




&lt;h2&gt;
  
  
  What a Service Mesh Actually Is
&lt;/h2&gt;

&lt;h3&gt;
  
  
  And Why That Matters
&lt;/h3&gt;

&lt;p&gt;At its core, a service mesh inserts itself into every request path,&lt;br&gt;
usually via sidecar proxies.&lt;/p&gt;

&lt;p&gt;Your services no longer talk to each other directly.&lt;br&gt;
They talk through infrastructure.&lt;/p&gt;

&lt;p&gt;This matters because you are not adding a library.&lt;br&gt;
You are adding a distributed system.&lt;/p&gt;

&lt;p&gt;One that runs alongside your own.&lt;br&gt;
With its own control plane.&lt;br&gt;
Data plane.&lt;br&gt;
Failure modes.&lt;br&gt;
And upgrade cycle.&lt;/p&gt;

&lt;p&gt;If you do not model it as a first-class system,&lt;br&gt;
it will surprise you later.&lt;/p&gt;

&lt;p&gt;Usually at 3 a.m.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  The First Trade-off
&lt;/h2&gt;

&lt;h3&gt;
  
  
  You Gain Consistency, but Lose Locality
&lt;/h3&gt;

&lt;p&gt;Before a mesh, behavior lives close to the code.&lt;/p&gt;

&lt;p&gt;Retries.&lt;br&gt;
Timeouts.&lt;br&gt;
Authentication.&lt;br&gt;
They are explicit.&lt;/p&gt;

&lt;p&gt;With a mesh, those behaviors move into configuration.&lt;/p&gt;

&lt;p&gt;That gives you consistency,&lt;br&gt;
but removes locality.&lt;/p&gt;

&lt;p&gt;When something breaks,&lt;br&gt;
the answer is no longer in the repository you are reading.&lt;/p&gt;

&lt;p&gt;It might be in a policy,&lt;br&gt;
applied by a controller,&lt;br&gt;
rendered into a proxy,&lt;br&gt;
that updated five minutes ago.&lt;/p&gt;

&lt;p&gt;Debugging shifts from reasoning about code&lt;br&gt;
to reasoning about state.&lt;/p&gt;

&lt;p&gt;This is not bad.&lt;br&gt;
But it is different.&lt;br&gt;
And often underestimated.&lt;/p&gt;




&lt;h2&gt;
  
  
  Observability
&lt;/h2&gt;

&lt;h3&gt;
  
  
  More Visibility Does Not Mean More Understanding
&lt;/h3&gt;

&lt;p&gt;Meshes are observability machines.&lt;/p&gt;

&lt;p&gt;Metrics for everything.&lt;br&gt;
Spans for every hop.&lt;br&gt;
Dashboards that look like flight control.&lt;/p&gt;

&lt;p&gt;And yet, teams often feel more blind.&lt;/p&gt;

&lt;p&gt;Retries hide failures.&lt;br&gt;
Timeouts hide slowness.&lt;br&gt;
Success rates lie politely.&lt;/p&gt;

&lt;p&gt;The system looks healthy&lt;br&gt;
until it suddenly is not.&lt;/p&gt;

&lt;p&gt;The hardest question becomes:&lt;/p&gt;

&lt;p&gt;Are we being protected,&lt;br&gt;
or are we being masked?&lt;/p&gt;

&lt;p&gt;If you cannot answer that confidently,&lt;br&gt;
you are operating on vibes.&lt;/p&gt;

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




&lt;h2&gt;
  
  
  Performance Costs
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Tax You Pay Forever
&lt;/h3&gt;

&lt;p&gt;Every sidecar proxy consumes resources.&lt;/p&gt;

&lt;p&gt;CPU.&lt;br&gt;
Memory.&lt;br&gt;
Latency.&lt;/p&gt;

&lt;p&gt;At small scale, this feels negligible.&lt;br&gt;
At large scale, it becomes a budget line item.&lt;/p&gt;

&lt;p&gt;High-throughput systems notice.&lt;br&gt;
Latency-sensitive systems suffer.&lt;br&gt;
Cost-optimized systems feel it immediately.&lt;/p&gt;

&lt;p&gt;A mesh is never free.&lt;br&gt;
It is a permanent tax,&lt;br&gt;
paid per request.&lt;/p&gt;

&lt;p&gt;If you cannot explain why that tax is worth it,&lt;br&gt;
you are already in trouble.&lt;/p&gt;




&lt;h2&gt;
  
  
  Operational Reality
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Part That Rarely Makes the Slides
&lt;/h3&gt;

&lt;p&gt;Running a mesh means:&lt;/p&gt;

&lt;p&gt;Upgrading control planes.&lt;br&gt;
Rotating certificates.&lt;br&gt;
Debugging broken proxies.&lt;br&gt;
Managing version skew.&lt;/p&gt;

&lt;p&gt;It also changes team structure.&lt;/p&gt;

&lt;p&gt;Platform teams become infrastructure product owners.&lt;br&gt;
Application teams become consumers of invisible rules.&lt;/p&gt;

&lt;p&gt;If ownership is unclear,&lt;br&gt;
the mesh becomes a blame amplifier.&lt;/p&gt;

&lt;p&gt;If your Kubernetes fundamentals are shaky,&lt;br&gt;
a mesh will not stabilize them.&lt;br&gt;
It will magnify every weakness.&lt;/p&gt;




&lt;h2&gt;
  
  
  Policy Sprawl
&lt;/h2&gt;

&lt;h3&gt;
  
  
  When Configuration Becomes Behavior
&lt;/h3&gt;

&lt;p&gt;Service meshes are policy engines.&lt;/p&gt;

&lt;p&gt;Over time, policies accumulate.&lt;/p&gt;

&lt;p&gt;Traffic rules.&lt;br&gt;
Security rules.&lt;br&gt;
Exception rules.&lt;/p&gt;

&lt;p&gt;Each one makes sense in isolation.&lt;br&gt;
Together, they form a system nobody fully understands.&lt;/p&gt;

&lt;p&gt;Now behavior lives in YAML.&lt;br&gt;
Spread across namespaces.&lt;br&gt;
Applied eventually.&lt;br&gt;
Remembered vaguely.&lt;/p&gt;

&lt;p&gt;When production breaks,&lt;br&gt;
you are no longer debugging software.&lt;/p&gt;

&lt;p&gt;You are excavating intent.&lt;/p&gt;




&lt;h2&gt;
  
  
  When a Service Mesh Makes Sense
&lt;/h2&gt;

&lt;p&gt;Despite everything,&lt;br&gt;
there &lt;em&gt;are&lt;/em&gt; valid reasons to adopt one.&lt;/p&gt;

&lt;p&gt;A mesh fits when:&lt;/p&gt;

&lt;p&gt;You operate many teams&lt;br&gt;
with many services&lt;br&gt;
across trust boundaries.&lt;/p&gt;

&lt;p&gt;When security requirements demand uniform enforcement&lt;br&gt;
and application teams cannot realistically implement it themselves.&lt;/p&gt;

&lt;p&gt;When platform maturity is high,&lt;br&gt;
ownership is clear,&lt;br&gt;
and engineers understand distributed failure.&lt;/p&gt;

&lt;p&gt;In short:&lt;br&gt;
when complexity already exists&lt;br&gt;
and is unavoidable.&lt;/p&gt;




&lt;h2&gt;
  
  
  When You Should &lt;em&gt;Not&lt;/em&gt; Use a Service Mesh
&lt;/h2&gt;

&lt;p&gt;Do not use a mesh when:&lt;/p&gt;

&lt;p&gt;Your system is small enough to understand.&lt;br&gt;
Your main bottleneck is product velocity.&lt;br&gt;
Your team is still learning Kubernetes.&lt;br&gt;
Your outages come from basics, not edge cases.&lt;/p&gt;

&lt;p&gt;Do not install a mesh to feel mature.&lt;br&gt;
Install it because you are already paying the complexity cost elsewhere.&lt;/p&gt;

&lt;p&gt;Often,&lt;br&gt;
a load balancer,&lt;br&gt;
good client libraries,&lt;br&gt;
and boring TLS&lt;br&gt;
are more than enough.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Real Question to Ask
&lt;/h2&gt;

&lt;p&gt;The question is not:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Is a service mesh good?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The question is:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;What complexity are we choosing to own?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A service mesh trades application simplicity&lt;br&gt;
for operational and cognitive complexity.&lt;/p&gt;

&lt;p&gt;That trade can be correct.&lt;br&gt;
Or disastrous.&lt;/p&gt;

&lt;p&gt;Simplicity is not a phase.&lt;br&gt;
It is a competitive advantage.&lt;/p&gt;

&lt;p&gt;If you can keep your system simple,&lt;br&gt;
do it.&lt;/p&gt;

&lt;p&gt;And do not apologize.&lt;/p&gt;

</description>
      <category>note</category>
      <category>architecture</category>
      <category>designpatterns</category>
    </item>
    <item>
      <title>When Software Decays and AI Accelerates Complexity</title>
      <dc:creator>Edgar Nahama Alochi</dc:creator>
      <pubDate>Mon, 20 Jul 2026 09:03:57 +0000</pubDate>
      <link>https://dev.to/nahamaalochi/when-software-decays-and-ai-accelerates-complexity-1da7</link>
      <guid>https://dev.to/nahamaalochi/when-software-decays-and-ai-accelerates-complexity-1da7</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Focnjwo0n0avxo2hdv21n.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Focnjwo0n0avxo2hdv21n.webp" alt="image" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why systems get harder to understand over time and what to do about it
&lt;/h2&gt;

&lt;p&gt;Software does not remain good forever. Even the most elegant code begins a slow drift toward disorder once it is written. This does not happen because engineers are careless or unskilled. It happens because entropy is the default state of complex systems. Without continuous attention, clarity fades, accidental complexity accumulates, and teams eventually find themselves maintaining systems they no longer fully understand.&lt;/p&gt;

&lt;p&gt;This is not pessimism. It is engineering realism.&lt;/p&gt;

&lt;h2&gt;
  
  
  Software entropy as a law of code
&lt;/h2&gt;

&lt;p&gt;Like physical systems, software naturally moves toward disorder unless energy is applied to keep it organized. In codebases, this disorder appears gradually and often quietly. Dependencies become tangled. Side effects surface in places no one expects. Changes that should be safe become risky. Systems appear to work most of the time, yet fail unpredictably when modified.&lt;/p&gt;

&lt;p&gt;This phenomenon is commonly described as software entropy. It is not a failure mode or a bug. It is a property of long lived systems. Without discipline, entropy grows invisibly until the cost of change becomes impossible to ignore.&lt;/p&gt;

&lt;h2&gt;
  
  
  The visible steps of decay
&lt;/h2&gt;

&lt;p&gt;Entropy does not arrive all at once. It reveals itself through patterns that are easy to recognize in hindsight.&lt;/p&gt;

&lt;h3&gt;
  
  
  Technical debt
&lt;/h3&gt;

&lt;p&gt;Every shortcut, clever workaround, missing test, or postponed refactor is a loan taken against future maintainability. Technical debt does not disappear on its own. It accumulates interest every time someone hesitates before changing code, works around it instead of fixing it, or avoids it entirely out of fear.&lt;/p&gt;

&lt;h3&gt;
  
  
  Code rot
&lt;/h3&gt;

&lt;p&gt;Code rot does not mean code stops running. It means code stops being understood. Paths that are rarely exercised degrade quietly. Tests become inaccurate. Assumptions that were once valid lose their context. The system still functions, but fewer people can explain why.&lt;/p&gt;

&lt;h3&gt;
  
  
  Architectural erosion
&lt;/h3&gt;

&lt;p&gt;What begins as a clear structure slowly weakens. Boundaries are crossed for convenience. Dependencies leak across layers. Modules that once had a single responsibility become tightly coupled to many others. The original architecture still exists in name, but no longer in practice.&lt;/p&gt;

&lt;p&gt;These are not isolated problems. They are symptoms of entropy acting over time in the absence of deliberate care.&lt;/p&gt;

&lt;h2&gt;
  
  
  AI as a force multiplier
&lt;/h2&gt;

&lt;p&gt;AI enters this picture not as a villain, but as an accelerator.&lt;/p&gt;

&lt;p&gt;Modern AI tools promise speed. They reduce boilerplate. They generate code quickly. They help surface patterns humans might miss. Used well, they are powerful productivity aids.&lt;/p&gt;

&lt;p&gt;The risk is not that AI produces bad code. The risk is that AI produces plausible code without understanding intent.&lt;/p&gt;

&lt;p&gt;AI systems optimize for what looks correct in isolation. They do not carry your product vision. They do not understand the tradeoffs behind existing architectural decisions. When they generate solutions, they often duplicate patterns, introduce subtle inconsistencies, or optimize for local fixes rather than global coherence.&lt;/p&gt;

&lt;p&gt;This accelerates the exact conditions entropy thrives on. More code is added faster. More decisions are made without shared context. Complexity grows without a corresponding increase in understanding.&lt;/p&gt;

&lt;p&gt;As a result, large AI assisted codebases can feel unfamiliar even to the teams that build them. At a glance everything looks reasonable. Under closer inspection, the system feels disjointed. Different parts reflect different heuristics. The code works, but it does not speak with a single voice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Managing complexity through discipline
&lt;/h2&gt;

&lt;p&gt;Codebases do not decay because engineers are careless. They decay because complex systems require continuous stewardship, not one time design decisions.&lt;/p&gt;

&lt;p&gt;There are ways to slow entropy, even in the presence of AI.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Lead with principles&lt;br&gt;
Start from real problems rather than abstract features. Treat simplicity as a deliberate design choice, not a happy accident.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use tests as a compass&lt;br&gt;
Tests do more than catch bugs. They provide confidence. When change is safe and verified, engineers are less likely to avoid necessary refactoring and less likely to introduce hidden regressions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Enforce clear boundaries&lt;br&gt;
When a part of the system owns a domain, keep its responsibilities focused. Modular systems do not just scale better. They age better.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Keep architecture human led&lt;br&gt;
AI is excellent at assisting with routine work. Architecture requires intent. Use AI as a tool, not as a decision maker. Let humans remain responsible for structure and direction.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  A final thought
&lt;/h2&gt;

&lt;p&gt;Entropy always wins if nothing is done. But teams that value long term clarity over short term velocity are not powerless. Decay is not inevitable. It can be measured, managed, and reduced.&lt;/p&gt;

&lt;p&gt;Great systems last not because they were designed once, but because every change preserved their coherence over time.&lt;/p&gt;

</description>
      <category>note</category>
      <category>ai</category>
      <category>architecture</category>
      <category>bestpractices</category>
    </item>
    <item>
      <title>Vibe Coding Is Cheap. Engineering Remains Expensive.</title>
      <dc:creator>Edgar Nahama Alochi</dc:creator>
      <pubDate>Thu, 16 Jul 2026 05:15:40 +0000</pubDate>
      <link>https://dev.to/nahamaalochi/vibe-coding-is-cheap-engineering-remains-expensive-4i38</link>
      <guid>https://dev.to/nahamaalochi/vibe-coding-is-cheap-engineering-remains-expensive-4i38</guid>
      <description>&lt;p&gt;Writing code is getting cheaper and faster. Engineering remains expensive.&lt;/p&gt;

&lt;p&gt;This is not hype. It is reality. And it is measurable.&lt;/p&gt;

&lt;p&gt;A recent study by &lt;strong&gt;Anthropic&lt;/strong&gt; looked at how AI-assisted coding affects learning new programming skills. Developers unfamiliar with a Python library were split into two groups. One used an AI assistant, the other relied on documentation and web searches. After completing the tasks, participants were tested on understanding the library’s concepts. The result was clear. The AI group scored about &lt;strong&gt;17 percent lower&lt;/strong&gt; on comprehension, without finishing tasks any faster overall&lt;/p&gt;

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

&lt;p&gt;Think about that for a second. You can have code that works perfectly but not actually understand why it works. Some developers who relied on AI finished faster, but when it came to reasoning about the code, they struggled the most. Producing output is not the same as building skill. Speed without understanding is a trap&lt;/p&gt;

&lt;p&gt;The study also showed that how you interact with AI matters. Developers who used the AI for everything learned the least. Those who asked targeted questions, explored why the code worked, or generated snippets and then probed them preserved far more of their learning[^1]. The lesson is simple. AI can teach, but it cannot replace thinking. Treat it like a collaborator, not a magician.&lt;/p&gt;

&lt;p&gt;This matches what I see in real-world software work. Someone who knows how to vibe a prompt can get a function running in minutes. Someone who knows systems moves faster when complexity grows, not because they type faster, but because they anticipate what could break, what could scale poorly, and what might cause headaches down the line. That is judgment. That is engineering. That is the thing AI cannot fully outsource.&lt;/p&gt;

&lt;p&gt;Code is an artifact. Systems are living organisms. They accumulate state, fail in unpredictable ways, scale differently than expected, and evolve over time. Engineering is expensive because it works with what persists and what matters. Producing code fast is only part of the picture. Understanding, anticipating, and designing for durability is where the real value and the real cost lives.&lt;/p&gt;

&lt;p&gt;Vibe coding works beautifully for small problems, narrow contexts, or throwaway prototypes. But as soon as a system grows, complexity hides in plain sight. AI-generated code may look clean on the surface, but intent is implicit. Decisions are baked in without explanation. Debugging, extending, or refactoring that code becomes a treasure hunt you never signed up for. Suddenly, the cheap, fast code feels anything but cheap.&lt;/p&gt;

&lt;p&gt;This is why engineers continue to outpace prompt specialists. They do not necessarily write more code, or write cleverer code. They reduce future cost. They know what precision matters, where to add structure, and where to leave flexibility. They can delete or rewrite confidently because they understand the system. AI accelerates their work, but it never replaces their judgment.&lt;/p&gt;

&lt;p&gt;The bigger picture is this. The emerging divide is not AI versus human, or coder versus non-coder. It is between people who can reason about systems and people who only generate output. Code is becoming abundant. Judgment is scarce. AI makes writing software easier. Engineering determines whether that software survives reality.&lt;/p&gt;

&lt;p&gt;Here is a little truth that always makes me smile. Fast code without thought is like a skateboard with no brakes. It might be fun at first, but try turning a corner and you will find yourself in the ditch. AI can give you the skateboard. Engineering teaches you how to steer.&lt;/p&gt;




&lt;h3&gt;
  
  
  Footnotes and Sources
&lt;/h3&gt;

&lt;p&gt;Anthropic. &lt;em&gt;How AI Assistance Impacts the Learning of Programming Skills&lt;/em&gt;. Controlled study on AI-assisted coding and concept retention&lt;/p&gt;

&lt;p&gt;The Decoder: &lt;em&gt;AI coding tools hurt learning unless you ask why, Anthropic study finds&lt;/em&gt; &lt;/p&gt;

</description>
      <category>note</category>
      <category>ai</category>
      <category>research</category>
    </item>
    <item>
      <title>The Great Simplification: Why Your Database is Your Best Cache</title>
      <dc:creator>Edgar Nahama Alochi</dc:creator>
      <pubDate>Wed, 15 Jul 2026 08:58:27 +0000</pubDate>
      <link>https://dev.to/nahamaalochi/the-great-simplification-why-your-database-is-your-best-cache-1h3</link>
      <guid>https://dev.to/nahamaalochi/the-great-simplification-why-your-database-is-your-best-cache-1h3</guid>
      <description>&lt;p&gt;For years, the "Standard Stack" followed a predictable pattern: Postgres for persistence, Redis for caching, and RabbitMQ or SQS for background jobs. We accepted this as the "Microservices Tax"—the price of doing business at scale.&lt;/p&gt;

&lt;p&gt;But in 2026, we’re seeing a counter-movement. We’re realizing that for 90% of applications, the bottleneck isn't the database's speed; it's the architectural complexity of keeping all these systems in sync.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. The "Single Source of Truth" Problem
&lt;/h3&gt;

&lt;p&gt;When you introduce Redis, you introduce the Cache Invalidation nightmare. You now have two places where "the truth" lives. If your Redis write succeeds but your Postgres transaction fails, your system is in an inconsistent state. By using Postgres as your primary store and your high-speed lookup table (via Unlogged Tables), you gain Atomic Consistency.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Eliminating Distributed Transactions
&lt;/h2&gt;

&lt;p&gt;When your queue (RabbitMQ) is separate from your database, you can't wrap a "job dispatch" and a "database update" in a single transaction. You end up needing the Outbox Pattern, which adds even more code to manage.&lt;/p&gt;

&lt;p&gt;If your "jobs" table is just another table in Postgres, a simple DB::transaction ensures that the job is only created if the data is actually saved. No more "ghost jobs" that reference IDs that don't exist yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Postgres is Faster Than You Think
&lt;/h2&gt;

&lt;p&gt;With the advent of NVMe storage and huge memory buffers, the "slowness" of disk-based databases has largely vanished for most workloads.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;JSONB&lt;/code&gt;allows for schema-less "Redis-style" key-value storage.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;LISTEN/NOTIFY&lt;/code&gt; handles real-time pub/sub.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SKIP LOCKED&lt;/code&gt;allows Postgres to act as a high-performance, concurrent queue without the risk of multiple workers grabbing the same task.&lt;/p&gt;

&lt;p&gt;The "Garden" Takeaway&lt;br&gt;
The most senior move a developer can make is choosing not to add a tool. Every new service you add is another point of failure, another security surface area to patch, and another set of metrics to monitor. Before you reach for a specialized tool, ask: "Can I do this with a more clever SQL query first?"&lt;/p&gt;

</description>
      <category>note</category>
      <category>architecture</category>
      <category>postgres</category>
      <category>systemdesign</category>
    </item>
    <item>
      <title>The Cost of a Promise</title>
      <dc:creator>Edgar Nahama Alochi</dc:creator>
      <pubDate>Mon, 13 Jul 2026 10:33:48 +0000</pubDate>
      <link>https://dev.to/nahamaalochi/the-cost-of-a-promise-455o</link>
      <guid>https://dev.to/nahamaalochi/the-cost-of-a-promise-455o</guid>
      <description>&lt;p&gt;An API is a promise to unknown consumers about how your system behaves. Once published, that promise is difficult to change without breaking trust. &lt;/p&gt;

&lt;p&gt;That’s why API design deserves far more care than it usually receives.&lt;/p&gt;

&lt;p&gt;Good APIs are boring in the best way. They are predictable, explicit, and unsurprising. They avoid clever shortcuts in favor of clarity. Consumers should not need to guess what an endpoint does or how a field behaves under edge conditions.&lt;/p&gt;

&lt;p&gt;One of the hardest parts of API design is restraint. Every field added is a commitment. Every optional parameter increases the surface area for bugs. Flexibility feels generous in the moment but becomes expensive over time. Strong APIs say “no” more often than “yes.”&lt;/p&gt;

&lt;p&gt;Consistency matters more than perfection. Naming conventions, error formats, pagination strategies—these things compound. Inconsistent APIs force consumers to write special-case logic, which is a hidden tax on every integration.&lt;/p&gt;

&lt;p&gt;Versioning is another area where theory and practice diverge. In reality, versioning is less about URLs and more about change management. Backward compatibility, deprecation timelines, and communication matter more than whether you use &lt;code&gt;/v1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;APIs should also be designed with failure in mind. Clear error messages, meaningful status codes, and idempotent operations make systems more resilient. Consumers will misuse your API. it’s not a matter of if, but when.&lt;/p&gt;

&lt;p&gt;At their best, APIs reflect thoughtful system boundaries. They expose intent, not internals. When done right, they allow teams to move independently without stepping on each other. When done poorly, they become tight coupling disguised as a service.&lt;/p&gt;

</description>
      <category>article</category>
      <category>apidesign</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Learning to Think in Sets, Not Loops</title>
      <dc:creator>Edgar Nahama Alochi</dc:creator>
      <pubDate>Sun, 12 Jul 2026 04:47:50 +0000</pubDate>
      <link>https://dev.to/nahamaalochi/learning-to-think-in-sets-not-loops-klp</link>
      <guid>https://dev.to/nahamaalochi/learning-to-think-in-sets-not-loops-klp</guid>
      <description>&lt;p&gt;SQL is often treated as an implementation detail something to hide behind an ORM or repository layer. That attitude usually survives until the first serious performance incident. At that point, SQL becomes unavoidable.&lt;/p&gt;

&lt;p&gt;SQL is not just a query language. It is a way of thinking about data that forces clarity.&lt;/p&gt;

&lt;p&gt;The hardest part of SQL is not syntax, but mindset. SQL requires a shift from imperative thinking to declarative thinking. When developers think in loops, they tend to write inefficient queries. SQL rewards those who describe &lt;em&gt;sets&lt;/em&gt;, &lt;em&gt;relationships&lt;/em&gt;, and &lt;em&gt;constraints&lt;/em&gt; precisely.&lt;/p&gt;

&lt;p&gt;A useful rule of thumb:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you find yourself thinking “for each row…”, you are probably about to write a bad query.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Good SQL starts with good schema design. When tables reflect real-world relationships clearly, queries become simpler and faster. This is why SQL is inseparable from [[Database]] design.&lt;/p&gt;

&lt;p&gt;Indexes are often misunderstood. They are not universal speed boosts. They are promises to the query planner about access paths. Adding indexes without understanding query patterns leads to bloated storage, slower writes, and false confidence.&lt;/p&gt;

&lt;p&gt;Indexes are another area where intuition often fails. Indexes do not speed up queries universally; they optimize specific access path&lt;/p&gt;

&lt;p&gt;Some hard-earned SQL heuristics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Avoid &lt;code&gt;SELECT *&lt;/code&gt; in production code&lt;/li&gt;
&lt;li&gt;Read execution plans before optimizing&lt;/li&gt;
&lt;li&gt;Optimize queries before adding caches&lt;/li&gt;
&lt;li&gt;If a query is fast and you don’t know why, you don’t understand it yet&lt;/li&gt;
&lt;li&gt;Aggregations hide bugs as easily as they hide rows&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;SQL is also a truth serum for business logic. Vague requirements collapse when forced into queries. Terms like “latest”, “active”, or “valid” demand precision. This is why SQL pairs naturally with [[API Design]] and reporting work.&lt;/p&gt;

&lt;p&gt;Concurrency exposes the cost of misunderstanding SQL. Isolation levels, locking, and transactions are not academic topics. Many data corruption bugs are simply misunderstood transactional behavior.&lt;/p&gt;

&lt;p&gt;Avoiding SQL does not simplify systems. It moves complexity into places where it is harder to see, harder to measure, and harder to fix.&lt;/p&gt;

&lt;p&gt;SQL teaches humility. Data has gravity.&lt;/p&gt;

</description>
      <category>note</category>
      <category>database</category>
      <category>sql</category>
    </item>
  </channel>
</rss>
