How To Use AI To Generate Code More Effectively

Introduction

The use of AI tools like Github Copilot, ChatGPT, and Codebuddy to assist with writing code has the potential to greatly increase developer productivity. Rather than writing every line of code manually, developers can leverage AI to generate significant portions of an application's codebase through conversational prompts. This allows developers to focus their time on more high-value tasks like designing architecture and business logic.

With the right techniques, developers can prompt an AI assistant to produce clean, maintainable code across multiple files and layers of an application. While AI-generated code still requires oversight and revisions, it provides a strong foundation. Our own developer teams have managed to reduce the time spent on coding tasks by over 80% by working with AI code generation tools.

The key to effectiveness is understanding the strengths and limitations of current AI capabilities. Developers need to learn when and where to leverage AI, and to prompt it with clear direction while not overloading it with overly complex requests. In this article, we will talk about some of the techniques we have employed to maximize the effectiveness of AI code generation.

Keep File Sizes Small

When working with AI for code generation, it's important to keep your file sizes small. AI has a limited context memory, so working with smaller files allows it to better understand and work with your code. Large, complex files can be cumbersome when attempting to get the AI to make changes since applying code changes automatically to these large files can take a long time to process, or requires the user to manually apply the code changes.

On the other hand, small, modular files give the AI a more manageable scope to work within. Each file has fewer code elements to keep track of, allowing the AI to more fully understand how the code works. This helps the AI make accurate edits and additions when prompted. So aim to break large files down into multiple smaller files with clear purposes and scopes. Modular code is not only good practice in general, but particularly vital when leveraging AI for code generation. The AI will be able to work faster and with higher fidelity when file sizes are kept reasonable.

Having small file sizes is also just good coding practice in general and it's generally worth the effort to break down larger files into smaller ones when possible for better maintainability and readability.

Don't Give Too Much Complexity in One Prompt

When prompting an AI to write code, it's important to recognize its capabilities and limitations. The limitation is not necessarily the length of the prompt, but rather the complexity of the problem you're asking the AI to digest. However, modern AI systems are quite adept at handling complex tasks that follow a clear logic flow. For example, creating an entire web app feature spanning from database to UI can be within the AI's capabilities. The interactions between components such as controllers, services, repositories, DTOs, and the UI can be linear and well-defined within it's training data, making it feasible for the AI to handle in one prompt. There have been instances where Codebuddy has successfully created and modified a dozen files for a web application in response to a single, well-structured prompt.

Yet, it is possible to overextend the capabilities of the AI. In such cases, the AI may respond by neglecting certain aspects of the request or by inserting placeholders into the generated code, signaling that the code is not fully operational and necessitates further development. It is essential to be cognizant of the complexity of the task you're presenting to the AI. Ensure that you're not expecting the AI to undertake more than it can handle in one go. This boundary is not always clear and it is something that comes from experience and engagement with the AI.

Be Verbose and Free-flowing with Voice Input

When prompting an AI to generate code, it is often better to speak your requests verbally rather than typing them out. Using natural speech allows you to be more verbose and ramble freely, which provides the AI with more context and detail. Speaking conversationally leads to prompts that contain redundant phrasing, multiple ways of explaining the same request, and more filler words. While this may seem inefficient, it actually helps the AI understand your requirements better. The redundancy provides clarity, and the rambling gives more examples for the AI to draw from.

In contrast, typing prompts tends to make humans more concise and precise. But this brevity can remove valuable context that assists the AI. The AI benefits from hearing the full, meandering breadth of your thoughts and ideas. This provides a clearer picture of what you want implemented in code. So for the best results when generating code with AI, try speaking your prompts aloud instead of typing them. The free-flowing, redundant, conversational style of speech leads to higher quality code generation. The AI gains a deeper understanding of what you want when you verbalize prompts naturally - even if you're correcting yourself while vocal prompting!

Retry Prompts to Improve Quality

Working with AI can be difficult due to it's non-deterministic nature. The very same prompt can result in perfect code, or it can result in wrong implementations and poor instruction following. Codebuddy mitigates this by having a distinct planning stage, which not only allows you to confirm if the AI is moving in the right direction with it's solution, but it also serves as a way to focus the AI before it attempts to write code - giving itself clear instructions on how to approach the implementation.

Unfortunately the planning stage doens't always work the way you would expect and sometimes you have to simply retry. It's generally best to change your prompt before retrying to give it a better idea, but sometimes the AI will simply go off the rails completely - in this case a retry without any changes to your prompt is enough. As AI models continue to improve, we anticipate a decrease in the frequency of these sorts of events.

Allow AI to Implement Features Its Own Way - If You Can

When asking an AI code generator to implement a new feature, it will likely approach the task in its own way, based on how it has been trained. It is best to allow the AI to follow its own familiar patterns and approaches, rather than trying to force it into unfamiliar territory. The main advantage of letting the AI implement features its own way is that it will be more consistent. The code patterns and architecture it generates for one feature can be more easily adapted and expanded when you ask it to build new, related features later on.

