Month 1 was about learning the language.
Month 2 was about learning to think like a programmer.
The difference shows up everywhere. Month 1 me wrote functions because a lesson told me to. Month 2 me reaches for a class because the data has relationships, or a stack because the problem is fundamentally "last thing in, first thing out." This month had four weeks, each with a completely different texture — deep OOP, a full real-world project shipped publicly, a hard pivot into algorithms, and finally building data structures from scratch. Here's the whole story.
The Structure: Four Very Different Weeks
| Week | Theme | Days | Energy |
|---|---|---|---|
| Week 5 | OOP Deep Dive | 29–34 | Conceptual — learning to model the world in code |
| Week 6 | Real Project | 36–41 | Practical — designing, shipping, and defending one project |
| Week 7 | DSA: Arrays & Hashing | 43–48 | New territory — algorithms instead of applications |
| Week 8 | Stacks, Queues, Linked Lists | 50–55 | Foundational — building the structures themselves |
Two brand-new GitHub repos exist because of this month. progress-on-python kept growing with OOP and project work. neetcode-submissions was born in Week 7 specifically to hold algorithm practice — a sign that DSA started to feel like its own distinct skill, deserving its own home.
Week 5 — OOP Deep Dive
Theme: Stop writing functions. Start modeling things.
What I learned
- Classes,
__init__,self, instance attributes - Inheritance and
super()— sharing behaviour between related classes - Encapsulation with
@propertygetters and setters - Dunder methods —
__str__,__repr__,__eq__ - Composition vs inheritance — the "is-a" vs "has-a" question
What I built
| Project | Highlight |
|---|---|
| Bank Account | Deposit, withdraw, transfer, full transaction history per account |
| CheckingAccount / SavingsAccount | Inheritance, super().__init__(), overdraft fees, interest |
| Dunder Methods |
print(account) returning BankAccount(Alice, 85.0) instead of a memory address |
| Library System | Composition — Book, Member, Loan, Library as four separate classes |
| Task Manager | Walrus operator in regex property setters, date.today() overdue checks, 8 structured tests |
The moment that clicked
The library system's Loan class — capturing the relationship between a Book and a Member as its own object, rather than cramming that logic into either one. That's when composition stopped being a vocabulary word and became a design instinct.
Biggest surprise
OOP is about grouping, not just syntax. Wrapping related behaviour into a class doesn't change what code does — it changes how it's organised. That distinction reframed how I think about every program since.
Week 6 — One Project, One Week
Theme: Design it. Build it. Ship it. Defend it. Improve it.
What I learned
- Writing a design document before any code — data model, API shape, edge cases
- Building a complete CLI tool with JSON persistence
- Tracking analytics in CSV with a read-modify-rewrite pattern
- Writing a README for strangers
- Asking for public code review — and actually using the feedback
What I built
A URL shortener. One project, six days, fully designed before being built:
-
Design.txt— six sections answering what it does, the data model, the "API," storage choice, code generation strategy, and edge cases -
url_shortner.py— anUrlclass handling shortening, deduplication, and visit tracking -
clicked_report.csv— analytics tracking how many times each URL was visited - A public README with real usage examples
- Public sharing on Reddit and Discord, three+ code reviews, and a real bug fix afterward
The moment that clicked
Writing the design doc before touching the editor. The line "I will use Python's random module to generate 6 characters... I will check if the code already exists... if the code exists I will generate it again" became, almost word for word, the generate_code() method a day later. Planning wasn't separate from coding — it was coding in plain English first.
Biggest surprise
Public code review wasn't the ordeal I expected. A reviewer caught a real bug — most_clicked() was calling self.visit() twice in some cases, double-prompting the user. Strangers online were more useful for catching that than another week of solo work would have been.
Week 7 — A Hard Pivot Into Algorithms
Theme: Stop building. Start solving.
What I learned
- Big O notation — naming the "feels slow" instinct I already had
- Hash maps and sets as the "trade memory for speed" pattern
- Two pointers — and recognising sorted input as a signal to use them
- Sliding window — never re-scanning data you've already passed
- A brand-new repo,
neetcode-submissions, just for this kind of work
What I built
| Problem | Pattern |
|---|---|
| Two Sum | Hash map |
| Contains Duplicate | Set |
| Valid Anagram | Hash map counting |
| Group Anagrams | Canonical sorted key |
| Top K Frequent Elements | Bucket sort (no sorting algorithm needed) |
| Valid Palindrome | Two pointers |
| Two Sum II | Two pointers (sorted input) |
| 3Sum | Two pointers nested inside a loop |
| Best Time to Buy/Sell Stock | Running minimum |
| Longest Substring Without Repeating Characters | Sliding window |
The moment that clicked
Revisiting the Week 6 URL shortener's if code not in urls: line and realising it was already O(1) because urls was a dictionary — a design decision I'd made for convenience back in Week 6 turned out to already be the efficient choice. Naming why it was right, using Big O, was the real Week 7 lesson.
Biggest surprise
Mock-solving problems under a timer on Day 48 revealed the gap between "I understand this" and "I can rebuild this from a blank file." The patterns that came back fastest were the ones I'd genuinely internalised, not just followed along with once.
Week 8 — Building the Structures Themselves
Theme: Stop using built-in types. Build the data structures from scratch.
What I learned
- Stacks (LIFO) and queues (FIFO) implemented from raw Python lists and
deque - Linked lists — my first pointer-based structure with no array underneath
- The dummy node pattern for removing special cases in list problems
- Fast and slow pointers for "distance from the end" problems
- How stack thinking quietly shows up in completely unrelated problems
What I built
| Project | Highlight |
|---|---|
| Valid Parentheses | A stack matching brackets, with an odd-length early exit |
| Stack Using Queues | Implementing one structure's behaviour using only the other's primitives |
| Reverse Linked List | Three pointers (prev, curr, nxt) flipping arrows one at a time |
| Merge Two Sorted Lists | The dummy node pattern removing every "first node" special case |
| Remove Nth Node From End | Fast and slow pointers with a fixed gap, solved in one pass |
| Browser History Tracker | A single pointer + list quietly acting as two stacks glued together |
The moment that clicked
The browser history tracker's visit_site() truncating everything ahead of the current pointer before adding a new entry — exactly how real browsers discard "forward" history once you branch into a new page. That one line of code, self.history = self.history[:self.pointer + 1], is Day 50's stack thinking showing up in Day 54's project without ever mentioning a stack.
Biggest surprise
Drawing pointer diagrams on paper before writing the Reverse Linked List function made the logic obvious in a way that reading code never did. Two minutes of sketching saved twenty minutes of confusion.
Everything I Built in Month 2
| # | Project | Week | Key Concepts |
|---|---|---|---|
| 1 | Bank Account | 5 |
__init__, @property, transaction history |
| 2 | CheckingAccount / SavingsAccount | 5 | Inheritance, super(), overdraft, interest |
| 3 | Dunder Methods | 5 |
__str__, __repr__, __eq__
|
| 4 | Library System | 5 | Composition, 4-class design |
| 5 | Task Manager | 5 | Walrus operator, regex setters, 8 tests |
| 6 | URL Shortener | 6 | Design doc, OOP, JSON storage, CSV analytics |
| 7 | Two Sum | 7 | Hash map |
| 8 | Contains Duplicate | 7 | Set |
| 9 | Valid Anagram | 7 | Hash map counting |
| 10 | Group Anagrams | 7 | Canonical key |
| 11 | Top K Frequent Elements | 7 | Bucket sort |
| 12 | Valid Palindrome | 7 | Two pointers |
| 13 | Two Sum II | 7 | Two pointers |
| 14 | 3Sum | 7 | Two pointers + dedup |
| 15 | Best Time to Buy/Sell Stock | 7 | Running minimum |
| 16 | Longest Substring Without Repeating Characters | 7 | Sliding window |
| 17 | Valid Parentheses | 8 | Stack |
| 18 | Stack Using Queues | 8 | Stack/queue relationship |
| 19 | Reverse Linked List | 8 | Pointer reversal |
| 20 | Merge Two Sorted Lists | 8 | Dummy node |
| 21 | Remove Nth Node From End | 8 | Fast & slow pointers |
| 22 | Browser History Tracker | 8 | Stack logic, pointer state |
All of it is on GitHub:
👉 github.com/Omk4314/progress-on-python
👉 github.com/Omk4314/neetcode-submissions
What Changed in Month 2
How I design before I build. Week 6's design doc was the first time planning happened entirely separate from coding. By Week 8, sketching pointer diagrams on paper before writing linked list functions had become a habit, not an assignment.
How I think about efficiency. Month 1 me had a vague sense that some code "felt slow." Month 2 me can say why — O(1) dictionary lookups versus O(n) list scans, two pointers beating a hash map when the input is sorted, sliding windows avoiding redundant re-scans.
How I relate classes to each other. Inheritance for "is-a," composition for "has-a." That single distinction, learned in Week 5's library system, now shapes every design decision before a line of code gets written.
How I receive feedback. Week 6 was the first time I shared code publicly and asked strangers to find problems with it. The bug they found — a double-call in most_clicked() — was real, and fixing it based on someone else's eyes was more valuable than another week of solo debugging would have been.
How fast old patterns come back. Week 7's Day 48 mock test was uncomfortable. Week 8's Day 55 review of the same kind of exercise was fast. That gap is the clearest evidence that the patterns from this month are becoming reflexes rather than lessons.
What I'd Tell Myself at the Start of Month 2
-
Write the design doc first, even for small projects. The URL shortener's
Design.txtmade every day of building faster because the hard thinking happened once, up front. -
A new kind of problem deserves a new repo. Splitting
neetcode-submissionsaway fromprogress-on-pythonwasn't bureaucracy — it made it obvious which skill was being practiced on any given day. - Ask for code review before you feel ready. The feedback on the URL shortener was more useful because the code wasn't perfect yet.
- Sketch before you code, especially for pointers. Linked lists are a visual problem wearing a syntax costume.
- Re-solving old problems is the real test. Not whether you can follow a solution, but whether you can rebuild it cold, days later, without panic.
What's Next
Month 3 has clear targets already taking shape from Week 8's closing thoughts:
- Trees and recursion — the next data structure family, and the first one that forces recursive thinking
- Binary search trees — ordered structures with their own traversal rules
- Heaps and priority queues — a natural extension of this month's queue work
- Bigger, multi-class projects — combining OOP from Week 5 with the algorithmic thinking from Weeks 7 and 8
Two months down. The foundation isn't just "I know Python syntax" anymore — it's "I can model a problem, choose the right structure, and explain why." That's a different kind of confidence than the one I had at the end of Month 1.
If you're following along, building your own projects, or grinding the same NeetCode list — drop a comment. I'd genuinely like to see what Month 2 looked like for you.
See you in Month 3. 🐍
8 weeks. 22 projects and solutions. Two repos. One streak still going.
Top comments (0)