Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Taming Dependencies

Taming Dependencies

Managing Problematic Dependencies in Go: A Path to Sanity

Greg Poirier

June 14, 2016
Tweet

More Decks by Greg Poirier

Other Decks in Programming

Transcript

  1. 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.
  2. 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.
  3. 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).
  4. 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.
  5. 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.
  6. 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.
  7. 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.
  8. 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))
 }
  9. –Chris Knight in Real Genius I was thinking of the

    immortal words of Socrates, who said, “… I drank what?”
  10. Let’s fix it. • Must haves: • No more gRPC

    or shared dependency version conflicts causing problems. • A sensible build system.
  11. Let’s fix it. • Nice to haves: • `go get`

    still works • `go build` still builds projects • Easily update dependencies across all projects.*
  12. 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
  13. 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.
  14. Disadvantages • Yet another shared dependency. • Have to write

    generators. • Still haven’t really solved our problem, just delayed having to really address it.
  15. 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.
  16. 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.
  17. 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).
  18. 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.
  19. 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.