Go for Scalable Microservices

An introductory workshop

Iman Tumorang

Senior Software Engineer, Xendit Inc.

Golang

Gophers building a cloud system by Renée French
2

Creators of Go

Robert Griesemer, Rob Pike, Ken Thdeompson (left to right)
3

Golang

Golang on Google Trend
4

Why Golang? Why many companies started to use Golang?

5

Problems addressed by Go at Google

6

Dependencies in Go

Moving gopher by Ashley McNamara
7

Unused dependencies

8

Single Object File Approach

TLDR

package A imports package B
package B imports package C
package A does *not* import package C
9

Dependencies in Go

comic by xkcd
10

Deployment in Go

comic by kavan
11

Go Syntax

var count int

type Star struct{ brightness int }
func FnThatReturnsMulti(num int) (result int, err error) { return 0, nil }
12

Naming

Exported vs Un-exported

func ThisIsExported() {}

func thisIsNotExported() {}
13

Concurrency

14

Composition over Inheritance

type ExampleInterface interface {
    Read(b []byte) (string, error)
    Write(dest string) error
}

type AnotherExampleInterface interface {
    Echo() string
}
type EmbeddedInterface interface {
    ExampleInterface
    AnotherExampleInterface
    ExtraMethod()
}
15

Errors

16

Tooling

17

How does Go help me?

by Marcus Olsson
18

Go is simple

19

Go is stable

Ian Lance Taylor at Gopherpalooza 2018
20

Go is scalable

21

22

Workshop

23

Hello World

package main

import "fmt"

func main() {
    fmt.Println("Hello, World!")
}
24

Types in Go

25

Basic Types

package main

import (
	"fmt"
	"reflect"
)

type basicTypes struct {
    b   bool
    i   int
    i64 int64
    ui  uint64
    f   float32
    s   string
}

func main() {
    t := basicTypes{true, 1, 1e12, 1234, 1.234, "I am a string"}
    printTypeStruct(t)
}

func printTypeStruct(t basicTypes) {
	printType(t.b)
	printType(t.i)
	printType(t.i64)
	printType(t.ui)
	printType(t.f)
	printType(t.s)
}

func getTypeString(t interface{}) reflect.Kind {
	return reflect.ValueOf(t).Kind()
}

func printType(v interface{}) {
	fmt.Printf("%v is of type %s\n", v, getTypeString(v))
}
26

Variable Declaration & Zero Values

package main

import "fmt"

func main() {
    var x int     // Variable x initialized with zero-value
    var y int = 2 // y with value 2
    z := 3        // implicit type declaration
    y, z = x, y   // double declaration

    var b bool
    var st string

    s := make([]int, 3) // slice declaration with capacity 3
    fmt.Println(x, b, st, s)

	y = z
}
27

OOP in Go

28

Struct and methods

type Person struct {
    Name string
}

func (p Person) SayName() {
    fmt.Println("My name is", p.Name)
}
package main

import "github.com/bxcodec/slides/devfest/code/workshop/oop"

func main() {

    d := oop.Person{
        Name: "Iman Tumorang",
    }
    d.SayName()

}
29

Interfaces

type Human interface {
    SayName()
}
type HumanLikeAlien struct {
    Eman string
}

func (a HumanLikeAlien) SayName() {
    fmt.Println(reverse(a.Eman) + " si eman yM")
}
30

Interfaces

package main

import (
	"fmt"

	"github.com/bxcodec/slides/devfest/code/workshop/oop"
)

func main() {
    pete := oop.Person{
        Name: "Peter"}
    askForName(pete)

    optimusPrime := oop.HumanLikeAlien{
        Eman: "Optimus Prime"}
    askForName(optimusPrime)
}

func askForName(h oop.Human) {
    fmt.Println("What's your name?")
    h.SayName()
}
31

Embedding

type Developer struct {
    UnderstandingOfTechnology float64
}

type CommunityBuilder struct{}

func (b *CommunityBuilder) BuildCommunity() {}

type DeveloperAdvocate struct {
    Developer        // DeveloperAdvocate.UnderstandingOfTechnology is valid
    CommunityBuilder // DeveloperAdvocate.BuildCommunity() is a valid call
}
32

Embedding

