Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

How To Think In Go

787 views

Published on

See also (Sorry, mainly in Japanese)
http://go-talks.appspot.com/github.com/lestrrat/go-slides/tree/master/2014-golangstudy-HDE
http://go-talks.appspot.com/github.com/lestrrat/go-slides/2014-yapcasia-go-for-perl-mongers/main.slide#1

Published in: Internet
  • Be the first to comment

How To Think In Go

  1. 1. How To Think In Go or, let me tell you about all the ways I screwed up
  2. 2. https://www.flickr.com/photos/spam/3355824586
  3. 3. Panics and Errors
  4. 4. “Oh look, panic() and rescue()! I can probably use it like lightweight exceptions!” Misconception
  5. 5. ! panic: unrecoverable errors ! error: recoverable errors panic / error
  6. 6. sub foo { eval { might_die(); }; if ($@) { # handle $@ } important_task(); } Perl: Exceptions
  7. 7. func main() { defer func() { if err := recover(); err != nil { // handle err } }() mightPanic() importantTask() // Never reached if mightPanic() panics } A bad port
  8. 8. func mightPanic() { defer func() { if err := recover(); err != nil { // handle err } }() panic(“BOO!”) } func main() { mightPanic() importantTask() } Attempt #2
  9. 9. func main() { if err := tryit(mightPanic); err != nil { fmt.Printf(“Found error: %sn”, err) } importantTask() } func mightPanic() { panic(“BOO!”) } Attempt #3
  10. 10. 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
  11. 11. “Why don’t I just use plain errors to begin with?” Go Way
  12. 12. func mightError() error {      if errorCase {           return errors.New(“error case 1”)      }      if err := someOtherThingMightError(); err != nil {           // propagate error           return err      }      return nil } Use errors!
  13. 13. func main() {      if err := mightError(); err != nil {          // handle it      }      importantTask() } Use errors!
  14. 14. ! Do not dream about exceptions ! Do stick with errors Use errors!
  15. 15. Concurrency
  16. 16. “Go’s makes concurrency so easy, we can just port our multi-process code in an instant!” Misconception
  17. 17. ! PIDs to identify processes ! Processes can be signaled ! Processes can notify termination Processes
  18. 18. ! No pid to identify goroutines ! No signals to communicate ! Goroutines don’t notify on exit Goroutine
  19. 19. 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 $pidn”;      };      sleep 5;      kill TERM => $pid;      while (kill 0 => $pid) { sleep 1 } } Perl: Processes
  20. 20. func main() { // Won’t work     go func() { for { doStuff() } } } Go: A simple goroutine
  21. 21. 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
  22. 22. 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
  23. 23. // Send request to terminate loop time.AfterFunc(5 * time.Second, func() { incomingCh <-struct{}{} }) <-exitCh // Wait for something to happen } Go:Accept Termination Request
  24. 24. ! Explicit coordination required ! No goroutine specific storage Goroutine
  25. 25. ! You must explicitly bail out for infinite loops in goroutines One more thing:
  26. 26. ! Still, goroutines are worth it ! Channels can do much more Too much hassle?
  27. 27. Designing Structures
  28. 28. “Structs and methods will allow us to make our Object-oriented code easy to port” Misconception
  29. 29. Worker::Base Worker::Foo Worker::Foo Worker::Foo
  30. 30. 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
  31. 31. 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
  32. 32. ! No. Just No. ! Embedded structs + Automatic Delegation Go: No Inheritance
  33. 33. type Name string func (n Name) Greet() string { return fmt.Sprintf(“Hello, my name is %s”, n) } Go: Name
  34. 34. n := Name(“Daisuke Maki”) println(n.Greet()) // “Hello, my name is Daisuke Maki” Go: Name
  35. 35. type Person struct { Name // Embedded struct Age uint // A regular field } Go: Person
  36. 36. p := &Person{ Name: Name(“Daisuke Maki”), Age: 38 } println(p.Greet()) // “Hello, my name is Daisuke Maki” Go: Automatic Delegation
  37. 37. p.Greet() // → p.Name.Greet() // The receiver is p.Name, not p. Go: Automatic Delegation
  38. 38. 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()
  39. 39. 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
  40. 40. Wrong Approach:Top Down Abstract Base Class Concrete Implementation Specialized Implementation … …
  41. 41. Suggested Approach: Bottom Up Type A Component 1 Component 2 Component 3 Component 4 Type B Type C
  42. 42. ! Interfaces ! Promise that a type has certain methods Go: Grouping Types
  43. 43. 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()
  44. 44. func sayHello(g Greeter) {     println(g.Greet()) } for _, g := range greeters {     sayHello(g) } Go:Things that can Greet()
  45. 45. ! Think in terms of ability (methods) ! But note: no “base” method implementations Go: Interfaces
  46. 46. // WRONG! No methods for interfaces func (g Greeter) SayHello() {     println(g.Greet()) } Go: No “base” methods
  47. 47. // 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
  48. 48. ! Think of abilities, not Is-A, Has-A ! Compose from smaller components Go: Designing Models
  49. 49. ! Don’t Use Exception: Use errors Conclusions
  50. 50. ! Don’t Expect Goroutines = Threads/ Processes Conclusions
  51. 51. ! Don’t Design Using Tree-style hierarchy ! Create layers of standalone functionalities ! Compose them ! Use interfaces Conclusions
  52. 52. ! (If you haven’t already heard) 
 When In Go, Do As The Gophers Do Conclusions
  53. 53. Thank You Further 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

×