Why Rubyists Should Consider Learning Go
Tags: go, ruby, discuss
Published: 2020-06-03 22:04:09

*This article was originally written by [Ayooluwa Isaiah][1] on the [Honeybadger Developer Blog][2].*  
Ruby and Rails are great tools that allow you to create complex web applications quickly. Well, *some kinds* of complex web applications. While they excel at traditional, monolithic, server-rendered applications, they fail to excel at delivering real-time or distributed services. 

This is why it's so handy for Rubyists to learn a language like Go. Go is designed for writing light-weight services that handle lots of inbound connections. Its strengths line up surprisingly well with Ruby's weaknesses. If you know both of them, you're basically unstoppable.   

This article is the first in a series about learning Go from a Rubyist's perspective. It will cover the same basic principles of the langue you'll find in any other tutorial. However, it will spend time on the areas of the language you might find strange coming from Ruby and will point out possibilities that might not be obvious. 

## What's Go?

Go is a compiled, statically typed programming language designed at Google by Robert Griesemer, Rob Pike, and Ken Thompson and was first announced in 2007, more than 10 years after the first release of Ruby.

The idea of developing a new programming language was born out of frustrations related to the use of other languages at Google. The goal was to create a language that solved modern programming challenges while eliminating all the irrelevant features that made it difficult to maintain code written in languages like C++.

Go is minimalist. Its syntax is tiny, with only 25 keywords. Its spec is relatively easy to read. That means you can get up and running quickly. Let's see what "hello world" looks like in go: 

```go
// Hello World! program in Go
package main;

import "fmt";

func main(){
    fmt.Println("Hello World!")
}
```



## Go offers type-safety AND a fast development cycle 

As a Ruby developer, you can write code and then run it immediately. Many of us have never known anything different, so we don't realize what a luxury a fast development cycle is. 

Languages like C++ must be compiled. This can take minutes or even hours on larger code bases. Can you imagine how frustrating it would be to wait that long to run the code you just wrote?

Of course, the reason it takes so long is that the C++ compiler does a lot of work up-front that Ruby doesn't. In C++, if you misspell a method name, the compiler will tell you. This is because C++ is 'type-safe.' In Ruby, you don't know you made a mistake until you run the code and get the common `NoMethodError`.

