Search Tech Journey

Find topics, journeys and posts

back to blog
generalintermediate 30m read

Building a Learning System That Actually Sticks

Most self-study fails at retention, not effort. The complete architecture of a 26-week system — 130 concept sessions, 65 LeetCode sessions, spaced revision, and a calendar that enforces retrieval practice instead of re-reading.

Building a Learning System That Actually Sticks

I have restarted the same curriculum four times.

Not because the material was wrong. The material was fine — good books, good courses, a reasonable order. I restarted because six weeks in, I could not reliably explain something I had "learned" in week two. The notes existed. The highlighted PDFs existed. The knowledge did not.

That is a systems failure, not a discipline failure. The fix is not more hours. It is building a system whose default behaviour produces retention, so that on the days when motivation is absent — which is most days — the structure still works.

This post documents that system completely: what it is, why each piece exists, what the evidence says, and how it is enforced.


Part 1 · Why studying feels productive and isn't

The fluency illusion

Open a textbook chapter you read last week. It looks familiar. You recognise the diagrams, you nod along, the sentences make sense. That feeling of ease is what psychologists call fluency, and it is a catastrophically bad signal of learning.

Fluency measures how easily information moves in. Learning is about how reliably it comes out. These come apart badly. Re-reading maximises the first and does almost nothing for the second — which is exactly why it is the most popular study technique and one of the least effective.

The uncomfortable inversion at the heart of the research literature:

The techniques that feel most productive while you're doing them are usually the least effective, and the techniques that feel like failure are usually the ones that work.

This has a name — Bjork's desirable difficulties. Conditions that slow acquisition and increase perceived effort often improve long-term retention and transfer. Struggling to recall is not a sign the system is broken. It is the mechanism.

What the evidence actually supports

Four effects have survived decades of replication and are strong enough to build on.

1. The testing effect (retrieval practice). Trying to retrieve information strengthens memory more than re-studying it for the same duration. Roediger and Karpicke's 2006 work is the canonical demonstration: students who studied then tested outperformed students who studied repeatedly, and the gap widened at longer delays. Crucially, the study-repeatedly group predicted they would do better. They were confident and wrong.

2. Spacing. Reviewing material at increasing intervals beats massing it together, for the same total time. Cepeda and colleagues' 2006 meta-analysis found the effect robust across hundreds of experiments, with the optimal gap scaling with how long you need to retain. This is the Ebbinghaus forgetting curve exploited rather than fought.

3. Interleaving. Mixing problem types within a session beats blocking them, even though blocking feels better and produces better practice performance. Blocked practice teaches you to execute a procedure. Interleaved practice teaches you to select it — the skill you actually need when nobody tells you which chapter the problem came from.

4. Generation. Producing an answer before seeing it improves retention even when the attempt fails. A failed retrieval attempt still primes encoding. This is why guessing first, then checking, beats reading the answer directly.

The engineering translation

Strip the psychology and you get four design constraints:

PrincipleSystem requirement
Testing effectEvery session must end by producing, not reviewing
SpacingReview scheduled at expanding intervals, automatically
InterleavingTopics mixed, not batched by module
GenerationThe blank page comes before the material

Everything below implements that table.


Part 2 · The architecture

Three tracks in parallel, plus a consolidation layer.

1Concept track

130 sessions · Mon–Fri 20:30–21:30 IST · one atomic concept per session, from dev environment through distributed systems to LLMs

2LeetCode track

65 sessions · every other day 07:00–08:15 IST · pattern-first algorithmic practice, treated as a motor skill

3Revision track

27 sessions · Saturdays 09:30–11:00 IST · blank-page retrieval across all prior weeks

4Consolidation

Sunday off, deliberately. Plus a nightly automated digest that compresses each day's work into long-term notes.

Why separate tracks at all

Concepts and algorithms are different kinds of knowledge and decay differently.

Understanding how a B-tree index works is semantic knowledge — a model you reason with. Solving a sliding-window problem under time pressure is closer to a motor skill — pattern recognition plus a rehearsed motion, like a musician's scales. Semantic knowledge tolerates gaps and rebuilds from principles. Motor skills degrade fast without frequent, short, regular practice.

