Mastering Coding with LLMs

Leon Nicholls
15 min readAug 27, 2024

--

Ever wished you had a coding buddy who could whip up boilerplate code, brainstorm solutions, or even help debug that pesky error? Well, with Large Language Models (LLMs), that wish is closer to reality than you might think!

LLMs are quickly becoming the go-to tool for everything from generating code snippets to helping with complex problem-solving.

Some of the “rockstars” in the LLM coding scene include:

  • Google Gemini Advanced: Google’s latest and greatest, boasting impressive coding capabilities.
  • ChatGPT-4o: OpenAI’s powerhouse, known for its versatility and natural language understanding.
  • Claude 3.5 Sonnet: Anthropic’s offering, designed with safety and helpfulness in mind.
  • Cursor AI Code Editor: A code editor with LLM superpowers built right in.

This blog post will dive deep into our experience coding with these LLMs. We’ll show you how to harness their power to boost your productivity, tackle tricky problems, and even have a little fun. But, like any tool, LLMs have their quirks. We’ll also be upfront about their limitations and show you how to navigate them so you can get the most out of your LLM coding experience.

Setting the Stage: Gearing Up for Coding with LLMs

Before jumping into the exciting coding world with LLMs, let’s lay the groundwork for a smooth and productive experience. Think of it as prepping your tools and workspace before embarking on a DIY project.

Choosing the Right LLM: It’s Not Always Black and White

While each of the popular LLMs — Google Gemini Advanced (Pro model), ChatGPT-4, Claude 3.5 Sonnet, and Cursor AI Code Editor — have their strengths and specialties, the reality is that sometimes you’ll get surprisingly better results by simply trying a different LLM. It’s like having a team of expert consultants with unique perspectives and approaches.

Ideally, you’d have access to these LLMs and could experiment with each for every coding challenge. However, the reality is that the top-tier models often come with paid subscriptions, making it impractical for everyone to have the full suite at their disposal.

But that’s the nature of the LLM landscape right now — it’s constantly evolving. Your favorite LLM might only sometimes be the best choice for some tasks. And with updates and improvements happening at lightning speed, today’s underdog could be tomorrow’s champion.

The takeaway here is to be flexible and open to experimentation. Feel free to try different LLMs, even if it means stepping outside your comfort zone. You might be surprised at the results!

Role-Playing with LLMs: Unleash Their Inner Expert

Think of LLMs as actors on a stage, ready to take on any role you assign. Want your LLM to code like a seasoned Python developer with a knack for data visualization? Or you may need a bash scripting guru who can automate your workflow. With LLMs, you’re in luck!

By using specific prompts that define a role for the LLM, you essentially give it a “persona” to embody. This helps tap into its vast knowledge base and tailor its responses to your needs. It’s like having a team of expert consultants, each with a unique specialization.

Simple Roles to Get You Started

Try starting your prompts with these examples to see the difference role-playing can make:

  • “Act as a senior Python developer with expertise in data visualization using Matplotlib.”
  • “You are a bash scripting expert who can automate repetitive tasks on a Linux server.”
  • “Imagine you are a frontend developer specializing in React.js. Help me build…”

Level Up Your Prompts with Advanced Roles

As you become more comfortable with role-playing, you can explore even more specialized and nuanced roles:

  • “Act as a software architect and outline the design pattern suitable for a large-scale e-commerce platform.”
  • “You are a performance optimization expert focusing on reducing server response times in high-traffic scenarios.”
  • “Imagine you are a cybersecurity specialist, conduct a code review, and highlight potential vulnerabilities.”

Chain Roles for a Dynamic Workflow

For complex tasks, try chaining multiple roles together in your prompts. This allows you to guide the LLM through different project stages, leveraging its expertise in each area. For example:

  1. “Act as a project manager and outline the requirements for a mobile application that tracks fitness goals.”
  2. “Now, as a senior backend developer, implement the database schema based on the requirements provided.”
  3. “Finally, as a front-end developer, create a basic HTML structure and CSS styling for the app’s main screen based on the design concepts we’ve discussed.”

