Slide 1

Slide 1 text

Taming Dependencies Managing Problematic Dependencies: A Path to Sanity Greg Poirier - CTO - @GetOpsee

Slide 2

Slide 2 text

Who am I? Why am I here? • CTO at @GetOpsee • Go in production for more than a year. • Building a whole damn product in Go. • I like to talk to people about my problems.

Slide 3

Slide 3 text

“In the trenches…”

Slide 4

Slide 4 text

Background: Opsee • Two primary components: API and Stream Processing • Stream processing components need to be independently deployable • API downtime cannot affect stream processing downtime. • Microservices to the rescue, and it had nothing to do with organizations.

Slide 5

Slide 5 text

In the beginning…

Slide 6

Slide 6 text

HTTP JSON RPC APIs • Easy to use and build • Easily parsed by humans when they want to debug • A lot of boilerplate code to write to get them going (this was prior to go-micro being particularly stable or useful).

Slide 7

Slide 7 text

Let ‘em bleed…

Slide 8

Slide 8 text

gRPC and Protobuf • “Performance”, but not really. • Code generation mechanisms that were language independent and that we didn’t have to write. • Declarative syntax for services and objects.

Slide 9

Slide 9 text

github.com/opsee/basic

Slide 10

Slide 10 text

No content

Slide 11

Slide 11 text

Shared Dependencies • Services needed a common grammar to communicate with one another. • It was easier to standardize around a shared library than vendoring most of the same code in many individual components.

Slide 12

Slide 12 text

What is the problem?

Slide 13

Slide 13 text

gRPC • Tightly coupled ourselves to the transport layer. • Dependency management is hard. • Proliferation of multiple versions of the transport. • gRPC changes its exported interface all the time.

Slide 14

Slide 14 text

It can’t be that bad… Can it?

Slide 15

Slide 15 text

gmunch • gmunch: a service to abstract away the fact that we’re using AWS Kinesis. • You send it an event, it tells you if it was able to queue it for processing. • Significantly simpler interface to Kinesis, and client authentication doesn’t require IAM privileges.

Slide 16

Slide 16 text

No content

Slide 17

Slide 17 text

Let’s write a new service… package myservicethatusesgmunch import (
 gmunch “github.com/opsee/gmunch/client”
 “google.golang.org/grpc/credentials”
 )
 func main() {
 // Ignore this obviously bad TLS init.
 client, err := gmunch.New(
 “gmunch”,
 credentials.NewTLS(nil))
 }

Slide 18

Slide 18 text

Oopsie… https://github.com/grpc/grpc-go/commit/ 59486d9c172d7b02e0166fce76fd720a88c24914

Slide 19

Slide 19 text

No content

Slide 20

Slide 20 text

No content

Slide 21

Slide 21 text

–Chris Knight in Real Genius I was thinking of the immortal words of Socrates, who said, “… I drank what?”

Slide 22

Slide 22 text

This happens more often than you think…

Slide 23

Slide 23 text

What do we do now?

Slide 24

Slide 24 text

No content

Slide 25

Slide 25 text

I am bad, and I should feel bad.

Slide 26

Slide 26 text

Let’s fix it. • Must haves: • No more gRPC or shared dependency version conflicts causing problems. • A sensible build system.

Slide 27

Slide 27 text

Let’s fix it. • Nice to haves: • `go get` still works • `go build` still builds projects • Easily update dependencies across all projects.*

Slide 28

Slide 28 text

Well that sounds EASY…

Slide 29

Slide 29 text

Solution 1: DIP

Slide 30

Slide 30 text

Dependency Inversion Principle • Abstract away the gRPC bits from service clients. • Go vendor experiment takes care of the rest. • Example: • https://gist.github.com/grepory/ 0ee8067d99797d8430502135639be097

Slide 31

Slide 31 text

No content

Slide 32

Slide 32 text

Advantages • Free of the tyranny of gRPC developers. • `go get` and `go build` keep working. • We feel like we’re being good software engineers. • Don’t have to do either of the next two solutions.

Slide 33

Slide 33 text

Disadvantages • Yet another shared dependency. • Have to write generators. • Still haven’t really solved our problem, just delayed having to really address it.

Slide 34

Slide 34 text

Solution 2: Monorepo

Slide 35

Slide 35 text

“Advantages of monolithic version control” http://danluu.com/monorepo/

Slide 36

Slide 36 text

Advantages • Atomic updates to dependencies. • `go build` works. • No longer have to use vendoring tools (which are all very annoying for different reasons). • Easier to audit accretion of external dependencies and versions.

Slide 37

Slide 37 text

Disadvantages • CI sucks and we have to build a builder. • Ironically, `go get` doesn’t work very well with monorepos. • We probably have to build tools to manage the dependencies themselves.

Slide 38

Slide 38 text

Solution 3: Monolithic build container

Slide 39

Slide 39 text

https://github.com/opsee/build-go

Slide 40

Slide 40 text

Advantages • We already build in containers and this is easy to do in CI and locally. • Per-project CI/CD doesn’t change. • No VCS difficulties (because let’s face it, submodules are a VCS difficulty nobody likes).

Slide 41

Slide 41 text

Disadvantages • Bye bye `go get` and `go build`. • Developers have to know what they can and cannot vendor in their project. • Managing dependencies requires all new tooling. • Still have to setup CI fanciness for updating the build container to run tests for every project.

Slide 42

Slide 42 text

Well? What do we do?

Slide 43

Slide 43 text

–Donald Rumsfeld “I'm not into this detail stuff. I'm more concepty.”

Slide 44

Slide 44 text

Not sure yet. • We have our known knowns and our known unknowns, but we’re not sure about our unknown unknowns. • We’re aware of the problem, and we’re actively working on its resolution. • It will likely involve some dependency inversion, because that’s probably just a good idea anyway.

Slide 45

Slide 45 text

Thanks! • Greg Poirier - @grepory on Twitter • Try Opsee! https://try.opsee.com