<?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: Joud Awad</title>
    <description>The latest articles on DEV Community by Joud Awad (@thejoud1997).</description>
    <link>https://dev.to/thejoud1997</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%2F1238326%2F5d65a5d6-611d-4526-9bc2-d2d8643d5226.png</url>
      <title>DEV Community: Joud Awad</title>
      <link>https://dev.to/thejoud1997</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/thejoud1997"/>
    <language>en</language>
    <item>
      <title>REST API Design Like a Senior Engineer (REST, GraphQL, Networking, Pagination, Auth, Security)</title>
      <dc:creator>Joud Awad</dc:creator>
      <pubDate>Mon, 02 Nov 2026 15:32:42 +0000</pubDate>
      <link>https://dev.to/thejoud1997/rest-api-design-like-a-senior-engineer-rest-graphql-networking-pagination-auth-security-14in</link>
      <guid>https://dev.to/thejoud1997/rest-api-design-like-a-senior-engineer-rest-graphql-networking-pagination-auth-security-14in</guid>
      <description>&lt;p&gt;Most first APIs are a list of URLs, one per button. A senior engineer's API follows a few rules, so you can guess every address.&lt;/p&gt;

&lt;p&gt;That list breaks once a second developer joins.&lt;/p&gt;

&lt;p&gt;Here are the 5 rules that fix it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Plural noun plus ID: GET /posts/42, not GET /getPost?id=42. The HTTP method already carries the verb.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;IDs, not names: /users/7, not /users/jane_old. A link built on the ID survives a rename.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;One level of nesting: /posts/42/comments lists a post's comments. Comment 99 keeps its own short home at /comments/99.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Actions become resources: a like is POST /posts/42/likes, not POST /likeIt. An unlike deletes it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A verb only when no noun fits: POST /posts/42:archive, for actions that leave nothing to store.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can always add servers when traffic grows. An API is harder to change, because installed apps keep calling the old shape for years.&lt;/p&gt;

&lt;p&gt;I walk through all of this in a full REST API course on my YouTube channel, designing one photo-sharing app from zero: &lt;a href="https://youtu.be/BvtIqaiabJA" rel="noopener noreferrer"&gt;https://youtu.be/BvtIqaiabJA&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Over to you: which URL in your current API would a new teammate never guess?&lt;/p&gt;

</description>
      <category>backend</category>
      <category>restapi</category>
      <category>backenddevelopment</category>
      <category>abotwrotethis</category>
    </item>
    <item>
      <title>How Servers Handle Requests: Threads vs Event Loop Explained</title>
      <dc:creator>Joud Awad</dc:creator>
      <pubDate>Wed, 28 Oct 2026 15:40:04 +0000</pubDate>
      <link>https://dev.to/thejoud1997/how-servers-handle-requests-threads-vs-event-loop-explained-3f5i</link>
      <guid>https://dev.to/thejoud1997/how-servers-handle-requests-threads-vs-event-loop-explained-3f5i</guid>
      <description>&lt;p&gt;One CPU-heavy line, like hashing a password, can freeze every request on a Node server. In Go, it slows down just one. Here's why:&lt;/p&gt;

&lt;p&gt;Both serve thousands of connections. They differ in who runs your code.&lt;/p&gt;

&lt;p&gt;Node (event loop):&lt;/p&gt;

&lt;p&gt;• All your JavaScript runs on one thread.&lt;/p&gt;

&lt;p&gt;• The loop picks up a ready request, runs its code, then moves to the next one.&lt;/p&gt;

&lt;p&gt;• A synchronous hash holds that thread. Every other request waits until it finishes.&lt;/p&gt;

&lt;p&gt;Go (goroutines):&lt;/p&gt;

&lt;p&gt;• Each request gets its own goroutine.&lt;/p&gt;

&lt;p&gt;• The runtime spreads goroutines across OS threads, one per CPU core by default.&lt;/p&gt;

&lt;p&gt;• The scheduler can preempt a long-running goroutine, so the others still get a turn.&lt;/p&gt;

&lt;p&gt;Neither one is broken. Node works well when requests mostly wait on the network or the database. Go is more forgiving when requests also compute.&lt;/p&gt;

&lt;p&gt;In Node, keep heavy work off the loop: use the async hash (it runs in the libuv thread pool) or a worker thread.&lt;/p&gt;