The possibilities are truly endless! Get creative with your role-playing prompts and see what coding magic you can conjure up. With some experimentation, you’ll be amazed at how LLMs can adapt and deliver tailored solutions for your specific coding challenges (see my previous article on roles).

Prompt Refinement: LLM Teamwork Makes the Dream Work

Sometimes, even the best LLMs need help understanding precisely what you want. That’s where prompt refinement comes in.

Think of it like this: you’re trying to explain a complex coding problem to a friend. You might start with a vague description, but as your friend asks questions and seeks clarification, you refine your explanation until they fully understand.

You can do the same thing with LLMs! If you’re not getting the desired results, try using an LLM to help craft a more transparent, more effective prompt (see my previous article on using Gemini to help you write better prompts)

With these tips in your toolkit, you’re well on your way to mastering the art of coding with LLMs. Let’s move on to the next section and explore some common pitfalls you might encounter!

When LLM Code Goes Wonky: Common Issues and Fixes

Let’s face it: even the most advanced LLMs could be better. They can generate code that’s buggy, inefficient, or just plain doesn’t work. It’s like asking your friend for directions and ending up lost in the woods — frustrating but not the end of the world.

In this section, we’ll explore some common pitfalls you might encounter when coding with LLMs, and we’ll equip you with the knowledge and strategies to overcome them. Think of it as your LLM troubleshooting guide!

Logic Errors & Mismatched Requirements: When LLMs Miss the Mark

Sometimes, LLMs don’t seem to “get it.” You give them a clear set of requirements, and they generate code entirely off-base. Or, the code might work on the surface but contain subtle logical errors that cause unexpected behavior.

This can happen for a few reasons:

  • Ambiguous Prompts: If your prompt needs to be crystal clear, the LLM might make assumptions or fill in the gaps with its understanding, leading to mismatched results.
  • Limited Context: LLMs have a finite “memory.” If your coding problem is complex or requires a lot of context, the LLM might lose track of the bigger picture and generate locally correct but globally incorrect code.
  • Training Data Bias: LLMs are trained on massive code datasets, which can contain biases or outdated practices. This can lead to the LLM generating code that’s not optimal or doesn’t follow modern coding standards.

To avoid these issues, be as specific and detailed as possible in your prompts. Break down complex problems into smaller, more manageable tasks. And if you still need to get the desired results, please rephrase your prompt or try a different LLM.

Compilation Errors: The Bane of Every Coder’s Existence

We’ve all been there — you hit the compile button, and your code throws a tantrum of errors. LLMs, unfortunately, are not immune to this. They can generate code with compilation errors, just like any human coder.

Some common culprits include:

  • Undeclared Variables: The LLM might use a variable without declaring it first.
  • Missing Imports: It might need to remember to import necessary libraries or modules.
  • Wrong API Usage: It might try to use a function or method that doesn’t exist or has the wrong parameters.

The good news is that these errors are usually easy to spot and fix. Show the compilation error to the LLM and ask for an explanation or suggest a fix.

Code Quality Concerns: It’s Not Just About Getting It to Work

So, your LLM-generated code compiles and runs without errors — great! But does it meet your quality standards?

Here are a few things to watch out for:

  • Lack of Error Handling: LLMs are only sometimes proactive about including robust error handling in their code. If something goes wrong at runtime, this can lead to unexpected crashes or data corruption.
  • Modularization and Comments: LLM-generated code can sometimes be a monolithic mess, lacking clear modularization and helpful comments. This makes it harder to understand, maintain, and extend in the future.
  • Debugging Aids: When things inevitably go wrong, you’ll want your code peppered with helpful print statements or other debugging tools. LLMs may only include these by default.
  • Performance Issues: LLMs might prioritize generating functional code over highly optimized code. This can result in performance bottlenecks, especially for computationally intensive tasks.

