Ruby ain't Go, and vice versa

Just because you can do something is enough reason to do it Posted by Art Mills

Apr 9, 2023

When last I nerded

Many years ago, when I last spent the bulk of my free time doing silly tech things mostly for myself, I did it with Ruby, and specifically Ruby on Rails. If you know anything about coding you'll appreciate that Ruby is pretty easy on the eyes. And because I'm inspired by a famous quote:

A silly thing done once should be done at least twice

I have decided to basically re-write my many years retired Ruby on Rails personal tech site in Go. For those who know me, yes, it also explains at least one of and likely both ex-wives.

Anyway, Ruby is beautiful



  def create
    @slogan = Slogan.new(slogan_params)

    respond_to do |format|
      if @slogan.save
        format.html { redirect_to @slogan, notice: 'Slogan was successfully created.' }
        format.json { render action: 'show', status: :created, location: @slogan }
      else
        format.html { render action: 'new' }
        format.json { render json: @slogan.errors, status: :unprocessable_entity }
      end
    end
  end

Obviously there's Rails magic here, but on that site I had a Slogan model. I used it to fill silly things in the subhead on every page and randomize it so you never knew what you'd get. Even my mom, should she ever visit here, and she will never visit, could see the code above and kind of get it.

I picked up Golang starting at Pluralsight and other study. I came across a great Udemy course which I got on sale, obviously, from a guy who clearly had a Ruby background. He spoke my tech stack, being from Ruby, using Bootstrap 5 and, you know, basically avoiding testing.

But the same SloganCreate code in Ruby goes like this in Go:



func SloganCreate(user *User, slogan string) *Slogan {
	entry := Slogan{Slogan: slogan, UserID: user.ID}
	database.Database.Create(&entry)
	return &entry
}

When I say it goes like this in Go, I mean if you are from Ruby at all, and took a course instructed by a teacher who loves Ruby. The code above is not as sexy or refined as Ruby. But you can almost follow it. And though it is right...

It is also way wrong.

Why? I'm not going to say Golang treats errors like they are more important than most languages, but, only because the correct code does it for me.



func SloganCreate(user *User, slogan string) (*Slogan, error) {
	entry := Slogan{Slogan: slogan, UserID: user.ID}
	result := database.Database.Create(&entry)
	if result.Error != nil {
		log.Printf("Error creating slogan: %v", result.Error)
		return nil, result.Error
	}

	log.Printf("Slogan created: ID: %d, Slogan: %s, UserID: %d\n", entry.ID, entry.Slogan, entry.UserID)
	return &entry, nil
}

Go wants you dealing with errors everywhere, all the time, in everything. Did I say all the time? Because it really wants you to do this ALL THE TIME . Obviously this is even less easily discernable for my mom, but it does immediately uplift an error to a value that must be handled throughout the process.

Here by having the *( Slogan, error) return values, it's forcing you to deal with the fact that this will return either a Slogan or an error and you not only need to write code here to handle it immediately, but you have to write code in your tests and helper functions and other areas that call it as well.

You pass error "objects" around.

I kind of like it.

I think.

Check back later :).