Chapter 17 Exercises: GitHub Copilot and AI Code Assistants
These exercises build practical skill with AI coding tools through hands-on practice. They are designed for developers who have access to at least one AI code assistant (GitHub Copilot, Cursor, or a similar tool). Many exercises can also be completed using a conversational AI like Claude or ChatGPT if you do not have access to an in-editor tool.
Exercise 1: Comment-Guided Completion Baseline
Goal: Establish your baseline before practicing comment-guided prompting.
Write the following function using only the function signature (no guiding comment), accepting Copilot's first suggestion:
def parse_csv_to_dict(filepath: str) -> list[dict]:
pass
Note what Copilot generates. Now try again with this comment before the function:
# Parse a CSV file where the first row is headers. Return a list of dicts
# where keys are column headers and values are strings. Raise FileNotFoundError
# if path doesn't exist. Raise ValueError if the file is empty or has no headers.
# Use the csv module from the standard library.
def parse_csv_to_dict(filepath: str) -> list[dict]:
pass
Compare the two suggestions. What changed? Which required less editing?
Exercise 2: Docstring-First Development
Goal: Practice writing docstrings that guide implementation.
Write only the function signature and docstring for a function that:
- Takes a list of product dictionaries, each containing name, price (float), category (str), and in_stock (bool)
- Returns a dictionary grouping products by category
- Only includes in-stock products
- Sorts products within each category by price ascending
- Raises TypeError if any product is missing required fields
Write the docstring first, as precisely as you can. Then let Copilot generate the implementation. Review the implementation: did the docstring precision translate to implementation quality?
Exercise 3: Cycling Through Suggestions
Goal: Build the habit of viewing multiple suggestions before accepting.
Set up a simple function:
# Find all duplicate values in a list, return them as a sorted list with no duplicates
def find_duplicates(items: list) -> list:
Use Copilot's "Show Next Suggestion" (Alt+] on most platforms) to see at least three different implementations. For each: 1. What algorithm does it use? 2. What is the time complexity? 3. Does it handle empty input? 4. Are there any edge cases it misses?
Choose the best suggestion and explain your choice.
Exercise 4: Security Vulnerability Detection
Goal: Practice identifying security issues in AI-generated code.
Ask Copilot or an AI assistant to generate a user login function for a web application. Use a vague prompt like:
# Check if username and password are valid, return True if authenticated
def authenticate_user(username: str, password: str) -> bool:
Examine the generated code for: 1. Is the password stored and compared securely (hashed, not plaintext)? 2. Is there any SQL injection risk if a database query is involved? 3. Is a constant-time comparison used to prevent timing attacks? 4. Are there any information disclosure risks in error messages?
Write down every security issue you find. Then write the secure version.
Exercise 5: Test Generation and Evaluation
Goal: Use Copilot to generate tests, then evaluate their quality.
Take this function:
def calculate_discount(price: float, discount_percent: float, max_discount: float = 50.0) -> float:
"""
Apply a percentage discount to a price.
discount_percent must be between 0 and max_discount.
Raises ValueError for invalid inputs.
Returns the discounted price rounded to 2 decimal places.
"""
if not 0 <= discount_percent <= max_discount:
raise ValueError(f"Discount must be between 0 and {max_discount}")
if price < 0:
raise ValueError("Price cannot be negative")
discounted = price * (1 - discount_percent / 100)
return round(discounted, 2)
Use Copilot's /tests command to generate a test suite. Evaluate each test:
- Does it test meaningful behavior?
- Is the assertion correct?
- Will it catch actual bugs?
- What edge cases are missing?
Add at least five tests for cases Copilot missed.
Exercise 6: Refactoring with Explanation
Goal: Use AI to refactor legacy-style code and understand the improvements.
Ask Copilot Chat or Claude to refactor the following function. Request that it explain each change and why it improves the code:
def p(d):
r = []
for i in range(len(d)):
x = d[i]
if x['s'] == 1:
t = x['n'] + ' - $' + str(x['p'])
r.append(t)
return r
After refactoring, answer: What made the original code hard to read? What naming and structural choices in the refactored version make it clearer? Did the refactored code change any behavior?
Exercise 7: API Verification Drill
Goal: Build the habit of verifying AI-suggested API calls.
Ask Copilot or an AI assistant to write code that:
1. Makes an HTTP POST request using the requests library
2. Authenticates with a Bearer token
3. Handles rate limiting (HTTP 429 responses)
4. Implements exponential backoff on failure
For each API call in the generated code, verify against the requests library documentation:
- Does the function exist?
- Are the parameters correct?
- Is the return type used correctly?
- Are there any deprecated patterns?
Note any discrepancies between the suggestion and current documentation.
Exercise 8: Multi-Tool Workflow
Goal: Practice combining conversational AI and Copilot for a realistic task.
Design and implement a simple cache class with the following workflow: 1. Start with Claude or ChatGPT: ask it to explain the tradeoffs between LRU (Least Recently Used) and LFU (Least Frequently Used) cache eviction policies for a web application with heavily skewed access patterns 2. Based on that conversation, choose one policy and explain your choice in a comment 3. Use Copilot to implement the chosen cache class 4. Return to Claude to ask what edge cases you should test 5. Use Copilot to implement those tests
Write a brief reflection: what did each tool contribute? What would have been harder without either one?
Exercise 9: Import Verification Exercise
Goal: Practice verifying AI-suggested packages against package registries.
Ask an AI assistant (Copilot or conversational) to suggest Python packages for: 1. Sending email via SMTP 2. Parsing HTML 3. Generating PDF documents 4. Validating email addresses 5. Rate limiting function calls
For each suggested package:
1. Verify it exists on PyPI at pypi.org
2. Check the number of downloads (PyPI stats or pypistats.org)
3. Check when it was last updated
4. Check if the suggested API matches the current documentation
Document any suggestions that pointed to deprecated packages or incorrect APIs.
Exercise 10: Debugging with Structured Prompts
Goal: Practice using structured debugging prompts to diagnose a bug.
This code has a bug:
def merge_sorted_lists(list1: list[int], list2: list[int]) -> list[int]:
result = []
i, j = 0, 0
while i < len(list1) and j < len(list2):
if list1[i] <= list2[j]:
result.append(list1[i])
i += 1
else:
result.append(list2[j])
j += 1
return result
Use the debugging template from the chapter to ask Copilot Chat to help diagnose it. Do not just paste the code — use the full template with all fields. Note whether the structured prompt produces better guidance than an unstructured question would.
(The bug: the function does not append remaining elements from either list after one list is exhausted.)
Exercise 11: Copilot for Documentation
Goal: Use AI to generate documentation for undocumented code.
Find a function in any personal or open-source project that has no docstring. Use Copilot's /doc command to generate documentation. Evaluate:
1. Is the generated description accurate?
2. Are the parameter descriptions correct?
3. Are the return value and types described correctly?
4. Are exceptions documented?
5. What context (business rules, design decisions) did AI miss that a human author would have included?
Edit the generated documentation to add what AI missed.
Exercise 12: Security Code Audit Drill
Goal: Systematically audit AI-generated code for security issues.
Ask Copilot or an AI assistant to generate a complete user registration endpoint for a Python web API, including: - Input validation - Password hashing - Database insertion - Sending a confirmation email - Returning appropriate HTTP responses
Apply the security review template from the chapter. Audit specifically for: - SQL injection vulnerabilities - Password handling issues - Email enumeration vulnerabilities (does the error message reveal whether a username exists?) - Input validation gaps - Rate limiting on the endpoint
Write up your findings and corrections.
Exercise 13: Context Window Experiment
Goal: Understand how file length affects Copilot quality.
Create a Python file with a single utility function at the top (well-commented, clear purpose). Then add 300-400 lines of unrelated boilerplate code beneath it. At the bottom of the file, start a new function that should call the utility function from the top.
Observe: does Copilot suggest the correct utility function call, or does it suggest alternatives? What does this tell you about Copilot's context window in your setup?
Exercise 14: Model Comparison (Cursor Users)
Goal: Compare how different models handle the same code generation task.
If you have access to Cursor (which lets you select models), generate the same function using at least two different models (e.g., GPT-4 and Claude). Use this function as your test case:
# Implement a decorator that caches function results with TTL (time-to-live) in seconds.
# Thread-safe. Works with functions that have hashable arguments.
# Max cache size of 1000 entries (LRU eviction when full).
def ttl_cache(ttl_seconds: int = 300, maxsize: int = 1000):
Compare the two implementations: - Which is more complete? - Which has better edge case handling? - Which is more readable? - Are there correctness differences?
Exercise 15: Pull Request Review with AI
Goal: Practice using AI as a pre-review step in code review.
Take any recent code change you have made (or create a small feature branch in a personal project). Ask Copilot Chat or Claude:
Review this code change as a senior developer would.
Focus on: correctness, error handling, performance, and security.
Be specific about any issues found — include line numbers or code references.
[Paste the diff or changed code]
Evaluate the review quality: - Did it catch any real issues? - Were there false positives? - What did it miss that a human reviewer would catch? - How would you use this as a pre-review step in your team's workflow?
Exercise 16: Trust Calibration Audit
Goal: Develop your personal trust calibration protocol.
Over one week of development work, track every Copilot suggestion you accept. For each accepted suggestion, note: - Task type (boilerplate, algorithm, security-related, test, documentation) - Time spent reviewing before accepting (estimate) - Whether you modified the suggestion (and how much) - Any bugs you caught during review
At the end of the week: - What task types got fastest review? Slowest? - What percentage of suggestions required modification? - Did you catch any security or correctness issues? - How would you adjust your review depth based on what you found?
Exercise 17: The "Explain My Code" Test
Goal: Use AI code explanation as a comprehension check.
Find a function in your codebase that you wrote at least six months ago and do not clearly remember. Ask Copilot Chat to explain it:
Explain what this code does, step by step. Then explain what it is designed to accomplish
and what assumptions it makes about its inputs. Finally, note any potential issues or
edge cases that might not be handled.
[Paste code]
Evaluate the explanation against your now-refreshed memory: - Was it accurate about what the code does? - Did it correctly identify the purpose? - Did it identify any real issues? - What did it miss about context or intent that you remember?
Exercise 18: Generating Boilerplate at Speed
Goal: Practice rapid, review-as-you-go boilerplate generation.
Using Copilot, implement a complete REST API resource (Python/Flask or Node/Express) for a Product entity with:
- GET /products (list with pagination)
- GET /products/:id (single item)
- POST /products (create)
- PUT /products/:id (update)
- DELETE /products/:id (delete)
Time yourself. After generation, review the full implementation: - How much did you modify from Copilot's suggestions? - Where did Copilot's assumptions match your intent? Where did they diverge? - What parts required the most manual correction?
Target: complete implementation reviewed in under 20 minutes.
Reflection Questions
After completing several exercises:
- What task types do you now trust Copilot for without extensive review? What types require slow, careful review?
- What was the most useful prompt strategy you discovered?
- Did you catch any security issues in AI-generated code? What was the pattern?
- How has your tab-acceptance behavior changed since starting these exercises?
- What is one workflow change you will make to your daily development practice based on what you learned?