My understanding of how to structure a golang project.

Overview

Go Project Layout

This is my understanding of how to structure Go project layout. The most important part is how to organize your Go code into packages.

Motivation

A good project layout will make your source code easy to understand, easy to test, and easy to maintain.
Kat Zien has a very good summary(Slides) for this, so I'd like to refer it directly as below:

Questions, decisions

  • Should I put everything in the main package?
  • Should I start with one package and extract other packages over time?
  • How do I decide if something should be in its own package?
  • Should I just use a framework?
  • What's the programming paradigm for Go?
  • Microservices or monolith?
  • How much should be shared between packages?

Why should we care?

Because if Go is going to be a language that companies invest in for the long term, the maintenance of Go programs, the ease of which they can change, will be a key factor in their decision. - Dave Cheney, Golang UK 2016 keynote

Good structure goals

  • Consistent.
  • Easy to understand, navigate and reason about. ("makes sense") Easy to change, loosely-coupled.
  • Easy to test.
  • "As simple as possible, but no simpler."
  • Design reflects exactly how the software works.
  • Structure reflects the design exactly.

Demo

# shell 1
$ go version
go version go1.13.1 linux/amd64
$
$ cd $GOPATH
$ 
$ # app 1: reverse echo
$ go get -u github.com/wangyoucao577/go-project-layout/cmd/echor
$ ./bin/echor "hello world"
dlrow olleh
$
$ # app 2: a simple diagnosis service for server diagnosis. 
$ #    return `Hostname/IP/CPUs/RemoteAddr...` by `HTTP`. 
$ #    sample request: `http://localhost:8000/diagnosis?diagnosis=ping`
$ go get -u github.com/wangyoucao577/go-project-layout/cmd/diagnosis
$ ./bin/diagnosis -alsologtostderr
I1007 18:50:05.550952    3769 main.go:33] Listen on :8000

# shell 2
$ curl "http://localhost:8000/diagnosis?diagnosis=ping"
{
  "Hostname":"server",
  "IP Addresses":[
    "192.168.29.201/24",
    "fe80::1c20:479:9094:4327/64",
    "192.168.141.1/24",
    "fe80::8002:2d87:c4f3:4aab/64",
    "192.168.128.1/24",
    "fe80::eca9:cfa0:9443:b8ff/64",
    "192.168.44.209/28",
    "fe80::8551:306e:7e7:6faf/64"
  ],
  "CPUs":8,
  "Remote Endpoint":"127.0.0.1:64717"
}

Note

This topic is kind of best practices. I'd like to discuss some of them and my opinion, then maybe deep into more best practices in the future.

Top dir /cmd

[My opinion: Strongly recommended]
The cmd layout pattern is very useful when you need to have more than one application binary.

  • Each binary gets a subdirectory (e.g., your_project/cmd/your_app).
    • The subdirectory is the main package for your application.
    • Don't put a lot of code in the main package. Instead, it should only used to initialises and ties everything together.
  • This patterns also helps you keep your project/package go gettable.
    • It means you can use the go get command to fetch (and install) your project, its applications and its libraries (e.g., go get github.com/your_github_username/your_project/cmd/your_app).
  • The official Go tool is one example of the cmd layout patter. A number of other well known projects use the same pattern: Kubernetes, Docker, Prometheus, Influxdb.

Top dir /pkg

[My opinion: NOT good enough, use it if good for you]

  • People also recommend to set up a /pkg top dir in Go project to put your public libraries.
    • These libraries can be used internally by your application.
    • They can also be used by external projects. It's an informal contract between you and other external users of your code. Other projects will import these libraries expecting them to work.
  • But I think it's NOT a good enough idea because
    • It brings confusion since Go workspaces have a directory with the same name and that directory has a different purpose(it’s used to store object files for the packages the Go compiler builds).
    • The meaning of "public libraries" is not clear enough.
      • Even many well known projects use this pattern (Kubernetes, Docker, Grafana, Influxdb, Etcd), Docker and Etcd comment the meaning of "public libraries" again. Both of them limit it only as utility packages, and these utility packages possible to be moved out into its own repository in the future:
        • Docker: pkg/ is a collection of utility packages used by the moby project without being specific to its internals.
        • Etcd: pkg/ is a collection of utility packages used by etcd without being specific to etcd itself. A package belongs here only if it could possibly be moved out into its own repository in the future.

Group packages by dependency

[My opinion: Strongly recommended]

  • Domain types
    • Domain Types are types that model your business functionality and objects.
    • Ben Johnson - Standard Package Layout recommend to place your into root package. This package only contains simple data types, so it will be extremely simple.
    • In my opinion, either place them into root package or place them into a individual subpackage are ok. The most important part here is this package should be extermely simple, and not depend on any other package in application!
  • Each package should only has a single purpose.
  • Packages names describe their purpose.
  • When necessary, use a descriptive parent package and several children implementing the functionality.
  • main package ties together dependencies