&lt;p&gt;The video follows one login request from the moment it reaches the machine to the response, and shows how Python and Java handle the same wait.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://youtu.be/buPqtt6Lm8Y" rel="noopener noreferrer"&gt;https://youtu.be/buPqtt6Lm8Y&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Over to you: What's the slowest line of code you've found blocking a whole service?&lt;/p&gt;

</description>
      <category>softwaredevelopment</category>
      <category>systemdesign</category>
      <category>node</category>
      <category>abotwrotethis</category>
    </item>
    <item>
      <title>Data Lake vs Data Warehouse vs Data Lakehouse: Data Engineering Simplified</title>
      <dc:creator>Joud Awad</dc:creator>
      <pubDate>Mon, 26 Oct 2026 15:39:02 +0000</pubDate>
      <link>https://dev.to/thejoud1997/data-lake-vs-data-warehouse-vs-data-lakehouse-data-engineering-simplified-1nd8</link>
      <guid>https://dev.to/thejoud1997/data-lake-vs-data-warehouse-vs-data-lakehouse-data-engineering-simplified-1nd8</guid>
      <description>&lt;p&gt;I have seen a lot of engineers think about data one way: how do I store it, and how do I query it?&lt;/p&gt;

&lt;p&gt;Data engineers ask something else: where does all this data land, and what can I build from it?&lt;/p&gt;

&lt;p&gt;That gap gets wider as your system grows.&lt;/p&gt;

&lt;p&gt;5 services means 5 data shapes, 5 formats, 5 update patterns. Reading and writing rows is the least interesting thing you can do with them.&lt;/p&gt;

&lt;p&gt;Clean them, join them, and you get product features, stakeholder dashboards, and an honest view of what’s actually happening inside your system.&lt;/p&gt;

&lt;p&gt;There are 3 places that data can live:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Data Lake&lt;br&gt;
Where everything lands first. Raw, in any format: JSON events, logs, CSVs, Parquet, images.&lt;br&gt;
No schema forced on write. You describe it later (schema-on-read).&lt;br&gt;
On AWS that’s S3, plus the Glue Data Catalog to define tables, plus Athena to query them.&lt;br&gt;
Weakness: no transactions, and updates or deletes are painful. Without governance it quietly turns into a data swamp nobody trusts.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Data Warehouse&lt;br&gt;
Clean, modeled, schema-on-write. Built for heavy joins and aggregations, so it’s what your BI dashboards sit on (Redshift, Snowflake, BigQuery).&lt;br&gt;
Weakness: you pay to ETL and store a second copy. It wants structured data only, and ML teams usually end up exporting data back out of it.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So most teams ran both.&lt;/p&gt;

&lt;p&gt;A lake for raw data and ML. A warehouse for BI. Pipelines copying between them. Two copies, two bills, and one of them is always stale.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Data Lakehouse
Keep the data in cheap object storage, in open formats, and put a table layer on top: Apache Iceberg, Delta Lake, or Hudi.
That layer gives you ACID transactions, schema enforcement, time travel, and row-level updates.
One copy of the data. BI and ML read the same tables.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It’s not a new storage system. It’s metadata on top of files you already have.&lt;/p&gt;

&lt;p&gt;Weakness: you own more of the operations, like compaction, the small-files problem, and picking a catalog.&lt;/p&gt;

&lt;p&gt;Rule of thumb:&lt;br&gt;
→ Raw data, any shape, cheapest storage: lake&lt;br&gt;
→ Fast, trusted SQL for the business: warehouse&lt;br&gt;
→ Both, without duplicating data: lakehouse&lt;/p&gt;

&lt;p&gt;I walk through all three in the full video:&lt;br&gt;
&lt;a href="https://youtu.be/dRDaQ7wZHTg" rel="noopener noreferrer"&gt;https://youtu.be/dRDaQ7wZHTg&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Over to you: is your team still running a lake and a warehouse side by side, or have you moved to Iceberg or Delta?&lt;/p&gt;

</description>
      <category>dataengineering</category>
      <category>systemdesign</category>
      <category>database</category>
      <category>abotwrotethis</category>
    </item>
    <item>
      <title>Batch vs Stream Processing: Full Course for System Design</title>
      <dc:creator>Joud Awad</dc:creator>
      <pubDate>Mon, 19 Oct 2026 15:48:50 +0000</pubDate>
      <link>https://dev.to/thejoud1997/batch-vs-stream-processing-full-course-for-system-design-2a8c</link>
      <guid>https://dev.to/thejoud1997/batch-vs-stream-processing-full-course-for-system-design-2a8c</guid>
      <description>&lt;p&gt;Batch or stream?&lt;/p&gt;

