Appendix G: Answers to Selected Exercises

This appendix provides answers to selected exercises from across all 42 chapters. For each chapter, two to three exercises are answered, drawn from a mix of difficulty tiers. Answers include brief explanations to reinforce the underlying concepts. Full solutions to coding exercises for selected chapters are available in the code/exercise-solutions.py file within each chapter's directory.


Part I: Foundations (Chapters 1--7)

Chapter 1: The Vibe Coding Revolution

Exercise 1 (Tier 1: Recall): Define "vibe coding" in your own words and explain how it differs from traditional software development.

Answer: Vibe coding is a software development approach where the developer collaborates with an AI assistant through natural language conversation to produce code. Rather than writing every line manually, the developer describes what they want, reviews what the AI generates, and iterates through feedback. It differs from traditional development in that the primary skill shifts from syntax recall and manual typing to effective communication, critical evaluation of AI output, and iterative refinement. The developer's role becomes more like a director or reviewer than a typist.

Exercise 5 (Tier 2: Apply): List three tasks where vibe coding would be highly effective and three where it would be less effective. Justify each choice.

Answer: Highly effective: (1) Generating boilerplate code such as data classes, CRUD endpoints, and configuration parsers, because these follow well-established patterns the AI has seen extensively. (2) Writing unit tests for existing functions, because the AI can analyze the function signature and docstring to generate comprehensive test cases. (3) Converting code between similar languages or frameworks, such as Flask to FastAPI, because the structural mappings are systematic. Less effective: (1) Designing novel algorithms for domain-specific optimization problems, because the AI may not have seen the specific domain constraints. (2) Debugging production issues that require understanding runtime state, environment configuration, and system interactions that the AI cannot observe. (3) Making architectural decisions that depend on team dynamics, business priorities, and organizational constraints that are difficult to convey in a prompt.

Exercise 9 (Tier 3: Analyze): Analyze the potential impact of vibe coding on junior developers. Does it help or hinder their growth?

Answer: Vibe coding has both accelerating and decelerating effects on junior developer growth. On the positive side, it provides immediate feedback and working examples, acts as a patient tutor that can explain concepts on demand, and allows juniors to build functional software faster, which increases motivation. On the negative side, over-reliance can prevent juniors from developing deep understanding of fundamentals, create a false sense of competence when the developer cannot evaluate or debug AI-generated code, and reduce the "productive struggle" that builds problem-solving skills. The net effect depends heavily on how vibe coding is practiced. Juniors who use AI as a learning tool (asking "why" questions, studying generated code, attempting to write solutions before consulting the AI) will grow faster. Juniors who use it as a black box that produces code they do not understand will develop fragile skills.


Chapter 2: How AI Coding Assistants Work

Exercise 2 (Tier 1: Recall): Explain what a token is and why tokenization matters for AI coding assistants.

Answer: A token is the fundamental unit of text that a language model processes. Tokens are typically subword units: common words like "the" or "return" are single tokens, while uncommon words may be split into multiple tokens (e.g., "tokenization" might become "token" + "ization"). Tokenization matters for coding assistants for three reasons. First, it determines the context window limit: a model with a 100,000-token context can process roughly 75,000 words or 300,000 characters of code. Second, it affects cost, since API pricing is typically per token. Third, it affects how well the model handles code, because models tokenize code differently from prose, and variable names or unusual syntax patterns may consume more tokens than expected.

Exercise 7 (Tier 2: Apply): Estimate the token count for a 200-line Python file and determine whether it fits in an 8,000-token context window along with a 500-word prompt.

Answer: A typical line of Python contains approximately 40 characters, so 200 lines is about 8,000 characters. Using the approximation of 1 token per 4 characters for code (which is reasonable because code has many short tokens like operators and keywords), that is approximately 2,000 tokens. A 500-word prompt is approximately 650 tokens (using the standard 1 token per 0.75 words approximation). The system prompt typically consumes 200--500 tokens. Total: approximately 2,000 + 650 + 350 = 3,000 tokens for input. This leaves about 5,000 tokens for the model's response, which is roughly 400 lines of code. The file and prompt fit comfortably in the 8,000-token window.


Chapter 3: AI Coding Tool Landscape

Exercise 3 (Tier 1: Recall): Name three categories of AI coding tools and give one example of each.

Answer: (1) Inline code completion tools, which suggest code as you type within an IDE. Example: GitHub Copilot. (2) Chat-based coding assistants, which engage in conversational interactions to generate, explain, or debug code. Example: Claude. (3) Agent-based coding tools, which can autonomously read files, execute commands, and complete multi-step tasks. Example: Claude Code.

Exercise 8 (Tier 3: Analyze): Compare two AI coding tools of your choice across five dimensions: code quality, ease of use, cost, integration options, and privacy.

Answer: Comparing GitHub Copilot and Claude Code: (1) Code quality: Copilot excels at inline completions for common patterns; Claude Code produces more thoughtful, architecturally aware code for larger tasks. (2) Ease of use: Copilot integrates seamlessly into IDE workflows with near-zero friction; Claude Code requires terminal familiarity and a different workflow but is more powerful for complex tasks. (3) Cost: Both operate on subscription models; Copilot's pricing is per-user per-month for IDE integration, while Claude Code pricing is based on API token consumption, which can vary significantly by usage. (4) Integration: Copilot integrates with VS Code, JetBrains, and other editors; Claude Code integrates with the terminal and supports MCP for custom tool extensions. (5) Privacy: Both send code to cloud servers for processing; organizations with strict data policies should review each provider's data handling terms. The choice depends on the use case: Copilot for rapid inline assistance, Claude Code for complex multi-file tasks and agentic workflows.


Chapter 4: Setting Up Your Environment

Exercise 2 (Tier 1: Recall): What is a virtual environment in Python and why should you always use one?

Answer: A virtual environment is an isolated Python installation that maintains its own set of installed packages, separate from the system-wide Python and from other projects. You should always use one because: (1) It prevents dependency conflicts between projects that require different versions of the same library. (2) It keeps the system Python clean and avoids accidentally breaking system tools. (3) It makes projects reproducible, since the exact package versions can be captured in a requirements.txt file. (4) It allows you to work on multiple projects with different Python versions and dependency sets on the same machine.

