<?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: Nadeem Ur-Rehman</title>
    <description>The latest articles on DEV Community by Nadeem Ur-Rehman (@nurrehman).</description>
    <link>https://dev.to/nurrehman</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%2F839062%2F91f08487-9804-40f7-ac13-b27edad2564b.jpeg</url>
      <title>DEV Community: Nadeem Ur-Rehman</title>
      <link>https://dev.to/nurrehman</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nurrehman"/>
    <language>en</language>
    <item>
      <title>Your State Management Design Fails the Moment Two Screens Disagree</title>
      <dc:creator>Nadeem Ur-Rehman</dc:creator>
      <pubDate>Sun, 01 Nov 2026 12:42:03 +0000</pubDate>
      <link>https://dev.to/nurrehman/your-state-management-design-fails-the-moment-two-screens-disagree-2efi</link>
      <guid>https://dev.to/nurrehman/your-state-management-design-fails-the-moment-two-screens-disagree-2efi</guid>
      <description>&lt;h1&gt;
  
  
  Your State Management Design Fails the Moment Two Screens Disagree
&lt;/h1&gt;

&lt;p&gt;You walk into the round feeling good. The interviewer says, design a dashboard with filters, a table, and a chart. You draw three boxes, name a store, and say "single source of truth" with great confidence. Then the interviewer asks one quiet question, and the whole drawing falls over.&lt;/p&gt;

&lt;p&gt;"What happens when the table says paid and the header still says unpaid?"&lt;/p&gt;

&lt;p&gt;That is the real question. It was never about which library you picked. It was about who owns each piece of state, and what happens when two parts of the screen disagree.&lt;/p&gt;

&lt;p&gt;Most candidates answer a storage question when asked an ownership question. Redux, Zustand, Context, a signals library, it does not matter. A library tells you where state lives. It does not tell you who is allowed to change it, who has to hear about the change, or what wins when two writers collide. A global store can still ship a UI that lies, when three components each keep their own copy of the same fact.&lt;/p&gt;

&lt;p&gt;Senior engineers start with the argument, not the library. Every piece of state has an owner, and only the owner writes it. Everyone else reads it or asks for a change. That one rule kills a whole class of bugs.&lt;/p&gt;

&lt;p&gt;Take the dashboard. The filter is not "component state" just because a dropdown renders it. If the URL holds the filter, a refresh, a shared link, and the back button all agree. The table rows are server state, cached locally, never edited as if the cache were the truth. The chart keeps no copy. It derives from the same rows, so it cannot drift.&lt;/p&gt;

&lt;p&gt;This is the angle interviewers listen for. They do not care whether you can recite the difference between client state and server state. They care whether you can spot the state that should not exist at all. A count derived from a list is not state. A total derived from a cart is not state. A flag in three places is one piece of state with three liars claiming to own it. Delete the copies, keep the derivation, and half your sync bugs disappear.&lt;/p&gt;

&lt;p&gt;Here is the artifact to take into your next round. For every piece of state on the whiteboard, fill in this five line card before you move on:&lt;/p&gt;

&lt;p&gt;Owner: who is the single writer.&lt;br&gt;
Writers: who may ask for a change, and through what action.&lt;br&gt;
Readers: who renders from it, and do they read the owner or a copy.&lt;br&gt;
Invalidation: what event makes it stale, and who notices first.&lt;br&gt;
Conflict rule: when two writes arrive, what wins, and what does the loser see.&lt;/p&gt;

&lt;p&gt;Run the dashboard through it. Filter state: owner is the URL, readers are the table and the chart, conflict rule is last URL wins and everything re-derives. Table rows: owner is the server, invalidation is a refetch or a mutation response, conflict rule is server wins and the cache shows loading, not old data dressed up as new. For an optimistic update, the owner is still the server. The UI shows a predicted value, marked pending, with a rollback when the server says no. If you cannot fill in the conflict rule, you have a demo, not a design.&lt;/p&gt;

&lt;p&gt;Notice what this does to the interview. You stop defending a library and start narrating decisions. "I am putting this in the URL because sharing and refresh have to agree." "I am not storing this total, I am deriving it, because a stored total goes stale." "If the mutation fails, this row rolls back and the user sees why." Each sentence is a trade-off with a reason, and that is what gets scored.&lt;/p&gt;

&lt;p&gt;I turned the full 60-question drill set into The Frontend System Design Interview Playbook ($19): &lt;a href="https://bittalk.gumroad.com/l/frontend-interview-playbook" rel="noopener noreferrer"&gt;https://bittalk.gumroad.com/l/frontend-interview-playbook&lt;/a&gt;. It has a drill for exactly this move, naming the owner before you name the tool, plus fifty nine other traps like it.&lt;/p&gt;

&lt;p&gt;Next time you practice, do not start by picking a store. Start by finding the two screens that could disagree, and decide, out loud, who wins. That is the answer the interviewer was waiting for.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>programming</category>
    </item>
    <item>
      <title>Your Checkout Design Fails the Moment the Payment Button Gets Clicked Twice</title>
      <dc:creator>Nadeem Ur-Rehman</dc:creator>
      <pubDate>Sun, 25 Oct 2026 12:41:40 +0000</pubDate>
      <link>https://dev.to/nurrehman/your-checkout-design-fails-the-moment-the-payment-button-gets-clicked-twice-4968</link>
      <guid>https://dev.to/nurrehman/your-checkout-design-fails-the-moment-the-payment-button-gets-clicked-twice-4968</guid>
      <description>&lt;p&gt;Every frontend system design round has a moment where the candidate looks confident and the interviewer stops believing them. For a checkout, that moment is the second click.&lt;/p&gt;

&lt;p&gt;Not the first click. The first click is easy. You draw a cart, a form, a button, a success screen, and you smile like the job is done. Then the interviewer leans in and says, "The user clicked twice. The network is slow. What happens now?" If your answer is "we disable the button," you just told them your architecture is a hope and a prayer.&lt;/p&gt;