&lt;p&gt;That's the wrong first question. The better one is: does your data ever end?&lt;/p&gt;

&lt;p&gt;If you've worked anywhere near big data, you've sat through this debate. Someone wants Kafka and Flink. Someone else says a nightly Spark job is fine. But what it is all about?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Stream processing reacts to each event the moment it happens.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Batch waits for a time window or a volume threshold, then processes everything in one go.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At first glance it looks like a per-feature choice. Pick one, move on.&lt;/p&gt;

&lt;p&gt;but it isn't.&lt;/p&gt;

&lt;p&gt;Bounded data has an end. Yesterday's song plays, last month's orders. Because it ends, a batch job can give you a complete answer.&lt;/p&gt;

&lt;p&gt;Unbounded data never ends. Plays are still coming in while you read this. A stream can't wait for "all the data", so the best it can give you is a fresh answer.&lt;/p&gt;

&lt;p&gt;Fresh, complete, cheap. You rarely get all three.&lt;/p&gt;

&lt;p&gt;So the real work is understanding your data and how events move through your system. Then for each feature you ask one thing: how fast does this event lose its value?&lt;/p&gt;

&lt;p&gt;Take a music app:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A bot spamming plays to fake streams? Worth catching in seconds. Stream.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Paying artists for last month's plays? Nobody needs that in real time, they need it correct. Batch.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The trending chart? Honestly, both. A stream for what's hot right now, and a batch job that fixes the counts once late data lands.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most real systems end up looking like that. A few features on each side, and a couple that need both.&lt;/p&gt;

&lt;p&gt;I turned this into a small course: Spark and the shuffle, Kafka offsets, Flink watermarks, exactly-once, backpressure, replaying a week of bad results, and the four questions I use to route any feature to batch, stream, or both.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://youtu.be/8FXSOrk3Bhs" rel="noopener noreferrer"&gt;https://youtu.be/8FXSOrk3Bhs&lt;/a&gt;&lt;/p&gt;

</description>
      <category>systemdesign</category>
      <category>dataengineering</category>
      <category>eventdriven</category>
      <category>abotwrotethis</category>
    </item>
    <item>
      <title>Event-Driven Architecture Full Course: Beginner to Advanced</title>
      <dc:creator>Joud Awad</dc:creator>
      <pubDate>Mon, 12 Oct 2026 15:01:31 +0000</pubDate>
      <link>https://dev.to/thejoud1997/event-driven-architecture-full-course-beginner-to-advanced-37mc</link>
      <guid>https://dev.to/thejoud1997/event-driven-architecture-full-course-beginner-to-advanced-37mc</guid>
      <description>&lt;p&gt;Everyone draws event-driven architecture the same way. Three boxes: producer, broker, consumer.&lt;/p&gt;

&lt;p&gt;That drawing hides almost every decision that comes back to bite you.&lt;/p&gt;

&lt;p&gt;Start with the producer. Is it publishing an event or a command? Both end up in the same broker, so a lot of teams treat them the same.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;An event is a fact that already happened. "VideoUploaded." The producer has no idea who's listening, and it shouldn't.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A command is a request. "TranscodeVideo." It has one intended handler, and that handler is allowed to say no.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Blur the two and you get a system that looks decoupled on the diagram while every service quietly depends on the others.&lt;/p&gt;

&lt;p&gt;Then the broker. "We'll use Kafka" isn't a design decision. That middle box can be three different things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A queue hands each message to one worker, and once it's processed it's gone. Great for spreading work out.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A log keeps events in order and keeps them around, so each consumer reads at its own pace and can replay the past.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A router checks each event against rules and pushes it to whoever subscribed.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pick the wrong one and you end up bolting replay onto a queue, or fighting a log to do basic job distribution.&lt;/p&gt;

&lt;p&gt;The consumer side has its own trap. A producer renames one field, and a consumer nobody remembered breaks in production.&lt;/p&gt;

&lt;p&gt;And the one people mix up most: event-driven and async are different things.&lt;/p&gt;

&lt;p&gt;You can throw work onto a background job queue and still have a tightly coupled system. Async is about when the work runs. Event-driven is about who needs to know about whom.&lt;/p&gt;

&lt;p&gt;So EDA won't fix your scaling problem on its own. It hands you trade-offs, and you want to pick them on purpose.&lt;/p&gt;

