DEV Community

Laurent Charignon
Laurent Charignon

Posted on • Originally published at blog.laurentcharignon.com

Building with LLMs at Scale: Part 5 - Learning and Knowledge Accumulation

This is the final article in my series on working with LLMs at scale. Part 1 through Part 4 focused on building with LLMs—managing sessions, ensuring quality, coordinating parallel work.

This article is about something different: using LLMs as learning tools. Not just to write code, but to help you understand complex systems, internalize patterns, and build lasting knowledge.

The Learning Problem

As a developer, you're constantly learning:

  • New frameworks and libraries
  • Complex algorithms
  • System architecture patterns
  • Domain-specific knowledge
  • Best practices and anti-patterns

Traditional learning methods are slow:

  • Reading documentation takes hours
  • Watching tutorials is passive
  • Trial-and-error is inefficient
  • Taking notes manually is tedious

What if LLMs could accelerate this? Not by just answering questions, but by creating personalized learning materials tailored to how you learn best?

Pattern 1: Heavily-Annotated Code (Worksheets)

When learning a new codebase or pattern, I ask Claude to generate worksheets—code with extensive inline comments explaining every decision.

Example: Understanding React Hooks

Instead of:

Explain React hooks to me
Enter fullscreen mode Exit fullscreen mode

I ask:

Generate a complete React component using hooks, but add inline comments
explaining:
- Why this hook is needed
- What problems it solves
- Common mistakes to avoid
- How it compares to class components
- Performance implications
Enter fullscreen mode Exit fullscreen mode

Claude produces:

import { useState, useEffect, useCallback, useMemo } from 'react';