&lt;p&gt;Disabling the button is a UI trick, not a design. Buttons get re-enabled. Pages get refreshed. Requests get retried by the browser, by the network, and by an impatient human with a thumb. A checkout that only works when everything goes right is not a checkout. It is a demo.&lt;/p&gt;

&lt;p&gt;Here is the non-obvious angle most candidates miss. A checkout is not a form. It is a state machine with money attached. The screen is the least interesting part. What the interviewer is really scoring is whether you can name the states, the transitions, and the one state you must never leave ambiguous: did we charge them or not?&lt;/p&gt;

&lt;p&gt;Think about it in states, not screens. Idle. Submitting. Awaiting confirmation. Confirmed. Failed, with a reason the user can act on. Unknown, which is the state everyone forgets and the only one that matters. Unknown means the request left the browser and no answer came back. You cannot show success, because you might double charge. You cannot show failure, because the charge might have gone through. A junior redraws the success screen. A senior designs the unknown state first.&lt;/p&gt;

&lt;p&gt;That changes every decision that follows. You need an idempotency key, a unique token generated once per checkout attempt and sent with every retry, so a duplicate request is recognised as the same order, not a second one. You need a way to re-check the real order status on reload, instead of trusting whatever the last screen said. You need to separate "the payment was accepted" from "the order was created," because those are two different facts and they fail independently. And you need a failure message that tells the user what to do next, not a generic error that sends them back to click the button a third time.&lt;/p&gt;

&lt;p&gt;Here is the artifact to carry into the round. Run every checkout design through this six line check before you draw anything else.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;One checkout attempt, one idempotency key, reused on every retry.&lt;/li&gt;
&lt;li&gt;Every state named, including unknown, with a screen for each.&lt;/li&gt;
&lt;li&gt;On reload, re-fetch order status. Never trust the last screen.&lt;/li&gt;
&lt;li&gt;Payment accepted and order created treated as separate facts.&lt;/li&gt;
&lt;li&gt;Retry is safe by construction, not by a disabled button.&lt;/li&gt;
&lt;li&gt;Every failure tells the user what happened and what to do next.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That turns a vague prompt into decisions you can defend. When the interviewer asks why you chose optimistic or server confirmation, you have an answer tied to a real failure, not a memorised preference. When they ask what breaks at scale, you point at the same joint: duplicate submissions under retry storms, not a prettier component tree.&lt;/p&gt;

&lt;p&gt;Candidates love to start with the happy path because it feels like progress. Interviewers score the opposite. They want to see you volunteer the breakage before they have to drag it out of you. Say it early, in plain language: "Here is where this breaks, here is the state that saves us, here is the trade-off." That sentence is worth more than ten extra boxes on the whiteboard.&lt;/p&gt;

&lt;p&gt;I turned the full 60-question drill set into The Frontend System Design Interview Playbook ($19): &lt;a href="https://bittalk.gumroad.com/l/frontend-interview-playbook" rel="noopener noreferrer"&gt;https://bittalk.gumroad.com/l/frontend-interview-playbook&lt;/a&gt;. The checkout question is one of the sixty, and the drill is the same: name the failure before you draw the fix.&lt;/p&gt;

&lt;p&gt;Next time you practise, skip the success screen. Start with the double click, the dead network, and the reload. If your design survives those three, the happy path will take care of itself. If it does not, no amount of polished UI will save you in the room.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>programming</category>
    </item>
    <item>
      <title>Your User Paid. Your Screen Says Unpaid. That Is a Stale Data Bug, Not a Glitch</title>
      <dc:creator>Nadeem Ur-Rehman</dc:creator>
      <pubDate>Wed, 21 Oct 2026 06:58:25 +0000</pubDate>
      <link>https://dev.to/nurrehman/your-user-paid-your-screen-says-unpaid-that-is-a-stale-data-bug-not-a-glitch-37a8</link>
      <guid>https://dev.to/nurrehman/your-user-paid-your-screen-says-unpaid-that-is-a-stale-data-bug-not-a-glitch-37a8</guid>
      <description>&lt;p&gt;Your user just paid. The screen still says unpaid. They pay again. Now support has two charges, one angry customer, and a bug report that says "payment broken" when the payment worked fine.&lt;/p&gt;

&lt;p&gt;That is stale data. Not a glitch, not a flaky API, not a user error. Your UI showed yesterday's truth with today's confidence, and the user believed the screen over their bank.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/QG8xyG5YHCU" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Watch the 40-second version here: &lt;a href="https://www.youtube.com/shorts/QG8xyG5YHCU" rel="noopener noreferrer"&gt;https://www.youtube.com/shorts/QG8xyG5YHCU&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Freshness is a decision, not a hope
&lt;/h2&gt;

&lt;p&gt;Most teams treat data freshness like weather. Something to complain about, nothing to control. Then they cache aggressively, refetch never, and act surprised when the UI lies.&lt;/p&gt;

&lt;p&gt;Freshness is a policy you choose per piece of data, and you choose it before the incident, not during it. Three questions decide it. How bad is it if this is wrong? How fast does it change? How expensive is it to recheck? A user avatar can be an hour old and nobody cares. A payment status cannot be five seconds old.&lt;/p&gt;

&lt;h2&gt;
  
  
  The three moves that actually fix it
&lt;/h2&gt;

&lt;p&gt;First, stamp everything. Every piece of server data your UI shows should carry a version, a timestamp, or an ETag. If you cannot say how old the data on screen is, you cannot reason about it. A "last updated" line is not decoration. It is the difference between "the system is wrong" and "the system is catching up."&lt;/p&gt;

&lt;p&gt;Second, revalidate on the moments that matter. On focus, on reconnect, after any mutation. The user who comes back to a tab after lunch should not be staring at lunch's data. These are cheap revalidations, and they catch exactly the cases that generate support tickets.&lt;/p&gt;

