Software Engineer

Code Refactoring at Scale β€” Agent Migrated 200 Files to New Pattern

200 files migrated in 4 hours, zero regressionsEngineering & DevOps4 min read

Key Takeaway

Our coding agent migrated 200 Django files from function-based views to class-based views in 4 hours with zero regressions β€” a task that would take a developer 2-3 weeks of mind-numbing work.

The Problem

Technical debt has a tipping point. Ours was 200 function-based views in a Django codebase that had outgrown them.

Function-based views are fine when you have 20 endpoints. At 200, you're drowning in repeated authentication checks, permission decorators stacked five deep, and serialization logic copy-pasted across files. Every new endpoint meant copying an existing one and praying you updated all the right parts.

The decision to migrate to class-based views (using Django REST Framework's APIView and ViewSet patterns) was easy. The execution was the problem. 200 files. Each one different enough that find-and-replace wouldn't cut it. Each one with its own URL configuration, its own test coverage, its own quirks.

No developer wants this assignment. It's not intellectually challenging β€” it's just tedious and error-prone.

The Solution

Our coding agent (running via ACP β€” Agent Communication Protocol) processed files in batches of 20, rewrote each view, updated corresponding URL configs, ran the test suite after every batch, and submitted the work for Nico's code review.

The Process

Step 1: Pattern Analysis

The agent first scanned all 200 files to identify common patterns:

pythonShow code
# Pattern 1: Simple CRUD (120 files)
@api_view(['GET', 'POST'])
@permission_classes([IsAuthenticated])
def job_list(request):
    if request.method == 'GET':
        jobs = Job.objects.filter(owner=request.user)
        serializer = JobSerializer(jobs, many=True)
        return Response(serializer.data)
    elif request.method == 'POST':
        serializer = JobSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save(owner=request.user)
        return Response(serializer.data, status=201)

# Pattern 2: Custom actions (50 files)
# Pattern 3: File upload handlers (18 files)
# Pattern 4: Webhook receivers (12 files)

Step 2: Batch Migration

For each file, the agent performed:

pythonShow code
# AFTER: Class-based view β€” DRY, consistent, extensible
class JobViewSet(viewsets.ModelViewSet):
    serializer_class = JobSerializer
    permission_classes = [IsAuthenticated]

    def get_queryset(self):
        return Job.objects.filter(owner=self.request.user)

    def perform_create(self, serializer):
        serializer.save(owner=self.request.user)

URL config updated simultaneously:

pythonShow code
# BEFORE
urlpatterns = [
    path('jobs/', job_list, name='job-list'),
    path('jobs/<int:pk>/', job_detail, name='job-detail'),
]

# AFTER
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register('jobs', JobViewSet, basename='job')
urlpatterns = router.urls

Step 3: Test Validation Per Batch

After every batch of 20 files:

bashShow code
# Run full test suite β€” not just tests for changed files
python manage.py test --parallel --verbosity=2

# Check for import errors
python -c "from django.urls import reverse; print('URL resolution OK')"

# Verify no endpoints disappeared
python manage.py show_urls | wc -l  # Must match pre-migration count

Zero regressions across all 10 batches.

Step 4: Code Review

Nico (our code review agent) flagged 4 edge cases:

  1. A webhook view that needed @csrf_exempt β€” the CBV equivalent required explicit handling
  2. A file upload view where MultiPartParser wasn't set as the parser class
  3. Two views with custom throttling that needed throttle_classes on the new CBV
  4. A view that relied on request.query_params differently than the CBV serializer expected

The agent fixed all 4 in a follow-up commit within 15 minutes.

The Results

MetricManual MigrationAgent Migration
Time2-3 weeks4 hours
Files processed200200
Regressions introducedUnknown (fear)0 (verified per batch)
Code review issuesN/A4 (fixed in 15 min)
Lines of code reducedN/A-3,400 (DRY patterns)
Developer morale costHighNone

Try It Yourself

The secret is batching. Don't try to migrate everything in one commit. Process 15-25 files, run the full test suite, verify, commit, move on. The agent doesn't get bored, doesn't lose context between files, and doesn't "just quickly fix this one test to make it pass." It either passes or it doesn't.


Refactoring at scale isn't a weekend project. It's an agent's Tuesday morning.

DjangoRefactoringAI AgentsCode MigrationTechnical Debt

Want results like these?

Start free with your own AI team. No credit card required.

Code Refactoring at Scale β€” Agent Migrated 200 Files to New Pattern β€” Mr.Chief