a recovering java developer learns to go

74
A Recovering Java Developer Learns to Go Matt Stine (@mstine) Cloud Foundry Platform Engineer at Pivotal [email protected] http://www.mattstine.com OFFICE HOURS Wednesday, 2:30 - 3:10 PM Expo Hall (Table A)

Upload: matt-stine

Post on 10-May-2015

9.950 views

Category:

Documents


0 download

DESCRIPTION

As presented at OSCON 2014. The Go programming language has emerged as a favorite tool of DevOps and cloud practitioners alike. In many ways, Go is more famous for what it doesn’t include than what it does, and co-author Rob Pike has said that Go represents a “less is more” approach to language design. The Cloud Foundry engineering teams have steadily increased their use of Go for building components, starting with the Router, and progressing through Loggregator, the CLI, and more recently the Health Manager. As a “recovering-Java-developer-turned-DevOps-junkie” focused on helping our customers and community succeed with Cloud Foundry, it became very clear to me that I needed to add Go to my knowledge portfolio. This talk will introduce Go and its distinctives to Java developers looking to add Go to their toolkits. We’ll cover Go vs. Java in terms of: * type systems * modularity * programming idioms * object-oriented constructs * concurrency

TRANSCRIPT

Page 1: A Recovering Java Developer Learns to Go

A Recovering Java Developer Learns to Go

Matt Stine (@mstine) Cloud Foundry Platform Engineer at Pivotal

[email protected] http://www.mattstine.com

OFFICE HOURS Wednesday, 2:30 - 3:10 PM

Expo Hall (Table A)

Page 2: A Recovering Java Developer Learns to Go

I am not a Go expert.

Page 3: A Recovering Java Developer Learns to Go

I’m just learning to Go.

Page 4: A Recovering Java Developer Learns to Go

CF Architecture - January 2013

DEA Pool

Router

Cloud Controller

BOSH Director BOSH Agent

UAA/Login Servers Health Manager

Service Broker Node(s)

Messaging (NATS)

CLI Client

Ruby

Java/Spring

Go

Page 5: A Recovering Java Developer Learns to Go

CF Architecture - January 2014

Ruby

Java/Spring

Go

Loggregator

DEA Pool (Diego - Coming soon!)

Router

Cloud Controller

BOSH Director BOSH Agent

UAA/Login Servers Health Manager

Service Broker Node(s)

Messaging (NATS)

!

CLI Client

Page 6: A Recovering Java Developer Learns to Go

–Matt Stine

“Hey, wait! I just got done learning Ruby!”

Page 7: A Recovering Java Developer Learns to Go

• Mike Gehard: “Go Within Cloud Foundry”https://www.youtube.com/watch?v=d5aHr8VGU-8

• Onsi Fakhouri: “Diego: Re-envisioning the Elastic Runtime”https://www.youtube.com/watch?v=1OkmVTFhfLY

Go in Cloud Foundry

Page 8: A Recovering Java Developer Learns to Go

✓Hello World ✓Why Go? ✓Contrasts with Java:

- Features and Idioms - Packaging / Modularity - Types / OOP / Interfaces - Concurrency

Agenda

Page 9: A Recovering Java Developer Learns to Go

package main !import ( "fmt" ) !func main() { fmt.Println("Hello World") }

Hello WorldAll code goes in a package.

Give access to exported

stuff from other packages.

Function definition, main() is entrypoint.

Call an exported function!

Page 10: A Recovering Java Developer Learns to Go

Why Go?

Page 11: A Recovering Java Developer Learns to Go

Iron Triangle of Language Design

Effic

ient

Com

pilat

ion

Ease of Programming

Efficient ExecutionSystems Programming

Page 12: A Recovering Java Developer Learns to Go

• 2007-09-21: Go invented at Google by Robert Griesemer, Rob Pike, and Ken Thompson

• 2009-11-10: Go released as OSS

• 2012-03-28: Go 1.0 is Released

A History Lesson

Page 13: A Recovering Java Developer Learns to Go

Software Engineering in the LARGE

http://talks.golang.org/2012/splash.article

“Go is a programming language designed by Google to help solve Google's problems, and Google has big problems.”

Page 14: A Recovering Java Developer Learns to Go

Software Engineering in the LARGE

http://talks.golang.org/2012/splash.article

