I’ve went through numerous programming languages personally and professionaly. In the last year I’ve picked up Go as my primary backend and REST API development language. In this post I document the reasons. Please note that these reasons are coming from my perspective of primarily developing in Python for the last 3 years. The following are somewhat ordered by importance.
Simple language specification
The Go language specification is one of the shortest I can remember (https://golang.org/ref/spec). As an experienced developer it took no more than a few hours to fly over the basics. The main benefits include faster onboarding of new developers and improved readibility. At work, I wrote a new microservice of moderate complexity and witnessed my colleagues grasp the core logic with ease. I believe that having a limit on the amount of language features will also reduce the headache of understanding code I write when I look back at it months and years down the road. Finally, the enforced simplicity of Go restricts those certain developers (we all know at least one), who have an obsession for utilizing ever language feature offered and thus generating unreadable code.
Having spent a few years recently developing in Python, I certainly respect having shortcut language features. However, and a similar argument to the simplicity of the language, I appreciate having a more verbose language and notice it takes less cognitive bandwidth to unravel the shortcuts offered in many languages to understand core logic. This is especially true when reading other people’s code or reading over a library to understand the core logic before using it. Having matured, I’m no longer as obsessed with having as little lines of code as possible through some cool shortcut. I need readible and maintainable code.
I’ve seen interpreted languages become popular over the years, especially considering compilation time used to be horrible. I’m not sure whether Moore’s law has contributed to the faster compilation time for Go or whether there’s something more to it. Either way, the primary benefit of a compiled language like Go is that I reduce the risk of type mismatches and runtime errors that I typically see when developing in Python. Sometimes I don’t catch a typo when doing a refactor, only to see a runtime error during testing or deployment (I’m sure at least one person will point out I should just rely on test cases for this). For me, the compiler provides the first sanity check, making sure the correct types are passed throughout the code and from my code to a library. In addition, the Go compiler fails to compile when there are unused imports or variables, something that helps me keep my code cleaner. Finally, in most cases, the compilation to machine code provides a preformance gain over interpreted languages.
“I recall some of the nastiest bugs that hurt us most when using Python were rooted from mutable objects being changed in unexpected places or some downstream systems disagreeing on Types.” –Alex Poon, COO and Founder of x.ai
Outside “panics”, like trying to dereference a
nil pointer, there are no exceptions. There is no need to wrap code in try/catch blocks. The convention is for functions to return multiple values with the first being the function output and the second the error; or in the case of a void type function, return only the error. The
error type returned can be
nil indicating the lack of an error. This language feature and convention make code more readible and easier to handle failures throughout.
Libraries are high quality
I’ve noticed most open sources libraries I’ve used are of a high quality. I’m not sure whether the language is new and filled with enthusiasts who dedicate substanial time or whether the above reasons contribute to this. In either way, the combination of language readibility, error handling, and static typing have made it easy and efficent to integrate third party libraries, as well as minimizing unexpected runtime behavior.
The Go concurrency model of Goroutines and channels have made concurrent programming easy to understand. Goroutines are similar to threads but not the same. Channels are like queues that can be used to exchange messages between Goroutines, including messages instructing the Goroutine to terminate. Additionally, as a developer who spends considerable time on REST APIs, Go’s builtin in HTTP server places every incoming request onto it’s on Goroutine for independent non-blocking/async execution.
A quick tutorial on Go concurrency can be found here: https://www.golang-book.com/books/intro/10
Dep package manager
The dep package manager is similar to Maven and PIP in that it allows pulling in third party libraries and locking in version numbers. Libraries are pulled in as source into the projects
vendor folder, which is a part of the default compilation search space. At the end of the day, the compiler will static compile the application and it’s third party source libraries to generate a single executable for deployment.