There are many variables that go into choosing a language for a new project. When considering all these factors at DesignFast, we felt that developer productivity, network services, and type safety were most important. Ultimately, these values narrowed our choices for a language down to either Node.js or Go. In this article we’ll walk through weighing the pros and cons of both languages and explain why we eventually chose to use Go.
For several reasons, we strongly considered Node.js, a dynamically typed language. For one, most of our developers have previous experience in Node.js, and since our developers were already experienced in the language, developer productivity would have been immediately high. Additionally, Node is a great tool for rapid development and optimal for delivering new features and functions quickly regardless of developer experience level.
From a more technical specification perspective, Node’s event loop was ideal for our third-party API integrations due to its concurrent network call capabilities, and it also factored into our systems architecture plan because it is natively supported by AWS Lambda. This would allow us to utilize the serverless paradigm rather than writing a large monolithic application. Another merit was that Node’s out of the box ecosystem has great package management, and a large developer community exists to curate new frameworks and libraries are every day. That said, since Node is not a statically typed language, adding a superset such as TypeScript on top would definitely inhibit development, but increase type safety. The verbosity of Node and the amount of boilerplate that has to go into writing the application is also more error prone as there is more code to review and developers can write code how they see fit. The expansiveness of Node libraries and frameworks is great, though not all libraries and frameworks are well reviewed and can lead to potential bugs.
The other language we considered for DesignFast was Golang. A compiled language, Go was built by Rob Pike, Robert Griesemer, and Ken Thompson in 2009 at Google. It is a statically typed language, and it will compile and run the built binary almost as fast as Node interprets the bytecode. One of our initial concerns was how quickly developers would be able to pick up Go, but upon implementation, the small and concise syntax had developers producing some small API integrations in just a few days. The standard library is vast and well tested so most of our application has no external dependencies, other than the standard library and a few custom libraries.
For these reasons we came to the decision that Go was the right tool for us, but it has not come without its issues. One of the biggest problems we have had is dependency management, but with Go addressing this with Go Modules and Dep – a dependency management tool, we hope this issue is slowly resolved. Another downside is that the language inhibits some creativity as you are coupled to the core types and constructors in Go. This isn’t necessarily a negative in our opinion. It increases developer productivity and understanding of a codebase. It also keeps developers thinking about the business logic and topic at hand, rather than how a specific object is implemented. Additionally, Go’s error handling is verbose and repetitive as you the errors are return values, rather than throwing an exception as well as finding the causation of errors. Though this particular problem has been solved with Dave Cheney’s errors package, where you can continue to wrap errors and return them up the call stack to add context to the original error.
As we have adopted Go, more of our developers are starting to use Go for projects that they want to develop quickly and safely, like command line tools for internal project testing. Once Amazon Web Services announced native support for Go for AWS Lambda we were even more confident we had chosen the right language as it would allow us to write native Go code for Lambda without using a Node.js shim or adding extra complexity to our development lifecycle.
Go, just like any other language, is great for different cases. In the DesignFast case, we wanted fast concurrent network requests, easy developer adoption, type checking, and fast development. Go provided us with all of these features and more, and we couldn’t be happier with our choice.
We look forward to seeing the future of Go.