Building Cord with Go

At Cord Project, we believe in the power of voice. We believe in simplicity. This mantra has also guided our engineering practices. We focus on shipping product and avoiding technical debt. We automate as much as possible to focus on the fun stuff.

Jeff Baxter and Thomas Gayno founded Cord Project in May 2014 with the goal of building the next generation messaging app. They built an iOS prototype with a Parse backend and launched it in September 2014. I joined in August 2014 to build our own server application and migrate the Parse data. We aimed to launch an updated iOS app and a new Android app using our own infrastructure before Christmas 2014. I’m glad to say we achieved our goals. Here’s how we did it.

I spent about 3 weeks in August and September thinking about languages and architectures. I debated between Python, Postgres, and nginx on raw VMs on Amazon Web Services versus Go on Google Cloud Platform. My prior company used a Perl/Python/Postgres stack on AWS, so I was tempted to “go with what you know.” I decided to try something new, and to be honest, I mostly chose against my previous experience. I had no desire to manage VMs, databases, load balancers, security, and logging infrastructure. I was sick of operations. I needed and wanted to spend 100% of my time prior to launch on writing application code.

I had to build everything from scratch in about 3 months. This really meant that I had only half that time to develop in order to deliver to the client-side team. The major application features were:

Sign up, sign in, and authorization with phone number, Facebook, and Google

User account management

User social graph

Media (audio and image) storage

Message sending and receiving

Mobile push notifications

Social actions for messages and users

Data pipeline and warehouse to analyze user events

Web interface for messages

Administrative application

I needed to build and deploy quickly. Hence, I decided to write Go code using Google App Engine Classic and App Engine Managed VMs. I had read little about Go prior to building the app, and this was the first time I had written a non-trivial app in a compiled language. We have zero regrets.

I did not immediately realize how the compiler increases productivity and efficiency. As the only backend engineer, I would have pushed code that didn’t run if I didn’t have a compiler to check my work. It alerts me to typos and other trivial bugs. The Go compiler, as well as Go tools like Go vet and Gofmt, are like automated code-review tools, so I can quickly deploy correct code.

The official Go website has clear documentation of syntax, types, and functions, but also many articles, best practices, and guides. Code organization, package management, and versioning is easier in Go than Python. The Go team recommends that “import paths should be globally unique, so use the path of your source repository as its base.” Vendoring third-party packages is also a smart idea to give your application stability.

The Go philosophy also increases my efficiency. With a focus on data structures, well-tested algorithms, RFC specs, and composition, I can write clear code that responds to HTTPS requests with JSON. Server and client errors are handled easily too.

Good Go code does more with less, although not too little. For example, there is no ternary operator in Go. You need to write a 5-line if-else statement. Just write the damn code! Go style makes for readable, even glanceable, code. For example, in the Effective Go article, the author states, “code reads well if the successful flow of control runs down the page, eliminating error cases as they arise. Since error cases tend to end in return statements, the resulting code needs no else statements.” The programmer performs a series of steps (sometimes concurrently), and if one of those steps fails, then the function can return and the programmer needn’t worry about the rest. Thus, it is easy to visualize both success and error cases for API requests.

Moreover, I don’t need a complex class hierarchy or a web framework to make a JSON API. The net/http package has practically everything you need for a server. In general, a mobile backend receives incoming requests, sometimes with some data, authorizes them, does some computation and database calls, and responds with JSON. You can improve performance with concurrent RPCs and caching. At a high level, Go helps programmers write fast code with the following guidelines:

Do less work. Go makes it easy to delete code because you generally don’t have tightly-coupled complex code. :-) Do smarter work. The standard library has many sort, search, and other standard algorithms, and there is a strong open source community. Do the same amount of work but concurrently. Go offers goroutines, channels, and WaitGroups, as well as other basic synchronization primitives. Do less work and optionally do the rest. Go makes it easy to control variance with timeouts. Do less work now and do the rest later. Go on Google Cloud Platform makes it easy to defer work using Task Queues.

Not surprisingly, Go on Google Cloud Platform works very well. App Engine Classic and App Engine Managed VMs offers all the features the Cord Team needs:

OS, security updates, access control and private key management

Easy tools like deploy scripts, slow rollouts, rollbacks, A/B testing

Log aggregation and search

A console for request tracing, monitoring, and alerts

Autoscaling frontend and backend instances (which is very handy when you get featured in an app store and requests/second increase by 10x)

Autoscaling databases

Database exports to analytics engine (BigQuery)

I have used only one raw VM in my entire time working on Cord, and that was when I was migrating data from Parse to GCP. I can deploy new code in about 15 seconds and rollback just as quickly. I can search and monitor application requests in the web console. I can export my request logs to BigQuery and do SQL queries to find bottlenecks or patterns. I have no need to worry about instances because of App Engine’s autoscaler. I have no need to worry about database sharding, performance, and backups because of the strengths of the Datastore. Finally, the team can do ad hoc queries with BigQuery and make data-driven product decisions. For end-to-end application development, Go on GCP has given the Cord Team the ability to do more with exponentially less.