In Prompt Engineering is Communication I explored how getting the best from AI tools is really about communicating well with them. In this post I am going to share some of my strategies and approaches that help me to get the best results from my AI tools of choice.

To give some context, I primarily use two AI tools: Claude and GitHub Copilot. While some might argue that these tools overlap and I could just use one or the other, I find that they have different strengths and I like to use them in a blended way to leverage their respective strengths.

Start with a chat session

I’ll fire up a chat session whenever an idea pops into my head or I have a problem to solve. The mobile apps work great here because that thought might arrive when I’m out walking the dogs and away from my desk. I’ll lay out whatever is relevant: the problem I’m trying to solve, what I’ve tried, what I’m thinking in terms of a solution, any constraints or context that matters. Then I’ll let the AI take a first shot at it.

This is where something useful happens that’s worth calling out. The act of articulating the problem clearly enough to brief the AI properly often starts solving it. If you’ve heard of rubber duck debugging you’ll recognise this; the AI is just a very well read duck. Quite often my sessions end here; I’ve worked through the problem in the process of explaining it, answered my own questions, and I’m free to move on.

When I do need to take it further, I’ll pick the session back up and re-read the conversation so far. It helps me get back into the right mindset, and it gives me a chance to evaluate what the AI has offered. Then I work through a series of questions, challenging assumptions, providing feedback on what’s good, and pushing on anything that needs more thought. The key point here is I’m not looking at code yet. The AI may be offering partial code or a sketch of a solution, but I’m treating it as pseudocode. In the same way a junior engineer might grab a whiteboard with a senior to talk through a problem, that’s what I’m doing here. I’m playing the role somewhere between Product Owner and Architect, with the AI as a research and thinking partner.

If what we’ve worked up is something worth implementing, that leads me to…

Back to top

Build the prompt

Once I have a design or solution I’m happy with, I ask Claude to produce an implementation prompt for my build agent; in my case GitHub Copilot. This does a few things at once: it gives me a synopsis of what the chat has produced, it gives me one more chance to evaluate “is this actually what I want?”, and it gives me a well constructed starting point for the implementation. I find this approach surfaces things a human might skip over, like “make this change in that file, then make this related change in that other file”, the kind of sequencing that matters in practice.

By the time I’ve finished this process I have a clear mental model of what the solution should look like. That matters, because when Copilot produces its output I can compare it against that model and evaluate how well it has done rather than just accepting what comes back.

Back to top

Feedback and iterate

Taking the first output and running with it is a classic mistake; I’ve done it myself. The first step is simple: read the output and ask whether it actually makes sense based on your own experience, before you even get to whether it meets the criteria.

A concrete example from my own experience: one of the leading tools has a persistent tendency to hallucinate Terraform providers and resources. These days I’ve seen it often enough that a suspiciously perfect resource definition is a red flag. So my first pass after getting code back is always to go through the resources, imports, and external dependencies and verify they’re real. Then I’ll go through the logic: are we doing everything we should be, is there appropriate logging, is the error handling what I’d expect? Only once I’ve done that do I go back to the chat session with my feedback. Just like working with a junior engineer, it’s a back and forth.

Back to top

Get a second opinion

Another strategy I use consistently is to not trust the output from a single chat session, and often not even a single tool. You could run the same prompt multiple times and through multiple tools then aggregate the results. However this brute force approach can be exhausting I find, evaluating each and every output and providing feedback, it’s too much. Instead, my go to approach here is to work through to the solution within my preferred tool. Once I have a solution that I’m happy with, I will then take that solution and pass it back into the same and/or another tool and ask it to review the solution. I’ll give it the solution along with the original context and specifications and I will ask it to evaluate if the solution meets the criteria, have I missed anything, were there any other solutions I might have considered, and what might be improvements to consider. By doing this I reset the context and shift the task from creation to evaluation, from building to searching and reviewing.

I often take this concept further and ask for evaluation within a specific context; for example, I might ask for a security review of the code to highlight potential flaws or attack vectors. I’ll then take the feedback back to a development context and ask for improvements to address the security concerns. So you might see me bounce through multiple chats and contexts with the tool playing different personas or just resetting the context to move between creation and evaluation modes.

Back to top

Don’t forget to test

To me this one is a superpower that AI tools bring to the table. We have a solution, but just like we don’t trust human generated code to work flawlessly (we don’t do that, do we…?) we shouldn’t trust the code an AI produces. Even if everything looks good, we’ve iterated the design phase, and worked through the build and we’ve passed it back for a second opinion, we still need to test it to prove it works and can be trusted. Now, test engineering is an underrated skill, understanding failure modes and how humans interact with them is something many devs miss. This is where I find great value in AI tools. The short version here is “find all the ways to test this solution”. However as we’ve already discussed, a short prompt without context is a recipe for a bad result. Instead I go back through my steps above for the tests. I present the solution and the initial context (just like getting a second opinion) except this time I start exploring and asking about failure modes, testing against requirements etc. Much like building a prompt I’m now iterating through test design. I do this to build a conceptual suite of tests and then ask for the implementation prompt. Off that goes to Copilot to build and the loop starts again. We iterate the tests in exactly the same way, design, solution, second opinion, test, iterate.

Back to top

Stay in the loop

What you’ll notice across all of these steps is that I’m never just giving a prompt and running with the output. I’m staying in the loop; using my own judgement to evaluate the output, providing feedback, iterating on the design, guiding the process. This isn’t outsourcing the work to the AI, it’s collaborating with it.

There’s a side effect worth naming too. Many of these skills make you a better colleague and engineer regardless of the AI context. Explaining things clearly, giving useful feedback, evaluating results critically; these are all valuable when working with people too. By developing these habits in the context of working with AI, you’re also developing them for every other working relationship you have.

As for the hands-off, trust-the-AI approach; I understand the argument. AI assisted code doesn’t need to be perfect, it just needs to be better or faster than the alternative. But we don’t take a hands-off approach with our human colleagues either. We review, we give feedback, we stay in the loop. When every PR is perfect and every suggested change delivers exactly what was asked for with no side effects, then we can talk about loosening the reins. We’re not there yet.

Back to top

Wrapping up

The steps above aren’t a rigid process, they’re a cycle. Chat to explore and design, build with a well constructed prompt, review critically, get a second opinion, test thoroughly, and iterate. The loop repeats at every stage, and staying in it is the whole point.

To frame this in a wider context, we’ve moved on from the era of developers throwing switches to code 1s and 0s, we’ve mostly moved beyond writing assembly too. We have newer tools, programming languages, and frameworks that abstract away from the machine and let us work at a higher level. AI is the next step in that evolution, it’s a new tool that lets us work at an even higher level of abstraction; where we spend our time conceptualising something we want and considering how we’d like to get there, and then we use the AI to write the code for us. But we still need to be the ones conceptualising, designing, and evaluating.

None of this is about distrusting AI tools. It’s about applying the same standards you’d apply to any collaborative work. Brief clearly, review carefully, and don’t merge without testing. The AI’s role in that process is powerful, but it works best when you’re in the driving seat.

If the principles behind this approach are what you’re looking for rather than the workflow itself, my partner post Prompt Engineering is Communication covers the concepts and frameworks in more detail.

Back to top

If this article helped inspire you please consider sharing this article with your friends and colleagues, or let me know via LinkedIn or X / Twitter. If you have any ideas for further content you might like to see please let me know too.

Back to top

Updated: