← Back to all projects

SPRINT 3 CONTROL FLOW STATE PROJECTS

Learning Projects for Control Flow & State

Core Mental Model: Programs are state machines evolving over time.

Core Concept Analysis

The mental model “Programs are state machines evolving over time” breaks down into these fundamental building blocks:

Concept Cluster What You Need to Internalize
State Management Programs have explicit states, transitions between states have rules, invalid transitions should be impossible
Control Flow Discipline Code paths must be predictable; every branch needs consideration; cleanup must happen regardless of path taken
Resource Lifecycle Resources are acquired, used, and released in strict order; failure at any point requires proper unwinding
Temporal Correctness Order matters; bugs hide in “this worked yesterday” because state changed
API Robustness Good APIs guide users into the pit of success; bad APIs allow invalid states

Project 1: Modal Text Editor (Mini-Vim)

  • File: SPRINT_3_CONTROL_FLOW_STATE_PROJECTS.md
  • Programming Language: C
  • Coolness Level: Level 3: Genuinely Clever
  • Business Potential: 2. The “Micro-SaaS / Pro Tool”
  • Difficulty: Level 3: Advanced
  • Knowledge Area: State Machines / Text Processing
  • Software or Tool: Finite State Machine
  • Main Book: “Code: The Hidden Language” by Charles Petzold

What you’ll build: A terminal-based text editor with distinct modes (NORMAL, INSERT, COMMAND) that edits real files and displays changes in real-time.

Why it teaches Control Flow & State: A modal editor is a textbook state machine. Every keypress triggers different behavior depending on current mode. You’ll face reentrancy when a command triggers another command, must maintain invariants (cursor never outside buffer bounds), and handle cleanup paths (what happens when user quits with unsaved changes?).

Core challenges you’ll face:

  • State transition validity (can’t go INSERT→COMMAND directly) → maps to state machines
  • Cursor invariants (cursor.x ≤ line_length, cursor.y ≤ total_lines at ALL times) → maps to loop invariants
  • Command reentrancy (:s/foo/bar/g triggers multiple buffer modifications) → maps to reentrancy
  • Dirty buffer cleanup (quit without save, crash recovery) → maps to cleanup paths
  • Undo/redo stack integrity (can’t undo into invalid state) → maps to temporal bugs

Key Concepts:

  • Finite State Machines: “Code: The Hidden Language” Chapter 14 - Charles Petzold
  • Loop Invariants: “Programming: Principles and Practice Using C++” Chapter 4.5 - Bjarne Stroustrup
  • Resource Cleanup in C: “Effective C” Chapter 8 - Robert C. Seacord
  • Terminal Raw Mode: “The Linux Programming Interface” Chapter 62 - Michael Kerrisk

Difficulty: Intermediate Time estimate: 2-3 weeks Prerequisites: Basic C, terminal I/O basics, understanding of file operations

Real world outcome:

  • You will have a working text editor you can actually use to edit code
  • Open a file: ./myvi README.md
  • Press i to enter INSERT mode, type text, press ESC for NORMAL mode
  • Press :w to save, :q to quit
  • The mode indicator changes visibly in the status bar

Learning milestones:

  1. Mode switching works → You understand explicit state representation
  2. Cursor never goes out of bounds → You’ve internalized invariant maintenance
  3. :wq works even if file doesn’t exist yet → You understand cleanup and error paths
  4. Undo/redo doesn’t corrupt buffer → You’ve mastered temporal state consistency

Project 2: HTTP/1.1 Protocol Parser

  • File: SPRINT_3_CONTROL_FLOW_STATE_PROJECTS.md
  • Main Programming Language: C
  • Alternative Programming Languages: Rust, Go, Zig
  • Coolness Level: Level 3: Genuinely Clever
  • Business Potential: Level 1: The “Resume Gold”
  • Difficulty: Level 3: Advanced (The Engineer)
  • Knowledge Area: Networking, Parsing, State Machines
  • Software or Tool: HTTP Server
  • Main Book: TCP/IP Illustrated, Volume 1 by W. Richard Stevens

