I'm at an initial stage of creating a microservice application in Go, but due to the way that the import paths and directories are handled I'm not quite sure what's best way to structure the project files.
Normally, the project would look something like this in Java:
|-- gateway_microservice
|-- src
|-- docker
|-- config_microservice
|-- src
|-- docker
|-- recommendation_microservice
|-- src
|-- docker
|-- users_microservice
|-- src
|-- docker
Now if I do it the same way in Go, the import paths become somewhat cumbersome:
import (
"fmt"
"github.com/user/myproject/gateway_microservice/src/package1"
"github.com/user/myproject/gateway_microservice/src/package2"
)
Additionally, I hear that the idiomatic way is to put all main.go
files in a separate cmd
directory, which adds to the confusion. Would it look something like this:
|-- cmd
|-- gateway_microservice
|-- main.go
|-- config_microservice
|-- main.go
|-- recommendation_microservice
|-- main.go
|-- users_microservice
|-- main.go
|-- gateway_microservice
|-- src
|-- docker
|-- config_microservice
|-- src
|-- docker
|-- recommendation_microservice
|-- src
|-- docker
|-- users_microservice
|-- src
|-- docker
What is the 'correct' or idiomatic way of structuring a project like this in Go?
The syntax of Golang is relatively small and has been used for a long time without significant changes. Since there is no need to learn new paradigms or syntax, code written in Go is transparent and easy to understand. This makes Go an ideal choice for backends, microservices, cloud computing systems, and more.
Go has many advantages over other languages in microservices development: easy code writing, high level of security, high execution speed, and law entry threshold make it unrivaled for this architecture. Microservices are successfully used in startups and large companies.
Go programs are organized into packages. A package is a collection of source files in the same directory that are compiled together. Functions, types, variables, and constants defined in one source file are visible to all other source files within the same package. A repository contains one or more modules.
I'm structuring it like this; mono-repo per. project approach. Taking into account that these services are closely related:
github.com/user/some_project/
├── pkg/ (common own-created packages for all services)
| ├── errors/
| ├── log/
| ├── metrics/
| ├── sd/
| | ├── consul/
| | └── kubernetes/
| └── tracing/
├── services/
| ├── account/
| | ├── pb/
| | | ├── account.proto
| | | └── account.pb.go
| | ├── handler.go
| | ├── main.go
| | ├── main_test.go
| | ├── Dockerfile
| | └── README.md
| ├── auth/
| ├── frontend/
| └── user/
├── vendor/ (common vendor-packages for all services)
├── docker-compose.yml
├── go.mod
├── go.sum
├── Makefile
└── README.md
Alternative 2:
github.com/user/some_project/
├── pkg/
├── service.account/
| ├─ cmd/
| | └─ main.go
| ├─ pb/
| ├─ Dockerfile
| ├─ go.mod
| └─ go.sum
├── service.auth/
├── service.frontend/
├── service.user/
├── docker-compose.yml
├── go.mod (used primarly for packages in the /pkg dir.)
├── go.sum
├── Makefile
└── README.md
With the introduction of go-modules, I'm leaning more to the second alternative.
At some later time, when you start on your second macro/micro/nano-services project, many of the these packages in the /pkg folder would be required there too. What to do? Copy/paste? No! Instead, extract these packages from the project, i.e. log, metric and make your own kit.
Remember that if you use some kind of CI/CD (you really should), you have the option to write a script placed in the project root that will only detect the changes you make in the repository, thus only the affected services will be built and delivered. There are several examples out there how to do this.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With