GoLang at ZenMate

@nkhumphreys

29th June 2015

nkhumphreys.co.uk

GDG Berlin GoLang

nkhumphreys.co.uk

Who am I

  • API & Backend Lead @ ZenMate
  • Self confessed Go fanboy
  • Previously an embedded C and Python web developer

nkhumphreys.co.uk

What is ZenMate

  • VPN/Proxy provider based in Berlin
  • 12 million registered users
  • Over 200 servers in 10 locations
  • Supporting 8 platforms
  • Approx. 16 engineers

nkhumphreys.co.uk

What I will say

  • The world that was and why swap to Go
  • Tailor made user interfaces
  • Lessons learnt along the way
  • What's next?
  • End goal

nkhumphreys.co.uk

The World that was

  • Monolithic Ruby API
  • Un-scalable
  • Dependencies meant local development was hard
  • Deployment hell
kill unicorns
kill rabbits
kill god

nkhumphreys.co.uk

The World that was...

  • Responsible for 12 million registered users
  • Supported all clients with server/location information
  • Managed signups and premium purchases
  • Managed infrastructure and DNS
  • Made DevOps sad!

nkhumphreys.co.uk

The World that was...

Managing infrastructure looked like this

nkhumphreys.co.uk

The World that was...

When DevOps wanted it to look like this

nkhumphreys.co.uk

Why swap

We decided to build it, to make our DevOps lead look like this:

GOAL =>

nkhumphreys.co.uk

Why swap at all?

  • Manageable services
  • Easy to deploy
  • Easy to use <= very subjective!

nkhumphreys.co.uk

First steps

  • Infrastructure management
  • DevOps team want to stay in the terminal
  • They want to script repetitive tasks

Decisions

  • API to manage infrastructure
  • CLI to interact with API

nkhumphreys.co.uk

Obvious choice

nkhumphreys.co.uk

Obvious choice

  • Deploying binaries is easy (no dependencies to install)
  • Single binary to run locally (no dependencies to install)
  • Manages entire infrastructure including supplier API interaction e.g. DNS, using stdlib (no dependencies to install)

nkhumphreys.co.uk

Best day of my Career

One of my most productive days was throwing away 1,000 lines of code.

Ken Thompson

nkhumphreys.co.uk

Best day of my Career

Replacing 2,234 lines of Ruby with ~600 lines of GoLang

nkhumphreys.co.uk

Deployment

  • Deployed using Fabric
    • Very simple python script
  • Run using supervisor
    • No more killing god
supervisorctl restart <insert_service_name>
  • NGINX as a reverse proxy
    • Our stack is now super simple!

nkhumphreys.co.uk

Services for more than infrastructure

  • Not everyone wants a CLI
  • Marketing team would be pretty p*ssed if that was the interface to our news service

nkhumphreys.co.uk

Keeping everyone happy

Marketing also had to use this

nkhumphreys.co.uk

Keeping everyone happy

nkhumphreys.co.uk

Keeping everyone happy

Which made them look like this

nkhumphreys.co.uk

Easy-to-use is subjective

  • The CLI and the old interface were not what non-technical staff wanted
  • For them, neither were easy to use

 

 

  • A user interface is like a joke, but some jokes don't need explaining, they are just not funny!

nkhumphreys.co.uk

Tailor made UI

  • GoLang has all the tools we need to build tailor made user interfaces
  • Using the net/http library we built an API and CLI for devops
  • Using the net/http library and the html/template library we started to build a service that marketing could use

Gopher to the rescue, again!

nkhumphreys.co.uk

Tailor made UI

A little Bootstrap and JQuery, et voila

nkhumphreys.co.uk

Features that helped

Anonymous structures

// handleGetAdminHomePage renders the single page javascript application for
// the admin interface
func handleGetAdminHomePage(w http.ResponseWriter, req *http.Request, _ httprouter.Params) {
	log.Println("serving Admin")
	context := struct {
		News         []CompleteNewsItem
		AllPlatforms []string
	}{
		getCompleteNewsItems(),
		getSupportedPlatforms(),
	}
	templates.ExecuteTemplate(w, "list", context)
}

nkhumphreys.co.uk

Features that helped

Template language

<div class="container">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            {{ range $n := .News }}
            <div id="news-item-{{ $n.NewsItem.ID }}" class="row">
                <div class="row">
                    <div class="row">
                        <div class="col-md-6">
                            <h3>{{ $n.NewsItem.InternalReference  }}</h3>
                        </div>
                        <div class="col-md-2">
                            <button data-news-id="{{ $n.NewsItem.ID }}">
                                Edit
                            </button>
                        </div>

nkhumphreys.co.uk

Features that helped

Struct tags for JSON rendering and database column mapping

type NewsItem struct {
	ID                int       `json:"-" db:"id"`
	InternalReference string    `json:"-" db:"internal_reference"`
	Content           string    `json:"content"`
	Locale            string    `json:"-"`
	Premium           bool      `json:"-" db:"premium"`
	PublishAt         time.Time `json:"-" db:"publish_at"`
}

nkhumphreys.co.uk

We haven't left the stdlib

  • We have have made two different UI's
  • Tailor made with the user in mind
  • All achieved with the Go stdlib (not entirely true, shhhh)

nkhumphreys.co.uk

We now have two happy users

nkhumphreys.co.uk

Whats next...

  • Finish replacing our monolithic API with new GoLang services
  • Build unique interfaces that do one job, and do it well!
  • Our financial reporting interface will most likely look like this:
  • Move to continuous deployment
    • Deployment should be zero pain
SendMail(email_addr, auth, from, to, msg)

nkhumphreys.co.uk

Lessons Learned

  • The UI should be made with the user in mind
  • Easy-to-use is subjective
  • GoLang has all the necessary features and tools to make Easy-to-use UI's for everyone
    • But it will most likely be more than one UI
  • The Go tool suite has helped us write maintainable code
    • Thank god for GoLint (sorry about all the attempts to kill him!)

nkhumphreys.co.uk

End Goal

  • Every user who interacts with our services will have an interface that works the way they want it to
  • The tools will be there to make their lives easier, not harder, it will be easy-to-use
  • They will not fear using the tool
    • If a mistake can be easily made, that is our fault, not theirs

nkhumphreys.co.uk

@nkhumphreys

Questions?

nkhumphreys.co.uk

@nkhumphreys

Want some ZenMate goodies?

Made with Slides.com