<?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: Mohamed Idris</title>
    <description>The latest articles on DEV Community by Mohamed Idris (@edriso).</description>
    <link>https://dev.to/edriso</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F542036%2F3d38f955-495f-4ee8-9445-db0d27f2fd7b.png</url>
      <title>DEV Community: Mohamed Idris</title>
      <link>https://dev.to/edriso</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/edriso"/>
    <language>en</language>
    <item>
      <title>"Concurrency" vs "Parallelism": One Cook Juggling vs Two Cooks Cooking</title>
      <dc:creator>Mohamed Idris</dc:creator>
      <pubDate>Mon, 08 Jun 2026 09:30:00 +0000</pubDate>
      <link>https://dev.to/edriso/concurrency-vs-parallelism-one-cook-juggling-vs-two-cooks-cooking-5el8</link>
      <guid>https://dev.to/edriso/concurrency-vs-parallelism-one-cook-juggling-vs-two-cooks-cooking-5el8</guid>
      <description>&lt;p&gt;Everyone uses these two words like they mean the same thing. They don't, and the&lt;br&gt;
difference is actually kind of beautiful once it clicks. Let's make it click.&lt;/p&gt;


&lt;h2&gt;
  
  
  The idea in one line
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Concurrency&lt;/strong&gt; = dealing with many things at once by switching between them.&lt;br&gt;
&lt;strong&gt;Parallelism&lt;/strong&gt; = doing many things at once, truly at the same instant.&lt;/p&gt;


&lt;h2&gt;
  
  
  The metaphor: the kitchen
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CONCURRENCY                         PARALLELISM
one cook, many dishes               two cooks, two dishes
stirs soup, then chops, then        each cooking at the same
back to the soup...                 real moment
= juggling, fast switching          = literally simultaneous
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;One cook&lt;/strong&gt; can handle three dishes by switching: stir the soup, while it&lt;br&gt;
simmers go chop veggies, pop back to the soup. They're never doing two things in&lt;br&gt;
the &lt;em&gt;same instant&lt;/em&gt;, but they keep all three moving. That's &lt;strong&gt;concurrency&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Two cooks&lt;/strong&gt; each working a dish at the very same moment? That's&lt;br&gt;
&lt;strong&gt;parallelism&lt;/strong&gt;. Real simultaneous work, which needs more than one worker.&lt;/p&gt;

&lt;p&gt;So: concurrency is about &lt;strong&gt;structure&lt;/strong&gt; (juggling many tasks), parallelism is&lt;br&gt;
about &lt;strong&gt;execution&lt;/strong&gt; (more than one happening at the literal same time).&lt;/p&gt;


&lt;h2&gt;
  
  
  How it shows up in code
&lt;/h2&gt;

&lt;p&gt;JavaScript is famous for being a &lt;strong&gt;single cook&lt;/strong&gt; (one main thread) that is great&lt;br&gt;
at concurrency. While it waits on a slow thing, it goes does other work.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Concurrency: one thread, but it doesn't freeze while waiting&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;([&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="s2"&gt;/user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;    &lt;span class="c1"&gt;// start this...&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="s2"&gt;/posts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;   &lt;span class="c1"&gt;// ...and this, without waiting for the first to finish&lt;/span&gt;
&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="c1"&gt;// While the network is busy, the one thread is free to handle other stuff.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The single cook fired off both orders, then handled other things while waiting.&lt;br&gt;
That's concurrency without parallelism: one worker, no freezing.&lt;/p&gt;

&lt;p&gt;True parallelism needs more workers. In the browser that's &lt;strong&gt;Web Workers&lt;/strong&gt;; on a&lt;br&gt;
server it's multiple threads or processes running on multiple CPU cores at once.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CPU core 1:  [ resize image A ]      &amp;lt;- these two really run
CPU core 2:  [ resize image B ]         at the same instant = parallel
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  A real case
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Waiting on slow stuff&lt;/strong&gt; (network, disk, database)? You want &lt;strong&gt;concurrency&lt;/strong&gt;.
One worker stays busy instead of freezing. This is most web code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Heavy number crunching&lt;/strong&gt; (resize 1000 images, crunch big math)? You want
&lt;strong&gt;parallelism&lt;/strong&gt;, real extra workers on extra CPU cores.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A useful line: concurrency is great for &lt;strong&gt;waiting&lt;/strong&gt;, parallelism is great for&lt;br&gt;
&lt;strong&gt;working&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Gotchas juniors hit
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Thinking &lt;code&gt;async/await&lt;/code&gt; makes things parallel.&lt;/strong&gt;&lt;br&gt;
It doesn't. It makes them concurrent. One thread, not frozen while waiting. Real&lt;br&gt;
parallel work needs more workers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Awaiting things one by one when they could overlap.&lt;/strong&gt;&lt;br&gt;
Two &lt;code&gt;await fetch()&lt;/code&gt; lines run one after the other. &lt;code&gt;Promise.all&lt;/code&gt; lets them&lt;br&gt;
overlap. Same single cook, but smarter juggling.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Assuming more workers always means faster.&lt;/strong&gt;&lt;br&gt;
Coordinating many cooks has its own cost (and shared data brings race&lt;br&gt;
conditions). Sometimes one well-organized cook wins.&lt;/p&gt;




&lt;h2&gt;
  
  
  Recap
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Concurrency&lt;/strong&gt; = juggling many tasks by switching (one cook, no freezing).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Parallelism&lt;/strong&gt; = truly doing many at once (multiple cooks, multiple cores).&lt;/li&gt;
&lt;li&gt;JS is a single cook that's great at concurrency.&lt;/li&gt;
&lt;li&gt;Concurrency shines for &lt;strong&gt;waiting&lt;/strong&gt;; parallelism shines for &lt;strong&gt;heavy work&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Your turn
&lt;/h2&gt;

&lt;p&gt;Look at code where you &lt;code&gt;await&lt;/code&gt; two slow calls back to back. Could they overlap&lt;br&gt;
with &lt;code&gt;Promise.all&lt;/code&gt;? That tiny change is concurrency working for you. Then explain&lt;br&gt;
"one cook juggling vs two cooks cooking" to a friend.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>beginners</category>
    </item>
    <item>
      <title>"Declarative" vs "Imperative": Ordering a Pizza vs Making It Yourself</title>
      <dc:creator>Mohamed Idris</dc:creator>
      <pubDate>Sun, 07 Jun 2026 09:28:00 +0000</pubDate>
      <link>https://dev.to/edriso/declarative-vs-imperative-ordering-a-pizza-vs-making-it-yourself-335a</link>
      <guid>https://dev.to/edriso/declarative-vs-imperative-ordering-a-pizza-vs-making-it-yourself-335a</guid>
      <description>&lt;p&gt;You want a pizza. You have two choices. Call the shop and say "one large&lt;br&gt;
pepperoni, please." Or roll up your sleeves: make the dough, spread the sauce,&lt;br&gt;
slice the pepperoni, set the oven, watch it bake.&lt;/p&gt;

&lt;p&gt;Same pizza. Totally different style. That gap is the difference between&lt;br&gt;
&lt;strong&gt;declarative&lt;/strong&gt; and &lt;strong&gt;imperative&lt;/strong&gt; code, two words you'll hear constantly.&lt;/p&gt;


&lt;h2&gt;
  
  
  The idea in one line
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Imperative&lt;/strong&gt; = you spell out &lt;em&gt;how&lt;/em&gt; to do it, step by step. &lt;strong&gt;Declarative&lt;/strong&gt; =&lt;br&gt;
you say &lt;em&gt;what&lt;/em&gt; you want, and let something else handle the how.&lt;/p&gt;


&lt;h2&gt;
  
  
  The metaphor: ordering vs cooking
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;IMPERATIVE (cook it yourself)        DECLARATIVE (order it)
1. make dough                        "one large pepperoni, please"
2. add sauce
3. add pepperoni                     ...the kitchen figures out the steps
4. bake 12 min
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Neither is "better" in general. But declarative is shorter, easier to read, and&lt;br&gt;
lets you skip details you don't care about.&lt;/p&gt;


&lt;h2&gt;
  
  
  How it looks in code
&lt;/h2&gt;

&lt;p&gt;Say you want only the even numbers from a list.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Imperative: you manage every step yourself&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;evens&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;   &lt;span class="c1"&gt;// set up a counter&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;                 &lt;span class="c1"&gt;// check each one&lt;/span&gt;
    &lt;span class="nx"&gt;evens&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;                    &lt;span class="c1"&gt;// collect the keepers&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Declarative: say WHAT you want, skip the how&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;evens&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;// "give me the even ones"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both give the same &lt;code&gt;evens&lt;/code&gt;. But the second one reads almost like English. You&lt;br&gt;
don't see the counter, the index, or the pushing. You just declared the goal:&lt;br&gt;
"keep the even ones."&lt;/p&gt;


&lt;h2&gt;
  
  
  A real case: HTML and React
&lt;/h2&gt;

&lt;p&gt;HTML is declarative. You write &lt;code&gt;&amp;lt;button&amp;gt;Buy&amp;lt;/button&amp;gt;&lt;/code&gt; and say &lt;em&gt;what&lt;/em&gt; you want on&lt;br&gt;
the page. You never write the steps to draw pixels on the screen. The browser&lt;br&gt;
does the how.&lt;/p&gt;

&lt;p&gt;React works the same way. You describe what the UI should look like for a given&lt;br&gt;
state, and React figures out the steps to make the screen match.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Declarative: "when isLoading, show a spinner; otherwise show the list"&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;isLoading&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Spinner&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt; &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;// You never write "find the old spinner, remove it, insert the list..." React does that.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;SQL is declarative too. &lt;code&gt;SELECT name FROM users WHERE age &amp;gt; 18&lt;/code&gt; says &lt;em&gt;what&lt;/em&gt; rows&lt;br&gt;
you want. The database decides &lt;em&gt;how&lt;/em&gt; to find them fast.&lt;/p&gt;




