Przejdź do głównej zawartości

Legacy Code Refactoring - Cursor IDE

Ta treść nie jest jeszcze dostępna w Twoim języku.

You’ve inherited a 5-year-old e-commerce backend written in Node.js with Express. It has no tests, uses callbacks instead of promises, mixes business logic with database queries, and has grown to 15,000 lines across 50+ files. Your task: modernize it without breaking existing functionality that serves 10,000 daily users.

By completing this lesson, you’ll master:

  • Analyzing and understanding legacy codebases
  • Creating comprehensive documentation from undocumented code
  • Safe refactoring strategies with AI assistance
  • Adding tests to untested code
  • Incremental modernization techniques
  • Managing risk during large refactorings
  • Completed Lesson 1 or equivalent experience
  • Understanding of JavaScript evolution (callbacks → promises → async/await)
  • Basic knowledge of testing frameworks
  • Git for version control

Transform a legacy codebase by:

  • Understanding the existing architecture
  • Documenting critical flows
  • Adding test coverage
  • Modernizing to current standards
  • Improving performance
  • Maintaining backward compatibility
  1. Initial Assessment

Open the legacy project in Cursor and start with Ask mode:

@src
"Analyze this codebase and provide:
1. Technology stack and versions
2. Overall architecture pattern
3. Main entry points and critical paths
4. Code quality assessment
5. Potential risks and technical debt"
  1. Dependency Analysis
@package.json @package-lock.json
"Analyze dependencies:
- Which are outdated and need updates?
- Which are deprecated or abandoned?
- Which have known security vulnerabilities?
- What's the upgrade path for critical dependencies?"
  1. Create Architecture Documentation

Switch to Agent mode:

@src
"Create comprehensive architecture documentation:
- System overview diagram (mermaid)
- Component relationships
- Data flow diagrams
- API endpoint mapping
- Database schema documentation
Save to docs/architecture/legacy-analysis.md"
  1. Trace Critical Paths
@src/routes @src/controllers
"Trace the complete flow for:
1. User registration and login
2. Product search and display
3. Order placement
4. Payment processing
Document each flow with sequence diagrams"
  1. Extract Business Rules
@src
"Identify and document all business rules:
- Pricing calculations
- Discount logic
- Inventory management
- User permission rules
- Payment validation
Create a business rules document"
  1. Map Database Interactions
@src/models @src/db
"Analyze database interactions:
- List all tables/collections used
- Identify relationships
- Find N+1 queries
- Document transaction boundaries
- Note missing indexes"
  1. Set Up Testing Framework
"Set up modern testing framework:
- Install Jest and Supertest
- Configure for existing code
- Add test database setup
- Create test utilities
- Add npm scripts for testing"
  1. Generate Integration Tests
@src/routes/products.js
"Generate integration tests for product endpoints:
- Test all CRUD operations
- Include edge cases
- Test error scenarios
- Validate response formats
- Check authentication/authorization"
  1. Create Unit Tests for Business Logic
@src/services @src/utils
"Generate unit tests for business logic:
- Price calculation functions
- Discount application
- Inventory checks
- Data validation
- Utility functions
Aim for 80% coverage of critical paths"
  1. Create Modernization Plan
@docs/architecture/legacy-analysis.md
"Create a detailed modernization plan:
- Priority order for refactoring
- Risk assessment for each module
- Backward compatibility requirements
- Performance improvement opportunities
- Timeline with milestones"
  1. Refactor Callbacks to Async/Await
@src/controllers/products.js
"Refactor this controller:
- Convert callbacks to async/await
- Add proper error handling
- Maintain exact same behavior
- Keep API compatibility
Show before/after comparison"

Example transformation:

// Before
function getProduct(req, res) {
db.query('SELECT * FROM products WHERE id = ?', [req.params.id],
function(err, results) {
if (err) {
res.status(500).send('Error');
return;
}
if (results.length === 0) {
res.status(404).send('Not found');
return;
}
res.json(results[0]);
});
}
// After
async function getProduct(req, res) {
try {
const [product] = await db.query(
'SELECT * FROM products WHERE id = ?',
[req.params.id]
);
if (!product) {
return res.status(404).json({ error: 'Product not found' });
}
res.json(product);
} catch (error) {
logger.error('Error fetching product:', error);
res.status(500).json({ error: 'Internal server error' });
}
}
  1. Extract Business Logic from Controllers
