Abstract
In every product, we start by defining architectural guidelines and code conventions, but the hard part is to check if the code adheres to these definitions over the time. Arch-Go is a testing tool that can be included as part of the CI pipeline to continuously verify our architectural guidelines.
Most authors defines software architecture as a set of important decisions which are hard to change. If we are working in a software artifact, then these decisions are represented as architectural guideline, because of that it’s very common to talk about some unwritten rules like “Don’t call repository components from components in the presentation packages”, or “prefer the use of structs over too many parameters or return values in functions/methods”. We can check this kind of rules as part of a code review process, but as this is manual, is errors-prone, then is possible to pass this quality-gate and push code into our master branch that breaks our guidelines, so we need a way to automatically check if our code adheres to these rules.
This talk is about Arch-Go, a testing tool which provides a simple way to document the architectural guidelines and checks if our Go code complies with those rules as part of a continuous integration pipeline. We will review why we need to check architecture quality and how Arch-Go can help us to automate it.
Transcript
This transcript was autogenerated. To make changes, submit a PR.
Hello everyone, welcome to a new session of the deeptype track.
In this conference today I'm going to talk about Archgo
and how we can use it to continuously test the quality
of our architectures. Archgo is a very
simple testing tool strongly inspired in
Arc unit, a testing framework for Java
language. To start, I'm going to introduce
myself. My name is Francisco defines,
but most of the people call me Dino. I am a software
developer and I'm working in Walmart, Chile in the
artificial intelligence and data exploitation
department. I have worked in many industries,
in many business models, playing different roles
and working with different languages as Java,
C, Javascript, Python per Ruby
and others. Since last year I'm working with
Golang and today I consider myself a
gopher because I'm really impressed about its
simplicity. You can find me in social media
with the user fdaimas, in GitHub,
LinkedIn, Twitter, and of course you
got my email. Okay, the first topic that we
are going to talk about is what are the architectural
guidelines and why we should know but them architectural
guidelines in a very brief way are these important
decisions that we take along the development of
a product or a project mostly in the first moment.
But of course we can make changes to these definitions
as the project moves forward. A very common example
of architectural guidelines is when we
have to choose the package model we
want to follow in our code base in the project.
For example, if we have to create
a simple rest service, maybe we can
choose a layered architecture model
because it's a very simple approach. In this
approach we will have some
layers and each layer can have one
or more packages. And not only this.
Also we have rules about
how the packages in one layer can interact
with packages in another layer. For example,
looking at the diagram below,
packages that are contained inside the presentation
layer can only interact with packages
in the same layer or packages in the business logic
layer. Other example is that packages inside the
persistence layer cannot interact
with packages in any other layer. This image
shows us the clean architecture model proposed by
Robert Simarti. If we want to follow
this architecture model, we can implement an
onion architecture packages model in
our code base. But the case is very similar
to the previous one. We have packages
and we have to decide in what layers
those packages can be located and
how these packages can interact with
the other packages. This set of rules and definitions
about packages and their interactions
are part of the architectural guidelines.
Of course, the packages model is not the only important
decisions that we can take. There are many
other agreements, for example, how to
create functions if we want to require
some properties that these functions must
comply with. Or maybe if we want
to have a naming convention,
or if we want to restrict what kind
of items can be placed in certain
packages. Of course, if we want to restrict or allow
some interactions between packages.
Now we are going to look at some issues
related to architectural guidelines. These first
one is defining. Today it's very common to
heard about evolutionary architectures,
the approach proposed by Grepa, Caparsons,
Nielford and Pat Gua. By the way, it's a
very interesting approach. I strongly recommend to read
this book. So if we think
that our architecture can evolve, we must
provide a way to make and
record changes to our guidelines.
It's just common sense. The next one is
about outdated guidelines. If you are thinking
in publishing your architectural guidelines
in systems like confluence or an internal wiki,
you have to take care of an important risk.
Those systems are far from code. In a daily basis
we work with the code base, not with
the confluence system. So there is
a risk that these developers forget to update the
document in confluence. And after
a couple of months we will end with an
architectural guidelines that does not represent
what we are applying in the code base. These next
issue is about software quality degradation.
Even if we apply some powerful techniques
in our teams, like code reviews or pair
programming, we are humans,
so we made mistakes, and it's
fine to make mistakes. For example, if we
have a lot of rules as part of
our architectural guidelines, maybe a
couple of developers forgot to check
some of them in a certain pull request.
And after a couple of months,
our code base does not comply with
our architectural guidelines. But the worst part is
that we are not seeing it, so we
have no way to take care of this
situation. And finally, metrics.
It's always about metrics. If we
want to know if there is a relation
between the compliance level that
our code has against the architectural
guidelines and other metrics like lead time or
change values, or another kind of metrics,
the only way that we have is to measure
the compliance level. There is no
other way. So we need a way to
know if our code complies with our
architectural guidelines. Now we are
ready to know about Archgo and
see how we can use this tool to represent
our architectural guidelines and checks if our
project complies with them. The best
way to understand and introduce
ArG Go is looking at the execution flow.
The process starts when the team members complies
with a set of architectural guidelines and represents
them in a YAML file. This JAML file
must comply with these Archgo schema and
has to be included as part of the code base in
the root directory of the project. Then we
need to download Archgo,
for example using the Goget command. And finally
we just run Archgo in the console and
Argo makes his magic and
do all the verifications and the output
of ArchGo will be succeeded or
rejected. And of course the console output
has all the detailed information. An alternative
way to execute and run Archgo is
passing an optional argument that
generates an HTML report in cases that
we want to publish this report in another system.
Now that we know a typical execution
process of Archgo, let's see what
features are included in this tool.
Archgo contains three features. The first one
is the rules description. As our architectural guidelines
are represented in a jammer file,
Archgo offers a simple way to represented
those rules in a more readable way.
The second feature is the core feature of Archgo,
the rules evaluation. It checks if our
project complies with all of the architectural
guidelines described in this JAML
file. And finally the HTML report.
It creates an HTML report with the
result of all the evaluation process.
So let's go deeper in
the first feature, the rules description at
first time, the rules description feature does not
look very attractive because we think we
are representing our architectural guidelines
in a JAML file, and YAMl format is very
readable and easy to understand.
But the problem with YAML format is that
we have many ways to represent exactly the
same document. As we can see,
those two files represent exactly
the same rules. And of course,
both of these jammer configurations complies with the
same schema. That's the reason why
art go offer a simple way to describe this
rule in a more readable way.
The rules description process starts when we
have created the Jammer file and described
all our architectural guidelines inside this file.
Then we just run Archgo with
the describe option and the output will
be the description, in a very readable
way of all the rules contained in this jammer file.
So this format is very easy
to understand, and we can share this output
with other teams, with other members,
and maybe with other rules, like a product
owner or a business analyst. We can continue
with the core feature of Archgo, the rules evaluation.
The rules evaluation process starts when we have
created the Jammer file and described
all our architectural guidelines inside this file.
Of course, the Jammer file has to be included
as part of our code base.
Archgo will gather all the packages
from our application and base it on.
The rules described in the Jammer file will
resolve which rules will be evaluated.
ArchGo supports five types of rules,
dependency rules, content rules,
function rules, naming rules and cycles
rules. Finally, Archgo will consolidate
all the different evaluation results and
resolve what will be the global result
of the evaluation process that can be
succeeded or rejected. The first rule
type is dependency rules. Those rule
are about the allowed and the restricted
relations between different packages.
For example, the green arrows represented
allowed dependencies. So package a can
depends on package c and the red
arrows represented restricted and
not allowed dependencies. So if any file
in package b depends on anything that's
declared on package d, the evaluation process
will reject this rule. But not only
this. Also, ArchGo offers
a way to allow and restrict dependency
with external packages.
For example, in this case, package d can
depends on goSql driver, mySql package,
but cannot depends in the Fdynas go
mySql package. All of these dependency rules
can be modeled in archgo. As we
can see, it's very simple to represent those
rules in the JAML file, we have to declare a package
using a pattern and these the keywords that
can be should only depends on,
should not depends on, and should only
depends on external. The next type is content
rules. Those rules are about which
content are allowed as part of a
certain package. For example, package b
allows only interface definitions
and package c allows only functions
definitions. So if a developer
create an structs inside packages
b, the evaluation process will fail.
In the case of package a, it accepts
declarations of structures functions
methods, but does not allow interfaces
definitions. All of these cases can be modeled
in archgo. As we can see,
it's very simple to model.
We have two main forms to model these
content rules. We have the should only contain
and these item type that can be functions,
methods, interfaces and structs and these
opposite that is should not contain and the
item type. The next one are the function
rules. Those rules are about some properties
that the functions must comply with.
For example, we can restrict how
many parameters the functions can receive
because we prefer, for example, using structures
to encapsulate those parameters. A similar
case is for the return values. We can
restrict how many return values the
functions can declare, and also
we can define a maximum quantity
of lines of code that the function implementations
has to comply. And finally,
how many functions we accept
inside a single file. All of these properties
can be modeled in Archgo and as we can
see in this example, it's very natural
to represent those rules.
We define a package and all the packages
that complies with this pattern require the functions
to comply with these max quantity of parameters.
The max return values, these max public
functions per file, and the definitions
must comply with these maximum
lines of code. The next rule type is
naming rule. Those rules are about naming
conventions. Example above shows an
interface which is implemented by three
structs. So it's a common sense that
these structs have a naming convention,
a common pattern to comply with, because sometimes
makes sense to comply with a naming rules. More.
Even in Golang, where we
have an implicit interface
implementation, we don't have explicit one,
but in another case, like the one in the
right, it doesn't make sense. We are implementing
two interfaces, so we are free
to use the name that we
want in this structure. For the first case,
we can model this case in Archgo,
and it's very simple too. We have an interface
implementation naming rules attribute, and inside
them we can define what's the pattern for
the interface, and then what's the pattern that
the structs must comply with.
The last one are these cycles rules?
Those rules are about cycles
in the dependency graph, this diagram represents
a cycle between package b,
package c and package d. The truth is
that as Golan compiler does not allow import
cycles, this feature is evaluated and maybe
it will be deprecated in future releases.
If you want to know how to model this rule in the
YAML file, there is an example. In this example
we configure that all the packages
that complies with this pattern should
not contain cycles. Now we have reached
the last feature of Archgo, the HTML
report generation. This feature generates
a very simple verification report that shows
the result of the verification process.
This report is strongly inspired on Pytest
coverage report Pytest is a mutation
testing tool for Java language. This feature is
in work in progress status, so we
will be added more interactions in future releases.
At this moment I'm sure that you are asking yourself,
what about the continuously part in the title of this
session? Well, let's talk about
automation. A generic CI CD pipeline
contains several steps. The process starts
when the developers write the code and push
it to a virtual control repository.
This event triggers some automatic steps
as running these unit test or running the integration
test, and then we can continue with the deployment
part of the pipeline. Looking at this process,
it's natural to think in including architecture
tests as part of the CI CD pipeline for
Golang. Architecture tests are supported
by Archgo. As we've seen before,
running ArcGo is very simple. We just need
to run Archgo command, so include Argo
in different guidelines are very simple too.
Here are examples for GitHub actions
Circleci and bitbacket guidelines.
Of course we can run Archgo
inside a docker container. Do you want to contribute
with Archgo? These is these project repository
URL. So you just need to
download these tool, use it, and create some pull
requests. This is the ideas backlog.
There are many ideas in the backlog.
I'm very interested to know what do you think about them?
And of course, if you have new ideas,
you are welcome. And that's all.
We have reached the end of this session. I have to
thank you for being here and invite you
to participate in the rest of the sessions of this conference.
And finally, if you like what Archgo
offers, please promote the use of this
tool in the community. Thank you very much and
see you another time.