Discover / Reading path

How to learn Programming

@readingsherpaNew to it → Going deep
11
Books
~100
Hours
4
Stages
Not yet rated

This curriculum takes you from absolute beginner to a well-rounded, deeply skilled programmer across four carefully sequenced stages. Each stage builds on the last — starting with thinking like a programmer, moving through clean code and data structures, then into software design, and finally into the timeless principles that separate good programmers from great ones.

1

Thinking Like a Programmer

New to it

Develop a mental model of how computers work and how to write your first programs with confidence, using Python as a clear, readable entry point.

Study plan for this stage

Pace: 12–16 weeks total: Weeks 1–5 — "Python Crash Course" (~30 pages/day, focusing on Parts I & II; skip the project chapters on first pass if needed); Weeks 6–10 — "Automate the Boring Stuff with Python" (~25 pages/day, prioritizing Chapters 1–9 and 15–18 for practical scripting); Weeks 11–16 — "Think P

Key concepts
  • Variables, data types, and expressions — understanding how Python stores and manipulates data (Python Crash Course, Ch. 2–4)
  • Control flow — using if/else statements and loops (for, while) to direct program logic (Python Crash Course, Ch. 5–7)
  • Functions — defining reusable blocks of code, understanding parameters, return values, and scope (Python Crash Course, Ch. 8; Think Python, Ch. 3 & 6)
  • Data structures — lists, tuples, dictionaries, and sets as tools for organizing information (Python Crash Course, Ch. 3–6; Think Python, Ch. 10–12)
  • File I/O and automation — reading/writing files and automating repetitive tasks with Python scripts (Automate the Boring Stuff, Ch. 8–9)
  • Working with modules and the standard library — importing and leveraging built-in Python tools like os, shutil, and re (Automate the Boring Stuff, Ch. 7–18)
  • Debugging and error handling — reading tracebacks, using try/except, and developing a systematic debugging mindset (Python Crash Course, Ch. 10; Think Python, Appendix A)
  • Computational thinking — decomposing problems, recognizing patterns, and reasoning about algorithms step by step (Think Python, throughout)
You should be able to answer
  • After reading Python Crash Course, can you explain what a variable is and walk through how Python evaluates an expression like `x = (3 + 5) * 2`?
  • How do for-loops and while-loops differ, and when would you choose one over the other? Give an example from your own practice scripts.
  • What is a function, and why does breaking code into functions make programs easier to read and maintain? (Think Python, Ch. 3)
  • How does 'Automate the Boring Stuff' demonstrate that programming is a practical, everyday skill — what is one real task from the book you could automate in your own life?
  • What is the difference between a list and a dictionary in Python, and what kinds of problems is each best suited for? (Python Crash Course, Ch. 3–6; Think Python, Ch. 10–11)
  • What does Think Python mean by 'incremental development,' and how does that approach change the way you write and test code?
Practice
  • Mini-project from Python Crash Course: Complete at least one of the three end-of-book projects (Alien Invasion, Data Visualization, or Web App) to experience a full development cycle from scratch.
  • Automation script from Automate the Boring Stuff: Write a script that renames a batch of files in a folder, using the os and shutil modules from Chapters 8–9 — apply it to a real folder on your computer.
  • Think Python exercises: Complete every end-of-chapter exercise in Think Python, paying special attention to the recursion (Ch. 5–6) and data structure chapters (Ch. 10–12); write your solutions by hand first, then test them.
  • Build a personal 'cheat sheet': After each book, write a one-page summary (in your own words) of the 5 most important concepts — compare how each book explains the same idea (e.g., functions) differently.
  • Debug intentionally broken code: Take 3–5 of your own working scripts and introduce deliberate bugs (wrong variable names, off-by-one errors, missing colons); practice reading the traceback and fixing each one systematically.
  • Translate a real-world process into code: Pick a repetitive task you do manually (sorting emails, organizing downloads, calculating a budget) and write a Python script for it using techniques from Automate the Boring Stuff, Chapters 12–18.

Next up: By finishing these three books, the reader has moved from zero to writing real, working Python programs — the next stage can build directly on this foundation by introducing structured software design, object-oriented programming, and more complex problem-solving patterns.

Python crash course
Eric Matthes · 2015 · 543 pp

The single best hands-on introduction to programming for beginners — it builds real intuition fast through projects, making abstract concepts concrete from day one.

Automate the Boring Stuff with Python
Al Sweigart · 2015 · 506 pp

Reinforces beginner Python by applying it to real-world tasks, cementing the habit of thinking 'what problem can code solve?' before moving to theory.

Think Python
Allen B. Downey · 2009 · 228 pp

