henning77
henning77

Reputation: 3844

Golang code organization for multi-platform multi-language project

I am looking for a good project organization for a multi-platform project with multiple components written in Go. I am aware of the recommended layout from http://golang.org/doc/code.html, but the layout suggested there does not seem to fit my requirements.

Project components are:

My requirements are:

My current approach:

project/ (this is the repository root)
  server/
    server.go (package main)
    src/          
      server/
        package1/
          package1.go
        ...
  client/
    client.go (package main)
    src/
      client/
        package2/
          package2.go
        ...
  lib/
    src/
      lib/
         lib.go
         ...
  client-ios/
    ...
  client-android/
    ...

To build, I use a Makefile which

  1. Copies lib/ into both server/ and client/
  2. Builds server/ and client/ separately, setting GOPATH every time to the respective directory.

It works, but feels really klunky and is quite different to the recommended code layout.

Here is the alternative I am considering:

project/ (this is the repository root)
  gospace/
    src/
      server/...
      client/...
      lib/...
  client-ios/
    ...
  client-android/
    ...

With this layout I have a single GOPATH (gospace/) and don't need the klunky Makefile. However, the components are not separated as neatly as in the first alternative (i.e. via a top level directory).

My question: Which project layout would be best suited for both my requirements and Go conventions and tooling support? Are there better options which I did not see yet?

Upvotes: 8

Views: 4254

Answers (2)

goddtriffin
goddtriffin

Reputation: 155

It's been a long time since this question was answered (last comment on OP was Feb. 12, 2014, and the latest answer was Apr. 16, 2014). I wasn't around for the state of Go at that time, only really being introduced to it in 2018/19, yet it looks like a lot has changed.

The biggest change that influences the answer to this post, I believe, is Go Modules.

I have a similar project in the works (Go server, Go CLI, Android app, iOS app). I am currently using go version go1.13.7 darwin/amd64. Here is the structure I came with via Go Modules (very much influenced by this post by Ben Johnson):

directory-outside-GOPATH/
    go.mod
    go.sum
    domaintypes.go
    cmd/
        api/
            main.go
        cli/
            main.go
    postgres/
        ...(library Go code)...
    http/
        ...(library Go code)...
    android/
        ...(Android app)...
    iOS/
        ...(iOS app)...
    ...(other Go code).../
        ...

The root directory sits outside of the GOPATH and includes the necessary go.mod and go.sum files. The domaintypes.go file is to illustrate that the only Go files I leave in the root directory is code that will never import anything else - such as defining your domain types/models/service-interfaces/etc. I personally have multiple: user.go, group.go, etc.

The postgres and http directories are libraries I have written, both of which are layered adapters. Each library directory should be isolated to its domain. e.g. HTTP routes should not directly interact with database connections.

The cmd directory is where all executable Go code should live. I want an API server and a separate CLI so this is where that lives. These files should remain relatively small and call all of the other libraries you wrote.

As for the non-Go code, I simply created separate directories in the root directory for both Android and iOS.

Upvotes: 3

OneOfOne
OneOfOne

Reputation: 99431

This is how I organized a similar project :

$GOPATH/src/project-root/
    lib.go
    lib_test.go

    server/
        server.go
        server_test.go

        main/
            server.go // package main; import "project-root/server"

    client/
        client.go
        client_test.go

        main/
            client.go //package main; import "project-root/client"

    client-ios/
        ....

    client-android/
        ....

While mostly having server/server.go and client/client.go as package main should work, it's better to separate it so you could embed the client/server in other projects.

Upvotes: 6

Related Questions