Transitioning from Rails -> Go for a (relatively) Simple API part 1

(This is going to be a multi-part series of posts describing in detail the rationale, the research, and the actual implementation of a rewrite from a an API initially developed in Ruby on Rails to Golang

Part 1.0 or "so you have always done everything in Rails"

**Full disclosure: I have never had more fun in my career than after I learned Rails.**

I have always really enjoyed Ruby as a scripting language, since I was a fan of Perl at the beginning of my secondary education it just made sense, and who would have thought there is a huge web framework around it?? Wicked! Thus began a multi-year developer working on systems primarily architected in Rails + Ruby bits for workers. And it was awesome. Some parts were kind of slow, but debugging ruby apps really isn't too bad so it was fun. We solved some problems, created others, until the ugly truth in 2021 basically hit us square in the face:

**Finding Rails engineers is getting to be more and more difficult.**

We lost some talent (normal churn) and finding replacements seemed to be impossible with the biggest reason no one wants to work with Ruby/Rails anymore. We have a (rather large) population of Rails developers currently and thats fine, but its strange less and less people are picking it up. I understand that Rails isn't the "new hotness" that it once was, but it is still an incredibly featureful framework that make developing easy especially for PoC type work. Thus began the discussions to do a rewrite, since we don't want the application we're currently working on to go the way of COBOL and have only very specialized engineers know how to work it. This is my first full-rewrite so I'm sure there will be tons of fun things to learn (read: mess up and fix) along the way.

Part 1.1 or "ok you've twisted my arm, how do we get started with this?"

Probably the single biggest thing that became _abundantly_ apparent right away is that the Go community is famously minimal. So minimal as in ORM's are a highly debated topic. So minimal as in you should _probably_ just use the stdlib net/http package rather than any form of router (even though parsing out path params is a manual process if you go that route).

**To say it is a complete paradigm shift compared to Rails is an understatement.**

So the biggest question becomes "how much do I want to have to reinvent the wheel" vs "what does the framework provide".

After doing a bit of research, this is what I came up with:

  1. Use echo for our routing, parameter parsing, and middleware stack. We could probably use the stdlib or even gin/gonic but echo has some nice perks that set it apart.
  2. Use gorm for our persistence layer. Yes it's orm-ey, but basically all it does is figure out the SQL from the struct name + fields (kind of like ActiveRecord does, but not really). Debated going with go-pg but that one is a bit too much work for people that come from using an ORM exclusively for interacting with a database.
  3. Use go-migrate in order to provide db migrations, fairly simple db migration library that can be done in code OR via CLI which is handy. There is apparently a fork that works with gorm models as well - so I will have to look into that.

So far those are the 2 big building blocks that replace a bunch of what Rails provides. I was able to get a PoC together fairly quickly that conformed to our OpenAPI spec for a few endpoints, and it was pretty fun.

Whats next?

In my next post I'll go through the patterns I developed and in another post I will most likely document my development environment since it seems like a lot of gophers (Go programmers) either just use a text editor + dlv, but I also tried out the Jetbrains GoLand IDE as well as the VSCode plugin.

Thanks for reading!

Jacob Lindgren

Jacob Lindgren

Nebraska, USA