Claude Code Shine in Explaining How Developers Work

This is the best insight I’ve ever received, straight from Claude Code, addressing the questions I have about developing professional SDKs.

RIGHT approach:

  1. Start at Level 0: def add(a, b): return a + b
  2. When you need it in 2 projects → Level 2 (class)
  3. When projects have different needs → Level 3 (config)
  4. When others use it → Level 4 (hooks)
  5. When it’s a product → Level 5 (full SDK)

So The journey with Claude Agent SDK

  • You started simple: “I want to query Claude”
  • Then needed: “I want my own tools” → MCP servers
  • Then needed: “I want to control permissions” → Hooks
  • Then needed: “I want sessions” → ClaudeSDKClient
"""
SDK Evolution: From Simple to Complex

This shows WHY and WHEN you add abstraction layers.
Start simple, add complexity ONLY when needed.
"""

import asyncio

# ===========================================================================
# LEVEL 0: The Simplest Thing That Works (5 lines)
# ===========================================================================

def add(a, b):
    return a + b

# Usage:
print(f"Level 0: {add(5, 3)}")

# ✓ Works perfectly
# ✓ Easy to understand
# ✓ No abstraction
# USE THIS if you just need to add numbers in YOUR OWN code

print("\n" + "="*80 + "\n")


# ===========================================================================
# LEVEL 1: Multiple Operations (20 lines)
# ===========================================================================

def add(a, b):
    return a + b

def subtract(a, b):
    return a - b

def multiply(a, b):
    return a * b

def divide(a, b):
    if b == 0:
        raise ValueError("Cannot divide by zero")
    return a / b

# Usage:
print(f"Level 1: Add = {add(5, 3)}")
print(f"Level 1: Divide = {divide(10, 2)}")

# ✓ Still simple
# ✓ Handles errors
# ✓ No fancy types needed
# USE THIS if you only need it in ONE project

print("\n" + "="*80 + "\n")


# ===========================================================================
# LEVEL 2: You Need to Share Across Projects (50 lines)
# ===========================================================================

# Now you want to use this in 3 different projects
# Problem: Copy-pasting is bad, bugs multiply
# Solution: Make a simple module

# calculator.py (separate file)
class Calculator:
    """Simple calculator - reusable across projects"""

    def add(self, a, b):
        return a + b

    def divide(self, a, b):
        if b == 0:
            raise ValueError("Cannot divide by zero")
        return a / b

    # ... other operations

# Usage:
calc = Calculator()
print(f"Level 2: {calc.add(5, 3)}")

# ✓ Reusable
# ✓ Still simple
# ✗ But: What if different projects need different precision?
# ✗ What if one project needs logging?
# USE THIS if needs are simple and similar

print("\n" + "="*80 + "\n")


# ===========================================================================
# LEVEL 3: Different Projects, Different Needs (100 lines)
# ===========================================================================

# Now:
# - Project A needs 2 decimal places
# - Project B needs logging
# - Project C needs to block certain operations

# You need CONFIGURATION

class Calculator:
    def __init__(self, precision=10, verbose=False):
        self.precision = precision
        self.verbose = verbose

    def add(self, a, b):
        if self.verbose:
            print(f"Adding {a} + {b}")

        result = a + b
        return round(result, self.precision)

# Usage:
calc_a = Calculator(precision=2)
calc_b = Calculator(verbose=True)

print(f"Level 3 (Project A): {calc_a.add(1/3, 1/3)}")  # 0.67 (2 decimals)
calc_b.add(5, 3)  # Prints log

# ✓ Configurable
# ✗ But: Hard to extend without changing source code
# ✗ What if Project C wants to intercept operations?
# USE THIS if you control all the projects

print("\n" + "="*80 + "\n")


# ===========================================================================
# LEVEL 4: You're Building a Product (200 lines)
# ===========================================================================

# Now you're building a PRODUCT that OTHER DEVELOPERS will use
# They want to:
# - Audit all calculations
# - Block dangerous operations
# - Add custom logic WITHOUT modifying your code

# You need: HOOKS

class Calculator:
    def __init__(self, precision=10, before_calculate=None):
        self.precision = precision
        self.before_calculate = before_calculate  # Hook!

    def add(self, a, b):
        # Call hook if provided
        if self.before_calculate:
            should_continue = self.before_calculate("add", a, b)
            if not should_continue:
                raise ValueError("Blocked by hook")

        result = a + b
        return round(result, self.precision)

