sf-agent-framework
Version:
AI Agent Orchestration Framework for Salesforce Development - Two-phase architecture with 70% context reduction
804 lines (635 loc) • 20.7 kB
Markdown
# Recommend Refactoring Task
---
task: recommend-refactoring
agent: sf-architect
priority: high
estimated_time: 4-6 hours
requires_tools:
- sfdx
- pmd
- ast-parser
depends_on:
- identify-technical-debt
---
# Task Overview
Provide specific, actionable refactoring recommendations with code examples, patterns, and implementation strategies. Focus on high-impact improvements that reduce complexity, improve maintainability, and enhance performance.
# Pre-requisites
- [ ] Technical debt analysis completed
- [ ] Target components identified
- [ ] Current metrics baseline established
- [ ] Test coverage verified
- [ ] Backup of current code
# Refactoring Categories
## 1. Code Structure Refactoring
- Extract Method
- Extract Class
- Move Method
- Inline Method
- Replace Temp with Query
- Split Loop
- Replace Conditional with Polymorphism
## 2. Data Structure Refactoring
- Replace Array with Object
- Encapsulate Collection
- Replace Type Code with Class
- Replace Data Value with Object
## 3. Conditional Expression Refactoring
- Decompose Conditional
- Consolidate Conditional Expression
- Replace Nested Conditional with Guard Clauses
- Remove Control Flag
## 4. Method Call Refactoring
- Rename Method
- Add Parameter
- Remove Parameter
- Preserve Whole Object
- Replace Parameter with Method
## 5. Object-Oriented Refactoring
- Move Field
- Extract Interface
- Form Template Method
- Replace Inheritance with Delegation
- Replace Delegation with Inheritance
# Instructions
## Phase 1: Identify Refactoring Candidates
### 1.1 Complexity-Based Candidates
```javascript
class RefactoringCandidateFinder {
findHighComplexityMethods() {
return [
{
class: 'OrderProcessor',
method: 'processOrder',
cyclomaticComplexity: 25,
linesOfCode: 250,
recommendation: 'Extract Method',
priority: 'CRITICAL',
},
{
class: 'AccountManager',
method: 'calculateDiscount',
cyclomaticComplexity: 18,
linesOfCode: 150,
recommendation: 'Replace Conditional with Polymorphism',
priority: 'HIGH',
},
];
}
}
```
### 1.2 Duplication-Based Candidates
```
Duplicate Code Blocks:
1. Validation logic in 8 classes
- Recommendation: Extract to ValidationService
2. Error handling in 15 methods
- Recommendation: Create ErrorHandler utility
3. SOQL query patterns in 10 classes
- Recommendation: Implement Repository pattern
```
### 1.3 Coupling-Based Candidates
```
High Coupling Classes:
1. InvoiceGenerator (15 dependencies)
- Recommendation: Apply Dependency Injection
2. ReportBuilder (12 dependencies)
- Recommendation: Use Builder pattern
3. NotificationService (10 dependencies)
- Recommendation: Implement Observer pattern
```
## Phase 2: Specific Refactoring Recommendations
### 2.1 Extract Method Refactoring
#### Before:
```apex
public class OrderProcessor {
public void processOrder(Order__c order) {
// 250 lines of code doing multiple things
// Validate order
if (order.Status__c == null) {
throw new OrderException('Status required');
}
if (order.Items__r.isEmpty()) {
throw new OrderException('Items required');
}
// ... 20 more validation checks
// Calculate pricing
Decimal subtotal = 0;
for (OrderItem__c item : order.Items__r) {
Decimal price = item.Quantity__c * item.UnitPrice__c;
if (item.Discount__c != null) {
price = price * (1 - item.Discount__c / 100);
}
subtotal += price;
}
// ... 30 more lines of pricing logic
// Apply taxes
Decimal taxRate = 0;
if (order.ShippingState__c == 'CA') {
taxRate = 0.0725;
} else if (order.ShippingState__c == 'NY') {
taxRate = 0.08;
}
// ... 15 more state conditions
// Send notifications
// ... 40 lines of notification logic
}
}
```
#### After:
```apex
public class OrderProcessor {
private OrderValidator validator = new OrderValidator();
private PricingCalculator pricingCalc = new PricingCalculator();
private TaxCalculator taxCalc = new TaxCalculator();
private NotificationService notifier = new NotificationService();
public void processOrder(Order__c order) {
validator.validate(order);
Decimal subtotal = pricingCalc.calculateSubtotal(order);
Decimal tax = taxCalc.calculateTax(order, subtotal);
Decimal total = subtotal + tax;
order.Subtotal__c = subtotal;
order.Tax__c = tax;
order.Total__c = total;
update order;
notifier.sendOrderConfirmation(order);
}
}
public class OrderValidator {
public void validate(Order__c order) {
validateRequired(order);
validateBusinessRules(order);
}
private void validateRequired(Order__c order) {
if (order.Status__c == null) {
throw new OrderException('Status required');
}
if (order.Items__r.isEmpty()) {
throw new OrderException('Items required');
}
}
private void validateBusinessRules(Order__c order) {
// Business rule validations
}
}
public class PricingCalculator {
public Decimal calculateSubtotal(Order__c order) {
Decimal subtotal = 0;
for (OrderItem__c item : order.Items__r) {
subtotal += calculateItemPrice(item);
}
return subtotal;
}
private Decimal calculateItemPrice(OrderItem__c item) {
Decimal price = item.Quantity__c * item.UnitPrice__c;
if (item.Discount__c != null) {
price = applyDiscount(price, item.Discount__c);
}
return price;
}
private Decimal applyDiscount(Decimal price, Decimal discountPercent) {
return price * (1 - discountPercent / 100);
}
}
```
### 2.2 Replace Conditional with Polymorphism
#### Before:
```apex
public class DiscountCalculator {
public Decimal calculateDiscount(Account acc) {
Decimal discount = 0;
if (acc.Type == 'Bronze') {
discount = acc.AnnualRevenue__c * 0.05;
if (acc.NumberOfEmployees > 100) {
discount += 500;
}
} else if (acc.Type == 'Silver') {
discount = acc.AnnualRevenue__c * 0.10;
if (acc.NumberOfEmployees > 100) {
discount += 1000;
}
if (acc.Industry == 'Technology') {
discount += 750;
}
} else if (acc.Type == 'Gold') {
discount = acc.AnnualRevenue__c * 0.15;
discount += 2000;
if (acc.Industry == 'Technology') {
discount += 1500;
}
} else if (acc.Type == 'Platinum') {
discount = acc.AnnualRevenue__c * 0.20;
discount += 5000;
}
return discount;
}
}
```
#### After:
```apex
public abstract class DiscountStrategy {
protected Account account;
public DiscountStrategy(Account acc) {
this.account = acc;
}
public abstract Decimal calculate();
protected Decimal getEmployeeBonus() {
return account.NumberOfEmployees > 100 ? getEmployeeBonusAmount() : 0;
}
protected virtual Decimal getEmployeeBonusAmount() {
return 0;
}
protected Decimal getIndustryBonus() {
return account.Industry == 'Technology' ? getIndustryBonusAmount() : 0;
}
protected virtual Decimal getIndustryBonusAmount() {
return 0;
}
}
public class BronzeDiscount extends DiscountStrategy {
public BronzeDiscount(Account acc) { super(acc); }
public override Decimal calculate() {
return account.AnnualRevenue__c * 0.05 + getEmployeeBonus();
}
protected override Decimal getEmployeeBonusAmount() {
return 500;
}
}
public class SilverDiscount extends DiscountStrategy {
public SilverDiscount(Account acc) { super(acc); }
public override Decimal calculate() {
return account.AnnualRevenue__c * 0.10 +
getEmployeeBonus() +
getIndustryBonus();
}
protected override Decimal getEmployeeBonusAmount() {
return 1000;
}
protected override Decimal getIndustryBonusAmount() {
return 750;
}
}
public class GoldDiscount extends DiscountStrategy {
public GoldDiscount(Account acc) { super(acc); }
public override Decimal calculate() {
return account.AnnualRevenue__c * 0.15 +
2000 +
getIndustryBonus();
}
protected override Decimal getIndustryBonusAmount() {
return 1500;
}
}
public class PlatinumDiscount extends DiscountStrategy {
public PlatinumDiscount(Account acc) { super(acc); }
public override Decimal calculate() {
return account.AnnualRevenue__c * 0.20 + 5000;
}
}
public class DiscountCalculator {
private static Map<String, Type> strategies = new Map<String, Type>{
'Bronze' => BronzeDiscount.class,
'Silver' => SilverDiscount.class,
'Gold' => GoldDiscount.class,
'Platinum' => PlatinumDiscount.class
};
public Decimal calculateDiscount(Account acc) {
Type strategyType = strategies.get(acc.Type);
if (strategyType == null) {
return 0;
}
DiscountStrategy strategy = (DiscountStrategy)strategyType.newInstance();
strategy.account = acc;
return strategy.calculate();
}
}
```
### 2.3 Implement Repository Pattern
#### Before:
```apex
public class OrderService {
public List<Order__c> getActiveOrders() {
return [SELECT Id, Name, Status__c, Total__c
FROM Order__c
WHERE Status__c = 'Active'];
}
public List<Order__c> getOrdersByCustomer(Id customerId) {
return [SELECT Id, Name, Status__c, Total__c
FROM Order__c
WHERE Customer__c = :customerId];
}
public Order__c getOrderWithItems(Id orderId) {
return [SELECT Id, Name, Status__c, Total__c,
(SELECT Id, Product__c, Quantity__c FROM Items__r)
FROM Order__c
WHERE Id = :orderId];
}
}
```
#### After:
```apex
public interface IOrderRepository {
List<Order__c> findByStatus(String status);
List<Order__c> findByCustomer(Id customerId);
Order__c findByIdWithItems(Id orderId);
void save(Order__c order);
void save(List<Order__c> orders);
}
public class OrderRepository implements IOrderRepository {
private QueryBuilder queryBuilder = new QueryBuilder();
public List<Order__c> findByStatus(String status) {
return queryBuilder
.selectFields(getBasicFields())
.fromObject('Order__c')
.whereEquals('Status__c', status)
.build()
.execute();
}
public List<Order__c> findByCustomer(Id customerId) {
return queryBuilder
.selectFields(getBasicFields())
.fromObject('Order__c')
.whereEquals('Customer__c', customerId)
.orderBy('CreatedDate', 'DESC')
.build()
.execute();
}
public Order__c findByIdWithItems(Id orderId) {
return queryBuilder
.selectFields(getBasicFields())
.withChildQuery('Items__r', getItemFields())
.fromObject('Order__c')
.whereEquals('Id', orderId)
.build()
.executeSingle();
}
public void save(Order__c order) {
upsert order;
}
public void save(List<Order__c> orders) {
upsert orders;
}
private List<String> getBasicFields() {
return new List<String>{'Id', 'Name', 'Status__c', 'Total__c'};
}
private List<String> getItemFields() {
return new List<String>{'Id', 'Product__c', 'Quantity__c', 'UnitPrice__c'};
}
}
public class OrderService {
private IOrderRepository repository;
public OrderService() {
this.repository = new OrderRepository();
}
public OrderService(IOrderRepository repo) {
this.repository = repo;
}
public List<Order__c> getActiveOrders() {
return repository.findByStatus('Active');
}
public List<Order__c> getOrdersByCustomer(Id customerId) {
return repository.findByCustomer(customerId);
}
public Order__c getOrderWithItems(Id orderId) {
return repository.findByIdWithItems(orderId);
}
}
```
### 2.4 Extract Service Layer
#### Before:
```apex
public class AccountTriggerHandler {
public void afterUpdate(List<Account> newAccounts, Map<Id, Account> oldMap) {
// Business logic mixed with trigger handling
List<Case> casesToCreate = new List<Case>();
List<Task> tasksToCreate = new List<Task>();
for (Account acc : newAccounts) {
Account oldAcc = oldMap.get(acc.Id);
// Revenue threshold logic
if (acc.AnnualRevenue > 1000000 && oldAcc.AnnualRevenue <= 1000000) {
Case c = new Case(
AccountId = acc.Id,
Subject = 'High Value Account',
Priority = 'High'
);
casesToCreate.add(c);
Task t = new Task(
WhatId = acc.Id,
Subject = 'Schedule Executive Meeting',
ActivityDate = Date.today().addDays(7)
);
tasksToCreate.add(t);
}
// Status change logic
if (acc.Status__c == 'Inactive' && oldAcc.Status__c != 'Inactive') {
// 50 lines of deactivation logic
}
}
insert casesToCreate;
insert tasksToCreate;
}
}
```
#### After:
```apex
public class AccountTriggerHandler {
private AccountService service = new AccountService();
public void afterUpdate(List<Account> newAccounts, Map<Id, Account> oldMap) {
service.handleAccountUpdates(newAccounts, oldMap);
}
}
public class AccountService {
private AccountEventHandler eventHandler = new AccountEventHandler();
private AccountValidator validator = new AccountValidator();
public void handleAccountUpdates(List<Account> newAccounts, Map<Id, Account> oldMap) {
List<AccountEvent> events = identifyEvents(newAccounts, oldMap);
for (AccountEvent event : events) {
eventHandler.handle(event);
}
}
private List<AccountEvent> identifyEvents(List<Account> newAccounts, Map<Id, Account> oldMap) {
List<AccountEvent> events = new List<AccountEvent>();
for (Account acc : newAccounts) {
Account oldAcc = oldMap.get(acc.Id);
if (isHighValueTransition(acc, oldAcc)) {
events.add(new HighValueAccountEvent(acc));
}
if (isDeactivation(acc, oldAcc)) {
events.add(new AccountDeactivationEvent(acc));
}
}
return events;
}
private Boolean isHighValueTransition(Account newAcc, Account oldAcc) {
return newAcc.AnnualRevenue > 1000000 && oldAcc.AnnualRevenue <= 1000000;
}
private Boolean isDeactivation(Account newAcc, Account oldAcc) {
return newAcc.Status__c == 'Inactive' && oldAcc.Status__c != 'Inactive';
}
}
public abstract class AccountEvent {
protected Account account;
public AccountEvent(Account acc) {
this.account = acc;
}
public abstract void process();
}
public class HighValueAccountEvent extends AccountEvent {
public HighValueAccountEvent(Account acc) { super(acc); }
public override void process() {
createHighValueCase();
scheduleExecutiveMeeting();
}
private void createHighValueCase() {
insert new Case(
AccountId = account.Id,
Subject = 'High Value Account',
Priority = 'High'
);
}
private void scheduleExecutiveMeeting() {
insert new Task(
WhatId = account.Id,
Subject = 'Schedule Executive Meeting',
ActivityDate = Date.today().addDays(7)
);
}
}
```
## Phase 3: Performance Refactoring
### 3.1 Optimize SOQL Queries
#### Before:
```apex
public class ReportGenerator {
public void generateReport() {
List<Account> accounts = [SELECT Id, Name FROM Account];
for (Account acc : accounts) {
List<Contact> contacts = [SELECT Id, Email FROM Contact WHERE AccountId = :acc.Id];
List<Opportunity> opps = [SELECT Id, Amount FROM Opportunity WHERE AccountId = :acc.Id];
// SOQL in loop - Governor limit risk!
}
}
}
```
#### After:
```apex
public class ReportGenerator {
public void generateReport() {
Map<Id, Account> accountMap = new Map<Id, Account>([
SELECT Id, Name,
(SELECT Id, Email FROM Contacts),
(SELECT Id, Amount FROM Opportunities)
FROM Account
]);
for (Account acc : accountMap.values()) {
processAccount(acc, acc.Contacts, acc.Opportunities);
}
}
private void processAccount(Account acc, List<Contact> contacts, List<Opportunity> opps) {
// Process data
}
}
```
### 3.2 Bulkify Operations
#### Before:
```apex
public class LeadConverter {
public void convertLead(Lead lead) {
Database.LeadConvert lc = new Database.LeadConvert();
lc.setLeadId(lead.Id);
Database.LeadConvertResult lcr = Database.convertLead(lc);
}
}
```
#### After:
```apex
public class LeadConverter {
public void convertLeads(List<Lead> leads) {
List<Database.LeadConvert> converts = new List<Database.LeadConvert>();
for (Lead lead : leads) {
Database.LeadConvert lc = new Database.LeadConvert();
lc.setLeadId(lead.Id);
converts.add(lc);
}
List<Database.LeadConvertResult> results = Database.convertLead(converts);
handleResults(results);
}
private void handleResults(List<Database.LeadConvertResult> results) {
for (Database.LeadConvertResult result : results) {
if (!result.isSuccess()) {
logError(result.getErrors());
}
}
}
}
```
## Phase 4: Generate Refactoring Report
```markdown
# Refactoring Recommendations Report
## Executive Summary
- **Total Refactoring Opportunities**: 45
- **Estimated Effort**: 320 hours
- **Expected Complexity Reduction**: 40%
- **Expected Maintainability Improvement**: 60%
## Priority Matrix
| Priority | Count | Est. Hours | Impact |
| -------- | ----- | ---------- | --------- |
| Critical | 5 | 80 | Very High |
| High | 12 | 120 | High |
| Medium | 18 | 90 | Medium |
| Low | 10 | 30 | Low |
## Top 10 Refactoring Recommendations
1. **Extract OrderProcessor Methods**
- Current Complexity: 25
- Target Complexity: 5
- Effort: 16 hours
- Impact: HIGH
2. **Implement Repository Pattern**
- Affected Classes: 15
- Effort: 24 hours
- Impact: HIGH
3. **Replace Conditional with Polymorphism**
- Instances: 8
- Effort: 20 hours
- Impact: MEDIUM
[... continue for all recommendations]
## Implementation Roadmap
### Sprint 1 (2 weeks)
- Extract critical methods
- Add missing tests
- Fix SOQL in loops
### Sprint 2 (2 weeks)
- Implement repository pattern
- Extract service layer
- Refactor complex conditionals
### Sprint 3 (2 weeks)
- Apply design patterns
- Optimize performance
- Update documentation
## Success Metrics
- Code Coverage: 75% → 90%
- Avg Complexity: 15 → 8
- Duplication: 12% → 3%
- Build Time: -30%
- Bug Rate: -50%
```
## Output Artifacts
1. `docs/analysis/refactoring-recommendations.md` - Main report
2. `docs/analysis/refactoring-examples.md` - Code examples
3. `docs/analysis/refactoring-roadmap.md` - Implementation plan
4. `docs/analysis/refactoring-checklist.md` - Validation checklist
5. `src/refactored/` - Refactored code samples
## Success Criteria
- [ ] All high-complexity code addressed
- [ ] Code examples provided
- [ ] Before/after comparisons shown
- [ ] Effort estimates calculated
- [ ] Impact assessment completed
- [ ] Implementation roadmap created
- [ ] Success metrics defined
## Follow-up Actions
1. Review recommendations with team
2. Prioritize based on business impact
3. Create refactoring backlog
4. Schedule refactoring sprints
5. Set up metrics tracking
6. Document patterns for future use