Try free
7 min read Guide 535 of 877

Managing Legacy Code in Active Projects

Legacy code requires careful handling to avoid breaking existing functionality while enabling new development. GitScrum helps teams track legacy-related work separately, plan incremental improvements, and maintain clear visibility into the balance between maintenance burden and feature development.

Legacy Code Strategies

StrategyWhen to UseEffort
Add tests onlyHigh-risk, frequently changedLow
Extract and testModule worth preservingMedium
Wrap and replaceStrangler Fig patternMedium-High
Full rewriteObsolete, unmaintainableHigh

Working with Legacy Code

LEGACY CODE IMPROVEMENT FRAMEWORK

1. ASSESS THE LEGACY CODE
┌─────────────────────────────────────────────────┐
│  For each legacy component, evaluate:           │
│                                                 │
│  Change Frequency:                              │
│  ├── High: Modified monthly      → Priority     │
│  ├── Medium: Modified quarterly  → Plan ahead   │
│  └── Low: Rarely touched         → Leave alone  │
│                                                 │
│  Bug Rate:                                      │
│  ├── High: Frequent bugs         → Fix urgently │
│  ├── Medium: Occasional bugs     → Improve      │
│  └── Low: Stable                 → Maintain     │
│                                                 │
│  Test Coverage:                                 │
│  ├── None: No tests              → Add tests    │
│  ├── Low: < 40%                  → Improve      │
│  └── Good: > 70%                 → Maintain     │
└─────────────────────────────────────────────────┘

2. CATEGORIZE APPROACH
┌─────────────────────────────────────────────────┐
│                                                 │
│       High Change Frequency                     │
│              │                                  │
│   ┌──────────┼──────────┐                       │
│   │  WRAP    │ EXTRACT  │                       │
│   │  AND     │   AND    │                       │
│   │ REPLACE  │  TEST    │                       │
│   │          │          │                       │
│   ├──────────┼──────────┤                       │
│   │  DEFER   │  ADD     │                       │
│   │  (costs  │  TESTS   │                       │
│   │  exceed  │  ONLY    │                       │
│   │  benefit)│          │                       │
│   └──────────┴──────────┘                       │
│   Low Quality │ High Quality                    │
│                                                 │
└─────────────────────────────────────────────────┘

The Boy Scout Rule

INCREMENTAL IMPROVEMENT PRACTICE

RULE: Leave the code better than you found it

WHEN TOUCHING LEGACY CODE:
┌─────────────────────────────────────────────────┐
│  Before making your change:                     │
│  1. Add tests for the code you'll modify        │
│  2. Verify tests capture current behavior       │
│                                                 │
│  Make your change:                              │
│  3. Implement the feature/fix                   │
│  4. Ensure tests still pass                     │
│                                                 │
│  Leave it better:                               │
│  5. Small refactor (rename, extract method)     │
│  6. Add any missing documentation               │
│  7. Improve test coverage slightly              │
│                                                 │
│  Constraint: Improvement adds ≤30% to task time │
└─────────────────────────────────────────────────┘

EXAMPLE:
┌─────────────────────────────────────────────────┐
│  Task: Add discount calculation to order        │
│  Time estimate: 3 hours                         │
│                                                 │
│  Improvement time budget: ~1 hour               │
│                                                 │
│  Improvements made:                             │
│  ├── Added 3 tests for existing calculateTotal │
│  ├── Renamed confusing variable names           │
│  ├── Extracted duplicate logic to helper        │
│  └── Added JSDoc for public methods             │
│                                                 │
│  Result: Feature works + code slightly better   │
└─────────────────────────────────────────────────┘

Strangler Fig Pattern

GRADUAL REPLACEMENT STRATEGY

STRANGLER FIG APPROACH:
┌─────────────────────────────────────────────────┐
│  New features use new code                      │
│  Old features gradually migrate                 │
│  Legacy shrinks over time                       │
└─────────────────────────────────────────────────┘

