<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Luis Tor</title>
    <description>The latest articles on Forem by Luis Tor (@luisdoingdev).</description>
    <link>https://forem.com/luisdoingdev</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%2F826103%2F52546163-7ca8-4766-b1db-fa31435a0b4d.jpeg</url>
      <title>Forem: Luis Tor</title>
      <link>https://forem.com/luisdoingdev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/luisdoingdev"/>
    <language>en</language>
    <item>
      <title>The Confident Soup</title>
      <dc:creator>Luis Tor</dc:creator>
      <pubDate>Wed, 18 Mar 2026 15:11:17 +0000</pubDate>
      <link>https://forem.com/luisdoingdev/the-confident-soup-4iha</link>
      <guid>https://forem.com/luisdoingdev/the-confident-soup-4iha</guid>
      <description>&lt;p&gt;It is 2:14 AM. Production is degraded. You are hunting for the edge of the fire. There is no edge.&lt;/p&gt;

&lt;p&gt;Forty minutes have passed. The code compiles. The tests are green. The deployment was flawless. But the system is failing under load, and you are staring at a file trying to find where the payment logic ends and the user logic begins. You cannot find it. Everything is touching everything. The auth module reaches into the billing service. The billing service is mutating concerns it should never have touched.&lt;/p&gt;

&lt;p&gt;There are no boundaries. No interfaces. No quiet spaces where one system hands off to another and walks away. Just a wall of syntax, perfectly indented, completely entangled.&lt;/p&gt;

&lt;p&gt;The codebase is confident. The codebase is everywhere. You are drowning in it.&lt;/p&gt;




&lt;p&gt;Good engineering is not the speed of the typing. It is knowing which battles to lose first.&lt;/p&gt;

&lt;p&gt;Before you build the feature, you sketch the failure mode. You write the interface before the implementation, and you leave it deliberately loose — not because you don't know what it should do, but because you know the requirements will pivot, the load will spike, or the database will lock. You decouple the boundary so the system fails &lt;em&gt;predictably&lt;/em&gt; when it does. The payment service drops dead. The auth service keeps running. The fire stops at the seam because you built the seam before the fire.&lt;/p&gt;

&lt;p&gt;This is designed loss. You plan a small, controlled failure so the larger system can survive real pressure. You leave things unfinished on purpose, because that early loss is how you download enough information to build the thing that actually lasts.&lt;/p&gt;

&lt;p&gt;And you stay loose because you do not actually know how users will interact with your solution. Humans arrive at your interface with contexts you never modeled. They find the path you did not design for and pull on it until something breaks. The system that cannot flex will fracture. A seam is not a metric of clean code. It is a planned retreat point — from your own assumptions as much as anything else.&lt;/p&gt;




&lt;p&gt;Go on social media and watch amateurs fight.&lt;/p&gt;

&lt;p&gt;No jab. No feint. No reading the opponent. Just two people throwing the hardest punch they can, as fast as they can, from the first bell. It looks like aggression. It looks like confidence. By the second round both fighters are gassing out, arms dropping, eating shots they would have slipped if they hadn't already spent everything.&lt;/p&gt;

&lt;p&gt;The amateur does not throw a punch to gather information. They throw a punch to end it. Every swing is a haymaker. Every haymaker is a vote against the future — against round three, against the pivot, against the moment the fight changes and you need something left in reserve.&lt;/p&gt;

&lt;p&gt;The LLM fights like an amateur. Not because it is stupid. Because it has no stamina to conserve. There is no round three for the model. There is only the ticket, and the response, and the need to fill every void with syntax before the context window closes. It cannot throw a jab. It cannot leave the interface deliberately underspecified. It cannot resist closing the seam. Incompleteness feels, to the model, like failure. So it finishes. Every time. Instantly. With total confidence.&lt;/p&gt;

&lt;p&gt;That is not a bug. It is the nature of the tool.&lt;/p&gt;




&lt;p&gt;Dave Farley studied 150 developers and found that AI makes them around 55% faster. The data is real.&lt;/p&gt;

&lt;p&gt;But we are misreading what got faster.&lt;/p&gt;

