<?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: Zack Grooms</title>
    <description>The latest articles on DEV Community by Zack Grooms (@grooms_nicholas).</description>
    <link>https://dev.to/grooms_nicholas</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%2F1405986%2F39bcbddb-89e0-4b2f-af22-f295c33ec6d6.png</url>
      <title>DEV Community: Zack Grooms</title>
      <link>https://dev.to/grooms_nicholas</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/grooms_nicholas"/>
    <language>en</language>
    <item>
      <title>CountIQ: A Systems Notebook on Real-World Backend Engineering</title>
      <dc:creator>Zack Grooms</dc:creator>
      <pubDate>Sun, 15 Feb 2026 18:00:06 +0000</pubDate>
      <link>https://dev.to/grooms_nicholas/countiq-a-systems-notebook-on-real-world-backend-engineering-1nei</link>
      <guid>https://dev.to/grooms_nicholas/countiq-a-systems-notebook-on-real-world-backend-engineering-1nei</guid>
      <description>&lt;p&gt;This is a developer notebook documenting what building a real backend is teaching me about invariants, state transitions, concurrency, and system design. No fluff — just real architecture lessons from building CountIQ.&lt;/p&gt;

&lt;p&gt;I didn’t build CountIQ to ship a product.&lt;br&gt;
I built it to understand what actually happens inside a backend.&lt;/p&gt;

&lt;p&gt;Not in theory.&lt;br&gt;
In reality — with state, invariants, race conditions, and deployment in mind.&lt;/p&gt;

&lt;p&gt;This post isn’t a tutorial.&lt;br&gt;
It’s a developer notebook.&lt;/p&gt;

&lt;p&gt;I’m documenting what building a real system is teaching me about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;modeling state instead of writing endpoints&lt;/li&gt;
&lt;li&gt;aligning database constraints with domain rules&lt;/li&gt;
&lt;li&gt;preventing race conditions through transaction boundaries&lt;/li&gt;
&lt;li&gt;why most backend bugs are invariant bugs, not syntax bugs&lt;/li&gt;
&lt;li&gt;and how a simple service evolves into something deployable&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;CountIQ started as a small inventory backend.&lt;br&gt;
But it quickly became a controlled environment for learning system design the hard way — by building, breaking, and fixing a real system.&lt;/p&gt;

&lt;p&gt;If you’re learning backend engineering and want to see how a system evolves layer by layer — architecture, logging, concurrency, and deployment — this series is for you.&lt;/p&gt;

&lt;p&gt;No frameworks magic.&lt;br&gt;
No hand-wavy abstractions.&lt;/p&gt;

&lt;p&gt;Just the mental models and design decisions that actually make a backend stable.&lt;/p&gt;


&lt;h2&gt;
  
  
  1. Core System Model
&lt;/h2&gt;

&lt;p&gt;CountIQ is modeled as a state machine.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
S = Map[id → item]
S' = f(S, input)

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Translation
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;S → current system state
&lt;/li&gt;
&lt;li&gt;input → request
&lt;/li&gt;
&lt;li&gt;f → transition logic
&lt;/li&gt;
&lt;li&gt;S' → new system state
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every endpoint is a state transition.&lt;/p&gt;

&lt;p&gt;If validation fails:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
S' = S

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

&lt;/div&gt;



&lt;p&gt;State must remain unchanged.&lt;/p&gt;




&lt;h2&gt;
  
  
  State Visualization
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
Current State (S)
{
"1": milk,
"2": eggs
}

&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;request
  ↓
&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;
Apply transition f(S, input)

