Why You Must Start Using Hexagonal Architecture Now!

As a software engineer, I’m always on the lookout for architectural patterns which can elevate the quality and maintainability of my applications. One pattern which has caught my attention is Hexagonal Architecture. In this blog post, I’ll explain what Hexagonal Architecture is, what makes it so great, and provide an example of how you could implement it in your next Go microservice.

Table Of Contents

What Is Hexagonal Architecture?

Hexagonal Architecture (also referred to as Ports and Adapters) is an architectural pattern which focuses on modularity and the separation of concerns. Its main goal is to organise the application in a way which isolates the core business logic from external dependencies.

The pattern revolves around the idea of a hexagon. At the centre of the hexagon is the core business logic. This is surrounded by ports, which are the interfaces used to interact with the outside world. Surrounding the Hexagon are the adapters which are the practical implementations of those interfaces.

You might be curious about why it’s a hexagon. The reason is straightforward… it simplifies the process of drawing a diagram. The hexagon allows for a clear illustration of the core, port and adapter layers. Its six sides also conveniently make it easy to show six distinct dependencies.

Benefits Of Hexagonal Architecture

Now that we understand the principles of Hexagonal Architecture, let’s examine the benefits.

The modular design allows for changes to be made to the dependencies without affecting the core logic. This can be useful in situations where the dependencies are subject to change.

By breaking down the application into separate layers, including the core, port, and adapter layers, the codebase becomes easier to navigate and maintain.

Decoupling the dependencies from the core business logic makes it much easier to write mocks which encourages the developer to write more tests, leading to a more robust system.

Example Project Structure

It can be challenging to grasp the concept of Hexagonal Architecture without hands-on experience and analysis. I decided against a step-by-step guide for building a sample project, as it would likely lead to a lot of copying and pasting. Instead, I would encourage you to build your own project by looking at the descriptions in the example and at each stage ask yourself why the code goes here.

To keep confusion to a minimum, I simplified the example to keep the focus on the essential principles of Hexagonal Architecture. The example shows a folder structure for a basic Go API which has Gin, MongoDB, Redis and Zap as dependencies.

go.mod
go.sum
/cmd Executable packages.
/app Entry point to the app.
main.go Inject all dependencies, initialise an App struct and call the start method.
/config Package for all of the configs.
app.go App config struct with a factory function.
mongo.go Mongo config struct with a factory function.
redis.go Redis config struct with a factory function.
/internal Internal application logic.
/app Package for initialising the application.
app.go App struct with handler + app config as dependencies, a start method and a factory function.
/core The centre of the hexagon which is unconcerned with the outside world implementations.
/domain Domain logic.
model.go Domain structs e.g. Person.
/ports Package for all ports to the outside world.
handler.go Handler interface.
repository.go Repository interface.
service.go Service interface.
/services The services package is in the core directory because the services communicate with the ports/interfaces and do not care about the implementations.
services.go Implementation of the service interface with a repository dependency and a factory function.
/adapters Package for the implementations of the ports/interfaces.
/handlers Handler implementations.
/gin Gin handler implementation.
handler.go Implementation of the handler interface with a service + logger dependency and a factory function.
/repositories Repository implementations.
/mongo Mongo repository implementation.
repository.go Mongo setup and implementation of the repository interface with the Mongo config as a dependency and a factory function.
model.go Mongo related structs.
/redis Redis repository implementation.
repository.go Redis setup and implementation of the repository interface with the Redis config as a dependency and a factory function.
model.go Redis related structs.
/logger Any internal dependency which is difficult to switch or unlikely to change should have its own package in the internal directory
zap.go Zap logger initialisation with a factory method.
/external External application logic e.g. consumers.

You may have noticed that there are two NoSQL databases with MongoDB and Redis. As long as the repository implements the interface, you can switch between dependencies. This could even be set from a config value in the app config.

As long as the basic principles of the pattern are followed, the implementation should be effective even with various modifications. It may be necessary to adjust the scope of some of the packages depending on the scale of your project. Nevertheless, hopefully, the provided example can point you in the right direction.

Once you come to grips with Hexagonal Architecture it becomes clear where new entities should go, which prevents wasted time debating where a package should live. Leave a comment below on where you would place a message broker in the example structure.

Conclusion

In conclusion, using Hexagonal Architecture in your Go microservice provides a wide range of benefits. By decoupling the core logic from external dependencies, the codebase becomes flexible, maintainable, and testable. With a deep understanding of Hexagonal Architecture, locating and placing new packages becomes a breeze.

So if you’re looking for a way to take your Go microservices to the next level, give Hexagonal Architecture a try. You might be surprised by how much it can transform the way you approach your projects.

If you have any questions or comments, please leave them below. Also, don’t forget to subscribe to our newsletter to receive more informative posts like this directly to your inbox.

If you found this article helpful, please share it with your friends and colleagues.

Thank you for reading!

2 responses

  1. Jose Gonzalez avatar
    Jose Gonzalez

    Can you provide a repo example following this architecture? Also great stuff, learning a lot through this articles! Thank you very much

    1. Hi Jose, I was trying to get people to write the solution themselves rather than copy mine. That’s why I didn’t provide an example repo. In the future, I am looking at bringing out an example microservice which follows Hex architecture. So keep your eye out for that.

Leave a Reply

Your email address will not be published. Required fields are marked *