IMPLEMENTATION:
┌─────────────────────────────────────────────────┐
│                                                 │
│  PHASE 1: Create wrapper                        │
│  ┌────────────────────────────────────────────┐ │
│  │  Consumers → Facade → Legacy Code          │ │
│  └────────────────────────────────────────────┘ │
│                                                 │
│  PHASE 2: New implementation behind facade      │
│  ┌────────────────────────────────────────────┐ │
│  │                  ┌→ New Code (new features)│ │
│  │  Consumers → Facade                        │ │
│  │                  └→ Legacy (existing)      │ │
│  └────────────────────────────────────────────┘ │
│                                                 │
│  PHASE 3: Migrate features to new code          │
│  ┌────────────────────────────────────────────┐ │
│  │                  ┌→ New Code (80%)         │ │
│  │  Consumers → Facade                        │ │
│  │                  └→ Legacy (20%)           │ │
│  └────────────────────────────────────────────┘ │
│                                                 │
│  PHASE 4: Remove legacy                         │
│  ┌────────────────────────────────────────────┐ │
│  │  Consumers → Facade → New Code (100%)      │ │
│  └────────────────────────────────────────────┘ │
│                                                 │
└─────────────────────────────────────────────────┘

Legacy Backlog Management

LEGACY IMPROVEMENT TRACKING

BACKLOG STRUCTURE:
┌─────────────────────────────────────────────────┐
│  Project: Legacy Improvements                   │
│                                                 │
│  Labels:                                        │
│  ├── [legacy-testing] - Add test coverage       │
│  ├── [legacy-refactor] - Code improvements      │
│  ├── [legacy-replace] - Module replacement      │
│  └── [legacy-debt] - Technical debt items       │
│                                                 │
│  Capacity: 15% of team time per sprint          │
│                                                 │
│  Prioritization:                                │
│  1. Modules being actively modified             │
│  2. High bug rate areas                         │
│  3. Performance bottlenecks                     │
│  4. Security concerns                           │
│  5. Developer frustration areas                 │
└─────────────────────────────────────────────────┘

TASK TEMPLATE:
┌─────────────────────────────────────────────────┐
│  Title: Add test coverage to PaymentService     │
│  Labels: [legacy-testing] [payments]            │
│                                                 │
│  Current State:                                 │
│  Test coverage: 12%                             │
│  Bug rate: 3 bugs/month                         │
│  Change frequency: High                         │
│                                                 │
│  Goal:                                          │
│  Add tests for core payment flows               │
│  Target coverage: 60%                           │
│                                                 │
│  Approach:                                      │
│  1. List critical paths to test                 │
│  2. Create test fixtures                        │
│  3. Write tests for happy path                  │
│  4. Add edge case tests                         │
│                                                 │
│  Acceptance:                                    │
│  ☐ Coverage > 60% for PaymentService            │
│  ☐ All existing tests still pass                │
│  ☐ No behavior changes                          │
└─────────────────────────────────────────────────┘

Metrics Dashboard

LEGACY IMPROVEMENT METRICS

CODE QUALITY TRENDS:
┌─────────────────────────────────────────────────┐
│  Module: PaymentService                         │
│                                                 │
│  Test Coverage:                                 │
│  Jan: 12% → Feb: 35% → Mar: 58%  ↗ Improving   │
│                                                 │
│  Bug Rate (per month):                          │
│  Jan: 5 → Feb: 3 → Mar: 1        ↘ Improving   │
│                                                 │
│  Change Velocity (time per change):             │
│  Jan: 4h → Feb: 3h → Mar: 2h     ↘ Improving   │
└─────────────────────────────────────────────────┘

OVERALL LEGACY STATUS:
┌─────────────────────────────────────────────────┐
│  Total legacy modules: 45                       │
│  ├── Critical (needs attention): 8              │
│  ├── Improving (work in progress): 12           │
│  ├── Stable (acceptable state): 20              │
│  └── Modern (fully updated): 5                  │
│                                                 │
│  Trend: -3 critical modules this quarter        │
└─────────────────────────────────────────────────┘

Best Practices

  1. Test before changing legacy code
  2. Small, incremental improvements with each touch
  3. Dedicated capacity for legacy work (10-20%)
  4. Track metrics to show improvement
  5. Strangler pattern for large replacements
  6. Document tribal knowledge when discovered
  7. Celebrate progress even if slow
  8. Don't rewrite unless truly necessary

Anti-Patterns

✗ Changing legacy without tests
✗ Big bang rewrite attempts
✗ No time allocated for improvements
✗ Mixing feature + major refactor in one PR
✗ Only fixing when broken
✗ No metrics on legacy health