All posts

3 min read Nathan Broadbent

Refactoring a Huge Go File in Under 5 Minutes with AI and ast-grep

An illustrated coding assistant examines code panels and a syntax tree.

Large monolithic files are a common problem in software projects, especially when AI agents are involved. These files are hard to navigate, difficult to review in pull requests, and violate the single responsibility principle. We had a monster in one of our greenfield projects: internal/gateway/handlers/admin.go. This file weighed in at 2,371 lines with 44 methods handling everything from user management to audit logging.

Traditional refactoring approaches are painful:

  • Manual copy-paste is error-prone and tedious
  • You need to carefully track imports and dependencies
  • It's easy to miss functions or create duplicates
  • The whole process can take hours

We found a better way using ast-grep: a structural search tool that operates on Abstract Syntax Trees. Here's how Claude Code split that massive file into 9 focused, single-responsibility files in less than 5 minutes.

The Technique: Three-Step Refactoring

The pattern is simple and repeatable:

  1. Extract functions with ast-grep scripts - Use exact function signatures to reliably extract code
  2. Fix imports automatically - Run goimports -w . to add/remove imports
  3. Verify compilation - Run go build to catch any issues

This approach is dramatically faster than manual refactoring and much more reliable.

Real-World Example: Breaking Down admin.go

Step 1: Analyze the File Structure

First, we identified logical groupings by listing all methods:

ast-grep --pattern 'func (h *AdminHandler) $NAME($$$) $$$' internal/gateway/handlers/admin.go \
  --json=compact | jq -r '.[].text' | grep -E '^func \(h \*AdminHandler\)' | \
  sed 's/func (h \*AdminHandler) //' | sed 's/(.*//' | sort

This revealed clear categories like User Management, API Tokens, Sessions, Settings, and Audit Logging.

Step 2: Run Extraction Scripts

Example for user management:

#!/bin/bash
set -euo pipefail
output="internal/gateway/handlers/admin_users.go"
cat > "$output" << 'EOF'
package handlers

import (
	"github.com/gin-gonic/gin"
)

EOF

for func in "ListUsers" "GetUser" "CreateUser" "notifyUserCreated" \
            "DeleteUser" "UpdateUserProfile" "UpdateUserRoles" \
            "LockUser" "UnlockUser"; do
  ast-grep --pattern "func (h *AdminHandler) $func(\$\$\$) \$\$\$" \
    internal/gateway/handlers/admin.go --json=compact | \
    jq -er 'if length == 1 then .[0].text else error("Expected exactly one method match") end' >> "$output"
  echo -e "\n" >> "$output"
done

Tips:

  • Use exact names for reliability
  • Use $$$ wildcards for params and bodies
  • Keep imports minimal - let goimports handle them

The extraction script copies methods. Once you have checked that every method was extracted exactly once, remove the moved declarations from the original file. Keep the original intact until all extraction scripts have succeeded.

Step 3: Extract the Core Struct

We extracted the AdminHandler struct and constructor into a lean core file, then let goimports fix the imports across all files.

Step 4: Verify Everything

Run all scripts, fix imports, and verify with:

goimports -w .
go build ./...
go test ./...

Fix any missing types or constants, review the diff, and run the project’s relevant tests. Compilation catches structural mistakes; it does not prove that behavior is unchanged.

Results

Before: internal/gateway/handlers/admin.go - 2,371 lines

After: Split into 9 focused files:

  • admin.go (38 lines)
  • admin_users.go (413)
  • admin_tokens.go (292)
  • admin_sessions.go (166)
  • admin_settings.go (368)
  • admin_audit.go (411)
  • admin_rack.go (28)
  • admin_roles.go (30)
  • admin_helpers.go (305)

Why It Works

ast-grep is structure-aware and language-agnostic, allowing precise, scriptable refactors. Combined with goimports, you get a fast, reliable workflow:

  1. Extract code structurally
  2. Fix imports automatically
  3. Compile and run tests

One of the key benefits is that an AI doesn't have to read the entire file. It just needs to know the names of the functions that need to be moved.

When an AI agent knows how to perform these steps, this refactoring workflow can take minutes instead of a lengthy, error-prone process. No "Compacting conversation..." required.

References

More posts

Try DocSpring with your own documents

Upload a PDF or a Word document, or create an HTML template, then send a test request. No credit card needed.

Blog posts and product news by email

New articles and product changes, once a month.