<?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: Rahad Bhuiya</title>
    <description>The latest articles on DEV Community by Rahad Bhuiya (@rahad_bhuiya).</description>
    <link>https://dev.to/rahad_bhuiya</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3985826%2F37c0afb1-2db1-4cb6-91b4-b4eb1161aa16.jpg</url>
      <title>DEV Community: Rahad Bhuiya</title>
      <link>https://dev.to/rahad_bhuiya</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rahad_bhuiya"/>
    <language>en</language>
    <item>
      <title>Turing's Escape</title>
      <dc:creator>Rahad Bhuiya</dc:creator>
      <pubDate>Fri, 19 Jun 2026 15:54:52 +0000</pubDate>
      <link>https://dev.to/rahad_bhuiya/turings-escape-219e</link>
      <guid>https://dev.to/rahad_bhuiya/turings-escape-219e</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/june-game-jam-2026-06-03"&gt;June Solstice Game Jam&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;Turing's Escape is a single-file browser puzzle game set in a fictional 1954 cryptography station, built around one idea: a literal Turing Test. The player is a new recruit who has to clear three tests before going home — break a Caesar-shifted intercept, talk to two telegraph operators and work out which one is human, then decode a punched-tape Morse message to open the vault. The middle test is the whole point: one operator's replies are scripted, the other's come live from Google's Gemini API, re-randomized every playthrough, and the player has to guess which is which with no hint beyond the conversation itself.&lt;br&gt;
It ties into the jam themes on three levels at once rather than one per box: the "longest day" setting (a desk-lamp lit case file on the solstice night, light pooling against the dark edges of the page), the Alan Turing tribute (explained fully below), and a closing dedication that quietly lets Pride Month and Turing's own history sit in the same place, since June is both.&lt;br&gt;
Play it: &lt;a href="https://rahadbhuiya.itch.io/turings-escape" rel="noopener noreferrer"&gt;https://rahadbhuiya.itch.io/turings-escape&lt;/a&gt;&lt;br&gt;
Built with: HTML, CSS, vanilla JavaScript, Google Gemini API — no backend, no build step, no framework.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;github: &lt;a href="https://github.com/rahadbhuiya/turings-escape" rel="noopener noreferrer"&gt;https://github.com/rahadbhuiya/turings-escape&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;p&gt;Most jam entries treat their bonus categories as separate boxes to check: a Turing reference bolted onto otherwise generic gameplay, an AI API called once for a line of flavor text nobody reads twice. The decision that shaped everything else here was refusing to do that — building one mechanic that was simultaneously the theme, the tribute, and the AI integration, so pulling out any single piece would break the game rather than just shrink a credits screen. The other honest constraint was a five-day window and a zero-dollar API budget, which ruled out a backend, paid models, and any art we didn't have time to make.&lt;br&gt;
What that left is a single static HTML file: no server, no database, no build step. The state machine, all three puzzle modules, and a small WebAudio engine that synthesizes every sound effect on the fly (there are no audio asset files in the project at all) run entirely client-side in vanilla JavaScript.&lt;/p&gt;

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

&lt;p&gt;The only network call the game ever makes is the one outbound request to Gemini, for the live half of the Turing Test puzzle — everything else, including the entire "human" side of that same conversation, is local and offline by design. That made the game trivial to deploy as one file and just as trivial to demo with no internet connection at all, if a key isn't on hand.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prize Category
&lt;/h2&gt;

&lt;p&gt;Best Ode to Alan Turing — Turing isn't a skin on top of a generic escape room here; he's the reason the central mechanic exists. His 1950 paper, "Computing Machinery and Intelligence," asked whether a human judge could reliably tell a machine from a person through conversation alone — that question is the entire second test in this game. We chose not to put Turing on stage as a speaking character; he never appears, and nothing invents a quote in his name. Instead the closing screen dedicates the game to him as history rather than fiction: breaking Enigma, the 1950 paper, his 1952 prosecution for being gay under then-current UK law, and his death two years later at forty-one. It's also why the visuals are paper, typewriter type, and rubber stamps instead of a green-phosphor hacker terminal — interactive CRT screens barely existed yet in 1954, so the case-file look is the one actually true to his era, not just the one that reads as "computer-y" now.&lt;/p&gt;