So they get different treatment. Concepts get long evening sessions with depth and derivation. Algorithms get short frequent morning sessions with drills. Merging them into one block would apply the wrong protocol to both.

The schedule

Mon–Fri  07:00–08:15   LeetCode        (every other day)
Mon–Fri  20:30–21:30   Concept session
Sat      09:30–11:00   Revision
Sun      —             rest (load-bearing)

About 9 hours a week. Sustainable for 26 weeks alongside a full-time job, which was the actual binding constraint. A 20-hour-a-week plan that collapses in month two is worth less than a 9-hour plan that survives to month six.

The tradeoff

Morning LeetCode or evening LeetCode? Both slots were available.

Morning (chosen)
+ you gain algorithmic work needs peak executive function, highest after sleep; it is finished before the workday can eat it; failing to finish does not cascade into the evening
− you pay requires waking earlier; poor sleep destroys the session directly; socially inflexible on weekday mornings
pick when the work is cognitively demanding and non-negotiable, and your evenings are unpredictable
Evening
+ you gain no schedule change; can run long when in flow; pairs naturally with the concept session
− you pay competes with the concept session for the same depleted attention; work overruns kill it first; two hard blocks back-to-back is where burnout starts
pick when your mornings are genuinely impossible or your job has predictable hours
What a senior engineer actually does

Morning, but with a make-good rule rather than a streak: a missed morning is re-solved during the Saturday block, not skipped and not doubled up the next day. Streaks create an incentive to fake completion. A make-good queue does not.

Interleaving, concretely

The 130 concept sessions come from 16 modules — Python, math, data structures, databases, data engineering, backend, systems, distributed systems, observability, security, classical ML, deep learning, NLP, LLMs, system design.

The naive schedule runs module by module. That is blocked practice, and it is the wrong shape.

Instead the sessions are round-robin interleaved across 7 tracks, with prerequisites enforced by a DAG validator. The first two weeks look like this:

Day 001  S001  Dev Environment          (SETUP)
Day 002  S005  Python Variables & Types (SWE)
Day 003  S002  Git & GitHub             (SETUP)
Day 004  S006  Control Flow             (SWE)
Day 005  S003  The Command Line         (SETUP)
Day 006  S055  HTTP Fundamentals        (BACKEND)
Day 007  S007  Functions                (SWE)
Day 008  S056  REST API Design          (BACKEND)

Python, tooling, and backend are braided together rather than served in blocks. It feels less tidy. That is the point — you are forced to context-switch, which makes the retrieval cue the problem itself rather than the chapter you happen to be in.

The constraint is that prerequisites must still hold. A validator checks the DAG before any calendar is generated: no session is scheduled before its prerequisites. Interleaving reorders; it never breaks dependencies.


Part 3 · The session protocol

Structure alone does nothing. What happens inside the 60 minutes is where retention is won or lost. Every concept session in the calendar now carries this protocol in its description, so there is no decision to make at 20:30.

The 60-minute concept protocol

1Blank page · 2 min

Before opening anything: write everything you already believe about today's topic. Being wrong is fine and useful — a failed retrieval attempt still primes encoding.

2Intuition · 8 min

The analogy and the why-this-exists. What breaks in a world without this concept?

3Visual · 10 min

Diagrams, memory layouts, request flows. Redraw them by hand rather than reading them.

4Code · 20 min

Type it, don't copy it. Then modify it until it breaks — and predict the breakage before running.

5Production reality · 8 min

War stories, failure modes, what this looks like at scale.

6Retrieval close · 12 min

Everything closed. Explain it out loud. Then answer the three questions.

The last block is the one that matters, and the one everybody skips. Three questions, every session, no exceptions:

  1. What did I learn today? — closed-book, out loud, in your own words.
  2. What breaks if this doesn't exist? — forces purpose, not just mechanism.
  3. Where have I already seen this in my own work? — the highest-value one.

That third question does the heavy lifting. A fact connected to your own experience has far more retrieval handles than a free-floating fact. I work on large-scale data pipelines and Copilot evaluation, so write-ahead logging is not an abstract concept — it is the thing that explains a specific recovery behaviour I have actually debugged. That connection is what makes it survive six months.