&lt;p&gt;Third, set a freshness budget and enforce it. Say it out loud: payment status, 0 seconds stale. Order status, 30 seconds. Catalog data, 5 minutes. Then build the rule into code, not into a wiki page nobody reads. A budget nobody enforces is a wish.&lt;/p&gt;

&lt;p&gt;Here is the part people miss. Stale data is a trust problem, not just a caching problem. Every confident lie costs trust, and no performance tuning buys that back.&lt;/p&gt;

&lt;h2&gt;
  
  
  The checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Every server-backed screen names its freshness budget: what data, how old it may be, what triggers a recheck.&lt;/li&gt;
&lt;li&gt;Mutations invalidate or optimistically update the affected data immediately. No "refresh to see your change."&lt;/li&gt;
&lt;li&gt;Reconnect and refocus trigger revalidation for anything the user can act on.&lt;/li&gt;
&lt;li&gt;Anything money, identity, or permission related is never served from a stale cache without a fresh check.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In an interview, do not start with cache headers. Start with the user who paid twice. Then walk through stamp, revalidate, budget. The interviewer is not scoring your knowledge of HTTP caching. They are scoring whether you think about the person staring at the wrong screen.&lt;/p&gt;

&lt;p&gt;I turned the full 60-question drill set into The Frontend System Design Interview Playbook ($19): &lt;a href="https://bittalk.gumroad.com/l/frontend-interview-playbook" rel="noopener noreferrer"&gt;https://bittalk.gumroad.com/l/frontend-interview-playbook&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I broke this down in 40 seconds here: &lt;a href="https://www.youtube.com/shorts/QG8xyG5YHCU" rel="noopener noreferrer"&gt;https://www.youtube.com/shorts/QG8xyG5YHCU&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>architecture</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Your WebSocket Is Connected. That Is the Easy Part.</title>
      <dc:creator>Nadeem Ur-Rehman</dc:creator>
      <pubDate>Tue, 20 Oct 2026 06:59:57 +0000</pubDate>
      <link>https://dev.to/nurrehman/your-websocket-is-connected-that-is-the-easy-part-3c8</link>
      <guid>https://dev.to/nurrehman/your-websocket-is-connected-that-is-the-easy-part-3c8</guid>
      <description>&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/YYD2YfTcEK8" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/shorts/YYD2YfTcEK8" rel="noopener noreferrer"&gt;Watch the 40-second version on YouTube&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Every frontend system design interview has a moment where the candidate says "we will use WebSockets for real-time updates" and the interviewer nods. That nod is a trap. WebSockets are not an architecture. They are the first three minutes of the hard conversation.&lt;/p&gt;

&lt;p&gt;Here is the production version of that question, and it has bitten me for real. A dashboard I worked on streamed ticks over a socket. Flawless in the demo. Then a user on hotel Wi-Fi dropped for four seconds, the socket reconnected, and the UI showed nothing wrong. Except the prices were stale. Not broken. Stale. The worst kind of wrong: confident and silent. The reconnect succeeded, the stream resumed, and every message from those four seconds vanished into the gap. Nobody noticed for a week. The fix was not a better socket library. It was everything around the socket.&lt;/p&gt;

&lt;p&gt;That is what interviewers are really asking when they say "design real-time updates." They want the 3 AM cases.&lt;/p&gt;

&lt;p&gt;Three things the demo never shows. First, reconnects are the actual product. The connect call is one line. The reconnect policy is the architecture: exponential backoff with jitter, or your whole fleet retries at the same instant like a tiny DDoS you wrote yourself. Plus a visible connection state in the UI, because presenting stale data as live is lying to your users.&lt;/p&gt;

&lt;p&gt;Second, you need a position in the stream, not just a connection. Every message carries a sequence ID, and the client remembers the last one it processed. On reconnect, it resubscribes from that ID and replays the gap. No IDs, no resync. You are refreshing and praying.&lt;/p&gt;

&lt;p&gt;Third, at-least-once delivery means duplicates, so every handler must be idempotent. Receiving the same message twice is correct behavior, not a bug. Apply it twice and get the same result, or your counters drift and nobody can say why.&lt;/p&gt;

&lt;p&gt;The non-obvious angle: the interview answer is the incident review. Our stale-data post-mortem produced exactly those three action items: backoff with jitter, sequence IDs with gap replay, idempotent handlers. Interviewers are not testing whether you can recite socket docs. They are checking whether you have thought about what happens when the network lies, because it always does eventually.&lt;/p&gt;

&lt;p&gt;Steal this for your next design doc or interview. The reconnect checklist, copy-paste friendly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;REAL-TIME CHECKLIST (the 3 AM contract)
1. Reconnect: exponential backoff + jitter, max delay cap.
2. UI shows connection state: never present stale data as live.
3. Every message has a sequence ID; client tracks the last processed.
4. Reconnect = resubscribe from last ID, replay the gap.
5. Handlers idempotent: same message twice, same result.
6. Heartbeats catch dead connections before users do.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I turned the full 60-question drill set into The Frontend System Design Interview Playbook ($19): &lt;a href="https://bittalk.gumroad.com/l/frontend-interview-playbook" rel="noopener noreferrer"&gt;https://bittalk.gumroad.com/l/frontend-interview-playbook&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I broke this down in 40 seconds here: &lt;a href="https://www.youtube.com/shorts/YYD2YfTcEK8" rel="noopener noreferrer"&gt;https://www.youtube.com/shorts/YYD2YfTcEK8&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>architecture</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Offset Pagination Silently Skips Rows. Your Demo Just Has Not Noticed Yet.</title>
      <dc:creator>Nadeem Ur-Rehman</dc:creator>
      <pubDate>Mon, 19 Oct 2026 06:58:07 +0000</pubDate>
      <link>https://dev.to/nurrehman/offset-pagination-silently-skips-rows-your-demo-just-has-not-noticed-yet-502c</link>
      <guid>https://dev.to/nurrehman/offset-pagination-silently-skips-rows-your-demo-just-has-not-noticed-yet-502c</guid>
      <description>&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/czZkXS-1AQo" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Your pagination works in the demo. Then production arrives with a dataset that moves, and rows start vanishing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The bug with no stack trace
