Mastering Software Development with Claude
Technical Prompt Engineering
Structuring Prompts for Code
Basic prompts get you basic code. To get production-ready results from an LLM like Claude, you need to stop having a conversation and start giving detailed instructions. The key is structure. Just as a well-structured project has clear directories and files, a well-structured prompt has clear sections that guide the model toward a specific, high-quality output.
Claude responds particularly well to prompts structured with tags. This format allows you to create distinct blocks for your request, the constraints the code must follow, and the style you expect. Instead of a single, messy paragraph, you provide a clean, machine-readable specification.
Think of it like filing a bug report. You wouldn't just write "the app is broken." You'd provide steps to reproduce, expected behavior, and actual behavior. Technical prompting requires the same level of detail.
<prompt>
<user_request>
Create a Python function that takes a URL and returns the text content of the page.
</user_request>
<constraints>
- Must use the `requests` and `BeautifulSoup` libraries.
- The function must handle potential `requests.exceptions.RequestException`.
- If an error occurs, the function should return `None`.
</constraints>
<code_style>
- Follow PEP 8 guidelines.
- Include a docstring explaining what the function does, its arguments, and what it returns.
</code_style>
</prompt>
Guiding the AI's Reasoning
The most powerful technique for improving code quality is forcing the model to think before it writes. This is done using a approach, explicitly telling Claude to outline its logic first. By using a <thinking> tag, you instruct the model to write down its plan, step-by-step. This internal monologue dramatically improves the final code's logic and reduces errors.
This method also gives you a way to debug the model's approach. If the code is wrong, you can look at the thinking steps to see where the logic failed. You can then correct its reasoning in a follow-up prompt to get the right output.
<prompt>
<user_request>
Write a Javascript function to validate an email address format.
</user_request>
<thinking>
First, I need to define what constitutes a valid email format. It's typically `local-part@domain`. The local part can have various characters. The domain has at least one dot. I should use a regular expression for this.
The regex should check for:
1. An initial set of characters for the username.
2. An `@` symbol.
3. A domain name followed by a `.`
4. A top-level domain of at least two letters.
The function will take the email string as input and return `true` if the regex matches, and `false` otherwise. I will wrap this logic in a function called `isValidEmail`.
</thinking>
</prompt>
<!-- Claude will now generate the code based on the thinking process it just outlined. -->
Personas and Constraints
To further refine the output, you can assign the model a persona. A persona is a system-level instruction that tells the model who it should be. This biases its responses toward a particular style and level of expertise. For example, asking it to act as a "Senior Site Reliability Engineer" will produce more robust, production-focused code than a generic request.
You combine this persona with a <constraints> block to enforce strict technical requirements. This is where you move from requesting code to architecting a solution. You can specify exact library versions, error-handling patterns, logging formats, and even performance requirements like time complexity.
Finally, complex features often require more than one prompt. You can chain prompts together, breaking a large task into smaller, manageable steps. First, ask for the database schema. Then, using that output, ask for the API endpoints. Then, using those endpoints, ask for the unit tests. Each step provides context for the next, resulting in a cohesive and complex piece of software.
System Prompt: You are a Senior Site Reliability Engineer specializing in backend systems. Your code must be robust, well-documented, and include comprehensive error handling.
---
User Prompt:
<prompt>
<user_request>
Design a Go function that retrieves user data from a PostgreSQL database given a user ID.
</user_request>
<thinking>
1. I'll define a `User` struct to hold the data.
2. The function will accept a database connection pool (`*sql.DB`) and a user ID (`int`) as arguments.
3. It will return a pointer to a `User` struct and an `error`.
4. I need to write the SQL query `SELECT id, username, email FROM users WHERE id = $1`.
5. I'll use `db.QueryRow()` to execute the query.
6. I'll use `row.Scan()` to map the result to the `User` struct fields.
7. I must handle the `sql.ErrNoRows` case specifically, returning `nil, nil` to indicate not found without an error.
8. Any other database error should be wrapped and returned.
</thinking>
<constraints>
- Use the standard `database/sql` and `pq` libraries.
- The function must handle the case where no user is found.
- All potential errors from the database driver must be handled and returned.
</constraints>
<code_style>
- Follow standard Go formatting (`gofmt`).
- Include comments explaining the logic for handling the `sql.ErrNoRows` case.
</code_style>
</prompt>
What is the primary benefit of structuring a prompt with XML tags when asking an LLM to generate code?
The practice of instructing a model to outline its logic step-by-step before writing code is known as what?