Code examples are the heart of most technical books. They are where theory meets reality. A well-crafted example can teach more than pages of explanation, while a poorly constructed one can confuse and frustrate readers. This chapter covers how to write code examples that genuinely teach, and how to design exercises that reinforce learning.
This is non-negotiable. Every code snippet in your book should compile, run, and produce the output you claim it does. Broken code examples destroy trust instantly. A reader who encounters one broken example will question every example that follows.
Establish a process for verifying code:
Show enough code for the reader to understand and reproduce the example, but no more. Remove everything that is not directly relevant to the concept being taught.
Bad example (too much noise):
import os
import sys
import logging
from datetime import datetime
from pathlib import Path
from myapp.config import load_config
from myapp.database import get_connection
from myapp.utils import format_output, validate_input
logger = logging.getLogger(__name__)
def process_order(order_id: int) -> dict:
"""Process an order and return the result."""
config = load_config()
conn = get_connection(config.database_url)
# ... 30 more lines
Good example (focused on the concept):
from myapp.database import get_connection
def process_order(order_id: int) -> dict:
conn = get_connection()
order = conn.execute("SELECT * FROM orders WHERE id = ?", (order_id,))
# Process the order...
If the surrounding imports and setup matter, show them once in a complete listing and then omit them in subsequent snippets with a comment like # (imports omitted for brevity).
Build examples incrementally across a chapter. Start with a simple version and add to it section by section. This mirrors how developers actually build software, and it lets you teach one concept at a time.
# Version 1: Basic function
def greet(name):
return f"Hello, {name}"
Then, a few sections later:
# Version 2: With validation
def greet(name):
if not name or not name.strip():
raise ValueError("Name cannot be empty")
return f"Hello, {name.strip()}"
Then later still:
# Version 3: With logging and default
def greet(name=None):
if name is None:
name = "World"
name = name.strip()
if not name:
raise ValueError("Name cannot be empty")
logger.info(f"Greeting {name}")
return f"Hello, {name}"
Each version teaches a specific concept (basic functionality, validation, logging). The reader sees the code evolve naturally.
Short (1-5 lines) code fragments embedded in the text. Use for syntax demonstrations, single-line commands, or quick illustrations.
To install the package, run:
pip install flask
A focused block of code (5-25 lines) that demonstrates a single concept. The most common type in technical books. Always accompanied by an explanation of what the code does and why.
A full, working program or module (25-100+ lines). Use sparingly — typically once per chapter to show how individual concepts fit together. Number the listing for easy reference.
Show the code before and after a change. This is powerful for teaching refactoring, optimization, or migration concepts.
Never drop code on the reader without context. Before every code example, explain what the reader is about to see and why.
Bad:
Here is the code:
@app.route('/api/users', methods=['POST']) def create_user(): ...
Good:
We need an endpoint that accepts POST requests to create new users. The function validates the incoming JSON, creates a user record, and returns the new user’s ID:
@app.route('/api/users', methods=['POST']) def create_user(): ...
After the code, walk through the key parts. You don’t need to explain every line, but highlight the important decisions and non-obvious behavior.
Use a callout style for line-by-line annotations:
- Line 1: We register the route to handle POST requests at
/api/users.- Line 3: We parse the JSON body. Flask’s
get_json()returnsNoneif the body isn’t valid JSON.- Line 5: We call the database layer. Note that we pass the validated data, not the raw request body.
When modifying previously shown code, make it clear what changed. You can:
# NEW or # CHANGED.When your code produces output, show it:
$ python app.py
Server running on http://localhost:5000
Match the output format to the reader’s environment. If they are using a terminal, show terminal output. If they are using a browser, consider a screenshot or a formatted representation.
Exercises transform passive reading into active learning. A reader who works through exercises retains far more than one who only reads.
Verification exercises: “Run the example and confirm you see the same output.” Low effort, high confidence building. Use at the start of chapters.
Modification exercises: “Modify the example to add feature X.” Requires understanding the code well enough to change it. The most valuable type for learning.
Extension exercises: “Build Y using the techniques from this chapter.” Open-ended, requires synthesis. Good for end-of-chapter challenges.
Debugging exercises: “The following code has a bug. Find and fix it.” Teaches critical thinking and attention to detail.
Design exercises: “How would you architect a system that does Z?” No single correct answer. Good for advanced readers.
Two to five exercises per chapter is typical. At minimum, include one at the end of each chapter. If exercises are a core part of your teaching approach, you might include them after each major section.
Organize your repository to match your book structure:
book-examples/
chapter-01/
example-01-basic-server/
example-02-with-routing/
exercise-01-solution/
chapter-02/
...
requirements.txt
README.md
Consider using branches or tags for different stages of the running example:
chapter-01-start: The starting point for Chapter 1 exercises.chapter-01-end: The completed state after Chapter 1.chapter-02-start: The starting point for Chapter 2 (may differ from chapter-01-end if you clean up between chapters).This lets readers jump to any chapter without working through the entire book.
Your repository’s README should explain:
An example that works but the reader cannot understand why. Every line should be either self-explanatory or explained in the text. If you find yourself thinking “the reader doesn’t need to understand this part,” you should either explain it or remove it.
Libraries update, APIs change, syntax evolves. Examples that worked when you wrote them may not work when the reader tries them. Mitigate this by:
If a reader copies your code example and it doesn’t work because you included smart quotes, invisible characters, or output mixed with code, you have failed them. Test that your code is copy-paste friendly from the final output format.
| ← Chapter 4: Writing Your First Draft | Table of Contents | Chapter 6: Diagrams, Visuals, and Formatting → |