Mental modelEncoding vs retrieval

Think of memory as a warehouse with no search function. Encoding is putting a box in. Retrieval is finding it again using only the labels you wrote at the time.

Most studying obsesses over putting boxes in — reading more, highlighting more, taking prettier notes. But knowledge is rarely lost because it went in badly. It is lost because there was no path back to it.

  • Re-reading adds another copy of the box. It does not add a path.
  • Every retrieval attempt builds a path — and a failed attempt still builds part of one.
  • Connecting new material to something you already own gives you paths you did not have to invent.
  • Spacing works because retrieving a partially-faded trace builds a stronger path than retrieving a fresh one.
🔔 Fires when you see

Fire this whenever you catch yourself about to re-read something, re-watch a video at 2x, or highlight a passage. Ask instead: what path am I building, and could I get there from a blank page?

The 90-minute Saturday revision protocol

Revision was the weakest part of the original plan. The sessions existed, but their instructions amounted to "review weeks 1–2", which in practice meant re-reading notes and feeling good. All 27 were rewritten:

1Blank-page dump · 20 min

Notes CLOSED. For each session in scope, write what you remember. This will be uncomfortable. The discomfort is the mechanism.

2Gap check · 15 min

NOW open the notes. Mark only what you missed. That red list is your actual syllabus — not the original session list.

3Re-implement · 30 min

Pick one thing from the red list. Build it from memory. Not copy — rebuild.

4Write cards · 15 min

Turn each gap into a question. Questions only, never statements.

5Connect · 10 min

How does this week link to earlier weeks? Explicit connections are extra retrieval paths.

Common misconception
✗ What most people think

"Flashcards are for vocabulary and trivia. They are not useful for real engineering concepts."

✓ What is actually true

Cards fail for engineering when written as statements to recognise rather than questions requiring reconstruction. The format is not the problem; the card content is.

Why the myth is so sticky

Because most people's first exposure to flashcards was rote memorisation at school, where the cards genuinely were "term to definition". That works for vocabulary and produces nothing for conceptual knowledge — so the conclusion "cards don't work for hard material" feels earned rather than mistaken.

Prove it to yourself

Compare two cards on the same material.

Bad: "A B-tree index has O(log n) lookup." You read it, you nod, you learn nothing. That is recognition.

Good: "Why does a B-tree beat a binary search tree on disk, given both are O(log n)?" You must reconstruct the argument about node size matching page size and minimising disk seeks. That is retrieval.

The rule: if you can answer without generating anything, it is not a card.


Part 4 · The algorithm track

65 sessions, every other day, 75 minutes.

Pattern-first, not problem-first

The standard advice is "grind 300 problems". This mostly produces people who have seen 300 problems and can solve the 301st only if it closely resembles one of them.

The alternative is to learn the pattern first, then solve 4–6 problems that are the same pattern wearing different clothes. You are explicitly training the mapping from problem surface features to technique — because that mapping, not the coding, is what fails under interview pressure.

From first principles
Start with the question

Why do the constraints in a problem statement tell you the intended algorithm before you have thought about the problem at all?

  1. 1
    Judges enforce a time limit — typically around one second — and commodity hardware executes on the order of 108 simple operations in that window.
    forced by · the limit must be generous enough for the intended solution and tight enough to reject worse ones
  2. 2
    The setter chooses the input bound n precisely so the intended complexity fits inside that budget while the next-worse complexity does not.
    forced by · otherwise the problem fails to discriminate between solutions, which defeats its purpose
  3. 3
    So n and the target complexity are locked together. Given n, only a narrow band of complexities is viable.
    forced by · complexity classes separate fast — at n = 105, O(n log n) is comfortable while O(n²) is 1010 operations
  4. 4
    Therefore reading n eliminates most of the search space before you have understood the problem.
    forced by · you are inverting the setter's own design constraint
⇒ Therefore