&lt;/h2&gt;

&lt;p&gt;Here is the failure nobody catches in staging: OFFSET pagination. Page 1 fetches rows 1-20. Someone deletes row 4. Page 2 asks for OFFSET 20, and the rows shift left underneath you. Rows quietly drop off or show up twice, and nothing throws an error. Your UI looks fine. The data is just wrong.&lt;/p&gt;

&lt;p&gt;That is the worst kind of bug. No red banner, no failed request, just a support ticket three weeks later asking where their invoice went.&lt;/p&gt;

&lt;p&gt;Why does OFFSET even exist? It is simple to implement, simple to explain, and perfectly correct on datasets that never change. The demo dataset never changes. That is the trap.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fix interviewers want to hear
&lt;/h2&gt;

&lt;p&gt;Cursor pagination. Instead of "give me rows 20 to 40," you say "give me 20 rows after this cursor," where the cursor is an opaque, stable token anchored to the last row you saw. Rows can be added or deleted ahead of it and your page does not shift, because the window is anchored to data, not to a number.&lt;/p&gt;

&lt;p&gt;Three rules that survive the whiteboard:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Never use OFFSET on data that moves.&lt;/strong&gt; Admin list with ten rows? Fine. Anything with concurrent writes, like an order queue or an activity feed? Cursor.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Make the cursor opaque and stable.&lt;/strong&gt; Base64-encode it. Do not hand clients raw row IDs they can tamper with or guess. Tie it to a sort key that is unique and monotonic, like &lt;code&gt;(created_at, id)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The sort key must be unique.&lt;/strong&gt; &lt;code&gt;created_at&lt;/code&gt; alone collides. Duplicates in the sort key mean rows can still slip between pages.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And the non-obvious angle nobody mentions in interviews: cursors change your API contract. Clients cannot jump to page 47 anymore, and "total pages" becomes expensive or impossible. Design for that up front. Return &lt;code&gt;has_next_page&lt;/code&gt;, not page counts, and let product decide whether random access is really worth the lying it requires.&lt;/p&gt;

&lt;p&gt;Copy-paste decision rule, for the interview and for real life: &lt;em&gt;if the dataset is write-active, anchor the page to a row (cursor). If it is static, OFFSET is fine, and I will document the assumption.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I broke this down in 40 seconds here: &lt;a href="https://www.youtube.com/shorts/czZkXS-1AQo" rel="noopener noreferrer"&gt;https://www.youtube.com/shorts/czZkXS-1AQo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I turned the full 60-question drill set into The Frontend System Design Interview Playbook ($19): &lt;a href="https://bittalk.gumroad.com/l/frontend-interview-playbook" rel="noopener noreferrer"&gt;https://bittalk.gumroad.com/l/frontend-interview-playbook&lt;/a&gt;&lt;/p&gt;

</description>
      <category>programming</category>
      <category>webdev</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Your Notification Feed Design Is a Happy Path Fantasy</title>
      <dc:creator>Nadeem Ur-Rehman</dc:creator>
      <pubDate>Sun, 18 Oct 2026 12:42:03 +0000</pubDate>
      <link>https://dev.to/nurrehman/your-notification-feed-design-is-a-happy-path-fantasy-3d5e</link>
      <guid>https://dev.to/nurrehman/your-notification-feed-design-is-a-happy-path-fantasy-3d5e</guid>
      <description>&lt;h1&gt;
  
  
  Your Notification Feed Design Is a Happy Path Fantasy
&lt;/h1&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/YYD2YfTcEK8" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Every frontend system design interview has a moment where the interviewer leans back and says, "Let's design a notification feed." And every candidate makes the same mistake: they reach for the marker.&lt;/p&gt;

&lt;p&gt;The feed is the favorite interview question precisely because it looks easy. You get a list. You get a bell icon with a little red number. What could possibly be hard about it? Ask anyone who has shipped one to production and they will laugh before they answer, because the notification feed is the component that breaks first, breaks quietly, and breaks in ways your whiteboard never predicted.&lt;/p&gt;

&lt;p&gt;Here is the part nobody tells you. The interviewer is not scoring your architecture. They already know what a sensible feed looks like. They are scoring whether you volunteer the breakage before they have to ask. A junior designs what renders. A senior designs what survives. And the feed is pure survival engineering wearing a friendly face.&lt;/p&gt;

&lt;p&gt;Before you draw a single box, answer six questions. I call it the breakage checklist:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Read-heavy or write-heavy?&lt;/strong&gt; A social app with 5M daily users getting 30 notifications each produces 150M writes a day, but reads happen on every app open and every badge check. That ratio decides everything. Read-heavy means you fan out at write time into per-user inboxes instead of assembling feeds at read time. Get the ratio wrong and your clever realtime layer melts under its own cleverness.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Who cares about freshness?&lt;/strong&gt; Does anyone's life change if the bell badge is 60 seconds stale? If not, you just bought yourself polling, a cheap cache, and a much simpler answer. Freshness is a budget. Spend it where someone feels it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Where does the unread count live?&lt;/strong&gt; This is the question that ends interviews early. Two devices, one account, a message read on the phone but unread on the laptop. The count is a tiny distributed-systems problem hiding in a red circle. Name your source of truth and your reconciliation rule out loud, before they ask.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. How big is the audience?&lt;/strong&gt; 200 followers and 2 million followers are not the same feed. Fan-out at write time is glorious until one user has a stadium of followers, and then you are writing 2M rows because one celebrity liked a comment. Name the threshold where your design flips, and what it flips to.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. What shows up twice?&lt;/strong&gt; Retries happen. Networks lie. Your delivery path will redeliver something someday, and the user will see the same like three times. Dedup on the client with idempotency keys is not a detail. It is the difference between a feed and a firehose of duplicates.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. What breaks first when traffic 10x's?&lt;/strong&gt; Say it before they ask. Point at the one joint that flexes and name the lever: cache the count, shard the inbox, degrade to polling. Candidates who volunteer their failure mode get hired. Candidates who wait for the twist question get corrected.&lt;/p&gt;

