-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathintroduction-to-go2-v2.slide
770 lines (462 loc) · 23 KB
/
introduction-to-go2-v2.slide
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
Introduction to Go (Part 2) v2
10 Jul 2018
Ivan Kutuzov
https://golang.org.ua
https://golang-ua.slack.com
@arbrix
* License and Materials
Dave Cheney is the original author of all this materials
This presentation is licensed under the [[https://creativecommons.org/licenses/by-sa/4.0/][Creative Commons Attribution-ShareAlike 4.0 International]] licence.
The materials for this presentation are available on GitHub:
.link https://github.com/davecheney/introduction-to-go
You are encouraged to remix, transform, or build upon the material, providing you give appropriate credit and distribute your contributions under the same license.
If you have suggestions or corrections to this presentation, please raise [[https://github.com/davecheney/introduction-to-go/isues][an issue on the GitHub project]].
* Agenda
- Development environment and tooling
- The standard library
- Packages and applications
* Development environment and tooling
* Development environment and tooling
This section focuses on the developer experience
- Installing Go.
- Setting up a `$GOPATH` workspace.
- Introduction to the `go` command.
- Writing unit tests with the go test command.
* Installing Go
The next few slides give examples of how to install Go on various systems.
The official installation documentation is here:
.link https://golang.org/doc/install
The current version of Go is 1.10.3.
- New minor releases, Go 1.11, Go 1.12, etc, ship twice a year.
- Historically 2–4 bug fix or security releases occur during each six month period.
* Installing Go on OS X
Installing Go on OS X (also known as `darwin`) can be accomplished with
*Mac*OS*Installer*
The Go project provides an `.pkg` installer, use:
.link https://storage.googleapis.com/golang/go1.10.3.darwin-amd64.pkg
*Homebrew*
If you use Homebrew to manage third party software on your Mac, use:
brew install golang
*MacPorts*
If you use MacPorts to manage third party software on your Mac, use:
sudo port install go
* Installing Go on Windows
*MSI*Installer*
The Go project provides a `.msi` installer for 32bit and 64bit Windows, use:
.link https://storage.googleapis.com/golang/go1.10.3.windows-amd64.msi Windows 64bit MSI installer
.link https://storage.googleapis.com/golang/go1.10.3.windows-386.msi Windows 32bit MSI installer
*.zip*file*
The Go project provides a `.zip` file of the Go compiler and standard library, use:
.link https://storage.googleapis.com/golang/go1.10.3.windows-amd64.zip Windows 64bit zip file
.link https://storage.googleapis.com/golang/go1.10.3.windows-386.zip Windows 32bit zip file
Unzip the zip file and place it at `C:\Go`.
* Installing Go on Linux
Depending on your Linux distribution they may have an up to date version of Go, but this is rare.
The most reliable way to install the latest version of Go is to untar
.link https://storage.googleapis.com/golang/go1.10.3.linux-amd64.tar.gz
to the directory
/usr/local
and add
/usr/local/go/bin
to your `$PATH`.
echo "export PATH=$PATH:/usr/local/go/bin" >> ~/.bash_profile
* Go tool
Your Go installation comes with a tool we call the `go` tool, because that's its name.
The `go` tool can
- compile your programs
- run your tests
- display documentation for a package
- fetch packages from the internet.
* $GOPATH
The `go` tool works inside a workspace where _all_ your Go source code is stored.
All the source code for this workshop is included with this repository.
You can set `$GOPATH` to be the base directory where you checked out this repository. eg.
% export GOPATH=$HOME/introduction-to-go
Using a workspace allows you to import code from other packages with a fixed name. eg.
import "github.com/pkg/profile"
Will import the code for the `profile` package stored in
$GOPATH/src/github.com/pkg/profile
* Golang workspace
A workspace is a directory hierarchy with three directories at its root:
- src contains Go source files,
- pkg contains package objects, and
- bin contains executable commands.
[[https://golang.org/doc/code.html#Workspaces][Workspace]]
* Coding style
All Go code is formatted according to a single style guide which is enforced with a tool called `gofmt`
Having one single style that all Go code is formatted in improves readability and avoids the time wasted arguing about code formatting.
"Gofmt's style is no one's favorite, yet gofmt is everyone's favorite."
.caption [[https://go-proverbs.github.io/][Go Proverb]].
The Go playground can format your code according to the canonical Go style.
* Packages
* Packages
A package is the unit in which software is shared and reused in Go. All Go code is arranged into packages.
Each source file in a package must begin with the same `package` declaration.
A package's name must be a valid identifier, just like `const`, `var`, and `func`.
.code -edit src/packages/packages1/main.go
`package`main` is the name of the package which contains the entry point to your program, `func`main`.
* main packages
This program has the wrong `package` declaration.
.code -edit src/packages/packages2/main.go
- Change the `package` declaration to make the program compile.
* Import
The final declaration we'll cover in this section is the _import_ declaration.
The `import` declaration allows you to use code from other _packages_ into your package.
When you `import` a package, the _public_ types, functions, variables, types, and constants, are available with a prefix of the package's name.
time.Now // denotes the Now function in package time
Note that
import "fmt"
import "time"
and
import (
"fmt"
"time"
)
both import the `fmt` and `time` packages. The syntax is different, but they are equivalent.
* Import (cont.)
The `import` declaration must appear _after_ the `package` declaration, but before any `type`, `const`, `var`, or `func` declarations.
.code -edit src/imports/imports1/main.go
This program does not compile as the `import` declaration is in the wrong place.
- Move the `var`now`=`time.Now()` declaration _below_ the `import` declaration.
* Import (cont.)
Packages contain both _public_ and _private_ symbols. We also call these _exported_ and _not_exported_, respectively.
.code -edit src/imports/imports2/main.go
This program does not compile as it refers to two _private_ symbols.
- Fix the program by using the correct case for `Println` and `Time`.
_note_: If you are running this slide from [[https://go-talks.golang.org/][gotalks.golang.org]], the time may be reported as `2009-11-10`23:00:00`+0000`UTC`. This is a technical limitation.
* Circular dependencies
It’s the belief of Golang developers that circular dependencies are design flaws.
If you have package *alice* that depends on package *bob* for some things, and then you have package *bob* that depends on package *alice* for some things,… it shouldn’t be necessary to join packages *alice* and *bob* into one package to resolve the circular dependency.
Write programs that do one thing and do it well. (Solid)
* The standard library
* fmt package
Do you remember this program?
.code -edit src/imports/imports3/main.go
Here it is again, showing the `func`, `package` and `import` declarations making it a complete Go program.
This program also uses the `Println` function from the `fmt` package, which is more capable than the built in `println` function.
* fmt
The format verbs are derived from C's but are simpler. Some verbs (%-sequences) that can be used:
- %v The value in a default format. when printing structs, the plus flag (%+v) adds field names.
- %#v a Go-syntax representation of the value.
- %T a Go-syntax representation of the type of the value.
.link https://medium.com/go-walkthrough/go-walkthrough-fmt-55a14bbbfc53 Ben Johnson, Go Walkthrough: fmt
* io
This package provides basic interfaces to I/O primitives. Whether you have lists of bytes, streams of bytes, or individual bytes, Go makes it easy to process.
.link https://medium.com/go-walkthrough/go-walkthrough-io-package-8ac5e95a9fbd Ben Johnson, Go Walkthrough: io package
* bufio
This package implements buffered I/O.
- type Scanner
- func ScanBytes(data []byte, atEOF bool) (advance int, token []byte, err error)
- func ScanLines(data []byte, atEOF bool) (advance int, token []byte, err error)
- func ScanRunes(data []byte, atEOF bool) (advance int, token []byte, err error)
- func ScanWords(data []byte, atEOF bool) (advance int, token []byte, err error)
.link https://godoc.org/bufio GoDoc
* sort
The sort package provides primitives for sorting arrays and user-defined collections.
type Interface interface {
// Len is the number of elements in the collection.
Len() int
// Less reports whether the element with
// index i should sort before the element with index j.
Less(i, j int) bool
// Swap swaps the elements with indexes i and j.
Swap(i, j int)
}
but now just use proper func: Float64s, Ints, Strings
.link https://godoc.org/sort GoDoc
* strconv
The strconv package implements conversions to and from string representations of basic data types.
i, err := strconv.Atoi("-42")
s := strconv.Itoa(-42)
b, err := strconv.ParseBool("true")
f, err := strconv.ParseFloat("3.1415", 64)
i, err := strconv.ParseInt("-42", 10, 64)
u, err := strconv.ParseUint("42", 10, 64)
s := strconv.FormatBool(true)
s := strconv.FormatFloat(3.1415, 'E', -1, 64)
s := strconv.FormatInt(-42, 16)
s := strconv.FormatUint(42, 16)
.link https://medium.com/go-walkthrough/go-walkthrough-strconv-7a24632a9e73 Ben Johnson, Go Walkthrough: strconv
* bytes / strings
Byte slices represent a mutable, resizable, contiguous list of bytes.
Strings, on the other hand, represent an immutable, fixed-size, contiguous list of bytes.
At first glance the bytes and strings packages appear large but they are really just a collection of simple helper functions.
- Comparison functions
- Inspection functions
- Prefix/suffix functions
- Replacement functions
- Splitting & joining functions
.link https://medium.com/go-walkthrough/go-walkthrough-bytes-strings-packages-499be9f4b5bd Ben Johnson, Go Walkthrough: bytes + strings packages
* os
The os package provides a platform-independent interface to operating system functionality. The design is Unix-like.
file, err := os.Open("file.go") // For read access.
if err != nil {
log.Fatal(err)
}
Exported global variables:
var (
Stdin = NewFile(uintptr(syscall.Stdin), "/dev/stdin")
Stdout = NewFile(uintptr(syscall.Stdout), "/dev/stdout")
Stderr = NewFile(uintptr(syscall.Stderr), "/dev/stderr")
)
.link https://godoc.org/os GoDoc
* sync
The package sync provides basic synchronization primitives such as mutual exclusion locks.
- type Mutex
- type Pool
- type WaitGroup
.link https://godoc.org/sync GoDoc
* flag
The flag package implements command-line flag parsing.
import "flag"
var ip = flag.Int("flagname", 1234, "help message for flagname")
flag.Var(&flagVal, "name", "help message for flagname")
flag.Parse()
.link https://godoc.org/flag GoDoc
* encoding/json
The encoding/json package implements encoding and decoding of JSON objects as defined in RFC 4627
type Encoder struct {}
func NewEncoder(w io.Writer) *Encoder
func (enc *Encoder) Encode(v interface{}) error
func Marshal(v interface{}) ([]byte, error)
type Decoder struct {}
func NewDecoder(r io.Reader) *Decoder
func (dec *Decoder) Decode(v interface{}) error
func Unmarshal(data []byte, v interface{}) error
.link https://medium.com/go-walkthrough/go-walkthrough-encoding-json-package-9681d1d37a8f Ben Johnson, Go Walkthrough: encoding/json package
* JSON encoding
The `encoding/json` package requires the fields of a struct to be public (start with an upper case letter), this means the keys in your JSON document will be upper case.
We can fix this and control the output of the JSON with a _tag_.
The format of the JSON tag is documented on the [[https://golang.org/pkg/encoding/json/#Marshal][`json.Encode`]] method.
.code -edit src/jsonenc/jsonenc2.go /START OMIT/,/END OMIT/
* html/template
Data-driven templates for generating textual output such as HTML.
func HTMLEscape(w io.Writer, b []byte)
func HTMLEscapeString(s string) string
func HTMLEscaper(args ...interface{}) string
func IsTrue(val interface{}) (truth, ok bool)
func JSEscape(w io.Writer, b []byte)
func JSEscapeString(s string) string
func JSEscaper(args ...interface{}) string
func URLQueryEscaper(args ...interface{}) string
.link https://godoc.org/html/template GoDoc
* net/http request
Get, Head, Post, and PostForm make HTTP (or HTTPS) requests:
resp, err := http.Get("http://example.com/")
...
resp, err := http.Post("http://example.com/upload", "image/jpeg", &buf)
...
resp, err := http.PostForm("http://example.com/form",
url.Values{"key": {"Value"}, "id": {"123"}})
.link https://godoc.org/net/http GoDoc
* net/http client
client := &http.Client{
CheckRedirect: redirectPolicyFunc,
}
resp, err := client.Get("http://example.com")
// ...
req, err := http.NewRequest("GET", "http://example.com", nil)
// ...
req.Header.Add("If-None-Match", `W/"wyzzy"`)
resp, err := client.Do(req)
// ...
* net/http transport
tr := &http.Transport{
MaxIdleConns: 10,
IdleConnTimeout: 30 * time.Second,
DisableCompression: true,
}
client := &http.Client{Transport: tr}
resp, err := client.Get("https://example.com")
* net/http server
myHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path))
})
s := &http.Server{
Addr: ":8080",
Handler: myHandler,
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
MaxHeaderBytes: 1 << 20,
}
log.Fatal(s.ListenAndServe())
* net/http handler
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
type HandlerFunc func(ResponseWriter, *Request)
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request)
func Handle(pattern string, handler Handler)
* Let's make a break
* Documentation
* Documenting packages with comments
Go code is traditionally documented with comments in the source code. This is similar to Python's heredoc convention.
Here are some examples
// simplestrings provides simple helper functions to work with strings
package simplestrings
// APIVersion is the version of this package's API
const APIVersion = 3
// NextID returns the next ID in the sequence
func NextID() uint64 { ... }
_Notes_
- Comments directly precede the thing they apply to, don't put an extra newline in between the comment and the symbol
- You should comment both Public and private symbols, but godoc will only show you the Public as documents
* Testing
* Testing
I wanted to spend some time on testing because for the rest of the day we'll be using tests to complete code exercises.
The testing package can also contain benchmark functions and examples, which show up in godoc.
You should include tests for each package that you write.
The `testing` package is ideal for _unit_tests_. It's _ok_ for functional tests, but not really suitable for complex integration tests.
* go test
`go`test` is the unit testing framework built into the Go standard library. It lives in the `testing` package.
Tests live in `_test.go` files, eg. the `strings` package has these files:
- `strings.go` functions to manipulate UTF-8 encoded strings.
- `strings_test.go` tests for the `strings` package.
Each test is a function in the form
func TestNameOfTest(t *testing.T) { ... }
- `NameOfTest` is the name of your test, it _must_ start with an upper case letter.
- Test functions take a `testing.T` value, which provides helpers like `t.Error` and `t.Fail`.
* Test API
- `func`(t`*T)`Fail()`, Fail marks the test function as having failed but continues execution.
- `func`(t`*T)`FailNow()`, FailNow marks the test function as having failed and stops its execution. Any remaining tests in this file are skipped, and execution continues with the next test.
- `func`(t`*T)`Log(args`...interface{})`, Log formats its arguments using default formatting, analogous to Print(), and records the text in the error log.
- `func`(t`*T)`Fatal(args`...interface{})`, Fatal is equivalent to Log() followed by FailNow().
* Test coverage
`go`test` can report coverage
go test -coverprofile=cover.out
This produces a coverage file, `cover.out`
- `go`tool`cover`-func=cover.out` will print the coverage report
- `go`tool`cover`-html=cover.out` will open the report in a browser
* package is
simple, smole
func Test(t *testing.T) {
is := is.New(t)
a, b := 1, 2
is.Equal(a, b) // expect to be the same
}
Will output:
your_test.go:123: 1 != 2 // expect to be the same
.link https://youtu.be/MMnaq2jwAiE GothamGo 2016 - Quality Tests in Go by Mat Ryer
.link https://youtu.be/EOpj9aZ8Kfo dotGo 2017 - Mat Ryer - The Art of Testing
* Some best practices
* Write Code Like the Go Team
- how to organize your code into packages, and what those packages should contain
- code patterns and conventions that are prevalent in the standard library
- how to write your code to be more clear and understandable
- unwritten Go conventions that go beyond “go fmt” and make you look like a veteran Go contributor wrote it
.link https://youtu.be/MzTcsI6tn-0 Ashley McNamara + Brian Ketelsen. Go best practices.
* Code Organization
* Package Organization - Libraries
Packages contain code that has a single purpose
archive cmd crypto errors go index math path sort syscall unicode
bufio compress database expvar hash internal mime reflect strconv
testing unsafe builtin container debug flag
* Package Organization - Libraries
When a group of packages provides a common set of functionalities with different implementations, they're organized under a parent. Look at the contents of package encoding:
ascii85 base32 binary encoding.go hex pem
asn1 base64 csv gob json xml
* Package Organization - Libraries
- Packages names describe their purpose
- It's very easy to see what a package does by looking at the name
- Names are generally short
- When necessary, use a descriptive parent package and several children implementing the functionality -- like the encoding package
* Package Organization - Applications
They're intended to be imported and used by some executable program like a service or command line tool.
Application package organization has a huge impact on the testability and functionality of your system.
When writing an application your goal should be to write code that is easy to understand, easy to refactor, and easy for someone else to maintain.
* Package Organization - Applications
Most libraries focus on providing a singularly scoped function; logging, encoding, network access.
Your application will tie all of those libraries together to create a tool or service. That tool or service will be much larger in scope.
When you're building an application, you should organize your code into packages, but those packages should be centered on two categories:
- Domain Types
- Services
* Package Organization - Applications
Domain Types are types that model your business functionality and objects.
The domain type package, or root package of your application should not have any external dependencies.
It exists for the sole purpose of describing your types and their behaviors.
.link https://medium.com/@benbjohnson/standard-package-layout-7cdbc8391fc1 Ben Johnson, Standard Package Layout
* Package Organization - Applications
Services are packages that operate on or with the domain types.
The implementations of your domain interfaces should be in separate packages, organized by dependency.
Dependencies include:
- External data sources
- Transport logic (http, RPC)
You should have one package per dependency.
* Package Organization - Applications
- Simple testing
- Easy substitution/replacement
- No circular dependencies
* Conventions
* Naming Conventions - Packages
Naming things is hard, but putting some thought into your type, function, and package names will make your code more readable.
short:
- Prefer "transport" over "transportmechanisms"
clear:
- Name for clarity based on function: "bytes"
- Name to describe implementation of external dependency: "postgres"
* Naming Conventions - Packages
Packages should provide functionality for one and only one purpose. Avoid catchall packages:
- util
- helpers
- etc.
Frequently they're a sign that you're missing an interface somewhere.
* Naming Conventions - Variables
Some common conventions for variable names:
- use camelCase not snake_case
- use single letter variables to represent indexes
for i:=0; i < 10; i++ {}
- use short but descriptive variable names for other things
var count int
var cust Customer
There are no bonus points in Go for obfuscating your code by using unnecessarily short variables. Use the scope of the variable as your guide. The farther away from declaration you use it, the longer the name should be.
* Naming Conventions - Variables
- use repeated letters to represent a collection/slice/array
var tt []*Thing
- inside a loop/range, use the single letter
for i, t := range tt {}
These conventions are common inside Go's own source code.
* Naming Conventions - Functions and Methods
Avoid a package-level function name that repeats the package name.
GOOD: log.Info()
BAD: log.LogInfo()
The package name already declares the purpose of the package, so there's no need to repeat it.
Go code doesn't have setters and getters.
GOOD: custSvc.Customer()
BAD: custSvc.GetCustomer()
* Naming Conventions - Interfaces
If your interface has only one function, append "-er" to the function name:
type Stringer interface{
String() string
}
If your interface has more than one function, use a name to represent its functionality:
type CustomerStorage interface {
Customer(id int) (*Customer, error)
Save(c *Customer) error
Delete(id int) error
}
* Naming Conventions - Interfaces
Some purists think that all interfaces should end in -er. I think interfaces should be descriptive and readable.
type CustomerStorer interface {} // MEH
type CustomerStorage interface {} // Better
* Naming Conventions - Source Code
Inside a package separate code into logical concerns.
If the package deals with multiple types, keep the logic for each type in its own source file:
package: postgres
orders.go
suppliers.go
products.go
* Naming Conventions - Source Code
In the package that defines your domain objects, define the types and interfaces for each object in the same source file:
package: inventory
orders.go
-- contains Orders type
and OrderStorage interface
* Question time
* Resources
.link http://devs.cloudimmunity.com/gotchas-and-common-mistakes-in-go-golang/ 50 Shades of Go
.link https://go-traps.appspot.com Go Traps
.link https://gobyexample.com/ Go by Example
.link https://dave.cheney.net/resources-for-new-go-programmers Resources for new Go programmers
.link https://golang.org/doc/effective_go.html Effective Go
.link https://miek.nl/go/ LEARNING GO online book