Blog
November 13, 2019
TABLE OF CONTENTS
In late July 2019, I took the opportunity to attend the annual Go developer conference in San Diego, affectionately referred to as GopherCon. As a Go enthusiast and hobbyist developer, I was thoroughly interested in the recent proposals for the language as well as the ecosystem of companies leveraging Go in production.
Over the week, a diverse group of speakers and evangelists from companies, including Google, Uber, and GitHub, took the stage to talk about their experiences, best practices, and lessons learned from building services in Go. While listening to these talks and interacting with the broader Go community, I had a fundamental question I wanted to try to answer. Namely, as a consultant and a developer, can I be confident in recommending Go for enterprise applications?
Thinking about Go as an emerging technology, it is clear that it is beginning to be adopted outside of its traditional base of bleeding -edge tech companies and startups. Initially, Go was primarily used by a select few innovative companies to build platforms and developer tools such as Docker, Kubernetes, and Terraform . Notably, these tools are employed by a wide variety of mainstream enterprises, though most are unaware that they’re leveraging Go behind the scenes.
Looking at Go usage today, more and more companies are adopting it as a server -side language of choice to build out their technical solutions to modern business problems. This is evidenced by the surprising variety of companies represented at GopherCon this year. Not only were traditionally tech -centric companies such as Uber, Google, and Microsoft present and recruiting for Golang developers, but also non -traditional companies such as The Home Depot.
While Go is clearly on an upswing of adoption, there are still a significant number of companies and business leaders who don’t view it as a viable enterprise language. One of the main reasons behind this, which tends to affect any young technology, is simply a lack of information. Primarily, business leaders making decisions about technology stacks for new projects or refactors either aren’t aware of Go as an option or believe that the language ecosystem isn’t mature enough for their use case.
Furthermore, another common sentiment when proposing Go as part of a solution revolves around alternative technologies. Namely, why choose Go over an established enterprise language such as Java? Finally, the last common question that tends to arise is what companies are using Go in production?
Even though Go has benefitted from 10 years of iteration as an open-source tool, it also has the distinct advantage of being architected by a team with unprecedented experience in shaping present-day computing standards. While initially in development at Google, the core team included Ken Thompson, Rob Pike, and Robert Griesemer who, between them, had helped create many foundational elements of modern computing, including the Unix operating system, the C programming language, and the UTF-8 encoding format.
This team was able to leverage the decades of experience between them to encode many of the best practices and proven standards from these technologies into the DNA of Go and its language specification. In practical terms, this means that Go was built from the ground up to take advantage of the lessons learned from decades of production deployments of C and other C -like programming languages, including Java and C#.
One of the areas that illustrate Go’s maturity as a language, in addition to the guiding hand of its creators, is its “batteries included” philosophy. Namely, the standard library in Go comes with just about everything needed by a developer to build a production-ready application right out of the box. Standardized, easy -to -use packages exist for HTTP requests, cryptography, and database connections, to name only a few.
From a maintainability standpoint, this is a highly desirable feature given that conflicting standards and choices when it comes to common programming tasks often result in unmaintainable software. In turn, code that is difficult to maintain often becomes a major source of technical debt that correlates to costly upkeep over time. Moreover, the standard library that defines Go’s core functionality has remained mostly stable since its initial release, thanks to the emphasis placed by the Go community on backwards compatibility.
One of the areas that illustrate Go’s maturity as a language, in addition to the guiding hand of its creators, is its “batteries included” philosophy.
On the topic of backwards compatibility, whenever a new programming language is initially released, there is always a period of significant growth and change. However, if backward compatibility is not a priority for language contributors and architects, then early adopters can quickly find themselves stuck with rapidly deprecated, unmaintainable software.
Anyone who invested heavily in Angular.js understands this pain given that Angular 2+ was released a couple of years later and is an entirely different framework, requiring a full rewrite of existing code to migrate. While Go is no exception to the trend of significant growth and change, it does have the benefit of being released with a compatibility guarantee put forward by its creators and embraced by its community.
What this means in practical terms is that for any proposed change to the language, backwards compatibility with previous versions is one of the main criteria by which the proposal is evaluated. Because Go is open -sourced, the above principle is policed by a diverse community of developers, advocates, and stakeholders with translates to a stable, well-architected programming language . From a maintainability standpoint, this arguably makes Go a safer bet than previous emerging technologies.
Concerning ecosystem maturity, several talks given at GopherCon by principal software engineers at premier technology companies gave insight into the way these companies are applying standardized design principles using Go. In a talk by Uber engineer Elena Morozova titled “How Uber Go’es,” Morozova covers some of the tactics used by her organization to manage their expansive codebase, all while boosting developer productivity and reducing time to delivery. Namely, she explained in detail the standardized use of dependencies as well as a uniform code structure implemented across all services.
Looking at dependency usage, when Uber initially began building services in Go in 2015, each service was built in relative isolation with different standards being applied for logging, web servers, and other common application dependencies. This resulted in a fractured codebase with a myriad of different “standards” for common programming tasks that dramatically lowered developer productivity and time-to-delivery of new services.
After identifying this problem, Uber moved quickly and developed a dependency injection framework that allowed developers to pick and choose reusable, composable, and standardized modules with which to build out their applications. The Uber team also began enforcing consistent code structure for all Go services based off of well-known design patterns. With these changes in place, Morozova notes that “Uber greatly increased the consistency of the developer experience for creating Go services,” which consequently has “allowed Uber to scale to over a thousand Go services containing over 20 million lines of Go code”.
To understand why Go is a good choice for enterprise development, it’s important to understand a little about its background. Initially designed at Google to address scalability, performance, and maintainability challenges faced by organizations operating at scale, the Go programming language was officially open-sourced in late 2009. By 2012, the first official V1 iteration of the language and core libraries was released. Fast-forwarding to today and a dozen minor releases later, millions of developers and a fleet of companies ranging from Netflix to The Home Depot have embraced it as a tool and a central part of their technology stack.
At its core, Go embraces the tenants of efficiency, simplicity, and concurrency as a first-class citizen. In terms of efficiency, Go is a compiled, statically typed language with garbage collection. This means that it reaps the type safety and performance benefits of other compiled languages such as C/C++ but without the difficulty and error -prone aspects of manual memory management.
With respect to simplicity, Go supports a clean syntax that is light on keywords. This ultimately translates to simpler, easier to read code that conveys the same meaning with less verbosity. An example of this can be seen in how Golang handles variable declaration and initialization:
// Declaring a variable with a zero value
var v int
// Declaring and initializing 1 or more variables
var w,x int = 2, 3
// Go can infer variable type upon initialization
var y = 4
// Short assignment statement (idiomatic Go)
z := 5
While there are multiple ways to declare variables in Go, the most common by far is the short assignment statement, as seen above . This is part of what is referred to as “Idiomatic Go,” or the set of best practices embraced by both the language specification and developer community for writing clear, effective Go code.
More than just variable declaration, Go includes a variety of optimizations and syntactic simplifications over previous generation programming languages that make it easier to parse at a glance . From a business perspective, what this means is that developers can spend less time trying to translate complex syntax and more time writing valuable code.
Finally, one of the most critical aspects of the Go programming language is its emphasis on concurrency. Specifically, concurrency refers to the ability of a program to handle and execute more than one task simultaneously. This paradigm is imperative to modern computing, as it is no longer unusual for web applications to have to scale to serve millions of requests in concise periods of time.
To address the need for this kind of scalability at Google, Go was built from the ground up with concurrency primitives such as Goroutines and channels that make it easy for developers to interact with threads in a light-weight manner as well as share data between related processes.
While the implementation details of Goroutines are relatively complex and outside the scope of this article, they are essentially an abstraction on top of operating system threads that handle many of the challenging aspects of multi-threaded programming while also drastically reducing the overhead of launching concurrent processes.
With these foundational elements, Go has a distinct advantage in terms of handling concurrency over other programming languages that either force users to interact with operating system threads directly, use third -party libraries to provide concurrency, or don’t support multi -threading at all.
The purpose of this section is to give a high -level overview of Go compared to another common programming language for enterprise development. However, it is important to note that there is no such thing as a “best” programming language, as each language has strengths and weaknesses that make it suited to solving different problems.
Choosing a programming language is fundamentally about understanding the problem being solved and the context around it. With that being said, let’s take a brief look at how Go compares to one of the most common enterprise languages today, Java.
Java has long been considered a first -class enterprise language and continues to be an excellent choice for a variety of reasons. Foremost, Java has a proven track record of success spanning decades of production use as well as a vast array of libraries that can be used to solve even the most obscure of problems. The Java ecosystem also includes popular frameworks like Spring that can be used to rapidly deliver secure, production -ready applications with less developer effort.
However, all of this power and overhead does come at a cost. Java, especially without the use of the Spring framework, is very verbose. This equates to developers having to write more lines of code to accomplish the same thing that can be achieved in significantly fewer lines of code by a newer programming language.
Choosing a programming language is fundamentally about understanding the problem being solved and the context around it.
Additionally, because so many libraries are available for Java and the language itself has gone through so many iterations, there are many different ways to solve the same problem. This can make codebases written in Java more difficult to understand by new developers and reduce code maintainability if more than one “standard” is implemented in a codebase. Finally, as of 2019, the use of Java 8 SE in production is no longer free for users as per the Oracle licensing agreement. This means that enterprise users will now have to pay to run their commercial applications or forgo new updates and bug fixes.
In terms of similarities between Java and Go, both are compiled languages with garbage collection. As a result, their performance profiles for common computing benchmarks are relatively similar, and neither imposes the burden of manual memory management on the developer.
Furthermore, both Java and Go are statically typed languages, which means both can benefit from compile -time error checking, which generally catches a broad swath of common programming errors. Finally, both Go and Java are cross-platform, although Java requires the Java Virtual Machine (JVM ) to interpret Java bytecode while Go compiles down to machine code like C/C ++.
Looking at some notable differences, Java fully embraces the paradigm of object -oriented programming (OOP ) while Go provides a hybrid approach. Namely, Go leaves out classic OOP constructs such as classes while still maintaining other elements such as interfaces. This results in Go having “cherry -picked” concepts from OOP that come together to provide a more flexible and direct paradigm that avoids some of the pitfalls of OOP, such as bloated base classes and excessive abstraction that reduces code readability.
public class User {
String name;
String email;
public User(String name, String email) {
this.name = name;
this.email = email;
}
public String getName() {
return name;
}
public String getEmail() {
return email;
}
}
type User struct {
Name string
Email string
}
func (u User) GetName() string {
return u.Name
}
func (u User) GetEmail() string {
return u.Email
}
Continuing on the topic of differences between Go and Java, the way Go and Java approach concurrency is subtly different. While both are multi-threaded programming languages, Go provides an abstraction called a Goroutine on top of operating system thread while Java does not. Particularly, when an operating system thread is created by a Java program, it is created with a fixed block of memory about a MB in size, depending on the operating system. In the case of a Go program, though, when a Goroutine is created, it is created with 2kbs of memory that can be increased as needed.
What this means in practical terms is that whereas a server may top out at several thousand operating systems threads created by a Java program, the same server can support millions of Goroutines without running out of memory. From a developer productivity perspective, Go provides a simple and more elegant way to write concurrent code as compared to Java.
This comes down to the fact that concurrency is a foundational part of Go’s architecture, while additional support for concurrency in Java was added after the fact and was not an initial design consideration. As a result of this, Go is a better choice for web servers where massive concurrency and performance is an utmost priority.
On the whole, deciding whether to use Go or a competing language ultimately comes down to the problem and the environment in which it’s being solved. If the team that’s building the solution is broadly proficient using Java or another language, then the developer productivity gains and increased velocity from choosing that language likely wins out over Go’s benefits. However, if the use case requires scalability or the organization is looking to modernize its technology stack, then Go can be considered a competitive option for server -side development.
As mentioned earlier, Go has been growing in popularity in recent years among companies of all sizes. This popularity was evident given the diverse group of companies represented at Gophercon this year, as well as their various use cases for the language. To name a few, Home Depot is currently using Go to power its e-commerce and retail platform that ultimately helps drive its hundred plus billion dollar business. Others like Crowdstrike are using it to build out next-generation cybersecurity solutions that process hundreds of billions of events a day and secure its client’s API endpoints.
Still, others like Robinhood are using it to revolutionize the way individual investors buy and sell stocks. Although all of these companies are using Go because its technical advantages match up with their business needs, they are also using it to attract engineering talent. This can be attributed to Go’s popularity with developers. According to Stack Overflow’s 2019 developer survey, Go ranks as one of the top three most desired languages to work with, as well as one of the top ten most loved programming languages. The same trend can be seen in the previous year’s surveys as well.
For a more complete list of production users of Go, an up -to -date list can be found here. At a glance, this list shows the language continues to have major backing in industries ranging from technology to finance to media and everything in -between. With companies like these continuing to build out large portions of their platforms using Go and developers continuing to enjoy working with the language, it is certain that it will remain relevant for application development for the foreseeable future.
By the end of the conference, in addition to my experience building with Go, I feel validated proposing Go as an integral part of an enterprise application. Go is heavily backed by influential companies like Google and offers exceptional benefits in terms of developer productivity, such as ease of building concurrent software, simplicity, and clear style guides. In addition, Go offers the performance and flexibility needed to solve modern business challenges.
Authored By
Nicholas McHenry
Engineering Consultant
Meet our Experts
Engineering Consultant
Nicholas is an Engineering Consultant with expertise in application development and a passion for cloud computing. He holds certifications in both AWS and Azure cloud solution architecture, and has worked with a variety of Fortune 500 clients to deliver both technical and business value. Nicholas has experience in Node.js, front-end Javascript, Java, and Go as well as building cloud-native applications at enterprise scale.
Let's chat.
You're doing big things, and big things come with big challenges. We're here to help.