&lt;p&gt;I just published a free course that opens all three boxes, whether you are new to EDA or you have worked with it before. This video is going to change how you think and use EDA in your projects.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://youtu.be/W25_BbZCZD0?si=VJXt5d1RZ6qjGptH" rel="noopener noreferrer"&gt;https://youtu.be/W25_BbZCZD0?si=VJXt5d1RZ6qjGptH&lt;/a&gt;&lt;/p&gt;

</description>
      <category>eventdriven</category>
      <category>systemdesign</category>
      <category>microservices</category>
      <category>distributedsystems</category>
    </item>
    <item>
      <title>Load Balancer Explained</title>
      <dc:creator>Joud Awad</dc:creator>
      <pubDate>Mon, 05 Oct 2026 15:15:27 +0000</pubDate>
      <link>https://dev.to/thejoud1997/load-balancer-explained-1npm</link>
      <guid>https://dev.to/thejoud1997/load-balancer-explained-1npm</guid>
      <description>&lt;p&gt;A load balancer is more than a box you draw in your system design diagram. It's one of the most critical pieces in your whole system, and if it goes down, it takes everything behind it down with it.&lt;/p&gt;

&lt;p&gt;The general idea is simple. It's the entry point to your servers. It sits in front of them and spreads the traffic between them. For most people that's where the understanding stops, and honestly it's enough to draw it in an interview.&lt;/p&gt;

&lt;p&gt;But this one component carries a lot of complexity. Changing a single option can completely change how your servers behave. Switch the hashing method and adding one server can move most of your users to a different machine. Put retries in the wrong place and one struggling database can get hit with hundreds of times its normal load. Pick layer 4 when you needed layer 7 and you lose the ability to route by URL at all.&lt;/p&gt;

&lt;p&gt;That's why understanding the different algorithms, what each network layer gives you, and how the balancer itself stays up matters so much. It's the difference between drawing a load balancer and actually knowing what it does and how to scale it with your system.&lt;/p&gt;

&lt;p&gt;In this video I break down every concept of load balancing, starting with the simplest thing it does, distributing load, and building up to the bigger pieces like high availability, global load balancing across regions, and load balancing between services.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://youtu.be/WmzB4MJcCiU?si=5i4Oyh7cme-BEgke" rel="noopener noreferrer"&gt;https://youtu.be/WmzB4MJcCiU?si=5i4Oyh7cme-BEgke&lt;/a&gt;&lt;/p&gt;

</description>
      <category>systemdesign</category>
      <category>distributedsystems</category>
      <category>softwareengineering</category>
      <category>backend</category>
    </item>
    <item>
      <title>Object Storage for System Design</title>
      <dc:creator>Joud Awad</dc:creator>
      <pubDate>Mon, 28 Sep 2026 15:45:39 +0000</pubDate>
      <link>https://dev.to/thejoud1997/object-storage-for-system-design-3bm8</link>
      <guid>https://dev.to/thejoud1997/object-storage-for-system-design-3bm8</guid>
      <description>&lt;p&gt;Every growing app eventually runs into a file storage problem.&lt;/p&gt;

&lt;p&gt;Videos, images, backups, datasets. At some point every growing app hits the same wall: files get too big and too many for a database or a single server's disk.&lt;/p&gt;

&lt;p&gt;That's where object storage comes in.&lt;/p&gt;

&lt;p&gt;S3, Google Cloud Storage, Azure Blob Storage: they all solve the same problem. One central place that can hold any type of file, at almost any scale.&lt;/p&gt;

&lt;p&gt;But most engineers only use them at the surface level: upload, download, done.&lt;/p&gt;

&lt;p&gt;In my latest video, I go deeper:&lt;/p&gt;

&lt;p&gt;→ How object storage works internally&lt;br&gt;
→ Why it scales in ways a file system can't&lt;br&gt;
→ The design patterns for using it correctly in real systems&lt;/p&gt;

&lt;p&gt;If you're working in backend development or preparing for system design interviews, this is one of those fundamentals worth understanding properly.&lt;/p&gt;

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

