- Short and clear - May be abbreviated when the abbreviation is familiar - Abbrv name is easy to understand See standard packages for good examples - io (input and output) 7
- Short and clear - May be abbreviated when the abbreviation is familiar - Abbrv name is easy to understand See standard packages for good examples - io (input and output) - strconv (string conversion) 8
- Short and clear - May be abbreviated when the abbreviation is familiar - Abbrv name is easy to understand See standard packages for good examples - io (input and output) - strconv (string conversion) - syscall (system call) 9
- If abbreviating is unclear - If name is ambiguous - snake_case or camelCase - psdb (Postgres? Parallel search?) - srv (service? server? surviving?) 15
- Avoid giving a package a name that is commonly used in client code - buf is a good variable name for a buffer - the buffered I/O package is called bufio (buffer + io) 18
- Avoid giving a package a name that is commonly used in client code - buf is a good variable name for a buffer - the buffered I/O package is called bufio (buffer + io) - client is a good name for...client - but not a package name 19
- Avoid giving a package a name that is commonly used in client code - buf is a good variable name for a buffer - the buffered I/O package is called bufio (buffer + io) - client is a good name for...client - but not a package name - imagine a replacement for it 20 c ? clnt ? cli ? clientHTTP ?
23 These std packages are a good names thiefs: - path - path/filepath - net/url And you cannot use your variable url easily, oh :( But there are good examples: - strings - bytes - net/urls instead of net/url looks good enough
Most of the projects in Go are flat and this is fine - Try to keep it clean github.com/foo/bar/pl/goava/src/main/code/go/validation - Avoid do src/ or pkg/ (in most cases) gitlab.com/foo/bar/pkg/process 26
Write shy code - modules that don’t reveal anything unnecessary to other modules and that don’t rely on other modules' implementations. --- Dave Thomas (with Andy Hunt, he co-authored The Pragmatic Programmer) 27
Write shy code - modules that don’t reveal anything unnecessary to other modules and that don’t rely on other modules' implementations. --- Dave Thomas (with Andy Hunt, he co-authored The Pragmatic Programmer) And shy also means: 1 package = 1 thing 28
39 - Organize by functional responsibility - Don’t put all the type into models package - Keeping them in one gives nothing - In the end this will be a spaghetti code
40 - Organize by functional responsibility - Don’t put all the type into models package - Keeping them in one gives nothing - In the end this will be a spaghetti code - (The same applies to the interfaces, implementations and so on)
pkg, internal, misc or util Whatever works for your team and you 48 . ├── app ├── cmd │ └── ├── blog ├── comment ├── mock ├── pkg │ ├── superpay │ └── validation ├── store │ └── postgres ├── user └── .go
- Use multiple files - Do not separate structs and their methods (not a C/C++) - It’s okay to store few structs in one file (it’s not Java after all) - And keep test files next to code store ├── postgres │ ├── postgres.go │ ├── user.go │ └── user_test.go └── redis ├── redis.go └── comments.go 58
- Use multiple files - Do not separate structs and their methods (not a C/C++) - It’s okay to store few structs in one file (it’s not Java after all) - And keep test files next to code store ├── postgres │ ├── postgres.go │ ├── user.go │ └── user_test.go └── redis ├── redis.go └── comments.go // type Comment and Comment.HasImage method 59
- Use multiple files - Do not separate structs and their methods (not a C/C++) - It’s okay to store few structs in one file (it’s not Java after all) - And keep test files next to code store ├── postgres │ ├── postgres.go │ ├── user.go // type User and type Credentials │ └── user_test.go └── redis ├── redis.go └── comments.go 60
- Use multiple files - Do not separate structs and their methods (not a C/C++) - It’s okay to store few structs in one file (it’s not Java after all) - And keep test files next to code store ├── postgres │ ├── postgres.go │ ├── user.go │ └── user_test.go └── redis ├── redis.go └── comments.go 61
- 1 init() per package (pretty please) - Do not depend on init’s call order - No heavy tasks - Preferably no I/O, especially blocking - Better to not have it at all 76
// but wait, it can be flexible... package foo func Init() { iCanPanicButOoooohhYouCanCatchMe() } ----------- package bar func ... { defer func() { if r := recover(); r != nil { // process a panic } }() foo.Init() } 80
- Exported package variable is mutable by everyone - You have no power to control other packages - Tight coupling makes code less flexible - You cannot mock a package! 90
- Exported package variable is mutable by everyone - You have no power to control other packages - Tight coupling makes code less flexible - You cannot mock a package! - Logger, metrics? - mmmmaybe 91
- Exported package variable is mutable by everyone - You have no power to control other packages - Tight coupling makes code less flexible - You cannot mock a package! - Logger, metrics? - mmmmaybe - Config, flags? - better no 92
- Exported package variable is mutable by everyone - You have no power to control other packages - Tight coupling makes code less flexible - You cannot mock a package! - Logger, metrics? - mmmmaybe - Config, flags? - better no - DB driver? - NONONO 93
- Exported package variable is mutable by everyone - You have no power to control other packages - Tight coupling makes code less flexible - You cannot mock a package! - Logger, metrics? - mmmmaybe - Config, flags? - better no - DB driver? - NONONO 94 by the way unexported variables are also bad :(
102 - log.Printf A safe action, might be noisy, but harmless - log.Panicf Not idiomatic, but in an edge case might be fine - log.Fatalf Evil has no boundaries, omit it, no one can survive os.Exit(1) (even defer)
106 - doc.go is a README of your package - Run godoc locally to see how it looks - Also add package documentation // Package bytes implements functions for the manipulation of byte slices. // It is analogous to the facilities of the strings package. package bytes
Be conservative in what you send, be liberal in what you accept (с) Postel’s Law, Wikipedia TCP architecture: - We don’t care about how packets go through network 110
Be conservative in what you send, be liberal in what you accept (с) Postel’s Law, Wikipedia TCP architecture: - We don’t care about how packets go through network - but we expect them in a well defined order to process 111
func FetchUsers(db Store) ([]*User, error) { ... } - We don’t care what is inside: Postgres, Redis, plain file or a mock - Until it has desired API for us 114
func FetchUsers(db Store) ([]*User, error) { ... } - We don’t care what is inside: Postgres, Redis, plain file or a mock - Until it has desired API for us - But we know for sure that we need a specific struct User 115
func FetchUsers(db Store) ([]*User, error) { ... } - We don’t care what is inside: Postgres, Redis, plain file or a mock - Until it has desired API for us - But we know for sure that we need a specific struct User Tip: return error as interface, not as a struct 116
121 - There is the “Java-style” interface declaration - Define an interface - Create a type that implements it - Often you have one interface and one implementation
- There is the “Java-style” interface declaration - Define an interface - Create a type that implements it - Often you have one interface and one implementation That’s not a “Go style” ʕ◔ϖ◔ʔ 122
- Usability ~ Reusability - Make application team-friendly - Keep library easy to use Animated-emoji-colorful output in app - cool, whatever Math library with zero allocation HTTP router - thanks, but no 131