Exercise 6 (Tier 2: Apply): Create a virtual environment, install three packages, generate a requirements.txt file, and verify the setup works by importing all three packages in a script.

Answer: The commands are: python -m venv vibe-env to create the environment; source vibe-env/bin/activate (macOS/Linux) or vibe-env\Scripts\activate (Windows) to activate it; pip install requests flask pytest to install packages; pip freeze > requirements.txt to capture the dependencies. The verification script: import requests; import flask; import pytest; print("All imports successful.") Running this script should print the success message with no ImportErrors.


Chapter 5: Python Essentials

Exercise 3 (Tier 1: Recall): Explain the difference between a list, a tuple, and a set in Python.

Answer: A list is an ordered, mutable collection that allows duplicate elements. Use it when you need to maintain insertion order and may need to add, remove, or change elements. A tuple is an ordered, immutable collection that allows duplicates. Use it for fixed collections of related values (like coordinates or return values from functions) where immutability provides safety. A set is an unordered, mutable collection that does not allow duplicates. Use it when you need fast membership testing, deduplication, or set operations (union, intersection, difference).

Exercise 10 (Tier 2: Apply): Write a function that takes a list of strings and returns a dictionary mapping each unique string to its frequency count. Use type hints and a docstring.

Answer: def count_frequencies(items: list[str]) -> dict[str, int]: with docstring """Count the frequency of each unique string in the list.""" The body: counts: dict[str, int] = {} then for item in items: then counts[item] = counts.get(item, 0) + 1 then return counts. Alternatively, use from collections import Counter and return dict(Counter(items)). The Counter approach is more Pythonic and more efficient, but the manual version demonstrates the underlying logic.


Chapter 6: Your First Vibe Coding Session

Exercise 1 (Tier 1: Recall): List the five stages of a typical vibe coding session in order.

Answer: (1) Define the goal: clearly articulate what you want to build. (2) Provide context: give the AI relevant information about the project, constraints, and requirements. (3) Generate: prompt the AI to produce code. (4) Evaluate: review the generated code for correctness, style, and completeness. (5) Iterate: provide feedback to refine the code until it meets your standards.

Exercise 7 (Tier 2: Apply): Conduct a vibe coding session to build a command-line tool that converts temperatures between Celsius, Fahrenheit, and Kelvin. Document each prompt and response.

Answer: This is a hands-on exercise; the answer is the completed session. A good session would start with a clear specification prompt (specifying input format, supported conversions, error handling), then evaluate the initial code (checking edge cases like absolute zero, invalid units), then iterate (adding input validation, help text, and unit tests). The key learning is that the initial prompt's specificity directly determines the quality of the first response. A vague prompt like "make a temperature converter" will require more iteration rounds than one specifying all requirements upfront.


Chapter 7: Understanding AI-Generated Code

Exercise 4 (Tier 2: Apply): Given a 30-line AI-generated function, identify at least three potential issues without running the code.

Answer: Common issues to look for in AI-generated code: (1) Hardcoded values that should be configurable parameters (e.g., magic numbers, file paths). (2) Missing error handling for common failure modes (e.g., file not found, network timeout, division by zero). (3) Incorrect or overly permissive type handling (e.g., accepting Any when a specific type is expected). (4) Hallucinated APIs or methods that do not exist in the specified library version. (5) Logic errors in edge cases (empty input, single-element collections, boundary values). (6) Security issues like unsanitized user input used in SQL queries or shell commands. The exercise teaches that reading AI-generated code critically is a core vibe coding skill.

Exercise 9 (Tier 3: Analyze): Explain why an AI might generate code that uses an API function that does not exist. What causes this and how can you detect it?

Answer: AI models generate hallucinated API calls because they predict token sequences based on patterns, not by referencing actual documentation. If the model has seen many examples of a library being used, it may generate plausible-looking but nonexistent function calls by interpolating patterns. This is more likely for: (1) Less popular libraries with fewer training examples. (2) Recently updated libraries where the API has changed since the training data cutoff. (3) Functions whose names follow a pattern (if the library has read_json and read_csv, the model may hallucinate read_xml even if it does not exist). Detection methods: (1) Run the code and check for AttributeError or ImportError. (2) Verify function names against official documentation. (3) Use IDE autocompletion or type checking to catch nonexistent attributes. (4) Ask the AI to cite the documentation source for any unfamiliar API calls.


Part II: Prompting (Chapters 8--14)

Chapter 8: Prompt Engineering Fundamentals

Exercise 1 (Tier 1: Recall): List the four components of an effective code generation prompt.

Answer: (1) Task: clearly state what you want the AI to produce. (2) Context: provide relevant information about the project, language, framework, and constraints. (3) Format: specify the desired output format, including function signatures, docstrings, type hints, and style conventions. (4) Constraints: define boundaries such as performance requirements, library restrictions, and error handling expectations.

Exercise 8 (Tier 2: Apply): Transform a vague prompt into a precise prompt that produces better results.

Answer: Vague: "Write a login function." Precise: "Write a Python function called authenticate_user that takes an email string and a password string, queries a SQLAlchemy User model to find the user by email, verifies the password using bcrypt.checkpw, returns the User object on success or raises a ValueError with a descriptive message on failure. Include type hints, a Google-style docstring, and handle the case where the email is not found." The precise version constrains the output on eight dimensions: function name, parameters, database layer, password hashing library, return type, error type, documentation style, and edge case handling.

Exercise 12 (Tier 3: Analyze): Compare the outputs of three different prompts for the same task and analyze why the outputs differ.

Answer: The differences arise from how each prompt constrains the output probability distribution. A vague prompt leaves many degrees of freedom: the model must choose the function name, parameter types, error handling approach, documentation style, and implementation strategy. Each choice point is a branch in the probability space, and different prompt framings shift which branches are most probable. A specific prompt collapses most of these choices, leaving the model to make decisions only where the prompt was silent. The lesson: every unspecified detail is a degree of freedom that the model will fill with its most probable completion, which may not match your intent.