To address these concerns, be explicit in your prompts. Ask the LLM to include error handling, break down the code into modular functions, and add comments to explain the logic. If you’re debugging, don’t hesitate to ask the LLM to add print statements or other diagnostic tools to help you track down the issue. When faced with performance concerns, you can prompt the LLM to review its code and suggest optimizations, such as:

  • “Review the previous code you generated and improve it by addressing potential performance bottlenecks.”
  • “Identify areas where the code could be optimized for speed or memory usage.”
  • “Suggest alternative algorithms or data structures that might improve performance.”

By being mindful of these common pitfalls and using the strategies we’ve discussed, you can significantly improve the quality and reliability of your LLM-generated code. This will also boost the maintainability of the code when other software engineers or LLMs need to extend the code in the future.

LLMs Can Be Fickle: Dealing with Inconsistent Coding Responses

If you’ve spent time coding with LLMs, they can be unpredictable. One minute, they’re generating beautiful, elegant code; the next, they’re spitting out something that looks like a caffeinated monkey wrote.

In this section, we’ll explore some of the quirks and inconsistencies you might encounter when working with LLMs and share some strategies for avoiding them.

Code Variability: The Same Prompt, Different Results?

Have you ever given an LLM the same prompt twice and gotten a completely different code in response? It’s like asking your friend for their favorite ice cream flavor and getting a different answer every time!

This code variability can be frustrating, but it’s a natural consequence of how LLMs work. They’re probabilistic models, meaning they generate responses based on the likelihood of certain words or phrases appearing together, given the context of your prompt.

Even slight changes in your prompt or the random seed used by the LLM can lead to drastically different code outputs.

So, what can you do about it?

  • Be specific. The more specific and detailed your prompt, the less room for the LLM to interpret it differently. Only provide the particular lines you want to help with or specific instructions on what part of the code needs to be considered.
  • Experiment: If you’re unhappy with the first response, rephrase your prompt or ask the LLM to regenerate the code.
  • Iterate: Treat LLM-generated code as a starting point, not a finished product. Be prepared to refine and adapt it to your needs. Provide incremental feedback to the LLM to achieve better results.

The Vanishing Comments Phenomenon: Where Did My Comments Go?

Some LLMs have a curious habit of stripping comments out of their code responses. It’s like they’re trying to keep their code a secret!

This can be problematic, mainly if you rely on comments to understand the logic or document your code.

To combat this, try these tips:

  • Be explicit: In your prompt, ask the LLM to keep the existing comments in its code.
  • Use a different LLM: Some LLMs are better at preserving comments than others.
  • Add comments manually: If all else fails, you can always add comments to the generated code from previous versions of your code.

Repeating Mistakes: LLMs, Are You Even Listening?

You’ve pointed out an error in the LLM-generated code, but it repeatedly makes the same mistake. This can happen when the LLM’s context window is limited or simply not “paying attention” to your feedback.

Here are a few things you can try:

  • Provide more context: Give the LLM more information about the error and how to fix it.
  • Provide reminders: Remind the LLM of the history of the fixes already attempted.
  • Simplify your code: If it is too complex, the LLM might need help understanding it. Try breaking it down into smaller, more manageable chunks.
  • Fix it manually: Sometimes, it’s just faster and easier to fix the error yourself.

Remember, LLMs are potent tools, but they’re not infallible. By understanding their quirks and limitations, you can learn to work with them effectively and avoid getting frustrated when things don’t go according to plan.

Level Up Your Code: Strategies for LLM-Assisted Coding

Now that we’ve tackled some common LLM hiccups, let’s discuss how to elevate your code quality and make the most of these powerful tools. Think of it as going from LLM apprentice to LLM master!

Incremental Prompting: Baby Steps for Better Results

Imagine trying to explain a complex coding project all in one go. It’d be overwhelming. LLMs feel the same way.

Instead of throwing a massive, convoluted prompt at them, break your task into smaller, more manageable chunks. This is called incremental prompting, and it can work wonders for improving the quality and accuracy of LLM-generated code.

Here’s how it works:

  1. Start with the big picture: Give the LLM a high-level overview of your goal.
  2. Break it down: Divide the task into smaller steps or subtasks.
  3. Prompt for each step: Give the LLM a prompt based on previous responses.
  4. Iterate and refine: Review the LLM’s output at each step, provide feedback, and refine your prompts as needed.

By taking this step-by-step approach, you guide the LLM through the coding process, ensuring it stays on track and produces code that aligns with your vision.

Keeping LLMs in the Loop: Context is King

LLMs have a short-term memory problem. If you’re working on a large project, they might need to remember what they generated a few turns ago, leading to inconsistencies or errors.

To avoid this, keep your LLM updated with the latest version of your code. You can do this by:

  • Pasting the entire codebase into the prompt gives the LLM the full context to generate relevant and accurate code.
  • Using a code editor with LLM integration: These editors often keep track of your code changes and automatically provide the LLM with the latest context.

Keeping the LLM in the loop ensures it always works with the most up-to-date information, leading to better code quality and fewer headaches.

Know When to Go Manual: LLMs Aren’t Always the Answer

As impressive as LLMs are, they’re not a magic bullet for all your coding woes. Sometimes, it’s faster and more efficient to roll up your sleeves and write the code yourself.

Here are a few scenarios where you might want to take the reins:

  • Complex logic: If the code requires intricate algorithms or complex decision-making, the LLM might need help generating something correct and efficient.
  • Domain-specific knowledge: If the task requires specialized expertise that the LLM might not have been trained on, you’ll likely get better results by relying on your expertise.
  • Time constraints: If you’re under a tight deadline, you might not have the luxury of iterating with the LLM until it gets everything right. Sometimes, it’s just faster to code some of it yourself.

Remember, LLMs are tools to augment your coding skills, not replace them. By knowing when to step in and take control, you can maintain a productive workflow and ensure the quality of your code. With these strategies in your arsenal, you’re well-equipped to harness the full potential of LLMs for your coding projects.

The Dynamic Duo: Human Expertise + LLM Power = Productivity Boost

Let’s talk about the real magic: combining your human coding brilliance with the incredible capabilities of LLMs. Think of it as Batman and Robin, Sherlock and Watson, peanut butter and jelly — two forces working together to achieve greatness!

LLMs & Software Engineering: A Match Made in Heaven

LLMs aren’t here to replace software engineers but to make our lives easier and more productive. Think of them as your trusty coding sidekicks, ready to assist with a wide range of tasks:

  • Generating boilerplate code: Are you tired of repeatedly writing the same repetitive code? Let the LLM handle it!
  • Brainstorming solutions: Stuck on a problem? Ask the LLM for ideas or alternative approaches.
  • Refactoring and optimizing code: Need to clean up your code or make it more efficient? The LLM can suggest improvements or even refactor it for you.
  • Writing documentation and comments: Documenting code can be tedious. Let the LLM generate clear and concise explanations.
  • Learning new languages and frameworks: Exploring a new technology? The LLM can provide examples and tutorials and even answer your questions.

Integrating LLMs into your workflow frees up your mental bandwidth for more creative and strategic tasks, such as designing architecture, solving complex problems, and building excellent products.

Best Practices for Coding with LLMs: Your Productivity Playbook

Developing a productive and efficient workflow is essential to harness the power of LLMs. Here are some actionable tips to keep in mind:

  • Use LLMs for first drafts and boilerplate code: Let the LLM handle the tedious parts so you can focus on the big picture.
  • Refine code manually or with LLM assistance: Don’t just blindly accept the LLM’s output. Review it carefully, test it thoroughly, and make any necessary adjustments. You can even ask the LLM for suggestions on improving the code further.
  • Iterate with LLMs for feedback: If you need clarification on a particular approach or implementation, ask the LLM for its opinion. It can provide valuable insights and help you make informed decisions.
  • Be ready to step in: Be bold and take the reins, and write the code yourself regarding complex logic or domain-specific knowledge. Remember, you’re the master of your code!

By following these best practices, you can strike the perfect balance between human expertise and LLM assistance, leading to a coding workflow that’s both productive and enjoyable.