type JuniorDeveloper struct {
    Languages []string
}

func (d JuniorDeveloper) Code() {
    langs := ""
    for _, v := range d.Languages {
        langs += v + ", "
    }
    langs = langs[:len(langs)-2]
    fmt.Println("I code in " + langs)
}
type SoftwareMentor struct{}

func (m SoftwareMentor) Train(d *JuniorDeveloper, langs ...string) {
    for _, l := range langs {
        d.Languages = append(d.Languages, l)
    }
}
33

Embedding

type SeniorDeveloper struct {
    SoftwareMentor
}

func (d SeniorDeveloper) Code() {
    fmt.Println("I dont only code. I solve problems")
}
package main

import "github.com/bxcodec/slides/devfest/code/workshop/oop"

// EXAMPLE START OMIT

type Developer struct {
	UnderstandingOfTechnology float64
}

type CommunityBuilder struct{}

func (b *CommunityBuilder) BuildCommunity() {}

type DeveloperAdvocate struct {
	Developer        // DeveloperAdvocate.UnderstandingOfTechnology is valid
	CommunityBuilder // DeveloperAdvocate.BuildCommunity() is a valid call
}

// EXAMPLE END OMIT

func main() {
    j := &oop.JuniorDeveloper{
        Languages: []string{"go", "ruby", "js"}}
    s := &oop.SeniorDeveloper{}
    internalTraining(j, s, "java", "haskell")
}

func internalTraining(j *oop.JuniorDeveloper, s *oop.SeniorDeveloper, langs ...string) {
    s.Train(j, langs...)
    j.Code()
}
34

Composition Exercise

Use embedding to implement 3 structs type with one that can be a

type Founder interface {
    BizIdea() string
    TechIdea() string
}

the other 2 should hold separate business and tech concerns.
The Founder struct should be able to survive a VC pitch like below

func Pitch(f Founder) {
    fmt.Println("INVESTORS: What do you have to offer?")
    fmt.Printf("FOUNDER: I'm going to achieve %s\nwith %s\n", f.BizIdea(), f.TechIdea())
}
35

Composition Exercise - Sample Solution

type BusinessGuy struct {
    BusinessIdea string
}

func (g BusinessGuy) BizIdea() string {
    return g.BusinessIdea
}

type TechieGuy struct {
    SpecialTech string
}

func (g TechieGuy) TechIdea() string {
    return g.SpecialTech
}

type AspiredEntrepreneur struct {
    BusinessGuy
    TechieGuy
}
36

Composition Exercise - Sample Solution

package main

import "github.com/bxcodec/slides/devfest/code/workshop/composition"

func main() {
    elonMusk := composition.AspiredEntrepreneur{
        composition.BusinessGuy{"life on Mars"},
        composition.TechieGuy{"reusable rockets"},
    }
    composition.Pitch(elonMusk)
}
37

Concurrency in Go

38

Concurrency vs Parallelism

39

Concurrency vs Parallelism

40

Concurrency vs Parallelism

41

Concurrency vs Parallelism

42

Concurrency vs Parallelism

43

Concurrency vs Parallelism

44

Goroutines

45

Goroutines

package main

import (
	"fmt"
	"time"
)

func deplayedPrint(i int) {
    time.Sleep(time.Millisecond * 500)
    fmt.Println(i)
}

func main() {
    start := time.Now()
    for i := 1; i < 6; i++ {
        deplayedPrint(i)
    }
    fmt.Printf("Program took %s\n", time.Since(start))
}
46

channels

47

channels

    greenPipe := make(chan string)
    greenPipe <- "Mario" // Send a value to a channel
    mario := <-greenPipe // Receive a value from a channel
func deplayedPrint(i int, valChan chan<- int) {
    time.Sleep(time.Millisecond * 500)
    valChan <- i
}
package main

import (
	"fmt"
	"time"
)

func SendReceiveExample() {
	// EXAMPLE START OMIT

	greenPipe := make(chan string)
	greenPipe <- "Mario" // Send a value to a channel
	mario := <-greenPipe // Receive a value from a channel

	// EXAMPLE END OMIT
	fmt.Println(mario)
}

// DELAY START OMIT

func deplayedPrint(i int, valChan chan<- int) {
	time.Sleep(time.Millisecond * 500)
	valChan <- i
}

