Why Rubyists Should Consider Learning Go

These days fewer and fewer web developers get to specialize in a single language like Ruby. We use different tools for different jobs. In this article, Ayooluwa Isaiah argues that Go is the perfect complement to Ruby. The developer who knows both is in a great position to handle almost any back-end challenge.

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:

// 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

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).

// 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.

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 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.

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. Also, if you do need an all-encompassing framework, you'll be pleased to learn that several options exist. You can look at Buffalo 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:

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 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 to download and install it on your machine. To learn the basic syntax and features of the language, use A Tour of Go. 'Go by example' is another good resource to investigate.

Want to build programs with what you’ve learned? Use Gophercises. 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 and Go in action 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!

What to do next:
  1. Try Honeybadger for FREE
    Honeybadger helps you find and fix errors before your users can even report them. Get set up in minutes and check monitoring off your to-do list.
    Start free trial
    Easy 5-minute setup — No credit card required
  2. Get the Honeybadger newsletter
    Each month we share news, best practices, and stories from the DevOps & monitoring community—exclusively for developers like you.
    author photo

    Ayooluwa Isaiah

    Ayo is a developer with a keen interest in web tech, security and performance. He also enjoys sports, reading and photography.

    More articles by Ayooluwa Isaiah
    Stop wasting time manually checking logs for errors!

    Try the only application health monitoring tool that allows you to track application errors, uptime, and cron jobs in one simple platform.

    • Know when critical errors occur, and which customers are affected.
    • Respond instantly when your systems go down.
    • Improve the health of your systems over time.
    • Fix problems before your customers can report them!

    As developers ourselves, we hated wasting time tracking down errors—so we built the system we always wanted.

    Honeybadger tracks everything you need and nothing you don't, creating one simple solution to keep your application running and error free so you can do what you do best—release new code. Try it free and see for yourself.

    Start free trial
    Simple 5-minute setup — No credit card required

    Learn more

    "We've looked at a lot of error management systems. Honeybadger is head and shoulders above the rest and somehow gets better with every new release."
    — Michael Smith, Cofounder & CTO of YvesBlue

    Honeybadger is trusted by top companies like:

    “Everyone is in love with Honeybadger ... the UI is spot on.”
    Molly Struve, Sr. Site Reliability Engineer, Netflix
    Start free trial
    Are you using Sentry, Rollbar, Bugsnag, or Airbrake for your monitoring? Honeybadger includes error tracking with a whole suite of amazing monitoring tools — all for probably less than you're paying now. Discover why so many companies are switching to Honeybadger here.
    Start free trial
    Stop digging through chat logs to find the bug-fix someone mentioned last month. Honeybadger's built-in issue tracker keeps discussion central to each error, so that if it pops up again you'll be able to pick up right where you left off.
    Start free trial
    “Wow — Customers are blown away that I email them so quickly after an error.”
    Chris Patton, Founder of Punchpass.com
    Start free trial