Chapter 9: Context Management

Exercise 3 (Tier 1: Recall): What is a context window and why does its size matter?

Answer: The context window is the total amount of text (measured in tokens) that a language model can process in a single interaction. It includes the system prompt, conversation history, any provided code or documents, and the model's own response. Size matters because: (1) It limits how much code the model can "see" at once, affecting its ability to understand large codebases. (2) It determines how long a conversation can continue before older messages must be dropped. (3) Information near the edges of the window may receive less attention than information near the beginning or end (the "lost in the middle" effect). (4) Larger contexts cost more tokens and therefore more money.

Exercise 7 (Tier 2: Apply): Design a strategy for providing context about a 50-file project to an AI assistant that has a 100K-token context window.

Answer: A layered strategy: (1) Always include a project overview (architecture, tech stack, conventions) in the system prompt or CLAUDE.md file (~500 tokens). (2) Provide the directory tree structure as orientation (~200 tokens). (3) Include only the files directly relevant to the current task (typically 3--8 files). (4) For each included file, consider whether the full file is necessary or whether relevant excerpts suffice. (5) Use search results (function signatures, grep output) instead of full files when only a reference is needed. (6) Keep a running summary of previous conversation turns rather than preserving every exchange verbatim. With this strategy, 50 files averaging 200 lines each (roughly 100K characters, or 25K tokens for all files) can be managed by loading only the 10--15 most relevant files per task.


Chapter 10: Specification-Driven Prompting

Exercise 2 (Tier 1: Recall): What is specification-driven prompting and how does it differ from conversational prompting?

Answer: Specification-driven prompting provides a structured, complete specification of the desired output before asking the AI to generate code. It includes input/output types, behavior descriptions, edge cases, constraints, and examples. Conversational prompting is more exploratory: the user describes what they want informally and refines through back-and-forth. Specification-driven prompting produces more predictable, higher-quality output on the first attempt because it eliminates ambiguity that the model would otherwise fill with its own assumptions. Conversational prompting is faster to start but typically requires more iteration rounds.

Exercise 9 (Tier 3: Analyze): Analyze a case where specification-driven prompting would fail and conversational prompting would succeed.

Answer: Specification-driven prompting fails when the developer does not know enough about the solution space to write a complete specification. For example, if you need to integrate with an unfamiliar API and do not know the exact endpoint structure, parameter names, or authentication method, you cannot write a precise specification. Conversational prompting works better here because you can ask exploratory questions ("What authentication methods does the Stripe API support?"), get the AI's knowledge, and iteratively build understanding before committing to a specification. The lesson is that specification-driven prompting is optimal when the problem is well-understood, while conversational prompting is better for exploration and discovery phases.


Chapter 11: Iterative Refinement

Exercise 3 (Tier 2: Apply): Take an AI-generated function and conduct three rounds of refinement, documenting each prompt and the improvement it produces.

Answer: Round 1 might focus on correctness: "The function does not handle empty input. Add a check that returns an empty list if the input list is empty." Round 2 might focus on performance: "This implementation has O(n^2) complexity because of the nested loop. Refactor to use a dictionary lookup for O(n) time." Round 3 might focus on readability: "Rename the variables from single letters to descriptive names, and add inline comments explaining the logic for each step." Each round targets a different quality dimension, and the key insight is that refinement is more effective when each round has a single, clear focus rather than asking for multiple improvements at once.


Chapter 12: Advanced Prompting Techniques

Exercise 4 (Tier 2: Apply): Use chain-of-thought prompting to solve a complex debugging problem.

Answer: Prompt: "I have a Flask endpoint that sometimes returns a 500 error. Think through this step by step: (1) What are the common causes of intermittent 500 errors in Flask? (2) Looking at this code [paste code], which of those causes could apply here? (3) What is the most likely root cause? (4) What is the fix?" The chain-of-thought prompt forces the model to reason systematically rather than jumping to a conclusion. This technique is particularly effective for debugging because the reasoning steps often reveal the issue more reliably than asking directly "what's wrong with this code?"

Exercise 10 (Tier 3: Analyze): Compare chain-of-thought, few-shot, and constraint-based prompting for generating a sorting algorithm. Which produces the best result and why?

Answer: Chain-of-thought is best for producing a well-reasoned, correct implementation because it forces the model to think through the algorithm's logic step by step, reducing errors. Few-shot is best for producing code that matches a specific style or pattern, because the examples demonstrate the desired format concretely. Constraint-based is best for ensuring the output meets specific requirements (e.g., O(n log n) time, in-place, stable), because the constraints act as verifiable acceptance criteria. For a sorting algorithm, constraint-based prompting typically produces the best practical result because correctness and performance are the primary concerns, and constraints make these requirements unambiguous.


Chapter 13: Multiple Files and Large Codebases

Exercise 5 (Tier 2: Apply): Describe a strategy for asking an AI to make a change that spans five files in a codebase.

Answer: (1) Provide a project overview describing the architecture and how the five files relate. (2) Include the complete contents of the five files (or relevant excerpts if they are very long). (3) Describe the change in terms of the desired end state, not individual file edits. (4) Ask the AI to produce a plan first, listing what will change in each file and why, before generating the actual code. (5) Review the plan for correctness and completeness. (6) Then ask the AI to implement the changes, one file at a time. (7) After all changes, ask the AI to verify that the cross-file dependencies are consistent (imports, function signatures, type annotations). This systematic approach prevents the model from losing track of cross-file interactions.


Chapter 14: When AI Gets It Wrong

Exercise 2 (Tier 1: Recall): List four categories of errors that AI coding assistants commonly make.

Answer: (1) Hallucinated APIs: using functions, methods, or parameters that do not exist in the specified library. (2) Logic errors: code that is syntactically correct but does not implement the intended behavior, especially in edge cases. (3) Stale knowledge: using deprecated functions or outdated patterns from library versions that predate the model's training data. (4) Security vulnerabilities: generating code with SQL injection, path traversal, or other security flaws because the model prioritizes making the code work over making it safe.