// DELAY END OMIT

func main() {
	start := time.Now()
    ch := make(chan int)
    for i := 1; i < 6; i++ {
        go deplayedPrint(i, ch)
    }
    for i := 0; i < 5; i++ {
        fmt.Println(<-ch)
    }
	fmt.Printf("Program took %s\n", time.Since(start))
}
48

select

func flipACoin(heads chan<- int, tails chan<- int) {
    if rand.Float32() < 0.5 {
        heads <- 1
    } else {
        tails <- 1
    }
}
package main

import (
	"fmt"
	"math/rand"
)

// FLIP START OMIT
func flipACoin(heads chan<- int, tails chan<- int) {
	if rand.Float32() < 0.5 {
		heads <- 1
	} else {
		tails <- 1
	}
}

// FLIP END OMIT

func main() {
	heads := make(chan int)
	tails := make(chan int)
    for i := 0; i < 10; i++ {
        go flipACoin(heads, tails)
    }
    for i := 0; i < 10; i++ {
        select {
        case <-heads:
            fmt.Println("Heads!")
        case <-tails:
            fmt.Println("Tails!")
        }
    }
}
49

Orchestration Exercise - Space Expedition

package main

import (
	"fmt"
	"math/rand"
	"time"
)

type Astronaut struct {
    Name string
    Ship chan string
}

func main() {
    theHermes := make(chan string)
    neiArmstrong := Astronaut{"NEIL ARMSTRONG", theHermes}
    sallyRide := Astronaut{"SALLY RIDE", theHermes}
    done := make(chan bool)
    go neiArmstrong.Explore(done)
    go sallyRide.Explore(done)
    theHermes <- "start"
    <-done
}

func (a *Astronaut) Explore(done chan bool) {
	for {
		msg := <-a.Ship
		if msg == "GEM" {
			fmt.Println("Mission success!")
			done <- true
			break
		} else {
			time.Sleep(1000 * time.Millisecond) // delay for ease of reading log
			fmt.Printf("%s: I'm exploring...\n", a.Name)
			time.Sleep(time.Duration(rand.Intn(5)*1000+1000) * time.Millisecond)
			if rand.Float32() < 0.3 {
				fmt.Printf("%s: I have found it!\n", a.Name)
				a.Ship <- "GEM"
				break
			} else {
				fmt.Printf("%s: I will take a break now\n", a.Name)
				a.Ship <- ""
			}
		}
	}
}

// SOLUTION END OMIT
50

Space Expedition - Sample Solution

func (a *Astronaut) Explore(done chan bool) {
    for {
        msg := <-a.Ship
        if msg == "GEM" {
            fmt.Println("Mission success!")
            done <- true
            break
        } else {
            time.Sleep(1000 * time.Millisecond) // delay for ease of reading log
            fmt.Printf("%s: I'm exploring...\n", a.Name)
            time.Sleep(time.Duration(rand.Intn(5)*1000+1000) * time.Millisecond)
            if rand.Float32() < 0.3 {
                fmt.Printf("%s: I have found it!\n", a.Name)
                a.Ship <- "GEM"
                break
            } else {
                fmt.Printf("%s: I will take a break now\n", a.Name)
                a.Ship <- ""
            }
        }
    }
}
51

Orchestration Exercise - Creatures Research

Steve works at Google Moonshot on natural creatures. He is trying to develop a
system which can output a report on number of eyes and legs given a list of
creatures. He proposes to use GoogleImage to look up for the creature's photos
then run those results through deep-learning eyes and legs detectors. The board
of directors like his idea and gave him three instances of ImageSearch, and one
for each EyeDetector and LegDetector. Help Steve by completing RunResearch
inside template pkg.

go get github.com/bxcodec/slides/devfest/code/workshop/creatures_research
cd $GOPATH/github.com/bxcodec/slides/devfest/code/workshop/creatures_research/
go run main.go
52

Creatures Research - Sample Solution

Find the sample solution here

by Renée French
53

Thank you

Iman Tumorang

Senior Software Engineer, Xendit Inc.

twitter.com/bxcodec

Use the left and right arrow keys or click the left and right edges of the page to navigate between slides.
(Press 'H' or navigate to hide this message.)