What you’ll build: A from-scratch HTTP/1.1 request parser that reads bytes from a socket and produces structured request objects, handling chunked encoding, keep-alive, and malformed requests gracefully.

Why it teaches Control Flow & State: HTTP parsing is a state machine with strict transition rules. You’ll implement states like PARSING_METHOD, PARSING_HEADERS, PARSING_BODY, with explicit transitions. Error handling is critical—you must return proper 400/500 errors without crashing or leaking resources.

Core challenges you’ll face:

  • Incremental parsing (data arrives in chunks, parser must pause/resume) → maps to state transitions
  • Malformed input handling (return error code, don’t crash, clean up) → maps to error propagation
  • Buffer management (don’t overflow, don’t leak, reuse properly) → maps to resource patterns
  • Keep-alive connection reuse (reset parser state correctly for next request) → maps to reentrancy
  • Content-Length vs Chunked (different parsing modes, must not mix) → maps to control flow beyond if/else

Key Concepts:

  • State Machine Design: “Language Implementation Patterns” Chapter 2 - Terence Parr
  • Error Codes vs Exceptions: “C Interfaces and Implementations” Chapter 4 - David Hanson
  • Network Protocol Parsing: “TCP/IP Illustrated, Volume 1” Chapter 14 - W. Richard Stevens
  • Defensive Parsing: “Practical Binary Analysis” Chapter 3 - Dennis Andriesse

Difficulty: Intermediate-Advanced Time estimate: 2-3 weeks Prerequisites: Basic C, socket programming basics, familiarity with HTTP

Real world outcome:

  • Run your parser as a simple server: ./http_parser 8080
  • Open browser to http://localhost:8080/hello
  • See your parser correctly identify: method=GET, path=/hello, headers={…}
  • Send malformed requests with curl and see proper error responses, no crashes

Learning milestones:

  1. Simple GET requests parse correctly → You understand basic state machines
  2. Chunked encoding works → You’ve handled complex control flow
  3. Malformed requests return 400, server keeps running → You’ve mastered error propagation
  4. Keep-alive handles 100 requests without leaks → You understand resource lifecycle

Project 3: Database Connection Pool

  • File: SPRINT_3_CONTROL_FLOW_STATE_PROJECTS.md
  • Main Programming Language: C
  • Alternative Programming Languages: Rust, Go, Java
  • Coolness Level: Level 3: Genuinely Clever
  • Business Potential: Level 3: The “Service & Support” Model
  • Difficulty: Level 3: Advanced (The Engineer)
  • Knowledge Area: Concurrency, Resource Management
  • Software or Tool: PostgreSQL, pthreads
  • Main Book: C Programming: A Modern Approach by K.N. King

What you’ll build: A thread-safe connection pool manager that pre-allocates database connections, hands them out on request, reclaims them on release, handles timeouts, and recovers from dead connections.

Why it teaches Control Flow & State: A connection pool is pure state management under pressure. Each connection has states (IDLE, IN_USE, DEAD, VALIDATING). You’ll face reentrancy (what if validation triggers a callback that requests another connection?), temporal bugs (use-after-release), and must design an API that prevents misuse.

Core challenges you’ll face:

  • Connection state tracking (IDLE→IN_USE→IDLE, DEAD→REMOVED) → maps to state transitions
  • Acquire timeout (can’t wait forever, must propagate failure) → maps to error propagation
  • Use-after-release bugs (user keeps reference, pool reuses connection) → maps to temporal bugs
  • Cleanup on shutdown (all connections must close, even busy ones) → maps to cleanup paths
  • API that prevents misuse (can’t release twice, can’t use released connection) → maps to API design