For example, if you prompt the AI to add user login to your application, it may generate controller and service classes in a certain style. When you later want to add profile editing, the AI will recognize that existing code style and architecture, making it simpler to consistently extend the user management features. Allowing the AI to follow its own conventions also makes the generated code more editable later. When you need to maintain or modify code, an AI will have an easier time understanding code that matches what it is accustomed to producing. If the codebase contains unfamiliar patterns, the AI will struggle to make changes without breaking things - or suggesting patterns that are inconsistent with your codebase.

So while it may sometimes be tempting to tightly control how an AI implements a feature, it is better to provide high-level requirements and let the AI fill in the details itself when possible. Leveraging its familiar methodologies will result in code that is more extensible, maintainable, and aligned with the AI's strengths.

Provide Clear References

When generating code, providing clear references is crucial for guiding the AI and filling in any gaps in your prompts. The references allow the AI to better understand the context of what you want it to build. This could include code snippets, documentation, or a series of entire files related to similar implementations of the feature you want implemented.

Some key tips on providing good references:

  • Include code examples that are highly related to what you want generated. This allows the AI to better recognize the patterns.

  • Provide documentation like API references or blog posts that talk about the implementation you're trying to achieve.

The more tailored and relevant your references, the better the AI will be able to fill in gaps in your prompt. It helps ground the AI and provides crucial context for generating high quality, customized code. Taking the time to provide thoughtful references pays off in the end with code that closely matches your specifications and style.

Prototype Development Sees Most Benefit

When using AI to generate code, it seems to be particularly efficient at generating code for prototype applications. With greenfield or prototype projects, you have the flexibility to structure the code however you want, without having to adhere to existing patterns. This allows the AI to freely implement features according to its training, enabling it to generate a very high percentage of the required code.

Our development teams have found that prototype projects can achieve 80-90% code generation directly from the AI, even for very large projects. This significantly accelerates development timelines and allows for rapid validation of new ideas.

On the other hand, making changes in established codebases with years of development history presents more challenges. The AI has to analyze vast amounts of existing code to understand coding conventions, architectural patterns, variable names, and other context. It becomes more difficult to apply AI-generated code without breaking existing code or requiring extensive revisions.

The greatest returns come from leveraging AI tools on new projects where you can maximize automated code generation. Then as the codebase matures, the AI can continue to provide a high level of assistance.

Older Codebases Are Still Benefiting Greatly

Older codebases can be modified to be better suited for AI assistance, but even without modification, AI can significantly accelerate development in these environments. The key is to provide great references (not unlike you would do for a human developer that is learning your codebase). While updating older codebases with AI code generation may not be as effortless as starting a new project from scratch with AI, it is still an acceleration that improves over time with practice. Learning what the AI does well and offloading some of the more tedious tasks to AI is a great starting point, and as you continue to learn about what is possible with AI - you will begin to think differently and apply the AI in more situations.

Established Codebases Require More Editing

When using AI to generate code for established codebases rather than prototypes, it can be harder to produce large amounts of new code without disrupting existing patterns and constructs. The AI may struggle to adhere to the quality standards and architecture already in place across a mature, human-generated codebase. Generating small, isolated code changes within legacy systems is less problematic than large structural changes or entirely new features. Rapid large-scale changes risk disrupting established conventions and architectures. More iterative, targeted changes are recommended.

Whereas with a prototype, the AI can freely implement features according to its training, with an established project it needs to slot new code into the existing structure. This requires more precision in prompting and providing good references. The AI has a limited context size, and may lose track of key requirements when prompted to make too many interconnected changes spanning multiple files.

Even if accurate references are provided, the AI can fail to fully replicate certain coding patterns. When making widespread changes, it may miss applying a certain standard consistently across all affected files. Some manual editing is required to smooth over these inconsistencies. Overall, while AI can accelerate development substantially in prototypes, its benefits are more modest within mature code. The developer spends more time prompting carefully, checking outputs, tidying up inconsistencies, and tweaking their prompts to be more specific about the implementations they need.

Conclusion

Using AI to generate code can provide tremendous efficiency gains if used properly. The key benefits and best practices include:

  • Keeping file sizes small so the AI can process code changes quickly and stay within context memory limits. Smaller files also represent better coding practices in general.

  • Avoid overloading the AI with overly complex prompts spanning multiple features or files. Break prompts down into simpler, linear tasks focused on individual components - but don't be afraid to implement entire features that span from the UI to the database if you have a good reference and if the request isn't too intellectually deep.

  • Use free-flowing, verbose voice prompts instead of terse typed prompts. The natural rambling helps the AI grasp context and requirements better.

  • Where possible, allow the AI to implement features in its own way, which tends to follow common coding practices and allows consistency across your codebase. Try not to force it into unnatural patterns.

  • Provide clear references and examples when possible to guide the AI. Retrying or reworking prompts can help improve quality.

  • New and prototype projects maximize efficiency gains. Established codebases require more human effort to maintain existing patterns and quality.

You might also like...

How To Use AI To Generate Code More Effectively