Name Conventions In Go

twomeows/Getty Images

Summary: The ground rules for naming in Go are: use mixedCaps, keep it short and be consistent.

As a developer, naming is what we do every day, although it is quite easy most of the time, sometime it's really hard to come up with a good name, especially for fresher developers who are still struggling learning the languages. Some developers end up using i, j, v,... for almost everything. Those are good names in some cases but can be very confusing if being used in an inappropriate context.

Some time developers just want to name their code their own way, this is OK if you work on your side project. But in a project which involve multiple developers, the standard must be respected. Everyone in a same project must follow the same standard, otherwise your code would like like a mess and become super hard to maintain.

In this post, I would like to provide some simple rules so that you can name your code easier and avoid endless arguments with your colleagues about naming conventions.

This guideline can be used as a supplement to the name conventions of the Go guideline at effective-go.

Project Name #

Name your project in lowercase, otherwise it would look really weird in the imports. Logrus - a very good structured logging library in Go made this mistake at the beginning and they had to fix it a very hard way. You still can see their README mention about the naming problem today.

The import github.com/sirupsen/logrus is much better than github.com/Sirupsen/logrus

If your project name is long, use dash or underscore to separate the name. Use effective-go or effective_go instead of effectiveGo or EffectiveGo.

Package #

For package, use singular noun instead of plural. Use user instead of users , notification instead of notifications .

Use plural noun in case using singular noun causes collision with existing primitive type names. But this should be used with very careful considerations. Some examples from the standard libraries are bytes , errors.

If your package adds some extension to the current standard libraries, try to use another name instead of using the same name and fool yourselves with import alias. Use contextutil or contextx instead of context , use errorsx instead of errors so that you can use both the packages in your code without defining alias for your imports.

Try to keep package name short, use lower case, never use mixedCaps for package name and even snake_case should be avoided too. Use contextutil instead of contextUtil or context_util . This is similar why Go name its httputil package, and not httpUtil or http_util.

File Name #

For file name, try to keep it short, but still meaningful.

I have seen some developers naming their entry file in Go different from main.go, don't do that! Be different, be intelligent in something that avoid bugs instead.

Use lower case and use snake_case instead of mixedCaps. So, use server.go , notification.go or notification_server.go instead of notificationServer.go.

Use underscore instead of dash, dash would make your unit test file looks weird. So, use notification_server.go, notification_server_test.go or repository_mongo.go instead of notification-server.go or notification-server_test.go.

If there are multiple files for different purposes in a same package, all the files of a same purpose should be prefixed the same way, that way your code would be perfectly aligned in your IDE and super easy to find.

Function/Method #

Use mixedCaps for naming your function. Use getArticles or GetArticles instead of get_articles or get-articles.

Name of a function should reflect what it does. Don't naming your function getArticles but inside the function you also modify it.

Try to void the word Get from the getters of a struct. Use Name() and SetName(string) instead of GetName() and SetName(string).

If a function receives a context, the context must be the first parameter and its name should be ctx.

Use DeleteArticle(ctx context.Context, id string) error instead of DeleteArticle(id string, myCtx context.Context) error.

For the method receiver, 2 or 3 letter maybe enough for the name. If you prefer more meaningful name, that's OK but remember to try to shorten them. So, srv or svc are better than server, service or myService. r or repo is better than repository or myRepository

If a function requires only one struct as its request param, req is much better than getArticleRequest. If it requires multiple param, concrete names should be provided but tries to keep them short.

If a param of a function is a writer, then w is meaningful enough. If it's a reader, r is a good choice.

Variable #

Name of variable should be short but should be meaningful enough. So, you can use srv or svc instead of service, server or myService. User or repo instead of repository or myRepository.

Use ctx for context.Context. If it's a new context then newCtx is good enough.

Use i, j for your indexing of a loop. But what if you have 3 loops? Please don't! Having 3 loops means you should refactor your code.

Some developers prefer to use rs for naming result of something. This is OK, but in case you have multiple results of different API calls, the name should be more concrete, otherwise it would be really hard to read the code. You can use article if the result is just a single struct represent an article, articles if it's a slice, or searchArticleRs if it's a response struct.

Constant #

Constant follows the same rule with variables and functions, hence use mixedCaps for naming. No underscore unless it's generated code. So, use StatusActive instead of STATUS_ACTIVE.

All constants of same type or represent a same values of something should be named with same prefix for easier to remember.

Error #

Name of error variable should start with Err. Use ErrNotFound instead of NotFoundError. Note that it's Err, not Error.

But when it's an error type, Error should be the suffix of the type name. Use NotFoundError instead of ErrorNotFound.

Interfaces #

The simplest rule for naming interface is adding er into the name of the action/method it represents.

Here are some examples from the standard library:

type Writer interface {
Write(p []byte) (n int, err error)
}

type Reader interface {
Read(p []byte) (n int, err error)
}

type ReadWriter interface{
Reader
Writer
}

The standard guideline is easy but sometime you have big interfaces which includes 4 or 5 or even more actions/methods and it's hard to come up with a good name. My recommendation is naming them base on the meaning of the set of the methods/actions they represent.

If it's all about retrieving/updating data for something, DataProvider, DataAdaptor, DataUpdater are good enough. If you want more concrete names, ArticleDataProvider, ArticleGetter, ArticleUpdater, ... are good names to choose.

If it's a service that provide a lot of actions for something, maybe Service or Server are good suffixes for the name. So you can use ArticleService, ArticleServer, ...