# Extract a Shared Helper from Duplicated Code in Go with Atlas (2026)

> Atlas finds duplicated Go code with codebase_search rather than grep, because copies differ in variable names, then swaps each callsite with one apply_patch per file.

To extract a shared helper from duplicated code in Go with Atlas, start with codebase_search rather than grep. Duplication is a semantic problem, not a textual one: the copies usually differ in variable names, so the same retry loop written in internal/api/client.go and internal/worker/queue.go will never match a grep pattern. Atlas asks codebase_search for the behavior, reads each hit to confirm the copies are genuinely equivalent, creates the shared helper with the write tool, and replaces each duplicate with a call using apply_patch, one file per patch. Atlas runs go test with bash after every swap, and finishes by grepping for any surviving copy.

## Key takeaways

- Duplication in Go is semantic, not textual: the copies differ in variable names, so codebase_search finds what grep cannot.
- Read every candidate before collapsing it. A wrapped error in one copy and a swallowed error in another is a behavioral difference, not a style one.
- The write tool shows the full contents of the new Go helper in the permission prompt before the file exists on disk.
- One apply_patch per file keeps each callsite swap independently reviewable and revertible.
- Run go test with bash after every swap, not once at the end, and run gofmt so the diff carries no formatting noise.
- Finish by grepping for the original code fragment: a surviving copy undoes the entire de-duplication.

## Why does grep miss duplicated Go code?

Grep misses duplicated Go code because the copies differ in variable names. The same error-wrapping pattern written as `if err != nil { return fmt.Errorf(...) }` around 3 different variables is textually distinct and semantically identical, which is exactly the case a regex cannot see and codebase_search can.

Duplication in a Go module rarely arrives as an exact copy. A developer copies a retry loop from internal/api/client.go into internal/worker/queue.go, renames resp to r, changes the timeout constant, and adjusts the error message. Grep sees two unrelated blocks. Atlas asks codebase_search for the behavior instead of the text: describe the retry with exponential backoff around an HTTP call, and the semantic index returns the candidate declarations wherever they live. Atlas searches code with hybrid semantic and keyword retrieval fused by reciprocal rank fusion, and indexes by AST declarations using tree-sitter, so the hits come back as whole Go functions rather than arbitrary line windows.

## How do I confirm two Go functions are really duplicates?

Atlas reads each codebase_search hit in full and confirms the Go copies are genuinely equivalent before collapsing them. Two Go functions that look alike can differ in the 1 detail that matters: an error wrapped in one and swallowed in the other, or a defer that only one of them runs.

Collapsing near-duplicates that are not actually duplicates is how a refactor introduces a bug. Atlas reads every candidate before touching anything, and in Go the differences that matter are quiet: one copy checks `if err != nil` and returns a wrapped error, the other logs and continues; one closes the response body with a defer, the other leaks it. Those are not stylistic variations, they are behavioral ones, and the correct outcome may be that two of the four copies collapse and two do not. Atlas states the differences it found so the decision to unify is made with the divergence visible, not assumed away.

## How does Atlas create the shared Go helper?

Atlas creates the new shared Go helper with the write tool, which shows the full diff in the permission prompt before the file is created. A new file in internal/ with the right package clause, the right imports, and 1 table-driven test alongside it is reviewed before it exists on disk.

The helper's shape is a Go design decision, not a mechanical one: which package it belongs in, whether it takes a context.Context, whether it returns an error or a wrapped one, whether it should be exported at all. Atlas writes the file with the write tool, which surfaces the entire contents in the permission prompt so you can reject the design before it lands. Because the whole point is one tested helper, the write includes a table-driven test in the same package, run with go test, and gofmt keeps the new file's formatting canonical. Every Atlas tool call is permission-gated against allow, ask, and deny rules.

## Why does Atlas use one apply_patch per Go file?

Atlas replaces each duplicate with a call to the new helper using apply_patch, one file per patch, so each swap is independently reviewable and revertible. Collapsing 5 Go duplicates in one giant patch means one bad hunk in internal/worker/queue.go poisons the whole change.