&lt;h2&gt;
  
  
  Gotchas juniors hit
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Thinking declarative is always better.&lt;/strong&gt;&lt;br&gt;
It's usually cleaner, but when you need fine control or top speed, imperative&lt;br&gt;
steps can be the right tool. Use the one that fits.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Mixing the two in a confusing soup.&lt;/strong&gt;&lt;br&gt;
A &lt;code&gt;.map()&lt;/code&gt; with a giant pile of imperative logic crammed inside often wants to be&lt;br&gt;
split up or rethought. Keep each piece clear.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Forgetting that declarative still runs steps.&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;.filter()&lt;/code&gt; still loops under the hood. You just don't have to write or babysit&lt;br&gt;
the loop. The how didn't vanish; someone else handles it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Recap
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Imperative&lt;/strong&gt; = the recipe, every step (a &lt;code&gt;for&lt;/code&gt; loop you manage).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Declarative&lt;/strong&gt; = the order, just the goal (&lt;code&gt;.filter()&lt;/code&gt;, HTML, SQL, React).&lt;/li&gt;
&lt;li&gt;Declarative code is usually shorter and easier to read.&lt;/li&gt;
&lt;li&gt;Pick the style that makes the goal clearest for the job.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Your turn
&lt;/h2&gt;

&lt;p&gt;Find a &lt;code&gt;for&lt;/code&gt; loop in your code that builds up a list. Can you rewrite it with&lt;br&gt;
&lt;code&gt;.map()&lt;/code&gt;, &lt;code&gt;.filter()&lt;/code&gt;, or &lt;code&gt;.reduce()&lt;/code&gt; so it says &lt;em&gt;what&lt;/em&gt; you want instead of &lt;em&gt;how&lt;/em&gt;?&lt;br&gt;
Try it, then explain "ordering a pizza vs cooking it" to a friend.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>beginners</category>
    </item>
    <item>
      <title>"Pure Function" and "Side Effect": The Tidy Cook vs the Messy One</title>
      <dc:creator>Mohamed Idris</dc:creator>
      <pubDate>Sat, 06 Jun 2026 09:28:00 +0000</pubDate>
      <link>https://dev.to/edriso/pure-function-and-side-effect-the-tidy-cook-vs-the-messy-one-52oa</link>
      <guid>https://dev.to/edriso/pure-function-and-side-effect-the-tidy-cook-vs-the-messy-one-52oa</guid>
      <description>&lt;p&gt;Two cooks make you the same soup. Cook A uses only what's on the cutting board&lt;br&gt;
and leaves the kitchen spotless. Cook B grabs random spices off the shelf, and on&lt;br&gt;
the way out, somehow sets the curtains on fire.&lt;/p&gt;

&lt;p&gt;Both made soup. But you trust Cook A way more. In code, Cook A writes &lt;strong&gt;pure&lt;br&gt;
functions&lt;/strong&gt;, and Cook B leaves &lt;strong&gt;side effects&lt;/strong&gt; everywhere.&lt;/p&gt;


&lt;h2&gt;
  
  
  The idea in one line
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;pure function&lt;/strong&gt; only uses its inputs and only returns an output. A &lt;strong&gt;side&lt;br&gt;
effect&lt;/strong&gt; is anything it touches &lt;em&gt;outside&lt;/em&gt; of that, like changing a global,&lt;br&gt;
writing a file, or hitting the network.&lt;/p&gt;


&lt;h2&gt;
  
  
  The metaphor: the tidy cook
&lt;/h2&gt;

&lt;p&gt;A pure function is the tidy cook:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Uses only the ingredients you hand it (its inputs).&lt;/li&gt;
&lt;li&gt;Gives back only the dish (its return value).&lt;/li&gt;
&lt;li&gt;Changes nothing else in the kitchen.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hand it the same ingredients, get the same dish. Every time. (Yes, that means&lt;br&gt;
pure functions are also deterministic.)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PURE                          IMPURE (has side effects)
in -&amp;gt; [ function ] -&amp;gt; out     in -&amp;gt; [ function ] -&amp;gt; out
nothing else moves                  ...and also: writes a file,
                                    changes a global, logs, fetches
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  How it looks in code
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Pure: depends only on input, returns only output, touches nothing else&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&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="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Impure: reaches outside itself (a side effect)&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;addToTotal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;          &lt;span class="c1"&gt;// changes a global. now the outside world moved.&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;// also writes to the console. another side effect.&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;add&lt;/code&gt; is a dream to test: &lt;code&gt;add(2, 3)&lt;/code&gt; is always &lt;code&gt;5&lt;/code&gt;. &lt;code&gt;addToTotal&lt;/code&gt; is trickier,&lt;br&gt;
because its result depends on what &lt;code&gt;total&lt;/code&gt; was before, and it messes with the&lt;br&gt;
world on its way out.&lt;/p&gt;


&lt;h2&gt;
  
  
  Wait, aren't side effects necessary?
&lt;/h2&gt;

&lt;p&gt;Yes! A program with zero side effects does nothing useful. Saving data, showing a&lt;br&gt;
page, calling an API: those are &lt;em&gt;all&lt;/em&gt; side effects, and you need them.&lt;/p&gt;

&lt;p&gt;The goal is not "no side effects." The goal is to &lt;strong&gt;keep them in their own&lt;br&gt;
corner&lt;/strong&gt;, so most of your code stays pure and easy to trust.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Keep the thinking pure...&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;nextCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;count&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="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;        &lt;span class="c1"&gt;// pure: easy to test&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// ...and do the messy stuff at the edge&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleClick&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;nextCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  &lt;span class="c1"&gt;// the side effect (updating the screen) lives here&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  A real case
&lt;/h2&gt;

&lt;p&gt;This is why utility and helper functions are usually pure: format a price,&lt;br&gt;
calculate a total, validate an email. They're easy to test because you just feed&lt;br&gt;
inputs and check outputs. No database, no clock, no mocking circus.&lt;/p&gt;

&lt;p&gt;The messy parts (saving to a database, sending an email) get pushed to the edges&lt;br&gt;
where they're easy to spot.&lt;/p&gt;




&lt;h2&gt;
  
  
  Gotchas juniors hit
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Calling logging or &lt;code&gt;console.log&lt;/code&gt; "harmless."&lt;/strong&gt;&lt;br&gt;
It's still a side effect. Usually fine, but it means the function isn't pure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Secretly mutating an input.&lt;/strong&gt;&lt;br&gt;
A function that does &lt;code&gt;arr.push(x)&lt;/code&gt; to an array you passed in changed your data.&lt;br&gt;
That's a side effect hiding in plain sight. Return a new value instead.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Thinking pure functions are useless because they "just return stuff."&lt;/strong&gt;&lt;br&gt;
That "just returning stuff" is exactly why they're easy to test, reuse, and&lt;br&gt;
trust. That's the win.&lt;/p&gt;




&lt;h2&gt;
  
  
  Recap
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pure function&lt;/strong&gt; = uses only its inputs, returns only an output, touches
nothing else. The tidy cook.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Side effect&lt;/strong&gt; = touching the outside world (globals, files, network, screen,
even logs).&lt;/li&gt;
&lt;li&gt;You &lt;em&gt;need&lt;/em&gt; side effects, just keep them at the edges.&lt;/li&gt;
&lt;li&gt;Pure code is easy to test and reuse. That's the whole point.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Your turn
&lt;/h2&gt;

&lt;p&gt;Pick one function in your project. Ask: does it touch anything besides its inputs&lt;br&gt;
and return value? If yes, can you pull that messy part out and leave a clean,&lt;br&gt;
pure core? Try it, then explain "the tidy cook vs the messy cook" to a friend.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>beginners</category>
    </item>
    <item>
      <title>"Mutable" vs "Immutable": Can You Change It After You Make It?</title>
      <dc:creator>Mohamed Idris</dc:creator>
      <pubDate>Fri, 05 Jun 2026 09:27:00 +0000</pubDate>
      <link>https://dev.to/edriso/mutable-vs-immutable-can-you-change-it-after-you-make-it-58gc</link>
      <guid>https://dev.to/edriso/mutable-vs-immutable-can-you-change-it-after-you-make-it-58gc</guid>
      <description>&lt;p&gt;You copy an array to be "safe," tweak the copy, and somehow the &lt;strong&gt;original&lt;/strong&gt;&lt;br&gt;
changes too. You stare at the screen. You didn't touch the original. Did the&lt;br&gt;
computer just lie to you?&lt;/p&gt;

&lt;p&gt;Welcome to the world of &lt;strong&gt;mutable&lt;/strong&gt; and &lt;strong&gt;immutable&lt;/strong&gt;. Two words that explain a&lt;br&gt;
ton of "wait, why did that change?" bugs.&lt;/p&gt;


&lt;h2&gt;
  
  
  The idea in one line
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Mutable&lt;/strong&gt; means "can be changed after it's made." &lt;strong&gt;Immutable&lt;/strong&gt; means "locked&lt;br&gt;
forever once it's made."&lt;/p&gt;


&lt;h2&gt;
  
  
  The metaphor: a whiteboard vs a printed photo
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;WHITEBOARD (mutable)            PRINTED PHOTO (immutable)
wipe it, rewrite it             can't edit it
same board, new content         want a change? print a NEW photo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;A whiteboard is &lt;strong&gt;mutable&lt;/strong&gt;. You change what's on it, but it's still the same&lt;br&gt;
board. A printed photo is &lt;strong&gt;immutable&lt;/strong&gt;. You can't change it. If you want a&lt;br&gt;
different picture, you make a brand new print and keep (or toss) the old one.&lt;/p&gt;


&lt;h2&gt;
  
  
  How it bites you in code
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;original&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&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;copy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;original&lt;/span&gt;        &lt;span class="c1"&gt;// NOT a copy! both names point to the SAME array&lt;/span&gt;
&lt;span class="nx"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;original&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;        &lt;span class="c1"&gt;// [1, 2, 3, 4]  &amp;lt;- surprise! the original changed too&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;code&gt;copy = original&lt;/code&gt; did not make a new array. It just gave the &lt;strong&gt;same&lt;/strong&gt; whiteboard&lt;br&gt;
a second name. Writing through one name shows up under the other. Arrays and&lt;br&gt;
objects in JavaScript are mutable, so this trap is everywhere.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// The fix: make a real new array (a fresh print), then change that&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;original&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&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;copy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;original&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;   &lt;span class="c1"&gt;// new array with the same items&lt;/span&gt;
&lt;span class="nx"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;original&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;        &lt;span class="c1"&gt;// [1, 2, 3]  &amp;lt;- safe!&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;            &lt;span class="c1"&gt;// [1, 2, 3, 4]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  A real case: React state
&lt;/h2&gt;

