Go 🐹

Hero image for Go 🐹

Linting

We mainly use the built in command go vet for automated code checks.

Formatting

  • Use tabs with 8 tab size for indentation.
  • Format the syntax using go fmt.
  • Use a single empty line to break between statements to organize logical chunks of code.
  • End each file with a newline.

Naming

  • Use UpperCamelCase for public and lowerCamelCase for private interfaces, structs, variables and functions.

    // Bad
    type hello_world interface{}
    
    type fizz_buzz struct{}
    
    var my_array []string
    my_array := []string{}
    
    func foo_bar() {
      // some code
    }
    
    // Good
    // public
    type HelloWorld interface{}
    
    type FizzBuzz struct{}
    
    // private
    var myArray []string
    myArray := []string{}
    
    func fooBar() {
      // some code
    }
    
  • Use err as a common variable name for error type.

    // Bad
    someErr := returnErrorFunc()
    
    // Good
    err := returnErrorFunc()
    
  • Use lowercase with NO underscore for package names. Prefer conciseness over long names.

    // Bad
    package string_conversion
    package operatingSystem
    package documentation
    package system_log
    package io_utility
    
    // Good
    package strconv
    package os
    package doc
    package syslog
    package ioutil
    

Imports

  • Organize packages in group, separated by blank line between each group.

    import (
      // Standard library packages
    
      // Internal project packages
    
      // Third-party packages
    )
    
    // Bad
    import (
      "errors"
      "nimblehq/controllers"
      "net/http"
      "github.com/fizz/buzz"
      "nimblehq/models"
      "github.com/foo/bar"
    )
    
    // Good
    import (
      "errors"
      "net/http"
    
      "nimblehq/controllers"
      "nimblehq/models"
    
      "github.com/fizz/buzz"
      "github.com/foo/bar"
    )
    
  • Sort packages by alphabetical order for each group.

    // Bad
    import (
      "net/http"
      "errors"
    
      "nimblehq/models"
      "nimblehq/controllers"
    )
    
    // Good
    import (
      "errors"
      "net/http"
    
      "nimblehq/controllers"
      "nimblehq/models"
    )
    
  • Use lowercase with NO underscore to rename imported packages. This is often needed to avoid package import conflicts.

    // Bad
    import (
      "errors"
      goUrl "net/url"
    
      errors_config "mypackage/config/errors"
      "mypackage/config/url"
    )
    
    // Good
    import (
      "errors"
      gourl "net/url"
    
      errorsconf "mypackage/config/errors"
      "mypackage/config/url"
    )
    

Slices

  • Prefer var s []string over s := []string{} when declaring an empty slice.

Functions

  • Prefer declaring the type for each parameter over declare single type for all parameters.

    // Bad
    func fooBar(num1, num2 int, str1, str2 string) {
      // Some code
    }
    
    // Good
    func fooBar(num1 int, num2 int, str1 string, str2 string) {
      // Some code
    }
    
  • Prefer unnamed over named return parameters for return values.

    // Bad
    func fruit(name string) (color, taste string) {
      switch name {
      case "Banana", "Mango":
        color, taste = "Yellow", "Sweet"
      default:
        color, taste = "Unknown", "Unknown"
      }
      return
    }
    
    // Good
    func fruit(name string) (string, string) {
      var color string
      var taste string
    
      switch name {
      case "Banana", "Mango":
        color, taste = "Yellow", "Sweet"
      default:
        color, taste = "Unknown", "Unknown"
      }
      return color, taste
    }
    
  • Prefer early return to avoid deep nesting.

    // Bad
    func validUser(u *User) bool {
        if u != nil {
            if u.Id != nil {
                return true
            } else {
                return false
            }
        } else {
            return false
        }
    }
    
    // Good
    func validUser(u *User) bool {
        if u == nil {
            return false
        }
          
        return u.Id != nil
    }
    
  • Prefer one or two letter abbreviation as the receiver name in the receiver function. The receiver name should be consistent other receiver functions.

    // Bad
    func (registration *Registration) New() {
        ...
        ...
    }
      
    func (serverHandler ServerHandler) ServeHTTP(rw ResponseWriter, r *Request) {
        ...
        ...
    }
      
    // Good
    func (r *Registration) New() {
        ...
        ...
    }
      
    func (sh ServerHandler) ServeHTTP(rw ResponseWriter, r *Request) {
        ...
        ...
    }
    

Errors

  • DO NOT ignore errors using _ variables if the function returns an error. Check them to make sure the function is completed.

  • Prefer declare then check over inline error handling for error returning functions.

    // Bad
    if err := fooBar(); err != nil {
      // Error handling
    }
    
    // Good
    err := fooBar()
    if err != nil {
      // Error handling
    }
    
  • Prefer reusing the variable err instead of assigning errors to a new variable for error handling since errors must be handled right away.

    // Bad
    func1Err := returnErrFunc1()
    if func1Err != nil {
      // Error handling
    }
    
    func2Err := returnErrFunc2()
    if func2Err != nil {
      // Error handing
    }
    
    // Good
    err := returnErrFunc1()
    if err != nil {
      // Error handing
    }
    
    err = returnErrFunc2()
    if err != nil {
      // Error handing
    }
    
  • DO NOT use panic for handling normal errors. Use error and multiple return values.

Testing

  • Any test file must have a _test.go suffix as the go test command automatically executes any file with names that match the file pattern *_test.go.

  • Prefer adding _test suffix to the package name for any test package instead of using the same name as the original package. This naming keeps in sync the file name with the package name.

    // controllers/foo.go
    package controllers
    
    // Bad
    // controllers/foo_test.go
    package controllers
    
    // Good
    // controllers/foo_test.go
    package controllers_test
    
  • Any test function must have a Test prefix as the go test command automatically executes any function that match following pattern.

    func TestXxx(*testing.T) {
      // Testing code
    }