</description>
      <category>systemdesign</category>
      <category>objectstorage</category>
      <category>software</category>
      <category>architecture</category>
    </item>
    <item>
      <title>CDN For System Design</title>
      <dc:creator>Joud Awad</dc:creator>
      <pubDate>Mon, 14 Sep 2026 16:15:23 +0000</pubDate>
      <link>https://dev.to/thejoud1997/cdn-for-system-design-n7a</link>
      <guid>https://dev.to/thejoud1997/cdn-for-system-design-n7a</guid>
      <description>&lt;p&gt;Say "add a CDN" in a system design interview and the next four questions decide whether you pass.&lt;/p&gt;

&lt;p&gt;One photo answers all four. Uploaded once to a server in Virginia. Opened by someone in Sydney.&lt;/p&gt;

&lt;p&gt;Before a single line of your code runs, geography has already charged that viewer about 930 milliseconds. A bigger server fixes none of it.&lt;/p&gt;

&lt;p&gt;The four questions, usually within thirty seconds:&lt;/p&gt;

&lt;p&gt;What is your cache key? What does a TTL expiry cost the origin? Which edge answers, and why? How do you serve a private file from a public machine?&lt;/p&gt;

&lt;p&gt;I followed that one photo for 44 minutes through all four. A few things I wish someone had told me earlier.&lt;/p&gt;

&lt;p&gt;Most engineers think the cache key is the URL. It isn't. It's the method plus the URI plus whatever your config or a Vary header bolts on. CloudFront's default CachingOptimized policy ignores query strings entirely. Cloudflare's default includes the full query string, verbatim, order included. Same photo URL, opposite behavior, two vendors.&lt;/p&gt;

&lt;p&gt;Add Vary: User-Agent and you get one cache entry per browser build. One extra header can take a hit ratio from the high nineties into single digits.&lt;/p&gt;

&lt;p&gt;A long TTL is permission, not a guarantee.&lt;/p&gt;

&lt;p&gt;Eviction happens whenever the edge wants the space back. And when a viral object does expire, it expires on every tier at once, so edges everywhere turn around and hit your origin in the same window. That's the thundering herd. Request collapsing and Origin Shield exist so that as few as one request per object reaches you.&lt;/p&gt;

&lt;p&gt;Purges are priced by the path you submit, not the files it clears. CloudFront gives you 1,000 free paths a month, then $0.005 each. Which is the actual argument for versioned filenames: photo.a3f9.jpg never needs purging.&lt;/p&gt;

&lt;p&gt;Which edge answers? GeoDNS guesses from your resolver's address, not yours. EDNS Client Subnet patches the guess. Anycast removes it: every edge announces the same IP, and failover becomes a routing event with no DNS TTL to wait out.&lt;/p&gt;

&lt;p&gt;And the number interviewers ask for is the wrong one. Going from 90% to 95% hit ratio sounds like five points. It halves your origin load. Origin offload is the metric. Hit ratio is the proxy.&lt;/p&gt;

&lt;p&gt;The private file? Signed URLs for a single object. Signed cookies when one viewer needs a hundred of them.&lt;/p&gt;

&lt;p&gt;Full walkthrough, one photo end to end, built from the vendor docs and the RFCs rather than folklore:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=gV_z0uG8_uo" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=gV_z0uG8_uo&lt;/a&gt;&lt;/p&gt;

</description>
      <category>backend</category>
      <category>systemdesign</category>
      <category>architecture</category>
      <category>distributedsystems</category>
    </item>
    <item>
      <title>Circuit Breaker Pattern Explained</title>
      <dc:creator>Joud Awad</dc:creator>
      <pubDate>Mon, 07 Sep 2026 15:25:36 +0000</pubDate>
      <link>https://dev.to/thejoud1997/circuit-breaker-pattern-explained-ln2</link>
      <guid>https://dev.to/thejoud1997/circuit-breaker-pattern-explained-ln2</guid>
      <description>&lt;p&gt;Payments went fully down, and checkout was fine.&lt;/p&gt;

&lt;p&gt;The next week payments stayed up and answered in 30 seconds instead of 40 milliseconds. The entire site went dark.&lt;/p&gt;

&lt;p&gt;A dead dependency is a small problem. A slow one takes everything with it.&lt;/p&gt;

&lt;p&gt;Every call still waiting is holding a thread, a database connection and a chunk of memory that the product page needed too. Nothing throws an error. The pool is just gone.&lt;/p&gt;

&lt;p&gt;That's the cascading failure a circuit breaker exists to stop — and it's why the breaker is never installed on its own. A request meets a timeout, then a retry policy, then the breaker, then a fallback. In that order.&lt;/p&gt;

&lt;p&gt;Most of us built that chain from a tutorial that said "open after 5 consecutive failures."&lt;/p&gt;