One patch per file is the discipline that makes a de-duplication safe. Each apply_patch turns one Go file's copy into a call to the shared helper, and that patch is reviewable on its own: you see the deleted block, the new call, and the import added to the file's import group. If one swap is wrong, only that file is reverted. Atlas computes a unified diff for every file edit and surfaces it for approval before writing, and snapshots file changes as git patches, so any individual swap can be rolled back without unwinding the rest. The commit history that results is also readable, which matters six months later.

## How do I verify a Go de-duplication actually finished?

Atlas runs go test with the bash tool after every swap, not once at the end, and finishes by grepping for any surviving copy. A de-duplication that leaves 1 un-migrated duplicate in internal/ is worse than none, because the next reader now believes there is a single source of truth.

Verification has two halves. First, correctness: go test runs through bash after each apply_patch, so a broken swap is caught against the file that broke it rather than at the end of five changes. Run gofmt over the touched files so the diff carries no formatting noise, and let go mod tidy settle any import changes the new helper introduced. Second, completeness: Atlas greps for the distinctive fragment of the original duplicated code and confirms zero remaining hits. A surviving copy is the failure mode that undoes the entire refactor, because the codebase now has both a shared helper and a straggler that does not use it.

## Steps

1. Run atlas in a module with a go.mod and let Atlas read your packages, interfaces, and go.sum dependencies.
2. Ask codebase_search for the behavior, not the exact code, to surface near-duplicate Go implementations that grep would miss because the copies differ in variable names.
3. Have Atlas read each hit in full and confirm the copies are genuinely equivalent, watching for a wrapped error in one and a swallowed error in another.
4. Create the shared Go helper with the write tool, which shows the full diff in the permission prompt before the file is created, and include a table-driven test beside it.
5. Replace each duplicate with a call to the helper using apply_patch, one file per patch, so each swap is independently reviewable and revertible.
6. Run go test through the bash tool after every swap, so a broken swap is caught against the file that broke it.
7. Run gofmt over the touched files and let go mod tidy settle any import changes the new helper introduced.
8. Finish by grepping for the original duplicated code fragment and confirming zero surviving copies remain.

## FAQ

### how to find duplicated code in a go codebase

Ask Atlas's codebase_search for the behavior rather than the exact text. Go duplicates usually differ in variable names, so a regex will not match them, while the semantic index returns the candidate declarations wherever they live.

### why doesn't grep find copy pasted go functions

Because copy-pasted Go code is renamed as it is pasted. The same retry loop with resp renamed to r and a different timeout constant is textually distinct and semantically identical, which is why Atlas uses codebase_search for this and grep only to verify completeness.

### atlas apply_patch vs edit for refactoring go files

Use apply_patch, one file per patch, when swapping duplicated Go blocks for a call to a shared helper. Each swap stays independently reviewable and revertible, so one bad hunk does not poison the whole refactor.

### how do i make sure i replaced every duplicate in go

Finish by having Atlas grep for the distinctive fragment of the original duplicated code and confirm zero remaining hits. A surviving copy is worse than no refactor, because readers now believe there is a single source of truth.

### when should i not extract a shared helper in go

When the copies are not genuinely equivalent. If one wraps its error and another swallows it, or one defers a Close and another does not, those are behavioral differences. Atlas reads each candidate and states the divergence before collapsing anything.

### should i run go test after each file or at the end

After each file. Atlas runs go test through bash after every apply_patch, so a broken swap is caught against the file that broke it rather than after five changes have piled up.

### how do i set up atlas in a go module

Run atlas in a module with a go.mod, let Atlas read your packages, interfaces, and go.sum dependencies, then have it add table-driven tests or refactor an interface and run go test on the diff.

---

Canonical HTML: https://runatlas.sh/resources/stacks/extract-a-shared-helper-from-duplicated-code-in-go
Source of truth: aeo_pages row `/resources/stacks/extract-a-shared-helper-from-duplicated-code-in-go` (segment: Stacks) (this file is generated from it, never hand-edited).
Licence: Atlas is proprietary with a free core. It is not open source and there is no public source repository.
