48 lines
3.5 KiB
Markdown
48 lines
3.5 KiB
Markdown
# Project Structure
|
|
One of Go's strength's is its simplicity. Project structure should be kept simple as well.
|
|
|
|
### A Common Misconception
|
|
Although the [golang-standards/project-layout](https://github.com/golang-standards/project-layout) repo looks official (23k+ stars, "golang" in the name, etc), it is not. [Russ Cox](https://swtch.com/~rsc/), a principal engineer at Google and the [most active contributor](https://github.com/golang/go/graphs/contributors) to Go has opened an [issue](https://github.com/golang-standards/project-layout/issues/117) to address this.
|
|
|
|
### How Complex is Your Project?
|
|
On the complex end of the spectrum, projects like [CockroachDB](https://github.com/cockroachdb/cockroach) and [Kubernetes](https://github.com/kubernetes/kubernetes) use a complex project structure. [gorilla/mux](https://github.com/gorilla/mux) is comparatively simple. It has no dependencies and has no directory structure. Here are complexity scores for these 3 projects, and a few others, using [scc](https://github.com/boyter/scc):
|
|
|
|
| Project | Lines in .go Files | Complexity score |
|
|
| :--- | ---: | ---: |
|
|
| [Kubernetes](https://github.com/kubernetes/kubernetes) | 4,913,049 | 524,227 |
|
|
| [CockroachDB](https://github.com/cockroachdb/cockroach) | 4,064,838 | 725,465 |
|
|
| [gitea](https://github.com/go-gitea/gitea) | 223,761 | 39,001 |
|
|
| [hugo](https://github.com/gohugoio/hugo) | 148,613 | 16,642 |
|
|
| [go-github](https://github.com/google/go-github) | 117,131 | 15,637 |
|
|
| [traefik](https://github.com/traefik/traefik) | 107,542 | 9,154 |
|
|
| [gio](https://gioui.org/) | 47,283 | 5,122 |
|
|
| [gorilla/mux](https://github.com/gorilla/mux) | 6,661 | 763 |
|
|
|
|
The complexity scores are rough estimates, but are useful in realizing how complex your code is. Creating project structure is not a pure science. There is an art to knowing how to lay out a project based on its current state, and its trajectory.
|
|
|
|
If your project is simple, do not add unnecessary structure. This increases the cognitive load of anyone trying to use the project.
|
|
|
|
### Organize Code by Responsibility
|
|
When creating modules and packages, be sure to define what the package's responsibility is. This is encouraged by the standard go practice of having a [package comment](https://blog.golang.org/godoc). Difficulty in defining a responsibility/purpose is a sign of an unnecessary or too broad package.
|
|
|
|
### Package `internal`
|
|
`internal` is additional complexity, and should really only be used for packages with substantial users. If there are only a few people using the project and it is in development, it may not be necessary to use this.
|
|
|
|
[Use internal packages to reduce your public API surface](https://dave.cheney.net/2019/10/06/use-internal-packages-to-reduce-your-public-api-surface)
|
|
|
|
### Package `pkg`
|
|
`pkg` should not be used in the package path. It is redudant at best (a package path always leads to a package).
|
|
|
|
[rakyll.org](https://rakyll.org/style-packages/)
|
|
|
|
[Organzing Go Code](https://talks.golang.org/2014/organizeio.slide#6)
|
|
|
|
[What's in a Name?](https://talks.golang.org/2014/names.slide#15)
|
|
|
|
|
|
### Use Encapsulation Tools to Create Project Structure
|
|
Modules, packages, files, funcs, and structs are all encapsulation tools. Use them according to their purpose. Using a package for one exported func (and none unexported) is probably a misuse.
|
|
|
|
### Adding Complexity Should Have a Rationale
|
|
Adding packages adds complexity to your project. The onus is on the person adding the complexity to rationalize it. If there is no rationale, it should probably be removed.
|