Key Concepts:

  • Resource Pools: “Pattern-Oriented Software Architecture Vol. 3” Chapter on Resource Lifecycle Manager - Kircher & Jain
  • RAII and Cleanup: “Effective C” Chapter 8 - Robert C. Seacord
  • Thread Safety: “C Programming: A Modern Approach” (online supplement on POSIX threads) - K.N. King
  • Object Pooling: “Patterns of Enterprise Application Architecture” - Martin Fowler

Difficulty: Advanced Time estimate: 2-3 weeks Prerequisites: C with pthreads, basic SQL, understanding of mutex/condition variables

Real world outcome:

  • Your test program spawns 50 threads, each doing 100 database operations
  • Pool has only 10 connections, threads wait when exhausted
  • Console shows: [POOL] Connection 3 acquired by thread 12, [POOL] Connection 3 released
  • Killing the database and restarting shows: [POOL] Connection 5 marked DEAD, reconnecting...
  • No leaks, no deadlocks, no use-after-free

Learning milestones:

  1. Basic acquire/release works → You understand resource lifecycle
  2. Timeout returns error, doesn’t hang → You’ve implemented error propagation
  3. 50 threads, 10 connections, no deadlock → You understand reentrancy concerns
  4. Double-release is caught, not silently corrupting → You’ve designed a misuse-proof API

Project 4: Undo/Redo Engine for a Drawing Application

  • File: SPRINT_3_CONTROL_FLOW_STATE_PROJECTS.md
  • Programming Language: C or C++
  • Coolness Level: Level 3: Genuinely Clever
  • Business Potential: 2. The “Micro-SaaS / Pro Tool”
  • Difficulty: Level 2: Intermediate
  • Knowledge Area: Software Design Patterns / GUI
  • Software or Tool: Command Pattern
  • Main Book: “Design Patterns” by Gang of Four

What you’ll build: A command-pattern based undo/redo system for a simple drawing app where you can add shapes, move them, change colors, group them, and undo/redo any operation while maintaining complete state consistency.

Why it teaches Control Flow & State: Undo/redo forces you to think about state as snapshots in time. Each command must know how to execute and reverse itself. You’ll face temporal ordering (undo must be LIFO), cleanup (redo stack clears on new action), and invariant maintenance (undo must never leave canvas in invalid state).

Core challenges you’ll face:

  • Command inversion (every action needs an inverse) → maps to state transitions
  • Redo stack invalidation (new action clears redo history) → maps to temporal bugs
  • Grouped operations (undo “group shapes” must ungroup exactly) → maps to invariants
  • Memory management (command history can grow unbounded) → maps to resource patterns
  • API clarity (canvas.do(cmd) vs cmd.execute(canvas)) → maps to API design

Key Concepts:

  • Command Pattern: “Design Patterns” Chapter on Command - Gang of Four
  • State Snapshots: “Refactoring” Chapter on temporal coupling - Martin Fowler
  • Invariant Preservation: “Code Complete” Chapter 8 on defensive programming - Steve McConnell
  • UI State Machines: “Designing Data-Intensive Applications” Chapter 7 (transactions analogy) - Martin Kleppmann

Difficulty: Intermediate Time estimate: 1-2 weeks Prerequisites: Basic C or C++, understanding of data structures (stacks, linked lists)

Real world outcome:

  • Launch app: ./drawing_app
  • Draw a rectangle (click-drag), change its color to blue, move it
  • Press Ctrl+Z three times: rectangle moves back, color reverts to original, rectangle disappears
  • Press Ctrl+Shift+Z: rectangle reappears exactly as first drawn
  • Console shows command history: [CMD] AddShape(rect_1) | [CMD] SetColor(rect_1, blue) | ...

Learning milestones:

  1. Single undo/redo works → You understand command inversion
  2. New action clears redo stack → You understand temporal ordering
  3. Group undo is atomic → You’ve mastered compound state transitions
  4. 1000 operations, memory stable → You understand resource lifecycle in long-running apps