# User A: Audit logging
def audit_hook(operation, a, b):
    print(f"[AUDIT] {operation}({a}, {b})")
    return True  # Allow

calc = Calculator(before_calculate=audit_hook)
print(f"Level 4: {calc.add(5, 3)}")

# ✓ Extensible without changing source
# ✗ But: Hook API is messy (just a function)
# ✗ What if user passes wrong type?
# USE THIS if you're building a library for others

print("\n" + "="*80 + "\n")


# ===========================================================================
# LEVEL 5: You're Building an SDK (500+ lines)
# ===========================================================================

# Now you're building an SDK that:
# - Thousands of developers will use
# - Needs to be stable for YEARS
# - Must provide GREAT developer experience
# - Can't break existing code when updating

# You need: TYPES, CONTRACTS, DOCUMENTATION

from dataclasses import dataclass
from typing import Literal, Callable

# Define the contract (types.py)
@dataclass
class CalculatorOptions:
    """Configuration options - THIS is your contract with users"""
    precision: int = 10
    verbose: bool = False

HookCallback = Callable[[str, float, float], bool]

class Calculator:
    """
    Professional calculator SDK.

    Example:
        >>> calc = Calculator(CalculatorOptions(precision=2))
        >>> calc.add(5, 3)
        8.0
    """

    def __init__(self, options: CalculatorOptions | None = None):
        self.options = options or CalculatorOptions()

    def add(self, a: float, b: float) -> float:
        """Add two numbers

        Args:
            a: First number
            b: Second number

        Returns:
            Sum of a and b, rounded to configured precision
        """
        result = a + b
        return round(result, self.options.precision)

# Usage:
options = CalculatorOptions(precision=5)
calc = Calculator(options)
print(f"Level 5: {calc.add(1/3, 1/3)}")

# ✓ Type-safe
# ✓ Self-documenting
# ✓ IDE support (autocomplete)
# ✓ Can evolve without breaking changes
# ✓ Professional
# USE THIS if you're building a PRODUCT for thousands of users

print("\n" + "="*80 + "\n")


# ===========================================================================
# THE KEY INSIGHT
# ===========================================================================

print("""
THE KEY INSIGHT: Don't Start with Level 5!

WRONG approach:
1. Need to add two numbers
2. Build entire SDK with types, hooks, etc.
3. Overwhelmed, give up

RIGHT approach:
1. Start at Level 0: def add(a, b): return a + b
2. When you need it in 2 projects → Level 2 (class)
3. When projects have different needs → Level 3 (config)
4. When others use it → Level 4 (hooks)
5. When it's a product → Level 5 (full SDK)

Each level solves a REAL PROBLEM you encountered.
Don't add complexity until you FEEL THE PAIN.

Example: Your journey with Claude Agent SDK
- You started simple: "I want to query Claude"
- Then needed: "I want my own tools" → MCP servers
- Then needed: "I want to control permissions" → Hooks
- Then needed: "I want sessions" → ClaudeSDKClient

Claude SDK is Level 5 because:
✓ Thousands of users
✓ Needs to be stable
✓ Complex use cases (hooks, MCP, sessions)
✓ Must evolve without breaking

Calculator SDK teaching example is Level 5 because:
✓ Teaching professional patterns
✓ Showing what production code looks like
✓ But you wouldn't write this for personal use!

For YOUR projects:
- Personal script? → Level 0 or 1
- Company internal tool? → Level 2 or 3
- Open source library? → Level 4
- Commercial product? → Level 5

START SIMPLE. Add complexity when you need it.
""")


# ===========================================================================
# PRACTICAL EXERCISE
# ===========================================================================

print("""
EXERCISE: Rebuild Calculator SDK from Level 0

Step 1 (5 min): Write add/subtract/multiply/divide functions
Step 2 (5 min): Put them in a class
Step 3 (10 min): Add precision parameter
Step 4 (15 min): Add a simple hook
Step 5 (30 min): Add types for the hook

By building it INCREMENTALLY, you'll understand WHY each piece exists.

Try it now! Create simple_calc.py and build Level 0 → Level 5.
""")

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.