![NoMethodError exception](https://www.honeybadger.io/images/blog/posts/rubyist-learn-go/nomethoderror.png)

Go gives you the best of both worlds: a fast development cycle AND type-safety. 

Go offers the same fast development experience typical of dynamic languages due to its lightning-fast compile times while providing the type-safety that these languages lack. Go programs are also really fast; they're not quite on the level of Rust or C but are much faster than other languages, such as Ruby or Python.

Go is a multi-purpose language and can be used in many different areas of software development. It’s particularly well-suited for network applications and distributed cloud services due to its baked-in concurrency features, which allow applications to make effective use of the available resources of the hardware running it.

## Go is simple

Avoiding the incorporation of too many features was a specific design goal for Go from the moment it was conceived. Many other languages want to keep adding more features, the reasoning often being for the sake of expressiveness. The designers of Go reject this philosophy by choosing to only include features that cover a solution space and interact predictably with the other features of the language.

Ken Thompson, one of the original designers of the language, sums up this unusual stance quite nicely:

“When the three of us [Thompson, Rob Pike, and Robert Griesemer] got started, it was pure research. The three of us got together and decided that we hated C++. [laughter] ... [Returning to Go,] we started off with the idea that all three of us had to be talked into every feature in the language, so there was no extraneous garbage put into the language for any reason.”

Through the years, the Go team has stayed true to that philosophy. This has resulted in a language that is designed for clarity even at the cost of being verbose in certain situations (such as when handling errors).

```go
// Error handling in Go
result, err := object.DoSomething()
if err != nil {
    log.Printf("Something failed", err)
    return err
}
```

Go programs are typically very readable and easy to maintain because, aside from the business logic, you don't need to understand too many things to work on any codebase even an unfamiliar one, and you don't have the problem where every developer uses a different subset of the language, as is often the case in large software projects written in other languages.

## Go is opinionated

Go has strong opinions on how you should write and format your code. For this reason, all Go code looks just about the same. This quality helps reduce the cognitive load when acquainting oneself with an unfamiliar codebase and eliminates unnecessary bike shed arguments about trivial details, such as spacing or brace position.

Tools such as `gofmt`, and `golint` are built into the language and provide formatting and linting for all Go code in existence, and the rules they follow are not configurable in any way. For example, `gofmt` formats Go programs using tabs for indentation. Do you prefer spaces over tabs? Well, you can't change it. Not with `gofmt` at least.

Go does not allow you to import a package or declare a variable without using it. If you attempt this, the code will fail to compile. The idea behind this behavior is to trade short-term convenience for long-term compilation speed and program clarity.

Access modifier keywords are not present in the language. There are no `public`,  `private`,  or `protected` keywords. Go supports two access modifiers for variables, functions, and other types (i.e., exported and unexported), and they work at the package level.

If you want to make an unexported identifier (one not accessible outside a package), start it with a lowercase letter. As you can probably guess, exported identifiers start with a capital letter. This is immediately understood when reading code and makes the code more succinct.

```go
var Foo string; // exported
var bar int; // unexported
```

Go's testing package comes with an expectation that any test file must have a `_test.go` suffix. A file called `program.go` must have its corresponding test file to be `program_test.go`. This is so that Go can ignore test files when compiling the code because they are not needed for the program to run. When you want to test your code, the `go test` command is provided out of the box, which executes these files and runs tests.

## Go is polarizing

While Go has its fair share of advocates, criticizing the language has become fashionable these days. There's even a [GitHub repository](https://github.com/ksimka/go-is-not-good) dedicated to listing articles that complain about Go. Most of them focus on the features Go doesn't have or how some things are broken in the language.

Like every other language, Go has its fair share of baggage and shortcomings. As the language evolves, these things will likely improve over time. A major strength of Go is its underlying minimalist philosophy. However, it's not perfect, and certain aspects can be improved, including the lack of [generics](https://blog.golang.org/why-generics).

Go will never make everyone happy, but when used for the problem sets it was designed for, it is an absolute winner!

## Go is great for web development

Go has an amazing standard library that allows you to rapidly develop scalable and secure web applications without reaching out for a framework. It ships with a fully functional web server (`net/http`) and includes templating, routing, and most things for which you would need something like Rails. For many types of projects, sticking to the standard library is a perfectly reasonable approach.

For times when the standard library does not meet your expectations, several third-party packages exist that complement the standard library, such as the [Gorilla Toolkit](http://www.gorillatoolkit.org/). Also, if you do need an all-encompassing framework, you'll be pleased to learn that [several options](https://pkg.go.dev/search?q=web+framework) exist. You can look at [Buffalo](https://gobuffalo.io/en/) if you're looking for something with similar characteristics to Rails.

The deployment story for Go programs is also a breeze! You don't need to install anything on the server; just compile the project for your target operating system, and you'll get a single portable binary that can be uploaded and executed on your server.

For example, to build for a Windows environment from a Linux machine, you can use this command:

```bash
GOOS=windows GOARCH=386 go build -o hello.exe hello.go
```

The resulting `hello.exe` file will run on any Windows machine with an x86 CPU without requiring any further setup. This is great for containers too; just toss a binary in a lightweight Docker container, set some environmental variables, and run the application!

If problems arise after deployment and you need to roll back, you can easily revert back to the previous binary. Since the entire program is compiled to a single binary, you never need to worry about a dependency being upgraded inadvertently.

Go programs also typically use much fewer resources in terms of CPU and memory resources compared to Rails, which helps bring down server costs significantly. For example, [Iron](https://blog.iron.io/how-we-went-from-30-servers-to-2-go/) was able to reduce their memory usage from 50MB to a few hundred kilobytes on start-up when they switched from Rails to Go.

Due to its built-in concurrency features, Go is perfectly suited for large software projects that require thousands of requests to be handled simultaneously. Go uses goroutines to execute some code concurrently while you proceed with other tasks, and a lightweight communication mechanism called 'channels' helps you to avoid concurrent data modification.

## Getting started with Go

If you're sold on learning Go, you can [follow the instructions provided here](https://golang.org/dl/) to download and install it on your machine. To learn the basic syntax and features of the language, use [A Tour of Go](https://tour.golang.org/welcome/1). ['Go by example'](https://gobyexample.com/) is another good resource to investigate.

Want to build programs with what you’ve learned? Use [Gophercises](https://gophercises.com/). It features free tutorials that cover practical aspects of the language by building several projects, each one designed to teach you something different.

If you want to read a book, [The Go Programming Language](https://www.amazon.com/Programming-Language-Addison-Wesley-Professional-Computing/dp/0134190440) and [Go in action](https://www.amazon.com/Go-Action-William-Kennedy/dp/1617291781/ref=sr_1_1?keywords=Go+in+action&qid=1579167942&s=books&sr=1-1) are excellent reads.

## Wrap-up

The choice of whether to use Go or Ruby will vary depending on your project requirements. Both are great skills to have, and they can definitely coexist in your language toolbox.

Learning Go as a Ruby developer will open your eyes to other paradigms in software development. It will feel strange and foreign at times but will ultimately give you a different perspective and help you become a better developer.

I hope this article has helped pique your curiosity about Go and prompted you to think about how you can utilize it in your current and future software projects.

Thanks for reading!
[1]: https://www.honeybadger.io/blog/rubyist-learn-go/#authorDetails
[2]: https://www.honeybadger.io/blog/rubyist-learn-go/