“Go is a programming language designed by Google to help solve Google's problems, and Google has big problems.”

Page 15: A Recovering Java Developer Learns to Go

✓ Safety and efficiency of astatically-typed, compiled language

✓ Productivity and feel of a dynamic,interpreted language

✓ Address modern compute environments:

- Multicore Processors

- Networked Systems

- Massive Computational Clusters

- Web Programming Model

Goals

Page 16: A Recovering Java Developer Learns to Go

https://www.flickr.com/photos/slackpics/4289782818

Page 17: A Recovering Java Developer Learns to Go

A Kit for

Systems Software

https://www.flickr.com/photos/pmiaki/6657150957

Page 18: A Recovering Java Developer Learns to Go

Differences from Java

https://www.flickr.com/photos/yukop/6778321940

Page 19: A Recovering Java Developer Learns to Go

• Features and Idioms

• Packaging / Modularity

• Types / OOP / Interfaces

• Concurrency

Contrasts with Java

Page 20: A Recovering Java Developer Learns to Go

Features and

Idioms

https://www.flickr.com/photos/yukop/6778321940

Page 21: A Recovering Java Developer Learns to Go

Multiple Return Valuesfunc vals() (int, int) { return 3, 7 } !func main() { a, b := vals() fmt.Println(a) fmt.Println(b) ! _, c := vals() fmt.Println(c) } GBE

Return a pair of values.

I

Ignore the first value returned.

Assign to multiple variables.

Page 22: A Recovering Java Developer Learns to Go

Closures

func intSeq() func() int { i := 0 return func() int { i += 1 return i } }

GBE

Closes over this state.

Page 23: A Recovering Java Developer Learns to Go

Closures

func main() { nextInt := intSeq() ! fmt.Println(nextInt()) fmt.Println(nextInt()) fmt.Println(nextInt()) ! newInts := intSeq() fmt.Println(newInts()) }

GBE

Captures its own value for i.

Increments own value of i.

Captures the value of i again!And increments it.

Page 24: A Recovering Java Developer Learns to Go

Where’s my java.util.List? Slicess := make([]string, 3) fmt.Println("emp:", s) !s[0] = "a" s[1] = "b" s[2] = "c" fmt.Println("set:", s) fmt.Println("get:", s[2]) !s = append(s, "d") s = append(s, "e", "f") fmt.Println("apd:", s)

GBE

Create an empty slice of strings (zero-valued).

Set value at index.

Get value at index.

Append function (not mutate in-place!).

Page 25: A Recovering Java Developer Learns to Go

Where’s my java.util.List? Slicesc := make([]string, len(s)) copy(c, s) fmt.Println("cpy:", c) !l := s[2:5] fmt.Println("sl1:", l) !l = s[:5] fmt.Println("sl2:", l) !t := []string{"g", "h", "i"} fmt.Println("dcl:", t)

GBE

Length function.Copy function.

Slicing function: index 2 (inclusive) to index 5 (exclusive).

Slicing function: index 0 (inclusive) to index 5 (exclusive).

Slice literals!

Page 26: A Recovering Java Developer Learns to Go

Where’s my java.util.Map? Mapsm := make(map[string]int) !m["k1"] = 7 m["k2"] = 13 !fmt.Println("map:", m) !v1 := m["k1"] fmt.Println("v1: ", v1) !fmt.Println("len:", len(m))

Create an empty map of string ! int.

Put values.

Get value.

Length function.

GBE

Page 27: A Recovering Java Developer Learns to Go

Where’s my java.util.Map? Mapsdelete(m, "k2") fmt.Println("map:", m) !_, prs := m["k2"] fmt.Println("prs:", prs) !n := map[string]int{"foo": 1, "bar": 2} fmt.Println("map:", n)

Delete function.

Optional second return indicating “presence.”

Map literals!GBE

Page 28: A Recovering Java Developer Learns to Go

Looping with Rangenums := []int{2, 3, 4} sum := 0 for _, num := range nums { sum += num } fmt.Println("sum:", sum) !for i, num := range nums { if num == 3 { fmt.Println("index:", i) } } !kvs := map[string]string{"a": "apple", "b": "banana"} for k, v := range kvs { fmt.Printf("%s -> %s\n", k, v) }

Discard first (index), sum second (value).

Keep both returns!

With maps, first = key, second = value.

