4
- About me
- Packages
- Modules
- Summary
- Q&A Interfaces
Slide 5
Slide 5 text
About me
Packages & Modules
Slide 6
Slide 6 text
6
Slide 7
Slide 7 text
- Gopher for ~4 years
7
Slide 8
Slide 8 text
8
- Gopher for ~4 years
- Open-source contributor
- Go-critic - static analysis tool
- Go-advice - list of Go tips @ GoGoConf 2018
Slide 9
Slide 9 text
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
Slide 10
Slide 10 text
- 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
Slide 11
Slide 11 text
Packages
Packages & Modules
Slide 12
Slide 12 text
12
Slide 13
Slide 13 text
- Short and clear
13
Slide 14
Slide 14 text
- Short and clear
- May be abbreviated when the abbreviation is familiar
14
Slide 15
Slide 15 text
- Short and clear
- May be abbreviated when the abbreviation is familiar
- Abbrv name is easy to understand
15
Slide 16
Slide 16 text
- 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
Slide 17
Slide 17 text
- 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
Slide 18
Slide 18 text
- 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
Slide 19
Slide 19 text
19
Slide 20
Slide 20 text
- If abbreviating is unclear
20
Slide 21
Slide 21 text
- If abbreviating is unclear
- If name is ambiguous
21
Slide 22
Slide 22 text
- If abbreviating is unclear
- If name is ambiguous
- snake_case or camelCase
22
Slide 23
Slide 23 text
- If abbreviating is unclear
- If name is ambiguous
- snake_case or camelCase
- psdb (Postgres? Parallel search?)
23
Slide 24
Slide 24 text
- If abbreviating is unclear
- If name is ambiguous
- snake_case or camelCase
- psdb (Postgres? Parallel search?)
- srv (service? server? surviving?)
24
Slide 25
Slide 25 text
- 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
Slide 26
Slide 26 text
- Avoid giving a package a name that is commonly used in client code
26
Slide 27
Slide 27 text
- 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
Slide 28
Slide 28 text
- 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
Slide 29
Slide 29 text
- 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 ?
Slide 30
Slide 30 text
30
Slide 31
Slide 31 text
These std packages are a good names thiefs:
- path
- path/filepath
- net/url
And you cannot use your variable url easily, oh :(
31
Slide 32
Slide 32 text
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
Slide 33
Slide 33 text
Most of the projects in Go are flat and this is fine
33
Slide 34
Slide 34 text
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
Slide 35
Slide 35 text
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
Slide 36
Slide 36 text
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
Slide 37
Slide 37 text
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
Slide 38
Slide 38 text
38
Slide 39
Slide 39 text
39
Slide 40
Slide 40 text
40
Slide 41
Slide 41 text
41
Slide 42
Slide 42 text
42
Slide 43
Slide 43 text
43
Slide 44
Slide 44 text
44
Slide 45
Slide 45 text
- Organize by functional responsibility
45
Slide 46
Slide 46 text
- Organize by functional responsibility
- Don’t put all the type into models package
46
Slide 47
Slide 47 text
47
- Organize by functional responsibility
- Don’t put all the type into models package
- Keeping them in one gives nothing
Slide 48
Slide 48 text
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
Slide 49
Slide 49 text
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)
pkg, internal,
misc or util
Whatever works for
your team and you
57
.
├── app
├── cmd
│ └──
├── blog
├── comment
├── mock
├── pkg
│ ├── superpay
│ └── validation
├── store
│ └── postgres
├── user
└── .go
- util.URLError
- common.SanitizeMessage
- base.EnsureAbsolutePath
- helpers.IsEmail
64
These packages say nothing!
Slide 65
Slide 65 text
65
- util.URLError
- common.SanitizeMessage
- base.EnsureAbsolutePath
- helpers.IsEmail
type URLError = app.URLError
These packages say nothing!
Slide 66
Slide 66 text
66
- util.URLError
- common.SanitizeMessage
- base.EnsureAbsolutePath
- helpers.IsEmail
type URLError = app.URLError
var isEmail = validation.IsEmail
These packages say nothing!
Slide 67
Slide 67 text
- 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
Slide 68
Slide 68 text
- 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
Slide 69
Slide 69 text
- 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
Slide 70
Slide 70 text
- 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
package main
func main() {
log.Fatal(app.Run())
}
79
Slide 80
Slide 80 text
80
Slide 81
Slide 81 text
- 1 init() per package (pretty please)
81
Slide 82
Slide 82 text
- 1 init() per package (pretty please)
- Do not depend on init’s call order
82
Slide 83
Slide 83 text
- 1 init() per package (pretty please)
- Do not depend on init’s call order
- No heavy tasks
83
Slide 84
Slide 84 text
- 1 init() per package (pretty please)
- Do not depend on init’s call order
- No heavy tasks
- Preferably no I/O, especially blocking
84
Slide 85
Slide 85 text
- 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
// but wait, it can be flexible...
package foo
func Init() {
iCanPanicButOoooohhYouCanCatchMe()
}
88
Slide 89
Slide 89 text
// 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
Slide 90
Slide 90 text
package foo
func (s *Service) Process() {
// let’s start a sweet goroutine
go func() {
iCanPanicAndYouCanDoNothing()
}()
}
90
Slide 91
Slide 91 text
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
Slide 92
Slide 92 text
package foo
func (s *Service) Process() {
go func() {
defer func() {
// recovery process
}()
iCanPanicAndAuthorWillRecover()
}()
}
92
Slide 93
Slide 93 text
package foo
func (s *Service) Process() {
iCanPanicButItDoesntMatter()
}
93
Slide 94
Slide 94 text
package foo
func (s *Service) Process() {
iCanPanicButItDoesntMatter()
}
-----------
package bar
func ... {
go func() {
defer func() {
// user defined recovery process
}()
s.Process()
}()
}
94
Slide 95
Slide 95 text
95
Slide 96
Slide 96 text
- Exported package variable is mutable by everyone
96
Slide 97
Slide 97 text
- Exported package variable is mutable by everyone
- You have no power to control other packages
97
Slide 98
Slide 98 text
- Exported package variable is mutable by everyone
- You have no power to control other packages
- Tight coupling makes code less flexible
98
Slide 99
Slide 99 text
- 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
Slide 100
Slide 100 text
- 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
Slide 101
Slide 101 text
- 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
Slide 102
Slide 102 text
- 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
Slide 103
Slide 103 text
- 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 :(
Slide 104
Slide 104 text
104
Slide 105
Slide 105 text
- Should be simply a container for consts, types, funcs
105
Slide 106
Slide 106 text
- Should be simply a container for consts, types, funcs
- Zero variables is brilliant (both exported and unexported)
106
Slide 107
Slide 107 text
- Should be simply a container for consts, types, funcs
- Zero variables is brilliant (both exported and unexported)
- Documentation and tests :)
107
Slide 108
Slide 108 text
108
Slide 109
Slide 109 text
- log.Printf
A safe action, might be noisy, but harmless
109
Slide 110
Slide 110 text
- log.Printf
A safe action, might be noisy, but harmless
- log.Panicf
Not idiomatic, but in an edge case might be fine
110
Slide 111
Slide 111 text
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)
Slide 112
Slide 112 text
112
Slide 113
Slide 113 text
- doc.go is a README of your package
113
Slide 114
Slide 114 text
- doc.go is a README of your package
- Run godoc locally to see how it looks
114
Slide 115
Slide 115 text
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
Slide 116
Slide 116 text
Interfaces
Packages & Modules
Slide 117
Slide 117 text
117
Slide 118
Slide 118 text
Be conservative in what you send, be liberal in what you accept
(с) Postel’s Law, Wikipedia
118
Slide 119
Slide 119 text
Be conservative in what you send, be liberal in what you accept
(с) Postel’s Law, Wikipedia
TCP architecture:
119
Slide 120
Slide 120 text
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
Slide 121
Slide 121 text
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
func FetchUsers(db Store) ([]*User, error) { ... }
- We don’t care what is inside: Postgres, Redis, plain file or a mock
123
Slide 124
Slide 124 text
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
Slide 125
Slide 125 text
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
Slide 126
Slide 126 text
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
Slide 127
Slide 127 text
127
Slide 128
Slide 128 text
- There is the “Java-style” interface declaration
128
Slide 129
Slide 129 text
- There is the “Java-style” interface declaration
- Define an interface
129
Slide 130
Slide 130 text
- There is the “Java-style” interface declaration
- Define an interface
- Create a type that implements it
130
Slide 131
Slide 131 text
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
Slide 132
Slide 132 text
- 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
Slide 133
Slide 133 text
133
Slide 134
Slide 134 text
- Go interfaces are in the package that uses it
134
Slide 135
Slide 135 text
- Go interfaces are in the package that uses it
- And this makes Go code easy to extend
135
- A module is a collection of Go packages that are versioned as a single unit
147
Slide 148
Slide 148 text
- 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
Slide 149
Slide 149 text
- 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
Slide 150
Slide 150 text
150
Slide 151
Slide 151 text
151
- If an old and a new package have the same import path
- the new package must be backwards-compatible with the old package
Slide 152
Slide 152 text
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"
)
Slide 153
Slide 153 text
153
- auto(default)
- on
- off
$ export GO111MODULE=on
$ go build ./...
Slide 154
Slide 154 text
154
Usage:
go mod [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
Slide 155
Slide 155 text
$ mkdir /mygo/hello
$ cd /mygo/hello
155
Slide 156
Slide 156 text
$ 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
Slide 157
Slide 157 text
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
Slide 158
Slide 158 text
$ git clone https://github.com/go-gitea/gitea
Cloning into gitea...
$ cd gitea
158
Slide 159
Slide 159 text
$ 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
Slide 160
Slide 160 text
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
...
Slide 161
Slide 161 text
module github.com/hashicorp/consul
go 1.12
...
161
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
Slide 165
Slide 165 text
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
Slide 166
Slide 166 text
166
Slide 167
Slide 167 text
167
Slide 168
Slide 168 text
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
Slide 169
Slide 169 text
169
Slide 170
Slide 170 text
# same (@latest is default for 'go get')
$ go get github.com/gorilla/mux@latest
170
Slide 171
Slide 171 text
# same (@latest is default 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
171
Slide 172
Slide 172 text
# same (@latest is default 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
172
Slide 173
Slide 173 text
173
# same (@latest is default 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
Slide 174
Slide 174 text
# go and get a repo
$ go get github.com/go-gitea/gitea
$ cd ~/go/src/github.com/go-gitea/gitea
174
Slide 175
Slide 175 text
# 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
Slide 176
Slide 176 text
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
Slide 177
Slide 177 text
# install
$ go get github.com/rogpeppe/gohack
177
Slide 178
Slide 178 text
# 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
Slide 179
Slide 179 text
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
Slide 180
Slide 180 text
180
Slide 181
Slide 181 text
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
Slide 182
Slide 182 text
182
Slide 183
Slide 183 text
*Remark
Packages & Modules
Slide 184
Slide 184 text
184
Slide 185
Slide 185 text
- Usability ~ Reusability
185
Slide 186
Slide 186 text
- Usability ~ Reusability
- Make application team-friendly
186
Slide 187
Slide 187 text
- Usability ~ Reusability
- Make application team-friendly
- Keep library easy to use
187
Slide 188
Slide 188 text
- Usability ~ Reusability
- Make application team-friendly
- Keep library easy to use
Animated-emoji-colorful output in app - cool, whatever
188
Slide 189
Slide 189 text
- 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
Slide 190
Slide 190 text
Summary
Packages & Modules
Slide 191
Slide 191 text
191
Slide 192
Slide 192 text
- Simple and shy packages
192
Slide 193
Slide 193 text
- Simple and shy packages
- Clear naming is important
193
Slide 194
Slide 194 text
- Simple and shy packages
- Clear naming is important
- No global state at all
194
Slide 195
Slide 195 text
- Simple and shy packages
- Clear naming is important
- No global state at all
- Interfaces are for abstraction
195
Slide 196
Slide 196 text
196
- Simple and shy packages
- Clear naming is important
- No global state at all
- Interfaces are for abstraction
- Modules == Go ecosystem 2.0
Slide 197
Slide 197 text
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
Slide 198
Slide 198 text
Thank you
Packages & Modules
Slide 199
Slide 199 text
- Ben Johnson @benbjohnson
- Dave Cheney @davecheney
- Jaana B. Dogan @rakyll
- Go team ʕ◔ϖ◔ʔ
- all the friends \o/
199