Technical debt is usually the first big challenge when you take over a legacy or unfinished project. Our team recently joined a project focused on fixing SonarQube issues. The solution was started by another company but left unfinished, unreleased, and full of technical debt. Our task was to finalise the solution, and one of the customer's requirements was to pass a comprehensive SonarQube quality analysis.
There were more than 5,000 SonarQube issues in the solution. SonarQube's built-in estimate, which uses set metrics for each rule type and severity, said it would take about 470 hours, or almost 12 weeks of developer time, to fix them by hand. With our tight deadlines, manual fixes were not realistic, so we chose to use AI coding agents to speed things up.
We asked Oleksiy Shovkoplyas to share a practical look at how we built an AI-driven workflow to tackle massive technical debt, what worked, and the pitfalls to avoid.
Background & experience:
- Close to 10 years of software development experience with a primary focus on .NET backend development, complemented by frontend and desktop expertise.
- Nearly a decade of prior experience in insurance as an actuary, working extensively with large datasets and risk models.
Where do you start when faced with thousands of code quality issues?
Oleksiy: When dealing with a large solution and thousands of issues, you cannot simply ask an AI to "fix the code." You need a systematic pipeline, and that begins with planning.
Before writing any prompts, you need to understand what you are dealing with. A good starting point is grouping the issues by rule, and then splitting them into four actionable categories:
- Fully automatic: Rules the agent can fix reliably without intervention.
- Semi-automatic: Rules requiring AI remediation but with strict human review and guidance.
- Manual: Complex architectural issues that AI cannot reliably solve.
- Rules to ignore: False positives or rules that aren't relevant to your project.
After categorising the issues, you can prioritise the rules based on issue volume and severity, tackling them systematically, rule by rule.
Because we were short on time and didn't know the codebase well, we skipped planning and started fixing rules one by one, mostly based on the number of issues. After going through this, I strongly suggest starting with planning to keep your workflow organised.
How do you feed thousands of issues to an AI agent effectively?
Oleksiy: Once you know which rules to tackle, you need to feed the specific issues to the AI.
To execute the fixes, we developed a targeted, reusable prompt template where we could simply pass the specific rule name or number. The core function of this template was to take the fetched SonarQube issues and pass them clearly to the AI agent.
Getting the data: You can use a SonarQube MCP server to fetch issues, but current MCP tools do not have strong rule-filtering features. So, we built reusable scripts to pull data straight from the SonarQube API, using the api/issues/search endpoint to filter by rule and component. Turning these JSON responses into plain text files made it easier for the AI to read and helped us track completed work.
Splitting the work into chunks: We had to watch out for context limits. If you ask an agent to fix 200 issues for the same rule all at once, it can overload its context window, leading to hallucinations or truncated code. Instead, we batched the work.
We began by having the agent fix only 5 issues, then manually reviewed the results. If the output looked good, we moved forward. If not, we gave the AI feedback on what to change and asked it to try again until we were happy with the results.
Once the prompt was dialled in, we could proceed in a more automated mode, splitting issues into chunks of 20 to 50. You can even instruct the agent to determine the optimal chunk size itself to manage its context window effectively. For traceability, we instructed the agent to add specific markdown tags in the text results file next to the issues it had successfully resolved.
Which AI tools and models delivered the best results?
Oleksiy: We started with VS Code and GitHub Copilot, but exhausted usage limits in less than two weeks due to the sheer volume of automated refactoring. Switching to Cursor offered significantly higher limits. While both tools are similarly priced, Cursor's higher limits made it the better choice for this intensive task. We didn't notice a significant difference in output quality between the two IDEs themselves.
Choosing the right model was very important. The free GPT-4.1 model in VS Code was not strong enough for complex refactoring. We got much better results with Claude 4.5, 4.6 Sonnet, and Gemini 3.0 and 3.1 Pro.
What are the key best practices for AI-driven refactoring?
Oleksiy: If you’re planning your own AI-driven technical debt cleanup, here are some practical tips to help you out:
- Isolate the work: We made our fixes while feature development continued, so to avoid disrupting the team and minimise merge conflicts, we set up a dedicated main branch just for SonarQube remediation.
- Enforce formatting: AI agents often break code formatting (we saw this a lot with Claude Sonnet in VS Code, even on lines it didn't modify). To fix this, run an automatic formatter, such as dotnet format , across the whole solution before you commit. It also helps to generate an .editorconfig file and format the solution before branching off from the main development branch. This will significantly simplify resolving conflicts when merging your branch back into main.
- Leverage native IDE features: Not everything requires AI. Rules prefixed with external_roslyn:... can usually be fixed natively. Simply open the issue in your IDE, use the built-in quick fix popup, and choose to apply the fix across the entire solution.
- Test before you refactor: As with any refactoring effort, ensure your source code is adequately covered by unit tests before letting an AI modify the logic.
- Expect cascading issues: Sometimes, an agent fixing one rule will inadvertently introduce an issue that triggers another rule. Be prepared to run multiple passes and repeat fixes for rules you thought were already resolved.
AI coding agents won't magically fix your architecture, but if you use them systematically, they can turn months of tedious technical debt remediation into a manageable, weeks-long process.
FAQs
No, and thinking about it that way is misleading. The real goal is to manage technical debt by focusing on the most valuable fixes and supporting innovation. AI can speed up certain remediation tasks. For example, Amazon reported that its Q generative AI assistant cut Java upgrade times from about 50 developer-days to just a few hours. Still, AI has clear limits. It is not yet good at judging whether code is maintainable or scalable, since these qualities depend on many factors. AI is most effective for repetitive, rule-based fixes like naming conventions, removing unused imports, and addressing simple code smells. However, AI models are not perfect. They can produce false positives or negatives during code analysis and often struggle to fully understand a codebase, especially in complex or specialised projects. In short, AI can greatly reduce the labour cost of managing technical debt, but it cannot replace the architectural judgment needed to prevent debt from building up in the first place.
Resolving technical debt needs a structured, ongoing approach instead of a one-time cleanup. Agile practices such as clear definitions of done, automated testing, and continuous integration help keep technical debt under control by prioritising and addressing debt during sprints. The best strategies start by making technical debt visible. Use both automated tools, like static code analysis, and manual checks to identify technical debt.
Prioritising is important because not all technical debt needs to be fixed. Focus first on debt that causes security risks or affects user experience, and accept that some debt can remain while you improve other areas. In practice, it helps to tackle debt bit by bit instead of trying to clear it all at once. Code reviews, automated testing, and regular refactoring should be part of the ongoing development process, not just occasional tasks.
Related insights
The breadth of knowledge and understanding that ELEKS has within its walls allows us to leverage that expertise to make superior deliverables for our customers. When you work with ELEKS, you are working with the top 1% of the aptitude and engineering excellence of the whole country.
Right from the start, we really liked ELEKS’ commitment and engagement. They came to us with their best people to try to understand our context, our business idea, and developed the first prototype with us. They were very professional and very customer oriented. I think, without ELEKS it probably would not have been possible to have such a successful product in such a short period of time.
ELEKS has been involved in the development of a number of our consumer-facing websites and mobile applications that allow our customers to easily track their shipments, get the information they need as well as stay in touch with us. We’ve appreciated the level of ELEKS’ expertise, responsiveness and attention to details.