GBE

Page 29: A Recovering Java Developer Learns to Go

We don’t need no stinkin’ exceptions…func f1(arg int) (int, error) { if arg == 42 { return -1, errors.New("can't work with 42") } return arg + 3, nil } !func main() { for _, i := range []int{7, 42} { if r, e := f1(i); e != nil { fmt.Println("f1 failed:", e) } else { fmt.Println("f1 worked:", r) } } }

Conventional: last return is error.

Makes an error with the provided message.

Return nil if there was no error.

Idiomatic inline error check.

GBE

Page 30: A Recovering Java Developer Learns to Go

(Semi)automatic Resource Managementfunc createFile(p string) *os.File { fmt.Println("creating") f, err := os.Create(p) if err != nil { panic(err) } return f }

func writeFile(f *os.File) { fmt.Println("writing") fmt.Fprintln(f, "data") !} !func closeFile(f *os.File) { fmt.Println("closing") f.Close() }

GBE

Page 31: A Recovering Java Developer Learns to Go

(Semi)automatic Resource Management

func main() { f := createFile("/tmp/defer.txt") defer closeFile(f) writeFile(f) }

Run after the function completes.

GBE

Page 32: A Recovering Java Developer Learns to Go

Packaging/Modularity

https://www.flickr.com/photos/yukop/6778321940

Page 33: A Recovering Java Developer Learns to Go

TL;DR

COMPLEX

SIMPLE

Page 34: A Recovering Java Developer Learns to Go

• Every class in a package

• Import classes explicitly

- import java.util.Map

• Import all classes in a package

- import java.util.*

• Statically import class static members:

- import static java.lang.Math.PI

- import static java.lang.Math.*

Java Packaging

Page 35: A Recovering Java Developer Learns to Go

• All types and functions belong to a package.

• Every source file must declare its package.

• Import packages to gain access to exported members.

Go Packaging

Page 36: A Recovering Java Developer Learns to Go

• public - any class in same package, or any importing class in a different package, can see

• default (“package private”) - any class in same package can see

• protected - any class in same package, or any subclass in a different package, can see

• private - no class other than this can see

• Scope indicated by prefixing name at declaration time.

Java Scoping

Page 37: A Recovering Java Developer Learns to Go

• exported - any code in an importing file can see

- exported names start with uppercase letter

- func Copy(src *[]byte, dest *[]byte)

• non-exported - only code in the same package can see

- non-exported names start with _ or lowercase letter

- func copy(src *[]byte, dest *[]byte)

- func _Copy(src *[]byte, dest *[]byte)

Go Scoping

Page 38: A Recovering Java Developer Learns to Go

• Conventional correspondence to directory paths (e.g. com.ms.foo should be at src/com/ms/foo) - tools expect this!

• Package paths do not have to be unique at compile or runtime (first dependency found/loaded wins!)

• Conventional correspondence to URL of author (e.g. my domain is www.mattstine.com, so my packages names start with com.mattstine) - but no actual relationship to source code location!

Java Naming

Page 39: A Recovering Java Developer Learns to Go

• Conventional correspondence to directory paths (e.g. github.com/go-martini/martini should be at src/github.com/go-martini/martini) - tools expect this!

• Package paths MUST BE UNIQUE across a $GOPATH.

• Package names do not have to be unique.

• Referring to imported names must be qualified by package name (e.g. sql.DB not just DB)…can locally alias (e.g. import dbstuff “database/sql”)