&lt;p&gt;It is 55% faster at &lt;em&gt;finishing&lt;/em&gt;. The machine crystallizes the entire feature on contact — tokens arranged the way code looks, the same way a photograph captures light arranged in the shape of a face without understanding the skull beneath it. No rebar. No load-bearing logic. In a low-saturation solution, molecules move freely. You can separate things, alter them, work them. Vibe coding is supersaturated. Everything binds to everything else the moment you hit enter. There is no seam left open for the pivot. No failure mode designed in advance. No room left for the user you forgot to model.&lt;/p&gt;

&lt;p&gt;Farley didn't prove that AI is good at engineering. He proved that AI is good at winning the first battle. The work that needed to stay loose? The planned retreat point? The architectural boundary? That work was skipped 55% faster.&lt;/p&gt;




&lt;p&gt;It is still 2:14 AM. You are still hunting for the edge of the fire.&lt;/p&gt;

&lt;p&gt;The architecture was never designed. It was merely outputted. The machine threw the haymaker, the PR was approved, and the sprint velocity chart pointed up and to the right. Leadership got the high. The engineer got the dark.&lt;/p&gt;

&lt;p&gt;In a few hours there is a standup. You do not know what you are going to say, because you still do not know what you are facing. The soup is everywhere. Somewhere inside it, something is burning.&lt;/p&gt;

&lt;p&gt;Somewhere, six months ago, a prompt won.&lt;/p&gt;

&lt;p&gt;And now, in the dark, you are losing.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;[1] We Studied 150 Developers Using AI (Here's What's Really Happening) — Dave Farley: &lt;a href="https://www.youtube.com/watch?v=b9EbCb5A408" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=b9EbCb5A408&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>software</category>
      <category>architecture</category>
    </item>
    <item>
      <title>The Little Singleton That Could</title>
      <dc:creator>Luis Tor</dc:creator>
      <pubDate>Sun, 15 Mar 2026 20:44:15 +0000</pubDate>
      <link>https://forem.com/luisdoingdev/the-little-singleton-that-could-2a2j</link>
      <guid>https://forem.com/luisdoingdev/the-little-singleton-that-could-2a2j</guid>
      <description>&lt;p&gt;"I can handle the connections," it said. "I am one. I am shared. I am efficient," it said.&lt;/p&gt;

&lt;p&gt;And for a while — it could.&lt;/p&gt;




&lt;h2&gt;
  
  
  A Home in settings.py
&lt;/h2&gt;

&lt;p&gt;The Singleton lived in &lt;code&gt;settings.py&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Not a glamorous address. Nobody visits &lt;code&gt;settings.py&lt;/code&gt; to admire the architecture. You go there to set a database password, flip a flag, move on. It's the utility drawer of a Django application — full of things that need to exist somewhere, and &lt;code&gt;settings.py&lt;/code&gt; is where they ended up.&lt;/p&gt;

&lt;p&gt;But the Singleton didn't mind. It had a job, and the job was simple: connect to Consul once, at startup, before the first request ever arrived. Then wait. When someone needed a service address, a config value, a secret — it was already there. Already connected. Already warm.&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="c1"&gt;# settings.py
&lt;/span&gt;&lt;span class="n"&gt;CONSUL_CLIENT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;consul&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One line. That's all it took to exist.&lt;/p&gt;

&lt;p&gt;And then the app would boot, and the workers would load &lt;code&gt;settings.py&lt;/code&gt;, and they'd find it sitting there like a receptionist who'd come in early and made the coffee. &lt;em&gt;I'm already here. I've already done the hard part. Just ask me.&lt;/em&gt;&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="c1"&gt;# consul.py
&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ConsulClient&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CONSUL_CLIENT&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No drama. No overhead. No redundant connections eating resources on a system that didn't need them. One request came in, the server handled it, sent a response, moved on. One worker. One world. One Singleton, perfectly matched to the life it had been given.&lt;/p&gt;

&lt;p&gt;It was good at its job because its job made sense.&lt;/p&gt;




&lt;h2&gt;
  
  
  Then Came Streaming
&lt;/h2&gt;

&lt;p&gt;But one night — no warning, no context, no ceremony — a requirement came in.&lt;/p&gt;

&lt;p&gt;Streaming.&lt;/p&gt;

