Find out how to Perform Large Code Refactors in Cursor

-

has historically been a tedious yet vital task. Refactoring is the work of taking some piece of code and cleansing it up, either by higher separation of concerns, the Don’t Repeat Yourself (DRY) principle, or other code hygiene principles.

Code refactors have all the time been vital, but with the discharge of coding agents, we’re seeing higher coding outputs, which inevitably results in more need for code refactoring. I an increasing number of often find myself in situations where some code must be refactored, though I don’t think it is a warning sign, considering the quantity of code I output can also be significantly higher now with the assistance of LLMs.

Luckily, the hassle to refactor code has significantly gone down because the release of LLMs.

In this text, I’ll undergo my high-level approach to performing code refactoring using coding agents like Cursor or Claude Code. I’ll cover my generic approach and thought process, so the model you utilize doesn’t matter.

This infographic covers my high-level approach to refactoring code using LLMs. I first discovered when to refactor, often triggered by detecting a whole lot of anti-patterns, and noticing that implementing code is now slower. I then start planning the refactoring, using Gemini, and the plan mode in Cursor. Moving on, I execute the refactoring, where I prefer the Claude models, and I’m liberal with my whitelisted commands. I then confirm the refactor by asking my coding agent to match against the fundamental branch and performing a secondary AI review with a refreshed context. Image by Gemini.

Why perform code refactoring

It’s best to perform code refactoring at any time when you notice a whole lot of antipatterns in your code, or whenever you notice you (or your coding agent) is spending more time than must be needed on an implementation. Your threshold before performing a refactoring also needs to be lower than it was before the discharge of LLMs, considering refactors are way easier and faster to implement now using coding agents.

It’s because a part of the training set for coding agents is to refactor code, they usually’re especially good at that. In a whole lot of cases, I might even say they’re higher than humans, considering refactoring requires a whole lot of working memory:

  • Remembering all variables
  • Ensuring input/output after the refactor is similar as before the refactor
  • Which files to maneuver, delete, and add

Thus, it is best to perform code refactoring when:

  • You or your coding agent discovers a whole lot of antipatterns in your code
  • Implementations start taking longer than they need to (an indication of bad code)

And it is best to perform code refactorings because:

  • They increase iteration speed
  • They’re relatively low-cost to perform with LLMs

My approach to refactoring code

On this section, I’ll cover my high-level approach to refactoring code. I’ll undergo 4 steps:

  1. Discovering when to refactor
  2. What to contemplate before the refactor
  3. What to contemplate throughout the refactor
  4. What to contemplate after the refactor

This may highlight how you may approach refactoring yourself, in such generic terms that you may replicate the processing yourself on your personal codebase.

1. Discovering when to refactor

Step one is all the time to find when it is best to resolve to refactor your code. There often isn’t a transparent line on when refactoring must be performed or not, and it thus requires some instinct to know when is an excellent time.

Nevertheless, it is best to apply some easy generic principles. Should you see a whole lot of antipatterns within the code, for instance, with:

  • Numerous duplicate code
  • Missing docstrings and performance types
  • Poor separation of concerns

It’s best to consider refactoring.

Also, if you happen to notice your coding agent is spending longer than usual reading through your codebase, trying to grasp it. Or it struggles more often with implementing something, and errors elsewhere pop up. It’s best to also consider refactoring.

Nevertheless, picking up this instinct takes time, and at first, you may try and refactor earlier quite than later (considering that performing a refactor is affordable with LLMs), after which adjust whenever you learn more along the way in which.

2. What to contemplate before the refactor

If you’ve come to this step, you’ve got decided that a certain a part of a code repository must be refactored. Now you have to plan for which scope the refactoring should cover, since it is best to naturally reduce the refactoring scope as much as possible.

Reduce the scope of the refactoring as much as possible

I then start planning, which I do in mostly two ways:

  1. (optional) If I would like to debate generic architectural decision-making or high-level ideas, I start chatting with Gemini within the console. I explain my situation, the trade-offs, the several solutions I’m considering, and all other relevant information. I then have a conversation with Gemini concerning the decision. Notice the word conversation. I’m not simply asking Gemini a matter about methods to solve my problem; I’m discussing with the model what might be the very best approach, and trying to grasp the difficulty as best as possible.
  2. I all the time start off using in either Cursor or Claude Code, where you tell the model what you desire to do, it looks through your code base, and it comes up with a plan for methods to implement an answer into your code base. Sometimes, I copy over my conversation from Gemini (if I did that), and sometimes I simply start my refactoring directly in Cursor.

Planning your approach is super worthwhile, because you grow to be aware of some issues you weren’t aware of before, and might make decisions with as much information as possible. Moreover, you may read through the plan that Cursor makes, and tweak it if need be. Most significantly, though, I like to recommend having a conversation together with your coding agent about methods to approach refactoring it, as opposed to only asking it an easy query and only getting one response.

It’s best to strive to have conversations together with your agents, and never only a single query and response

I like to recommend spending no less than 10-Quarter-hour on this conversation when performing a major refactoring.

After a plan is made, I move on to step 3.

"""
Example plan.md file after using plan mode
On this scenario, the context is refactoring a messy, monolithic `server.js` (Express node app) right into a cleaner MVC (Model-View-Controller) architecture with TypeScript.
"""
***

# Plan: Refactor Monolithic Server to MVC Architecture

## Context
Currently, `src/server.js` comprises all database connections, route definitions, and business logic in a single file. We want to refactor this right into a modular structure using TypeScript, splitting concerns into Controllers, Services, and Routes.

## User Requirements
1.  Convert the project to **TypeScript**.
2.  Extract database logic right into a Singleton/Service.
3.  Separate routes into `src/routes`.
4.  Move business logic to `src/controllers`.

