Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Packages & Modules - GopherCon Poland 2019

Packages & Modules - GopherCon Poland 2019

64a4ba69d50590e592cd8e572454daa8?s=128

Oleg Kovalov

June 27, 2019
Tweet

Transcript

  1. Packages & Modules GopherCon Poland, Gdansk, June 27 2019 Oleg

    Kovalov Allegro https://olegk.dev
  2. Agenda Packages & Modules

  3. 3 - About me - Packages - Modules - Summary

    - Q&A
  4. 4 - About me - Packages - Modules - Summary

    - Q&A Interfaces
  5. About me Packages & Modules

  6. 6

  7. - Gopher for ~4 years 7

  8. 8 - Gopher for ~4 years - Open-source contributor -

    Go-critic - static analysis tool - Go-advice - list of Go tips @ GoGoConf 2018
  9. 9 - Gopher for ~4 years - Open-source contributor -

    Go-critic - static analysis tool - Go-advice - list of Go tips @ GoGoConf 2018 - Engineer at allegro.pl core team
  10. - Gopher for ~4 years - Open-source contributor - Go-critic

    - 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 10 Twitter & slides
  11. Packages Packages & Modules

  12. 12

  13. - Short and clear 13

  14. - Short and clear - May be abbreviated when the

    abbreviation is familiar 14
  15. - Short and clear - May be abbreviated when the

    abbreviation is familiar - Abbrv name is easy to understand 15
  16. - 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) 16
  17. - 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) 17
  18. - 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) 18
  19. 19

  20. - If abbreviating is unclear 20

  21. - If abbreviating is unclear - If name is ambiguous

    21
  22. - If abbreviating is unclear - If name is ambiguous

    - snake_case or camelCase 22
  23. - If abbreviating is unclear - If name is ambiguous

    - snake_case or camelCase - psdb (Postgres? Parallel search?) 23
  24. - If abbreviating is unclear - If name is ambiguous

    - snake_case or camelCase - psdb (Postgres? Parallel search?) - srv (service? server? surviving?) 24
  25. - If abbreviating is unclear - If name is ambiguous

    - snake_case or camelCase - psdb (Postgres? Parallel search?) - srv (service? server? surviving?) - buf (buffer? buffer what? WoW buff?) 25
  26. - Avoid giving a package a name that is commonly

    used in client code 26
  27. - 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) 27
  28. - 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 28
  29. - 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 29 c ? clnt ? cli ? clientHTTP ?
  30. 30

  31. These std packages are a good names thiefs: - path

    - path/filepath - net/url And you cannot use your variable url easily, oh :( 31
  32. 32 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
  33. Most of the projects in Go are flat and this

    is fine 33
  34. 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 34
  35. 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 35
  36. 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) 36
  37. 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 37
  38. 38

  39. 39

  40. 40

  41. 41

  42. 42

  43. 43

  44. 44

  45. - Organize by functional responsibility 45

  46. - Organize by functional responsibility - Don’t put all the

    type into models package 46
  47. 47 - Organize by functional responsibility - Don’t put all

    the type into models package - Keeping them in one gives nothing
  48. 48 - 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
  49. 49 - 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)
  50. 50 . ├── app ├── cmd │ └── <project-name> ├──

    blog ├── comment ├── mock ├── pkg │ ├── superpay │ └── validation ├── store │ └── postgres ├── user └── <project-name>.go
  51. 51 . ├── app ├── cmd │ └── <project-name> ├──

    blog ├── comment ├── mock ├── pkg │ ├── superpay │ └── validation ├── store │ └── postgres ├── user └── <project-name>.go
  52. 52 . ├── app ├── cmd │ └── <project-name> ├──

    blog ├── comment ├── mock ├── pkg │ ├── superpay │ └── validation ├── store │ └── postgres ├── user └── <project-name>.go
  53. 53 mock.NewBlog(...) . ├── app ├── cmd │ └── <project-name>

    ├── blog ├── comment ├── mock ├── pkg │ ├── superpay │ └── validation ├── store │ └── postgres ├── user └── <project-name>.go
  54. 54 . ├── app ├── cmd │ └── <project-name> ├──

    blog ├── comment ├── mock ├── pkg │ ├── superpay │ └── validation ├── store │ └── postgres ├── user └── <project-name>.go
  55. 55 . ├── app ├── cmd │ └── <project-name> ├──

    blog ├── comment ├── mock ├── pkg │ ├── superpay │ └── validation ├── store │ └── postgres ├── user └── <project-name>.go
  56. 56 . ├── app ├── cmd │ └── <project-name> ├──

    blog ├── comment ├── mock ├── pkg │ ├── superpay │ └── validation ├── store │ └── postgres ├── user └── <project-name>.go
  57. pkg, internal, misc or util Whatever works for your team

    and you 57 . ├── app ├── cmd │ └── <project-name> ├── blog ├── comment ├── mock ├── pkg │ ├── superpay │ └── validation ├── store │ └── postgres ├── user └── <project-name>.go
  58. 58 . ├── app ├── cmd │ └── <project-name> ├──

    blog ├── comment ├── mock ├── pkg │ ├── superpay │ └── validation ├── store │ └── postgres ├── user └── <project-name>.go
  59. 59

  60. - util.URLError 60

  61. - util.URLError - common.SanitizeMessage 61

  62. - util.URLError - common.SanitizeMessage - base.EnsureAbsolutePath 62

  63. - util.URLError - common.SanitizeMessage - base.EnsureAbsolutePath - helpers.IsEmail 63

  64. - util.URLError - common.SanitizeMessage - base.EnsureAbsolutePath - helpers.IsEmail 64 These

    packages say nothing!
  65. 65 - util.URLError - common.SanitizeMessage - base.EnsureAbsolutePath - helpers.IsEmail type

    URLError = app.URLError These packages say nothing!
  66. 66 - util.URLError - common.SanitizeMessage - base.EnsureAbsolutePath - helpers.IsEmail type

    URLError = app.URLError var isEmail = validation.IsEmail These packages say nothing!
  67. - 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 67
  68. - 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 68
  69. - 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 69
  70. - 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 70
  71. 71 postgres ├── postgres.go ├── user.go ├── stats.go └── user_test.go

    redis ├── redis.go ├── cache.go └── comments.go
  72. 72 postgres ├── postgres.go ├── user.go ├── stats.go └── user_test.go

    redis ├── redis.go ├── cache.go └── comments.go cache ├── redis │ └── redis.go store ├── postgres │ ├── postgres.go │ ├── user.go │ └── user_test.go └── redis ├── redis.go └── comments.go
  73. 73

  74. - Main packages are not importable 74

  75. - Main packages are not importable - Don’t export from

    main, it’s useless 75
  76. - Main packages are not importable - Don’t export from

    main, it’s useless - main package is hard to test (see above) 76
  77. 77 package main func init() { config.Load() }

  78. 78 package main func init() { config.Load() } func main()

    { os.Exit(realMain()) } func realMain() int { log.SetOutput(ioutil.Discard) // ... }
  79. package main func main() { log.Fatal(app.Run()) } 79

  80. 80

  81. - 1 init() per package (pretty please) 81

  82. - 1 init() per package (pretty please) - Do not

    depend on init’s call order 82
  83. - 1 init() per package (pretty please) - Do not

    depend on init’s call order - No heavy tasks 83
  84. - 1 init() per package (pretty please) - Do not

    depend on init’s call order - No heavy tasks - Preferably no I/O, especially blocking 84
  85. - 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 85
  86. # Python is quite flexible # try: import foo except:

    print(‘good try lol’) 86
  87. # Python is quite flexible # try: import foo except:

    print(‘good try lol’) // Go isn’t so… // package foo func init() { iCanPanicAndYouCanDoNothing() } 87
  88. // but wait, it can be flexible... package foo func

    Init() { iCanPanicButOoooohhYouCanCatchMe() } 88
  89. // 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() } 89
  90. package foo func (s *Service) Process() { // let’s start

    a sweet goroutine go func() { iCanPanicAndYouCanDoNothing() }() } 90
  91. package foo func (s *Service) Process() { // let’s start

    a sweet goroutine go func() { iCanPanicAndYouCanDoNothing() }() } ----------- package bar func ... { // but internal goroutine // isn’t accessible here :( s.Process() } 91
  92. package foo func (s *Service) Process() { go func() {

    defer func() { // recovery process }() iCanPanicAndAuthorWillRecover() }() } 92
  93. package foo func (s *Service) Process() { iCanPanicButItDoesntMatter() } 93

  94. package foo func (s *Service) Process() { iCanPanicButItDoesntMatter() } -----------

    package bar func ... { go func() { defer func() { // user defined recovery process }() s.Process() }() } 94
  95. 95

  96. - Exported package variable is mutable by everyone 96

  97. - Exported package variable is mutable by everyone - You

    have no power to control other packages 97
  98. - Exported package variable is mutable by everyone - You

    have no power to control other packages - Tight coupling makes code less flexible 98
  99. - 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! 99
  100. - 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 100
  101. - 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 101
  102. - 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 102
  103. - 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 103 by the way unexported variables are also bad :(
  104. 104

  105. - Should be simply a container for consts, types, funcs

    105
  106. - Should be simply a container for consts, types, funcs

    - Zero variables is brilliant (both exported and unexported) 106
  107. - Should be simply a container for consts, types, funcs

    - Zero variables is brilliant (both exported and unexported) - Documentation and tests :) 107
  108. 108

  109. - log.Printf A safe action, might be noisy, but harmless

    109
  110. - log.Printf A safe action, might be noisy, but harmless

    - log.Panicf Not idiomatic, but in an edge case might be fine 110
  111. 111 - 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)
  112. 112

  113. - doc.go is a README of your package 113

  114. - doc.go is a README of your package - Run

    godoc locally to see how it looks 114
  115. 115 - 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
  116. Interfaces Packages & Modules

  117. 117

  118. Be conservative in what you send, be liberal in what

    you accept (с) Postel’s Law, Wikipedia 118
  119. Be conservative in what you send, be liberal in what

    you accept (с) Postel’s Law, Wikipedia TCP architecture: 119
  120. 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 120
  121. 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 121
  122. func FetchUsers(db Store) ([]*User, error) { ... } 122

  123. func FetchUsers(db Store) ([]*User, error) { ... } - We

    don’t care what is inside: Postgres, Redis, plain file or a mock 123
  124. 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 124
  125. 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 125
  126. 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 126
  127. 127

  128. - There is the “Java-style” interface declaration 128

  129. - There is the “Java-style” interface declaration - Define an

    interface 129
  130. - There is the “Java-style” interface declaration - Define an

    interface - Create a type that implements it 130
  131. 131 - There is the “Java-style” interface declaration - Define

    an interface - Create a type that implements it - Often you have one interface and one implementation
  132. - 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” ʕ◔ϖ◔ʔ 132
  133. 133

  134. - Go interfaces are in the package that uses it

    134
  135. - Go interfaces are in the package that uses it

    - And this makes Go code easy to extend 135
  136. Modules Packages & Modules

  137. 137 time Image credit: ©Istockphoto/JamesBrey

  138. 138

  139. - GOPATH 139

  140. - GOPATH - godep 140

  141. - GOPATH - godep - gopkg.in 141

  142. - GOPATH - godep - gopkg.in - glide 142

  143. - GOPATH - godep - gopkg.in - glide - vendor

    dir 143
  144. - GOPATH - godep - gopkg.in - glide - vendor

    dir - dep 144
  145. 145

  146. 146 - Modules - Semantic versioning - Import compatibility rule

    - go.mod
  147. - A module is a collection of Go packages that

    are versioned as a single unit 147
  148. - A module is a collection of Go packages that

    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 148
  149. - A module is a collection of Go packages that

    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 149 Can leave outside of GOPATH
  150. 150

  151. 151 - If an old and a new package have

    the same import path - the new package must be backwards-compatible with the old package
  152. 152 - If an old and a 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" )
  153. 153 - auto(default) - on - off $ export GO111MODULE=on

    $ go build ./...
  154. 154 Usage: go mod <command> [arguments] The 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
  155. $ mkdir /mygo/hello $ cd /mygo/hello 155

  156. $ mkdir /mygo/hello $ cd /mygo/hello $ go mod init

    github.com/golang/hello go: creating new go.mod: module github.com/golang/hello $ ls go.mod 156
  157. 157 $ mkdir /mygo/hello $ cd /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
  158. $ git clone https://github.com/go-gitea/gitea Cloning into gitea... $ cd gitea

    158
  159. $ git clone https://github.com/go-gitea/gitea Cloning into gitea... $ cd gitea

    $ go mod init go: creating new go.mod: module github.com/go-gitea/gitea go: copying requirements from Gopkg.lock 159
  160. 160 $ git clone https://github.com/go-gitea/gitea Cloning into gitea... $ cd

    gitea $ go mod init go: creating new go.mod: module github.com/go-gitea/gitea go: copying requirements from Gopkg.lock $ go mod tidy go: extracting github.com/PuerkitoBio/goquery v1.5.0 go: extracting github.com/blevesearch/bleve v0.7.0 go: finding github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57 go: finding golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961 go: finding golang.org/x/time v0.0.0-20181108054448-85acf8d2951c go: downloading github.com/facebookgo/grace v0.0.0-20180706040059-75cf19382434 ...
  161. module github.com/hashicorp/consul go 1.12 ... 161

  162. module github.com/hashicorp/consul go 1.12 require ( github.com/NYTimes/gziphandler v1.0.1 <...>/datadog-go v0.0.0-20160329135253-cc2f4770f4d6

    // indirect github.com/go-redis/redis v6.15.2+incompatible ... ) 162
  163. module github.com/hashicorp/consul go 1.12 require ( github.com/NYTimes/gziphandler v1.0.1 <...>/datadog-go v0.0.0-20160329135253-cc2f4770f4d6

    // indirect github.com/go-redis/redis v6.15.2+incompatible ... ) 163
  164. 164 module github.com/hashicorp/consul go 1.12 require ( github.com/NYTimes/gziphandler v1.0.1 <...>/datadog-go

    v0.0.0-20160329135253-cc2f4770f4d6 // indirect github.com/go-redis/redis v6.15.2+incompatible ... ) replace github.com/hashicorp/consul/api => ./api // can be fork or branch
  165. 165 module github.com/hashicorp/consul go 1.12 require ( github.com/NYTimes/gziphandler v1.0.1 <...>/datadog-go

    v0.0.0-20160329135253-cc2f4770f4d6 // indirect github.com/go-redis/redis v6.15.2+incompatible ... ) replace github.com/hashicorp/consul/api => ./api // can be fork or branch exclude github.com/not-a-hacker/supergeil v1270.0.1
  166. 166

  167. 167

  168. 168 cloud.google.com/go v0.26.0 h1:e0WKqKTd5BnrG8aKH3J3h+QvEIQtSUcf2n5UZ5ZgLtQ= cloud.google.com/go v0.26.0/go.mod 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
  169. 169

  170. # same (@latest is default for 'go get') $ go

    get github.com/gorilla/mux@latest 170
  171. # same (@latest is default for 'go get') $ go

    get github.com/gorilla/mux@latest # records v1.6.2 $ go get github.com/gorilla/mux@v1.6.2 $ go get github.com/gorilla/mux@e3702bed2 171
  172. # same (@latest is default for 'go get') $ go

    get github.com/gorilla/mux@latest # records v1.6.2 $ go get github.com/gorilla/mux@v1.6.2 $ go get github.com/gorilla/mux@e3702bed2 # records v0.0.0-20180517173623-c85619274f5d $ go get github.com/gorilla/mux@c856192 172
  173. 173 # same (@latest is default for 'go get') $

    go get github.com/gorilla/mux@latest # records v1.6.2 $ go get github.com/gorilla/mux@v1.6.2 $ 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
  174. # go and get a repo $ go get github.com/go-gitea/gitea

    $ cd ~/go/src/github.com/go-gitea/gitea 174
  175. # go and get a repo $ 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 175
  176. 176 # go and get a repo $ 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
  177. # install $ go get github.com/rogpeppe/gohack 177

  178. # install $ go get 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 178
  179. 179 # install $ go get 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
  180. 180

  181. 181 - https://proxy.golang.org - https://github.com/gomods/athens - https://github.com/goproxy/goproxy - export GOPROXY=my.proxy.com

    - go get github.com/foo/bar
  182. 182

  183. *Remark Packages & Modules

  184. 184

  185. - Usability ~ Reusability 185

  186. - Usability ~ Reusability - Make application team-friendly 186

  187. - Usability ~ Reusability - Make application team-friendly - Keep

    library easy to use 187
  188. - Usability ~ Reusability - Make application team-friendly - Keep

    library easy to use Animated-emoji-colorful output in app - cool, whatever 188
  189. - 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 189
  190. Summary Packages & Modules

  191. 191

  192. - Simple and shy packages 192

  193. - Simple and shy packages - Clear naming is important

    193
  194. - Simple and shy packages - Clear naming is important

    - No global state at all 194
  195. - Simple and shy packages - Clear naming is important

    - No global state at all - Interfaces are for abstraction 195
  196. 196 - Simple and shy packages - Clear naming is

    important - No global state at all - Interfaces are for abstraction - Modules == Go ecosystem 2.0
  197. 197 - Simple and shy packages - Clear naming is

    important - No global state at all - Interfaces are for abstraction - Modules == Go ecosystem 2.0 - App != Lib
  198. Thank you Packages & Modules

  199. - Ben Johnson @benbjohnson - Dave Cheney @davecheney - Jaana

    B. Dogan @rakyll - Go team ʕ◔ϖ◔ʔ - all the friends \o/ 199