1. Stick to Golang standard formatting
  2. Naming conventions:
    1. One method interfaces should be named the method name suffixed with “er”, e.g. Stringer, Logger
    2. Packages should be lower-case, single word
    3. Constructors should be named the type name prefixed with “New”, e.g. NewUser, except when the package only exports one type and the package is named after the type, then the constructor can be named “New”, e.g. user.New in package user
    4. Getters should be named the field name, e.g. User.Name() , while setters should be named the field name prefixed by “Set”, e.g. User.SetName(string)
    5. Struct methods should only be named ReadWriteCloseFlushString if they have the same canonical signature and meaning
    6. Models should be plural, Entities should be singular, e.g. Users (model), User (entity)
  3. Never use dot imports
  4. Prefer for ... range over for i loop, for arrays and slices
  5. Prefer Encoder.Encode and Decoder.Decode over Marshall and Unmarshall for serializing and parsing json or yaml
  6. Prefer mutex over sync/atomic
    1. Only use atomic operations for optimisation
    2. If atomic operations are used, detailed explanation is required
  7. Since interface types can either be a type that implements the interface (must use value receiver) or a pointer to that type,
  8. Checks:
    1. always check for nil values for pointers, slices, maps, channels, functions and interfaces
    2. nil checks must be performed at the start of functions, and when the value is returned from pointer dereferencing, slice access, map access, struct field access, channel access or function return
    3. always check slice length before access
    4. always check map entry exists after access
  9. Identifier that starts with a capital letter is exported can be accessed by anyone outside the package. lower case is private within the package. Granularity of privacy is the package
  10. Always add String() function to struct for logging purposes
  11. close or break condition is required when using range on channels
  12. Use Value Receiver as much as possible, do not use pointer receiver (for immutability).
    1. Only use for optimisation, too much mutability can complicate traceability and complicate concurrency management
    2. Generally all methods on a give type should have either a value or pointer receivers only, not a mix of both
    3. If pointer receiver is used, detailed explanation is required
  13. For implementing immutable structs
    1. Structs should not be immutable if a mutex, waitgroup or channel is stored, and the mutex, waitgroup or channel should not be copied
    2. Do not export any fields
    3. Mutable fields must be copied before exposing them
    4. Mutable arguments in constructors or setters must be copied before storing them
    5. Copying must be performed on each level of the data structure until an immutable structure is reached, e.g.
      • map[string]string needs to be copied on one level
      • map[string][]string needs to be copied on two levels
    6. Mutable fields can include
      • slices
      • maps
      • channels
      • interfaces
      • pointers
      • mutable structs (structs that do not follow the above criteria)