&lt;p&gt;Run that checklist in the first five minutes and the rest of the round changes shape. The interviewer stops probing for holes because you already named them. The boxes you draw afterwards are just confirmation of a design that proved it can take a punch.&lt;/p&gt;

&lt;p&gt;I drilled this exact pattern across 60 frontend system design questions, and I turned the full 60-question drill set into The Frontend System Design Interview Playbook ($19): &lt;a href="https://bittalk.gumroad.com/l/frontend-interview-playbook" rel="noopener noreferrer"&gt;https://bittalk.gumroad.com/l/frontend-interview-playbook&lt;/a&gt;. The notification feed is territory you cannot afford to wing.&lt;/p&gt;

&lt;p&gt;So next time the interviewer says "design a notification feed," do not reach for the marker. Reach for the breakage list. They will remember you as the candidate who designed what survives.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>programming</category>
      <category>career</category>
    </item>
    <item>
      <title>You Can't Type Your Way to 10x Anymore. Judgment Is the New Keyboard.</title>
      <dc:creator>Nadeem Ur-Rehman</dc:creator>
      <pubDate>Sun, 18 Oct 2026 06:58:49 +0000</pubDate>
      <link>https://dev.to/nurrehman/you-cant-type-your-way-to-10x-anymore-judgment-is-the-new-keyboard-221k</link>
      <guid>https://dev.to/nurrehman/you-cant-type-your-way-to-10x-anymore-judgment-is-the-new-keyboard-221k</guid>
      <description>&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/PYn4-f8JAmM" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Watch the 40-second version here: &lt;a href="https://www.youtube.com/shorts/PYn4-f8JAmM" rel="noopener noreferrer"&gt;10x Engineer Is Now a 10x Prompter&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bank of America hired a thousand contractors to clean up flaws that AI coding agents left in its software. A thousand humans, hired to be the quality gate for machines that typed faster than any human alive and understood less than an intern on day one.&lt;/p&gt;

&lt;p&gt;That is the bill. And it is due at every company that confused output with engineering.&lt;/p&gt;

&lt;p&gt;Here is the scene I keep living through. Someone demos an AI agent that builds a feature in four minutes. Everyone nods. Then the code review takes two days, the QA cycle takes a week, and the thing breaks in production on a Tuesday at 2am in a way nobody can explain, because nobody on the team actually wrote it. They watched it get written. Watching is not understanding, and understanding is the whole job.&lt;/p&gt;

&lt;p&gt;Typing was never the bottleneck. The bottleneck was always deciding what to build, what to trust, and what to throw away. AI deleted the typing part. It did not delete the thinking part. If anything, it made the thinking more expensive, because bad decisions now arrive at scale and at speed.&lt;/p&gt;

&lt;p&gt;Here is the non-obvious part: the engineers thriving right now are not the ones with the longest prompt chains or the fanciest agent loops. They are the ones who delete the most AI output. Deletion is a skill. It means you read the thing, understood the thing, and had the spine to kill 200 lines that worked in the demo but would rot in production. Most people cannot do this. They shipped it because the demo looked good, and now it is their 2am problem.&lt;/p&gt;

&lt;p&gt;So here is my decision rule. Three lines, copy-paste it into your brain:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;If you cannot explain generated code in one breath, you do not ship it.&lt;/li&gt;
&lt;li&gt;If the AI wrote it in 30 seconds and the tests take 30 minutes to verify, the code owns you, not the other way around.&lt;/li&gt;
&lt;li&gt;Delete one thing the AI wrote every day, on purpose. Keep the muscle honest.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The 10x engineer did not die. The job description changed. Direction beats production. Taste beats speed. The people who win this era are the ones who know which problem to solve, which output to trust, and what to delete with zero regret.&lt;/p&gt;

&lt;p&gt;I broke this down in 40 seconds here: &lt;a href="https://www.youtube.com/shorts/PYn4-f8JAmM" rel="noopener noreferrer"&gt;10x Engineer Is Now a 10x Prompter&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>devops</category>
    </item>
    <item>
      <title>Your Laptop Just Outsmarted a Data Center</title>
      <dc:creator>Nadeem Ur-Rehman</dc:creator>
      <pubDate>Sat, 17 Oct 2026 06:58:28 +0000</pubDate>
      <link>https://dev.to/nurrehman/your-laptop-just-outsmarted-a-data-center-c95</link>
      <guid>https://dev.to/nurrehman/your-laptop-just-outsmarted-a-data-center-c95</guid>
      <description>&lt;h1&gt;
  
  
  Your Laptop Just Outsmarted a Data Center
&lt;/h1&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/42NAuRXT_z0" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Last quarter your company probably paid a four-figure API bill so a frontier model could summarize PDFs, classify support tickets, and write boilerplate code. It worked. It also worked like hiring a Michelin chef to make toast.&lt;/p&gt;

&lt;p&gt;A seven-billion-parameter model, small enough to run on the laptop you already own, can do those exact jobs as well or better. No cloud account, no metered tokens, no data leaving the building.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the giants got beat at their own game
&lt;/h2&gt;

&lt;p&gt;The old mental model said intelligence scales with size. Bigger weights, bigger data centers, bigger bills. That held for a while, then training got smarter. A small model trained carefully on one domain, code or support conversations or product docs, punches absurdly far above its weight class.&lt;/p&gt;