&lt;p&gt;Server-Sent Events. The browser needed live data — pushed from the server continuously, without asking. A stock ticker. A status feed. Something alive.&lt;/p&gt;

&lt;p&gt;SSE is async by nature. Our app was not. So we brought in Django Channels and swapped WSGI for ASGI. The app could now handle multiple connections simultaneously. Multiple async workers, all spinning, all alive at the same time, all serving requests in parallel.&lt;/p&gt;

&lt;p&gt;The Singleton's world had changed.&lt;/p&gt;

&lt;p&gt;Nobody told the Singleton.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Ghost in vCluster
&lt;/h2&gt;

&lt;p&gt;Locally, everything worked fine.&lt;/p&gt;

&lt;p&gt;The Singleton was still humming. Still proud. Still delivering. We ran the test suite. Green. We hit the endpoints manually. Responsive. We spun up the dev server and watched the SSE stream come through clean and steady. We looked at each other and said the thing you should never say out loud in a codebase.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Looks good to me.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Then, before anyone could reach for the staging deploy button, one voice from the back of the call.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Hey — didn't we try ASGI last time and run into something?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The room went quiet in that particular way it does when nobody wants to be the first to say &lt;em&gt;yes, actually.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Someone had. Six months ago, a different feature, a different branch. ASGI had been the plan then too — and it had hit something nobody could fully explain at the time. The branch got shelved. The decision got quietly filed under &lt;em&gt;not yet&lt;/em&gt; and life moved on. Nobody wrote it down. Nobody had to. It just lived in the room, in the people who'd been there.&lt;/p&gt;

&lt;p&gt;So we didn't push to staging. Not yet.&lt;/p&gt;

&lt;p&gt;We pushed to vCluster instead — the environment that exists specifically so nothing surprises you later, the place you send code when you're confident but not &lt;em&gt;that&lt;/em&gt; confident. When you need to be sure before you let it touch anything that matters.&lt;/p&gt;

&lt;p&gt;It broke.&lt;/p&gt;

&lt;p&gt;Badline errors. Consul interaction failing under any real load. Requests timing out. Workers dying quietly, without drama, without useful stack traces. Just — gone. And then the challenging part: we couldn't reproduce it locally no matter what we tried.&lt;/p&gt;

&lt;p&gt;We added logging. We reran the tests. We hit the endpoints harder. Nothing. Clean every time. The local environment held firm, serene, unbothered, completely useless as evidence.&lt;/p&gt;

&lt;p&gt;The bug lived on vCluster and nowhere else.&lt;/p&gt;

&lt;p&gt;Someone suggested it was a networking issue. We checked the networking. Fine. Someone suggested the Consul instance itself was flaky. We tested the Consul instance directly. Responsive. Someone else said maybe it was a memory leak, a timeout misconfiguration, a version mismatch between environments. We chased each theory to its end and each one closed without resolution.&lt;/p&gt;

&lt;p&gt;We were debugging a ghost. It knew we were looking. It kept not being there.&lt;/p&gt;

&lt;p&gt;Nobody trusted their fix enough to push it forward. Nobody wanted to be the person who turned a vCluster problem into a staging problem, and a staging problem into a production incident. That question was still in the room. It hadn't left. So the branch sat. And the bug sat with it. And every morning someone would open the logs again, scroll through the same errors, form a new theory, and by afternoon that theory would be dead too.&lt;/p&gt;

&lt;p&gt;We stared at the code until the code told us something.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Race Condition Has No Manners
&lt;/h2&gt;

&lt;p&gt;Load was the key.&lt;/p&gt;

&lt;p&gt;It wasn't in the logs we'd been reading — it was in the number we'd stopped noticing. vCluster ran with real concurrency. Local dev did not. We'd been so focused on &lt;em&gt;what&lt;/em&gt; was failing that we hadn't sat long enough with &lt;em&gt;when&lt;/em&gt;. Low traffic hid it completely. One or two requests and the Singleton held. But the moment traffic climbed — multiple async workers spinning up simultaneously, all of them loading &lt;code&gt;settings.py&lt;/code&gt;, all of them reaching for the same Consul connection, all of them absolutely certain they were the only one in the room — it collapsed.&lt;/p&gt;