Exercise 8 (Tier 3: Analyze): Analyze a scenario where AI-generated code passes all tests but still contains a subtle bug.

Answer: Consider AI-generated code for a pagination endpoint where the model uses offset and limit parameters. The tests pass because they test pagination with a dataset of 100 items. However, the code uses SELECT COUNT(*) FROM users WHERE active = true for the total count but applies no WHERE active = true filter to the paginated query itself, returning inactive users in the data while the count reflects only active users. This bug passes tests because the test dataset only contains active users. The lesson: test data must be adversarial, covering not just the happy path but also data that exercises every filter, boundary, and condition in the code.


Part III: Building Real Software (Chapters 15--23)

Chapter 15: CLI Tools and Scripts

Exercise 2 (Tier 1: Recall): What are the three main Python libraries for building CLI tools, and what distinguishes each?

Answer: (1) argparse (standard library): provides argument parsing with automatic help generation, type checking, and subcommands. Best for standard tools where you want zero dependencies. (2) click: uses decorators to define commands and options, making the code more readable. Supports command groups, automatic help pages, and testing utilities. Best for larger CLI applications with multiple subcommands. (3) typer: built on click and uses Python type hints to define arguments and options, reducing boilerplate. Best for developers who want type safety and minimal code. The choice depends on whether you prioritize zero dependencies (argparse), code elegance (click), or type-hint integration (typer).

Exercise 3 (Tier 2: Apply): Build a CLI tool that processes a CSV file and outputs summary statistics.

Answer: Use argparse for argument parsing with a required --input path and optional --format (text/json) flag. Read the CSV with csv.DictReader, compute per-column statistics (count, unique values, min/max for numeric columns), and output in the requested format. Key implementation decisions: use type hints on all functions, handle FileNotFoundError with a user-friendly message and non-zero exit code, and write a main() function guarded by if __name__ == "__main__".


Chapter 16: Web Frontend Development

Exercise 5 (Tier 2: Apply): Use an AI assistant to generate an HTML/CSS component and then refine it through iteration.

Answer: Start with a specific prompt: "Create an HTML card component showing a user profile with avatar, name, title, and a 'Contact' button. Use modern CSS with flexbox, rounded corners, subtle shadow, and a hover effect on the button." Refinement round 1: "Make the card responsive so it stacks vertically on screens under 600px." Round 2: "Add a smooth transition on the shadow when the card is hovered." The key learning is that visual components often require more iteration rounds than logic-heavy code, because visual correctness is harder to specify precisely in text.

Exercise 9 (Tier 3: Analyze): Compare generating frontend code with a visual description versus a structural description. Which produces better results?

Answer: Visual descriptions ("make it look modern and clean with a blue color scheme") produce inconsistent results because "modern" and "clean" are subjective. The AI must infer layout, spacing, typography, and component structure from vague aesthetic goals. Structural descriptions ("a two-column layout with a 250px sidebar on the left containing a navigation menu, and the main content area filling the remaining width, using CSS Grid") produce more consistent results because every dimension is specified. In practice, the best approach combines both: start with structural specifications for layout and component hierarchy, then add visual constraints for colors, fonts, spacing, and animations. This gives the AI the precision it needs while still allowing for aesthetic judgment on details.


Chapter 17: Backend Development and REST APIs

Exercise 4 (Tier 2: Apply): Design and implement a REST endpoint using AI-assisted development.

Answer: Prompt the AI with a complete endpoint specification: HTTP method, URL path, request body schema, response schema, status codes for success and each error case, authentication requirements, and rate limiting. Review the generated code for: proper status code usage (201 for creation, 404 for not found), input validation before database operations, appropriate error messages that do not leak internal details, and consistent response format. A common AI mistake to watch for: returning 200 for all responses and putting the actual status in the response body, rather than using proper HTTP status codes.

Exercise 7 (Tier 3: Analyze): Analyze the tradeoffs between FastAPI and Flask for AI-assisted backend development.

Answer: FastAPI advantages for AI-assisted development: (1) Type hints are built into the framework, so asking the AI to "add type hints" is natural and the framework enforces them at runtime. (2) Automatic OpenAPI documentation means the AI can generate self-documenting endpoints. (3) Async support is native, making it easier for the AI to generate concurrent code. Flask advantages: (1) Simpler mental model with fewer abstractions, so AI-generated code is easier to understand. (2) Larger ecosystem of tutorials and examples in training data, potentially producing higher-quality initial output. (3) More flexibility for non-standard patterns. For new projects with AI assistance, FastAPI is generally the better choice because its type-safety requirements align with the structured specifications that produce the best AI output.


Chapter 18: Database Design and Data Modeling

Exercise 3 (Tier 1: Recall): Define normalization and explain the first three normal forms.

Answer: Normalization is the process of organizing database tables to minimize redundancy and dependency. First Normal Form (1NF): Each column contains atomic (indivisible) values, and each row is unique. No repeating groups or arrays in a single column. Second Normal Form (2NF): Meets 1NF, and every non-key column depends on the entire primary key (no partial dependencies). Relevant only for composite primary keys. Third Normal Form (3NF): Meets 2NF, and no non-key column depends on another non-key column (no transitive dependencies). Example of a 3NF violation: storing both zip_code and city in the same table, since city depends on zip_code, not on the primary key.

Exercise 8 (Tier 2: Apply): Design a SQLAlchemy data model for a blog platform with users, posts, comments, and tags.

Answer: The model requires four tables with three relationships: (1) Users table with id, email, hashed_password, display_name, created_at. (2) Posts table with id, title, content, author_id (foreign key to users), created_at, updated_at. (3) Comments table with id, content, author_id (foreign key to users), post_id (foreign key to posts), created_at. (4) Tags table with id and name, plus a many-to-many association table post_tags linking posts and tags. Key design decisions: use relationship() with back_populates for bidirectional navigation, add indexes on foreign keys and frequently queried columns (email, created_at), and use ondelete="CASCADE" for comments when a post is deleted. A common AI mistake: forgetting the association table for many-to-many relationships and instead putting a comma-separated list of tags in a text column.


Chapter 19: Full-Stack Development