• Conventional correspondence to URL of code location (e.g. import http://github.com/joefitzgerald/cfenv as import “github.com/joefitzgerald/cfenv").

• Can “go get” remote packages - supports Git, SVN, Mercurial, Bazaar.

Go Naming

Page 40: A Recovering Java Developer Learns to Go

• Java admits:

- circular package dependencies

- dead imports

• Go rejects:

- circular package dependencies

- dead imports

Miscellany

Page 41: A Recovering Java Developer Learns to Go

Types/OOP/Interfaces

https://www.flickr.com/photos/yukop/6778321940

Page 42: A Recovering Java Developer Learns to Go
Page 43: A Recovering Java Developer Learns to Go
Page 44: A Recovering Java Developer Learns to Go

For realz this time…

Page 45: A Recovering Java Developer Learns to Go

structs FTW

type Point struct { X, Y float64 }

Define a type. Give it a name.

This type is a struct. (you can actually define others!)

Add stuff! (upcase exports apply here too!)

Page 46: A Recovering Java Developer Learns to Go

Methods are Functions!

func (p Point) Translate(xDist float64, yDist float64) Point { return Point{p.X + xDist, p.Y + yDist} }

Receiver argument!

Can define methods on pointers or values.

Page 47: A Recovering Java Developer Learns to Go

composition FTWtype Point struct { X, Y float64 } !const ( BLUE = iota RED = iota GREEN = iota ) !type ColorPoint struct { Point Point Color int }

Define an enumerated constant (closest to Java enum).

A ColorPoint has-a Point!

Page 48: A Recovering Java Developer Learns to Go

• I have Points.

• I have ColorPoints.

• ColorPoints are like Points, but they are not Points.

• But I want to compute the euclidean distance between them.

• What to do?

Problem

Page 49: A Recovering Java Developer Learns to Go
Page 50: A Recovering Java Developer Learns to Go

Interfaces Group Behaviors

type Positioner interface { Coordinates() Point } !type Distancer interface { DistanceTo(p Positioner) float64 }

Page 51: A Recovering Java Developer Learns to Go

It’s all about satisfaction…

Java = explicit !Go = implicit

Page 52: A Recovering Java Developer Learns to Go

Calculating Distancefunc distanceBetween(a Positioner, b Positioner) float64 { p := a.Coordinates() q := b.Coordinates() sqOfXDist := math.Pow(p.X-q.X, 2) sqOfYDist := math.Pow(p.Y-q.Y, 2) return math.Sqrt(sqOfXDist + sqOfYDist) }

Page 53: A Recovering Java Developer Learns to Go

Point Satisfies Distancer and Positioner

func (p Point) Coordinates() Point { return p } !func (p Point) DistanceTo(pos Positioner) float64 { return distanceBetween(p, pos) }

Page 54: A Recovering Java Developer Learns to Go

ColorPoint Satisfies Distancer and Positioner

func (cp ColorPoint) Coordinates() Point { return cp.Point } !func (cp ColorPoint) DistanceTo(pos Positioner) float64 { return distanceBetween(cp, pos) }

Page 55: A Recovering Java Developer Learns to Go

Behavior Not Taxonomy

Page 56: A Recovering Java Developer Learns to Go

Animal Satisfies Distancer and Positionerfunc (a Animal) Coordinates() point.Point { return point.Point{X: a.X, Y: a.Y} } !func (a Animal) DistanceTo(pos point.Positioner) float64 { thing := pos.Coordinates() sqOfXDist := math.Pow(a.X-thing.X, 2) sqOfYDist := math.Pow(a.Y-thing.Y, 2) return math.Sqrt(sqOfXDist + sqOfYDist) }

Page 57: A Recovering Java Developer Learns to Go

Go!p = point.Point{X: 1, Y: 2} q := point.ColorPoint{Point: point.Point{X: 1, Y: 4}, Color: point.BLUE} !fmt.Printf("Dist b/w p and q = %v\n", p.DistanceTo(q)) fmt.Printf("Dist b/w q and p = %v\n", q.DistanceTo(p)) !penguin := animal.Animal{Name: "penguin", X: 1, Y: 1} seal := animal.Animal{Name: "seal", X: 1, Y: 4} !fmt.Printf("Dist b/w penguin and seal = %v\n", penguin.DistanceTo(seal)) fmt.Printf("Dist b/w penguin and point = %v\n", penguin.DistanceTo(p))

Page 58: A Recovering Java Developer Learns to Go

Concurrency

https://www.flickr.com/photos/yukop/6778321940

Page 59: A Recovering Java Developer Learns to Go

• Parallelism = leveraging simultaneous execution of work to perform many things at once. Limited to number of processors/cores you have.

• Concurrency = composition of work to manage many things at once. No theoretical limit.

• Rob Pike: “Concurrency is Not Parallelism”http://www.youtube.com/watch?v=cN_DpYBzKso

Concurrency vs Parallelism

Page 60: A Recovering Java Developer Learns to Go

• Java - Threads - OS managed - Share address space with other threads in same process

• Go - Goroutines - user-space managed by language runtime - multiplexed onto pool of OS threads

Parallelism - How?

Page 61: A Recovering Java Developer Learns to Go

• Java - Shared memory - Locking

• Go - Can share memory (see http://golang.org/pkg/sync) - But there is a better way!

Synchronization?

Page 62: A Recovering Java Developer Learns to Go

– http://golang.org/doc/effective_go.html

“Do not communicate by sharing memory; instead, share memory by communicating.”

Page 63: A Recovering Java Developer Learns to Go

Goroutinesfunc f(from string) { for i := 0; i < 3; i++ { fmt.Println(from, ":", i) } } !func main() { f("direct") ! go f("goroutine") ! go func(msg string) { fmt.Println(msg) }("going") } GBE

Synchronous

Asynchronous

Asynchronous and Anonymous

Page 64: A Recovering Java Developer Learns to Go

Channelsfunc main() { messages := make(chan string) ! go func() { messages <- "ping" }() ! msg := <-messages fmt.Println(msg) }

GBE

Create a new channel.

Sending

Receiving

Page 65: A Recovering Java Developer Learns to Go

Channel Bufferingfunc main() { messages := make(chan string, 2) ! messages <- "buffered" messages <- "channel" ! fmt.Println(<-messages) fmt.Println(<-messages) }

GBE

Make a channel that will buffer two values.

Send twice

Receive twice

Page 66: A Recovering Java Developer Learns to Go

Channel Synchronizationfunc worker(done chan bool) { fmt.Print("working...") time.Sleep(time.Second) fmt.Println("done") done <- true } !func main() { done := make(chan bool, 1) go worker(done) <-done } GBE

Notify receive that I’m done.

Run worker on a goroutine, pass “done” channel.

Block until msg received!

Page 67: A Recovering Java Developer Learns to Go

Selectc1 := make(chan string) c2 := make(chan string) !go func() { time.Sleep(time.Second * 1) c1 <- "one" }() go func() { time.Sleep(time.Second * 2) c2 <- "two" }()

GBE

Create two channels.

Create two goroutines; each sends message to different channel.

Page 68: A Recovering Java Developer Learns to Go

Selectfor i := 0; i < 2; i++ { select { case msg1 := <-c1: fmt.Println("received", msg1) case msg2 := <-c2: fmt.Println("received", msg2) } }

GBE

Await both messages simultaneously!

Print each as it arrives!

Page 69: A Recovering Java Developer Learns to Go

Closing Channelsjobs := make(chan int, 5) done := make(chan bool) !go func() { for { j, more := <-jobs if more { fmt.Println("received job", j) } else { fmt.Println("received all jobs") done <- true return } } }()

GBE

Job channel for sending work.Done channel to indicate all work complete.

Receive jobs - more will be false if jobs is closed.

If no more jobs, say that I’m done!

Page 70: A Recovering Java Developer Learns to Go

Closing Channelsfor j := 1; j <= 3; j++ { jobs <- j fmt.Println("sent job", j) } close(jobs) fmt.Println("sent all jobs") !<-done

GBE

Send the jobs to the worker.

Close the jobs channel.

Block until the worker is finished.

Page 71: A Recovering Java Developer Learns to Go

Range Over Channels

func main() { queue := make(chan string, 2) queue <- "one" queue <- "two" close(queue) ! for elem := range queue { fmt.Println(elem) } }

GBE

Pull messages off channel for each iteration of the loop.

Page 72: A Recovering Java Developer Learns to Go

• Features and Idioms

• Packaging / Modularity

• Types / OOP / Interfaces

• Concurrency

Contrasts with Java

Page 73: A Recovering Java Developer Learns to Go

Thank You!!!Matt Stine (@mstine)

Cloud Foundry Platform Engineer at Pivotal [email protected]

http://www.mattstine.com

OFFICE HOURS Wednesday, 2:30 - 3:10 PM

Expo Hall (Table A)

Page 74: A Recovering Java Developer Learns to Go

Code samples marked “GBE” at https://gobyexample.com are by Mark McGranaghan and are Creative Commons Attribution 3.0 Unported licensed (http://creativecommons.org/licenses/by/3.0). !

The Go Gopher logo was created by Renee French and is Creative Commons Attribution 3.0 Unported licensed (http://creativecommons.org/licenses/by/3.0). !

The Java Duke logo is BSD licensed (http://opensource.org/licenses/bsd-license.php).