&lt;p&gt;They were not the only one in the room.&lt;/p&gt;

&lt;p&gt;The Singleton had spent its entire life in an orderly queue. One request. Then the next. Then the next. It had been built for a world with manners — a world where nobody cut in line, nobody reached across the table, nobody grabbed the door handle while you were still holding it. It had never been taught what to do when twelve versions of itself showed up at the same moment, all with the same idea, all with the same credentials, all reaching for the same single connection it had been holding patiently since boot.&lt;/p&gt;

&lt;p&gt;A race condition has no manners.&lt;/p&gt;

&lt;p&gt;Multiple workers touch the same shared state at the same time. No coordination. No turn-taking. No signal. They all arrive at the same door simultaneously and none of them knows the others are there. In our case, the shared state was the Consul client — that single connection initialized back in &lt;code&gt;settings.py&lt;/code&gt;, back when the world was synchronous, back when &lt;em&gt;shared&lt;/em&gt; meant &lt;em&gt;efficient&lt;/em&gt; instead of &lt;em&gt;contested&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Twelve workers. One connection. No locks between them.&lt;/p&gt;

&lt;p&gt;When they all reached for it at once, the Singleton had no protocol for that. It had never needed one. It had been given a world where it would never need one, and it had thrived there, and then the world had been quietly replaced while it wasn't looking.&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="c1"&gt;# settings.py — The problem
&lt;/span&gt;&lt;span class="n"&gt;CONSUL_CLIENT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;consul&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# consul.py — The problem, continued
&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ConsulClient&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CONSUL_CLIENT&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One door. Twelve hands reaching for the handle at the same moment.&lt;/p&gt;

&lt;p&gt;The Singleton didn't fail because it was careless. It failed because it was trusting — trusting that the world it had been built for was still the world it lived in. And the hardest part of sitting with that, once you finally see it, is the recognition that you made the same assumption. You trusted the same world. You pushed the same code into a changed environment and called it a deployment.&lt;/p&gt;

&lt;p&gt;The Singleton wasn't the only one who hadn't been told.&lt;/p&gt;




&lt;h2&gt;
  
  
  One Line Removed, One Line Rewritten
&lt;/h2&gt;

&lt;p&gt;The fix wasn't dramatic. That's not how these things go.&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="c1"&gt;# consul.py — The fix
&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ConsulClient&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;consul&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;client&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remove the Singleton from &lt;code&gt;settings.py&lt;/code&gt;. Initialize the connection on the class itself. Each worker gets its own client when it needs one. No shared state. No contested door. No assumption that order is guaranteed.&lt;/p&gt;

&lt;p&gt;One line removed, one line rewritten. The kind of diff that looks too small for how long it took to find. But what it represents is larger than the change — it's the moment you stop trusting that the world will stay the world you designed for, and start building things that can survive the world changing without warning.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Track Matters as Much as the Will
&lt;/h2&gt;

&lt;p&gt;The Singleton was not wrong.&lt;/p&gt;

&lt;p&gt;It was built for a synchronous world, and it thrived there. Everything it promised, it delivered — as long as requests arrived one at a time, as long as the workers waited their turn, as long as the app's soul was orderly.&lt;/p&gt;

&lt;p&gt;Async servers are not orderly. They are parallel by design. Twelve workers alive simultaneously is not a failure state — it's the goal. And shared state that was invisible as a problem with one worker becomes a liability with twelve. The thing that made the Singleton efficient in one world made it brittle in the next.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I think I can&lt;/em&gt; was enough when there was one hill and one engine. When there are twelve engines and one door, &lt;em&gt;I think I can&lt;/em&gt; isn't a strategy. It's an assumption.&lt;/p&gt;

&lt;p&gt;And assumptions live in &lt;code&gt;settings.py&lt;/code&gt;, quiet and warm, right up until the load increases and the workers spin up and the world you trusted turns out to have changed shape while you weren't watching.&lt;/p&gt;

&lt;p&gt;The track matters as much as the will.&lt;/p&gt;

&lt;p&gt;The Singleton knew the track.&lt;/p&gt;

&lt;p&gt;It just didn't know the track could change.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>django</category>
      <category>performance</category>
      <category>python</category>
    </item>
  </channel>
</rss>