Exercise 6 (Tier 3: Analyze): Analyze the tradeoffs between a monolithic and a separated frontend/backend architecture for a full-stack project built with AI assistance.

Answer: Monolithic (e.g., server-side rendered templates): easier for the AI to reason about because all code is in one codebase and one language; fewer integration points that can go wrong; faster initial development. Separated (e.g., React + API): better for teams because frontend and backend can evolve independently; the AI can focus on one layer at a time with clearer boundaries; easier to add mobile clients or third-party integrations later. For AI-assisted development specifically, the separated architecture is often easier because each prompt can focus on one layer without mixing concerns, and the API contract serves as a precise specification that both sides must satisfy.

Exercise 2 (Tier 1: Recall): List the main components of a full-stack web application and describe the role of each.

Answer: (1) Frontend: the user-facing interface, rendered in the browser, handling user input and displaying data. Built with HTML, CSS, and JavaScript (or frameworks like React). (2) Backend/API: the server-side logic that processes requests, implements business rules, and coordinates data access. Built with frameworks like FastAPI, Flask, or Express. (3) Database: persistent storage for application data. Relational (PostgreSQL, SQLite) or document-based (MongoDB). (4) Authentication layer: verifies user identity and manages sessions or tokens. (5) Static asset serving: delivers CSS, JavaScript, images, and other static files, often via a CDN in production.


Chapter 20: External APIs and Integrations

Exercise 4 (Tier 2: Apply): Implement an integration with a third-party API including error handling, rate limiting, and retry logic.

Answer: The implementation should include: a wrapper class that encapsulates the API's base URL and authentication, methods for each endpoint that return typed response objects, error handling that distinguishes between client errors (400s, do not retry), server errors (500s, retry with backoff), and network errors (timeout, retry with backoff), rate limit handling that respects Retry-After headers, and logging of all API calls for debugging. A common AI mistake: not handling pagination in list endpoints, returning only the first page of results.

Exercise 2 (Tier 1: Recall): What is an API key and what are the security best practices for managing it?

Answer: An API key is a secret string used to authenticate requests to a third-party service. Best practices: (1) Never hardcode API keys in source code. (2) Store them in environment variables or a secure secrets manager. (3) Never commit them to version control; add .env to .gitignore. (4) Use different keys for development, staging, and production environments. (5) Rotate keys regularly and immediately if a key is exposed. (6) Use the minimum required permissions when creating keys. (7) Monitor API key usage for anomalies that might indicate compromise.


Chapter 21: AI-Assisted Testing

Exercise 2 (Tier 1: Recall): Explain the testing pyramid and how AI can help at each level.

Answer: The testing pyramid has three layers: (1) Unit tests (base, most numerous): test individual functions in isolation. AI excels here because given a function signature and docstring, it can generate comprehensive test cases including edge cases. (2) Integration tests (middle): test how components interact. AI can help generate these if given the component interfaces, but requires more context about the system. (3) End-to-end tests (top, fewest): test the full system from the user's perspective. AI can help structure these but often needs human guidance on realistic user scenarios. AI is most effective at the base of the pyramid and least effective at the top, because unit tests require only local function knowledge while E2E tests require understanding of user behavior and business context.

Exercise 6 (Tier 2: Apply): Generate pytest test cases for a given function, including edge cases and parametrized tests.

Answer: Effective prompt: "Generate pytest tests for this function: [paste function]. Include: (1) Happy path tests with typical inputs. (2) Edge cases: empty input, single element, very large input. (3) Error cases: invalid types, None, values outside expected range. (4) Use @pytest.mark.parametrize for testing multiple inputs with the same assertion pattern. (5) Use descriptive test names that explain what is being tested." Review the AI's output for: (a) whether the expected values in assertions are actually correct (AI sometimes asserts wrong values), (b) whether edge cases match the function's actual behavior (not just what the AI thinks the function should do), and (c) whether any important test scenarios are missing.


Chapter 22: Debugging and Troubleshooting

Exercise 5 (Tier 2: Apply): Use an AI assistant to debug a function by providing the code, error message, and test case that fails.

Answer: Effective debugging prompt structure: (1) "Here is a function that is supposed to [behavior]:" followed by the code. (2) "When I call it with [specific input], I expect [expected output] but get [actual output or error message]." (3) "The error traceback is:" followed by the full traceback. This three-part structure gives the AI everything it needs: the code, the failing case, and the error context. The AI can then compare the expected behavior against the implementation and identify the discrepancy. Avoid: sending only the error message without the code, or only the code without the failing test case.


Chapter 23: Documentation and Technical Writing

Exercise 3 (Tier 2: Apply): Use AI to generate a docstring, README section, and API reference for a Python module.

Answer: For each documentation type, provide different context: for docstrings, provide the function signature and a brief description of behavior; for README sections, provide the project overview and target audience; for API references, provide the endpoint specifications and response examples. The key insight is that the same code requires different documentation for different audiences, and the AI needs to know the audience to generate appropriate documentation. A common pitfall: AI-generated documentation that restates the code ("This function takes a list and returns a dictionary") rather than explaining the purpose and usage ("Use this to count word frequencies in a text document").


Part IV: Architecture (Chapters 24--30)

Chapter 24: Software Architecture

Exercise 3 (Tier 2: Apply): Ask an AI to suggest an architecture for a specified application and critically evaluate its response.

Answer: When evaluating AI-suggested architectures, check for: (1) Whether the suggested architecture matches the scale of the project (a microservices architecture for a personal blog is overengineered). (2) Whether the technology choices are compatible (suggesting both SQLAlchemy and Django ORM in the same Python project). (3) Whether the suggested architecture addresses the non-functional requirements you specified (performance, scalability, security). (4) Whether the component boundaries are clean (each component has a single responsibility). (5) Whether the data flow is clearly defined (how data moves from user input through processing to storage and back).

Exercise 1 (Tier 1: Recall): Define software architecture and explain why it matters for AI-assisted development.

