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:
| Principle | System requirement |
|---|---|
| Testing effect | Every session must end by producing, not reviewing |
| Spacing | Review scheduled at expanding intervals, automatically |
| Interleaving | Topics mixed, not batched by module |
| Generation | The blank page comes before the material |
Everything below implements that table.
Part 2 · The architecture
Three tracks in parallel, plus a consolidation layer.
130 sessions · Mon–Fri 20:30–21:30 IST · one atomic concept per session, from dev environment through distributed systems to LLMs
65 sessions · every other day 07:00–08:15 IST · pattern-first algorithmic practice, treated as a motor skill
27 sessions · Saturdays 09:30–11:00 IST · blank-page retrieval across all prior weeks
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.
Morning LeetCode or evening LeetCode? Both slots were available.
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
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.
The analogy and the why-this-exists. What breaks in a world without this concept?
Diagrams, memory layouts, request flows. Redraw them by hand rather than reading them.
Type it, don't copy it. Then modify it until it breaks — and predict the breakage before running.
War stories, failure modes, what this looks like at scale.
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:
- What did I learn today? — closed-book, out loud, in your own words.
- What breaks if this doesn't exist? — forces purpose, not just mechanism.
- 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.
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.
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:
Notes CLOSED. For each session in scope, write what you remember. This will be uncomfortable. The discomfort is the mechanism.
NOW open the notes. Mark only what you missed. That red list is your actual syllabus — not the original session list.
Pick one thing from the red list. Build it from memory. Not copy — rebuild.
Turn each gap into a question. Questions only, never statements.
How does this week link to earlier weeks? Explicit connections are extra retrieval paths.
"Flashcards are for vocabulary and trivia. They are not useful for real engineering concepts."
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.
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.
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.
Why do the constraints in a problem statement tell you the intended algorithm before you have thought about the problem at all?
- 1Judges 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
- 2The setter chooses the input bound
nprecisely 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 - 3So
nand the target complexity are locked together. Givenn, 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 - 4Therefore reading
neliminates most of the search space before you have understood the problem.forced by · you are inverting the setter's own design constraint
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:
| Status | Meaning | Next review |
|---|---|---|
| cold | solved unaided, first attempt | +60 days |
| warm | solved, but slowly or with false starts | +21 days |
| hint | needed the pattern name | +7 days |
| failed | needed 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.
How aggressively should a memory system compress old notes?
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.
| Layer | Tool | Why |
|---|---|---|
| Curriculum | Markdown in git | Diffable, greppable, no lock-in |
| Session content | MDX + Next.js | Components for structure; this blog is the reading surface |
| Schedule | Google Calendar API via Python | Already on my phone and laptop; notifications for free |
| Session data | JSON | Curriculum is data; calendar generation is a pure function of it |
| Spaced review | Computed at generation time | No runtime dependency, no app to maintain |
| Progress | Markdown tables | Fast to edit; no tool between me and the record |
| Consolidation | Cron + Python | Runs 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.