Claude Code Best Practices That Actually Changed How I Write Code
Technology Blogs

Claude Code Best Practices That Actually Changed How I Write Code

Nadeem Khan
Associate Software Engineer

I’ve been using Claude Code for a while now, and I’ll be honest, the first few weeks I was using it wrong. Not wrong in a “your code will break” way, but wrong in a “you’re leaving 70% of the value on the table” way.

Over time, I developed a set of habits that genuinely transformed how I work. Documentation time dropped. Debugging got faster. Code reviews became less painful. And I stopped having those frustrating conversations with Claude where it confidently fixes the wrong thing.

In this post, I’ll walk through what actually works, not the generic tips you’ll find in any AI tool listicle, but the specific practices I’ve built into my daily workflow that I’d miss immediately if I lost them.

The Problem with How Most Developers Use Claude Code

If you’re like most developers, you open Claude Code, type a quick description of what you want, and then spend the next 20 minutes cleaning up code that almost does the right thing. Sound familiar?

The issue isn’t Claude. The issue is context. Claude Code is a powerful reasoning engine that works best when it understands not just what you want, but why you want it, what already exists, and what constraints matter. Without that, you get technically correct code that doesn’t fit your project.

The good news: fixing this is mostly about adopting a few habits. Let’s get into them.

My #1 Habit: The research.md + plan.md System

This is the one trick I’d fight to keep if someone forced me to drop everything else.

Here’s the rule: for every meaningful task, create two files before writing a single line of code.

research.md

This file captures your investigation phase. Before touching code, I spend time understanding the problem space and dump everything relevant into this file:

  • What already exists in the codebase related to this task?
  • What are the edge cases?
  • What packages or patterns are we already using that we should continue using?
  • Are there any gotchas – API limits, deprecation warnings, security constraints?
  • Links to relevant docs or Stack Overflow threads

It doesn’t need to be formal. Mine usually look like messy notes. But they exist, and that matters.

plan.md

Once I’ve researched, I write a plan. This is a step-by-step breakdown of exactly what I’m going to build:

