DEV Community

Matt Tanner
Matt Tanner

Posted on

How to use Amp's Oracle to plan complex refactoring tasks

Large refactoring projects are risky because they involve understanding complex dependencies, predicting ripple effects, and maintaining backwards compatibility. Of course, you can ask the Amp agent to refactor this to the best of its ability, but bringing in the Oracle to assist can make these large-scale refactors much more effective. The Oracle excels at analyzing complex and interconnected systems and planning refactoring approaches that minimize risk while maximizing the intended benefits.

This guide demonstrates how to utilize Oracle to tackle a common use case, safely refactoring duplicate code patterns, while preserving existing functionality.

Our example: Task completion notification duplication

For this example, let’s assume we have a task management API that supports notifications when tasks are completed. As the system has grown, it has resulted in duplicate notification logic across different channels. There are two functions that send emails and Slack notifications, which share a large amount of code. This leads to maintenance issues, especially as we start to add other channels, such as SMS and other integrations. For those who want to see the exact code for a better understanding of the problem, here's a snippet of the redundant code we will ask the Oracle to assess:

// server.js \- Duplicate notification logic in task completion  
app.patch('/tasks/:id/complete', async (req, res) \=\> {  
  const taskId \= parseInt(req.params.id);  
  const task \= tasks.find(t \=\> t.id \=== taskId);  

  if (\!task) {  
    return res.status(404).json({ error: 'Task not found' });  
  }  

  task.completed \= true;  
  task.completedAt \= new Date().toISOString();  

  // Send notifications \- duplicate logic across different methods  
  const user \= await getUserById(task.userId);  

  if (user.emailNotifications) {  
    await sendEmailNotification(task, user);  
  }  

  if (user.slackNotifications) {  
    await sendSlackNotification(task, user);  
  }  

  res.json(task);  
});

// Duplicate notification methods  
async function sendEmailNotification(task, user) {  
  // Validation  
  if (\!task.title) throw new Error('Task title required');  

  // Logging    
  console.log(\`Sending email notification for completed task: ${task.title}\`);  

  // External API call  
  const response \= await fetch('/api/email/send', {  
    method: 'POST',  
    body: JSON.stringify({  
      to: user.email,  
      subject: \`Task Completed: ${task.title}\`,  
      body: \`Your task "${task.title}" has been completed.\`  
    }),  
    headers: { 'Content-Type': 'application/json' }  
  });  

  // Response handling  
  if (\!response.ok) throw new Error('Email notification failed');  
  const result \= await response.json();  

  // Logging  
  console.log(\`Email notification sent for task ${task.id}\`);  
  return result;  
}

async function sendSlackNotification(task, user) {  
  // Validation (identical)  
  if (\!task.title) throw new Error('Task title required');  

  // Logging (nearly identical)  
  console.log(\`Sending Slack notification for completed task: ${task.title}\`);  

  // External API call (different endpoint, same pattern)  
  const response \= await fetch('/api/slack/message', {  
    method: 'POST',   
    body: JSON.stringify({  
      channel: user.slackId,  
      text: \`✅ Task completed: "${task.title}"\`  
    }),  
    headers: { 'Content-Type': 'application/json' }  
  });  

  // Response handling (identical)  
  if (\!response.ok) throw new Error('Slack notification failed');  
  const result \= await response.json();  

  // Logging (nearly identical)  
  console.log(\`Slack notification sent for task ${task.id}\`);  
  return result;  
}
Enter fullscreen mode Exit fullscreen mode

The refactoring challenge

Within the code, we aim to eliminate duplication while maintaining backward compatibility and avoiding disruptions to existing task completion workflows. To figure out the best path forward, let's ask the Oracle to analyze this code and plan a safe refactoring approach.

Here's our prompt to Amp:

Analyze how the task notification methods are used throughout our codebase. Then I want you to work with the oracle to figure out how we can refactor the duplication between them while keeping changes backwards compatible and maintaining the same notification behavior for completed tasks.

As you can see, we specifically invoke the Oracle in the prompt by stating “...work with the oracle to figure out how we can refactor the duplication…”. This will then kick off the analysis process.

Oracle analysis: Understanding the system

As the process gets executed, first we will see the main agent search through the code to see how the methods are used throughout the codebase.

Oracle refactor plan output

Then, as our prompt suggested, using the data collected Amp will use the Oracle to design the refactoring plan.

Amp main agent assessing code

Once it is done it’s assessment, we can see the output as well as an ask from the system to see if we would like to execute the refactor based on the Oracle’s breakdown.

Amp completes effective refactor with Oracle feedback

Using Amp to implement the refactoring

Assuming we like the Oracle’s output, we can then have Amp implement the Oracle's plan. To do so, we can send in a prompt similar to this one below:

Please implement the refactoring plan the oracle outlined. Proceed with each phase, but make sure that the implementation at each phase works as expected and does not break compatibility.

Then, the agent will go off to work refacotring based on the plan and testing to make sure backwards compatibility is maintained. Of course, with these types of refactors you’ll want to have some other layers of testing involved as well, but you can see from the output from Amp that it was able to successfully refactor the code based on the spec supplied by the Oracle.

Oracle being invoked in Amp

Oracle guidance for different refactoring types

Although the main agent and model (currently Sonnet 4.0) in Amp is great for refactoring, the Oracle provides strategic analysis for various refactoring scenarios that could use a little bit more foresight and care. Situations where input from the Oracle can be helpful include:

  • Legacy modernization: Gradual migration paths that minimize disruption
  • Architecture changes: Impact analysis for major structural shifts
  • Performance optimization: Identifying bottlenecks while preserving behavior
  • Security hardening: Adding security features without breaking functionality
  • Dependency updates: Managing version changes and compatibility issues

Since each of these refactor scenarios requires different approaches, the Oracle can independently make suggestions that are carefully thought out. The Oracle can help to comprehend these more complex changes and does a great job, in addition to the primary model, at giving insights on how to effectively refactor. This means that using the Oracle to refactor things like:

  • Large codebases with complex dependencies
  • Legacy systems with unclear usage patterns
  • Cross-team code that affects multiple services
  • Mission-critical systems requiring high reliability

While the default model is much better than simpler refactoring that likely doesn’t need the extra brainpower and logic, such as:

  • Simple, isolated code cleanup
  • Well-understood systems with comprehensive tests
  • Greenfield projects without legacy constraints

Top comments (0)