&lt;p&gt;Best Google AI Usage — One of the two operator lines, randomized to Line A or Line B every playthrough, is answered live by Google's Gemini API (gemini-2.5-flash) rather than pre-written. Every player message goes out with a system instruction that puts the model in character as a 1954 telegraph operator and tells it never to reveal it's an AI; whatever comes back streams straight into the chat log, unedited. Flash and Flash-Lite are the tiers Google currently leaves open for free-tier use, with Pro held back for paid accounts, which made Flash the only realistic choice on a zero-budget build. Because a live demo in front of judges is the worst place for a network call to fail, every Gemini request is wrapped end to end — a missing key, a failed fetch, a rate limit, or an empty response all fall through silently to a pool of scripted lines tuned to feel just slightly too smooth and agreeable, the uncanny-valley opposite of the deliberately imperfect lines written for the human side. The AI is real and load-bearing for the puzzle, but never a single point of failure for the submission itself.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>gamechallenge</category>
      <category>gamedev</category>
    </item>
    <item>
      <title>A load balancer inspired by how Emperor Penguins survive Antarctic winters</title>
      <dc:creator>Rahad Bhuiya</dc:creator>
      <pubDate>Mon, 15 Jun 2026 15:32:22 +0000</pubDate>
      <link>https://dev.to/rahad_bhuiya/a-load-balancer-inspired-by-how-emperor-penguins-survive-antarctic-winters-582n</link>
      <guid>https://dev.to/rahad_bhuiya/a-load-balancer-inspired-by-how-emperor-penguins-survive-antarctic-winters-582n</guid>
      <description>&lt;p&gt;Why I modeled a load balancer after Emperor Penguin huddles&lt;/p&gt;

&lt;p&gt;A few months ago I was reading about how emperor penguins survive Antarctic winters. Temperature drops to -40°C, wind hits 120km/h, and somehow these birds make it through. Not because they're individually tough. Because they rotate.&lt;/p&gt;

&lt;p&gt;Cold penguins on the outside push inward. Warm ones from the center move out to rest. Nobody coordinates this. No penguin is in charge. It emerges from one simple rule: if you're cold, push in. If you're warm, you'll get pushed out eventually.&lt;/p&gt;

&lt;p&gt;I couldn't stop thinking about this.&lt;/p&gt;

&lt;p&gt;I was working on a service mesh at the time and dealing with the usual problem — one slow server quietly dragging down the whole cluster. Round robin doesn't care. Least connections helps but not always. Weighted approaches need manual tuning that goes stale immediately.&lt;/p&gt;

&lt;p&gt;The penguin thing kept nagging at me. What if servers had a "temperature"? What if hot servers rotated out to rest?&lt;/p&gt;

&lt;p&gt;That's HuddleCluster.&lt;/p&gt;

&lt;p&gt;The basic structure&lt;/p&gt;

&lt;p&gt;Two rings:&lt;/p&gt;

&lt;p&gt;Inner ring (deque): Active servers. Requests go to them round-robin. Simple, fair, zero overhead for normal traffic.&lt;/p&gt;

&lt;p&gt;Outer ring (min-heap): Resting servers. Keyed by temperature — coolest server sits at the top, ready to rotate back in first.&lt;/p&gt;

&lt;p&gt;When a server in the inner ring runs hot past a threshold, it moves out. When an outer ring server cools down, it comes back in.&lt;/p&gt;

&lt;p&gt;That's the entire rotation logic. About 50 lines of Python.&lt;/p&gt;

&lt;p&gt;What is "temperature"?&lt;/p&gt;

&lt;p&gt;This took me a while to get right.&lt;/p&gt;

&lt;p&gt;My first attempt was just raw latency. That was bad. A server handling one slow database query looks terrible even when it's completely healthy. I needed something more composed.&lt;/p&gt;

&lt;p&gt;Current formula:&lt;/p&gt;

&lt;p&gt;pythontemperature = EMA(&lt;br&gt;
    0.7 * relative_latency_anomaly +&lt;br&gt;
    0.1 * cpu_score +&lt;br&gt;
    0.1 * memory_score +&lt;br&gt;
    0.1 * (error_rate + connection_score)&lt;br&gt;
)&lt;/p&gt;

&lt;p&gt;Three decisions here worth explaining.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;EMA over simple moving average&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;EMA weights recent measurements more heavily. If a server just had a bad spike but recovered, EMA reflects that recovery faster than a window average would. The formula:&lt;/p&gt;

&lt;p&gt;EMA_t = α * current_value + (1 - α) * EMA_{t-1}&lt;/p&gt;

&lt;p&gt;Higher α means faster reaction but more noise sensitivity. Lower means smoother but slower detection. I tuned α empirically — the benchmark section covers what I observed.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Relative latency anomaly, not absolute latency&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is the part I'm most happy with.&lt;/p&gt;

&lt;p&gt;Instead of flagging a server when latency crosses some hardcoded threshold like "300ms is bad," I compare each server to the cluster median:&lt;/p&gt;

&lt;p&gt;pythonrelative_anomaly = (server_latency - cluster_median) / cluster_median&lt;/p&gt;

&lt;p&gt;Why does this matter? If your whole cluster is running at 200ms — maybe it's a heavy batch job period, maybe your database is under load — that's just the current normal. A 200ms server shouldn't be punished when everyone is at 200ms. But a 400ms server in a 200ms cluster? That's a real anomaly.&lt;/p&gt;

&lt;p&gt;No manual threshold needed. The system self-calibrates to whatever your current traffic looks like. 60ms is fine if the cluster median is 60ms. The scoring is scale-invariant.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;70/30 split between latency and system metrics&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Latency is the user-visible signal. CPU, memory, and connections are leading indicators — they can catch problems before latency visibly degrades. I weighted latency higher because that's ultimately what matters, but the other signals pull their weight.&lt;/p&gt;