&lt;p&gt;React leans hard on immutability. If you change state in place, React often&lt;br&gt;
can't tell anything changed, so your screen doesn't update.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Wrong: mutating the same array. React may not re-render.&lt;/span&gt;
&lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newTodo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;setTodos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// Right: hand React a brand new array&lt;/span&gt;
&lt;span class="nf"&gt;setTodos&lt;/span&gt;&lt;span class="p"&gt;([...&lt;/span&gt;&lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newTodo&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The rule "don't mutate state, replace it" is this exact idea. Treat state like a&lt;br&gt;
printed photo: make a new one instead of scribbling on the old.&lt;/p&gt;




&lt;h2&gt;
  
  
  Gotchas juniors hit
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Thinking &lt;code&gt;=&lt;/code&gt; copies.&lt;/strong&gt;&lt;br&gt;
For arrays and objects, &lt;code&gt;=&lt;/code&gt; copies the &lt;strong&gt;reference&lt;/strong&gt; (the name), not the contents.&lt;br&gt;
Both names share one thing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. &lt;code&gt;const&lt;/code&gt; does not mean immutable.&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;const arr = [1,2]&lt;/code&gt; just means you can't point &lt;code&gt;arr&lt;/code&gt; at something else. You can&lt;br&gt;
still &lt;code&gt;arr.push(3)&lt;/code&gt;. The box is locked; the contents are not.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Shallow copies only go one level deep.&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;[...arr]&lt;/code&gt; copies the top level. Nested objects inside are still shared. Deep&lt;br&gt;
data needs deeper copying.&lt;/p&gt;




&lt;h2&gt;
  
  
  Recap
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Mutable&lt;/strong&gt; = changeable after creation (a whiteboard).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Immutable&lt;/strong&gt; = locked after creation (a printed photo).&lt;/li&gt;
&lt;li&gt;In JS, &lt;code&gt;=&lt;/code&gt; shares the same thing; it does not copy it.&lt;/li&gt;
&lt;li&gt;For safe updates (especially React state), make a &lt;strong&gt;new&lt;/strong&gt; value instead of
changing the old one.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Your turn
&lt;/h2&gt;

&lt;p&gt;Run the &lt;code&gt;const copy = original; copy.push(4)&lt;/code&gt; example yourself and watch the&lt;br&gt;
original change. Then fix it with &lt;code&gt;[...original]&lt;/code&gt;. Once that "aha" lands, explain&lt;br&gt;
"whiteboard vs printed photo" to a friend.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>beginners</category>
    </item>
    <item>
      <title>"Deterministic": Same Question, Same Answer, Every Time</title>
      <dc:creator>Mohamed Idris</dc:creator>
      <pubDate>Thu, 04 Jun 2026 09:27:00 +0000</pubDate>
      <link>https://dev.to/edriso/deterministic-same-question-same-answer-every-time-59km</link>
      <guid>https://dev.to/edriso/deterministic-same-question-same-answer-every-time-59km</guid>
      <description>&lt;p&gt;You run your tests. Green. You run them again, changing nothing. Red. You run a&lt;br&gt;
third time. Green again. You haven't touched a thing, but the result keeps&lt;br&gt;
flipping. Spooky, right?&lt;/p&gt;

&lt;p&gt;That flickering test is &lt;strong&gt;not deterministic&lt;/strong&gt;, and that one word explains a&lt;br&gt;
whole family of frustrating bugs.&lt;/p&gt;




&lt;h2&gt;
  
  
  The idea in one line
&lt;/h2&gt;

&lt;p&gt;Something is &lt;strong&gt;deterministic&lt;/strong&gt; if the same input always gives the &lt;strong&gt;same output&lt;/strong&gt;,&lt;br&gt;
every single time.&lt;/p&gt;




&lt;h2&gt;
  
  
  The metaphor: a vending machine vs a slot machine
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;VENDING MACHINE                 SLOT MACHINE
press B4 -&amp;gt; always a cola       pull lever -&amp;gt; who knows?
   = DETERMINISTIC                 = NOT deterministic
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Press B4 on a vending machine and you get a cola. Always. Press it a thousand&lt;br&gt;
times, a thousand colas. That's deterministic: predictable, repeatable, trustable.&lt;/p&gt;

&lt;p&gt;A slot machine takes the same pull and gives you a different result each time.&lt;br&gt;
Fun for gambling. Terrible for code you need to trust.&lt;/p&gt;




&lt;h2&gt;
  
  
  How it shows up in code
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// NOT deterministic: depends on the clock and a dice roll&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;makeId&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="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;-&lt;/span&gt;&lt;span class="dl"&gt;"&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;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  &lt;span class="c1"&gt;// different every call&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Deterministic: same input -&amp;gt; same output, forever&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;double&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&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="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;   &lt;span class="c1"&gt;// double(5) is 10. today, tomorrow, on any machine.&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;double(5)&lt;/code&gt; is &lt;code&gt;10&lt;/code&gt; and will be &lt;code&gt;10&lt;/code&gt; until the end of time. But &lt;code&gt;makeId()&lt;/code&gt; gives&lt;br&gt;
you something new each call, because it leans on &lt;code&gt;Date.now()&lt;/code&gt; and &lt;code&gt;Math.random()&lt;/code&gt;,&lt;br&gt;
two classic sources of "it depends."&lt;/p&gt;




&lt;h2&gt;
  
  
  A real case: flaky tests
&lt;/h2&gt;

&lt;p&gt;The number one place juniors meet this word is &lt;strong&gt;flaky tests&lt;/strong&gt;. A test that&lt;br&gt;
passes and fails for no clear reason is usually leaning on something&lt;br&gt;
non-deterministic:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The current time or date.&lt;/li&gt;
&lt;li&gt;Random values.&lt;/li&gt;
&lt;li&gt;The order results come back from an API or database.&lt;/li&gt;
&lt;li&gt;Another test that ran first and left junk behind.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Flaky: "today" changes, so this test rots over time&lt;/span&gt;
&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;formatDate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;())).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2026-05-31&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// Stable: feed in a fixed input, get a fixed output&lt;/span&gt;
&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;formatDate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2026-05-31&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2026-05-31&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;The fix is almost always the same: &lt;strong&gt;stop depending on the unpredictable thing.&lt;/strong&gt;&lt;br&gt;
Pass the date in. Lock the random seed. Sort the list before checking it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Gotchas juniors hit
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Hidden inputs.&lt;/strong&gt;&lt;br&gt;
A function can look pure but secretly read the clock, a global, or a file. Those&lt;br&gt;
hidden inputs make it non-deterministic. Hunt them down.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Relying on order you were never promised.&lt;/strong&gt;&lt;br&gt;
"The database gives rows back in insert order" is not guaranteed unless you&lt;br&gt;
&lt;code&gt;ORDER BY&lt;/code&gt;. Don't trust luck.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Thinking random is bad.&lt;/strong&gt;&lt;br&gt;
It's not! You &lt;em&gt;want&lt;/em&gt; randomness for IDs, salts, and shuffles. Just keep it out of&lt;br&gt;
the parts you need to test and trust.&lt;/p&gt;




&lt;h2&gt;
  
  
  Recap
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Deterministic&lt;/strong&gt; = same input, same output, every time. Like a vending machine.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Non-deterministic&lt;/strong&gt; = results that change on their own. Like a slot machine.&lt;/li&gt;
&lt;li&gt;The usual culprits: time, randomness, order, and leftover state.&lt;/li&gt;
&lt;li&gt;Flaky tests almost always hide a non-deterministic input.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Your turn
&lt;/h2&gt;

&lt;p&gt;Look at your flakiest test (you know the one). What unpredictable thing does it&lt;br&gt;
touch: the clock, a random value, or an order you never pinned down? Make that&lt;br&gt;
input fixed, and watch it go calm. Then go explain "vending machine vs slot&lt;br&gt;
machine" to a friend.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>beginners</category>
    </item>
    <item>
      <title>SQL: When to Use != and When to Use IS NOT</title>
      <dc:creator>Mohamed Idris</dc:creator>
      <pubDate>Wed, 03 Jun 2026 12:39:55 +0000</pubDate>
      <link>https://dev.to/edriso/sql-when-to-use-and-when-to-use-is-not-3aaa</link>
      <guid>https://dev.to/edriso/sql-when-to-use-and-when-to-use-is-not-3aaa</guid>
      <description>&lt;p&gt;If you are learning SQL, you have probably written something like &lt;code&gt;WHERE status != 'borrowed'&lt;/code&gt; and it worked fine. Then one day you tried &lt;code&gt;WHERE bonus != 1000&lt;/code&gt; and some rows mysteriously went missing. The reason is the difference between &lt;code&gt;!=&lt;/code&gt; and &lt;code&gt;IS NOT&lt;/code&gt;. Let me explain it in plain English.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Short Answer
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;!=&lt;/code&gt; (also written &lt;code&gt;&amp;lt;&amp;gt;&lt;/code&gt;) compares &lt;strong&gt;values&lt;/strong&gt;. Use it for text, numbers, and dates.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;IS NOT&lt;/code&gt; compares against &lt;strong&gt;NULL&lt;/strong&gt;, &lt;code&gt;TRUE&lt;/code&gt;, or &lt;code&gt;FALSE&lt;/code&gt;. In real life you will almost always use it as &lt;code&gt;IS NOT NULL&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They are not interchangeable, and the reason is how SQL treats NULL.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using != for Normal Values
&lt;/h2&gt;

&lt;p&gt;This is the one you use most of the time. It checks if a value is different from another value.&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;WHERE&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s1"&gt;'borrowed'&lt;/span&gt;   &lt;span class="c1"&gt;-- status is not the text "borrowed"&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;                 &lt;span class="c1"&gt;-- id is not 5&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;rating&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;           &lt;span class="c1"&gt;-- rating is not 8.9&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Simple. If the column has a real value, &lt;code&gt;!=&lt;/code&gt; does exactly what you expect.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using IS NOT for NULL
&lt;/h2&gt;

&lt;p&gt;NULL in SQL does not mean "empty." It means "unknown" or "missing." And here is the catch: you cannot compare anything to "unknown" using &lt;code&gt;=&lt;/code&gt; or &lt;code&gt;!=&lt;/code&gt;, because the result would also be unknown.&lt;/p&gt;

&lt;p&gt;So this silently breaks:&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;WHERE&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;   &lt;span class="c1"&gt;-- returns NO rows, ever&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even a row where status is truly missing will not match, because &lt;code&gt;something != NULL&lt;/code&gt; becomes NULL (unknown), and SQL only keeps rows where the condition is TRUE.&lt;/p&gt;

&lt;p&gt;The correct way:&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;WHERE&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="k"&gt;IS&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;   &lt;span class="c1"&gt;-- works as you would expect&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Quick Reference Table
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;You want to check&lt;/th&gt;
&lt;th&gt;Use&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Value is different from another value&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;!=&lt;/code&gt; or &lt;code&gt;&amp;lt;&amp;gt;&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Column is not missing&lt;/td&gt;
&lt;td&gt;&lt;code&gt;IS NOT NULL&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Column is missing&lt;/td&gt;
&lt;td&gt;&lt;code&gt;IS NULL&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Value equals another value&lt;/td&gt;
&lt;td&gt;&lt;code&gt;=&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  A Real Gotcha Worth Remembering
&lt;/h2&gt;

