I wrote the hexagonal architecture in go language

Introduction

This is the first post. After studying, I wrote a code that adopted the idea of ​​hexagonal architecture in Go.

I have referred to many sites, including Hexagonal Architecture Translation Site, but I am still not familiar with it and the description may be incorrect. If you notice any mistakes, please point them out.

What is hexagonal architecture?

A description of the hexagonal architecture can be found on this site (https://blog.tai2.net/hexagonal_architexture.html). It may be a little difficult to understand, so the features that I thought were important are listed below.

--Hexagonal architecture is an architecture that separates into two layers, the inner layer (adapter layer) and the outer layer (application layer). --The application (inside) and the external agent are separated by implementing communication with external agents such as HTTP, Email, and RDB in the outer adapter layer. --The adapter layer depends on the application layer, but the application layer must not depend on the adapter

The image looks like the figure below. (Hexagonal architecture is often represented by a hexagonal diagram as shown in the figure below.) 無題のスプレッドシート (1).png

Layer responsibilities

As mentioned above, the hexagonal architecture consists of two layers, the adapter layer and the application layer. Each layer has the following responsibilities:

Adapter layer

-Implement interaction with external agents such as Email and RDB --The adapter layer depends on the application layer

Application layer

--Application layer implements business logic --However, since the hexagonal architecture does not define business logic, it is up to the implementer how to implement it in the application layer. --Application layer must not depend on adapter layer

Implementation example

So far, we have explained the role of layers, but I think it is easier to imagine if you actually look at the code, so let's look at an implementation example.

The final configuration is Like this. Then, I will explain the implementation example for each layer.

Adapter layer implementation

The adapter layer implements interaction with external agents such as RDBs. Therefore, it has an implementation to acquire and create DB information.

The concrete implementation looks like the following.

As will be described later, define a structure for injecting into the interface of the application layer, and add a method to perform DB operations to that structure.


package dao

import (
	"database/sql"
	"hexagonal-architecture-sample/server/application/model"
	"log"

	_ "github.com/go-sql-driver/mysql"
)

type User struct {
	db *sql.DB
}

func ProveideUser(db *sql.DB) *User {
	return &User{db: db}
}

//Since the adapter layer depends on the application layer, the model of the application layer is used.
func (u *User) GetByID(id string) (*model.User, error) {
	var user model.User

	result := u.db.QueryRow("select * from users where id=?", id)

	err := result.Scan(&user.ID, &user.FirstName, &user.LastName, &user.Email)
	if err != nil {
		return nil, err
	}
	return &user, nil
}

Application layer implementation

At the application layer, you are responsible for implementing the business logic. However, the hexagonal architecture does not define business logic, so it is up to the implementer to implement it.

Also, in the hexagonal architecture, the application layer must not depend on the adapter layer. Therefore, you can avoid relying on the adapter layer by defining an interface that corresponds to the adapter layer in the application layer and injecting the adapter layer implementation into that interface.

The concrete implementation looks like the following.


package application

import (
	"hexagonal-architecture-sample/server/application/model"
)

//The application layer defines the interface that corresponds to the adapter.
//You can avoid relying on the adapter layer by injecting an adapter implementation into this interface.
type User struct {
	Interface repository.User
}

func (u *User) Create(user model.User) error {
	return u.Interface.Create(user)
}

func (u *User) GetAll() ([]model.User, error) {
	return u.Interface.GetAll()
}

func (u *User) Update(user model.User) error {
	return u.Interface.Update(user)
}

func (u *User) GetByID(id string) (*model.User, error) {
	return u.Interface.GetByID(id)
}

Application layer interface definition

package repository

import "hexagonal-architecture-sample/server/application/model"

type User interface {
	Create(user model.User) error
	GetAll() ([]model.User, error)
	Update(user model.User) error
	GetByID(id string) (*model.User, error)
}

Make the application layer independent of the adapter by injecting the adapter layer implementation into the interface defined in the application layer with the main function.

package main

import (
	"hexagonal-architecture-sample/server/adapter/mysql"
	"hexagonal-architecture-sample/server/adapter/mysql/dao"
	"hexagonal-architecture-sample/server/adapter/router"
	"hexagonal-architecture-sample/server/application"
	"log"
	"net/http"
)

func main() {

	resources := mysql.NewResource()
	resources.Initialize()
	defer resources.Finalize()
	p := &router.Provide{
		User: router.User{
			//I'm injecting an adapter layer User structure into the application layer interface.
			User: application.User{
				Interface: dao.ProveideUser(resources.DB),
			},
		},
	}

	err := http.ListenAndServe(":8080", router.NewRouter(resources, *p))
	if err != nil {
		log.Fatal("ListenAndServe", err)
	}
}

Finally

I didn't know what to do with the directory structure because there is no full stack framework in Go language, so I learned about hexagonal architecture this time. I think that the hexagonal architecture will have a cohesive directory structure by dropping the layer structure into the directory as it is. If you don't know the best practices for directory structure in Go, learning about architecture can help.

That is all for the content of the article.

References

Hexagonal Architecture (https://blog.tai2.net/hexagonal_architexture.html#id5) Hexagonal architecture in Go Pospome server-side architecture What is the most accessible architecture to get started with Domain Driven Design [DDD]

Recommended Posts

I wrote the hexagonal architecture in go language
I wrote the queue in Python
I wrote the stack in Python
I wrote it in Go to understand the SOLID principle
I wrote the selection sort in C
I wrote the sliding wing in creation.
I wrote you to watch the signal with Go
I wrote python in Japanese
Hello World in GO language
I wrote a CLI tool in Go language to view Qiita's tag feed with CLI
I wrote the basic operation of Seaborn in Jupyter Lab
I tried to illustrate the time and time in C language
I wrote the basic operation of Numpy in Jupyter Lab.
I wrote a script that splits the image in two
Try implementing Yubaba in Go language
Use optinal type-like in Go language
I got lost in the maze
I participated in the ISUCON10 qualifying!
Let's touch on the Go language
I wrote Fizz Buzz in Python
Post to slack in Go language
Switch the language displayed in Django 1.9
I wrote Gray Scale in Pytorch
Write tests in GO language + gin
Do something object-oriented in GO language
I wrote the code to write the code of Brainf * ck in python
Read the config file in Go language! Introducing a simple sample
The most sought after programming language in 2020
[GO language] Organize the behavior of import in places other than GOPATH
[C language] I want to generate random numbers in the specified range
I made a kind of simple image processing tool in Go language.
I saved the scraped data in CSV!
Looking back on 2016 in the Crystal language
I can't get the element in Selenium!
I wrote the code for Gibbs sampling
Draw graphs in the programming language Julia
[Python beginner] I collected the articles I wrote
I wrote Project Euler 1 in one liner.
Practical example of Hexagonal Architecture in Python
[Fundamental Information Technology Engineer Examination] I wrote the algorithm of Euclidean algorithm in Python.
I compared the speed of go language web framework echo and python web framework flask
I got an error when trying to run Hello World in Go language
Note that I understand the least squares algorithm. And I wrote it in Python.
I wrote a PyPI module that extends the parameter style in Python's sqlite3 module
Tweet regularly with the Go language Twitter API
I tried hitting the Qiita API from go
A memo that I wrote a quicksort in Python
Java programmer touched Go language (Implement Java inheritance in Go language)
I tried simulating the "birthday paradox" in Python
I tried the least squares method in Python
I wrote a class in Python3 and Java
I can't enter characters in the text area! ?? !! ?? !! !! ??
I wrote a design pattern in kotlin Prototype
I implemented the inverse gamma function in python
I wrote a Japanese parser in Japanese using pyparsing.
I checked the calendar deleted in Qiita Advent Calendar 2016
Create a web server in Go language (net/http) (2)
I implemented Human In The Loop ― Part ① Dashboard ―
I want to display the progress in Python!
I wrote matplotlib
What I do when imitating embedded go in python