how to think in go
TRANSCRIPT
![Page 1: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/1.jpg)
How To Think In Goor, let me tell you about all the ways I screwed up
![Page 2: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/2.jpg)
![Page 3: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/3.jpg)
![Page 4: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/4.jpg)
![Page 5: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/5.jpg)
![Page 7: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/7.jpg)
Panics and Errors
![Page 8: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/8.jpg)
“Oh look, panic() and rescue()! I can probably use it like lightweight exceptions!”
Misconception
![Page 9: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/9.jpg)
![Page 10: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/10.jpg)
! panic: unrecoverable errors ! error: recoverable errors
panic / error
![Page 11: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/11.jpg)
sub foo { eval { might_die(); }; if ($@) { # handle $@ } important_task(); }
Perl: Exceptions
![Page 12: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/12.jpg)
func main() { defer func() { if err := recover(); err != nil { // handle err } }() mightPanic() importantTask() // Never reached if mightPanic() panics }
A bad port
![Page 13: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/13.jpg)
func mightPanic() { defer func() { if err := recover(); err != nil { // handle err } }() panic(“BOO!”) }
func main() { mightPanic() importantTask() }
Attempt #2
![Page 14: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/14.jpg)
func main() { if err := tryit(mightPanic); err != nil { fmt.Printf(“Found error: %s\n”, err) } importantTask() }
func mightPanic() { panic(“BOO!”) }
Attempt #3
![Page 15: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/15.jpg)
func tryit(code func()) (err error) { defer func() { if e := recover(); e != nil { var ok bool if err, ok = e.(error); !ok { err = fmt.Errorf("%s", e) } } }() code() return err }
Attempt #3
![Page 16: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/16.jpg)
![Page 17: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/17.jpg)
“Why don’t I just use plain errors to begin with?”
Go Way
![Page 18: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/18.jpg)
func mightError() error { if errorCase { return errors.New(“error case 1”) } if err := someOtherThingMightError(); err != nil { // propagate error return err } return nil }
Use errors!
![Page 19: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/19.jpg)
func main() { if err := mightError(); err != nil { // handle it } importantTask() }
Use errors!
![Page 20: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/20.jpg)
! Do not dream about exceptions ! Do stick with errors
Use errors!
![Page 21: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/21.jpg)
Concurrency
![Page 22: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/22.jpg)
“Go’s makes concurrency so easy, we can just port our multi-process code in an instant!”
Misconception
![Page 23: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/23.jpg)
![Page 24: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/24.jpg)
! PIDs to identify processes ! Processes can be signaled ! Processes can notify termination
Processes
![Page 25: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/25.jpg)
! No pid to identify goroutines ! No signals to communicate ! Goroutines don’t notify on exit
Goroutine
![Page 26: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/26.jpg)
sub sub main { my $pid = fork(); if (! defined $pid) { die “Failed to fork: $!” } if (! $pid) { while(1) { do_stuff() } } $SIG{CHLD} = sub { my $pid = wait; print “reaped $pid\n”; };
sleep 5; kill TERM => $pid; while (kill 0 => $pid) { sleep 1 } }
Perl: Processes
![Page 27: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/27.jpg)
func main() { // Won’t work go func() { for { doStuff() } } }
Go: A simple goroutine
![Page 28: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/28.jpg)
func main() { exitCh := make(chan struct{}) go func() { defer func() { close(exitCh) }() // close upon termination for { doStuff() } } <-exitCh // Wait for something to happen }
Go: Detect termination
![Page 29: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/29.jpg)
func main() { exitCh := make(chan struct{}) incomingCh := make(chan struct{}) go func() { defer func() { close(exitCh) }() // close upon termination for { select { case <-incomingCh: // Got termination request return } doStuff() } }
Go: Accept Termination Request
![Page 30: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/30.jpg)
// Send request to terminate loop time.AfterFunc(5 * time.Second, func() { incomingCh <-struct{}{} }) <-exitCh // Wait for something to happen }
Go: Accept Termination Request
![Page 31: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/31.jpg)
! Explicit coordination required ! No goroutine specific storage
Goroutine
![Page 32: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/32.jpg)
! You must explicitly bail out for infinite loops in goroutines
One more thing:
![Page 33: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/33.jpg)
! Still, goroutines are worth it ! Channels can do much more
Too much hassle?
![Page 34: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/34.jpg)
Designing Structures
![Page 35: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/35.jpg)
“Structs and methods will allow us to make our Object-oriented code easy to port”
Misconception
![Page 36: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/36.jpg)
![Page 37: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/37.jpg)
Worker::Base
Worker::Foo Worker::Foo Worker::Foo
![Page 38: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/38.jpg)
package Worker::Base; # snip sub foo { # do stuff.. shift->something_overridable_in_child_class(); }
sub something_overridable_in_child_class { … }
Perl: Interaction Between Parent/Child
![Page 39: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/39.jpg)
package Worker::Foo; # snip use parent qw(Worker::Base); sub something_overridable_in_child_class { … } sub work { my $self = shift; while (1) { # do stuff… $self->foo(); # Doesn’t translate very well into Go } }
Perl: Interaction Between Parent/Child
![Page 40: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/40.jpg)
![Page 41: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/41.jpg)
! No. Just No. ! Embedded structs + Automatic Delegation
Go: No Inheritance
![Page 42: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/42.jpg)
type Name string func (n Name) Greet() string { return fmt.Sprintf(“Hello, my name is %s”, n) }
Go: Name
![Page 43: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/43.jpg)
n := Name(“Daisuke Maki”) println(n.Greet()) // “Hello, my name is Daisuke Maki”
Go: Name
![Page 44: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/44.jpg)
type Person struct { Name // Embedded struct Age uint // A regular field }
Go: Person
![Page 45: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/45.jpg)
p := &Person{ Name: Name(“Daisuke Maki”), Age: 38 }
println(p.Greet()) // “Hello, my name is Daisuke Maki”
Go: Automatic Delegation
![Page 46: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/46.jpg)
p.Greet() // → p.Name.Greet() // The receiver is p.Name, not p.
Go: Automatic Delegation
![Page 47: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/47.jpg)
func (p Person) Greet() string { return fmt.Sprintf( “%s. I’m %d years old”, p.Super.Greet(), // Pseudo-code. Doesn’t work p.Age, ) }
Go: Customizing Person.Greet()
![Page 48: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/48.jpg)
type BaseWorker struct {} func (w BaseWorker) Foo() { // This only class BaseWorker.SomethingOverridableInChildClass() w.SomethingOverridableInChildClass() }
type FooWorker struct { BaseWorker } func (w FooWorker) Work() { for { // Do interesting stuff… w.Foo() // w.BaseWorker.Foo(), receiver is never FooWorker } }
Go: Another Failed Attempt
![Page 49: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/49.jpg)
Wrong Approach: Top Down
Abstract Base Class
Concrete Implementation
Specialized Implementation
…
…
![Page 50: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/50.jpg)
Suggested Approach: Bottom Up
Type A
Component 1
Component 2
Component 3
Component 4
Type B Type C
![Page 51: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/51.jpg)
! Interfaces ! Promise that a type has certain
methods
Go: Grouping Types
![Page 52: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/52.jpg)
type Greeter interface { Greet() string }
func main() { p := &Person{ Name: “Mary Jane”, Age: 30 } n := Name(“John Doe”) greeters := []Greeters{ p, n } … }
Go: Things that can Greet()
![Page 53: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/53.jpg)
func sayHello(g Greeter) { println(g.Greet()) }
for _, g := range greeters { sayHello(g) }
Go: Things that can Greet()
![Page 54: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/54.jpg)
! Think in terms of ability (methods) ! But note: no “base” method
implementations
Go: Interfaces
![Page 55: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/55.jpg)
// WRONG! No methods for interfaces func (g Greeter) SayHello() { println(g.Greet()) }
Go: No “base” methods
![Page 56: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/56.jpg)
// OK. Functions that take interfaces work func sayHello(g Greeter) { println(g.Greet()) }
// Each type would have to make this call func (n Name) SayHello() { sayHello(n) // Name is a Greeter }
func (p Person) SayHello() { sayHello(n) // And so is Person, through delegation to p.Name }
Go: No “base” methods
![Page 57: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/57.jpg)
! Think of abilities, not Is-A, Has-A ! Compose from smaller components
Go: Designing Models
![Page 58: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/58.jpg)
! Don’t Use Exception: Use errors
Conclusions
![Page 59: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/59.jpg)
! Don’t Expect Goroutines = Threads/Processes
Conclusions
![Page 60: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/60.jpg)
! Don’t Design Using Tree-style hierarchy ! Create layers of standalone functionalities ! Compose them ! Use interfaces
Conclusions
![Page 61: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/61.jpg)
! (If you haven’t already heard) When In Go, Do As The Gophers Do
Conclusions
![Page 62: How To Think In Go](https://reader031.vdocument.in/reader031/viewer/2022022203/5875859e1a28ab901c8b4ad1/html5/thumbnails/62.jpg)
Thank YouFurther reading:
! https://talks.golang.org/2014/readability.slide ! https://talks.golang.org/2014/gocon-tokyo.slide ! https://talks.golang.org/2013/bestpractices.slide ! http://blog.golang.org/errors-are-values