Go Modules - naming convention of directories and packages

20,200

Approach 2 is correct.

Being a Go newbie, I had mistakenly thought that Approach 1 was one possible way, as Go does allow having package name different from directory name.

As Volker helped in the comments, Approach 1 is definitely not possible.
You will get a straight compilation error when trying to combine packages.

compilation error

The introduction of Go Modules does not affect the best practices outlined in existing documents, such as:

As a side note, I also came to know that package name should be singular form.

So that would leave me with the following structure along with Approach 2:

structure following the convention

Share:
20,200
Ryota
Author by

Ryota

Updated on October 12, 2020

Comments

  • Ryota
    Ryota over 3 years

    I understand Go Modules are yet an experimental opt-in feature, and perhaps because of that, I cannot find clear guidance on how to name directories and packages.
    In these Package names in Go Blog post and Package name in Effective Go, they talk about that the directory should match the package name - but I wasn't certain if Go Modules would follow the same pattern.

    If I want to bundle my business logic in package business with many files, is it reasonable to create subdirectory validators/ and keep the same package name package business?

    someDir
    ├── business
    │   ├── businessA.go // package business
    │   ├── businessB.go // package business
    │   ├── businessC.go // package business
    │   └── validators
    │       ├── businessValidatorX.go // package business, or validators?
    │       ├── businessValidatorY.go // package business, or validators?
    │       └── businessValidatorZ.go // package business, or validators?
    ├── go.mod   // module example.com
    └── main.go
    

    Approach 1.

    If I were to go with the same package name:

    // main.go
    package main
    
    import (
            "example.com/business"
            "example.com/business/validators"
    )
    
    // both imports would be combined to the same `business` package?
    func main() {
            b := business.SomeLogic()
            business.ValidateX(b) // validator from the same package
    }
    

    This looks to be prone to export conflict - but it is simple.

    Approach 2.

    If the validators/ path maps to package validators, the consuming code would look like the below instead.

    // main.go
    package main
    
    import (
            "example.com/business"
            "example.com/business/validators"
    )
    
    func main() {
            b := business.SomeLogic()
            validators.ValidateX(b) // validator from a separate package
    }
    

    How should I manage a package consisted of many files? Is the Approach 1. reasonable, although it somewhat contradicts from the blog post and doc above?
    Or should I go with Approach 2., complying with the convention, and add an alias as necessary in main.go?

  • Volker
    Volker over 5 years
    Well, I have to disappoint you. This answer is technically not correct as approach 1 is possible. You see, I lied in my comment above. Nevertheless my advice and your conclusion are 100% valid. There is just one golden way to structure your code layout and build your packages and projects. This is explained in How to Write Go Code and perfectly illustrated by the stdlib and the rest of the supporting Go repos and everybody should follow this advice and nothing else.
  • Volker
    Volker over 5 years
    But: It is technically not true. Instead of building your code with the go tool one can invoke the compiler and linker manually (or typically through a makefile or some other build tooling) and this allows to combine arbitrary files into one package. Nobody sane does this ever as this break each and every Go tool in the world, but it is possible and it is done.
  • Ryota
    Ryota over 5 years
    Hmm, that is an eyeopening point. As I find Go having golden rules and being opinionated how things should be done, I appreciate how the community can heavily rely on the conventions, more so than other languages IMO. Working around the go tools is probably beyond the scope of the original question, but certainly a valid point.