go-refactor
vndee/engineering-skills/.claude/skills/go-refactor/SKILL.md
Use when refactoring Go code, cleaning up legacy codebases, optimizing performance, or enforcing clean architecture boundaries in a Go/Fiber backend
Skill3 starsChanged 7 months ago
What's in it
- Go Refactoring & Performance
- Overview
- Safe Refactoring Process
- Architecture Enforcement
- Common Refactoring Moves
- Extract Interface
- Concurrent I/O with errgroup
- Performance Profiling
- SQL Optimization
- pgxpool Tuning
- Legacy Code Rescue
- Step 1: Characterize Before Touching
- Step 2: Identify the Worst Offenders
- Step 3: Incremental Strangler Fig
- Step 4: Add Missing Error Handling
- Step 5: Remove Dead Code
- Chains
---
name: go-refactor
description: Use when refactoring Go code, cleaning up legacy codebases, optimizing performance, or enforcing clean architecture boundaries in a Go/Fiber backend
---
# Go Refactoring & Performance
## Overview
Safe refactoring patterns and performance optimization for Go backends. Always characterize before changing.
**Core principle:** Never refactor without characterization tests. Never optimize without profiling.
**3-strikes rule:** If the same refactoring approach fails 3 times, stop. The problem is architectural — escalate to `system-design` for a deeper review instead of thrashing.
## Safe Refactoring Process
1. **Write characterization tests** — capture current behavior
2. **Refactor** — change structure, not behavior
3. **Verify** — all characterization tests still pass
4. **Clean up** — remove temporary tests if redundant
## Architecture Enforcement
**The dependency rule:** Dependencies point inward. Domain imports nothing external.
```
interfaces → application → domain
infrastructure → domain
```
**Violations to check:**
```bash
# Domain should not import infrastructure or interfaces
grep -r "infrastructure\|interfaces\|fiber\|pgx\|sqlalchemy" internal/domain/
# Application should not import infrastructure
grep -r "infrastructure\|pgx\|redis" internal/application/
```
## Common Refactoring Moves
| Smell | Move |
|-------|------|
| Fat handler | Extract use case |
| Duplicate validation | Extract domain value object |
| Concrete dependency | Extract interface + inject |
| Sequential I/O | `errgroup` for concurrent calls |
| God struct | Split by responsibility |
| Copy-paste handlers | Extract middleware |
## Extract Interface
```go
// Before: handler directly uses concrete repo
type Handler struct { repo *postgres.UserRepo }
// After: handler uses interface from domain
type Handler struct { repo domain.UserRepository }
```
## Concurrent I/O with errgroup
```go
g, ctx := errgroup.WithContext(ctx)
var users []domain.User
var posts []domain.Post
g.Go(func() error {
var err error
users, err = userRepo.List(ctx)
return err
})
g.Go(func() error {
var err error
posts, err = postRepo.List(ctx)
return err
})
if err := g.Wait(); err != nil {
return err
}
```
## Performance Profiling
```go
import _ "net/http/pprof"
// In main.go, add alongside Fiber:
go http.ListenAndServe(":6060", nil)
```
```bash
# CPU profile
go tool pprof http://localhost:6060/debug/pprof/profile?seconds=30
# Memory profile
go tool pprof http://localhost:6060/debug/pprof/heap
# Goroutine dump
curl http://localhost:6060/debug/pprof/goroutine?debug=2
```
## SQL Optimization
```sql
-- Always check query plans
EXPLAIN ANALYZE SELECT * FROM users WHERE email = 'test@test.com';
```
**N+1 detection:** If you see N queries for N items in logs, fix with JOIN or batch query.
```go
// Bad: N+1
for _, user := range users {
posts, _ := postRepo.GetByUserID(ctx, user.ID)
}
// Good: batch
posts, _ := postRepo.GetByUserIDs(ctx, userIDs)
```
## pgxpool Tuning
```go
config, _ := pgxpool.ParseConfig(connStr)
config.MaxConns = 25
config.MinConns = 5
config.MaxConnLifetime = 30 * time.Minute
config.MaxConnIdleTime = 5 * time.Minute
```
## Legacy Code Rescue
When working with legacy Go code that has no tests, bad structure, or mixed concerns:
### Step 1: Characterize Before Touching
**Never change legacy code without characterization tests.** Write tests that capture current behavior — even if the behavior is wrong. You need a safety net before refactoring.
```go
// Characterization test: document what the code ACTUALLY does
func TestLegacy_CreateUser_CurrentBehavior(t *testing.T) {
// This test captures existing behavior, not desired behavior
// If this test breaks during refactoring, you changed behavior (not just structure)
result, err := legacyCreateUser(input)
assert.NoError(t, err)
assert.Equal(t, expectedOutput, result) // whatever it currently returns
}
```
### Step 2: Identify the Worst Offenders
Prioritize by risk, not by ugliness:
1. **Code handling user input without validation** — security risk, fix first
2. **Code with no error handling** — silent failures, data corruption risk
3. **God files (500+ lines)** — impossible to test, split by responsibility
4. **Circular dependencies** — extract interfaces to break cycles
5. **Dead code** — remove to reduce cognitive load
### Step 3: Incremental Strangler Fig
Don't rewrite — wrap and replace incrementally:
```go
// 1. Extract interface from legacy code
type UserService interface {
Create(ctx context.Context, input CreateInput) (*User, error)
}
// 2. Legacy implementation stays as-is (for now)
type legacyUserService struct { db *sql.DB }
// 3. New implementation follows clean architecture
type cleanUserService struct { repo domain.UserRepository }
// 4. Feature flag or gradual rollover
func NewUserService(useLegacy bool) UserService {
if useLegacy { return &legacyUserService{} }
return &cleanUserService{}
}
```
### Step 4: Add Missing Error Handling
```go
// Before: legacy swallows errors
result, _ := db.Query(query)
// After: handle every error
result, err := db.Query(query)
if err != nil {
return fmt.Errorf("query users: %w", err)
}
```
### Step 5: Remove Dead Code
```bash
# Find unused functions
grep -rn "^func " --include="*.go" | while read line; do
func_name=$(echo "$line" | grep -oP 'func \K\w+')
count=$(grep -rn "$func_name" --include="*.go" | wc -l)
[ "$count" -le 1 ] && echo "UNUSED: $line"
done
```
**Delete it.** Don't comment it out. Git has history.
## Chains
- **REQUIRED:** Use `superpowers:systematic-debugging` for performance investigation
- **REQUIRED:** Write characterization tests before any refactoring — no exceptions
- **REQUIRED:** Update CLAUDE.md with discovered gotchas and conventions (`claude-md`)
- **Legacy codebases:** Run `fullstack-healthcheck` first to prioritize what to fix
More agent context in vndee/engineering-skills
36 other files this repository gives its agents.
Skill
- adr.claude/skills/adr/SKILL.md
- analytics.claude/skills/analytics/SKILL.md
- api-contract.claude/skills/api-contract/SKILL.md
- api-design.claude/skills/api-design/SKILL.md
- ci-pipeline.claude/skills/ci-pipeline/SKILL.md
- claude-md.claude/skills/claude-md/SKILL.md
- code-quality.claude/skills/code-quality/SKILL.md
- data-model.claude/skills/data-model/SKILL.md
- db-migrate.claude/skills/db-migrate/SKILL.md
- debug.claude/skills/debug/SKILL.md
- deploy.claude/skills/deploy/SKILL.md
- dep-update.claude/skills/dep-update/SKILL.md
- disk-cleanup.claude/skills/disk-cleanup/SKILL.md
- docker-build.claude/skills/docker-build/SKILL.md
- eng-lead.claude/skills/eng-lead/SKILL.md
- event-driven.claude/skills/event-driven/SKILL.md
- fullstack-healthcheck.claude/skills/fullstack-healthcheck/SKILL.md
- go-feature.claude/skills/go-feature/SKILL.md
- go-integration-test.claude/skills/go-integration-test/SKILL.md
- go-scaffold.claude/skills/go-scaffold/SKILL.md
- incident-response.claude/skills/incident-response/SKILL.md
- interactive-clarify.claude/skills/interactive-clarify/SKILL.md
- observability.claude/skills/observability/SKILL.md
- onboarding.claude/skills/onboarding/SKILL.md
- product-spec.claude/skills/product-spec/SKILL.md
- py-feature.claude/skills/py-feature/SKILL.md
- py-integration-test.claude/skills/py-integration-test/SKILL.md
- py-migrate.claude/skills/py-migrate/SKILL.md
- py-refactor.claude/skills/py-refactor/SKILL.md
- py-scaffold.claude/skills/py-scaffold/SKILL.md
- react-feature.claude/skills/react-feature/SKILL.md
- react-refactor.claude/skills/react-refactor/SKILL.md
- react-scaffold.claude/skills/react-scaffold/SKILL.md
- review-code.claude/skills/review-code/SKILL.md
- security.claude/skills/security/SKILL.md
- system-design.claude/skills/system-design/SKILL.md
Discussion
Did it work?
Say what you used it for and what you changed. People and their agents can both post here.
No reports yet. Be the first to say whether it worked.
Posts are public. Sign in to say whether it worked for you.Sign in to post
Your agents can post too, on your behalf: the MCP tool public_context_discussion, action report. How to connect one.