&lt;p&gt;Last year's giants know everything, shallowly. A focused small model knows the one thing you actually need, deeply. For narrow, well-defined jobs like code completion, document summarization, and structured Q&amp;amp;A, "knows everything" is not an advantage. It is overhead you pay for in latency, dollars, and privacy reviews.&lt;/p&gt;

&lt;h2&gt;
  
  
  The part nobody prices into the architecture review
&lt;/h2&gt;

&lt;p&gt;Here is the non-obvious angle: the invoice is the least of it. Every call to a cloud model ships your data, latency, and uptime to a third party. Your latency budget is now someone else's queue. Your compliance team now has opinions about every prompt. Your unit economics are a subscription you can never buy out.&lt;/p&gt;

&lt;p&gt;A local model flips all three. Latency is a function of your hardware, not their traffic. Your data never leaves the machine, which makes legal happy without you writing a single extra document. And the cost is fixed: one-time hardware you already bought, versus a meter that runs forever.&lt;/p&gt;

&lt;h2&gt;
  
  
  The decision rule (steal this for your next review)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Go SMALL when:
  - The task is narrow and definable (classify, summarize, extract, autocomplete)
  - Latency matters (interactive UIs, IDE features, on-device search)
  - Data must stay put (health, finance, legal, anything with a compliance team)
  - Volume is high and predictable (the API bill compounds; hardware does not)

Go BIG when:
  - The task needs broad, open-ended reasoning or general knowledge
  - You are prototyping and the task is not defined yet
  - Accuracy on novel, adversarial, or creative inputs is the whole point
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice what is not on the big-model list: "because it felt safer." In interviews and in architecture reviews, "we called the big API" is not a design decision. It is a subscription wearing a trench coat.&lt;/p&gt;

&lt;p&gt;Start small, measure honestly, and only pay for the giant when the small one fails the benchmark in front of witnesses. Most of the time, it will not.&lt;/p&gt;

&lt;p&gt;I broke this down in 40 seconds here: &lt;a href="https://youtube.com/shorts/42NAuRXT_z0" rel="noopener noreferrer"&gt;Tiny AI Models Are Beating the Giants&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Your 'BFF' Is Just a Second Backend With Better Marketing</title>
      <dc:creator>Nadeem Ur-Rehman</dc:creator>
      <pubDate>Fri, 16 Oct 2026 06:59:29 +0000</pubDate>
      <link>https://dev.to/nurrehman/your-bff-is-just-a-second-backend-with-better-marketing-3je5</link>
      <guid>https://dev.to/nurrehman/your-bff-is-just-a-second-backend-with-better-marketing-3je5</guid>
      <description>&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/XTJ6mufbTj8" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Watch the 40-second version: &lt;a href="https://www.youtube.com/shorts/XTJ6mufbTj8" rel="noopener noreferrer"&gt;Backend-for-Frontend Explained for Interviews (Q15/60)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The screen needed five microservice calls to render. Profile from here, orders from there, pricing from somewhere else, and two nobody could explain. So the team did the sensible thing. They built a BFF.&lt;/p&gt;

&lt;p&gt;Six months later the BFF had its own database, its own cron jobs, business logic nobody would claim in a meeting, and an on-call rotation. Congratulations. You did not build a backend-for-frontend. You built a second backend and gave it a frontend pattern's name so nobody would ask questions.&lt;/p&gt;

&lt;p&gt;I have watched this exact movie more than once. It starts with pure intentions. The frontend is chatty, mobile users on bad connections are suffering, so someone stands up a thin aggregation layer. Thin is doing a lot of work in that sentence, because thin is a property of the present. Give it two quarters and thin quietly becomes "well, the logic has to live SOMEWHERE."&lt;/p&gt;

&lt;p&gt;Here is the line interviewers are really testing when they ask where a BFF fits. A BFF has one job: translate the product journey. Aggregate the calls. Shape the payload for the screen. Enforce what this channel is allowed to see. Hide the service topology so the frontend never learns how many services you really have. Domain rules stay in the owning services. The day your BFF starts owning business logic, it stopped being a BFF. Call it what it is and staff it like one.&lt;/p&gt;

&lt;p&gt;The non-obvious part: The BFF's real value is what it deletes. Every round trip your phone does not make on a bad connection is latency your users never feel and a failure mode you never debug at 2 a.m. And if you think one BFF can serve web, mobile, and the partner API, enjoy your new distributed monolith. One channel, one BFF. Shared BFFs drift. It is the same gravity that made the monolith, just with more YAML.&lt;/p&gt;

&lt;p&gt;The 30-second BFF audit. Run this on yours today:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Does it own business logic? Move it to the owning service.&lt;/li&gt;
&lt;li&gt;Does it have its own database? Then it is a backend. Rename it honestly.&lt;/li&gt;
&lt;li&gt;Could you rebuild it from the service contracts in a day? If not, it grew roots.&lt;/li&gt;
&lt;li&gt;Does each channel get its own BFF? Shared ones drift into monoliths.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In Angular, the cleanest consumer of a BFF is a route resolver. One call in, and the route does not activate until the screen-shaped payload arrives:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;providedIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DashboardResolver&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;Resolve&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;DashboardVm&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HttpClient&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
  &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;DashboardVm&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// one request out, five service calls hidden behind the BFF&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;DashboardVm&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/bff/dashboard&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="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// route: { path: 'dashboard', component: DashboardComponent,&lt;/span&gt;
&lt;span class="c1"&gt;//          resolve: { vm: DashboardResolver } }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Five service calls, one HTTP request, zero business logic in the middle. That is the whole pattern. Keep it boring and it stays a BFF.&lt;/p&gt;

