Import Boundary Checker is a tool to automatically check if import boundaries are violated or not. Examples of where this tool is useful:
- Hexagonal/clean architecture where domain logic cannot import infrastructure code
- Mono-repositories with multiple microservices where you don't allow services to import code from other microservices
- Layered architecture where layers cannot import certain other layers
- Import boundaries are checked automatically (meaning you don't have to spend time in code review on manually checking)
- It is extremely fast (sub-second speeds with medium sized projects)
- Configuration is easy (within a few minutes you can define forbidden imports for your projects and have everything set up)
- The tool is independent (you don't need to change any production or testing code for the tool to work)
- Usage of the tool requires zero dependencies (so no outside dependencies are needed for running the tool, only the source code of your project)
You will need Go 1.14+.
go install github.com/BytecodeAgency/import-boundary-checker
Note: due to being in the alpha phase, the tool has only been tested on MacOS and Linux. Windows support is not guaranteed but will be added before the 1.0.0 release.
After setting your configuration and, you can invoke the tool by simply calling:
import-boundary-checker
Note that only production code (not the test modules) is tested.
You can use the following CLI options (they are all optional):
-config [filepath]
: set the configuration path (defaults to.importrules
in the current directory)-verbose
: set verbose output of main (does not enable debugging mode)
Note: the semicolons are required!
The tool is configured using a domain specific language. Follow the steps below to create your configuration:
-
Create a new configuration file
.importrules
in the root directory of the project you want to check -
Set the correct language for your project (currently only Go is supported, Typescript/Javascript will be added next)
LANG "Go";
- Set the
IMPORTBASE
variable (this is the same as themodule
value ingo.mod
)
IMPORTBASE "github.com/BytecodeAgency/example";
- Define the import boundaries, using
IMPORTRULE "[IMPORTBASE]{file you are defining forbidden imports for} CANNOTIMPORT "[IMPORTBASE]/{some module in project}" "[IMPORTBASE]/{another module in project}";
. Leaving out the[IMPORTBASE]
allows you to define forbidden imports from the standard library or outside dependencies. Whitespace is ignored. Note that when defining an import, importing from subdirectories within the given module will also cause errors (given/domain
, will also block/domain/user
and/domain/user/models
, etc.)
IMPORTRULE "[IMPORTBASE]/typings/entities"
CANNOTIMPORT "[IMPORTBASE]" "fmt" "github.com/go-playground/validator/v10";
IMPORTRULE "[IMPORTBASE]/domain"
CANNOTIMPORT
"[IMPORTBASE]/infrastructure"
"[IMPORTBASE]/data";
- When defining import boundaries, you can optionally add allowed imports, using
ALLLOW "{allowed module}" "allowed module"
(make sure you do this before the semicolon). This is useful f.e. when working with hexagonal architecture.
IMPORTRULE "[IMPORTBASE]/domain"
CANNOTIMPORT
"[IMPORTBASE]/infrastructure"
"[IMPORTBASE]/data"
ALLOW "[IMPORTBASE]/data/interactors";
This will give the following configuration file:
LANG "Go";
IMPORTBASE "github.com/BytecodeAgency/example"
IMPORTRULE "[IMPORTBASE]/typings/entities"
CANNOTIMPORT "[IMPORTBASE]" "fmt" "github.com/go-playground/validator/v10";
IMPORTRULE "[IMPORTBASE]/domain"
CANNOTIMPORT
"[IMPORTBASE]/infrastructure"
"[IMPORTBASE]/data"
ALLOW "[IMPORTBASE]/data/interactors";
- When working with hexagonal architecture it might be intereseting to block all imports at the root of the project and allow the specific imports in the more specific sub folders.
LANG "Go";
IMPORTBASE "github.com/BytecodeAgency/example"
IMPORTRULE "[IMPORTBASE]"
CANNOTIMPORT "[IMPORTBASE]";
IMPORTRULE "[IMPORTBASE]/entities"
CANNOTIMPORT "fmt"
IMPORTRULE "[IMPORTBASE]/interactors"
ALLOW "[IMPORTBASE]/entities";
IMPORTRULE "[IMPORTBASE]/data"
ALLOW
"[IMPORTBASE]/entities"
"[IMPORTBASE]/interactors";
You can read the full DSL specification in the docs/dsl.md
file.
In the examples
directory of this repository, you can find some examples of the tool configured. In each directory, you will find a .importrules
file with the import boundaries defined.
An example for running this in CI through Docker can be found in the Dockerfile
in the root of this repository.
The project is licensed under the Lesser GNU Public Licence version 3 (LGPLv3). Contributions (issues and pull requests) are welcome.
Development documentation can be found in docs/dev.md
.