Breaking the Output Barrier: Handling LLM Limitations

Even the most potent LLMs have their limits. Sometimes, they’ll hit a wall and abruptly stop generating code, leaving you in suspense. It’s like your favorite TV show ending on a cliffhanger — frustrating!

This section will explore some strategies for dealing with these output limitations and ensuring a smooth coding experience, even when LLMs reach their breaking point.

Handling Output Limits: When LLMs Hit the Wall

LLMs typically have a maximum token limit for their responses. If your generated code exceeds this limit, the LLM will cut it off mid-sentence, leaving you with an incomplete or unusable code.

But don’t despair! There are ways to overcome this limitation:

  • Break down your prompts: Instead of asking the LLM to generate a massive chunk of code simultaneously, break it down into smaller, more manageable pieces. This will help you stay within the token limit and avoid those frustrating cutoffs.
  • Use continuation prompts: If the LLM stops generating code mid-stream, you can use a continuation prompt to pick up where it left off. Start your following prompt with something like “Continue generating the code,” “Complete the previous code block, “ or “Continue.”
  • Experiment with different LLMs: Some LLMs have higher token limits than others. If you’re consistently hitting the limit with one LLM, try switching to another one that can handle more significant outputs.

Remember, LLM output limitations are another challenge to overcome on your coding journey. By using the techniques we’ve discussed, you can ensure that your LLM-assisted coding experience is smooth, productive, and free of frustrating interruptions.

Actionable Tips: Your LLM Coding Cheat Sheet

Ready to put your newfound LLM coding skills into practice? Here’s a quick recap of the most essential tips to keep in mind:

  • Experiment with Role-Based Prompts: Be bold, get creative, and assign roles to your LLM. Want to code like a seasoned Python pro? Tell it to “Act as a senior Python developer…” Need help with React? Ask it to “Imagine you are a frontend developer specializing in React.js.” The more specific you are, the better the results.
  • Break it Down: Don’t overwhelm your LLM with massive, complex prompts. Instead, break your tasks into smaller, more manageable chunks and use incremental prompting to guide the LLM step-by-step.
  • Keep LLMs Updated: LLMs have short attention spans. Regularly feed them your latest code so they stay in context and generate relevant responses. This should happen automatically if you use a LLM integration code editor.
  • Be the Master of Your Code: LLMs are excellent tools but not infallible. Know when to step in and take control, especially when dealing with complex logic or domain-specific knowledge. Remember, you’re the one calling the shots!
  • Always Verify: LLMs can sometimes introduce vulnerabilities or insecure coding practices into their output. Always double-check LLM-generated code against trusted, secure coding standards and best practices.
  • Embrace LLM Integration in Your IDE: Supercharge your coding workflow by integrating LLMs directly into your favorite development environment. Popular plugins and tools like GitHub Copilot, CodeGPT, or Tabnine can provide real-time code suggestions and explanations and even generate entire code blocks, all within your IDE. This seamless integration helps you stay in the flow and leverage the power of LLMs without switching between applications.

By following these tips and experimenting with different techniques, you’ll be well on your way to becoming an LLM coding ninja. So go forth and code with confidence!

Conclusion

So, there you have it! We’ve journeyed through the exciting world of coding with LLMs, explored their strengths and quirks, and armed you with a toolbox of strategies to make the most of them.

Remember, LLMs are like any tool — they’re most effective when used wisely. They’re not here to replace you but to augment your skills and boost your productivity. Think of them as your coding sidekicks, ready to lend a hand with everything from generating boilerplate code to brainstorming solutions to complex problems.

By understanding their limitations, embracing their strengths, and integrating them thoughtfully into your workflow, you can unlock new levels of creativity and efficiency in your coding projects.

And the best part? The world of LLMs is constantly evolving. New models, features, and techniques are emerging all the time. So, stay curious, keep experimenting, and never stop learning.

Check out my reading list of other Google Gemini articles.

This post was created with the help of AI writing tools, carefully reviewed, and polished by the human author.

--

--