Go

Go forbids import cycles. How do you detect and break them?

Question 436MediumGo 1.22 to 1.25

The compiler rejects cycles (import cycle not allowed) because package initialization and compilation units must form a DAG. A cycle usually signals a design problem: two packages that are really one, or a dependency pointing the wrong way.

Ways to break them:

  1. Dependency inversion with consumer-side interfaces. The lower-level package defines the small interface it needs, and the higher-level package satisfies it implicitly.
  2. Extract shared types into a leaf package (for example domain or model) that both import. Avoid turning it into a dumping-ground util package.
  3. Merge the packages if they are really one unit.
  4. Wire dependencies in main (composition root): pass funcs or interfaces in at construction time.
// package order (no import of package user)
type UserLookup interface {
    Email(ctx context.Context, id int64) (string, error)
}
type Service struct{ users UserLookup }

// package user imports order freely; main wires:
//   svc := order.Service{users: userRepo}

Tests: an external test package (package order_test) can import packages that import order, which breaks test-only cycles. Diagnose with go list -deps or go mod graph at the module level. Interviewers look for "accept interfaces, defined where they are consumed" instead of hacks such as moving code into main.

More on Modules, Packages & Tooling

All 36 Modules, Packages & Tooling questions