Project 5: Embedded Sensor State Machine (Arduino/STM32)

  • File: SPRINT_3_CONTROL_FLOW_STATE_PROJECTS.md
  • Programming Language: C
  • Coolness Level: Level 4: Hardcore Tech Flex
  • Business Potential: 3. The “Service & Support” Model
  • Difficulty: Level 3: Advanced
  • Knowledge Area: Embedded Systems / Real-time
  • Software or Tool: State Machines
  • Main Book: “Making Embedded Systems” by Elecia White

What you’ll build: A sensor monitoring system that reads temperature/humidity, manages power states (ACTIVE, LOW_POWER, SLEEP), handles sensor errors gracefully, and logs data—all with explicit state machine code, no hidden magic.

Why it teaches Control Flow & State: Embedded systems have no garbage collector, no exception unwinding, no “retry later.” You must handle every error explicitly, clean up every resource, and state transitions must be rock-solid because “undefined behavior” means hardware malfunction.

Core challenges you’ll face:

  • Power state machine (ACTIVE↔LOW_POWER↔SLEEP with rules) → maps to state transitions
  • Sensor timeout (what if sensor doesn’t respond?) → maps to error propagation
  • Interrupt safety (sensor interrupt during state transition) → maps to reentrancy
  • I2C cleanup (bus stuck? must reset) → maps to cleanup paths
  • Watchdog feeding (forget to feed → reset) → maps to temporal bugs

Resources for key challenges:

  • “Making Embedded Systems, 2nd Edition” Chapter 5 - Elecia White - State machine patterns for embedded
  • “AVR Workshop” Chapters 8-10 - John Boxall - Practical I2C and sensor handling

Key Concepts:

  • Embedded State Machines: “Making Embedded Systems” Chapter 5 - Elecia White
  • Error Handling without Exceptions: “Bare Metal C” Chapter 6 - Steve Oualline
  • Interrupt Safety: “The Art of Debugging with GDB, DDD, and Eclipse” Chapter on embedded - Matloff & Salzman
  • Resource Cleanup in C: “Effective C” Chapter 8 - Robert C. Seacord

Difficulty: Intermediate Time estimate: 2-3 weeks Prerequisites: Basic C, Arduino or STM32 basics, understanding of I2C/SPI

Real world outcome:

  • Device on your desk reads temperature every 5 seconds
  • LED blinks: green=ACTIVE, yellow=LOW_POWER, off=SLEEP
  • Serial monitor shows: [STATE] ACTIVE → LOW_POWER (idle 30s)
  • Disconnect sensor wire: [ERROR] I2C timeout, retry 1/3... [ERROR] Sensor DEAD, entering SAFE mode
  • Watchdog triggers if your state machine hangs: device resets cleanly

Learning milestones:

  1. State LED reflects actual state → You understand explicit state representation
  2. Sensor disconnect doesn’t crash → You’ve mastered error propagation without exceptions
  3. Interrupt during transition is safe → You understand reentrancy in hard real-time
  4. 24-hour run, no hangs → You’ve eliminated temporal bugs

Project Comparison Table

Project Difficulty Time Depth of Understanding Fun Factor Best For
Modal Text Editor Intermediate 2-3 weeks ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐ Visual state transitions, invariants
HTTP Parser Intermediate-Advanced 2-3 weeks ⭐⭐⭐⭐ ⭐⭐⭐ Error propagation, protocol correctness
Connection Pool Advanced 2-3 weeks ⭐⭐⭐⭐⭐ ⭐⭐⭐ Resource lifecycle, API design
Undo/Redo Engine Intermediate 1-2 weeks ⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ Temporal reasoning, command pattern
Embedded Sensor Intermediate 2-3 weeks ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐ No-magic state, hard error handling

Recommendation

Based on the curriculum’s emphasis on “state machines evolving over time” and the practical skills listed (preconditions, postconditions, temporal debugging), I recommend this progression:

Start with: Undo/Redo Engine (1-2 weeks)

