[go] Organizing a multiple-file Go project

Note: this question is related to this one, but two years is a very long time in Go history.

What is the standard way to organize a Go project during development ?

My project is a single package mypack, so I guess I put all the .go files in a mypack directory.

But then, I would like to test it during development so I need at least a file declaring the main package, so that I can do go run trypack.go

How should I organize this ? Do I need to do go install mypack each time I want to try it ?

This question is related to go

The answer is


I find very useful to understand how to organize code in Golang this chapter http://www.golang-book.com/11 of the book written by Caleb Doxsey


I have studied a number of Go projects and there is a fair bit of variation. You can kind of tell who is coming from C and who is coming from Java, as the former dump just about everything in the projects root directory in a main package, and the latter tend to put everything in a src directory. Neither is optimal however. Each have consequences because they affect import paths and how others can reuse them.

To get the best results I have worked out the following approach.

myproj/
  main/
    mypack.go
  mypack.go

Where mypack.go is package mypack and main/mypack.go is (obviously) package main.

If you need additional support files you have two choices. Either keep them all in the root directory, or put private support files in a lib subdirectory. E.g.

myproj/
  main/
    mypack.go
  myextras/
    someextra.go
  mypack.go
  mysupport.go

Or

myproj.org/
  lib/
    mysupport.go
    myextras/
      someextra.go
  main/
    mypack.go
  mypage.go

Only put the files in a lib directory if they are not intended to be imported by another project. In other words, if they are private support files. That's the idea behind having lib --to separate public from private interfaces.

Doing things this way will give you a nice import path, myproj.org/mypack to reuse the code in other projects. If you use lib then internal support files will have an import path that is indicative of that, myproj.org/lib/mysupport.

When building the project, use main/mypack, e.g. go build main/mypack. If you have more than one executable you can also separate those under main without having to create separate projects. e.g. main/myfoo/myfoo.go and main/mybar/mybar.go.


Keep the files in the same directory and use package main in all files.

myproj/
   your-program/
      main.go
      lib.go

Then run:

~/myproj/your-program$ go build && ./your-program

Let's explorer how the go get repository_remote_url command manages the project structure under $GOPATH. If we do a go get github.com/gohugoio/hugo It will clone the repository under

$GOPATH/src/repository_remote/user_name/project_name


$GOPATH/src/github.com/gohugoio/hugo

This is a nice way to create your initial project path. Now let's explorer what are the project types out there and how their inner structures are organized. All golang projects in the community can be categorized under

  • Libraries (no executable binaries)
  • Single Project (contains only 1 executable binary)
  • Tooling Projects (contains multiple executable binaries)

Generally golang project files can be packaged under any design principles such as DDD, POD

Most of the available go projects follows this Package Oriented Design

Package Oriented Design encourage the developer to keeps the implementation only inside it's own packages, other than the /internal package those packages can't can communicate with each other


Libraries

  • Projects such as database drivers, qt can put under this category.
  • Some libraries such as color, now follows a flat structure without any other packages.
  • Most of these library projects manages a package called internal.
  • /internal package is mainly used to hide the implementation from other projects.
  • Don't have any executable binaries, so no files that contains the main func.

 ~/$GOPATH/
    bin/
    pkg/
    src/
      repository_remote/
        user_name/
            project_name/
              internal/
              other_pkg/

Single Project

  • Projects such as hugo, etcd has a single main func in root level and.
  • Target is to generate one single binary

Tooling Projects

  • Projects such as kubernetes, go-ethereum has multiple main func organized under a package called cmd
  • cmd/ package manages the number of binaries (tools) that we want to build

 ~/$GOPATH/
    bin/
    pkg/
    src/
      repository_remote/
        user_name/
            project_name/
              cmd/
                binary_one/
                   main.go
                binary_two/
                   main.go
                binary_three/
                   main.go
              other_pkg/

There doesn't seem to be a standard way of organizing Go projects but https://golang.org/doc/code.html specifies a best practice for most projects. jdi's answer is good but if you use github or bitbucket and you have additional libraries as well, you should create the following structure:

~/projects/
bin/
pkg/
src/
  github.com/
    username/
        mypack/
            foo.go
            bar.go
            mypack_test.go
        mylib/
            utillib.go
            utillib_test.go

By doing it this way, you can have a separate repository for mylib that can be used for other projects and can be retrieved by "go get". Your mypack project can import your library using "github.com/username/mylib". For more information:

http://www.alexvictorchan.com/2014/11/06/go-project-structure/


jdi has the right information concerning the use of GOPATH. I would add that if you intend to have a binary as well you might want to add one additional level to the directories.

~/projects/src/
    myproj/
        mypack/
            lib.go
            lib_test.go
            ...
        myapp/
            main.go

running go build myproj/mypack will build the mypack package along with it's dependencies running go build myproj/myapp will build the myapp binary along with it's dependencies which probably includes the mypack library.