Skip to content

TodayILearned

365 entries of learning in public

A 365-entry fullstack engineering challenge. Entries are taught deeply and may be published in catch-up batches, so entry numbers are not calendar dates.

til.challenge

day 053 / 365

053

of 365 days

14.5% complete · 53 published · 35 with video

  • Databases 23
  • Algorithms 15
  • System Design 15

latest.entry

Day 053

lesson.log

52 earlier lessons, newest first

Day 052

Row-level security - tenant walls inside one table

GRANT leaks all tenants; RLS policies scope rows. Lab: open 100/100 vs RLS 40/60, cross INSERT 0 on til-postgres.

Databases Video
Day 051

Saga compensations - undo forward steps when the chain breaks

Multi-service checkout without 2PC: reverse compensations drive inconsistent terminals from ~46/200 to 0 in lab.

System Design Video
Day 050

Optimistic concurrency - version columns beat blind RMW

Blind read-modify-write loses concurrent decrements; version WHERE keeps stock correct with retries. Lab: final 99 vs 92 on til-postgres.

Databases Video
Day 049

Transactional outbox - publish without dual-write lies

Atomic business write + outbox row; dual-write loses ~15% under crash; outbox loses 0 and may duplicate.

System Design
Day 048

LISTEN / NOTIFY - wake workers without polling the table

DB-native doorbell after COMMIT; not a durable queue. Lab: 30/30 commit deliver, 30/30 rollback silent, coalesce 30/30.

Databases
Day 047

Container With Most Water - move the shorter wall

Converging two pointers maximize min(height)×width. Always advance the shorter side. 324.6x vs brute at n=2K.

Algorithms
Day 046

3Sum - fix one index, then run Two Sum II on the rest

Sort once, fix i, Day 40 squeeze for -nums[i], skip duplicates. O(n2). 236.9x vs brute at n=300.

Algorithms
Day 045

lock_timeout and NOWAIT - fail fast instead of waiting forever

Unbounded lock waits vs lock_timeout ceiling vs FOR UPDATE NOWAIT; lab medians 441 / 114 / 13.3 ms on til-postgres.

Databases
Day 044

Backpressure - teach the producer to slow down

Fast producer, slow consumer. Unbounded max depth 3,750 vs cap 64 (58.6x). Block keeps all work; reject fails fast.

System Design Video
Day 043

Advisory locks - a mutex that is not a row lock

Leader election without a job row. pg_try_advisory_xact_lock. Lab: 8 false leaders vs 1 winner 30/30 on Podman PG 18.

Databases Video
Day 042

Bulkhead Isolation - Seal the Flood

Partition worker capacity so a slow dependency cannot starve healthy work. Lab: healthy 0→80 by t=40; wall 210→400 tradeoff.

System Design Video
Day 041

Isolation Levels - What Each Level Permits

RC permits non-repeatable reads (30/30); RR blocks them but write-skew 30/30; SSI blocks skew with serialization failures (retry).

Databases Video
Day 040

Two Sum II - sorted array, squeeze from both ends

Day 11 needed a hash map. Sorted input flips the tool: converging two pointers - O(n) time, O(1) space. 13.0x vs binary, 59.4x vs hash at n=100K.

Algorithms
Day 039

Valid Palindrome - two pointers that walk toward each other

Day 33 moved pointers in the same direction. Today they converge from both ends, skipping noise inline. No-alloc two-ptr: 6.3× faster than reverse at n=100K.

Algorithms
Day 038

SKIP LOCKED - Claim the Next Free Job

FOR UPDATE queues workers; SKIP LOCKED lets them claim different jobs. Lab: 40/0 vs ~18/22; 1.25× drain (1595→1271 ms).

Databases Video
Day 037

Retry Backoff Needs Full Jitter

Exponential backoff alone still clusters. Full jitter cuts client work ~4.21× (1275→303 attempts). Labeled multi-client sim.

System Design Video
Day 036

Deadlocks - When Lock Waits Form a Cycle

Opposite lock order creates a wait-for cycle; PG aborts one victim. Lab: opposite 30/30 DL; ordered 0. Defense: sorted lock helper + 40P01 retry.

Databases Video
Day 035

Circuit Breaker - Fail Fast on a Dead Dependency

CLOSED to OPEN to HALF-OPEN: stop paying the timeout tax. Lab (fake clock): 10,200 ms to 450 ms (~22.67x wall), 200 to 5 dep calls (~40x). Pool-fill blast radius craft.

System Design Video
Day 034

Deferred Constraints - Check at COMMIT

DEFERRABLE FKs let multi-statement txs temporarily break order; integrity still holds at COMMIT. Timing SVG + lab: cycle 1↔2 OK deferred; bulk child-first 3.467 vs parent-first 6.146 ms (0.564×).

Databases Video
Day 033

Is Subsequence - Two Pointers, Order Kept

Two pointers: walk t once, advance i only on match. Subsequence ≠ substring. Lab: indexOf ~97× vs two-pointer JS on |t|=500K.

Algorithms
Day 032

Valid Sudoku - One Pass, Three Memberships

Row / col / box Sets in one pass. Box index floor(r/3)*3+floor(c/3). Lab: bitmask 2.99× vs brute; Sets slower (alloc tax) on 20K boards.

Algorithms
Day 031

Exclusion Constraints - No Two Rows May Conflict

EXCLUDE USING gist blocks multi-row conflicts (double-book). Lab PG 18.4: 2 rows/1 pair without; reject with; bulk 1.035×; range-race craft.

Databases Video
Day 030

Idempotency Keys - Retries That Do Not Double-Charge

At-least-once delivery needs exactly-once effects. Lab: 6 attempts → 6 charges naive vs 1 with key; 50K unique 28.417 ms vs replay 1.716 ms (16.56×).