&lt;p&gt;Say you have a &lt;code&gt;bonus&lt;/code&gt; column. Some employees have a number, and some have NULL because no bonus was recorded. You want everyone whose bonus is not 1000.&lt;/p&gt;

&lt;p&gt;You might write this:&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;WHERE&lt;/span&gt; &lt;span class="n"&gt;bonus&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will &lt;strong&gt;miss&lt;/strong&gt; every employee with a NULL bonus, even though their bonus is clearly not 1000. To include them you need:&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;WHERE&lt;/span&gt; &lt;span class="n"&gt;bonus&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="k"&gt;OR&lt;/span&gt; &lt;span class="n"&gt;bonus&lt;/span&gt; &lt;span class="k"&gt;IS&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This exact problem shows up a lot in practice (the classic "Employee Bonus" type query), so it is worth burning into memory.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus: A Real Query
&lt;/h2&gt;

&lt;p&gt;Here is a small example. You run a library and you want to report books with an odd ID whose status is not "borrowed", ordered by rating so the best available books show first.&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;Books&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
  &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s1"&gt;'borrowed'&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;rating&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A couple of small notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;!=&lt;/code&gt; works in MySQL, but the official SQL standard operator is &lt;code&gt;&amp;lt;&amp;gt;&lt;/code&gt;. Both do the same job in MySQL.&lt;/li&gt;
&lt;li&gt;Use single quotes (&lt;code&gt;'boring'&lt;/code&gt;) for strings. Double quotes work in MySQL but single quotes are safer if you ever switch databases.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Wrap Up
&lt;/h2&gt;

&lt;p&gt;Remember it like this: &lt;code&gt;!=&lt;/code&gt; is for things that have a value, and &lt;code&gt;IS NOT NULL&lt;/code&gt; is for checking that a value even exists. The moment NULL enters the picture, switch from &lt;code&gt;!=&lt;/code&gt; to &lt;code&gt;IS NOT&lt;/code&gt;. That one habit will save you from a lot of confusing "where did my rows go" moments.&lt;/p&gt;

</description>
      <category>sql</category>
      <category>database</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>"Race Condition": When Two Things Reach for the Same Cookie</title>
      <dc:creator>Mohamed Idris</dc:creator>
      <pubDate>Wed, 03 Jun 2026 09:26:00 +0000</pubDate>
      <link>https://dev.to/edriso/race-condition-when-two-things-reach-for-the-same-cookie-36do</link>
      <guid>https://dev.to/edriso/race-condition-when-two-things-reach-for-the-same-cookie-36do</guid>
      <description>&lt;p&gt;There is one cookie left on the plate. You and your sibling both see it. You both&lt;br&gt;
reach at the same time. Who gets it? Nobody planned for "both hands at once," so&lt;br&gt;
the result is a mess (and maybe a broken plate).&lt;/p&gt;

&lt;p&gt;Computers do this too, and we call it a &lt;strong&gt;race condition&lt;/strong&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  The idea in one line
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;race condition&lt;/strong&gt; is a bug that shows up when two things run at the same time&lt;br&gt;
and the result depends on &lt;strong&gt;who happens to get there first&lt;/strong&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  The metaphor: the last cookie
&lt;/h2&gt;

&lt;p&gt;Two people, one cookie. The rule was "first to grab it gets it." But if they&lt;br&gt;
grab at the &lt;em&gt;exact&lt;/em&gt; same moment, the rule breaks. Sometimes one wins, sometimes&lt;br&gt;
the other, sometimes the cookie ends up on the floor. Same start, different&lt;br&gt;
endings. That randomness is the smell of a race condition.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Time -&amp;gt;
You:     see cookie ----------- grab!
Sibling: see cookie -- grab!
                          ^ both saw "1 cookie", both grabbed. now what?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  How it looks in code
&lt;/h2&gt;

&lt;p&gt;Classic example: two requests buying the last item in stock.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Both requests run this at almost the same time&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;      &lt;span class="c1"&gt;// both read: stock = 1&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stock&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;                 &lt;span class="c1"&gt;// both see 1 &amp;gt; 0, both say "yes!"&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setStock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stock&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// both write stock = 0&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;ship&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                     &lt;span class="c1"&gt;// we just shipped TWO. we had ONE.&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both requests read &lt;code&gt;stock = 1&lt;/code&gt; before either one updated it. So both think&lt;br&gt;
they're fine. You oversell. The bug only appears when the timing lines up, which&lt;br&gt;
is why it's so sneaky: it passes every test on your laptop, then explodes on busy&lt;br&gt;
days.&lt;/p&gt;


&lt;h2&gt;
  
  
  The fix: don't let them both reach at once
&lt;/h2&gt;

&lt;p&gt;You make the "check and update" happen as &lt;strong&gt;one locked step&lt;/strong&gt;, so the second&lt;br&gt;
request has to wait its turn.&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="c1"&gt;-- Let the database do the check-and-subtract atomically, one at a time&lt;/span&gt;
&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;products&lt;/span&gt;
&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;stock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stock&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;stock&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;-- only succeeds if stock is still &amp;gt; 0&lt;/span&gt;
&lt;span class="c1"&gt;-- if 0 rows changed, you know you were too late. don't ship.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the database hands out the cookie to exactly one winner. The loser is told&lt;br&gt;
"sorry, sold out," instead of both walking away thinking they won.&lt;/p&gt;




&lt;h2&gt;
  
  
  A real case
&lt;/h2&gt;

&lt;p&gt;Race conditions love:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Selling the last ticket or item.&lt;/li&gt;
&lt;li&gt;Two clicks creating two accounts with the same email.&lt;/li&gt;
&lt;li&gt;A counter (likes, views) losing updates when many people act at once.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The pattern is always the same: &lt;strong&gt;read, decide, write&lt;/strong&gt;, with someone sneaking in&lt;br&gt;
between your read and your write.&lt;/p&gt;




&lt;h2&gt;
  
  
  Gotchas juniors hit
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. "It works on my machine."&lt;/strong&gt;&lt;br&gt;
Of course it does. You're the only user. Races need traffic. Test with the real&lt;br&gt;
world in mind.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Adding a &lt;code&gt;sleep&lt;/code&gt; to "fix" it.&lt;/strong&gt;&lt;br&gt;
Slowing things down just hides the bug for a while. The race is still there.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Trusting a read you made a moment ago.&lt;/strong&gt;&lt;br&gt;
By the time you write, the value may have changed. Let the database check the&lt;br&gt;
condition at write time.&lt;/p&gt;




&lt;h2&gt;
  
  
  Recap
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;race condition&lt;/strong&gt; = the answer depends on who gets there first.&lt;/li&gt;
&lt;li&gt;It hides during quiet times and bites under load.&lt;/li&gt;
&lt;li&gt;The shape is always &lt;strong&gt;read, decide, write&lt;/strong&gt; with a gap in the middle.&lt;/li&gt;
&lt;li&gt;Fix it by making the check-and-change one locked, atomic step.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Your turn
&lt;/h2&gt;

&lt;p&gt;Find a "read, check, then write" in your code (like "if username is free, create&lt;br&gt;
it"). Imagine two users doing it at the exact same millisecond. Could both win?&lt;br&gt;
If yes, you found a race. Tell a friend about the last cookie.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>beginners</category>
    </item>
    <item>
      <title>"Atomic": All of It, or None of It</title>
      <dc:creator>Mohamed Idris</dc:creator>
      <pubDate>Tue, 02 Jun 2026 09:26:00 +0000</pubDate>
      <link>https://dev.to/edriso/atomic-all-of-it-or-none-of-it-mnm</link>
      <guid>https://dev.to/edriso/atomic-all-of-it-or-none-of-it-mnm</guid>
      <description>&lt;p&gt;You send money to a friend. The app takes $50 out of your account. Then, right&lt;br&gt;
in the middle, the server crashes. Your $50 is gone, but your friend never got&lt;br&gt;
it. Money just vanished into the void.&lt;/p&gt;

&lt;p&gt;That nightmare is exactly what the word &lt;strong&gt;atomic&lt;/strong&gt; is here to prevent.&lt;/p&gt;


&lt;h2&gt;
  
  
  The idea in one line
&lt;/h2&gt;

&lt;p&gt;An &lt;strong&gt;atomic&lt;/strong&gt; action either fully happens or fully doesn't. There is no&lt;br&gt;
half-finished, in-between mess.&lt;/p&gt;


&lt;h2&gt;
  
  
  The metaphor: stapling pages together
&lt;/h2&gt;

&lt;p&gt;Imagine a contract with two pages: "take $50 from Alex" and "give $50 to Sam."&lt;/p&gt;

&lt;p&gt;If the pages are loose, someone could grab page one and drop page two. Disaster.&lt;br&gt;
So you &lt;strong&gt;staple them together&lt;/strong&gt;. Now they move as one thing. Either both pages go&lt;br&gt;
through, or neither does. You can't tear them apart.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NOT ATOMIC                       ATOMIC (stapled)
[ take $50 ] done                [ take $50 ]  \
[ give $50 ] CRASH                            } both, or neither
money lost                       [ give $50 ]  /
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;"Atomic" comes from the old idea of an atom: something you cannot cut in half.&lt;/p&gt;




&lt;h2&gt;
  
  
  How you actually do it: a transaction
&lt;/h2&gt;

&lt;p&gt;In databases, you staple steps together with a &lt;strong&gt;transaction&lt;/strong&gt;.&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="c1"&gt;-- Wrong way: two separate steps. A crash between them loses money.&lt;/span&gt;
&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;accounts&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Alex'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;-- ... crash here ...&lt;/span&gt;
&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;accounts&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Sam'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- Right way: staple them. All of it, or none of it.&lt;/span&gt;
&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;accounts&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Alex'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;accounts&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Sam'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;COMMIT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;-- if anything fails before this, ROLLBACK undoes the whole thing&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;BEGIN&lt;/code&gt; starts the staple. &lt;code&gt;COMMIT&lt;/code&gt; makes it real. If something breaks in&lt;br&gt;
between, a &lt;code&gt;ROLLBACK&lt;/code&gt; throws the whole half-done mess away, like it never started.&lt;/p&gt;




&lt;h2&gt;
  
  
  A real case
&lt;/h2&gt;