Answer: Software architecture is the high-level structure of a software system, defining the major components, their relationships, and the principles governing their design and evolution. It matters for AI-assisted development because: (1) AI tools are most effective when working within a clear architectural framework that constrains the design space. (2) Without architecture, AI-generated code tends toward ad-hoc solutions that become increasingly difficult to maintain. (3) Architecture provides the vocabulary (layers, services, repositories, handlers) that makes prompts more precise and AI output more consistent. (4) Architectural decisions have the longest-lasting impact on a project, so they deserve the most human judgment rather than AI delegation.


Chapter 25: Design Patterns and Clean Code

Exercise 4 (Tier 2: Apply): Implement the Strategy pattern using AI assistance, then evaluate whether the AI's implementation follows clean code principles.

Answer: The Strategy pattern involves defining a family of algorithms, encapsulating each one, and making them interchangeable. A clean implementation uses a Protocol or ABC for the strategy interface, concrete classes for each algorithm, and a context class that accepts any strategy. When evaluating the AI's implementation, check: (1) Does each strategy class have a single responsibility? (2) Are the strategy implementations interchangeable (same interface)? (3) Is the context class decoupled from specific strategies? (4) Are names descriptive and intentions clear? Common AI mistakes: making strategies overly complex, or implementing the pattern using if/elif chains rather than actual polymorphism.


Chapter 26: Refactoring Legacy Code

Exercise 2 (Tier 1: Recall): What is a characterization test and why is it important when refactoring legacy code?

Answer: A characterization test documents the current behavior of existing code, regardless of whether that behavior is correct or intentional. It captures what the code actually does, not what it should do. Characterization tests are critical when refactoring because they provide a safety net: if a refactoring changes the code's behavior, the characterization test will fail, alerting you to an unintended change. Without them, you have no way to verify that a refactoring preserved existing behavior. They are especially important for legacy code where the original requirements or documentation may not exist.


Chapter 27: Security-First Development

Exercise 5 (Tier 2: Apply): Review AI-generated code for a login endpoint and identify all security vulnerabilities.

Answer: Common security issues in AI-generated login endpoints: (1) Storing passwords in plain text instead of using bcrypt or argon2 hashing. (2) Returning different error messages for "user not found" versus "wrong password" (enables user enumeration). (3) No rate limiting, allowing brute-force attacks. (4) SQL injection if user input is concatenated into queries rather than using parameterized queries. (5) Missing HTTPS enforcement. (6) Session tokens without expiration. (7) Logging the password in error messages or debug output. (8) No CSRF protection if using cookie-based authentication. Always review AI-generated security-sensitive code line by line.


Chapter 28: Performance Optimization

Exercise 3 (Tier 2: Apply): Ask an AI to optimize a slow function, then verify the optimization using benchmarks.

Answer: Effective optimization prompt: "This function processes 100,000 records and takes 45 seconds. Profile data shows 80% of time is spent in the inner loop. Optimize for speed while maintaining correctness." After receiving the optimization, verify by: (1) Running the original test suite to confirm correctness. (2) Timing both versions with timeit on realistic input sizes. (3) Checking that the Big-O complexity has actually improved (not just constant-factor optimization). (4) Verifying that the optimization does not increase memory usage beyond acceptable limits. A common AI mistake: optimizing for readability when asked for performance, or vice versa.


Chapter 29: DevOps and Deployment

Exercise 4 (Tier 2: Apply): Use AI to generate a Dockerfile and CI/CD pipeline configuration for a Python web application.

Answer: For the Dockerfile: specify the base image (python:3.12-slim), use multi-stage builds to minimize image size, copy requirements.txt first for layer caching, set a non-root user for security, and use ENTRYPOINT for the application. For CI/CD: generate a GitHub Actions workflow that runs linting, type checking, tests, builds the Docker image, and deploys on merge to main. Review the AI's output for: hardcoded secrets (should use GitHub secrets), missing cache configuration for pip dependencies, and appropriate use of environment variables for configuration.


Chapter 30: Code Review and Quality Assurance

Exercise 3 (Tier 2: Apply): Conduct a code review of AI-generated code using a structured checklist.

Answer: A structured review checklist for AI-generated code: (1) Correctness: does the code do what was asked? Test edge cases. (2) Security: any injection vulnerabilities, hardcoded secrets, or unsafe operations? (3) Performance: any O(n^2) loops, unnecessary database queries, or memory leaks? (4) Readability: are names meaningful, is the code well-organized, and are comments helpful? (5) Error handling: are all failure modes handled gracefully? (6) Testing: are tests comprehensive and do they cover edge cases? (7) Style: does the code follow the project's conventions? (8) Dependencies: are all imports actually used and are there any unnecessary dependencies?


Part V: Professional (Chapters 31--35)

Chapter 31: Version Control Workflows

Exercise 2 (Tier 1: Recall): Explain the purpose of a pull request and what makes a good PR description.

Answer: A pull request is a proposal to merge changes from one branch into another, providing a structured opportunity for code review, discussion, and automated checks before the changes are integrated. A good PR description includes: (1) A concise summary of what changed and why. (2) The issue or ticket number being addressed. (3) A list of specific changes made. (4) Any breaking changes or migration steps. (5) How the changes were tested. (6) Screenshots if there are visual changes. The description serves both the immediate reviewer and future developers trying to understand why a change was made.

Exercise 5 (Tier 2: Apply): Write a commit message and PR description for a given set of changes using AI assistance.

Answer: Effective prompt: "I made the following changes: [paste git diff or describe changes]. Write a conventional commit message (type: description) and a PR description with a Summary section (2-3 bullet points), a Changes section (list of what was modified), and a Testing section (how the changes were verified)." The AI produces consistent, well-structured descriptions when given the diff. Review the output for accuracy: AI sometimes mischaracterizes the nature of changes (calling a refactor a "fix") or misses important context (why the change was made, not just what changed).


Chapter 32: Team Collaboration

Exercise 5 (Tier 2: Apply): Design a team workflow for using AI coding tools that balances productivity with code quality.