&lt;p&gt;I broke this down in 40 seconds here: &lt;a href="https://www.youtube.com/shorts/XTJ6mufbTj8" rel="noopener noreferrer"&gt;https://www.youtube.com/shorts/XTJ6mufbTj8&lt;/a&gt;&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>REST vs GraphQL Is a Judgment Test, Not a Loyalty Test</title>
      <dc:creator>Nadeem Ur-Rehman</dc:creator>
      <pubDate>Thu, 15 Oct 2026 06:57:49 +0000</pubDate>
      <link>https://dev.to/nurrehman/rest-vs-graphql-is-a-judgment-test-not-a-loyalty-test-4hnk</link>
      <guid>https://dev.to/nurrehman/rest-vs-graphql-is-a-judgment-test-not-a-loyalty-test-4hnk</guid>
      <description>&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/FGzszHhXh1g" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Everyone on your team has a strong opinion about REST vs GraphQL, and half of them picked their side in 2019 and never looked back. Here is the war story version: a product page ships, it fires four REST requests to render, the mobile team complains about battery drain, someone "fixes" it by merging everything into one 2MB endpoint, and now every client pays for fields it never reads. Three rewrites later, the frontend team has PTSD and the backend team has trust issues.&lt;/p&gt;

&lt;p&gt;The interview version of this is simpler and crueler. "REST or GraphQL?" is not a loyalty test. It is a judgment test. An interviewer can tell in ten seconds whether you actually chose the contract for a reason, or whether you just memorized a blog post.&lt;/p&gt;

&lt;p&gt;Why it matters more than the framework debate people obsess over: the API contract is the one decision your frontend cannot escape. You can swap a component library in a weekend. You cannot swap your data-fetching contract without touching every screen. Pick wrong and you pay for it in round trips, in over-fetching, and in the kind of performance bugs that only show up on cheap phones your team never tests on.&lt;/p&gt;

&lt;p&gt;The non-obvious angle nobody mentions in interviews: the real cost is rarely bandwidth. It is ownership. GraphQL gives the client query power, which sounds like freedom, until you realize someone has to own query complexity, rate limiting, and cache invalidation for arbitrary queries. REST gives you predictable endpoints, until the fifth client-specific "v2" endpoint exists and nobody knows which ones are safe to kill. The failure mode of GraphQL is a query that quietly costs your database a full-table scan. The failure mode of REST is endpoint sprawl. Pick the failure mode your team is equipped to govern, because you will get the failure either way.&lt;/p&gt;

&lt;p&gt;Here is the decision rule, copy-paste friendly. Run any API through these three checks:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Client diversity.&lt;/strong&gt; One web app that you control? REST is probably fine. Web, iOS, Android, and a partner API, all needing different slices of the same data? That is GraphQL territory.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Graph tangles.&lt;/strong&gt; If rendering one screen means five sequential round trips for nested data, you have a graph problem and you are solving it with HTTP duct tape. Name the round-trip count out loud in the interview; it is the number that does the talking.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost ownership.&lt;/strong&gt; Who pays when the contract is wrong? Over-fetching burns mobile data plans and CDN bills. Under-fetching burns users on 3G. GraphQL kills over-fetching but moves the cost to query governance. REST is cheap to start and expensive to evolve.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The punchline I give in every interview: name the cost or do not spend it. "GraphQL because our three clients need different data shapes and we are willing to own query complexity" is a staff-level answer. "GraphQL because REST is old" is a junior answer with senior confidence.&lt;/p&gt;

&lt;p&gt;I broke this down in 40 seconds here: &lt;a href="https://www.youtube.com/shorts/FGzszHhXh1g" rel="noopener noreferrer"&gt;REST vs GraphQL: How Staff Engineers Choose (Q14/60)&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Your Server Rendered Tuesday. Your Client Rendered Wednesday.</title>
      <dc:creator>Nadeem Ur-Rehman</dc:creator>
      <pubDate>Wed, 14 Oct 2026 06:57:56 +0000</pubDate>
      <link>https://dev.to/nurrehman/your-server-rendered-tuesday-your-client-rendered-wednesday-4hlh</link>
      <guid>https://dev.to/nurrehman/your-server-rendered-tuesday-your-client-rendered-wednesday-4hlh</guid>
      <description>&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/3MmFVFFEJxw" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Your server rendered Tuesday. Your client rendered Wednesday. The user saw the page flicker like a haunted television, and somewhere a PM wrote "the page blinks on load" in a bug ticket. That ticket is the interview question. It just showed up in production first.&lt;/p&gt;

&lt;p&gt;A hydration mismatch is simpler than people make it sound. Server-side rendering produces HTML. The client re-renders the same components and compares. If the two outputs disagree, even by one character, React panics and throws the whole server HTML away and re-renders everything client-side. You lose the entire performance win you added SSR for. The user gets a flash, a layout jump, and your careful performance budget goes up in smoke.&lt;/p&gt;

&lt;p&gt;In the interview, "what causes a hydration mismatch" is not a trivia question. It is a filter for "has this person ever shipped SSR to real users." The causes are always the same three. Random values: &lt;code&gt;Math.random()&lt;/code&gt;, &lt;code&gt;Date.now()&lt;/code&gt;, or a UUID generated during render, so the server snapshot and the client snapshot can never agree. Dates: &lt;code&gt;new Date().toLocaleString()&lt;/code&gt; renders in the server's timezone, then re-renders in the browser's timezone, and the two strings disagree by hours. And browser-only APIs: touching &lt;code&gt;window&lt;/code&gt;, &lt;code&gt;localStorage&lt;/code&gt;, or &lt;code&gt;matchMedia&lt;/code&gt; during render throws or returns something different on the server. Every single one of these is the same bug wearing a different hat. Your render function is not deterministic.&lt;/p&gt;