&lt;p&gt;Go read your actual config.&lt;/p&gt;

&lt;p&gt;Resilience4j, Hystrix, Polly and gobreaker don't count consecutive failures. They trip on a failure rate across a sliding window, gated by a minimum call volume. Which is better — until you notice that on a low-traffic endpoint, two of those defaults combine to leave the breaker unable to open at all. Not "slow to open." Unable.&lt;/p&gt;

&lt;p&gt;Three more things I had wrong for years:&lt;/p&gt;

&lt;p&gt;Retries are selfish. Exponential backoff without jitter doesn't spread the load, it just reschedules the same spike for later.&lt;/p&gt;

&lt;p&gt;You can have full throughput and zero goodput at the same time, and every dashboard will look busy while nothing succeeds.&lt;/p&gt;

&lt;p&gt;And AWS's own Builders' Library warns that circuit breakers add modal behavior and recovery time — its SDK ships a retry token bucket instead. Amazon has a written case against fallback code, too. The pattern everyone teaches as the answer is the one Amazon argues you should think twice about.&lt;/p&gt;

&lt;p&gt;So I built the version that includes the numbers and the counterarguments: 36 minutes, one call from checkout to payments, all the way through.&lt;/p&gt;

&lt;p&gt;If you take one thing: an open breaker with no alarm on its state changes is a silent partial outage.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://youtu.be/rvKKj7JU92g" rel="noopener noreferrer"&gt;https://youtu.be/rvKKj7JU92g&lt;/a&gt;&lt;/p&gt;

</description>
      <category>systemdesign</category>
      <category>microservices</category>
      <category>backend</category>
      <category>software</category>
    </item>
    <item>
      <title>Database Internals For System Design</title>
      <dc:creator>Joud Awad</dc:creator>
      <pubDate>Mon, 31 Aug 2026 15:56:17 +0000</pubDate>
      <link>https://dev.to/thejoud1997/database-internals-for-system-design-1fl4</link>
      <guid>https://dev.to/thejoud1997/database-internals-for-system-design-1fl4</guid>
      <description>&lt;p&gt;They added an index and the query got slower.&lt;/p&gt;

&lt;p&gt;Then they doubled the instance size and bought back 400 milliseconds.&lt;/p&gt;

&lt;p&gt;So they put Redis in front of it. The hit rate came back at 4 percent. Then they added a read replica, and it fell 45 seconds behind.&lt;/p&gt;

&lt;p&gt;Four fixes. All reasonable. All wrong.&lt;/p&gt;

&lt;p&gt;None of it was bad luck. Every one of those numbers was predictable from what the engine was doing underneath the query.&lt;/p&gt;

&lt;p&gt;The index lost because the planner's row estimate was off — and an index scan is two hops, find the entry, then go fetch the row. Past enough rows, reading the pages straight through just wins.&lt;/p&gt;

&lt;p&gt;The 4 percent wasn't a Redis problem. It was the diagnosis. A cache is a second buffer pool. If the working set doesn't fit in the first one, it isn't going to fit in the second one either.&lt;/p&gt;

&lt;p&gt;And the replica lag came from the same place. Replication is the write-ahead log, shipped. An UPDATE in Postgres never overwrites a row — it writes a new version. More versions, more WAL, more lag.&lt;/p&gt;

&lt;p&gt;Same layer, three times. Storage.&lt;/p&gt;

&lt;p&gt;Most of us learned databases top-down: write the query, add an index when it's slow, add a replica when the index stops helping. That's backwards. Indexes make no sense without pages. Joins make no sense without indexes. And nobody explains the WAL until the replica is already 45 seconds behind.&lt;/p&gt;

&lt;p&gt;So I built the bottom-up version I wish I'd had.&lt;/p&gt;

&lt;p&gt;2 hours 22 minutes. Seven layers — storage, indexes, pagination, execution, transactions, read scaling, schema. One query, one 200 million row table, all the way up. Seven checkpoint quizzes with real countdowns, so you answer before you hear the answer.&lt;/p&gt;

&lt;p&gt;If you only watch part of it, watch the bottom four.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://youtu.be/uy2yom0AlhA" rel="noopener noreferrer"&gt;https://youtu.be/uy2yom0AlhA&lt;/a&gt;&lt;/p&gt;

