This living document describes some Go design philosophies I personally try to use/start with when working, building, or writing in Go.
- Prefer easy to understand over easy to do
- First do it, then do it right, then do it better, then make it testable 14
- When you spawn goroutines, make it clear when - or whether - they exit. 2
- Packages that are imported only for their side effects should be avoided 4
- Package level and global variables should be avoided
- Magic is bad; global state is magic → no package level vars; no func init 13
- Engineer with clear and obvious layers of concern and purpose. 16
- External dependencies should be tried and fail fast or just keep trying
- For example, external connections, port binding, environment variables, secrets, etc
- Examples of "failing fast"
- Try external connections immediately
- Binding to ports immediately
 
- Examples of "keep trying"
- Block ingress traffic or calls until external connections are successful
- Should be accompanied by some way to check health status of external connections
 
 
- Block ingress traffic or calls until external connections are successful
 
- Make all dependencies explicit 11
- Naming general rules 12
- Structs are plain nouns: API, Replica, Object
- Interfaces are active nouns: Reader, Writer, JobProcessor
- Functions and methods are verbs: Read, Process, Sync
 
- Package names 15
- Short: no more than one word
- No plural
- Lower case
- Informative about the service it provides
- Avoid packages named utility/utilities or model/models
 
- Avoid renaming imports except to avoid a name collision; good package names should not require renaming 3
- Accept interfaces, return structs 5
- Small interfaces are better 6
- Define an interface when you actually need it, not when you foresee needing it 7
- Interfaces 15
- Use interfaces as function/method arguments & as field types
- Small interfaces are better
 
- All top-level, exported names should have doc comments, as should non-trivial unexported type or function declarations. 1
- Methods/functions 15
- One function has one goal
- Simple names
- Reduce the number of nesting levels
 
- Only func main has the right to decide which flags, env variables, config files are available to the user 10a,10b
- context.Contextshould, in most cases, be the first argument of all functions or methods
- Prefer synchronous functions - functions which return their results directly or finish any callbacks or channel ops before returning - over asynchronous ones. 8
- Error Handling 15
- Func main/packagemainshould normally be the only one calling fatal errors, i.e.os.Exit
 
- Func 
- One file should be named like the package 9
- One file = One responsibility 9
- If you only build one binary prefer a top level main.go, if you have more than one binary put the code in acmd/package