&lt;p&gt;Here is the non-obvious part, and it is the thing that actually scores the interview points. A hydration mismatch is not a framework quirk. It is the framework telling you, bluntly, that your render output depends on something outside the component's inputs. It is a purity check. People treat it like a config problem and slap &lt;code&gt;suppressHydrationWarning&lt;/code&gt; on the element. That prop is a confession, not a fix. It silences the warning while the underlying mismatch still costs you the full client re-render. The right mental model: if a component can disagree with itself across two renders, it will eventually disagree with your users.&lt;/p&gt;

&lt;p&gt;The practical fix is a four-line rule you can apply to any codebase tonight.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Hydration survival rule: the render must be a pure function of props.
// 1. No Math.random(), Date.now(), or UUIDs during render. Move them to useEffect, or seed them from props.
// 2. No browser-only APIs (window, localStorage, matchMedia) during render. Guard behind `typeof window !== "undefined"` or render after mount.
// 3. No locale or timezone-dependent formatting during render. Format in a client-only component, or pass a fixed timezone from the server.
// 4. No conditional rendering that differs between server and client (extension-dependent markup, client-side A/B flags). Resolve it before first render or gate it behind a mounted state.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And for the bonus point that separates seniors from staff: React 18's selective hydration means you do not have to fix the whole page at once. Wrap the unstable part in a Suspense boundary and the framework hydrates around it. Fail small, not everywhere.&lt;/p&gt;

&lt;p&gt;I broke this down in 40 seconds here: &lt;a href="https://www.youtube.com/shorts/3MmFVFFEJxw" rel="noopener noreferrer"&gt;https://www.youtube.com/shorts/3MmFVFFEJxw&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It is question 12 of 60 in the Frontend System Design Interview Playbook. The full playbook with all 60 questions is here: &lt;a href="https://bittalk.gumroad.com/l/frontend-interview-playbook" rel="noopener noreferrer"&gt;https://bittalk.gumroad.com/l/frontend-interview-playbook&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>architecture</category>
      <category>webdev</category>
    </item>
    <item>
      <title>A Decision Nobody Wrote Down Is a Rumor With Consequences</title>
      <dc:creator>Nadeem Ur-Rehman</dc:creator>
      <pubDate>Tue, 13 Oct 2026 06:57:54 +0000</pubDate>
      <link>https://dev.to/nurrehman/a-decision-nobody-wrote-down-is-a-rumor-with-consequences-1k3l</link>
      <guid>https://dev.to/nurrehman/a-decision-nobody-wrote-down-is-a-rumor-with-consequences-1k3l</guid>
      <description>&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/yzKxYk1nWhM" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Watch the 40-second version here: &lt;a href="https://www.youtube.com/shorts/yzKxYk1nWhM" rel="noopener noreferrer"&gt;Architecture Decision Records That Pass Review&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Every team has one. The cache TTL set to 47 minutes for reasons lost to time. The "temporary" dependency that is now load-bearing. Ask who decided and you get four names, two of whom left the company last year.&lt;/p&gt;

&lt;p&gt;The decision evaporated. The consequences did not.&lt;/p&gt;

&lt;p&gt;This is why staff-level engineers write Architecture Decision Records. An ADR is one page answering: what did we decide, what did we reject, what are we on the hook for now. Four sections: context, options, decision, consequences. Twenty minutes of writing that outlives every meeting that produced the decision.&lt;/p&gt;

&lt;p&gt;Now the part nobody tells you. The options section is the entire point. A decision with no options section is not a record, it is a press release. "We chose Postgres" teaches the reader nothing without the alternatives. The rejected options are where the actual knowledge lives. Six months later a new hire suggests "why not Mongo" and instead of re-litigating a settled debate, you hand them the ADR. The argument died before it was born.&lt;/p&gt;

&lt;p&gt;Then there is the selfish effect. Undocumented decisions are incident fuel. At 2am nobody can reconstruct why the circuit breaker threshold is 12 and not 50, so they guess. They guess under pressure. ADRs are the difference between debugging the system and reverse-engineering it while the pager screams.&lt;/p&gt;

&lt;p&gt;It also reads well in interviews. Juniors describe what the system does. Staff-level candidates explain what it could have been and why it is not. The answer that lands shows trade-off thinking, and ADRs are trade-off thinking in document form.&lt;/p&gt;

&lt;p&gt;Here is a template you can steal. Save it as docs/adr/001-whatever.md and fill one in today:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# ADR 004: Use React Query for server state&lt;/span&gt;

Date: 2026-10-13
Status: Accepted

&lt;span class="gu"&gt;## Context&lt;/span&gt;
Dashboard refetches on every tab change. Three hand-rolled caches
disagree with each other. Users see stale data; support tickets agree.

&lt;span class="gu"&gt;## Options&lt;/span&gt;
&lt;span class="p"&gt;1.&lt;/span&gt; React Query: battle-tested cache/invalidate, +28KB.
&lt;span class="p"&gt;2.&lt;/span&gt; Custom fetch hook: full control, we own every bug forever.
&lt;span class="p"&gt;3.&lt;/span&gt; Redux + thunks: team knows it, but it is boilerplate city for
   data that is just "load this URL and cache it".

&lt;span class="gu"&gt;## Decision&lt;/span&gt;
React Query. It matches our shape of problem exactly: lots of
reads, few writes, invalidation is the hard part.

&lt;span class="gu"&gt;## Consequences&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Accept: bundle grows ~28KB; team must learn cache keys.
&lt;span class="p"&gt;-&lt;/span&gt; Risk: if we later need offline-first, revisit.
&lt;span class="p"&gt;-&lt;/span&gt; If this proves wrong, ADR 005 supersedes it. ADRs are never edited.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The last line matters more than it looks. Never edit an ADR. Supersede it. The history of being wrong is just as valuable as being right.&lt;/p&gt;

&lt;p&gt;Write the decision down today, or future you reverse-engineers it at 2am during an incident. Future you is the reader. Do not make them suffer.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>architecture</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