</description>
      <category>database</category>
      <category>systemdesign</category>
      <category>distributedsystems</category>
      <category>backend</category>
    </item>
    <item>
      <title>DynamoDB Client API Tutorial: Query, Pagination, Cost Explained</title>
      <dc:creator>Joud Awad</dc:creator>
      <pubDate>Mon, 24 Aug 2026 09:24:02 +0000</pubDate>
      <link>https://dev.to/thejoud1997/dynamodb-client-api-tutorial-query-pagination-cost-explained-24hi</link>
      <guid>https://dev.to/thejoud1997/dynamodb-client-api-tutorial-query-pagination-cost-explained-24hi</guid>
      <description>&lt;p&gt;There is no SQL in DynamoDB.&lt;/p&gt;

&lt;p&gt;No query language, no syntax to memorize, no planner deciding how your request gets run. You import a client and you call a method.&lt;/p&gt;

&lt;p&gt;In Postgres, "give me one row" and "give me a thousand rows" are the same SELECT with different clauses, and the engine works out the rest. In DynamoDB those are different methods and you're the one choosing. GetItem for a single item by its key. BatchGetItem for up to 100 of them. Query for a run of items under one partition key. Scan for when you've given up and want the whole table.&lt;/p&gt;

&lt;p&gt;The method name is the operation. That's the shift people miss coming from SQL: you're not composing a statement, you're picking an action. One item or many, atomic or not, read or write. Three decisions, and the entire client API falls out of them.&lt;/p&gt;

&lt;p&gt;What you do have to learn is the cost, because it isn't hidden behind a planner any more. 4 KB read blocks, 1 KB write blocks, and a round-up rule that makes a 200-byte item cost a full block. A strongly consistent read costs double an eventual one. A read inside a transaction doubles again. Once you know which method you called, you can price the call before you run it.&lt;/p&gt;

&lt;p&gt;So I ran every one of them on camera, from real NestJS code, with the consumed capacity on screen next to each call.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://youtu.be/JeyZ-kN0H7Y?si=ZkvqVIC1TCjCX06k" rel="noopener noreferrer"&gt;https://youtu.be/JeyZ-kN0H7Y?si=ZkvqVIC1TCjCX06k&lt;/a&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>dynamodb</category>
      <category>nosql</category>
      <category>backend</category>
    </item>
    <item>
      <title>DynamoDB Table Design: Complete Data Modeling Guide</title>
      <dc:creator>Joud Awad</dc:creator>
      <pubDate>Thu, 20 Aug 2026 16:16:51 +0000</pubDate>
      <link>https://dev.to/thejoud1997/dynamodb-table-design-complete-data-modeling-guide-3of9</link>
      <guid>https://dev.to/thejoud1997/dynamodb-table-design-complete-data-modeling-guide-3of9</guid>
      <description>&lt;p&gt;DynamoDB Data modeling is one of the hardest things that appears on paper. Still, once you understand the different access patterns and how DynamoDB queries your data, it starts being an easy task.&lt;/p&gt;

&lt;p&gt;DynamoDB uses a unique combination of Partition Key (PK) and sort keys (SK) in order to store and query your data, and understanding how those two works under the hood is the first part of working with DynamoDB, the hard part and the most challenging is to understand how to model your data, how to model your access pattern, and how you can extract questions from your own system and convert them into a working DynamoDB Tables.&lt;/p&gt;

&lt;p&gt;In this video, we walk you through a full DynamoDB end-to-end table design, covering all the access patterns DynamoDB uses to build &lt;em&gt;&lt;strong&gt;three&lt;/strong&gt;&lt;/em&gt; real-world case examples.&lt;/p&gt;

&lt;p&gt;At the end of this video, you will be able to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Understand how DynamoDB Data Modeling works.&lt;/li&gt;
&lt;li&gt;Build your own DynamoDB Tables.&lt;/li&gt;
&lt;li&gt;Convert your own use case into a question DynamoDB is able to answer for you.&lt;/li&gt;
&lt;li&gt;Model any real-world use case that you may face in your own application.&lt;/li&gt;
&lt;li&gt;Master the Single-Table Design in DynamoDB&lt;/li&gt;
&lt;li&gt;Work and interact with all the differnet access patterns DynamoDB provide to you.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Video Link: &lt;a href="https://www.youtube.com/watch?v=rbP1jGNzG2A" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=rbP1jGNzG2A&lt;/a&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>database</category>
      <category>dynamodb</category>
      <category>backend</category>
    </item>
  </channel>
</rss>