## Proposed File Structure
* `src/app.ts` (Entry point)
* `src/config/database.ts` (DB connection)
* `src/routes/userRoutes.ts` (Route definitions)
* `src/controllers/userController.ts` (Request handling)
* `src/services/userService.ts` (Business logic)

---

## Step-by-Step Plan

### Phase 1: Setup & Configuration
- [ ] Initialize TypeScript configuration (`tsconfig.json`).
- [ ] Install needed `@types` dev dependencies (`node`, `express`).
- [ ] Rename `server.js` to `server.ts` temporarily to resolve immediate linting errors.

### Phase 2: Database Layer
- [ ] Create `src/config/database.ts`.
- [ ] Move the MongoDB connection string and connection logic from `server.ts` to `src/config/database.ts`.
- [ ] Make sure the database connection exports a strong singleton or connection function.

### Phase 3: Service & Controller Extraction
- [ ] Create `src/services/userService.ts`.
    - [ ] Move raw database queries (find, create, update) here.
    - [ ] Define interfaces for User data.
- [ ] Create `src/controllers/userController.ts`.
    - [ ] Implement `getUsers`, `createUser`, and `updateUser` methods.
    - [ ] Import `userService` to handle the logic.
    - [ ] Ensure proper type typing for `Request` and `Response`.

### Phase 4: Routing
- [ ] Create `src/routes/userRoutes.ts`.
    - [ ] Setup `express.Router()`.
    - [ ] Map endpoints (`/users`, `/users/:id`) to the precise Controller methods.

### Phase 5: Entry Point Cleanup
- [ ] Create `src/app.ts`.
    - [ ] Initialize the Express app.
    - [ ] Import and apply middleware (CORS, JSON body parser).
    - [ ] Mount `userRoutes`.
    - [ ] Connect with the database using `src/config/database.ts`.
- [ ] Delete the unique `src/server.js`.

### Phase 6: Verification
- [ ] specific verification step: Start the server using `ts-node src/app.ts` to make sure no runtime errors.
- [ ] specific verification step: Test the `/users` endpoint to make sure data flow is unbroken.

---

### Would you want me to create this file structure for you now, or start specifically with Phase 1?

3. What to contemplate throughout the refactor

Should you’ve come to this step, you’ve already prepared an excellent plan together with your coding agent, and also you’ve began performing the refactor. To make the refactor efficient and to make sure it really works in addition to possible, I keep these items in mind:

  • Be as lenient as you may with permissions. In fact, watch out with destructive commands, but having the agent give you the chance to perform most commands significantly hastens the method
  • Using Claude. My experience is that Claude Sonnet/Opus 4.5 are significantly the very best and fastest coding model on the market
  • Tell the agent to create testing scripts if needed. Sometimes the agents just attempt to debug from the code alone, but often it’s higher to tell it to create a testing script where it may well see the input and output

I then let the Coding agent run until it’s done, which might take anywhere from a minute to twenty minutes. If it’s one among the primary times you’re running code within the repo, you may must allow list some commands, but as mentioned, I attempt to be lenient here, especially once we’re talking about read commands, which might’t cause any damage.

I also allow my agent to create test scripts and run them at will, to not only debug the code from the code, but additionally from seeing input and output.

With this setup, I’m mostly succeeding with the refactor with a maximum of a number of prompts backwards and forwards, and in lots of cases only one prompt.

4. What to contemplate after the refactor

After the refactoring is finished, you have to consider the changes. Sometimes it is best to glance through all of the code thoroughly, though sometimes it’s not needed. Nevertheless, I even have some particular recommendations after a refactor is finished:

  • Ask the model to match input and output before the refactor (point the model to your fundamental or dev branch, whatever branch you branch off of when starting a brand new branch). The model will offer you an outline, and it is best to often be sure that the input and output are the identical before and after. This tip has saved me a whole lot of bugs
  • Run a coding review with a separate agent (start it with a brand new context), which makes it easier to indicate errors your agent didn’t see when refactoring
  • Ask Cursor to offer a thoughtful commit message, and create the PR for you. This each hastens the means of getting the code to production, and it makes your PR’s more descriptive

Particularly, my first point on comparing against the fundamental/dev branch is very important. Having the model compare the input and output with the previous code and the present code has uncovered so many bugs that the model didn’t see during refactoring.

I consider that with even higher coding models, we’ll see fewer and fewer of those mistakes, though for now, I definitely think it’s worthwhile to have the model to a second review of the changes, each through comparing input and output, and likewise by conducting a code review.

Conclusion

In this text, I’ve provided a high-level overview of how I perform code refactors. I first discussed methods to know when a refactor is required, before diving into the specifics of the refactoring approach. I then covered how I exploit plan mode before the refactoring, allow list commands throughout the refactoring, and ask the model to do a second review of the refactored code, with a refreshed context window.

I consider LLM refactoring will grow to be an increasing number of vital as we see higher and better coding output, due to LLM coding agents. I also consider that refactoring with LLMs is super effective, and something everyone should be mindful, especially when coding loads using coding agents.

👉 My free eBook and Webinar:

🚀 10x Your Engineering with LLMs (Free 3-Day Email Course)

📚 Get my free Vision Language Models ebook

💻 My webinar on Vision Language Models

👉 Find me on socials:

💌 Substack

🔗 LinkedIn

🐦 X / Twitter

ASK ANA

What are your thoughts on this topic?
Let us know in the comments below.

0 0 votes
Article Rating
guest
0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments

Share this article

Recent posts

0
Would love your thoughts, please comment.x
()
x