Constraints are a hint channel, and reading them first is not cheating — it is reading the problem correctly. Roughly: n up to 20 suggests exponential (bitmask, backtracking); n up to a few thousand permits O(n²) DP; n up to 105 demands O(n log n) or better; n up to 109 means you cannot even iterate, so think math, binary search on the answer, or closed form.

Note what this predicts: if you meet a problem where n is small yet the setter still rejects your exponential solution, the intended difficulty was never speed — it is correctness on adversarial cases you have not considered.

Structure

  • Phase 0 (L01–L06) — assumes you have never opened LeetCode. Reading constraints as hints, Big-O by counting rather than vibes, the twenty Python idioms that matter, the UMPIRE framework.
  • Phase 1 (L07–L32) — the core patterns covering most interviews: two pointers, sliding window, binary search including binary search on the answer, monotonic stack, trees, graphs, union-find, backtracking.
  • Phase 2 (L33–L44) — twelve sessions on dynamic programming alone, because that is where nearly everyone stalls and where one or two sessions is simply not enough.
  • Phase 3 (L45–L56) — tries, bit manipulation, intervals, greedy exchange arguments, LRU and design problems, segment trees, KMP, Dijkstra.
  • Phase 4 (L57–L65) — timed mocks, one recorded narrated mock, a Blind-75 gap audit, targeted weak-pattern repair, contest simulation.

The two-attempt rule

The single most important rule in the track:

Attempt cold for 25 minutes. If stuck, look only at the pattern name — not the solution. Attempt again for 15 minutes. Only then read the editorial. Whatever happens, re-solve it from scratch on the scheduled review date.

Reading a solution and understanding it produces the fluency illusion in its purest form. You understood it; you did not generate it; you will not reproduce it. The middle step — being told only the pattern — is where the learning happens, because it forces you to do the mapping yourself within a narrowed search space.

Status codes drive the spacing

Every solved problem gets a status, and the status sets when it returns:

StatusMeaningNext review
coldsolved unaided, first attempt+60 days
warmsolved, but slowly or with false starts+21 days
hintneeded the pattern name+7 days
failedneeded the editorial+2 days

This is spaced repetition with the interval driven by demonstrated difficulty rather than a fixed schedule. Every LeetCode calendar event already carries its own review queue: session L09 tells you to re-solve L05's problems, and so on at +7 / +21 / +60 days.

The failure log

Every miss is logged with one unusual column: the cue I missed.

Not "I didn't know DP" — that is useless. Instead:

"'Maximum number of non-overlapping intervals' should have triggered interval-DP-or-greedy. I read it as a sorting problem and lost 20 minutes."

The cue is the thing being trained. Interview failure is almost never "I couldn't implement a heap". It is "I didn't realise this was a heap problem". The failure log makes that invisible mapping visible so it can be drilled directly.


Part 5 · The content layer

Scheduling is only half of it. I also audited the written material — 210 sessions — and found a systematic gap.

Every session already had intuition, an analogy, diagrams, hands-on code, a production war story, and a quiz. That is a good structure. But across all 210 files there were zero instances of four things:

So I built four new MDX components and every session is being rewritten to include them.

The Misconception block is the one I would defend hardest, and its most important field is neither the myth nor the correction — it is why the myth is sticky. "This is wrong because X" is forgettable. "You believe this because it is true for integers and false for lists, and integers are what you met first" is not, because it explains your own error back to you.

The Tradeoff block has one hard rule: the "pick this when" condition must be testable. "When appropriate" is banned. "When writes exceed roughly 10k/s" or "when the team is under five people" is what a real decision rule looks like.


Part 6 · Consolidation and the memory layer

Sunday is load-bearing

There is no session on Sunday. That is a design decision, not a concession.

Memory consolidation — the transfer from fragile short-term traces to stable long-term storage — happens substantially during rest and sleep, not during study. Sleep-dependent consolidation is among the better-established findings in memory research. Filling every day is not more efficient; it removes the process that makes the other six days work.

The same logic applies daily: the concept session ends at 21:30 and not later, because studying up to the moment you sleep trades consolidation for the feeling of having done more.

Automated nightly consolidation

