Mert Özen Further With Every Line

Blog

Mert Özen's blog posts on software development, backend, frontend, and DevOps.

Series
15 posts found
What Is System Design and How Do You Approach It? A 4-Step Method from Requirements to Deep Dive
Software Architecture PART 01

What Is System Design and How Do You Approach It? A 4-Step Method from Requirements to Deep Dive

You approach system design in four steps: clarify requirements and scope, draw a high-level design and get buy-in, deep dive into the component that carries the problem, then state the trade-offs and wrap up. In the Bookstore campaign day example, Little's law (L = λ × W) shows on paper that the bottleneck is the connection pool, not the CPU, and real SqlClient output confirms it.

8 Nov 2026 10 min 3
Back-of-the-Envelope Estimation: QPS, Storage, Bandwidth and Availability Math
Software Architecture PART 02

Back-of-the-Envelope Estimation: QPS, Storage, Bandwidth and Availability Math

Back-of-the-envelope estimation is a short chain of calculations from DAU to average and peak QPS, and from there to storage, bandwidth and availability, that gets the order of magnitude right. For a URL shortener with 10 million DAU, ~1,700 peak QPS and ~1 TB over 5 years fit one database, while 55.6 Gbps of egress makes a CDN mandatory for a photo app; 99.9% means 8.76 hours of downtime a year, and availability multiplies across serial components.

8 Nov 2026 13 min 3
From One Server to Millions of Users: Vertical and Horizontal Scaling and the Stateless Tier
Software Architecture PART 03

From One Server to Millions of Users: Vertical and Horizontal Scaling and the Stateless Tier

The precondition for scaling the application tier horizontally is being stateless: session, the Data Protection key ring, IMemoryCache, local files and scheduled jobs must move outside the instance. In a real two-instance experiment moving session to Redis alone fixes nothing, because session and authentication cookies are encrypted with Data Protection keys; once the key ring is shared too and SetApplicationName is set, the two servers behave like one application.

8 Nov 2026 11 min 2
Load Balancing: L4 vs L7, Algorithms, Health Checks and Sticky Sessions
Software Architecture PART 04

Load Balancing: L4 vs L7, Algorithms, Health Checks and Sticky Sessions

A load balancer's algorithm decides the latency users see when one instance slows down: in a real YARP experiment round robin pushes p99 to 4.6 seconds, while LeastRequests and power of two choices cut traffic to the slow instance by themselves and keep p99 at 300 ms. Only a health check removes a crashed instance (133 errors down to 35); the post also covers L4 vs L7, the cost of sticky sessions, connection draining and global load balancing with GeoDNS and anycast.

8 Nov 2026 11 min 3
Caching Strategies: Cache-Aside, Write-Through, Write-Behind and Cache Stampede
Software Architecture PART 05

Caching Strategies: Cache-Aside, Write-Through, Write-Behind and Cache Stampede

Cache-aside is the most common strategy, but the moment a popular entry expires all its load hits the database: in a real Redis experiment 200 concurrent requests produce 200 queries, and request coalescing brings that down to 1. 10,000 entries warmed in bulk expire in the same second without jitter, while ±10% jitter cuts the busiest second to 109 entries; early refresh with XFetch turns 500 recomputations into 1, and hot keys are found with Redis' LFU counter.

8 Nov 2026 11 min 3
Scaling the Data Layer: Replication, Sharding and SQL vs NoSQL
Software Architecture PART 06

Scaling the Data Layer: Replication, Sharding and SQL vs NoSQL

Scaling the data layer starts with access patterns: replication scales reads and availability but not writes, and sharding scales writes but turns queries without the shard key into scatter-gather. In a million-order experiment the customer query returns from one shard in 0.1 ms while the last-30-days query scans all four shards end to end; an async replica doesn't show a new order and needs a read-your-writes fix, and going from 4 to 5 shards with hash % N moves 80% of customers.

8 Nov 2026 11 min 3
Consistent Hashing: Hash Rings, Virtual Nodes and a C# Implementation
Software Architecture PART 07

Consistent Hashing: Hash Rings, Virtual Nodes and a C# Implementation

Consistent hashing is a distribution method that moves only about 1/(N+1) of the keys when the node count changes: going from 4 to 5 nodes hash % N moves 80% of the keys, while a hash ring written in C# with 200 virtual nodes moves ~20% and keeps the load within ±10% of the average. The properties are pinned down with xUnit tests; rendezvous hashing, Redis Cluster's hash slots and the string.GetHashCode trap are covered too.

8 Nov 2026 9 min 3
Asynchronous Processing: Queues, Workers, Fan-Out and Backpressure
Software Architecture PART 08

Asynchronous Processing: Queues, Workers, Fan-Out and Backpressure

Heavy work that is not part of the response moves out of the request to a queue and workers; the API returns 202 Accepted and a status address. In a real experiment the synchronous invoice endpoint times out 52 of 100 concurrent requests yet still renders 100 PDFs, while the bounded-queue version answers in 9 ms and pushes back with 503 and Retry-After when full; asynchrony decouples the work's timing, it doesn't speed it up.

8 Nov 2026 10 min 3
Designing Rate Limiting: Token Bucket, Sliding Window and a Distributed Rate Limiter
Software Architecture PART 09

Designing Rate Limiting: Token Bucket, Sliding Window and a Distributed Rate Limiter

A single rate limit needs its counter in a single place: ASP.NET Core's built-in limiter keeps counters in each instance's memory, so three instances triple the limit; the fix is an atomic counter in the gateway or in Redis. A comparison of five algorithms, a distributed sliding window limiter with Redis and Lua with real output, 429, Retry-After, the IETF RateLimit header draft and the DoS risk of partition keys.

8 Nov 2026 13 min 3
Reliability Patterns: Timeouts, Retries, Backoff with Jitter, Circuit Breakers and Load Shedding
Software Architecture PART 10

Reliability Patterns: Timeouts, Retries, Backoff with Jitter, Circuit Breakers and Load Shedding

Against a slow or failed dependency you need, in order, a timeout chosen from p99.9, jittered retries at a single layer and only for idempotent operations, a retry budget, a circuit breaker and bulkhead per dependency, and finally load shedding and graceful degradation. Real simulation output for retry amplification (27 and 243 calls), jitter, a 10% retry budget and a circuit breaker, failover, and .NET's standard resilience handler defaults.

8 Nov 2026 12 min 4
Generating Unique IDs: Auto-Increment, UUIDv4, UUIDv7 and Snowflake
Software Architecture PART 11

Generating Unique IDs: Auto-Increment, UUIDv4, UUIDv7 and Snowflake

In a sharded or multi-instance system, choosing an ID is a trade-off between uniqueness, sortability, size, coordination and what the ID leaks: UUIDv7 needs no coordination and is index friendly, Snowflake fits in 64 bits but needs worker ID and clock management. Real output showing .NET's CreateVersion7 doesn't guarantee order within a millisecond, a C# Snowflake generator and JavaScript's 2^53 limit.

8 Nov 2026 11 min 3
System Design Case Study: Designing a URL Shortener
Software Architecture PART 12

System Design Case Study: Designing a URL Shortener

A URL shortener is a read-heavy system: ~3,900 redirects against ~40 writes per second, so it needs a stateless redirect path, cache-aside, codes that never collide and are hard to guess, and 302 rather than 301 for analytics. A computed capacity table, a real measurement of hash collisions, counter + bijective mapping + base62, 301/302 curl output, aliases, expiration and abuse.

8 Nov 2026 12 min 3
Blog Map