&lt;p&gt;Any time &lt;strong&gt;two things must be true together&lt;/strong&gt;, you want atomic:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Move money between accounts.&lt;/li&gt;
&lt;li&gt;Book the last concert seat AND charge the card.&lt;/li&gt;
&lt;li&gt;Create a user AND give them a starter project.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If only one half lands, you get "ghost" data: a charge with no seat, a user with&lt;br&gt;
no project. Atomic operations keep those from ever existing.&lt;/p&gt;




&lt;h2&gt;
  
  
  Gotchas juniors hit
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Doing related writes as separate, unprotected steps.&lt;/strong&gt;&lt;br&gt;
Two &lt;code&gt;UPDATE&lt;/code&gt;s in a row are not safe just because they sit next to each other in&lt;br&gt;
your code. Wrap them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Confusing atomic with "fast."&lt;/strong&gt;&lt;br&gt;
Atomic is about all-or-nothing, not speed. A slow operation can still be atomic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Thinking one row is always safe but many rows aren't.&lt;/strong&gt;&lt;br&gt;
A single statement is usually atomic on its own. The danger shows up when &lt;strong&gt;one&lt;br&gt;
logical action needs multiple steps&lt;/strong&gt;. That's when you reach for a transaction.&lt;/p&gt;




&lt;h2&gt;
  
  
  Recap
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Atomic&lt;/strong&gt; = all of it, or none of it. No half-done state.&lt;/li&gt;
&lt;li&gt;Picture stapled pages: they move together or not at all.&lt;/li&gt;
&lt;li&gt;In databases, you get this with a &lt;strong&gt;transaction&lt;/strong&gt; (&lt;code&gt;BEGIN&lt;/code&gt; ... &lt;code&gt;COMMIT&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Use it whenever two or more changes must succeed together.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Your turn
&lt;/h2&gt;

&lt;p&gt;Find a place in your app where you write to the database twice for one action.&lt;br&gt;
Ask: "What if it crashes between the two writes?" If that scares you, wrap them&lt;br&gt;
in a transaction. Now go explain "stapled pages" to a friend.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>beginners</category>
    </item>
    <item>
      <title>A bot opened a pull request for me! and I finally "got" automation</title>
      <dc:creator>Mohamed Idris</dc:creator>
      <pubDate>Tue, 02 Jun 2026 03:42:49 +0000</pubDate>
      <link>https://dev.to/edriso/a-bot-opened-a-pull-request-for-me-and-i-finally-got-automation-203k</link>
      <guid>https://dev.to/edriso/a-bot-opened-a-pull-request-for-me-and-i-finally-got-automation-203k</guid>
      <description>&lt;p&gt;Today I added a tool called &lt;strong&gt;Renovate&lt;/strong&gt; to one of my projects. A few minutes later, something quietly magical happened: a bot opened a pull request for me, my tests ran themselves, and after I clicked one button, my app redeployed with the update.&lt;/p&gt;

&lt;p&gt;I didn't write a single line of code for any of that.&lt;/p&gt;

&lt;p&gt;That's the moment it clicked for me. There's a whole world of little robots that do the boring, repetitive parts of building software so you don't have to. Companies lean on them heavily. And once you see the pattern, you start spotting places to use them everywhere.&lt;/p&gt;

&lt;p&gt;This post is the friendly tour I wish I'd had. No deep jargon, I promise — and if I use a word, I'll explain it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The one idea behind all of them
&lt;/h2&gt;

&lt;p&gt;Every one of these tools, no matter how fancy it sounds, is built on the same simple idea:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;When &lt;em&gt;X&lt;/em&gt; happens, do &lt;em&gt;Y&lt;/em&gt;.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's it. Something happens (you push code, a clock hits 6am, a website goes down), and the bot does a task in response (runs your tests, sends a message, opens a fix). No human needed for the boring middle part.&lt;/p&gt;

&lt;p&gt;A nice way to picture it: imagine a tireless assistant who&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;watches&lt;/strong&gt; your project,&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;follows the rules&lt;/strong&gt; you set,&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;does the repetitive task&lt;/strong&gt;, and&lt;/li&gt;
&lt;li&gt;only &lt;strong&gt;taps you on the shoulder&lt;/strong&gt; when a real human decision is needed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's the whole genre. The differences are just &lt;em&gt;what&lt;/em&gt; they watch and &lt;em&gt;what&lt;/em&gt; they do.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Quick vocab, so nothing trips you up:&lt;br&gt;
&lt;strong&gt;PR (pull request)&lt;/strong&gt; = a proposed change to your code that you review and approve. &lt;strong&gt;CI/CD&lt;/strong&gt; = robots that automatically test and ship your code. &lt;strong&gt;Webhook&lt;/strong&gt; = a little "hey, something just happened!" ping one app sends to another.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Why companies are obsessed with these
&lt;/h2&gt;

&lt;p&gt;Because boring work is where humans make mistakes and lose time. Bots are good at exactly the things we're bad at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;They &lt;strong&gt;never forget&lt;/strong&gt; a step on the checklist.&lt;/li&gt;
&lt;li&gt;They &lt;strong&gt;never get tired&lt;/strong&gt;, and they work at 3am.&lt;/li&gt;
&lt;li&gt;They do the same job whether you have &lt;strong&gt;1 project or 1,000&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;They free people up to do the &lt;strong&gt;thinking&lt;/strong&gt; work instead of the chores.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A junior engineer with good automation can quietly do the work of a much bigger team. That's not hype — it's just leverage.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real use cases, across very different areas
&lt;/h2&gt;

&lt;p&gt;Here's where it gets fun. These bots aren't just one thing. Let me walk through genuinely different corners of the software world.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Keeping your code safe and up to date
&lt;/h3&gt;

&lt;p&gt;This is the one that started my "aha." The libraries your app depends on get updates all the time — bug fixes, new features, and importantly, &lt;strong&gt;security patches&lt;/strong&gt;. Staying current by hand is tedious and easy to forget.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Renovate&lt;/strong&gt; and &lt;strong&gt;Dependabot&lt;/strong&gt; watch for new versions, open a PR with the update, let your tests run on it, and wait for you to merge. &lt;strong&gt;Snyk&lt;/strong&gt; focuses on the scary stuff: it warns you when a library you use has a known security hole.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Think of it as a friend who reads every "version 2.4.1 is out" announcement so you never have to.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  2. Reviewing every change, automatically
&lt;/h3&gt;

&lt;p&gt;Good teams review each other's code. But humans forget things, and reviews take time. So bots help:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Codecov&lt;/strong&gt; tells you if your new code is actually covered by tests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SonarCloud&lt;/strong&gt; and &lt;strong&gt;CodeRabbit&lt;/strong&gt; read the change and leave comments about bugs, smells, or style.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitGuardian&lt;/strong&gt; screams if you accidentally committed a password or API key.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's like having a reviewer who never sleeps and never forgets the checklist — so the humans can focus on the interesting parts of the review.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Building, testing, and shipping (CI/CD)
&lt;/h3&gt;

&lt;p&gt;This is the backbone. You push code, and a robot &lt;strong&gt;builds it, runs all the tests, and deploys it&lt;/strong&gt; if everything's green. Tools: &lt;strong&gt;GitHub Actions&lt;/strong&gt;, &lt;strong&gt;GitLab CI&lt;/strong&gt;, &lt;strong&gt;CircleCI&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;On top of that, release bots like &lt;strong&gt;semantic-release&lt;/strong&gt; and &lt;strong&gt;release-please&lt;/strong&gt; read your commit messages, figure out the new version number, write the changelog, and tag the release — all by themselves.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;My own setup does this: I push to the main branch, the tests run, and if they pass, the app redeploys to my server. I haven't manually deployed anything in weeks.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  4. Talking to your team (alerts and "ChatOps")
&lt;/h3&gt;

&lt;p&gt;Software needs to tell humans things. Bots are the messengers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;UptimeRobot&lt;/strong&gt; and &lt;strong&gt;healthchecks.io&lt;/strong&gt; ping your sites and message you the moment one goes down.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PagerDuty&lt;/strong&gt; and &lt;strong&gt;Opsgenie&lt;/strong&gt; wake up the on-call engineer when something breaks at night.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Slack, Discord, and Telegram bots&lt;/strong&gt; post updates: a new signup, a failed payment, a daily summary.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Fun fact: I build &lt;strong&gt;Telegram bots&lt;/strong&gt; that send people a verse of the Quran every morning. That's exactly this category — a bot that does something useful on a schedule and talks to people. If you've ever made a Discord bot, you've already lived here.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Tidying up your issues and project board
&lt;/h3&gt;

&lt;p&gt;Open-source projects and busy teams drown in issues and tasks. Bots keep things tidy:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;stale bot&lt;/strong&gt; politely closes issues nobody has replied to in months.&lt;/li&gt;
&lt;li&gt;Triage bots &lt;strong&gt;auto-label&lt;/strong&gt; new issues ("bug", "documentation") and assign them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Linear&lt;/strong&gt; and &lt;strong&gt;Jira&lt;/strong&gt; automations move a card to "Done" the moment its PR is merged.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Small things, but they save hours of clicking every week.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Infrastructure on autopilot (GitOps)
&lt;/h3&gt;

&lt;p&gt;Here's a wilder one. Instead of clicking around a cloud dashboard to set up servers, you &lt;strong&gt;describe&lt;/strong&gt; your infrastructure in a file. Then a bot makes the real world match the file.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Terraform + Atlantis&lt;/strong&gt;: you open a PR that changes your infrastructure, and a bot shows exactly what will change before you approve it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ArgoCD&lt;/strong&gt; / &lt;strong&gt;Flux&lt;/strong&gt;: whatever's in your Git repo &lt;em&gt;is&lt;/em&gt; what's running, always. Change the file, the cluster updates itself.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The big idea: your servers are described in code, and a robot keeps reality in sync. Fewer "it works on my machine" surprises.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Connecting apps with zero code
&lt;/h3&gt;

&lt;p&gt;Not everything needs to be programmer-y. Tools like &lt;strong&gt;Zapier&lt;/strong&gt;, &lt;strong&gt;Make&lt;/strong&gt;, &lt;strong&gt;n8n&lt;/strong&gt;, and &lt;strong&gt;IFTTT&lt;/strong&gt; let you wire apps together by dragging boxes around:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;New Google Form submission → add a row to a spreadsheet → send a welcome email.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;No coding. This is huge for small businesses and side projects, and honestly even devs use it for quick wins instead of writing a whole script.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bonus: the new wave — AI agents
&lt;/h3&gt;

&lt;p&gt;The newest members of this family use AI to do fuzzier work: reviewing a PR in plain English, drafting a fix, triaging a bug report, or answering "why is this failing?" They're early and not magic, but they're the same old pattern — &lt;em&gt;watch, decide, act&lt;/em&gt; — with a smarter brain in the middle. Worth keeping an eye on.&lt;/p&gt;

&lt;h2&gt;
  
  
  So how do they actually work? (the honest, simple version)
&lt;/h2&gt;

&lt;p&gt;Under the hood, almost all of them start from one of two triggers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;An event&lt;/strong&gt; — something happens and an app gets a &lt;strong&gt;webhook&lt;/strong&gt; ping. "Someone just pushed code." "A new issue was opened." The bot wakes up and reacts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A schedule&lt;/strong&gt; — a clock. "Every hour, check for new versions." "Every morning at 6am, send the report." (Programmers call this a &lt;strong&gt;cron job&lt;/strong&gt;.)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Then the bot uses an &lt;strong&gt;API&lt;/strong&gt; (a way for programs to talk to each other) to do the actual task — open a PR, post a message, restart a server.&lt;/p&gt;

&lt;p&gt;On GitHub, many of these are &lt;strong&gt;"GitHub Apps"&lt;/strong&gt; you install with a click and give specific permissions to. That's exactly what I did with Renovate: install, point it at my repos, done.&lt;/p&gt;

&lt;h2&gt;
  
  
  You can build these too (you might already have)
&lt;/h2&gt;

&lt;p&gt;Here's the encouraging part: this is not wizard stuff. If you've ever:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;written a script that runs on a schedule, or&lt;/li&gt;
&lt;li&gt;made a Telegram/Discord bot, or&lt;/li&gt;
&lt;li&gt;set up a GitHub Action,&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;…you've already built an automation bot. The mental model is the whole skill. The tools are just details you look up when you need them.&lt;/p&gt;

&lt;p&gt;Start tiny. Pick &lt;strong&gt;one&lt;/strong&gt; annoying thing you do by hand every week, and ask: &lt;em&gt;could a "when X, do Y" robot do this?&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Ideas to spark your next project
&lt;/h2&gt;

&lt;p&gt;A few buildable ones, from "an afternoon" to "a real product":&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A bot that posts your app's &lt;strong&gt;daily signups&lt;/strong&gt; to a Discord channel each morning.&lt;/li&gt;
&lt;li&gt;A scheduled job that &lt;strong&gt;backs up your database&lt;/strong&gt; and messages you if the backup fails.&lt;/li&gt;
&lt;li&gt;A PR bot that comments &lt;strong&gt;"hey, you forgot to update the changelog."&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;A bot that &lt;strong&gt;checks all your websites are up&lt;/strong&gt; and texts you if one isn't.&lt;/li&gt;
&lt;li&gt;A friendly &lt;strong&gt;"welcome!"&lt;/strong&gt; bot that greets first-time contributors on your open-source repo.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;"stale PR"&lt;/strong&gt; nudger that pings you about pull requests sitting untouched for a week.&lt;/li&gt;
&lt;li&gt;A no-code &lt;strong&gt;Zapier&lt;/strong&gt; flow: new customer in Stripe → add them to your mailing list → say hi.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The takeaway
&lt;/h2&gt;

&lt;p&gt;These tools aren't magic. They're just &lt;strong&gt;patient&lt;/strong&gt;. They do the small, repetitive, easy-to-forget tasks so you can spend your energy on the parts that actually need a human brain.&lt;/p&gt;

&lt;p&gt;Once you start noticing the chores in your own workflow — updating dependencies, deploying, sending the same message, checking the same dashboard — you'll see automation opportunities everywhere.&lt;/p&gt;

&lt;p&gt;My advice? Pick the most boring thing you did this week, and let a robot do it next week. That first "it worked while I was making tea" moment is genuinely delightful. ☕&lt;/p&gt;




&lt;p&gt;&lt;em&gt;If you found this useful, take a moment and think of a boring task you want to automate first.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>automation</category>
      <category>devops</category>
      <category>productivity</category>
      <category>beginners</category>
    </item>
    <item>
      <title>"Idempotent": The Scary Word That Means "Press It Again, It's Fine"</title>
      <dc:creator>Mohamed Idris</dc:creator>
      <pubDate>Mon, 01 Jun 2026 11:30:00 +0000</pubDate>
      <link>https://dev.to/edriso/idempotent-the-scary-word-that-means-press-it-again-its-fine-4k28</link>
      <guid>https://dev.to/edriso/idempotent-the-scary-word-that-means-press-it-again-its-fine-4k28</guid>
      <description>&lt;p&gt;You click &lt;strong&gt;Pay Now&lt;/strong&gt;. The page hangs. Did it work? You don't know. So you click&lt;br&gt;
it again. And now you're sweating, because what if you just paid twice?&lt;/p&gt;

&lt;p&gt;That little moment of fear is exactly the problem one fancy word solves. The word&lt;br&gt;
is &lt;strong&gt;idempotent&lt;/strong&gt;. It sounds like a spell from a wizard book, but the idea is&lt;br&gt;
simple and you already understand it from real life.&lt;/p&gt;


&lt;h2&gt;
  
  
  The idea in one line
&lt;/h2&gt;

&lt;p&gt;An action is &lt;strong&gt;idempotent&lt;/strong&gt; if doing it once or doing it ten times leaves the&lt;br&gt;
world in the &lt;strong&gt;same state&lt;/strong&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  The metaphor: a light switch vs a counter
&lt;/h2&gt;

&lt;p&gt;Think about two buttons.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ELEVATOR "UP" BUTTON              A TALLY COUNTER
press once  -&amp;gt; light on          press once  -&amp;gt; 1
press again -&amp;gt; still on          press again -&amp;gt; 2
press 50x   -&amp;gt; still on          press 50x   -&amp;gt; 50
   = IDEMPOTENT                      = NOT idempotent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pressing the elevator button again does nothing new. The button is already lit,&lt;br&gt;
the elevator is already coming. That extra press is harmless. &lt;strong&gt;That&lt;/strong&gt; is&lt;br&gt;
idempotent.&lt;/p&gt;

&lt;p&gt;The tally counter is the opposite. Every press changes the result. Pressing it&lt;br&gt;
again is never safe if you only meant to count once.&lt;/p&gt;

&lt;p&gt;So when someone says "make this endpoint idempotent," they mean: &lt;strong&gt;make it like&lt;br&gt;
the elevator button, not the tally counter.&lt;/strong&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Where you actually meet this: HTTP
&lt;/h2&gt;

&lt;p&gt;HTTP methods are a classic example. Some are idempotent by design.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET    /users/7      read it        -&amp;gt; idempotent (reading never changes anything)
PUT    /users/7      set name="Al"  -&amp;gt; idempotent (set to the same value = same result)
DELETE /users/7      remove user 7  -&amp;gt; idempotent (gone once, gone forever)
POST   /users        create a user  -&amp;gt; NOT idempotent (each call makes a NEW user)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See &lt;code&gt;PUT&lt;/code&gt;? "Set the name to Al" gives the same result whether you call it once or&lt;br&gt;
five times. The name is just Al at the end. But &lt;code&gt;POST&lt;/code&gt; to create a user? Call it&lt;br&gt;
five times and you get five users. Oops.&lt;/p&gt;

&lt;p&gt;That's why a flaky network plus a &lt;code&gt;POST&lt;/code&gt; is the scary "did I pay twice?" combo.&lt;/p&gt;


&lt;h2&gt;
  
  
  The fix: an idempotency key
&lt;/h2&gt;

&lt;p&gt;Real payment APIs (like Stripe) solve this with an &lt;strong&gt;idempotency key&lt;/strong&gt;. You make&lt;br&gt;
up a unique id for the action and send it along:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// What a junior might write first&lt;/span&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="s2"&gt;/charge&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;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="c1"&gt;// retry on timeout -&amp;gt; might charge twice. yikes.&lt;/span&gt;

&lt;span class="c1"&gt;// The fix: send a key that names THIS one attempt&lt;/span&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="s2"&gt;/charge&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;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Idempotency-Key&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;order-42-attempt&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="c1"&gt;// same key on every retry&lt;/span&gt;
  &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2000&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;Now the server has a rule: "If I already saw &lt;code&gt;order-42-attempt&lt;/code&gt;, don't charge&lt;br&gt;
again. Just return the result from last time." Retry as much as you want. One&lt;br&gt;
charge. The button is now an elevator button.&lt;/p&gt;




&lt;h2&gt;
  
  
  A real case you've probably hit
&lt;/h2&gt;

&lt;p&gt;Webhooks. A service like GitHub or Stripe sends your server a message ("payment&lt;br&gt;
succeeded!"). Networks being networks, they sometimes send the &lt;strong&gt;same&lt;/strong&gt; message&lt;br&gt;
twice to be safe. If your handler is idempotent, the duplicate does no harm. If&lt;br&gt;
it isn't, you might email the customer twice or ship two boxes.&lt;/p&gt;

&lt;p&gt;The senior move: check "have I already handled event &lt;code&gt;evt_123&lt;/code&gt;?" before doing&lt;br&gt;
the work.&lt;/p&gt;




&lt;h2&gt;
  
  
  Gotchas juniors hit
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Thinking idempotent means "returns the same response."&lt;/strong&gt;&lt;br&gt;
Not quite. It means the &lt;strong&gt;state&lt;/strong&gt; ends up the same. A second &lt;code&gt;DELETE&lt;/code&gt; might&lt;br&gt;
return &lt;code&gt;404 Not Found&lt;/code&gt; instead of &lt;code&gt;200 OK&lt;/code&gt;, and that's fine. The user is still&lt;br&gt;
deleted. Same world.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Assuming &lt;code&gt;POST&lt;/code&gt; can never be safe.&lt;/strong&gt;&lt;br&gt;
It can, with an idempotency key. The method isn't magic; your design is.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Forgetting reads can have side effects.&lt;/strong&gt;&lt;br&gt;
A &lt;code&gt;GET&lt;/code&gt; that secretly bumps a "view count" is no longer truly idempotent. Keep&lt;br&gt;
reads clean.&lt;/p&gt;




&lt;h2&gt;
  
  
  Recap
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Idempotent&lt;/strong&gt; = doing it again changes nothing new. Like an elevator button.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not idempotent&lt;/strong&gt; = each call adds up. Like a tally counter, or &lt;code&gt;POST /users&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;It's about the final &lt;strong&gt;state&lt;/strong&gt;, not the exact response text.&lt;/li&gt;
&lt;li&gt;Make risky actions safe with an &lt;strong&gt;idempotency key&lt;/strong&gt; so retries can't double up.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Your turn
&lt;/h2&gt;

&lt;p&gt;Look at the last form you built. If a user double-clicks submit on a slow&lt;br&gt;
connection, what happens? If the answer is "two records," you found a spot that&lt;br&gt;
wants idempotency. How would you fix it?&lt;/p&gt;

&lt;p&gt;If you can explain "elevator button vs tally counter" to a friend, you've got it.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>beginners</category>
    </item>
    <item>
      <title>SSH Keys Easily Explained</title>
      <dc:creator>Mohamed Idris</dc:creator>
      <pubDate>Mon, 01 Jun 2026 09:30:00 +0000</pubDate>
      <link>https://dev.to/edriso/ssh-keys-easily-explained-2573</link>
      <guid>https://dev.to/edriso/ssh-keys-easily-explained-2573</guid>
      <description>&lt;p&gt;You signed up for a hosting service. You're ready to deploy your app. Then a box&lt;br&gt;
pops up: &lt;strong&gt;"Paste your SSH public key."&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And you freeze. What key? Where is it? Is it safe to paste? Did I just leak&lt;br&gt;
something I shouldn't?&lt;/p&gt;

&lt;p&gt;Take a breath. By the end of this post you'll know exactly what an SSH key is,&lt;br&gt;
why there are two of them, and what to paste (and what to never, ever paste).&lt;br&gt;
You'll get it so well you could teach a friend.&lt;/p&gt;


&lt;h2&gt;
  
  
  The idea in one line
&lt;/h2&gt;

&lt;p&gt;An SSH key is a pair of files that lets you prove who you are to a server,&lt;br&gt;
&lt;strong&gt;without typing a password&lt;/strong&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  The metaphor: a padlock and its only key
&lt;/h2&gt;

&lt;p&gt;Think of a &lt;strong&gt;public key&lt;/strong&gt; as a padlock. You can make a thousand copies of it and&lt;br&gt;
hand them out to anyone. Servers, friends, GitHub, your hosting provider. It's&lt;br&gt;
fine. A padlock locked shut is useless to a stranger.&lt;/p&gt;

&lt;p&gt;Think of the &lt;strong&gt;private key&lt;/strong&gt; as the one real key that opens those padlocks.&lt;br&gt;
There is only one, it lives on your computer, and you never give it away. Ever.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PUBLIC KEY  =  a padlock        -&amp;gt; share it freely
PRIVATE KEY =  the only key     -&amp;gt; keep it secret, keep it safe
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So when a server wants to know "are you really you?", it puts a message inside a&lt;br&gt;
box, locks it with your padlock (public key), and tosses it over. Only your real&lt;br&gt;
key (private key) can open it. You open it, prove you can, and you're in.&lt;/p&gt;

&lt;p&gt;The magic part: &lt;strong&gt;your private key never leaves your machine.&lt;/strong&gt; The server only&lt;br&gt;
ever sees the padlock.&lt;/p&gt;


&lt;h2&gt;
  
  
  How it actually works (the short version)
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You                                  Server
 |                                      |
 | "Hi, I'm Alex"     ----------------&amp;gt; |
 |                                      |  finds your padlock (public key)
 |                                      |  locks a random message with it
 | &amp;lt;----------------  here's a puzzle   |
 |                                      |
 | unlock it with my                    |
 | private key, send proof  ----------&amp;gt; |
 |                                      |  proof checks out
 | &amp;lt;----------------  welcome in!       |
 |                                      |
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;You never send your private key across the internet. You only send &lt;strong&gt;proof&lt;/strong&gt; that&lt;br&gt;
you own it. That's why SSH keys are way safer than passwords. A password gets&lt;br&gt;
typed and sent; a private key just stays home and answers puzzles.&lt;/p&gt;


&lt;h2&gt;
  
  
  Making your keys (the part you actually do)
&lt;/h2&gt;

&lt;p&gt;Open a terminal and run this one command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh-keygen &lt;span class="nt"&gt;-t&lt;/span&gt; ed25519 &lt;span class="nt"&gt;-C&lt;/span&gt; &lt;span class="s2"&gt;"you@example.com"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ssh-keygen&lt;/code&gt; is the tool that makes the key pair.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-t ed25519&lt;/code&gt; picks a modern, strong key type. (If a service complains it's too
old to support it, use &lt;code&gt;-t rsa -b 4096&lt;/code&gt; instead.)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-C "..."&lt;/code&gt; is just a label, usually your email, so you remember whose key it is.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It will ask where to save and for an optional passphrase. Press Enter to accept&lt;br&gt;
the defaults. When it's done, you have &lt;strong&gt;two new files&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;~/.ssh/id_ed25519        &amp;lt;- PRIVATE key. secret. never share.
~/.ssh/id_ed25519.pub    &amp;lt;- PUBLIC key. the .pub one is safe to share.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See that &lt;code&gt;.pub&lt;/code&gt;? That tiny detail saves people. &lt;strong&gt;The file ending in &lt;code&gt;.pub&lt;/code&gt; is&lt;br&gt;
the public one.&lt;/strong&gt; That is the one you paste into hosting dashboards.&lt;/p&gt;


&lt;h2&gt;
  
  
  "The host wants my SSH key": what to actually paste
&lt;/h2&gt;

&lt;p&gt;When a hosting service, GitHub, or a server asks for "your SSH key," they almost&lt;br&gt;
always mean your &lt;strong&gt;public&lt;/strong&gt; key. Here's how to grab it safely:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; ~/.ssh/id_ed25519.pub
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll see something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAID...a bunch of characters... you@example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy that whole line and paste it into the box. Done. That's the padlock. It is&lt;br&gt;
&lt;strong&gt;meant&lt;/strong&gt; to be shared, so pasting it is totally safe.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The box says "SSH key"?
        |
        v
Paste the file that ends in  .pub      [ OK ]   yes
Paste the file with NO .pub            [STOP]   NEVER (that's your private key)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you ever open a file and the very first line says&lt;br&gt;
&lt;code&gt;-----BEGIN OPENSSH PRIVATE KEY-----&lt;/code&gt;, &lt;strong&gt;stop&lt;/strong&gt;. That's the private one. Close it&lt;br&gt;
and grab the &lt;code&gt;.pub&lt;/code&gt; file instead.&lt;/p&gt;


&lt;h2&gt;
  
  
  A real case: deploying with &lt;code&gt;git push&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Say you set up your public key on your hosting provider. Now you can do this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git push production main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No password prompt. No "enter your credentials." It just works, because your&lt;br&gt;
machine quietly proves it owns the matching private key. That smooth, password-free&lt;br&gt;
deploy you've seen senior devs do? This is the whole trick.&lt;/p&gt;

&lt;p&gt;Same thing with connecting to a server directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh user@your-server.com
&lt;span class="c"&gt;# you're in, no password typed&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Gotchas juniors hit
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Pasting the private key by mistake.&lt;/strong&gt;&lt;br&gt;
If you ever paste a key and it starts with &lt;code&gt;-----BEGIN ... PRIVATE KEY-----&lt;/code&gt;, you&lt;br&gt;
pasted the wrong file. Treat that key as burned: generate a new pair and replace&lt;br&gt;
it everywhere.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Thinking you need a new key for every service.&lt;/strong&gt;&lt;br&gt;
You don't. One public key can go on GitHub, your host, and ten servers at once.&lt;br&gt;
It's a padlock. Copies are fine.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Wrong file permissions.&lt;/strong&gt;&lt;br&gt;
SSH is picky for your safety. If it refuses your key, tighten the permissions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;chmod &lt;/span&gt;600 ~/.ssh/id_ed25519        &lt;span class="c"&gt;# private key: only you can read it&lt;/span&gt;
&lt;span class="nb"&gt;chmod &lt;/span&gt;644 ~/.ssh/id_ed25519.pub    &lt;span class="c"&gt;# public key: readable is fine&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4. Forgetting to back up the private key.&lt;/strong&gt;&lt;br&gt;
If you wipe your laptop without saving &lt;code&gt;~/.ssh/&lt;/code&gt;, that key is gone. You're not&lt;br&gt;
locked out forever (just make a new pair and re-add the public key everywhere),&lt;br&gt;
but it's annoying. Keep a safe backup.&lt;/p&gt;




&lt;h2&gt;
  
  
  Recap
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;An SSH key is a &lt;strong&gt;pair&lt;/strong&gt;: a public key (padlock) and a private key (the only key).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Share the public key freely.&lt;/strong&gt; It's the file ending in &lt;code&gt;.pub&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Never share the private key.&lt;/strong&gt; It stays on your machine and just answers puzzles.&lt;/li&gt;
&lt;li&gt;When a host asks for "your SSH key," paste the &lt;strong&gt;&lt;code&gt;.pub&lt;/code&gt;&lt;/strong&gt; file. That's it.&lt;/li&gt;
&lt;li&gt;Result: secure, password-free logins and deploys.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Your turn
&lt;/h2&gt;

&lt;p&gt;Run &lt;code&gt;ssh-keygen -t ed25519&lt;/code&gt; on your machine, then run&lt;br&gt;
&lt;code&gt;cat ~/.ssh/id_ed25519.pub&lt;/code&gt;. Look at the two files you made. Which one would you&lt;br&gt;
paste into a hosting dashboard, and which one would you guard with your life?&lt;/p&gt;

&lt;p&gt;If you can answer that out loud, you've got it. Now go teach a friend.&lt;/p&gt;

</description>
      <category>ssh</category>
      <category>learning</category>
    </item>
    <item>
      <title>Part 14: Window Functions (Ninja Mode)</title>
      <dc:creator>Mohamed Idris</dc:creator>
      <pubDate>Fri, 29 May 2026 17:48:42 +0000</pubDate>
      <link>https://dev.to/edriso/part-14-window-functions-ninja-mode-4ah9</link>
      <guid>https://dev.to/edriso/part-14-window-functions-ninja-mode-4ah9</guid>
      <description>&lt;p&gt;&lt;em&gt;This post is part of the SQL: Zero to Ninja series.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Your boss asks: "Show me each user's orders, and next to every order put its rank, like their 1st order, 2nd order, 3rd, by total." You reach for &lt;code&gt;GROUP BY&lt;/code&gt;... and hit a wall. &lt;code&gt;GROUP BY&lt;/code&gt; squashes all of a user's orders into one row. But you wanted to keep every order AND add a rank. You need both. That is exactly what window functions do, and they are the move that turns you into a SQL ninja.&lt;/p&gt;

&lt;h2&gt;
  
  
  The idea in one line
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;window function&lt;/strong&gt; computes a value across a group of rows (a "window") while &lt;strong&gt;keeping every single row&lt;/strong&gt;, unlike &lt;code&gt;GROUP BY&lt;/code&gt;, which collapses them into one.&lt;/p&gt;

&lt;h2&gt;
  
  
  The metaphor: the bakery queue
&lt;/h2&gt;

&lt;p&gt;You are standing in line at the bakery. A little screen says you are customer &lt;strong&gt;number 4&lt;/strong&gt;. You can see your position in the line. But here is the thing: you are still &lt;strong&gt;you&lt;/strong&gt;, still standing there as yourself. You did not get blended into "the line." You kept your identity and also got a number.&lt;/p&gt;

&lt;p&gt;That is a window function. Every row stays itself, and you bolt on extra info computed from the rows around it (your position, the running total, the person before you).&lt;/p&gt;

&lt;p&gt;&lt;code&gt;GROUP BY&lt;/code&gt; is the opposite. It is like the baker saying "I do not care about individuals, there are 12 people total." Twelve people become one number. Useful sometimes, but you lost everybody.&lt;/p&gt;

&lt;h2&gt;
  
  
  The shape: OVER (PARTITION BY ... ORDER BY ...)
&lt;/h2&gt;

&lt;p&gt;A window function always has an &lt;code&gt;OVER (...)&lt;/code&gt; clause. That is what makes it a window function.&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="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;ROW_NUMBER&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;OVER&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;PARTITION&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;user_id&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;total&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;rank_in_user&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Read &lt;code&gt;OVER (...)&lt;/code&gt; in plain English:&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;PARTITION&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;user_id&lt;/span&gt;   &lt;span class="c1"&gt;--&amp;gt;  split rows into one queue per user&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;total&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;     &lt;span class="c1"&gt;--&amp;gt;  inside each queue, line them up biggest first&lt;/span&gt;
&lt;span class="n"&gt;ROW_NUMBER&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;            &lt;span class="c1"&gt;--&amp;gt;  hand each row its position number&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;PARTITION BY&lt;/code&gt; is like having a separate bakery line per user. &lt;code&gt;ORDER BY&lt;/code&gt; decides who stands where. No &lt;code&gt;PARTITION BY&lt;/code&gt;? Then it is one big single line for the whole table.&lt;/p&gt;

&lt;h2&gt;
  
  
  Numbering rows: ROW_NUMBER, RANK, DENSE_RANK
&lt;/h2&gt;

&lt;p&gt;These three all number rows, but they treat &lt;strong&gt;ties&lt;/strong&gt; differently. Say two orders have the same total of 100.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;total   ROW_NUMBER   RANK   DENSE_RANK
 150        1          1         1
 100        2          2         2
 100        3          2         2
  80        4          4         3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ROW_NUMBER()&lt;/strong&gt;: always 1, 2, 3, 4. No ties allowed, it just picks an order. Great for "give me exactly one row each."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RANK()&lt;/strong&gt;: ties share a number, then it &lt;strong&gt;skips&lt;/strong&gt; ahead (1, 2, 2, 4). Like the Olympics, two silvers and no bronze.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DENSE_RANK()&lt;/strong&gt;: ties share a number, but it does &lt;strong&gt;not&lt;/strong&gt; skip (1, 2, 2, 3). No gap.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pick &lt;code&gt;ROW_NUMBER&lt;/code&gt; when you need a unique number, &lt;code&gt;RANK&lt;/code&gt;/&lt;code&gt;DENSE_RANK&lt;/code&gt; when ties should genuinely tie.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running totals with SUM() OVER
&lt;/h2&gt;

&lt;p&gt;Add &lt;code&gt;ORDER BY&lt;/code&gt; inside the window and &lt;code&gt;SUM&lt;/code&gt; becomes a &lt;strong&gt;running total&lt;/strong&gt; (each row adds itself to everything before it):&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="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;OVER&lt;/span&gt; &lt;span class="p"&gt;(&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="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;running_total&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;id  total   running_total
 1    50         50
 2    30         80     (50 + 30)
 3    20        100     (80 + 20)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every row is still here, and now each one knows the total so far. Try doing that with &lt;code&gt;GROUP BY&lt;/code&gt;. You cannot, because &lt;code&gt;GROUP BY&lt;/code&gt; would have crushed these into one row.&lt;/p&gt;

&lt;h2&gt;
  
  
  Peeking at neighbors: LAG and LEAD
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;LAG()&lt;/code&gt; looks at the &lt;strong&gt;previous&lt;/strong&gt; row, &lt;code&gt;LEAD()&lt;/code&gt; looks at the &lt;strong&gt;next&lt;/strong&gt; one. Perfect for "compare this order to the user's last order."&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="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;LAG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;OVER&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;PARTITION&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;user_id&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="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;previous_total&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;user_id  total   previous_total
   7       50         NULL    (first order, nobody before)
   7       80         50      (look back one row)
   7       60         80
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now subtract &lt;code&gt;total - previous_total&lt;/code&gt; and you instantly see if a user is spending more or less than last time.&lt;/p&gt;

&lt;h2&gt;
  
  
  The killer real case: top 3 orders per user
&lt;/h2&gt;

&lt;p&gt;Here is the request from the top of the post: rank each user's orders, biggest first. &lt;code&gt;ROW_NUMBER&lt;/code&gt; with &lt;code&gt;PARTITION BY&lt;/code&gt; nails it:&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="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;ROW_NUMBER&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;OVER&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;PARTITION&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;user_id&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;total&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;rn&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Same trick ranks products by price inside each category:&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="n"&gt;category&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;ROW_NUMBER&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;OVER&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;PARTITION&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;category&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;price&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;price_rank&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;products&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice the difference from &lt;code&gt;GROUP BY&lt;/code&gt;:&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;GROUP&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;category&lt;/span&gt;       &lt;span class="c1"&gt;--&amp;gt;  ONE row per category (you lose the products)&lt;/span&gt;
&lt;span class="n"&gt;ROW_NUMBER&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;OVER&lt;/span&gt; &lt;span class="p"&gt;(...)&lt;/span&gt; &lt;span class="c1"&gt;--&amp;gt;  EVERY product stays, plus a rank column&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is the whole point. The window keeps everybody and adds a column.&lt;/p&gt;

&lt;h2&gt;
  
  
  Gotcha: you cannot filter a window result in WHERE
&lt;/h2&gt;

&lt;p&gt;This is the big one. Window functions run &lt;strong&gt;after&lt;/strong&gt; &lt;code&gt;WHERE&lt;/code&gt;. So you cannot say &lt;code&gt;WHERE price_rank &amp;lt;= 3&lt;/code&gt;, the rank does not exist yet when &lt;code&gt;WHERE&lt;/code&gt; runs.&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="c1"&gt;-- WRONG: price_rank is not known during WHERE&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;ROW_NUMBER&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;OVER&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;PARTITION&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;category&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;price&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;price_rank&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;products&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;price_rank&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;-- error!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The fix is to wrap it in a subquery or a CTE (remember Part 10?), then filter on the outside:&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="c1"&gt;-- RIGHT: compute the rank inside, filter it outside&lt;/span&gt;
&lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="n"&gt;ranked&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ROW_NUMBER&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;OVER&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;PARTITION&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;category&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;price&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;price_rank&lt;/span&gt;
  &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;products&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;ranked&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;price_rank&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;-- now it works, the column exists out here&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That CTE wrapper is the standard "top N per group" pattern. Memorize it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Gotchas juniors hit
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Filtering on a window in WHERE.&lt;/strong&gt; It is not there yet. Wrap it in a CTE or subquery and filter outside.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Forgetting PARTITION BY.&lt;/strong&gt; Without it, your "rank per user" becomes "rank across the whole table." The partition is what resets the count for each group.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mixing up RANK and DENSE_RANK on ties.&lt;/strong&gt; &lt;code&gt;RANK&lt;/code&gt; leaves gaps (1, 2, 2, 4), &lt;code&gt;DENSE_RANK&lt;/code&gt; does not (1, 2, 2, 3). Pick on purpose.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Recap
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;window function&lt;/strong&gt; keeps every row and adds a value computed from nearby rows. &lt;code&gt;GROUP BY&lt;/code&gt; collapses rows; windows do not.&lt;/li&gt;
&lt;li&gt;Shape: &lt;code&gt;function OVER (PARTITION BY ... ORDER BY ...)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ROW_NUMBER&lt;/code&gt;, &lt;code&gt;RANK&lt;/code&gt;, &lt;code&gt;DENSE_RANK&lt;/code&gt; number rows and differ on ties. &lt;code&gt;SUM() OVER (ORDER BY ...)&lt;/code&gt; gives running totals. &lt;code&gt;LAG&lt;/code&gt;/&lt;code&gt;LEAD&lt;/code&gt; peek at neighbors.&lt;/li&gt;
&lt;li&gt;"Top N per group" = &lt;code&gt;ROW_NUMBER()&lt;/code&gt; inside a CTE, then filter in the outer &lt;code&gt;WHERE&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Windows run &lt;strong&gt;after&lt;/strong&gt; &lt;code&gt;WHERE&lt;/code&gt;, so filter their results in a wrapper, not in &lt;code&gt;WHERE&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Your turn
&lt;/h2&gt;

&lt;p&gt;Write a query that gives each user only their &lt;strong&gt;single most expensive order&lt;/strong&gt; (use &lt;code&gt;ROW_NUMBER()&lt;/code&gt; and a CTE wrapper). Which column do you &lt;code&gt;PARTITION BY&lt;/code&gt;, and what do you keep where &lt;code&gt;rn = 1&lt;/code&gt;? Explain it to a friend and the ninja headband is yours.&lt;/p&gt;




&lt;p&gt;And that is the series. You went from "what even is a database" all the way to window functions, the stuff a lot of working devs still find scary. You can query, filter, join, group, change data safely, model relationships, use subqueries and CTEs, index for speed, wrap things in transactions, block SQL injection, and now slice data with windows. That is a real, job-ready SQL toolkit.&lt;/p&gt;

&lt;p&gt;So go build something. A tiny dashboard, a leaderboard, a "top products" report, anything that makes you write real queries against real data. That is how it sticks. Want to revisit a topic or share the series with a friend? Head back to the &lt;a href="//00-sql-series-README.md"&gt;README&lt;/a&gt; for the full roadmap. Congratulations, ninja. You finished.&lt;/p&gt;

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