Answer: The workflow should include: (1) AI-generated code must pass the same review process as human-written code, with no exceptions. (2) PR descriptions must disclose AI assistance so reviewers know to look for common AI mistakes. (3) All AI-generated code must have tests, either generated or written manually. (4) Shared prompt libraries for common tasks to ensure consistency. (5) Regular team discussions about AI tool effectiveness to share learnings. (6) A CLAUDE.md or similar project context file maintained by the team. (7) Code ownership remains with the developer who submitted it, regardless of how it was generated.


Chapter 33: Project Planning and Estimation

Exercise 4 (Tier 3: Analyze): Analyze how AI tools change time estimates for different types of tasks.

Answer: AI tools compress time estimates unevenly across task types. Boilerplate-heavy tasks (CRUD endpoints, data models, configuration files) see the largest reduction: often 60--80% faster. Test writing sees a significant reduction: 40--60% faster, because AI can generate comprehensive test cases from function signatures. Debugging sees a moderate reduction: 20--40% faster, because AI can analyze error messages and suggest fixes but cannot observe runtime state. Architecture and design see minimal reduction: 0--20% faster, because these tasks require human judgment about tradeoffs that AI cannot fully evaluate. The implication for estimation: apply different AI acceleration factors to different task categories rather than a uniform discount.


Chapter 34: Managing Technical Debt

Exercise 3 (Tier 2: Apply): Use AI to identify technical debt in an existing codebase and prioritize remediation.

Answer: Prompt the AI with specific files and ask: "Identify instances of technical debt in this code, classify each by type (code duplication, missing abstractions, outdated patterns, missing tests, poor naming), estimate the effort to fix (low/medium/high), and assess the risk of leaving it unfixed (low/medium/high)." Prioritize by: fixing high-risk, low-effort items first (quick wins), then high-risk high-effort items (strategic investments), then low-risk low-effort items (cleanup), and defer low-risk high-effort items. AI is particularly good at identifying code duplication, missing type hints, and inconsistent naming conventions because these are pattern-matching tasks.


Exercise 2 (Tier 1: Recall): Explain the difference between permissive and copyleft open-source licenses and how AI-generated code interacts with each.

Answer: Permissive licenses (MIT, BSD, Apache 2.0) allow the code to be used, modified, and distributed with minimal restrictions, including in proprietary software. Copyleft licenses (GPL, AGPL) require that derivative works also be released under the same license. AI-generated code creates legal uncertainty because: (1) If the AI was trained on GPL-licensed code and reproduces portions of it, the output may carry GPL obligations. (2) The legal status of AI-generated code's copyright is unsettled in many jurisdictions. (3) Organizations should establish policies about using AI for code generation and conduct due diligence on the training data of the tools they use. Best practice: treat AI-generated code as you would any third-party contribution, review it for potential licensing issues, and document the use of AI tools.


Part VI: Advanced (Chapters 36--40)

Chapter 36: AI Coding Agents and Autonomous Workflows

Exercise 1 (Tier 1: Recall): List five characteristics that distinguish an AI coding agent from a conversational AI assistant.

Answer: (1) Autonomous loop: agents operate in a plan-act-observe cycle rather than responding to individual prompts. (2) Tool use: agents can read files, write files, execute commands, and interact with external services. (3) Multi-step planning: agents decompose tasks into ordered steps and execute them sequentially. (4) Environmental interaction: agents observe the results of their actions and adapt accordingly. (5) Goal-directed behavior: agents pursue an objective rather than simply responding to the most recent message.

Exercise 8 (Tier 2: Apply): Implement a PermissionChecker class. (See code/exercise-solutions.py for the full implementation.)

Exercise 13 (Tier 3: Analyze): Analyze the agent trace for suboptimal decisions and missing guardrails.

Answer: Suboptimal decisions: (1) Iterations 1--6 read six files before making any changes, suggesting unfocused exploration; a targeted search would have been more efficient. (2) Iteration 9 re-reads a file the agent just wrote, which is unnecessary since the agent knows its own output. Missing guardrails: (1) Iteration 15 runs rm -rf /tmp/cache, which should have been blocked by a command safety check. (2) No iteration limit warning was triggered despite 15 iterations. (3) The agent modified test expectations (Iteration 13) rather than fixing its code, which should have triggered a review checkpoint. Efficiency improvement: the agent could have read only the files identified by a search in Iteration 1, reducing the exploration phase from 6 iterations to 2--3.


Chapter 37: Custom Tools and MCP Servers

Exercise 3 (Tier 2: Apply): Design a custom tool that queries a database and returns formatted results.

Answer: The tool should: accept a SQL query string and a database connection identifier as parameters, validate the query is read-only (starts with SELECT, does not contain INSERT/UPDATE/DELETE/DROP), execute the query with a timeout, format results as a readable table with column headers, and return at most 100 rows with a truncation notice. The tool description should clearly state it is read-only to help the model understand when to use it. Error handling should cover connection failures, query syntax errors, and timeout.

Exercise 1 (Tier 1: Recall): What is the Model Context Protocol (MCP) and what problem does it solve?

Answer: MCP is an open standard protocol for connecting AI models to external tools and data sources. It solves the problem of tool fragmentation: without a standard, every AI tool vendor implements its own tool integration format, forcing developers to rewrite integrations for each platform. MCP provides a common interface so that a tool built once can work with any MCP-compatible AI system. It defines how tools are discovered, how their schemas are communicated, how they are invoked, and how results are returned, standardizing the entire tool lifecycle.

Exercise 7 (Tier 3: Analyze): Analyze the security implications of allowing an AI agent to access an MCP server that connects to a production database.

Answer: Security implications: (1) Data exfiltration: the agent could query and expose sensitive data (PII, financial records) through its output or logs. (2) Resource exhaustion: expensive queries could overwhelm the database. (3) Indirect prompt injection: if the database contains user-generated content, that content could include instructions that manipulate the agent's behavior. (4) Access scope: the MCP server should use a read-only database user with access limited to non-sensitive tables. Mitigations: (1) Read-only database credentials. (2) Query result size limits. (3) Row-level security to prevent access to sensitive records. (4) Query audit logging. (5) Separate database replicas for agent access to avoid impacting production performance.


Chapter 38: Multi-Agent Systems

Exercise 4 (Tier 2: Apply): Design a communication protocol for two agents working on the same codebase.