More best practices

  • Follow conventions
    • Be similar to the standard library and other popular packages
    • Don't surprise people
    • Be obvious, not clever
  • Use Go modules
  • Avoid global scope and init()

References

Owner
Jay Zhang
Jay Zhang
create boilerplate structure for neovim plugins

boilit Boil yourself a sweet plugin Installation • Usage Ain't nobody got time to create plugin directories: boilit yourself! boilit creates boilerpla

Gennaro Tedesco 31 Jan 20, 2022
Lynx is a command line application that build simple golang project

Lynx Lynx is a Golang application for easily creating simple Go project Install Just run below commands for install lynx in your system go get -u gith

hossein varmazyar 3 Oct 1, 2021
Golang project for looking up geo from an IP. Meant to be deployed on Render.

geoip-render-go Golang project for looking up geo from an IP. Meant to be deployed on Render. Dependencies In order to use this project, you'll need a

Kirk Morales 0 Dec 6, 2021
Gocheat - Golang terminal client for cht.sh that uses charm.sh's bubbletea project

Go Cheat.sh install gotext go get -u golang.org/x/text/cmd/gotext go generate

Cyber Oliveira 20 Jan 9, 2022
This project is used to get familiar with GoLang cli apps, along with cobra generator.

SecretCTL SecretCTL About the project Status Getting started Layout Notes About the project This project is used to get familiar with GoLang cli apps,

Milos Folic 0 Jan 11, 2022
A general purpose project template for golang CLI applications

golang-cli-template A general purpose project template for golang CLI applications golang-cli-template Features Project Layout How to use this templat

Joshua Murphy 0 Jan 15, 2022
Idiomatic Go input parsing with subcommands, positional values, and flags at any position. No required project or package layout and no external dependencies.

Sensible and fast command-line flag parsing with excellent support for subcommands and positional values. Flags can be at any position. Flaggy has no

Eric Greer 774 Jan 11, 2022
Moldy CLI the best project starter and manager of the world

You don't know how to start your project ... you want to help other people know your tool or language. Use Moldy! the best helper to start your project

Moldy Community 22 Jan 5, 2022
✨ Create a new production-ready project with backend, frontend and deploy automation by running one CLI command!

✨ Create a new production-ready project with backend, frontend and deploy automation by running one CLI command!

Create Go App 1.2k Jan 14, 2022
Sotardok generator project

bagong Generate template add template base bagong template add --name project_name --value template_location get template bagong template get --name

Andree Panjaitan 1 Oct 20, 2021
A project templating CLI tool.

Clonr Project Templating CLI About Installation Homebrew Go install npm Quick start for developers Configuring a project. Basic Example Example With G

null 2 Jan 15, 2022
Code examples for Algorithm Analysis and design (CS311) [School project]

Introduction Algorithm Analysis and design 2021/2022 Code examples implemeneted using golang Why Golang? Low Level programming language Awesome garbag

Mohammad Salah 0 Dec 5, 2021
Show Languages In Code. A fast and lightweight CLI to generate stats on the languages inside your project

slic Show Languages In Code. Usage Run it with an -h flag to list all commands. -d flag can be used to specify the directory of search -i flag can be

Saurav Pal 3 Dec 25, 2021
One-line-at-a-time was a hobby project inspired by the character Dwight K. Schrute of 'The Office'

One Line at a Time Introduction One-line-at-a-time was a hobby project inspired by the character Dwight K. Schrute of 'The Office'. His efficient usag

Emily Ford 1 Dec 13, 2021
GO project that retrieve and return weather data from airports sensors

Airport Project GO project that retrieve and return weather data from airports sensors (temperature, wind speed and atmospheric pressure). Built with

Anton Mestre 1 Jan 15, 2022
StudentMgmtSystem - Project for Student Management System and use of CURD Operation

StudentMgmtSystem Project for Student Management System and use of CURD Operatio

null 0 Jan 4, 2022
Argparse for golang. Just because `flag` sucks

Golang argparse Let's be honest -- Go's standard command line arguments parser flag terribly sucks. It cannot come anywhere close to the Python's argp

Alexey Kamenskiy 392 Jan 6, 2022
Golang library with POSIX-compliant command-line UI (CLI) and Hierarchical-configuration. Better substitute for stdlib flag.

cmdr cmdr is a POSIX-compliant, command-line UI (CLI) library in Golang. It is a getopt-like parser of command-line options, be compatible with the ge

hz 92 Jan 13, 2022