Any good advice about how to avoid import cycle in Go?
go list -f '{{join .Deps "\n"}}' <import-path>
Will show import dependencies for package at <import-path>
- or in current directory if <import-path>
is left empty. Alternatively
go list -f '{{join .DepsErrors "\n"}}' <import-path>
hopefully shows some useful information in your case. See also the output of
go help list
for additional information about the go list tool.
To complement on jnml's answer (which helps "debug" circular references problems), you can use dependency inversion to break those cycles, coupled with dependency injection. For an application, I always try to follow the guidelines of the Clean Architecture - see here for a Go-specific example - and I find that Go's "non-declarative implementation" of interfaces (that is, you don't have to explicitly say type MyStruct struct implements IfceSomething
) makes this very simple.
So, if you have packages A -> B -> C -> A
, you create InterfaceA
(some relevant name, obviously, more behaviour-related than package-related :) in package C and make it depend on this interface instead of on package A, and you make sure package A "implements" this interface.
Then you just have to provide a concrete implementation of A to C at some point (many possibilities here, I usually do this "glue" code in the main package that knows about all dependencies).
Since import relationship just become more and more complex while code grows, I'm eager to know how to avoid import cycle more efficiently in Go.
Another option is to visualize the dependencies in your project. This can be done with CLI tool godepgraph. You can install it with:
go get -u github.com/kisielk/godepgraph
And then use it for finding import cycles in your app with help of another CLI tool graphvis. Having this tools you can visualize package dependencies:
godepgraph -s path/to/my/package | dot -Tpng -o godepgraph.png
open ./godepgraph.png
to find cycles in my code: