I worked with Ruby for years on frontend and backend projects. At the time, I had many backend services in Ruby and although everything ran fine, I was interested in reducing server costs. If feasible, I could dramatically reduce the IT budget. This is extremely important – Less server costs equals more money to spend on new engineers!
I needed something new. The following pointed me towards Go:
- Iron.io switched from Ruby to Go. I wanted to experiment with Go and see the same reduction in resources Iron.io observed.
- Another blog ran benchmarks on basic web-related tasks like json parsing and http requests. Go performed pretty well. These articles convinced me to attempt Go in a production environment.
For the next step, evangelizing a new technology in any organization can be difficult. Even early-stage startups have preferences for programming languages and tools.
The quickest path for learning and adoption is to translate a service and demonstrate benefits. From a high-level, you’re swapping out a system with a well-defined input and output. You will prioritize learning the relevant libraries while preparing the system for production. Deploy your translated service to staging. If you can show improved performance, design simplicity, or any positive impact, you’ve built a solid case for switching to Go.
The drawback to this method is spending extra time to implement a service with the new language. You will have to find time on the side. There’s no real shortcut to this.
Here’s a simplified version of a case that worked for me. My service was fleet of individual processes written in Ruby that interacted with a JSON API. This was a system that received the Twitter firehose in real-time.
To begin, I had to learn how to parse JSON and make HTTP requests. I was able to map my Ruby code nearly one-to-one. Thankfully the libraries in Go were all included within the base package which were ‘encoding/json’ and ‘net/http.’
I also learned I could define structs for JSON parsing, allowing self-documenting code for JSON fields. This is extremely useful and a great time-saver when I’m stepping into someone’s code.
Because the service functioned as a standalone system, I was able to swap it out for the Go implementation. By taking advantage of Go’s concurrency, I compacted the system into one single process that was easily deployable. This reduced the memory and cpu footprint to 12% of the original. A clear win.
For complex projects, I would black box a section of the system and translate the code into Go. I might take an initial hit to my productivity due to the learning curve but this is a great way to learn quickly.
If you mess up, you can return to the old service.
And that is how you begin evolving a stack from legacy code. If you want to continue with Go, I highly recommend Docker’s source code as a template for style and organization of Go projects.
Leave a Reply