- static analysis tool - Go-advice - list of Go tips @ GoGoConf 2018 - Engineer at allegro.pl core team Website: https://olegk.dev Twitter: @oleg_kovalov Github: @cristaloleg I don’t have a Soundcloud...but 10 Twitter & slides
abbreviation is familiar - Abbrv name is easy to understand See standard packages for good examples - io (input and output) - strconv (string conversion) Naming 17
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) Naming 18
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 Don’t steal good names 28
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 Don’t steal good names 29 c ? clnt ? cli ? clientHTTP ?
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
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 Try to keep clean import paths 35
to other modules and that don’t rely on other modules' implementations. --- Dave Thomas (with Andy Hunt, he co-authored The Pragmatic Programmer) Shy packages 36
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 Shy packages 37
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
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)
and you One of the possible structures 57 . ├── app ├── cmd │ └── <project-name> ├── blog ├── comment ├── mock ├── pkg │ ├── superpay │ └── validation ├── store │ └── postgres ├── user └── <project-name>.go
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 Inside the package 67
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 Inside the package 68
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 Inside the package 69
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 Inside the package 70
a sweet goroutine go func() { iCanPanicAndYouCanDoNothing() }() } ----------- package bar func ... { // but internal goroutine // isn’t accessible here :( s.Process() } I heard you like goroutines 91
have no power to control other packages - Tight coupling makes code less flexible - You cannot mock a package! - Logger, metrics? - mmmmaybe Global state 100
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 Global state 101
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 Global state 102
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 Global state 103 by the way unexported variables are also bad :(
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)
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
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 Accept interfaces, return structs 121
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 Accept interfaces, return structs 125
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 Accept interfaces, return structs 126
declaration - Define an interface - Create a type that implements it - Often you have one interface and one implementation That’s not a “Go style” ʕ◔ϖ◔ʔ 132
are versioned as a single unit - A module is a tree/directory of Go source files with a go.mod file in the root ├── cmd │ └── main.go ├── consum │ ├── consum.go │ └── handlers.go ├── produce │ ├── handlers.go │ ├── handlers_test.go │ └── processing.go ├── go.mod └── go.sum What is a module? 148
are versioned as a single unit - A module is a tree/directory of Go source files with a go.mod file in the root ├── cmd │ └── main.go ├── consum │ ├── consum.go │ └── handlers.go ├── produce │ ├── handlers.go │ ├── handlers_test.go │ └── processing.go ├── go.mod └── go.sum What is a module? 149 Can leave outside of GOPATH
new package have the same import path - the new package must be backwards-compatible with the old package import ( "github.com/golang/hello/hey" // v0 or v1 "github.com/golang/hello/v2/hey" )
commands are: download download modules to local cache edit edit go.mod from tools or scripts graph print module requirement graph init initialize new module in current directory tidy add missing and remove unused modules vendor make vendored copy of dependencies verify verify dependencies have expected content why explain why packages or modules are needed
/mygo/hello $ go mod init github.com/golang/hello go: creating new go.mod: module github.com/golang/hello $ ls go.mod $ cat go.mod module github.com/golang/hello
h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/Azure/azure-sdk-for-go v16.0.0+incompatible h1:gr1qKY/Ll72VjFTZmaBwRK1yQHAxCnV25ekOKroc9ws= github.com/Azure/azure-sdk-for-go v16.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= // you might want to use go mod verify
get github.com/gorilla/mux@latest # records v1.6.2 $ go get github.com/gorilla/[email protected] $ go get github.com/gorilla/mux@e3702bed2 go get understands versioning 171
'go get') $ go get github.com/gorilla/mux@latest # records v1.6.2 $ go get github.com/gorilla/[email protected] $ go get github.com/gorilla/mux@e3702bed2 # records v0.0.0-20180517173623-c85619274f5d $ go get github.com/gorilla/mux@c856192 172
for 'go get') $ go get github.com/gorilla/mux@latest # records v1.6.2 $ go get github.com/gorilla/[email protected] $ go get github.com/gorilla/mux@e3702bed2 # records v0.0.0-20180517173623-c85619274f5d $ go get github.com/gorilla/mux@c856192 # records current meaning of master $ go get github.com/gorilla/mux@master
$ cd ~/go/src/github.com/go-gitea/gitea # set a env var and check why do we use this dependency $ export GO111MODULE=on $ go mod why github.com/RoaringBitmap/roaring go mod why 175
$ go get github.com/go-gitea/gitea $ cd ~/go/src/github.com/go-gitea/gitea # set a env var and check why do we use this dependency $ export GO111MODULE=on $ go mod why github.com/RoaringBitmap/roaring # github.com/RoaringBitmap/roaring code.gitea.io/gitea/modules/indexer github.com/blevesearch/bleve github.com/blevesearch/bleve/index/scorch github.com/RoaringBitmap/roaring
# will clone repo into $HOME/gohack/example.com/foo/bar # will add replace statement $ cat go.mod replace example.com/foo/bar => /home/rog/gohack/example.com/foo/bar gohack by Roger Peppe 178
github.com/rogpeppe/gohack $ gohack get example.com/foo/bar # will clone repo into $HOME/gohack/example.com/foo/bar # will add replace statement $ cat go.mod replace example.com/foo/bar => /home/rog/gohack/example.com/foo/bar # to remove specific replace: $ gohack undo example.com/foo/bar # to remove all replaces: $ gohack undo
library easy to use Animated-emoji-colorful output in app - cool, whatever Math library with zero allocation HTTP router - thanks, but no Application != Library 189