function UserProfile({ userId }) {
  // useState: Manages local component state
  // Why: We need to track user data that changes over time
  // Replaces: this.state in class components
  // Common mistake: Forgetting state updates are asynchronous
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);

  // useEffect: Handles side effects (API calls, subscriptions)
  // Why: We need to fetch data after component mounts
  // Dependencies: [userId] means "re-run when userId changes"
  // Common mistake: Missing dependencies causes stale closures
  // Performance: Cleanup function prevents memory leaks
  useEffect(() => {
    // Start loading
    setLoading(true);

    // Fetch user data
    fetch(`/api/users/${userId}`)
      .then(res => res.json())
      .then(data => {
        setUser(data);
        setLoading(false);
      });

    // Cleanup: Cancel fetch if component unmounts
    return () => {
      // In production, you'd actually cancel the fetch here
    };
  }, [userId]); // Dependency array: re-run when userId changes

  // useMemo: Memoizes expensive computations
  // Why: Prevents recalculating on every render
  // Only recalculates when 'user' changes
  // Common mistake: Overusing for cheap operations (adds overhead)
  const displayName = useMemo(() => {
    if (!user) return 'Loading...';
    // Expensive operation example (yours might be more complex)
    return `${user.firstName} ${user.lastName}`.toUpperCase();
  }, [user]);

  // useCallback: Memoizes function references
  // Why: Prevents child components from re-rendering unnecessarily
  // Without this: New function created on every render
  // Performance: Only useful if passed to optimized child components
  const handleRefresh = useCallback(() => {
    setLoading(true);
    // Refresh logic here
  }, []);

  if (loading) return <div>Loading...</div>;
  if (!user) return <div>User not found</div>;

  return (
    <div>
      <h1>{displayName}</h1>
      <button onClick={handleRefresh}>Refresh</button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

This isn't just code—it's a learning artifact. I can:

  • Read it top to bottom to understand the flow
  • See why each decision was made
  • Learn common mistakes to avoid
  • Understand performance implications

The Prompt Pattern

The key is being specific about what you want explained:

Generate [concept] code with inline comments explaining:
- Why this approach (vs alternatives)
- Common mistakes
- Performance considerations
- When to use / not use
- How it connects to [related concept]
Enter fullscreen mode Exit fullscreen mode

I've used this pattern to learn:

  • Rust's ownership system
  • Clojure's transducers
  • Kubernetes operators
  • Distributed system patterns
  • Database indexing strategies

Pattern 2: Flashcards for Spaced Repetition

Reading annotated code helps understanding, but doesn't ensure retention. For that, I use flashcards with spaced repetition.

The Flashcard System

I built a flashcard CLI (see github.com/charignon/flashcards) that implements spaced repetition algorithms (SM-2, Leitner boxes).

But manually creating flashcards is tedious. So I ask Claude to generate them.

Example: Learning System Design

Generate flashcards for distributed systems concepts. Format as JSON.
Focus on: CAP theorem, consensus algorithms, partitioning strategies.

Each card should have:
- A precise question
- A complete answer
- Tags for organization
- Notes with additional context
Enter fullscreen mode Exit fullscreen mode

Claude generates:

[
  {
    "question": "In the CAP theorem, what does 'Partition Tolerance' actually mean?",
    "answer": "The system continues to operate despite network partitions (messages between nodes being lost or delayed). You must choose: consistency (all nodes see same data) or availability (all requests get responses) during a partition.",
    "tags": ["cap-theorem", "distributed-systems", "fundamentals"],
    "notes": "Common misconception: You can't 'give up' partition tolerance—network partitions will happen. You choose between CP (consistent but not available during partition) or AP (available but inconsistent during partition)."
  },
  {
    "question": "What is the key difference between Raft and Paxos consensus algorithms?",
    "answer": "Raft uses leader election + log replication (simpler to understand). Paxos uses proposal numbers + acceptors (more flexible but complex). Raft is easier to implement correctly.",
    "tags": ["consensus", "raft", "paxos", "algorithms"],
    "notes": "Raft was explicitly designed to be more understandable than Paxos. In practice, most systems use Raft (etcd, Consul) or Raft-like algorithms (Zab in ZooKeeper)."
  },
  {
    "question": "When should you use hash-based partitioning vs range-based partitioning?",
    "answer": "Hash partitioning: Uniform distribution, good for random access. Range partitioning: Preserves ordering, good for range queries. Choose based on your query patterns.",
    "tags": ["partitioning", "sharding", "database"],
    "notes": "Real example: User IDs → hash partition (uniform load). Timestamps → range partition (range queries like 'last 24 hours'). Hybrid approaches exist (compound keys)."
  }
]
Enter fullscreen mode Exit fullscreen mode

I import these directly into my flashcard system:

cat system_design_cards.json | ./flashcards bulk-create --project system-design
Enter fullscreen mode Exit fullscreen mode

Now I can quiz myself:

$ ./flashcards quiz --project system-design --limit 5

Question 1/5: In the CAP theorem, what does 'Partition Tolerance' actually mean?

[Show answer? y/n]
Enter fullscreen mode Exit fullscreen mode

The Spaced Repetition Loop

Here's how the system works:

  1. Generate flashcards from concept (Claude)
  2. Import into flashcard CLI
  3. Quiz yourself (spaced repetition schedules reviews)
  4. Rate confidence (1-5): Low = see again soon, High = see much later
  5. Repeat over days/weeks until internalized

The beauty: I can generate flashcards for any technical topic in minutes. No manual card creation. No finding existing decks that don't quite match my needs.

Topics I've Created Flashcard Decks For

  • Algorithms: Time complexity, specific algorithm details, when to use what
  • System design: Distributed systems patterns, scalability techniques
  • Languages: Rust ownership, Clojure idioms, Python async/await
  • Databases: Indexing strategies, transaction isolation levels, CAP tradeoffs
  • Kubernetes: Resource types, networking concepts, operator patterns
  • Interview prep: LeetCode patterns, behavioral question frameworks

The Meta-Pattern: AI as a Learning Compiler

These patterns share a common insight:

LLMs can transform any learning goal into a personalized learning artifact.

You provide a concept to learn, your preferred style (flashcards, annotated code), and your knowledge gaps. Claude generates materials tailored to you—at the right complexity, in the format you learn best from.

Practical Workflow

My typical learning workflow:

  1. Generate annotated code: Complete implementation with explanatory comments
  2. Extract flashcards: Key concepts become cards for spaced repetition
  3. Quiz over time: Spaced repetition embeds knowledge long-term

This takes 30-60 minutes to generate materials, then ongoing review. Traditional learning (reading papers, watching videos, manual note-taking) would take hours or days to achieve the same depth.

The Flashcard System Details

Since I mentioned my flashcard system, here's how it works:

Features:

  • Multiple spaced repetition algorithms (SM-2, Leitner, fixed intervals)
  • Project organization (tag by topic)
  • Adaptive quiz sessions (repeat failed items immediately)
  • JSON import/export (easy to generate with LLMs)
  • CLI for terminal-based studying

Usage:

# Create from Claude-generated JSON
flashcards bulk-create --file cards.json --project rust

# Start adaptive quiz session
flashcards quiz --project rust --limit 10

# Review a specific card
flashcards review <id> --confidence 4

# See statistics
flashcards stats --project rust
Enter fullscreen mode Exit fullscreen mode

The adaptive sessions are key: if you get a card wrong (confidence < 3), it immediately re-queues it. You practice until you get it right, then spaced repetition takes over for long-term retention.

Key Learnings

After a year of using LLMs for learning:

Annotated code beats plain code. The "why" matters more than the "what."

Flashcards with spaced repetition work. Generate hundreds of cards in minutes, internalize them over weeks.

Active learning beats passive. Quizzing yourself is more effective than rereading notes.

Conclusion: Beyond Code Generation

This series has been about working with LLMs at scale—managing multiple sessions, ensuring quality, building coordination patterns. But it's also been about a fundamental shift in how we work with code and knowledge.

LLMs aren't just code generators. They're:

  • Productivity multipliers (Part 2)
  • Quality enforcers (Part 3)
  • Coordination layers (Part 3)
  • Learning accelerators (Part 5)

The developers who thrive in this new world won't be the ones who use LLMs as fancy autocomplete. They'll be the ones who build workflows, tooling, and patterns that let them work at 10x their previous speed while maintaining quality and continuously learning.

My system—tmux integration, telemetry, memento, smoke tests, code review workflows, flashcards—is just one approach. Yours will look different based on your needs, your style, your projects.

But the core principles apply:

  • Make the invisible visible (ergonomics, telemetry)
  • Enforce quality automatically (smoke tests)
  • Share context between sessions (memento)
  • Learn continuously (flashcards, annotated code)

The future of software development is human-AI collaboration. Not humans being replaced, but humans being amplified. The question isn't whether to use LLMs—it's how to use them most effectively.

I hope this series has given you ideas, tools, and patterns you can adapt to your own workflow.

Now go build something amazing.


All tools mentioned are open source:
- Memento - Note system for LLM context
- Flashcards - Spaced repetition CLI
- Dotfiles - Tmux scripts and config
- AppDaemon - Home automation examples

Find me on GitHub or read more on my blog.

Top comments (1)

Collapse
 
ericjs profile image
Eric Schwarznbach

Your Part 1 and Part 4 links are broken.