Johnny.sh

Conventions and Such

Various notes on writing Go Code. Mainly taken from Effective Go and How To Write Go Code.

Other notable resources:

Files and Packages

Use snake_case for multi-file packages. e.g., if a package has multiple files, use mypackage/another_func.go. Function names are still camel case. Anything exported from the package is capitalized.

Formatting

  • Use gofmt or go fmt whenever possible. This is one of the cool features of go — formatting is built into the language.
  • No semi-colons.
  • Use tabs. Not spaces.
  • Fewer parentheses than most other languages — if and for and switch etc. all don’t use parentheses.
  • No rules about line-length. If you want to split things onto multiple lines, you can.
  • Comments and godoc have some special magic that plays well together. Generally speaking, add a comment to every exported function of a package; add a block comment to every package.
  • Functions can be called before they’re declaration (similar to JS hoisting behavior)/

Naming Conventions

  • CamelCase for multi-word variable and function names
  • Go leans towards short names for variables and stuff. e.g., i not index. The larger the scope and significance of a variable, the longer the name.
  • Package names in lower case
  • Acronyms and initials - the important part is that the same case is used for the acronym, e.g. httpResponse or requestHTML are both acceptable, but NOT requestHtml
  • Any function that might panic should be prefixed with Must. e.g., MustParseIntFromString
  • Any interface should be a -er suffix. e.g., Reader, Writer, Storer, etc.

Coding Style

Generally, go tends to go towards succinct code as it’s method to achieve readability. Go made me realize that if statements have lexical block just in the statement.

func doStuff (fName) {
  if fName === "some name" {
    fmt.Println("It is the file u want")
  }
}

This statement has 3 scopes. The function scope, the if statement’s declaration scope (if fName ===...) and the if statment block body.

If a variable can be enclosed in an if statement’s declaration that is not needed outside of this scope, then it certainly should be. For succinctness.

For example:

func doThings (fName) {
  if _, err := os.Stat(fName); os.IsNotExist(err) {
    fmt.Println("This file does not exist")
  }
}

There’s a lot encapsulated in the scope of this if statement. It doesn’t leak outside the if statement declaration. That’s considered a good thing in go.

Organizing one file

Syntactically speaking, the order of your function and type declarations does not matter in Go. Go does not parse top-to-bottom like a scripting language or procedural style, so you don’t need to define a function “before” using it, e.g., it doesn’t need to be defined higher in the file.

In Go, the convention is to declare the entrypoint function at the top of the file, then declare the functions used in that function below.

package main

import (
  "fmt"
  "time"
)
// constants

const (
  TIMEZONE = "America/Buenos_Aires"
  LAYOUT = "3:04pm"
)

// typedefs
type SomeType struct {
  ///
}

// main func calls tellMeWhatTimeItIsInBuenosAires
func main() {
  fmt.Println("Starting the app")
  tellMeWhatTimeItIsInBuenosAires()
}

// declare BELOW main func
func tellMeWhatTimeItIsInBuenosAires() {
  nowInBuenosAires := time.Now().In(TIMEZONE).Format(LAYOUT)
  fmt.Println("The time in Buenos Aires is %s", nowInBuenosAires)
}

Also, similarly, put more important things near the top of the file. e.g., exported functions should be above private funcs.

Organizing many files

Generally go doesn’t care too much about how you organize your files in a project. But, there are some basic conventions:

  • There should be a directory called cmd in the root of your project, each subdir in this directory is an application-specific use of other code and packages from the project. For example, cmd/www would be the web-based entrypoint, cmd/cli would be the CLI-based entrypoint, etc.
  • There should be a directory called internal in the root of your project. In here goes non-application-specific code. For example, reusable business logic would go in internal, which could then be used by both the cli and www entrypoints, and is unaware of if it’s handling an http request or whatever it’s doing.

Initialisms and Acronyms

Super annoying topic, but they make the convention clear in the community: casing for acronyms and initialisms should be consistent, and preferably upper case. Lower case is okay as long as it’s consistent and not camelized.

For example, URLParser, urlParser, parseURL are all acceptable, while parseUrl, UrlParser are both unnacceptable.

Last modified: December 01, 2022
/about
/uses
/notes
/talks
/projects
/podcasts
/reading-list
/spotify
© 2024