Go Project: Difference between revisions

From NovaOrdis Knowledge Base
Jump to navigation Jump to search
 
(41 intermediate revisions by the same user not shown)
Line 1: Line 1:
=External=
=External=
* https://github.com/golang-standards/project-layout
* https://github.com/golang-standards/project-layout
* https://medium.com/@benbjohnson/standard-package-layout-7cdbc8391fc1


=Internal=
=Internal=
* [[Go_Language_Modularization#Project|Go Language Modularization]]
* [[Go_Language_Modularization#Project|Go Language Modularization]]
=TODO=
<font color=darkkhaki>
* Where are the generated executables placed? In a transient <code>./build</code>? This is how YuniKorn does it. The project layout document does not say anything about it.
</font>


=Overview=
=Overview=
This page collects recommendation and facts about Go projects and it was mainly written with the assumption that one project lives in its own repository and contains a single module, as described in [[Go_Language_Modularization#Packages.2C_Modules.2C_Projects_and_Repositories|Packages, Modules, Projects and Repositories]]. Of course project can contain multiple modules, but that is not recommended.  
This page collects recommendation and facts about Go projects and it was mainly written with the assumption that one project lives in its own repository and contains a single module, as described in [[Go_Language_Modularization#Packages.2C_Modules.2C_Projects_and_Repositories|Packages, Modules, Projects and Repositories]]. Of course project can contain multiple modules, but that is not recommended.
 
A Java-style <code>/src</code> is not recommended.


=Project Layout=
=Project Layout=
Line 15: Line 22:


  .
  .
├── [[#api|api]]
│    ├── openapi.yaml
│    ├── openapi-spec.gen.go <font color=teal># Generated from openapi.yaml</font>
│    ├── openapi-types.gen.go <font color=teal># Generated from openapi.yaml</font>
│    └── file1.proto, ...
├── [[#Protocol_Buffer|protobuf]] <font color=teal># Alternative directory for Protocol Buffer files.</font>
│    ├── somepkgpb
│    │    ├── file1.proto
│    │    └── file2.proto
│    └── someotherpkgpb
│        ├── file3.proto
│        └── file4.proto
  ├── [[#cmd|cmd]]
  ├── [[#cmd|cmd]]
  │    ├── myserver  
  │    ├── myserver  
Line 21: Line 41:
  │        └── main.go
  │        └── main.go
  ├── [[#pkg|pkg]]
  ├── [[#pkg|pkg]]
  ├── [[#internal|internal]]
  ├── [[#internal_dir|internal]]
│    └── server
│        └── openapi-http-server.gen.go <font color=teal># Generated from openapi.yaml</font>
├── [[#config|config]]
  ├── [[#scripts|scripts]]
  ├── [[#scripts|scripts]]
│    ├── build-myserver.sh
│    └── build-myclient.sh
├── [[#docs|docs]]
  ├── Makefile
  ├── Makefile
  ├── README.md
  ├── README.md
Line 32: Line 58:


==Directories==
==Directories==
===<tt>api</tt>===
The directory contains OpenAPI specification files, JSON schema files, protocol definition files.
One option is to also place the type and the spec files generated by the OpenAPI code generator, as shown in the layout [[#Project_Layout|above]]. For more details on how to generate code from the OpenAPI specification, see: {{Internal|Oapi-codegen#Generate_Code|Generate Code with <tt>oapi-codegen</tt>}}
====<span id='Protocol_Buffer'></span>Protocol Buffer Support====
Protocol Buffer files can be placed in this directory. Alternatively, a <code>protobuf</code> or a <code>protocol</code> can be used. Also see: {{Internal|Protocol_Buffers_Data_Type_Go_Code_Generation#Code_Generation|Protocol Buffers Go Code Generation}}
===<tt>cmd</tt>===
===<tt>cmd</tt>===


The directory contains the main applications for this project. If the project has multiple executables, their code should live under their own directory, and the name of the directory should match the name of the executable. The Go code file name can be either <code>main.go</code> (preferred) or the name of the command (<code>myserver.go</code>). Different projects use one of these two conventions. Do not put a lot of code in the <code>/cmd</code> directory. If you think the code can be imported and used in other projects, put it in the <code>[[#pkg|/pkg]]</code> directory. If the code is not reusable, put it in the <code>[[#internal|/internal]]</code> directory. It's common to have a small <code>main</code> function that imports and invokes the code from the <code>/internal</code> and <code>/pkg</code> directories and nothing else.
The directory contains the main applications for this project. If the project has multiple executables, the code fore each should live under their own directory, and the name of the directory should match the name of the executable. This convention aligns with the behavior of the <code>go build</code> command, which [[Go_build#Executable_Name|names the executable after the name of its parent directory]]. The Go code file name can be either <code>main.go</code>, which is preferred, or the name of the command <code>myserver.go</code>. Different projects use one of these two conventions. Do not put a lot of code in the <code>/cmd</code> directory. If you think the code can be imported and used in other projects, put it in the <code>[[#pkg|/pkg]]</code> directory. If the code is not reusable, put it in the <code>[[#internal|/internal]]</code> directory. It's common to have a small <code>main</code> function that imports and invokes the code from the <code>/internal</code> and <code>/pkg</code> directories and nothing else.


====<tt>main.go</tt>====
====<tt>main.go</tt>====
Line 49: Line 83:


===<tt>pkg</tt>===
===<tt>pkg</tt>===
===<tt>internal</tt>===
Place here the packages publicly exported by the module. The presence of a package in this directory shows that it is OK to be used by external applications. Other projects will import these libraries expecting the to work, so think twice before putting something there. The <code>[[#internal_dir|internal]]</code> directory is a better way to ensure your private packages are not importable, because this is enforced by the complier.
 
===<span id='internal_dir'></span><tt>internal</tt>===
This is the module code that shouldn't be imported by the module's dependent application or libraries. This layout pattern is enforced by the Go compiler. For more details, see: {{Internal|Go_Packages#Internal_.28Private.29_Packages|Internal (Private) Packages}}
 
===<span id='config_dir'></span><tt>config</tt>===
 
Configuration file templates and default configuration.
 
===<tt>scripts</tt>===
===<tt>scripts</tt>===


Line 55: Line 97:


They should be used by <code>[[#Makefile|Makefile]]</code>, which will keep the file small and simple.
They should be used by <code>[[#Makefile|Makefile]]</code>, which will keep the file small and simple.
===<tt>docs</tt>===
Generated documentation, user documentation, design documentation.
==Files==
==Files==
===<tt>Makefile</tt>===
===<tt>Makefile</tt>===
Line 61: Line 108:


<syntaxhighlight lang='make'>
<syntaxhighlight lang='make'>
.PHONY: build dwm
.PHONY: build


build: myserver myclient
build: myserver myclient
Line 74: Line 121:


<font color=darkkhaki>Example to process: https://github.com/hashicorp/terraform/blob/main/Makefile</font>
<font color=darkkhaki>Example to process: https://github.com/hashicorp/terraform/blob/main/Makefile</font>
===Generated Code===
Placed within the regular layout, though files have a <code>.gen.go</code> extension.
=Project Bootstrap=
<font color=darkkhaki>Follow the same template as [[Python_Project_Layout#Project_Bootstrap|Python Project Bootstrap]]. Use and possibly merge with [[Go.mod#Initialize_go.mod]]</font>


=Microservice-based Project Layout=
=Microservice-based Project Layout=
{{Internal|Microservices_in_Go#Project_Layout|Microservices in Go &#124; Project Layout}}
{{Internal|Microservices_in_Go#Project_Layout|Microservices in Go &#124; Project Layout}}
=TODO=
=TODO=


<font color=darkkhaki>
<font color=darkkhaki>
Integrate [[Go_Packages#Vendoring|Vendoring]].
* Finish parsing https://github.com/golang-standards/project-layout
* Integrate [[Go_Packages#Vendoring|Vendoring]]
</font>
</font>

Latest revision as of 19:11, 19 September 2024

External

Internal

TODO

  • Where are the generated executables placed? In a transient ./build? This is how YuniKorn does it. The project layout document does not say anything about it.

Overview

This page collects recommendation and facts about Go projects and it was mainly written with the assumption that one project lives in its own repository and contains a single module, as described in Packages, Modules, Projects and Repositories. Of course project can contain multiple modules, but that is not recommended.

A Java-style /src is not recommended.

Project Layout

This layout is inspired by:

https://github.com/golang-standards/project-layout

.
├── api
│    ├── openapi.yaml
│    ├── openapi-spec.gen.go # Generated from openapi.yaml
│    ├── openapi-types.gen.go # Generated from openapi.yaml
│    └── file1.proto, ...
├── protobuf # Alternative directory for Protocol Buffer files.
│    ├── somepkgpb
│    │    ├── file1.proto
│    │    └── file2.proto
│    └── someotherpkgpb
│         ├── file3.proto
│         └── file4.proto
│
├── cmd
│    ├── myserver 
│    │    └── main.go
│    └── myclient
│         └── main.go
├── pkg
├── internal
│    └── server
│         └── openapi-http-server.gen.go # Generated from openapi.yaml
├── config
├── scripts
│    ├── build-myserver.sh 
│    └── build-myclient.sh 
├── docs
├── Makefile
├── README.md
├── go.mod
├── go.sum
└── .gitignore


Directories

api

The directory contains OpenAPI specification files, JSON schema files, protocol definition files.

One option is to also place the type and the spec files generated by the OpenAPI code generator, as shown in the layout above. For more details on how to generate code from the OpenAPI specification, see:

Generate Code with oapi-codegen

Protocol Buffer Support

Protocol Buffer files can be placed in this directory. Alternatively, a protobuf or a protocol can be used. Also see:

Protocol Buffers Go Code Generation

cmd

The directory contains the main applications for this project. If the project has multiple executables, the code fore each should live under their own directory, and the name of the directory should match the name of the executable. This convention aligns with the behavior of the go build command, which names the executable after the name of its parent directory. The Go code file name can be either main.go, which is preferred, or the name of the command myserver.go. Different projects use one of these two conventions. Do not put a lot of code in the /cmd directory. If you think the code can be imported and used in other projects, put it in the /pkg directory. If the code is not reusable, put it in the /internal directory. It's common to have a small main function that imports and invokes the code from the /internal and /pkg directories and nothing else.

main.go

Some project name this file myserver.go.

package main

import "fmt"

func main() {
  fmt.Print("starting my service ...\n")
}

pkg

Place here the packages publicly exported by the module. The presence of a package in this directory shows that it is OK to be used by external applications. Other projects will import these libraries expecting the to work, so think twice before putting something there. The internal directory is a better way to ensure your private packages are not importable, because this is enforced by the complier.

internal

This is the module code that shouldn't be imported by the module's dependent application or libraries. This layout pattern is enforced by the Go compiler. For more details, see:

Internal (Private) Packages

config

Configuration file templates and default configuration.

scripts

This directory contain scripts to perform various build functions, install, analysis, etc.

They should be used by Makefile, which will keep the file small and simple.

docs

Generated documentation, user documentation, design documentation.

Files

Makefile

Makefile should prefer to use scripts from the /scripts directory, which should keep it simple.

.PHONY: build

build: myserver myclient

myserver:
	"$(CURDIR)/scripts/build-myserver.sh"

myserver:
	"$(CURDIR)/scripts/build-myclient.sh"

Example to process: https://github.com/hashicorp/terraform/blob/main/Makefile

Generated Code

Placed within the regular layout, though files have a .gen.go extension.

Project Bootstrap

Follow the same template as Python Project Bootstrap. Use and possibly merge with Go.mod#Initialize_go.mod

Microservice-based Project Layout

Microservices in Go | Project Layout

TODO