I implemented the same principle for my working notes. A job runs at 02:00 IST nightly and compresses that day's raw activity log into a compact digest. A second job at 02:15 rebuilds a curated "spine" — the durable rules and decisions — from those digests.

Order matters, and it is the whole trick: consolidate before clearing. The digest is written to disk before any context is reset. The failure mode being guarded against is the obvious one — a system that clears working state on a timer and loses whatever had not yet been written down.

The other hard rule: nothing is ever deleted, only demoted. Old daily logs move to an archive directory and stay searchable. There is no path where the maintenance job destroys information, because a memory system you cannot trust to be lossless is one you will stop relying on.

The tradeoff

How aggressively should a memory system compress old notes?

Aggressive summarisation
+ you gain a small, fast, high-signal corpus you can actually load and read end-to-end; less noise when searching
− you pay compression is lossy and irreversible; the detail you discard is chosen by a past self who did not know what a future self would need
pick when the material is genuinely transient, or a full archive is preserved separately
Tiered demotion (chosen)
+ you gain nothing is ever lost; hot tier stays small and readable while cold tier remains searchable on demand
− you pay storage grows without bound; search must span tiers; requires discipline about what gets promoted
pick when the cost of losing one important detail exceeds the cost of storing everything — which for notes is almost always
What a senior engineer actually does

Demote, never delete. Storage is effectively free and regret is not. The one real risk is that the hot tier silently bloats until nothing loads it, so the hot tier needs a hard size cap enforced by the nightly job — a cap on what is promoted, not on what is kept.


Part 7 · What I would tell someone copying this

Start with the calendar, not the curriculum. A perfect curriculum with no scheduled time produces nothing. A mediocre curriculum on a real calendar produces a lot. I spent far too long on curriculum design before admitting that scheduling was the binding constraint.

Put the protocol in the calendar event. Not in a document you will open once. At 20:30 on a Tuesday you will not go looking for the retention protocol — but you will read the thing already on your screen. Every event carries its full protocol inline.

Make the review automatic. If you have to decide what to review, you will review what feels comfortable, which is what you already know. Every session's review targets are computed and embedded when the calendar is generated.

Track the cue, not the topic. "I'm weak at DP" is not actionable. "I don't recognise when 'minimum cost to reach' means DP" is a drill you can run tomorrow.

Expect the first month to feel bad. Blank-page dumps are unpleasant when the page stays mostly blank. That is the system working as designed, not evidence that it is failing.

Delete the streak. Streaks optimise for unbroken chains, which means they optimise for doing the minimum that counts as "done" and for lying to yourself on bad days. A make-good queue is honest: the work is either done or queued, and nothing is hidden.

The honest limitations

I should be clear about what this system does not do.

It has not yet been run to completion — it starts in August and ends in December. What I can defend today is that each component rests on well-replicated findings and that the failure modes of my previous four attempts were specifically designed against. I cannot yet tell you it worked, and any post claiming otherwise about an unfinished plan is selling something.

The 9-hour weekly load is calibrated to my life. It is not a universal number.

And the biggest risk is not retention at all — it is schedule collapse under work pressure. No amount of spacing theory survives a bad quarter. That is why the make-good queue exists instead of a streak, and why Sunday stays empty as slack rather than being filled with a seventh session.


Appendix · The stack

Deliberately boring, because the failure mode of a personal system is maintenance burden.

LayerToolWhy
CurriculumMarkdown in gitDiffable, greppable, no lock-in
Session contentMDX + Next.jsComponents for structure; this blog is the reading surface
ScheduleGoogle Calendar API via PythonAlready on my phone and laptop; notifications for free
Session dataJSONCurriculum is data; calendar generation is a pure function of it
Spaced reviewComputed at generation timeNo runtime dependency, no app to maintain
ProgressMarkdown tablesFast to edit; no tool between me and the record
ConsolidationCron + PythonRuns nightly, writes markdown, never deletes

The pattern throughout: curriculum is data, schedule is a pure function of that data, and both live in git. Regenerating the entire calendar is one command, which means the plan can be reshaped when life changes — and it will.

Everything except my private notes is in the repos behind this blog. If you want to copy the structure, take the protocols first. The content is mine; the protocols are general.