Go Naming Conventions: A Practical Guide

Go Naming Conventions: A Practical Guide

Package, interface, function and variable naming in Go, with the rules that matter and the habits worth dropping.

In the world of software development, choosing the right naming conventions is path to unlocking the gateway to readable and maintainable code. Go has seen massive adoption and development in past few years. Go embraces a set of naming conventions designed to promote simplicity, collaboration, and elegance in codebases.

“There are only two hard things in Computer Science: cache invalidation and naming things.” — Phil Karlton

Naming conventions play a significant role in writing clean and readable code. It is a practice of using meaningful identifiers in the code that describes the purpose of the variable, function, or type. Purpose of these conventions is to make the code easier to understand and maintain. These are the fundamental blocks to writing good code that leads to fewer errors. This also helps in long term maintainability of large sized projects.

In this blog post, we will deep dive into best practices for naming in Go. We will explore the significance of clear and concise naming choices along with practical examples. By the end, you'll gain a deeper understanding of how Go's naming conventions contribute to code readability, ease of collaboration, and the overall development experience. Let's get started!

Writing is easy, but reading is painful!


Package naming

Alan Donovan, co-author of "The Go Programming Language," advises, Choose package names that will sound natural in a sentence. This approach fosters clarity and ensures intuitive import statements throughout your codebase.

Package name should be:

  • good: short, concise, evocative.
  • by convention, packages are given lower case, single-word names;
  • no need for underscores or mixedCaps
  • common practise is to use package name as the base name of its source directory

Another convention is that the package name is the base name of its source directory; the package in src/encoding/base64 is imported as "encoding/base64" but has name base64, not encoding_base64 and not encodingBase64.

Point to Remember

When importing a package, package name is used to refer to it's content, hence exported names in the package can use that fact to avoid repetition.

Eg. The function to make new instances of user.User would normally be called NewUser, but since User is the only type exported by the package, and since the package is called user, it's called just New, which clients of the package see as user.New. This does sound natural in a sentence.


Interface naming

  • Use a noun or noun phrase as the name
  • One-method interfaces are named by the method name plus an -er suffix or similar modification to construct a noun. Eg. Reader, Writer, etc.
  • use MixedCaps or mixedCaps rather than underscores to write multiword names.
  • Skip the I prefix (IUser) and the Interface suffix (UserInterface). Both are Java and C# habits, and neither is idiomatic Go. UserService reads better than IUserService.

File Naming

  1. Generally, file names are single lowercase words.
  2. Go follows a convention where source files are all lower case with underscore separating multiple words.
  3. Compound file names are separated with _
  4. File names that begin with “.” or “_” are ignored by the go tool
  5. Test files in Go come with suffix _test.go . These are only compiled and run by the go test tool.
  6. Files with os and architecture specific suffixes automatically follow those same constraints, e.g. name_linux.go will only build on linux, name_amd64.go will only build on amd64.

Functions and Variables

  • Use camel case, exported functions and variables start with uppercase. (unexported/private are lowercase)
  • Constants use MixedCaps too. Write MaxRetries, not MAX_RETRIES; the underscore style is a C convention that Go does not use.
  • If variable type is bool, its name should start with Has, Is, Can or Allow, etc.
  • Avoid cryptic abbreviations. Eg: usrAge := 25

Example

Here's a simple user package that showcases interface, struct, functions and variables.

package user // <- package name

import "fmt"

type User struct {
    name string // private attribute of user struct
}

// importers can call using user.New()
func New(name string) *User {
    return &User{
        name: name,
    }
}

// using the suffix `Interface` here
type UserInterface interface {
    Name() string
}

// public function for user
func (u *User) Name() string {
    return "Name: " + u.name
}

// in main.go - to make this code work change package name to main instead
func main() {
    userA := New("mohit")
    fmt.Println(userA.Name())
}

General guidelines

  • Long names don't automatically make things more readable. A helpful doc comment can often be more valuable than an extra long name.
  • There's no line limit in Go but having too long lines hampers readability.
  • Avoid using Get as prefix for getters. Rather, use of upper-case names for export provides the hook to discriminate the field from the method. Eg. user.User() instead of user.GetUser()

Naming conventions play a crucial role in creating clean, maintainable, and collaborative code. Go's approach to naming favors clarity and simplicity over cleverness, aligning with its overall design philosophy. By adhering to Go's naming conventions, you can enhance the readability of your code, foster collaboration, and make your programs more robust and enjoyable to work with.


Should Go interface names start with I?

No. Go names a one-method interface after its method plus an -er suffix, like Reader or Writer. The I prefix comes from Java and C# codebases and is not idiomatic Go.

Should Go constants be ALL_CAPS?

No. Go uses MixedCaps for constants, so MaxRetries rather than MAX_RETRIES. The underscore style is a C convention.

How should Go packages be named?

Short, lowercase and a single word, usually the base name of the directory. Skip underscores and mixedCaps, and do not repeat the package name in exported identifiers, which is why user.New reads better than user.NewUser.

Do Go getters need a Get prefix?

No. Export the field-level name directly: user.Name() rather than user.GetName(). Go avoids Get prefixes in general.

Should Go file names use underscores or dashes?

Lowercase, with underscores between words: user_handler.go. File names starting with . or _ are ignored by the go tool.

Resources

Books to learn Golang

Explore more programming books and get a copy.

Liked the article? Consider supporting me ☕️


I share regular updates and resources on Twitter. Let's connect!

Keep exploring 🔎 Keep learning 🚀

Written by

Mohit Khare

Senior software lead at Abnormal.AI, prev. CRED and Gojek. Backend engineer working on AI, security, and engineering leadership. Based in Bangalore.

Connect on LinkedInMore writing