Introducing Arch-Go
Tags: go, architecture, testing, tooling
Published: 2021-04-20 22:53:18

# Summary
In this article, we'll show what is [Arch-Go](https://pkg.go.dev/github.com/fdaines/arch-go) and how to use it in order to check the architecture of a project in Go.

# What is Arch-Go?
Arch-Go is a testing tool that verifies if your Go project adheres to your architectural guidelines. 

## A little review of architectural guidelines
The architectural guidelines of a system defines properties like the following:
* How packages are defined
* How packages interact
* What kind of assets should be part of each package
* Some properties related to specific assets, for example it describes some functions or interfaces properties.

For instance, let's think that you're working on a Rest Service using a layered structure containing the following three packages: _presentation_, _businesslogic_ and _persistence_.
- **Presentation:** it contains our REST handlers.
- **Business Logic:** it contains the components that encapsulates the business logic of our service.
- **Persistence:** it contains components to access our persistence services, like a database client.

![REST Service using a layered architecture.](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0uf9knxq6kh7dwuohi0m.png "REST Service using a layered architecture.")

As we have decided to use a layered architecture, we can find out some dependency rules between its packages:
* The components in *presentation* package should depend only on components in the *businesslogic* package.
* The components in *businesslogic* package should depend only on components in the *persistence* package.
* Components in *persistence* package should not depend on any other package.

What happens if a developer includes a dependency that is not allowed?, for example, a handler that depends on a persistence component. Of course, we should detect this violation in a Pull-Request code review, but as this process is manual then is prone to errors, so we can easily get the following result.

![REST Service using a layered architecture that includes not allowed dependencies.](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wx2for9slyeurswbvajc.png "REST Service using a layered architecture that includes not allowed dependencies.")

What are the consequences of including these dependencies?, in terms of functionalities maybe there will be no impact, but related to system maintenance there are some implications, like:
- Unnecessary coupling between _presentation_ and _persistence_ layers, so changes in _persistence_ probably will have an impact on _presentation_.
- As our handlers have more dependencies, testing them will require more effort.
- Onboarding of new developers will be more complex, as the explanation of dependencies is an important part of this process.

## Declarative aproach
Arch-Go uses a declarative approach to set the architecture rules, so in order to specify what rules to check we need to setup a YAML file.
The selection of a declarative approach was made thinking in simplify the comprehension of the architectural rules and to help the sharing of these rules between artifacts, products and teams.

## Verification rules in Arch-Go
### Rules for dependencies between packages:
* Set what dependencies between packages are allowed and what are not allowed.

### Rules for packages content:
* Set the allowed content for the package (interfaces, structs, functions and methods).
* Set the restricted content for the package (interfaces, structs, functions and methods).

### Cyclic dependencies:
* Allows to check for dependency cycles in selected packages.

### Functions properties:
* Set the maximum number of parameters that functions in a package are allowed to receive.
* Set the maximum number of values that functions in a package are allowed to return.
* Set the maximum number of public functions per file.
* Set the maximum number of lines inside a function.

# Architecture validation using Arch-Go

## Installation
Arch-Go is currently published as a module, so, in order to install it, you need to execute the `go get` command, as follows.
```
$ go get -u github.com/fdaines/arch-go
```
For the verification of a successful installation process, you can execute the following command:
```
$ arch-go -h
```

## Creating Dependencies Rules
Going back to our example service, we can see some dependency rules:
* Components in *presentation* package should only depends on components in *businesslogic* package.
* Components in *businesslogic* package should only depends on components in *persistence* package.
* Components in *persistence* package should not depends on any other package.

Those dependency rules, can be described using the Arch-Go YAML schema as follows:
```
dependenciesRules:
  - package: "**.presentation"
    shouldOnlyDependsOn:
      - "**.businesslogic"
  - package: "**.businesslogic"
    shouldOnlyDependsOn:
      - "**.persistence"
    shouldNotDependsOn:
      - "**.presentation"
  - package: "**.persistence"
    shouldNotDependsOn:
      - "**.presentation"
      - "**.businesslogic"
```

## Running Arch-Go
To run Arch-Go we will use an example project that has the code and rules defined.
```
$ git clone https://github.com/fdaines/arch-go-sample-project.git
$ cd arch-go-sample-project
$ arch-go
```
As our project complies with our architectural guidelines, the output should be similar to:
![Arch-Go's output when our project complies with the architectural guidelines](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/atl725f8sbk5dvytqcy9.png "Arch-Go's output when our project complies with the architectural guidelines")

Of course, we have a code example that violates a dependency rule (the branch is named: `dependency-rule-violation`). To check this example, just run in the command line
```
$ git checkout dependency-rule-violation
$ arch-go
```
In this case, the output from Arch-Go should be similar as follows.
![Arch-Go's output when some rules were violated](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eh53vlqa2m2r18fr5mx9.png "Arch-Go's output when some rules were violated")


## Running Arch-Go as part of a Github Actions Workflow

To include Arch-Go verification as part of a Github actions workflow, you need to include a YAML file under `github/workflows/`, with content as follows:
```
name: 'arch-go'

on:
  workflow_dispatch:
  push:
    branches:
      - master

jobs:
  Arch-Go:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v1
      - uses: actions/setup-go@v2
        with:
          stable: 'false'
          go-version: '1.15'
      - name: Install Arch-Go
        run: go get -u github.com/fdaines/arch-go
      - name: Run Arch-Go
        run: arch-go
```

Then, each time we push into master branch, Github Actions will run this workflow and checks if the code complies with our architectural guidelines.

![Running Arch-Go as part of a Github Actions Workflow](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nt4un8qo0f852p65la18.png "Running Arch-Go as part of a Github Actions Workflow")


# Conclusion
In this article, we have explored the basics of using Arch-Go to check our projects. Arch-Go simplifies the verification of architectural guidelines improving the quality project for reducing maintenance costs.