This is the “pit of success” project—relatively contained scope, extremely clear state model, and immediate visual feedback. You’ll internalize command patterns and temporal ordering without getting bogged down in I/O complexity.

Then: Modal Text Editor (2-3 weeks)

This takes the state machine concept and adds real-world messiness: terminal I/O, file handling, user input at unpredictable times. The invariants (cursor position) become critical, and you’ll face cleanup paths (unsaved changes on exit).

For deep mastery: Connection Pool (2-3 weeks)

This is where you’ll face the hardest challenges: reentrancy, concurrent access, designing APIs that prevent misuse. If you can build a pool that 50 threads can hammer without deadlocking or corrupting, you’ve truly internalized resource lifecycle management.


Final Overall Project: Build a Git-like Version Control System

What you’ll build: A simplified version control system that tracks file changes, manages commits as a directed acyclic graph, handles branches/merges, and maintains repository integrity even on interrupted operations.

Why it synthesizes everything: This project is the ultimate state machine challenge. The repository has states (clean, modified, merging, rebasing). Operations have strict preconditions (“can’t commit with unstaged changes”), postconditions (“after commit, working tree matches HEAD”), and cleanup requirements (“interrupted merge must be recoverable”). You’ll face:

  • State transitions: repo states (CLEAN, DIRTY, MERGING, REBASING, DETACHED)
  • Invariants: commit graph must be acyclic, every commit reachable from refs
  • Error propagation: disk full during commit? must not corrupt repository
  • Cleanup paths: interrupted operations must leave recoverable state
  • Temporal bugs: operations depend on previous state
  • Reentrancy: hooks that trigger other git operations
  • API design: commands must prevent impossible states

Core challenges you’ll face:

  • Atomic commits (all-or-nothing, even on power failure) → everything you learned
  • Merge conflict state machine (MERGING→resolve→CLEAN, or abort→CLEAN) → state transitions
  • Object database integrity (SHA verification, dangling object cleanup) → resource patterns
  • Hook reentrancy (post-commit hook does another commit?!) → reentrancy
  • Index/staging area invariants (index always consistent with something) → loop invariants
  • Detached HEAD handling (user can get into weird states) → API misuse prevention

Key Concepts:

  • Content-Addressable Storage: “Pro Git” Chapter 10 (Git Internals) - Scott Chacon (free online)
  • DAG Structures: “Algorithms, Fourth Edition” Chapter on Directed Graphs - Sedgewick & Wayne
  • Atomic File Operations: “The Linux Programming Interface” Chapter 5 - Michael Kerrisk
  • Crash-Safe Design: “Designing Data-Intensive Applications” Chapter 7 - Martin Kleppmann

Difficulty: Advanced Time estimate: 4-6 weeks Prerequisites: All projects above, or equivalent experience

Real world outcome:

$ ./mygit init
Initialized empty repository in .mygit/

$ echo "hello" > file.txt
$ ./mygit add file.txt
$ ./mygit commit -m "Initial commit"
[master (root-commit) a1b2c3d] Initial commit

$ ./mygit branch feature
$ ./mygit checkout feature
Switched to branch 'feature'

$ echo "world" >> file.txt
$ ./mygit commit -am "Add world"
[feature e4f5g6h] Add world

$ ./mygit checkout master
$ ./mygit merge feature
Merge made by the 'recursive' strategy.

$ ./mygit log --graph
* e4f5g6h (HEAD -> master, feature) Add world
* a1b2c3d Initial commit

Learning milestones:

  1. Basic commit/checkout works → You understand state snapshots
  2. Interrupted commit doesn’t corrupt repo → You’ve mastered cleanup paths
  3. Merge conflicts enter MERGING state, abort works → State machine mastery
  4. 100 rapid commits, no corruption → Temporal correctness achieved
  5. mygit fsck finds no errors after stress test → Invariants are bulletproof

This final project integrates every concept from Sprint 3 into a single, real-world tool that you’ll actually understand at the deepest level—because you built it from nothing.