System Design Video
Day 029

CHECK Constraints - Last Line of Defense

CHECK enforces domain predicates on every write. Lab PG 18.4: 2 bad rows without CHECK, 0 with; bulk tax 0.986× noise. Gate-slam craft.

Databases Video
Day 028

Consistent Hashing - Add a Server Without Reshuffling the World

Ring placement + virtual nodes: minimize remap on membership change. Lab: 3→4 modulo 75.29% vs consistent 20.71% (3.64× fewer moves); 10→11 10.61×. Vnode-spread craft.

System Design Video
Day 027

WAL - Commit Hits Disk Before the Table Does

Write-ahead log: append, fsync, then COMMIT; heap later. Lab PG 18.4: durable 3587.703 ms vs async 2392.958 ms (1.50×) vs UNLOGGED 2440.399 ms (1.47×). Crash-timeline craft.

Databases Video
Day 026

Longest consecutive sequence - hash-set sequence heads

Only expand from sequence heads (n-1 missing). Amortized O(n) with a Set - 124.7× faster than brute at n=5K mixed.

Algorithms
Day 025

Encode / Decode Strings - Length-Prefix Framing

join("#") is not a codec. Prefix each string with its length, slice by that length on decode - 14.3× faster than escaping on hostile data.

Algorithms
Day 024

MVCC - How PostgreSQL Does Concurrency

UPDATE never overwrites a row. It creates a new version. Readers use snapshots. Dead versions pile up until VACUUM reclaims them - and restores Heap Fetches: 0.

Databases Video
Day 023

Database Replication - Single-Leader

Your database has one copy. If it goes down, everything goes down. Replication creates copies - but each copy introduces a new question: how stale is too stale?

System Design Video
Day 022

Partial Indexes - When Less Is More

Index only the rows you actually query. A partial index uses a WHERE clause to index a subset of rows - smaller, faster, and sometimes the only way to make a unique constraint make sense.

Databases Video
Day 021

CDN - caching at the edge

Your origin server is fast. But if the user is 10,000 km away, physics dominates. A CDN moves the cache to 300+ cities worldwide - the request never reaches your origin.

System Design Video
Day 020

Covering indexes - when the index is enough

An index finds rows fast. A covering index returns the data too - PostgreSQL skips the table entirely. Heap Fetches: 0 is the magic line in EXPLAIN.

Databases Video
Day 019

Product of array except self - prefix × suffix

The no-division constraint forces a reframe: the answer for each position is the product of everything before it × everything after it. Two passes, O(n) time, O(1) auxiliary space.

Algorithms
Day 018

Top K Frequent Elements - Heap vs Bucket Sort

Day 5 counted frequencies. Day 12 grouped anagrams by a canonical signature. Today: find the top K. Three approaches, three Big O complexities - and a benchmark that shows the textbook O(n) answer isn't always the fastest in practice.

Algorithms
Day 017

Keyset Pagination - Why OFFSET Breaks at Scale

Your API returns page 500 in 50ms. Page 5000 takes half a second. Page 10000 takes two seconds. The user is just clicking 'next page' - so why does each page get slower? The answer is OFFSET, and the fix is a cursor.

Databases Video
Day 016

API Gateway - The Front Door

Load balancing distributes traffic. Rate limiting caps it. Caching skips work entirely. An API gateway does all three - plus authentication, routing, and protocol translation - at a single entry point. It's the composition layer where every previous lesson converges.

System Design Video
Day 015

JOINs - when two tables become one

Normalization split your data into honest tables. JOINs stitch it back together - at a cost. The planner picks the algorithm, but you control the indexes that make it fast.

Databases Video
Day 014

Message queues - when the request can't wait for the work

A load balancer distributes requests synchronously. A message queue decouples them asynchronously - the producer fires and forgets, the consumer processes at its own pace.

System Design Video
Day 013

Database normalization - 1NF, 2NF, 3NF

Three normal forms, three problems they solve. Normalization prevents anomalies; denormalization trades safety for speed.

Databases Video
Day 012

Group anagrams - sort key vs count key

Two ways to build a canonical key: sort each string (O(n × k log k)) or count characters (O(n × k)). The benchmark reveals a surprising crossover.

Algorithms
Day 011

Two Sum - hash map complement lookup

The #1 most-asked LeetCode problem. One pass, one hash map, one key insight: for each number, check if you've already seen its complement.

Algorithms
Day 010

Transactions and ACID - when all or nothing is the point

A connection pool gives you a connection. A transaction is what you do inside it - a unit of work that either fully succeeds or fully fails.

Databases Video
Day 009

Rate limiting - protecting your API

A load balancer distributes traffic. A rate limiter caps it. Here are the four algorithms and the tradeoff each one makes.

System Design Video
Day 008

Connection pooling - sharing database connections

Every database connection is expensive. A pool keeps a few warm and reuses them - the load balancer's cousin, one layer deeper.

Databases Video
Day 007

Load balancing - distributing traffic

One server can't handle it all. Here's how you spread the load - and the tradeoffs of each strategy.

System Design Video
Day 006

Composite indexes - the leftmost prefix rule

When you index multiple columns, order matters. Here's why - with a real benchmark.

Databases Video
Day 005

Valid Anagram - the frequency count pattern

When the question is 'how many times?', a hash map is the answer.

Algorithms
Day 004

Contains Duplicate - the hash set pattern

When 'have I seen this before?' is the question, a hash set is the answer.

Algorithms
Day 003

Reading EXPLAIN output

How to see what the database is actually doing - and whether your index is being used.

Databases Video
Day 002

What is caching?

And when does it bite you?

System Design Video
Day 001

Why does an index speed up a query?

And the part nobody mentions: when it actually makes things worse.

Databases Video