&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;  ↓
&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;
New State (S')
{
"1": milk,
"2": eggs,
"3": bread
}

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

&lt;/div&gt;






&lt;h2&gt;
  
  
  2. Architecture
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
interface
↓
transport
↓
service
↓
domain
↓
database

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Layer Responsibilities
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Transport&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;parse request
&lt;/li&gt;
&lt;li&gt;no business logic
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Service&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;orchestrate mutation
&lt;/li&gt;
&lt;li&gt;enforce boundaries
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Domain&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;validate invariants
&lt;/li&gt;
&lt;li&gt;normalize input
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Database&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;persistence
&lt;/li&gt;
&lt;li&gt;final authority
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  3. Mutation Pipeline
&lt;/h2&gt;

&lt;p&gt;All mutations follow one path:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
read → validate → commit

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Diagram
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
Request
↓
Read state
↓
Validate invariants
↓
Commit transaction
↓
Return response

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

&lt;/div&gt;



&lt;p&gt;If validation fails:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
no commit
state unchanged

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

&lt;/div&gt;






&lt;h2&gt;
  
  
  4. Bug Refurbishment
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Global vs Per-Owner Uniqueness
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Original constraint
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
name UNIQUE

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Observed behavior
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
User A → create milk → OK
User B → create milk → rejected

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

&lt;/div&gt;



&lt;p&gt;System enforced:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;name globally unique&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This was incorrect.&lt;/p&gt;




&lt;h2&gt;
  
  
  Correct invariant
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
(owner_id, name) must be unique

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

&lt;/div&gt;



&lt;p&gt;Meaning:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;same user → duplicates forbidden
&lt;/li&gt;
&lt;li&gt;different users → duplicates allowed
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Namespace Visualization
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
User A:
milk
eggs

User B:
milk   ← allowed
bread

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

&lt;/div&gt;






&lt;h2&gt;
  
  
  Fix Alignment
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Domain
&lt;/h3&gt;

&lt;p&gt;Define invariant clearly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Database
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
UNIQUE(owner_id, name)

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Service
&lt;/h3&gt;

&lt;p&gt;Attempt write → catch integrity error → translate.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tests
&lt;/h3&gt;

&lt;p&gt;Verify:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;same owner duplicate fails
&lt;/li&gt;
&lt;li&gt;different owners succeed
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  5. Concurrency Model
&lt;/h2&gt;

&lt;p&gt;Key truths:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;processes don’t share memory
&lt;/li&gt;
&lt;li&gt;threads share heap
&lt;/li&gt;
&lt;li&gt;requests interleave
&lt;/li&gt;
&lt;li&gt;database enforces consistency
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Concurrency Diagram
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
Request A ──────┐
├── Database
Request B ──────┘

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

&lt;/div&gt;



&lt;p&gt;Both requests may attempt mutation simultaneously.&lt;br&gt;&lt;br&gt;
Database constraint prevents corruption.&lt;/p&gt;


&lt;h2&gt;
  
  
  6. Request Lifecycle Graph
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
client
↓
OS
↓
kernel
↓
network
↓
process
↓
database
↓
response

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

&lt;/div&gt;


&lt;p&gt;Latency becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
path cost + contention

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

&lt;/div&gt;






&lt;h2&gt;
  
  
  7. Testing Philosophy
&lt;/h2&gt;

&lt;p&gt;Tests validate the mental model.&lt;/p&gt;

&lt;p&gt;Rules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;assert state unchanged on failure
&lt;/li&gt;
&lt;li&gt;test transitions
&lt;/li&gt;
&lt;li&gt;separate transport vs service tests
&lt;/li&gt;
&lt;li&gt;integration tests verify layers
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If tests are hard to write:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;the model is wrong.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  8. Logging System Direction
&lt;/h2&gt;

&lt;p&gt;Logging is a system component.&lt;/p&gt;

&lt;p&gt;Goals:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;structured logs
&lt;/li&gt;
&lt;li&gt;lifecycle visibility
&lt;/li&gt;
&lt;li&gt;transition tracing
&lt;/li&gt;
&lt;li&gt;concurrency debugging
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Logging = observability = understanding.&lt;/p&gt;




&lt;h2&gt;
  
  
  9. Why This Project Exists
&lt;/h2&gt;

&lt;p&gt;CountIQ is a systems lab for learning:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;invariants
&lt;/li&gt;
&lt;li&gt;mutation safety
&lt;/li&gt;
&lt;li&gt;concurrency
&lt;/li&gt;
&lt;li&gt;architecture
&lt;/li&gt;
&lt;li&gt;deployment
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Built:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;layer by layer
&lt;/li&gt;
&lt;li&gt;frozen interfaces
&lt;/li&gt;
&lt;li&gt;deployment-first mindset
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  10. Forward Roadmap
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
logging middleware
user model
Docker
AWS deployment
Python internals
concurrency deep dive

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

&lt;/div&gt;



&lt;p&gt;Each addition updates this notebook.&lt;/p&gt;




&lt;h2&gt;
  
  
  Developer Takeaway
&lt;/h2&gt;

&lt;p&gt;Most backend bugs are not syntax bugs.&lt;br&gt;&lt;br&gt;
They are invariant bugs.&lt;/p&gt;

&lt;p&gt;If the model is wrong:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;code feels fragile
&lt;/li&gt;
&lt;li&gt;fixes are temporary
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the model is correct:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;code simplifies
&lt;/li&gt;
&lt;li&gt;scaling becomes predictable
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Rule:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Model the system first.&lt;br&gt;&lt;br&gt;
Then write the code.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>backend</category>
      <category>systemdesign</category>
      <category>architecture</category>
      <category>python</category>
    </item>
    <item>
      <title>Building an Atomic Quantity Update Endpoint in Django (and the Bugs That Taught Me More Than the Feature)</title>
      <dc:creator>Zack Grooms</dc:creator>
      <pubDate>Tue, 10 Feb 2026 19:54:07 +0000</pubDate>
      <link>https://dev.to/grooms_nicholas/-building-an-atomic-quantity-update-endpoint-in-django-and-the-bugs-that-taught-me-more-than-the-1d6j</link>
      <guid>https://dev.to/grooms_nicholas/-building-an-atomic-quantity-update-endpoint-in-django-and-the-bugs-that-taught-me-more-than-the-1d6j</guid>
      <description>&lt;p&gt;I’m building a backend-only inventory system to practice real systems engineering fundamentals:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;state transitions&lt;/li&gt;
&lt;li&gt;invariants&lt;/li&gt;
&lt;li&gt;atomicity&lt;/li&gt;
&lt;li&gt;correctness under concurrency&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No UI.&lt;br&gt;
Just HTTP + database.&lt;/p&gt;

&lt;p&gt;This week I finished the &lt;strong&gt;service + transport layer&lt;/strong&gt; for:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PATCH /items/&amp;lt;uuid&amp;gt;/qty
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This endpoint applies a delta-based transition to item quantity.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why use &lt;code&gt;delta&lt;/code&gt; instead of setting quantity directly?
&lt;/h2&gt;

&lt;p&gt;Instead of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;qty = 4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;we send:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"delta"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The system performs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;qty' = qty + delta
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This allows the database to apply the change atomically and avoids read-modify-write race conditions.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Service-Layer Implementation
&lt;/h2&gt;

&lt;p&gt;All state mutation lives in the service layer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;updated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&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="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;item_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;qty__gte&lt;/span&gt;&lt;span class="o"&gt;=-&lt;/span&gt;&lt;span class="n"&gt;delta&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qty&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;F&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;qty&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;delta&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What this does
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Guard against invalid state
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;qty__gte=-delta
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;current_qty + delta ≥ 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the result would be negative, the update never runs.&lt;/p&gt;

&lt;p&gt;The database enforces this invariant.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. Atomic update
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;qty = qty + delta
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;is executed entirely inside the database using &lt;code&gt;F("qty")&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;No Python read-modify-write.&lt;br&gt;
No race conditions.&lt;/p&gt;


&lt;h3&gt;
  
  
  3. Explicit outcome classification
&lt;/h3&gt;

&lt;p&gt;If no row updated, we determine why:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;updated&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;item_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&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="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;item_id&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;exists&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

&lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;qty cannot go below 0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Service contract becomes:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Return&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Item&lt;/td&gt;
&lt;td&gt;success&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;not found&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ValueError&lt;/td&gt;
&lt;td&gt;invariant violated&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Transport maps to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;200 → success  
404 → not found  
400 → invalid transition  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Bugs That Taught Me More Than the Feature
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Bug 1 — Update succeeded but returned 404
&lt;/h2&gt;

&lt;p&gt;Qty updated correctly but response returned “not found”.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;updated&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bare return → &lt;code&gt;None&lt;/code&gt;.&lt;br&gt;
View interpreted &lt;code&gt;None&lt;/code&gt; as 404.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;updated&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;item_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lesson:&lt;br&gt;
Return contracts must be explicit and deterministic.&lt;/p&gt;


&lt;h2&gt;
  
  
  Bug 2 — UUID routing mismatch
&lt;/h2&gt;

&lt;p&gt;Model used UUID primary key.&lt;br&gt;
URL used:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;int:item_id&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;View never matched correctly.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;path("items/&amp;lt;uuid:item_id&amp;gt;/qty", ...)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lesson:&lt;br&gt;
URL converters define runtime identity types.&lt;/p&gt;


&lt;h2&gt;
  
  
  Bug 3 — Django HTML error pages
&lt;/h2&gt;

&lt;p&gt;Invalid routes returned Django HTML debug pages.&lt;/p&gt;

&lt;p&gt;Fix: custom JSON 404 handler.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;json_404&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exception&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;JsonResponse&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;error&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;not_found&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lesson:&lt;br&gt;
Transport layer should always return consistent API responses.&lt;/p&gt;


&lt;h2&gt;
  
  
  Bug 4 — The boolean delta bug (subtle but dangerous)
&lt;/h2&gt;

&lt;p&gt;This one looks small but is actually critical.&lt;/p&gt;
&lt;h3&gt;
  
  
  Python behavior
&lt;/h3&gt;

&lt;p&gt;In Python:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# True
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;bool&lt;/code&gt; is a subclass of &lt;code&gt;int&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So if validation only checks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;delta&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then this passes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"delta"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What happens if you accept it?
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;True → behaves like 1  
False → behaves like 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{ "delta": true }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;qty = qty + 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates a &lt;strong&gt;hidden mutation path&lt;/strong&gt; where boolean values mutate state.&lt;/p&gt;

&lt;p&gt;Even worse:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;qty__gte&lt;/span&gt;&lt;span class="o"&gt;=-&lt;/span&gt;&lt;span class="n"&gt;delta&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If &lt;code&gt;delta=True&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-True == -1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The guard becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;qty &amp;gt;= -1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Almost always true.&lt;/p&gt;

&lt;p&gt;So a boolean silently becomes an increment operation.&lt;/p&gt;

&lt;p&gt;That violates the API contract and creates extremely hard-to-trace bugs.&lt;/p&gt;




&lt;h3&gt;
  
  
  The fix
&lt;/h3&gt;

&lt;p&gt;Reject bool explicitly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;delta&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;delta&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;delta must be an int&lt;/span&gt;&lt;span class="sh"&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 system only accepts real integers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lesson
&lt;/h3&gt;

&lt;p&gt;Type validation must be explicit at the transport boundary.&lt;br&gt;
Silent coercion creates invisible state transitions.&lt;/p&gt;


&lt;h2&gt;
  
  
  Bug 5 — Missing transaction boundary
&lt;/h2&gt;

&lt;p&gt;If update succeeded but later code failed, state could commit partially.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;atomic&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This guarantees:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;all-or-nothing transition
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Example Invariant Violation
&lt;/h2&gt;

&lt;p&gt;Current state:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;qty = 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"delta"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;-2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Would produce:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;qty = -2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Database blocks update.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;400
{ "error": "qty cannot go below 0" }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;State remains unchanged.&lt;/p&gt;




&lt;h2&gt;
  
  
  Architecture That Emerged
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;transport → service → model → database
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Transport
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;parse JSON&lt;/li&gt;
&lt;li&gt;validate shape&lt;/li&gt;
&lt;li&gt;map service results → HTTP&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Service
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;normalize input&lt;/li&gt;
&lt;li&gt;enforce invariants&lt;/li&gt;
&lt;li&gt;perform atomic transitions&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Database
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;source of truth&lt;/li&gt;
&lt;li&gt;guard state&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Biggest Takeaway
&lt;/h2&gt;

&lt;p&gt;Correctness comes from:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;explicit transitions&lt;/li&gt;
&lt;li&gt;database guards&lt;/li&gt;
&lt;li&gt;deterministic return contracts&lt;/li&gt;
&lt;li&gt;atomic updates&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Not clever abstractions.&lt;/p&gt;

&lt;p&gt;Today the system became predictable.&lt;/p&gt;




&lt;h2&gt;
  
  
  Next Steps
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;remove csrf_exempt&lt;/li&gt;
&lt;li&gt;auth boundary&lt;/li&gt;
&lt;li&gt;request logging&lt;/li&gt;
&lt;li&gt;concurrency tests&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;If you’re learning backend systems, try implementing an atomic delta update yourself.&lt;/p&gt;

&lt;p&gt;The bugs you hit will teach you more than the feature ever will.&lt;/p&gt;

</description>
      <category>backend</category>
      <category>django</category>
      <category>database</category>
      <category>systemdesign</category>
    </item>
    <item>
      <title>What Building a Backend Taught Me About Statelessness and Idempotent APIs</title>
      <dc:creator>Zack Grooms</dc:creator>
      <pubDate>Mon, 09 Feb 2026 00:58:04 +0000</pubDate>
      <link>https://dev.to/grooms_nicholas/what-building-a-backend-taught-me-about-statelessness-and-idempotent-apis-366k</link>
      <guid>https://dev.to/grooms_nicholas/what-building-a-backend-taught-me-about-statelessness-and-idempotent-apis-366k</guid>
      <description>&lt;p&gt;This article was originally published on Medium: &lt;a href="https://medium.com/@nzack92/from-curiosity-to-systems-thinking-how-tech-shaped-the-engineer-im-becoming-1dd5823127de" rel="noopener noreferrer"&gt;From Curiosity to Systems Thinking...&lt;/a&gt;&lt;br&gt;
While building a backend system from scratch, I started to understand why Roy Fielding’s REST constraints exist...&lt;/p&gt;

</description>
      <category>backend</category>
      <category>systems</category>
      <category>python</category>
      <category>rest</category>
    </item>
    <item>
      <title>Implementing an Idempotent Delete in Django</title>
      <dc:creator>Zack Grooms</dc:creator>
      <pubDate>Sun, 08 Feb 2026 22:19:07 +0000</pubDate>
      <link>https://dev.to/grooms_nicholas/implementing-an-idempotent-delete-in-django-57i8</link>
      <guid>https://dev.to/grooms_nicholas/implementing-an-idempotent-delete-in-django-57i8</guid>
      <description>&lt;p&gt;Today I worked on the delete mutation for my Django inventory system.&lt;br&gt;
The goal was to make the endpoint idempotent:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;br&gt;
DELETE /items/&amp;lt;id&amp;gt;/&lt;br&gt;
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If the item exists → remove it&lt;br&gt;
If it doesn’t exist → no change&lt;br&gt;
Always safe to retry&lt;/p&gt;




&lt;h3&gt;
  
  
  The bug
&lt;/h3&gt;

&lt;p&gt;The delete wasn’t actually changing state.&lt;/p&gt;

&lt;p&gt;I was calling:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;python&lt;br&gt;
Item.objects.filter(item_id).delete()&lt;br&gt;
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;instead of:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;python&lt;br&gt;
Item.objects.filter(id=item_id).delete()&lt;br&gt;
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Because the query wasn’t filtering on the correct field, the state transition wasn’t happening. The endpoint &lt;em&gt;looked&lt;/em&gt; like it worked, but the underlying state wasn’t being modified correctly.&lt;/p&gt;




&lt;h3&gt;
  
  
  The fix
&lt;/h3&gt;

&lt;p&gt;Using:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;python&lt;br&gt;
Item.objects.filter(id=item_id).delete()&lt;br&gt;
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;inside a transaction made the delete naturally idempotent:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;existing item → removed&lt;/li&gt;
&lt;li&gt;missing item → no-op&lt;/li&gt;
&lt;li&gt;safe under retries&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No extra conditional logic needed.&lt;/p&gt;




&lt;h3&gt;
  
  
  System takeaway
&lt;/h3&gt;

&lt;p&gt;Idempotence often comes from how you shape the query and state transition, not from adding more control flow.&lt;/p&gt;

&lt;p&gt;Designing the delete this way keeps the service:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;stateless&lt;/li&gt;
&lt;li&gt;retry-safe&lt;/li&gt;
&lt;li&gt;predictable&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Next step
&lt;/h3&gt;

&lt;p&gt;Next feature is atomic quantity updates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;invariant enforcement&lt;/li&gt;
&lt;li&gt;transaction boundaries&lt;/li&gt;
&lt;li&gt;avoiding lost updates&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Building one feature per day and focusing on correctness first.&lt;/p&gt;

</description>
      <category>django</category>
      <category>backend</category>
      <category>api</category>
      <category>systemdesign</category>
    </item>
  </channel>
</rss>
