github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/talks/2014/readability.slide (about) 1 When in Go, do as Gophers do 2 Go Conference 2014 autumn 3 30 Nov 2014 4 5 Fumitoshi Ukai 6 Google Software Engineer - Chrome Infra team 7 ukai@google.com 8 https://plus.google.com/+FumitoshiUkai 9 @fumitoshi_ukai 10 11 * Go Readability Approver 12 13 A team to review Go readability. 14 15 - help to learn idiomatic Go though code review 16 - review code of projects that are not main project of the reviewer 17 18 - [[http://blogger.ukai.org/2013/12/code-readability.html][I joined the team about a year ago]] as 20% time, and reviewed ~200 CLs 19 - For now, I'm reviewing at most 3 CLs per day, 12 CLs per week. 20 21 .image readability/project.png 22 .caption _Gopher_ by [[http://www.reneefrench.com][Renée French]] 23 24 * What is Readability skill? 25 26 Literacy of a programming language. 27 28 A skill to read or write *idiomatic* code. 29 30 Each programming language has its own preferred style. 31 In C++, each project chooses a preferred style. 32 33 - [[http://google-styleguide.googlecode.com/svn/trunk/cppguide.html][google]] ([[http://www.chromium.org/developers/coding-style][chromium]]), [[https://www.webkit.org/coding/coding-style.html][webkit]] ([[http://www.chromium.org/blink/coding-style][blink]]) 34 35 Don't write Go code as you write code in C++/Java/Python. 36 Write Go code as Gophers write code. 37 38 * Go code should ... 39 40 - be articulate, concise. 41 - provide a simple API. 42 - have precise comments. 43 - be readable, top-down code. 44 45 _"_Want_to_understand_something_in_google_servers?_Read_the_Go_implementation!_"_ 46 47 .caption by some Googler 48 49 .image readability/pkg.png 50 .caption _Gopher_ by [[http://www.reneefrench.com][Renée French]] 51 52 53 * Good tools 54 55 [[https://golang.org/cmd/gofmt/][go fmt]] - format Go programs. 56 [[https://godoc.org/golang.org/x/tools/cmd/vet][go vet]] - report suspicious code 57 [[https://github.com/golang/lint][golint]] - report coding style errors. 58 [[http://blog.golang.org/godoc-documenting-go-code][godoc]] - browse documenation 59 60 # Go code is easy to read for tools too. 61 62 * Tools are not enough 63 64 # Developer doesn't read code the same as tools. 65 # Programs(compiler, etc) will read code if its syntax is ok. 66 # Tools are not enough, have false-positive/false-negative. 67 # Needs human judgments. 68 69 Readable code == easy to recognize, less burden for brain. 70 Both writer and reader should have readability skills. 71 Go is very simple ([[https://golang.org/ref/spec][lang spec]] is about 50 pages) 72 73 .image readability/gophers5th.jpg 74 .caption _Gopher_ by [[http://www.reneefrench.com][Renée French]] 75 76 * Readability Reviews 77 78 - Any mistakes/bugs? 79 - Layout? 80 - Simple code flow? 81 - Simple API? 82 83 .image readability/gopher-ok-no.png 84 .caption _Gopher_ by [[http://www.reneefrench.com][Renée French]], and [[https://github.com/tenntenn/gopher-stickers/][tenntenn]] 85 86 * mistakes/bugs 87 88 * error check 89 90 original code 91 92 .code readability/err_regexp_bad.go 93 94 revised 95 96 .code readability/err_regexp_good.go 97 98 - Check error with [[https://golang.org/pkg/regexp/#MustCompile][regexp.MustCompile]]. 99 - Must should be used only in [[http://golang.org/ref/spec#Package_initialization][initialization]] (package `var` or `init()`). 100 101 - [[http://golang.org/ref/spec#String_literals][Raw string literal]] makes it easy to read regexp. 102 103 * error check: original code 104 105 .code readability/err_close_write_bad.go 106 107 * error check: revised 108 109 .code readability/err_close_write_good.go 110 111 - Check error of Close for write. 112 - No need to use defer, when it's simpler. 113 114 * in-band error: original code 115 116 .code readability/in-band-error-client.go 117 118 .code readability/in-band-error.go 119 120 * return value and error: revised 121 122 .code readability/val-and-error.go 123 124 [[http://golang.org/doc/effective_go.html#multiple-returns][Return error as error, not as some value]] 125 126 * error design 127 128 If client doesn't need to distinguish errors, e.g. ok with `err` `!=` `nil` check only. 129 130 fmt.Errorf("error in %s", val) or errors.New("error msg") 131 132 If client wants to distinguish several errors by error code. 133 134 var ( 135 ErrInternal = errors.New("foo: inetrnal error") 136 ErrBadRequest = errors.New("foo: bad request") 137 ) 138 139 If you want to put detailed information in error. 140 141 type FooError struct { /* fields of error information */ } 142 func (e *FooError) Error() string { return /* error message */ } 143 144 &FooError{ /* set error data */ } 145 146 Don't use `panic`. 147 But when you do, use it only within the package, and [[http://golang.org/doc/effective_go.html#recover][return error with catching it by recover]]. 148 149 * nil error 150 151 .code readability/nil_error.go 152 153 [[https://golang.org/doc/faq#nil_error][FAQ: Why is my nil error value not equal to nil?]] 154 155 [[http://blog.golang.org/laws-of-reflection][interface has 2 data]] (type and value). interface value is nil == both are nil. 156 157 * embed interface: original code 158 159 .code readability/implement-interface-bad.go 160 161 - `scan.Writer` is an interface. 162 - `ColumnWriter` will have methods of the `scan.Writer` interface (i.e. `ColumnWriter` implements the `scan.Writer` interface), but ... 163 164 * check interface implementation: revised 165 166 .code readability/implement-interface-good.go 167 168 - The original author wanted to check `ColumnWriter` [[http://golang.org/doc/effective_go.html#blank_implements][implements]] the `scan.Writer` interface. 169 170 * embed interface 171 172 If a struct doesn't have a method of a interface explicitly, the interface is embedded in the struct, and you didn't set the interface field to a concrete value (i.e. the interface field value is nil), the method call will panic. 173 174 .code readability/nil_interface_en.go 175 176 It would be useful in a test when you want to implement only a subset of methods in the huge interface. 177 178 * Readable layout 179 180 * layout of fields in struct: original code 181 182 .code readability/struct-field-bad.go 183 184 * layout of fields in struct: revised 185 186 .code readability/struct-field-good.go 187 188 - Organize fields in groups, with blank lines between them. 189 - Put [[https://golang.org/pkg/sync/#Mutex][sync.Mutex]] in top of a block of fields that the mutex protects. 190 191 * Long line 192 193 .code readability/long-line-fold.go 194 195 * Merge into one line 196 197 .code readability/long-line-nofold.go 198 199 - [[https://golang.org/s/comments#Line_Length][No rigid line length limit]] 200 - though, can't we make it shorter? 201 202 * Choose concise names 203 204 [[https://golang.org/s/comments#Variable_Names][Choose good name in the context]] 205 206 - Long names are not always better than short names. 207 208 Short and accurate names. 209 210 - [[https://golang.org/s/comments#Package_Names][SamplingServer in sampling package is stutter]]. Name `Server`, which clients will write as `sampling.Server`. 211 - Use [[https://golang.org/s/comments#Receiver_Names][one or two letters for receiver names]]. 212 - Use short names for parameters since type name will give some information. 213 - Use descriptive names for basic types, though. 214 - Use short names for local variables: prefer `i` to `index`, `r` to `reader`. 215 - Short names should be fine if function is not long. 216 217 * Revised one line version 218 219 .code readability/long-line-short.go 220 221 * top-down code 222 223 * conditional branch 224 225 - [[https://golang.org/s/comments#Indent_Error_Flow][Keep the normal code path at a minimal indentation.]] 226 227 original code 228 229 .code readability/if-else-bad.go 230 231 revised 232 233 .code readability/if-else-good.go 234 235 * conditional branch (2): original code 236 237 .code readability/resthandler.go 238 239 * conditional branch (2): revised 240 241 .code readability/resthandler-fix2.go 242 243 - factor out function. 244 245 * conditional branch (3): original code 246 247 .code readability/if-switch-bad.go 248 249 * conditional branch (3): revised 250 251 .code readability/if-switch-good.go 252 253 - use [[http://golang.org/ref/spec#Switch_statements][switch]] 254 255 * Simpler code 256 257 * time.Duration 258 259 Use [[https://golang.org/pkg/time/#Duration][time.Duration]] ([[https://golang.org/pkg/flag/#Duration][flag.Duration]]) rather than `int` or `float` to represent time duration. 260 261 original code 262 263 .code readability/time_duration_bad.go 264 .code readability/time_duration_bad1.go 265 .code readability/time_duration_bad2.go 266 267 revised 268 269 .code readability/time_duration_good.go 270 271 - Don't write unnecessary type conversion. 272 - Since [[http://blog.golang.org/constants][const is untyped]], no need to convert 30 to `time.Duration`. 273 - Don't write unnecessary comments. 274 275 * sync.Mutex and sync.Cond: original code 276 277 .code readability/close-cond-bad.go 278 279 * chan: revised 280 281 .code readability/close-cond-good.go 282 283 - You could use [[http://golang.org/ref/spec#Channel_types][chan]], instead of [[https://golang.org/pkg/sync/#Mutex][sync.Mutex]] and [[https://golang.org/pkg/sync/#Cond][sync.Cond]]. 284 285 * reflect: original code 286 287 .code readability/reflect-bad.go 288 289 * without reflect: revised 290 291 .code readability/reflect-good.go 292 293 - Don't use [[https://golang.org/pkg/reflect/][reflect]], if you know the type at compilation time. 294 295 * Test 296 297 * Test code 298 299 .code readability/test-pattern_en.go 300 301 - [[https://golang.org/s/comments#Useful_Test_Failures][Have helpful test failure messages]] 302 - Don't create yet-another assert function. Use existing programming language features. 303 - Write [[https://golang.org/pkg/testing/#hdr-Examples][an example test]] rather than writing how to use API in a doc comment. 304 305 .code readability/example_test.go 306 307 * Comment 308 309 * Comment 310 311 [[https://golang.org/s/comments#Package_Comments][Write package comment.]] Write command comment in main package. 312 [[https://golang.org/s/comments#Doc_Comments][Write comments on exported names.]] 313 [[https://golang.org/s/comments#Comment_Sentences][Doc comment should be a complete sentence that starts with the name being declared.]] 314 315 // Package math provides basic constants and mathematical functions. 316 package math 317 318 // A Request represents a request to run a command. 319 type Request struct { .. 320 321 // Encode writes the JSON encoding of req to w. 322 func Encode(w io.Writer, req *Request) { 323 324 Browse with [[http://blog.golang.org/godoc-documenting-go-code][godoc]] 325 326 $ godoc bytes Buffer 327 328 $ godoc -http=:6060 # http://localhost:6060/pkg 329 330 If you feel comments are unclear or hard to write concisely, reconsider your API design. 331 332 * API design 333 334 Important to choose a good package name. 335 336 - e.g. package `util` is not good name, since most packages are utilities of something. 337 # split it into smaller packages, or merge it in bigger package, or wrong package boundary. 338 339 Make API simple. 340 341 - [[http://golang.org/doc/effective_go.html#multiple-returns][Use multiple returns]]. Don't use pointers as output parameters. 342 - Don't use pointer to slice, map, chan or interface. 343 - [[http://golang.org/doc/effective_go.html#multiple-returns][Return error as error]]: [[https://golang.org/s/comments#Don't_Panic][don't panic]] 344 - Implement common interfaces ([[https://golang.org/pkg/fmt/#Stringer][fmt.Stringer]], [[https://golang.org/pkg/io/#Reader][io.Reader]] and so on) if they match your code. 345 - Use interfaces for parameters. They makes it easier to test. e.g.: If a function reads from a file, use [[https://golang.org/pkg/io/#Reader][io.Reader]] as a parameter instead of [[https://golang.org/pkg/os/#File][*os.File]]. 346 - Prefer synchronous API to async API: refrain from using chan across package boundary. 347 - Clients can easily run synchronous API concurrently with goroutine and chan. 348 349 * To write readable code 350 351 * Code is communication 352 353 Be articulate: 354 355 - Choose good names. 356 - Design simple APIs. 357 - Write precise documentation. 358 - Don't be too complicated. 359 360 .image readability/talks.png 361 .caption _Gopher_ by [[http://www.reneefrench.com][Renée French]] 362 363 * When you write code 364 365 Keep in mind 366 367 - Articulate, concise. 368 - Provide simple API. 369 - Have precise comment. 370 - Readable, top-down code. 371 372 * References 373 374 - Effective Go: [[https://golang.org/doc/effective_go.html][https://golang.org/doc/effective_go.html]] 375 - standard package: [[https://golang.org/pkg/][https://golang.org/pkg/]] 376 - Code Review Comments: [[https://golang.org/s/comments][https://golang.org/s/comments]] 377 378 - Go for gophers: [[http://talks.golang.org/2014/go4gophers.slide][http://talks.golang.org/2014/go4gophers.slide]] 379 - What's in a name? [[http://talks.golang.org/2014/names.slide][http://talks.golang.org/2014/names.slide]] 380 - Organizing Go code: [[http://talks.golang.org/2014/organizeio.slide][http://talks.golang.org/2014/organizeio.slide]] 381 382 .image readability/ref.png 383 .caption _Gopher_ by [[http://www.reneefrench.com][Renée French]]