&lt;p&gt;Data structure choices&lt;/p&gt;

&lt;p&gt;Inner ring as deque: Round-robin is just rotating a deque. Append to right, pop from left. O(1) for both. I tried a list first — the index tracking got messy and error-prone whenever servers got removed mid-rotation. Deque was cleaner and the right tool.&lt;/p&gt;

&lt;p&gt;Outer ring as min-heap: I want the coolest resting server to come back in first. Min-heap gives me that in O(log n) for insertion and extraction. I briefly considered just sorting the outer ring on every update — fine at small n, but min-heap felt more principled and honest about the intent.&lt;/p&gt;

&lt;p&gt;The whole thing is about 700 lines of Python with zero external dependencies. I deliberately avoided pulling in anything external. I wanted this to be droppable into any project without a dependency audit conversation.&lt;/p&gt;

&lt;p&gt;What the benchmarks showed&lt;/p&gt;

&lt;p&gt;I tested with 6 FastAPI servers on loopback (all on the same machine). That's a significant caveat — I'll address it directly in the limitations section.&lt;/p&gt;

&lt;p&gt;Normal load: HuddleCluster performs comparably to round-robin and least-connections. No meaningful difference. That's expected. When nothing is degraded, rotation rarely triggers and the deque just does round-robin like anything else.&lt;/p&gt;

&lt;p&gt;Server failure simulation: I introduced artificial 5-second delays on one server mid-test. This is where the gap appeared.&lt;/p&gt;

&lt;p&gt;AlgorithmP95 LatencyRound Robin5,026msLeast Connections4,891msHuddleCluster85.6ms&lt;/p&gt;

&lt;p&gt;Round-robin kept routing 1-in-6 requests to the slow server throughout the test. HuddleCluster evicted it after approximately 3 request cycles — detection converges in about 36 cluster requests on average.&lt;/p&gt;

&lt;p&gt;Inner ring fairness: Gini coefficient was 0.00 in every test scenario. The deque distributes perfectly evenly among active servers.&lt;/p&gt;

&lt;p&gt;Routing overhead: 10.7μs per request average. Acceptable for the use case.&lt;/p&gt;

&lt;p&gt;Where it breaks&lt;/p&gt;

&lt;p&gt;I think this section matters as much as the benchmark numbers.&lt;/p&gt;

&lt;p&gt;Loopback is not production. Every benchmark I ran is on a single machine. WAN introduces higher base latency, more jitter, and failure modes I haven't tested. The EMA sensitivity I tuned for loopback may need adjustment for real network conditions — high per-server jitter could cause false evictions if α is too aggressive. This is the most honest gap in the current work.&lt;/p&gt;

&lt;p&gt;The k ≥ n/2 problem. Relative scoring works well when a minority of servers degrade. If half or more of your cluster slows down simultaneously — shared database contention, a network event, a traffic spike hitting everyone — the cluster median shifts up and no individual server looks anomalous. The algorithm goes blind. I document this in the paper but haven't solved it yet.&lt;/p&gt;

&lt;p&gt;No cross-host state. HuddleCluster runs per-process. Multiple load balancer instances don't share rotation state. There's a gossip protocol stub in v1.3.0 but it's not complete.&lt;/p&gt;

&lt;p&gt;Detection speed&lt;/p&gt;

&lt;p&gt;One thing that surprised me during benchmarking: how fast eviction actually happens in practice.&lt;/p&gt;

&lt;p&gt;A 3× slower server gets rotated out in roughly 3 request cycles. For most traffic volumes that's well under a second. I expected slower convergence — the EMA smoothing should delay reaction — but the relative scoring amplifies the signal enough that threshold crossing happens fast.&lt;/p&gt;

&lt;p&gt;What's next&lt;/p&gt;

&lt;p&gt;WAN benchmarks are the obvious priority. I want to understand how the EMA α needs to change under real network jitter before claiming this is production-ready.&lt;/p&gt;

&lt;p&gt;The multi-server simultaneous degradation case also needs empirical testing. I have theoretical analysis of why relative scoring breaks at k ≥ n/2, but I want to measure the actual degradation curve — at what point does detection start failing?&lt;/p&gt;

&lt;p&gt;Distributed state via gossip is in progress.&lt;/p&gt;

&lt;p&gt;GitHub: github.com/rahadbhuiya/HuddleCluster&lt;/p&gt;

&lt;p&gt;Paper: doi.org/10.5281/zenodo.20348019&lt;/p&gt;

&lt;p&gt;If you've worked with adaptive load balancing in production — especially anything with relative or percentile-based scoring — I'd be curious what threshold strategies held up under WAN jitter.&lt;/p&gt;

</description>
      <category>python</category>
      <category>huddlecluster</category>
      <category>load</category>
      <category>balancer</category>
    </item>
  </channel>
</rss>