@src/controllers @src/services
"Extract business logic into service layer:
- Create service classes/modules
- Move business rules from controllers
- Add dependency injection
- Improve testability
- Maintain controller interfaces"
  1. Add Query Builder/ORM
"Migrate from raw SQL to query builder:
- Install and configure Knex.js
- Create migration from existing schema
- Convert queries incrementally
- Add connection pooling
- Implement transactions properly"
  1. Optimize Queries
@src/models
"Optimize database queries:
- Fix N+1 query problems
- Add appropriate indexes
- Implement caching layer
- Batch similar queries
- Add query logging/monitoring"
  1. Add Data Validation Layer
"Implement data validation:
- Install Joi or Zod
- Create schemas for all inputs
- Add validation middleware
- Improve error messages
- Document validation rules"

Always follow this pattern:

// 1. Understand current behavior
@old-file.js
"Explain what this code does and all edge cases"
// 2. Add tests for current behavior
"Generate tests that verify current behavior"
// 3. Refactor with confidence
"Refactor this code while maintaining all tested behavior"
// 4. Verify tests still pass
"Run tests and fix any failures"

Migrate module by module:

// Create new version alongside old
@src/controllers/products-old.js
"Create modernized version at products-new.js"
// Add feature flag
"Add feature flag to switch between old and new implementation"
// Test in production
// Gradually migrate traffic
// Remove old version when stable

Generate and maintain documentation:

@src/routes
"Generate OpenAPI/Swagger documentation from existing routes"
@src/models
"Generate database documentation with relationships"
@src/services
"Generate JSDoc comments explaining business logic"

Problem: Refactoring breaks existing functionality

Solution:

  • Always add tests before refactoring
  • Use feature flags for gradual rollout
  • Maintain old endpoints during transition
  • Monitor error rates closely

Take your refactoring further:

  1. Performance Optimization

    • Add Redis caching layer
    • Implement database connection pooling
    • Add request queuing for heavy operations
    • Profile and optimize hot paths
  2. Microservices Migration

    • Extract authentication service
    • Separate order processing
    • Implement API gateway
    • Add service discovery
  3. Modern Infrastructure

    • Containerize with Docker
    • Add Kubernetes manifests
    • Implement health checks
    • Set up monitoring/alerting

Track these metrics:

  • ✅ Test coverage increased from 0% to 80%+
  • ✅ Response times improved by 40%
  • ✅ Error rates remain below 0.1%
  • ✅ All existing APIs maintain compatibility
  • ✅ Technical debt score improved
  • ✅ Development velocity increased
  • ✅ Code complexity metrics improved
  • ✅ Zero downtime during migration

Teams using these techniques report:

  • 70% reduction in bug reports after refactoring
  • 3x faster feature development in refactored code
  • 50% reduction in onboarding time for new developers
  • 90% reduction in production incidents

Before starting any refactoring:

  • Current behavior is documented
  • Tests cover critical paths
  • Backup/rollback plan exists
  • Monitoring is in place
  • Team is aligned on approach
  • Success metrics defined
  • Timeline is realistic
  • Stakeholders are informed
  1. Understand Before Changing: Use AI to quickly grasp legacy code patterns
  2. Test Everything: Never refactor without test coverage
  3. Incremental Progress: Small, safe changes beat big rewrites
  4. Document as You Go: Future you will thank current you
  5. Measure Impact: Data proves the value of refactoring
  • Initial analysis: 2-4 hours
  • Test creation: 4-6 hours
  • Incremental refactoring: 2-3 days per module
  • Full modernization: 2-4 weeks for typical project

ROI: 10x return within 6 months through reduced bugs and faster development

You’ve mastered legacy code transformation. Ready for more challenges?

Automate It

Create scripts to automate common refactoring patterns

Scale It

Apply techniques to larger, more complex systems

Teach It

Share your refactoring patterns with your team

Continue to Bug Hunting Workflow →