Naming Conventions in Golang

19 May 2023 ⏱️ 5 min
Naming Conventions in Go - Key to Readable and Maintainable Code

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. ReaderWriter, etc.
  • use MixedCaps or mixedCaps rather than underscores to write multiword names.
  • Use prefix I Eg. IUser, IRead, etc. One con - searching for interfaces across codebase is harder due to I
  • Use suffix Interface. Eg. UserInterface, ReadInterface, etc.

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)
  • Constant should use all capital letters and use underscore _ to separate words. Eg. INT_MAX
  • If variable type is bool, its name should start with HasIsCan 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.


Resources

Books to learn Golang

Explore more programming books and get a copy.

Liked the article? Consider supporting me ☕️


I hope you learned something new. Feel free to suggest improvements ✔️

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

Keep exploring 🔎 Keep learning 🚀

Liked the content? Do support :)

Paypal - Mohit Khare
Buy me a coffee