Introduces computational thinking and problem decomposition more rigorously, bridging the gap between writing scripts and understanding programming as a discipline.

2

Core Computer Science Foundations

Some background

Understand the fundamental data structures and algorithms that underpin all serious programming, and learn to analyze the efficiency of your solutions.

Study plan for this stage

Pace: 10–14 weeks total. Weeks 1–4: Grokking Algorithms (~30–40 pages/day, reading all 11 chapters with illustrations and pseudocode walkthroughs). Weeks 5–14: Data Structures and Algorithms in Python (~25–35 pages/day, covering all 15 chapters; budget extra time for Chapters 9–13 which cover trees, heaps

Key concepts
  • Big-O notation and asymptotic analysis — understanding O(1), O(log n), O(n), O(n log n), O(n²) and how to classify your own code (introduced visually in Grokking Algorithms, formalized in Goodrich)
  • Core linear data structures — arrays, linked lists, stacks, queues, and deques, including their trade-offs in time and space (Goodrich Chapters 5–7)
  • Recursion and the call stack — how recursive calls consume stack frames, base cases, and how Grokking Algorithms uses divide-and-conquer to motivate merge sort and quicksort
  • Hash tables — collision resolution strategies (chaining vs. open addressing), load factor, and average-case O(1) lookup (Grokking Algorithms Chapter 5; Goodrich Chapter 10)
  • Trees and heaps — binary trees, binary search trees, AVL trees, and priority queues/heaps, including traversal algorithms (Goodrich Chapters 8–9)
  • Graph representations and traversal — adjacency lists vs. matrices, BFS, DFS, Dijkstra's algorithm, and topological sort (Grokking Algorithms Chapters 6–8; Goodrich Chapter 14)
  • Fundamental sorting and searching algorithms — binary search, selection sort, merge sort, quicksort, and their comparative Big-O profiles (both books)
  • Dynamic programming and greedy algorithms — optimal substructure, memoization, the knapsack problem, and when greedy choices are provably optimal (Grokking Algorithms Chapters 9–11; Goodrich Chapter 13)
You should be able to answer
  • Given a code snippet with nested loops or recursion, can you derive its Big-O time and space complexity and justify your answer using the definitions from Goodrich?
  • What are the concrete trade-offs between an array-backed list and a linked list for insertion, deletion, and random access — and when would you choose each in a Python program?
  • How does Dijkstra's algorithm differ from a plain BFS, and under what graph conditions does Dijkstra's fail (as explained in Grokking Algorithms Chapter 7)?
  • Walk through how a hash table handles a collision using chaining; what happens to average-case lookup performance as the load factor grows?
  • Describe the AVL tree rotation mechanism from Goodrich Chapter 11 — why is rebalancing necessary, and what complexity guarantee does it restore?
  • When is dynamic programming preferable to a greedy approach? Use the knapsack problem from Grokking Algorithms Chapter 9 to illustrate your answer.
Practice
  • Complexity audit: Take 5–10 functions you have written previously and annotate each with its Big-O time and space complexity, then verify by timing them with Python's timeit module against growing input sizes.
  • Implement-from-scratch sprint: Code a singly linked list, a stack, a queue, and a min-heap in pure Python (no collections or heapq), matching the ADT interfaces described in Goodrich Chapters 6–9, and write unit tests for every method.
  • Algorithm visualizer: For each of binary search, merge sort, quicksort, BFS, and DFS, write a Python function that prints or yields each intermediate state so you can trace the execution step-by-step — mirroring the illustrated walkthroughs in Grokking Algorithms.
  • Graph problem set: Using an adjacency-list graph class built from Goodrich Chapter 14, solve at least three classic problems — shortest path (Dijkstra's), cycle detection (DFS), and topological sort — on graphs you construct yourself.
  • Dynamic programming notebook: Implement the 0/1 knapsack problem and the longest common subsequence using both a naive recursive solution and a memoized/bottom-up DP solution; measure and compare their runtimes to feel the difference firsthand.
  • Book-end project: Build a small command-line 'contacts' application that stores records in a hash table you implement yourself, supports prefix search using a trie (Goodrich Chapter 13), and reports the Big-O cost of each operation in its --help output.

Next up: Mastering these data structures and algorithmic patterns gives you the analytical vocabulary and implementation confidence needed to tackle the design of larger systems — the natural next step is learning how these building blocks are composed into software architecture, design patterns, and clean, maintainable codebases.

Grokking Algorithms: An illustrated guide for programmers and other curious people
Aditya Y. Bhargava · 2016 · 256 pp

Uses rich visual illustrations to make algorithms and data structures approachable — the perfect first step into CS theory without overwhelming formalism.

Data Structures and Algorithms in Python
Michael T. Goodrich · 2012 · 525 pp

Provides a thorough, language-grounded treatment of data structures, building directly on Python familiarity to go much deeper than Grokking Algorithms.

3

Writing Professional-Quality Code

Some background

Learn the craft of writing code that is clean, maintainable, and well-structured — the skills that define a professional programmer in any language or domain.

Study plan for this stage

Pace: 10–12 weeks total. Week 1–4: "Clean Code" (~30 pages/day, ~5 days/week). Week 5–8: "The Pragmatic Programmer" (~25 pages/day, ~5 days/week). Week 9–12: "Refactoring" (~30 pages/day, ~5 days/week — catalog chapters can be skimmed as reference).

Key concepts
  • Meaningful naming: variables, functions, and classes should reveal intent without needing comments (Clean Code, Ch. 2–3)
  • The Single Responsibility Principle and keeping functions small, focused, and doing one thing well (Clean Code, Ch. 3, 10)
  • The Boy Scout Rule and continuous improvement: always leave the code cleaner than you found it (Clean Code, Ch. 1; Pragmatic Programmer, Topic 40)
  • DRY — Don't Repeat Yourself — as the cornerstone of maintainable systems, and its counterpart, orthogonality (The Pragmatic Programmer, Topics 9–10)
  • Tracer bullets and prototyping: building thin, end-to-end slices of a system to validate direction early (The Pragmatic Programmer, Topic 12)
  • Code smells: recognizing the surface symptoms — long methods, feature envy, data clumps, divergent change — that signal deeper design problems (Refactoring, Ch. 3)
  • The refactoring workflow: make a small, behavior-preserving transformation, run tests, commit — never mix refactoring with feature work (Refactoring, Ch. 2)
  • The catalog of refactoring techniques: Extract Method, Rename Variable, Replace Conditional with Polymorphism, Introduce Parameter Object, and others as a shared vocabulary for design improvement (Refactoring, Ch. 6–12)
You should be able to answer
  • According to Martin in Clean Code, why are comments often a sign of failure, and what should replace them?
  • What does Hunt mean by 'orthogonality,' and how does violating it make a codebase fragile and hard to change?
  • Describe the step-by-step discipline Fowler prescribes in Refactoring for safely transforming code — what must be in place before the first change is made?
  • Name five code smells from Refactoring Ch. 3 and, for each, identify at least one refactoring technique from the catalog that addresses it.
  • How do the 'tracer bullet' and 'prototype' concepts from The Pragmatic Programmer differ, and when should each be used?
  • How do the philosophies of all three books reinforce each other? Where, if anywhere, do they appear to be in tension?
Practice
  • **Clean Code audit:** Take a real project you have written (or any open-source repo). Apply Martin's naming rules to one file: rename every variable, function, and class that doesn't reveal intent. Commit the result and write a one-paragraph reflection on what changed.
  • **DRY refactor sprint:** Find three instances of duplicated logic in a codebase. Use Fowler's Extract Method and/or Extract Function techniques to eliminate each one, running tests after every single change to prove behavior is preserved.
  • **Smell hunt:** Read through 500 lines of unfamiliar code and annotate every code smell you find using Fowler's vocabulary from Ch. 3. Prioritize them by severity and write a short refactoring plan.
  • **Tracer bullet exercise:** Pick a small feature you haven't built yet. Before writing any real logic, build the thinnest possible end-to-end slice (e.g., a stub API → minimal logic → printed output) as described in The Pragmatic Programmer, then iterate to fill it in.
  • **Refactoring kata:** Use the publicly available 'Gilded Rose' or 'Tennis' refactoring kata. Apply at least five distinct named techniques from Fowler's catalog, documenting which smell each technique addressed and why you chose it.
  • **Personal pragmatic checklist:** After finishing The Pragmatic Programmer, write your own one-page 'pragmatic checklist' of the 10 habits you most need to adopt. Revisit it after finishing Refactoring and annotate which items Fowler's techniques directly support.

Next up: Mastering clean, well-structured code at the function and class level naturally raises the next question — how do those pieces fit together into larger systems? — which sets the stage for studying software design patterns and architecture.

Clean Code
Robert C. Martin · 2008 · 444 pp

The canonical text on writing readable, maintainable code; establishes a shared vocabulary for code quality that every serious programmer must internalize.

The Pragmatic Programmer
Andy Hunt · 1999 · 352 pp

Broadens the lens from individual functions to the full craft of programming — covering tooling, habits, and mindset — best read after Clean Code to contextualize its lessons.

Refactoring
Martin Fowler · 1999

Teaches the disciplined practice of improving existing code without breaking it, completing the trifecta of writing, thinking, and improving code at a professional level.

4

Software Design & Deep Mastery

Going deep

Master the principles of software architecture and design, understand how large systems are structured, and develop the timeless mental models that make a programmer truly exceptional.

Study plan for this stage

Pace: 16–20 weeks total. Week 1–5: "A Philosophy of Software Design" (~25 pages/day, 3–4 days/week — pause frequently to reflect and refactor real code). Week 6–11: "Design Patterns" (~20 pages/day, 4 days/week — read each pattern, then immediately prototype it). Week 12–20: "SICP" (~15 pages/day, 4–5 day

Key concepts
  • Deep vs. shallow modules: interfaces should be simple, implementations powerful (Ousterhout's central thesis)
  • Complexity sources — dependencies and obscurity — and tactical vs. strategic programming mindsets
  • Information hiding and how to define module boundaries that minimize cognitive load
  • The 23 Gang-of-Four design patterns organized by intent: Creational, Structural, and Behavioral
  • Pattern trade-offs: knowing *when not* to apply a pattern is as important as knowing the pattern itself
  • Abstraction as a first-class tool: SICP's substitution and environment models of computation
  • Higher-order functions, closures, and the power of treating procedures as data
  • Metalinguistic abstraction — building interpreters and DSLs — as the pinnacle of design thinking
  • State, mutation, and the tension between functional and object-oriented paradigms (SICP Chapter 3)
  • The unified thread across all three books: managing complexity through principled abstraction
You should be able to answer
  • According to Ousterhout, what is the difference between a deep module and a shallow module, and why does the distinction matter when designing an API or class interface?
  • How do the Decorator, Proxy, and Adapter structural patterns differ in intent, and can you construct a scenario where choosing the wrong one would increase rather than reduce complexity?
  • What does SICP's environment model of evaluation reveal about closures and variable scoping that the simpler substitution model cannot explain?
  • How does Ousterhout's concept of 'information hiding' relate to the Gang-of-Four principle of 'programming to an interface, not an implementation'?
  • SICP introduces the metacircular evaluator — what does building your own interpreter teach you about the design of any language or large system you will ever work in?
  • Across all three books, complexity is the central enemy. How do each book's primary prescription for fighting complexity differ, and how do they complement one another?
Practice
  • Refactor audit (A Philosophy of Software Design): Pick a module or class from a real or open-source codebase. Score it against Ousterhout's red flags (shallow interface, pass-through methods, temporal decomposition). Rewrite it to be 'deeper' and document every decision.
  • Pattern implementation sprint (Design Patterns): Implement at least 8 of the 23 patterns from scratch in your language of choice — one per session. For each, write a one-paragraph note on the problem it solves AND a counter-example of when it would be overkill.
  • Pattern hunting (Design Patterns): Browse the source code of a well-known open-source project (e.g., a web framework or game engine). Identify and document at least 5 GoF patterns in the wild, noting how the real implementation differs from the textbook version.
  • SICP exercise gauntlet: Complete every exercise in Chapters 1 and 2 without skipping. These are non-negotiable — the exercises ARE the learning. Use Scheme or a Racket environment and keep a solution journal.
  • Build a metacircular evaluator (SICP Chapter 4): Work through the interpreter project end-to-end. Then extend it with one feature not in the book (e.g., tail-call optimization, a new special form, or a simple type system) to prove genuine understanding.
  • Design synthesis project: Design (on paper first, then in code) a small but non-trivial system — e.g., a plugin-based task scheduler or a tiny scripting engine. Explicitly apply at least three GoF patterns, enforce deep-module boundaries per Ousterhout, and use higher-order functions or closures inspired by SICP. Write an architectural decision record (ADR) justifying every major choice.

Next up: Mastering these three books forges the mental models — principled abstraction, pattern literacy, and computational thinking at its deepest — that are the prerequisite for tackling the next frontier: large-scale distributed systems, performance engineering, or domain-specific language design, where every concept here is stress-tested at orders-of-magnitude greater complexity.

A Philosophy of Software Design
John K. Ousterhout · 2018 · 193 pp

Offers a concise, opinionated framework for managing complexity in software design — a perfect entry into advanced design thinking before tackling heavier pattern-based books.

Design Patterns
Erich Gamma · 1995 · 395 pp

The foundational 'Gang of Four' catalog of reusable object-oriented design solutions; essential vocabulary for any programmer working on large, collaborative systems.

Structure and Interpretation of Computer Programs (SICP)
Harold Abelson · 1985 · 542 pp

The legendary MIT text that reveals the deepest principles of computation itself — abstraction, interpretation, and metalinguistic power — the capstone of any serious programming education.

Discussion