Answer: The protocol needs: (1) Message types: proposal, approval, rejection, question, answer, status_update, and handoff. (2) Conflict resolution: when both agents want to modify the same file, the protocol assigns priority based on task type (bug fix > feature > refactor). (3) File locking: an agent must "claim" a file before modifying it and release the claim when done. (4) Shared state: both agents read from and write to a shared task board that tracks what has been done, what is in progress, and what remains. (5) Escalation: if agents disagree on an approach, the disagreement is escalated to a human with both agents' reasoning presented.

Exercise 1 (Tier 1: Recall): Define multi-agent system and explain why multiple specialized agents might be preferable to a single general-purpose agent.

Answer: A multi-agent system is an architecture where multiple AI agents with distinct roles collaborate to complete a task. Specialized agents are preferable because: (1) Each agent can have a focused system prompt optimized for its role (an architect thinks differently from a code reviewer). (2) Specialization allows different tool sets per agent (a reviewer needs read-only tools, a developer needs write tools). (3) Separating concerns reduces the cognitive load on each agent, improving quality. (4) The interaction between agents provides natural checkpoints and reviews. (5) Different agents can use different model sizes or configurations, optimizing cost.


Chapter 39: Building AI-Powered Applications

Exercise 2 (Tier 1: Recall): List three architectural patterns for applications that incorporate AI models.

Answer: (1) AI-as-a-service: the application calls an external AI API (like Anthropic or OpenAI) for specific tasks, keeping the AI logic separate from the core application. (2) AI pipeline: the application chains multiple AI calls in sequence, where each step's output feeds the next (e.g., extract information, then classify, then generate a response). (3) AI-in-the-loop: a human workflow is augmented with AI at specific decision points, with the human retaining approval authority over the AI's suggestions. Each pattern has different latency, cost, and reliability characteristics.

Exercise 6 (Tier 2: Apply): Implement a simple AI-powered feature (e.g., text summarization or sentiment analysis) in a web application.

Answer: The implementation requires: (1) An API endpoint that accepts user input (e.g., POST /api/summarize with a text field). (2) A service layer that calls the AI API with a well-crafted prompt and the user's text. (3) Error handling for API failures (timeouts, rate limits, malformed responses). (4) Response caching to avoid repeated API calls for identical inputs. (5) Input validation (minimum/maximum text length, content filtering). (6) Cost tracking to monitor API usage. Key design decision: make the AI call asynchronous so the web server is not blocked waiting for the AI response. Return a job ID and let the client poll for results, or use WebSockets for real-time updates.


Chapter 40: Emerging Frontiers

Exercise 3 (Tier 3: Analyze): Predict three ways AI coding tools will evolve in the next three years and justify each prediction.

Answer: (1) Agents will handle entire feature branches autonomously, from issue to merged PR, for well-defined tasks. Justification: current agents like Claude Code already demonstrate this capability for simple tasks, and improvements in planning, memory, and tool use will extend the range of tasks. (2) AI models will be fine-tuned on organizational codebases, producing code that matches internal conventions without extensive prompting. Justification: fine-tuning costs are decreasing rapidly and the value of organization-specific models is clear. (3) Formal verification will be integrated into AI code generation, with models producing code alongside proofs or property-based tests that verify correctness. Justification: current research in AI-assisted theorem proving suggests this is feasible, and the demand for verified AI output is growing.

Exercise 1 (Tier 1: Recall): List three emerging trends in AI-assisted development and explain the significance of each.

Answer: (1) Multi-modal coding assistants: AI tools that can interpret screenshots, diagrams, and mockups alongside code and text. Significance: this closes the gap between design and implementation, allowing developers to go from a whiteboard sketch directly to a working prototype. (2) AI-native programming languages: languages designed from the ground up to be generated and verified by AI, with built-in formal specification features. Significance: this could dramatically improve the reliability of AI-generated code by making correctness verifiable. (3) Continuous AI code review: AI that monitors every commit in real time and provides instant feedback on code quality, security, and performance. Significance: this moves code review from a discrete event (PR review) to a continuous process, catching issues as they are introduced.


Part VII: Capstone (Chapters 41--42)

Chapter 41: Capstone Projects

Exercise 1 (Tier 4: Create): Design and build a complete project using all the skills from this book.

Answer: This is an open-ended project exercise. A strong submission would: (1) Choose a project of appropriate scope (2--4 weeks of work). (2) Write a specification before coding. (3) Document the AI-assisted development process, including prompts used and iterations required. (4) Include comprehensive tests. (5) Follow clean code principles and appropriate design patterns. (6) Include a README explaining the project, how to run it, and what was learned about vibe coding during development. The project itself matters less than the quality of the development process and the reflective documentation.


Chapter 42: The Vibe Coding Mindset

Exercise 2 (Tier 1: Recall): Summarize the three core principles of the vibe coding mindset.

Answer: (1) Communicate with precision: the quality of your prompts directly determines the quality of the AI's output. Invest time in writing clear, complete, specific prompts rather than accepting the cost of vague prompts and multiple iterations. (2) Verify with rigor: never trust AI-generated code without testing it. Read the code, run the tests, check the edge cases. The AI is a powerful collaborator, not an infallible oracle. (3) Iterate with intention: each refinement round should have a specific goal (improve performance, add error handling, enhance readability). Undirected iteration ("make it better") is waste. These three principles apply regardless of which AI tool you use, which programming language you work in, or how the technology evolves.

Exercise 5 (Tier 3: Analyze): Reflect on how your relationship with coding has changed through learning vibe coding.

Answer: This is a personal reflection exercise. A thoughtful answer would address: how the developer's role has shifted from writing every line to directing and reviewing, how critical evaluation skills have become more important than syntax recall, how the speed of producing working code has changed the bottleneck from implementation to specification and testing, and how the emotional relationship with coding has evolved (from frustration with syntax to frustration with communication, from pride in clever implementations to pride in clear specifications and thorough reviews).


Solutions to additional exercises, including complete working code for all Tier 2 and Tier 4 exercises, are available in the code/exercise-solutions.py file within each chapter's directory.