IS 4010: Application Development with Artificial Intelligence

Optional appendix: advanced AI workflows and prompting

Brandon M. Greenwell

Overview

This material is optional. It is not tied to a lab, and nothing here is required for the final project. Work through it when you want more deliberate habits for the tools you already use.

Part 1: advanced prompting

  • Outcome-focused prompting
  • Context management and iteration
  • AI-assisted code review
  • Debugging with AI

Part 2: repeatable AI workflows

  • Documentation generation
  • Refactoring strategies
  • Custom AI workflows
  • Evaluating AI outputs
  • Limitations and verification practices

Why AI workflow skills matter

A useful workflow can:

  • Reduce time spent on routine drafts and repetitive edits
  • Help explain unfamiliar code and compiler messages
  • Generate candidate tests, documentation, and refactors for review
  • Make assumptions and verification steps visible

The important question is not whether AI was used. It is whether the final result is correct, understood, tested, and appropriate for the project.

Part 1: advanced prompting

Anatomy of a useful prompt

Poor prompt:

write a function to sort a list

Better prompt:

Write a Python function that sorts a list of dictionaries by a
specified key. Include type hints, docstring, and handle edge
cases like missing keys.

More complete prompt:

I'm building a data processing pipeline in Python. I need a
function that:
- Takes a list of dictionaries and a key name
- Sorts the list by that key's value
- Handles missing keys gracefully (should those items go first or last?)
- Returns a new sorted list (don't modify original)
- Include NumPy-style docstring and type hints
- Should this be case-sensitive for string values?

Example input: [{"name": "Alice", "age": 30}, {"name": "Bob"}]

OpenAI guidance for current models

Five prompt checks

1. Context - Provide background information

I'm working on a Rust CLI tool for processing log files...

2. Constraints - Specify requirements and limitations

Must use only standard library, no external dependencies

3. Clarity - Be specific and unambiguous

Parse Apache Common Log Format, not generic logs

4. Success criteria - State how the result will be evaluated

Input: representative `access.log` fixture
Output: JSON summary of status codes
Check: fixture output matches the expected counts

5. Evidence - Request checks or sources that can be inspected

That's good, but can you make it handle malformed lines
without crashing?

Prompt pattern: review perspective

Technique: Name the review perspective and the evidence you want

Generic approach:

How do I optimize this Python code?

Specific review approach:

Review this function for performance risks in a high-traffic
web service. Identify the suspected bottleneck, explain what
measurement would confirm it, and propose the smallest change
worth benchmarking.

Examples:

  • “You are a security auditor reviewing this code…”
  • “As a Rust compiler, explain why this ownership pattern fails…”
  • “Act as a code reviewer focusing on maintainability…”
  • “You are teaching this concept to a beginner…”

Prompt Engineering Patterns

Prompt pattern: explanations and evidence

Technique: Ask for a concise explanation that you can check

Standard prompt:

Why doesn't this Rust code compile?
[code snippet]

Evidence-focused prompt:

This Rust code doesn't compile. Using the compiler message:
1. Identify the conflicting borrows and their source lines.
2. State the ownership rule involved.
3. Propose two fixes and explain their trade-offs.
4. Show the smallest corrected example.
5. Give the Cargo command that verifies the fix.

[code snippet]

Benefits: - Grounds the explanation in visible code and compiler output - Produces claims that can be checked independently - Separates alternative fixes from the chosen fix - Ends with an executable verification step

OpenAI model guidance

Prompt pattern: examples

Technique: Provide examples of desired input/output

Without examples (zero-shot):

Convert this function to use type hints

With examples (few-shot):

Convert this function to use type hints. Follow this style:

Example 1:
Input:  def add(a, b): return a + b
Output: def add(a: int, b: int) -> int: return a + b

Example 2:
Input:  def greet(name): return f"Hello, {name}"
Output: def greet(name: str) -> str: return f"Hello, {name}"

Now convert this function:
def process_data(items, threshold):
    return [x for x in items if x > threshold]

When to use: - Specific output formatting - Consistent code style - Complex transformations - Domain-specific patterns

Context management strategies

Problem: AI tools have limited context windows

Strategy 1: Chunking

First, let's focus on the data structures (send relevant code)
[AI responds]
Now let's look at the processing logic (send next chunk)

Strategy 2: Explicit references

In the validate_input() function we just discussed, add
error handling for the case where...

Strategy 3: Summary anchors

To summarize what we've built so far:
- User input validation with regex patterns
- SQLite database connection with connection pooling
- Error handling using Result types

Now let's add the query builder...

Strategy 4: Start fresh when needed

Let's start a new conversation. Here's the complete current
state of the module... [provide full context]

AI-assisted code review

Effective review prompt:

Review this Rust function for:

1. **Correctness**: Logic errors, edge cases, type safety
2. **Performance**: Unnecessary allocations, algorithmic complexity
3. **Idiomatic Rust**: Better patterns, standard library usage
4. **Security**: Input validation, potential vulnerabilities
5. **Maintainability**: Naming, documentation, structure

For each issue found:
- Explain WHY it's a problem
- Show HOW to fix it
- Rate severity (critical/moderate/minor)

[paste code]

Better than:

Is this code good?

Google Code Review Guidelines

Code review example

Reviewing for performance:

# Original code
def find_duplicates(items):
    duplicates = []
    for i in range(len(items)):
        for j in range(i + 1, len(items)):
            if items[i] == items[j]:
                duplicates.append(items[i])
    return duplicates

Prompt:

Review this Python function for performance issues. What's
the time complexity? How could we improve it? Show a more
efficient implementation using appropriate data structures.

Evaluate the response: - Does it identify the actual complexity from the supplied code? - Does the proposed data structure preserve ordering and duplicate behavior? - Do tests distinguish the original and revised implementations? - Does a benchmark support any performance claim?

Debugging with AI

Focused debugging prompt:

I'm getting this error in my Rust program:

[paste error message]

Here's the relevant code:
[paste minimal reproducing code]

Context:
- Using the repository's current stable Rust toolchain
- This worked before I added the new caching feature
- Error only happens with concurrent requests

Please:
1. Explain what's causing this error
2. Why did it start happening now?
3. Provide 2-3 different fix approaches
4. Which fix is most idiomatic for Rust?

Don’t just:

fix this error [paste entire file]

Rust Error Index

Debugging pattern: rubber duck and AI

Technique: Explain the problem as if teaching someone

Effective debugging conversation:

I'm confused about this borrow checker error. Let me walk
through what I'm trying to do:

1. I have a Vector of items
2. I iterate over it and process each one
3. During processing, I need to modify the vector
4. The compiler says I can't borrow mutably while iterating

I understand why this is unsafe (iterator invalidation), but
I'm not sure of the best pattern to solve it. Should I:
- Collect items to process first, then modify?
- Use indices instead of iterators?
- Restructure to avoid modification?

What's the most idiomatic Rust approach?

Why this works: - Demonstrates you understand the problem - Shows what you’ve tried - Requests trade-offs alongside proposed solutions

Iterative refinement

Conversation pattern:

Turn 1: Get initial implementation

Create a Python function to parse CSV files with error handling

Turn 2: Add requirements

Review the first draft. Then add these missing requirements:
- Support for custom delimiters
- Type validation for numeric columns
- Progress reporting for large files

Turn 3: Optimize

This works but it's slow on my 50MB file. Can you optimize it
to process in chunks and use a streaming approach?

Turn 4: Polish

Add a NumPy-style docstring and type hints for the public interface

Turn 5: Test

Generate pytest tests covering edge cases: empty files,
malformed rows, encoding issues

Multi-tool strategies

Different tools for different tasks:

GitHub Copilot (in-editor): - Autocompleting functions - Generating boilerplate - Quick inline suggestions - Pattern completion

Browser chat (conversational): - Complex explanations - Architecture decisions - Debugging multi-file issues - Learning new concepts

Copilot CLI or Antigravity CLI (terminal): - Explaining error messages - Generating shell scripts - Quick command lookups - Repository analysis

Primary documentation and search: - Verifying current APIs and commands - Comparing claims with authoritative sources - Finding release notes and migration guidance

Try it yourself: code review

Exercise: Use AI to review this code

def calculate_total(items):
    total = 0
    for i in items:
        total = total + i['price'] * i['quantity']
    tax = total * 0.08
    return total + tax

Prompt to try:

Review this Python function for:
1. Edge cases and error handling
2. Code clarity and maintainability
3. Potential bugs
4. More Pythonic approaches

Provide specific improvements with explanations.

Try in Claude | Try in ChatGPT

Part 2: repeatable AI workflows

AI-generated documentation

Focused documentation prompt:

Draft documentation for this Python module:

[paste code]

Please create:
1. Module-level docstring explaining purpose and usage
2. Function docstrings in NumPy style
3. README section with installation and examples
4. API reference table
5. Common usage patterns section

Focus on:
- Why to use each function, along with what it does
- Executable examples using the module's documented inputs
- Edge cases and limitations
- Performance characteristics

Why this works: - Specifies format (NumPy style) - Requests usage context alongside signatures - Requests examples and edge cases - Structures output clearly

Documentation quality checklist

After AI generates documentation, verify:

Accuracy: - [] Parameter types match actual code - [] Return values correctly described - [] Examples actually work - [] No hallucinated features

Completeness: - [] All public functions documented - [] Edge cases mentioned - [] Error conditions explained - [] Performance characteristics noted

Clarity: - [] Written for target audience - [] Examples are practical - [] Jargon explained - [] Links to related functions

Maintenance: - [] Matches current code version - [] Breaking changes highlighted - [] Deprecation warnings included

Documentation example

Code to document:

pub fn parse_log_entry(line: &str) -> Result<LogEntry, ParseError> {
    // Implementation
}

Draft documentation to review:

/// Parses a single log entry from Apache Common Log Format.
///
/// This function takes a raw log line and converts it into a
/// structured `LogEntry`. It handles standard Apache CLF format
/// and returns a parsing error for malformed entries.
///
/// # Arguments
///
/// * `line` - A string slice containing a single log line
///
/// # Returns
///
/// * `Ok(LogEntry)` - Successfully parsed log entry
/// * `Err(ParseError)` - Line doesn't match expected format
///
/// # Examples
///
/// ```
/// let line = r#"127.0.0.1 - frank [10/Oct/2000:13:55:36 -0700] "GET /index.html HTTP/1.0" 200 2326"#;
/// let entry = parse_log_entry(line)?;
/// assert_eq!(entry.status_code, 200);
/// ```
///

Refactoring with AI

Effective refactoring prompt:

I need to refactor this code for better maintainability.

Current issues:
- 300-line function doing too much
- Duplicated error handling logic
- Hard to test individual components
- Poor separation of concerns

Goals:
- Break into smaller, focused functions
- Extract common error handling
- Make testable with dependency injection
- Maintain backward compatibility

Please:
1. Propose a refactoring strategy
2. Show the refactored structure
3. Explain the benefits of each change
4. Identify any risks or trade-offs

[paste code]

Martin Fowler - Refactoring

Refactoring patterns

Common refactoring requests:

Extract function:

This function does validation, processing, and logging.
Extract each into separate, testable functions.

Replace magic numbers:

Replace all magic numbers with named constants at the
module level. Explain what each represents.

Introduce error types:

Convert these string error messages into a proper error enum.
Show how to use them with the ? operator.

Dependency injection:

This function directly creates a database connection. Refactor
to accept a connection as a parameter for better testing.

Simplify conditionals:

This nested if-else chain is hard to read. Refactor using
early returns or match expressions.

Test generation with AI

Focused test prompt:

Generate pytest tests for this Python function:

[paste function]

Please create tests for:
1. **Happy path**: Normal expected inputs
2. **Edge cases**: Empty inputs, None, extremes
3. **Error cases**: Invalid types, out-of-range values
4. **Boundary conditions**: Min/max values
5. **Integration**: How it works with related functions

For each test:
- Use descriptive test names
- Add docstrings explaining what's being tested
- Use pytest fixtures for common setup
- Include assertions with helpful failure messages

Result to inspect: Candidate cases that must be checked against the function contract

pytest Documentation

Test quality review

After AI generates tests, check:

Coverage: - [] Required behavior and important branches tested - [] Edge cases included - [] Error conditions verified - [] Integration scenarios covered

Quality: - [] Tests are independent (no shared state) - [] Meaningful test names - [] Clear assertions - [] Good failure messages

Practicality: - [] Tests actually run and pass - [] No flaky tests - [] Reasonable execution time - [] Mock external dependencies

Maintenance: - [] Tests will remain stable as code evolves - [] Not too brittle (over-specified) - [] Well-organized

Building custom workflows

Example: Git commit message generation

Workflow:

# 1. Stage only the files you reviewed
git add path/to/file.py path/to/test_file.py

# 2. Get diff
git diff --staged

# 3. Prompt AI
"Generate a conventional commit message for these changes.
Format: <type>(<scope>): <description>
Types: feat, fix, docs, refactor, test, chore
Keep description under 50 chars.

Changes:
[paste diff]"

# 4. Review and use
git commit -m "[AI-generated message]"

Then give the staged diff to Copilot CLI or Antigravity CLI from inside the repository. Review the proposed message before running git commit; do not create a global alias that silently sends every staged diff to an external tool.

Conventional Commits

Workflow: PR description generation

Custom GitHub PR workflow:

Generate a pull request description for these changes:

Branch: feature/user-authentication
Base: main

Changes made:
[paste git log]

File changes:
[paste git diff --stat]

Please create:
## Summary
- What this PR does (2-3 sentences)

## Changes
- Bullet list of main changes

## Testing
- How this was tested

## Screenshots (if applicable)

## Checklist
- [] Tests added/updated
- [] Documentation updated
- [] No breaking changes

Save as a template or shell script for reuse

Workflow: code explanation for teams

When explaining complex code to teammates:

Help me explain this code to my team in our documentation:

[paste complex function]

Create an explanation that:
1. **High-level overview**: What does this do and why?
2. **Step-by-step breakdown**: Walk through the logic
3. **Key concepts**: Any patterns or techniques used?
4. **Visual diagram**: ASCII diagram if helpful
5. **Example**: Concrete input → output walkthrough
6. **Common questions**: What might teammates ask?

Audience: Junior developers familiar with Rust basics

Result to inspect: An explanation whose examples and claims can be checked against the code

Evaluating AI output quality

Red flags in AI-generated code:

Hallucinated APIs

# This doesn't exist in standard library!
from requests import super_fast_download

Outdated patterns

// Old Rust 2015 style
extern crate serde;  // Not needed in 2021 edition

Over-complicated

# AI wrote 50 lines when 5 would work

Missing error handling

let file = File::open("data.txt").unwrap();  // Unhandled failure path

Security issues

eval(user_input)  # Never do this!

Quality verification checklist

Before using AI-generated code:

Correctness: - [] Code actually compiles/runs - [] Logic is sound - [] Edge cases handled - [] No hallucinated functions/APIs

Security: - [] Input validation present - [] No SQL injection risks - [] No command injection - [] Secrets not hardcoded

Performance: - [] Algorithms are efficient - [] No unnecessary allocations - [] Appropriate data structures - [] Scalability considered

Maintainability: - [] Code is readable - [] Well-structured - [] Properly documented - [] Follows project conventions

Understanding AI limitations

Tasks that often have useful drafts: - Boilerplate with an explicit template - Explanations of supplied code - Common implementation candidates - Test cases for specified behavior - Documentation outlines - Syntax translation with verification

Tasks that need stronger evidence: - Novel or context-dependent designs - Business rules absent from the prompt or repository - Performance claims without profiling - Security conclusions from a single review - Cross-file consistency in a large or partially supplied codebase - Decisions that depend on unstated project history

Response: Define the task, inspect the output, and use independent evidence to decide what to keep

When not to use AI

Situations where AI may hurt more than help:

Learning fundamentals:

Bad: "Write a binary search tree implementation for me"
Good: "Explain how BST insertion works, then I'll implement it"

Critical security code:

Don't trust AI blindly for:
- Authentication systems
- Encryption implementation
- Permission checks
- Input sanitization

Novel problem solving:

Models often reproduce familiar patterns more reliably than they solve
novel, context-dependent problems

Production hotfixes:

Under pressure, AI mistakes are more likely. Understand
the fix before deploying.

Academic integrity with AI

In this course:

  • AI use is encouraged as part of the development workflow
  • Each lab’s written instructions define its required files and any AI-specific activity
  • Do not modify supplied tests or workflows unless the assignment explicitly permits it
  • Never include passwords, tokens, API keys, or authentication output in a prompt or repository
  • Inspect git diff, run the documented checks, and understand every submitted line
  • Document AI use where the assignment requires it; the final project requires an AGENTS.md that orients an agent and an AI_USAGE.md that honestly records how you worked

The standard: > You must be able to explain every line of code you submit, > whether you wrote it, AI wrote it, or you found it online.

UC Academic Integrity Policy

Prompting for learning

Instead of: “Write this entire program for me”

Try: “I’m learning error handling in Rust. Help me understand…”

Learning-focused prompts:

I'm trying to implement [specific feature]. I've written
this code but it's not working:

[paste your attempt]

Please:
1. Don't give me the complete solution yet
2. Point out what I'm misunderstanding
3. Ask me questions to guide my thinking
4. Give me hints about which concept to study
5. Only show a solution after I've learned the concepts

Goal: Use AI as a tutor, not a solution generator

Socratic Method

Explaining your AI workflow

A clear workflow can demonstrate: - Efficiency: Get more done in less time - Code quality: Consistent reviews and testing - Communication: Clear documentation - Adaptability: Learning new tools/languages faster - Judgment: Knowing when to use AI vs. manual work

Questions you should be ready to answer: - “How do you use AI in your development workflow?” - “Describe a time AI helped you solve a complex problem” - “What are the limitations of AI coding assistants?” - “How do you verify AI-generated code quality?”

Common AI workflow patterns

Patterns to evaluate in your own work: - AI for first draft, human for refinement - AI for explanations, human for decisions - AI for tedious work, human for creative work - Tests, documentation, and source code as independent evidence - Small diffs and reversible changes during iteration

Building your AI toolkit

Recommended workflow setup:

In-editor (GitHub Copilot): - Tab completion for code - Function generation - Quick documentation

Terminal (Copilot CLI or Antigravity CLI): - Start the agent from inside the intended repository. - Ask it to inspect a concrete error or the staged diff. - Review every proposed command and edit before approval.

Browser chat: - Architecture discussions - Complex debugging - Learning new concepts

Documentation and search: - Current authoritative instructions - Release notes and migration details - Evidence for factual or time-sensitive claims

Create a personal prompt library: - Save effective prompts you use often - Customize for your projects - Share with teammates

Meta-prompting

Prompts about prompting:

Improve your prompts:

I want to ask an AI to help me optimize this Rust code.
What information should I include in my prompt to get the
best advice?

Generate custom prompts:

Create a prompt template I can reuse for generating
focused pytest tests for Python functions. Include
placeholders for [function_code] and [special_requirements].

Learn from AI:

What are the most effective techniques for prompting AI to
help with code review? Give me 3 example prompts showing
different approaches.

Evaluate your workflow:

I'm using AI to help with [task]. Here's my current process:
[describe workflow]

How could I improve this workflow for better results?

Key takeaways

Advanced prompting: - State the outcome, relevant context, constraints, and success criteria - Apply review criteria and examples when they communicate a real requirement - Manage context around the current task

Repeatable workflows: - AI for documentation, testing, refactoring - Build custom workflows for repetitive tasks - Verify output with independent evidence

Quality and ethics: - Understand AI limitations - Verify before using generated code - Use AI to enhance learning, not replace it - Maintain academic integrity and honest attribution

Decision making: - Choose the right tool for each task - Iterate and refine - Focus on understanding and verifiable solutions

Additional resources

Model guidance: - OpenAI guidance for current models - Anthropic prompting documentation

AI tools: - GitHub Copilot Documentation - Claude AI - ChatGPT - GitHub Copilot CLI - Antigravity CLI

Best practices: - Google Code Review Guidelines - Refactoring Catalog - Academic Integrity Resources

Final project application

Apply these skills to your final project:

Documentation: - [] Draft and verify a complete README - [] Add docstrings where they clarify public behavior - [] Create usage examples - [] Document installation steps

Code quality: - [] AI-assisted code review - [] Refactor complex functions - [] Add tests for required behavior, failure paths, and important boundaries - [] Check for security issues

Repository polish: - [] Write clear commit messages - [] Create detailed PR descriptions (if applicable) - [] Add comments where the reason for a choice is not evident from the code - [] Include performance notes only when they are measured and relevant

Use AI where it improves a rubric requirement, and verify every resulting change.

Questions?

Get help:

  • Office hours: Schedule on Teams
  • Course discussion: Microsoft Teams channel
  • AI tools: browser chat, GitHub Copilot, Copilot CLI, Antigravity CLI
  • Primary documentation for the tool in use

Follow the final-project deadline shown on the course site and in Canvas.

Remember: tool output is a proposal. You remain responsible for the requirements, evidence, and submitted result.

Course wrap-up

You have reached the final project stage.

Throughout this course, you’ve learned: - Python and Rust programming - Repeatable development practices - Testing, CI/CD, and distribution - Evidence-based AI-enhanced development workflows

What’s next: - Complete the final project against the published rubric - Publish work only when its configuration and data are safe to share - Continue practicing AI-enhanced development - Apply the same verification habits in future projects

Finish the final project by testing the behavior, reviewing the diff, and checking every rubric item.