gogo-get

Golang subproject or submodule dependency


What is the recommended way in Golang to download a submodule of a dependency? I think my question can be best described by examples.

Example #1:

I have a client and a server. My server is an API and has a bunch of other dependencies, such as databases, messages queues, consul, and etc. I would like my client to be a lightweight package where users download only few dependencies needed for the client.

You could say that the client and server can be on separate repositories. However, there may also be some common code amongst them, which if we follow this pattern, would again be another repository.

I'm thinking of some structure that looks like this:

service/
---> common/
------> redis.go
------> kafka.go
---> client/
------> client.go
---> server/
------> database/
------> swagger/
------> producer/
------> etc/

Example #2:

It's pretty common for projects to share models. If we have microservices that communicate through message brokers with a common model, we'd probably want some structure like this.

service/
---> model/
------> message.go
---> service1/
---> service2/

Comparison to other languages

I am from a Scala/Java background and have started to use Golang less than a month. Comparing with Scala, I could have handled this in two ways. Let's take Example #2

  1. Publish model as its own jar and import model.jar in each service
  2. Use multi-project setup in sbt: https://www.scala-sbt.org/1.x/docs/Multi-Project.html.

Some Things I Explored in Go

  1. https://blog.gopheracademy.com/advent-2015/vendor-folder/
  2. https://github.com/golang/go/wiki/Modules#faqs--multi-module-repositories

But so far they don't seem to solve my question

Final Question

What is the recommended way in Golang to tackle the issues I stated in the examples?

Thank you for your help!


Solution

  • Generally, try to stick to one repo and one module, as much as possible. Splitting your codebase to multiple repos and/or multiple modules incurs costs that will grow over time. You'll need to define clear version dependencies between your own modules, do phased upgrades carefully, etc. Especially for small-to-medium projects, one repo and one module is the best way to go.

    Regarding your specific requirement in Example 1, if it's critical for the users of "client" to not pull "server" code, then client and server will have to be in separate modules. These modules can be either in the same repo or in different repos - this makes no difference to Go. The common code will have to be in a module of its own, e.g.:

    github.com/user/myrepo/
      client/
        go.mod
      server/
        go.mod
      common/
        go.mod
    

    Then, a module using your client would have, in their go.mod:

    require github.com/user/myrepo/client <version>
    

    And this will pull in client and common, but not server.

    If it's OK for server to depend on client, you could potentially make common part of client, though I'm not sure this would save much.

    For Example 2 the idea is similar - common code can go into its own module.


    I strongly recommend you read the official blog posts on Using Go Modules.

    For a simple Go project layout with modules, see this post