Learning Golang from Python (II) - Project structure
In the previous post, I went into details on how to make golang work like python. After reading up a lot, I came to sense that the best way to learn golang is to unlearn how things are done in python and learn the way of Go.
In python, I tend to have a nested workspace where I group various related modules together.
├── dist ├── private │ ├── app.py │ ├── handlers │ │ └── user.py │ └── models │ └── user.py └── venv
In Go, it is better to deal with a flat structure than a nested one. In order for nested structure in golang, you will have to perform absolute import, as golang do not support relative import. This is actually problematic because you will have to assume the location of the project and also where you are hosting it.
Another thing that I ended up with is to set a default GOPATH for my binary, and generic golang modules. This is where I install all my global packages that I commonly used.
On top of the default GOPATH, I also have a generic workspace for testing small go snippet.
$GOPATH ├── pkg ├── bin └── src ├── project1 ├── project2 └── project3
Golang requires your code to be in $GOPATH/src before it can run, something that takes a while to get used to coming from Python.
After looking at a lot of open source projects, I realized that most of them do one thing and only have a couple of files in them. This allow them to have a relatively flat structure.
But what if the project is big and we want to break the code into sub-modules/folders ?
Well, there are few ways that I found.
Split into multiple projects
If you can split your stuffs into logical modules, this will be a good solution.
A good example is gorilla web tookkit. This is a macro-framework but because it is broken down into modules, you can use them like micro-framework.
Subfolders but with absolute imports
I personally don’t like this approach as it requires aboslute import.
The main example we have is hugo.
The pros for this approach is that you get to have all in one repo, and have nice sub folders.
However, the problem is that you will have to include the hosting platform like “github.com” in the import statement in order for
go get to work.
This also means that you will not be able to use
go get on a fork of a project, which might be something that you want.
The next approach is to put the subfolders inside the vendor folder
$GOPATH ├── pkg ├── bin └── src └── project1 ├── main.go └── vendor └── module └── user.go
This is actually not a bad idea, although vendor isn’t really meant for this.
On top of that, nesting inside vendor is not the nicest thing to see.
go get is not a requirement, this might be a good solution.
project_root ($GOPATH) ├── .git ├── bin ├── pkg └── src ├── web ├── models └── logic
This allow you to put all the files for the project in a single repo. To start working, you will need to add the project_root to the GOPATH.
This will then allow you to input models and logic from any code in web.
go get will definitely not work in this case.
I am learning to start from 0 when it comes to golang, trying not to bring too many ideas/conventions from other languages into golang.
As for the project structure, I really have nothing against the few solutions I listed above, except for the absolute import.
All other approaches has their uses, and mostly depend on the size of the project and if you really have the need for
PS: I also started committing a lot of simple golang code into a learning github repo.