Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Structuring Go subpackages for teams

Tags:

We are currently moving some of our codebase to Go and are struggling a bit with a flexible directory structure for multiple devs within a team. Apologies if this is a noob question but I've searched everywhere else and not come up with an answer.

Say I have a package with the following structure:

package main  import "username/myproject/subpackage"  func main() {  } 

and a subpackage:

package subpackage  func main() {  } 

This works fine and from reading other peoples code on Github, it seems like this is the accepted way to define subpackages.

See the CoreOS source as an example: https://github.com/coreos/etcd/blob/master/main.go

My problem is that due to the directory structure of Go, these packages are stored within a specific git repo and if someone else in the team checks out this code to work on, their directory structure will be different due to forking. The username in the paths and the import statements will change. This isn't helped by the fact we pull and push a lot to each other rather than using a centralised repo.

package main  import "otherusername/myproject/subpackage" (This line will have to be changed)  func main() {  } 

Everything I have read about Go points to its usability in team environments so I'm wondering if I'm understanding the package system properly.

Ideally we would like to be able to call subpackages with relative paths. We are used to working with namespaces and I know Go doesn't have them. ie:

package main  import "myproject/subpackage"  func main() {  } 

But Go can't find the file and I'm sure it's not the right way of doing it as no examples online use relative paths.

So a couple of questions:

1) Should packages have a defined owner and always keep that username as part of the import paths?

2) Should this "owner" repo be a centalised repository (say a company or organisation) that all code is pushed to / pulled from?

3) Should other team members working on a piece of code use it within the creators folder/namespace rather than their own?

4) Is there a way to define relative paths in import statements, and if so, why does no-one do it? Is it considered bad practice?

5) How is repo forking handled with Go subpackages?

Thanks.

like image 966
Tom Jowitt Avatar asked Jul 23 '14 04:07

Tom Jowitt


1 Answers

Short version:

  1. Package should always be go gettable (work with go get package), so 99% of the time, your package will be github.com/user/reponame and you always keep that across your project.

  2. Yes, this should be the central repo and contributor (internal employee or community) should create pull request to that repo, never actually work on it.

  3. Yes, they should use it within the original folder with their git remote forked (see bellow)

  4. No and Yes. You can define relative import for non go-gettable package. I.e. when your are not in your gopath, you can import "./subpackage". However, if you go to your GOPATH, Go will complain that you mix local and remote imports. In the general case, don't use relative import.

  5. Forking of subpackage is handled by forking the main package.

Long version:

I'll take as example a Github repo with multiple team members.

Central repo would be http://github.com/central/repo

This repo has sub repos like github.com/central/repo/pkg, github.com/central/repo/whatever.

The easiest way and IMHO the best way is to use git remote.

Let's say I want to contribute to a subrepo (or anything for that matter), the process is simple: just like in any other language, fork the repo.

Now, as you mentioned, you have a copy of the repository with import which targets the central one. Not very practical to work with indeed. This is why (expect for simple small projects), I never go get my fork, I go get the central repository, go to $GOPATH/src/github.com/central/repo and add my remote with git remote add creack https://github.com/creack/repo

Now I can work on the project, use it as if it were the central one and once I am done, I push my branch to my fork, then create a pull request.

In this case, the fork is only a placeholder for the sources on github and is not used.

like image 87
creack Avatar answered Sep 29 '22 15:09

creack