Markdown:

    # Task: Add CSV export to the reports dashboard

    ## Approach
    1. Add export button to ReportsDashboard component
    2. Create useExportCSV hook that handles:
       - Formatting data as CSV string
       - Triggering browser download
    3. Wire button to hook
    4. Add loading state during export
    5. Add error toast if export fails
    ## Files to modify
    - src/components/ReportsDashboard.tsx
    - src/hooks/ (new file: useExportCSV.ts)
    
    ## Not in scope
    - Scheduled exports (separate task)
    - Excel format (not requested)
    
    ## Notes
    - Use existing useToast hook for error messages
    - Match button style to existing Export buttons in SettingsPage

    Why does this matter so much? Two reasons.

    Reason one: it makes Claude dramatically more useful. When I start my Claude Code session, I can paste or reference this plan. Claude knows exactly what we’re building, what we’re not building, and what conventions already exist. The output quality jumps immediately.

    Reason two: it makes code reviews so much easier. When you open a PR, your reviewer doesn’t have to reverse-engineer your thinking from the diff. They can read the plan, understand the approach, and review whether the code matches the intention. I’ve had PRs get merged in 20 minutes that would have taken two rounds of back-and-forth without this context.

    I keep both files in a /tasks or /docs/tasks folder. After the feature ships, they stay there as a record of decisions made. Future-you (or a new teammate) will thank present-you.

    Want to get more out of Claude Code in your development process? Talk to our Team.

    Keep Sessions Separate. Seriously.

    This one sounds almost too simple, but it makes a huge difference: one session per task, and don’t mix concerns.

    Claude Code sessions accumulate context. Early in a session, you’re working with a fresh, focused model. As the conversation grows especially if you’re jumping between different problems the signal-to-noise ratio drops. You start getting suggestions that technically fit what you just said but conflict with something you mentioned 30 messages ago.

    My rules:

    One session for one task. If I’m adding the CSV export feature, that’s the only thing happening in that session. If I notice a bug in a completely different part of the codebase, I note it somewhere (usually a quick comment or a GitHub issue) and deal with it in a new session.

    Start fresh when you change direction. If the task evolves significantly mid-session say, the feature needs a completely different architecture than you initially discussed it’s usually worth starting a new session with the updated plan rather than trying to walk Claude back from its existing assumptions.

    Name your sessions meaningfully. If your Claude Code setup supports naming/labeling sessions, do it. “Task: CSV export – ReportsDashboard” is much easier to navigate back to than an unnamed session from last Tuesday.

    This isn’t just about Claude’s performance it’s about yours. Separate sessions force you to be intentional about task boundaries, which is just good engineering hygiene.

    Terminal Commands That Actually Save Time

    The CLI is where Claude Code gets really powerful. Here are the commands I use constantly:

    Running Claude on a specific file with context

    claude "Refactor this function to use async/await instead of promises" --file src/utils/fetchData.js

    Passing the file directly means Claude sees exactly what you’re working with, not a description of it.

    Asking Claude to explain before touching anything

    claude "Explain what this function does and what could go wrong with it. Don't make any changes yet."

    Getting an explanation first is underrated. It surfaces misunderstandings before they turn into bad code.

    Generating tests for existing code

    claude "Write Jest unit tests for this function, covering happy path and edge cases" --file src/utils/parseCSV.js

    I almost never write tests from scratch anymore. I write the implementation, then ask Claude to generate tests, then review the tests to make sure they’re actually testing the right things.

    Using –context for project-wide awareness

    claude "Add error handling to this API call, consistent with how we handle errors elsewhere in the project" \
      --file src/api/reports.js \
      --context src/api/users.js \
      --context src/api/settings.js

    Passing related files as context means Claude can match your existing patterns instead of inventing new ones. This is huge for consistency.

    Pipe input for quick questions

    cat src/components/ComplexComponent.tsx | claude "Identify potential performance issues in this component"

    Fast and flexible. Great for quick reviews of a file without setting up a full session.

    Asking for a plan before execution

    claude --plan "Add pagination to the users table"

    If your setup supports a –plan flag or similar, use it. Getting Claude to outline its approach before it writes code catches architectural mismatches early.

    Prompt Engineering Habits That Actually Matter

    The quality of your prompts is the multiplier on everything else. Here’s what I’ve learned:

    Give context, not just requirements

    ❌ “Fix the bug in the login form”

    ✅ “The login form is submitting before client-side validation runs. The validation function exists in src/utils/validate.js and returns a boolean. It should run on form submit, block submission if it returns false, and display the existing error state. Here’s the component: [paste or reference file]”

    The second prompt takes an extra two minutes to write and saves you 30 minutes of debugging a “fix” that doesn’t solve the actual problem.

    Specify what you don’t want

    Claude is good at inferring what you want. It’s less good at inferring what you want to avoid without being told. So tell it:

    “Refactor this to be more readable. Don’t change the function signatures, other code depends on them. Don’t add new dependencies.”

    Negative constraints are often more valuable than positive requirements.

    Use examples from your own codebase

    “Write a custom hook for managing form state, following the same pattern as useModal in src/hooks/useModal.ts”

    This is so much more effective than a general description. Claude will match your naming conventions, your TypeScript patterns, your error handling approach. The output feels like your code.

    Ask for explanation alongside code

    “Write this function and add a comment above it explaining the approach and any non-obvious decisions.”

    This slows Claude down slightly but dramatically improves your ability to review the output. If the explanation is wrong, the code is probably wrong too. Catch it in the comment, not in production.

    Code Review Workflows with Claude

    Using Claude Code during code review both reviewing others’ code and preparing your own PRs is something I started doing recently and wish I’d started sooner.

    Before opening a PR

    claude "Review this diff for potential bugs, edge cases, and anything that doesn't match the plan in plan.md"
    --file plan.md
    --diff

    Self-reviewing with Claude before requesting human review catches the embarrassing stuff. Missing null checks, functions that don’t handle empty arrays, inconsistent error handling Claude finds these quickly.

    When reviewing someone else’s PR

    claude "Explain what this code change does and whether the implementation matches what the PR description says it does"
    --file pr-description.md
    --diff

    This helps you review PRs faster without shallow reviews. You understand the change better, you ask more relevant questions, and you catch discrepancies between intention and implementation.

    Asking for a second opinion on your own implementation

    “Here’s how I solved [problem]. Are there downsides to this approach I haven’t considered? Is there a simpler way to achieve the same thing?”

    Getting Claude to critique your own work is uncomfortable but valuable. It’s much better to hear about the downside of your approach from an AI at 2pm than from a reviewer at 5pm.

    Claude Code Terminal vs. the VS Code Extension: What I Actually Use

    Let me give you my honest take.

    The VS Code extension is great for interactive, in-context work. Autocomplete, inline suggestions, quick questions about the code you’re looking at it’s seamless. If you’re deep in a file and want to quickly ask “what does this function return when the array is empty,” the extension wins because it sees exactly what you see.

    The terminal (Claude Code CLI) is better for anything that crosses file boundaries, anything involving a plan or context document, and any workflow that benefits from a structured conversation rather than inline suggestions.

    The distinction I’ve landed on: I use the extension for micro-level work (writing a function, completing a pattern, asking quick questions) and the terminal for macro-level work (planning a feature, reviewing a whole module, generating tests for a set of files, debugging something that spans multiple layers).

    They’re not competitors they’re complementary. But if you haven’t set up the CLI and you’re only using the extension, you’re missing a lot of the power. The CLI’s ability to bring in context files, run structured sessions, and pipe input/output is what enables the more sophisticated workflows I described above.

    One more thing: the terminal is where the automation potential lives. You can script Claude Code commands, include them in Makefiles, wire them into CI pipelines. The extension doesn’t give you that.

    A Real Example: How This Workflow Comes Together

    Let’s say I’m adding a new feature: exporting a PDF report from a dashboard.

    Step 1:

    1. Create tasks/pdf-export/research.md

    2. Spend 30 minutes looking at what already exists which components, which libraries are installed, how similar features work in the codebase

    3. Note everything relevant in the research file

    Step 2:

    1. Write tasks/pdf-export/plan.md specific steps, files to touch, what’s out of scope

    2. Open a new Claude Code terminal session named “pdf-export”

    3. Start the session by pasting the plan: “Here’s what I’m building today. Let’s work through it step by step.”

    4. Work through the plan item by item, keeping the session focused

    Step 3:

    1. Run a quick Claude review of the diff against the plan

    2. Fix anything flagged

    3. Open PR with a link to the plan.md so reviewers have context

    This sounds like more process than it is. The research and planning take maybe an hour on a multi-day feature. But they pay back multiple times over in cleaner sessions, faster reviews, and fewer “wait, why did we do it this way” conversations.

    Common Mistakes and How to Avoid Them

    Giving Claude too much at once. Dumping a 500-line file and saying “make this better” doesn’t work well. Break it into specific, scoped requests.

    Not telling Claude what already exists. Claude will happily invent a new utility function if you don’t tell it one already exists. Always mention relevant existing code.

    Using Claude to avoid thinking. The best results come from knowing what you want and using Claude to execute it faster and more thoroughly not from outsourcing the thinking entirely. The plan.md habit enforces this naturally.

    Trusting output without reading it. Claude produces confident-sounding code that can still be subtly wrong. Always read what it generates. The explanation-alongside-code habit helps here.

    Keeping a bad session alive. If a session has gone sideways Claude is stuck in a wrong assumption, or the conversation is too long and muddled just start fresh. Don’t fight it.

    Conclusion

    The underlying theme of everything I’ve shared is this: Claude Code works best when you treat it as a capable collaborator who needs good context, clear scope, and specific instructions not as a magic box that reads your mind.

    The research.md + plan.md habit gave me structure. The session discipline gave me focus. The terminal commands gave me flexibility. And the prompt habits gave me consistency.

    Start with one of these. The plan.md habit is probably the highest-leverage place to begin if you’re only going to try one thing. Even just writing down what you’re going to build before you start building it separate from Claude entirely makes your sessions dramatically more productive.

    Healthcare tech, SaaS products, internal tools, open source the workflow holds up across contexts. The common denominator is that good engineering requires clear thinking, and these habits force the clear thinking to happen before the coding starts.

    If you try any of this and run into something that doesn’t work the way I’ve described, I’d genuinely like to hear it. These practices are still evolving, and the best improvements have come from hitting friction and figuring out why.

    Nadeem Khan

    Associate Software Engineer

    Nadeem is a front-end developer with 1.5+ years of experience. He has experience in web technologies like React.js, Redux, and UI frameworks. His expertise in building interactive and responsive web applications, creating reusable components, and writing efficient, optimized, and DRY code. He enjoys learning about new technologies.

    Nadeem Khan

    Nadeem Khan

    Associate Software Engineer

    Nadeem is a front-end developer with 1.5+ years of experience. He has experience in web technologies like React.js, Redux, and UI frameworks. His expertise in building interactive and responsive web applications, creating reusable components, and writing efficient, optimized, and DRY code. He enjoys learning about new technologies.

    Share This Blog

    Read More Similar Blogs

    Let’s #Transform Healthcare,# Together.

    Partner with us to design, build, and scale digital solutions that drive better outcomes.

    BOOK A QUICK CONSULTATION

    Have a Healthcare Project in Mind?

    Let’s discuss your goals, workflows, and next steps in a focused consultation call.

    Calendar icon Schedule a Call

    Contact form