Should I stay or should I Go?

fricardi

FRicardi

Posted on October 3, 2023

Should I stay or should I Go?

One of the thing that has been helping me to keep pushing with my studies is to share them. This is something that makes me stay focused on doing things properly, without skipping steps. So, on this article I will be sharing my thoughts on how it was to learn Go Lang and how I've explored some tools.

What I want?

So, first of all, for you to understand what I was trying to accomplish here, let me introduce myself. On the start of my career, I've worked mostly with landing pages creation with pure HTML/CSS/JS, as well as some simple PHP systems. Later on, spent some time on a Node JS with microservices migration project, and a complex Java Spring based tool. Recently, working almost full time on frontend with React.
To make sure that I will not be retained only to learning the tools I'm currently working, I've started exploring some trending techs and documenting them here. On this article, you can find my thoughts on how it was to work with Svelte (spoiler: I loved it!).
GoLang is something that I've always wanted to check because of its pointer usage, as well as error handling techniques and performance. First of all, I want to know how to make a basic API. Later on, I will try to implement the Rinha de Backend challenge to dive deeper in some topics.

Getting started

To install Go to my system, I've used this great post and the official documentation. The entire setup did not took more than 5 minutes, which is a great starting point.

On the official site, Go has a tour that showcases the functionalities and syntax of the language, using some examples and exercises to make sure that you understood that.

Highlights

The first few concepts were nothing to write home about, mostly present on all languages, so the only thing to take away was how to write it in Go. A really nice thing on the functions is that you can return two (or more) values, which allows you to do a lot of fun things, which we'll talk about later. Other small thing is that switch/case has the break functionality by default on each case.

One remarkable concept is that they use the for loop encapsulates the functionalities of for, do while, while and for each. It is nice to have only one keyword for it, although I can see that as difficult to grasp for beginners. By the time I've ended my proof of concept, it was totally natural to use the for loop.

Being able to use scoped variables on the if clause, combined with functions returning two values makes it work almost as a try/catch block. It took a while for me to adapt to this mindset.

    if data, error := service.GetData(); error == nil {
        fmt.Println(data)
    } else {
        fmt.Println(error)
    }
Enter fullscreen mode Exit fullscreen mode

Now we are getting to my Achilles heel: pointers. It was an alien concept for me when I've learned C. Not because I've didn't understand it, but because I've never got to learn C on real world examples, so I haven't internalized it. On the docs, it seemed straight forward how go uses it, and the preferences to send a reference to an object and assign to it inside a method. For now, seems enough.

The first time I've looked to Arrays in Go I thought I was going to drop the goal of learning this language. Honestly, what the f* are slices? Why would I need an extra abstraction for it? Java all over again...

But fear no more, when the tour start showing how to use slices and how they behave, you understand that there's no need for panicking about it.

Other powerful feature, which I haven't got the chance to use on my POC, was the defer clause. It waits for the method to return before executing the code near to it. I can see it saving my life in some real world cases.

Rest API

On Go official documentation, they have a walkthrough on web services with gin.

It's nice to see that we can create a struct and add properties to it, such as changing their accessors when it is transformed to JSON for RestAPI returns. Since Go uses PascalCase for package accessors, that is specially helpful to maintain consistency.

Image description

Other than that, there's not much to say as someone who is already familiar with web services. You create a router, assign HTTP verbs with paths and a method to handle it, and raise the server. To return a value, you can use gin context to return an HTTP status and the data that you want to send to the consumer.

Image description

func GetAlbums(ctx *gin.Context) {
    if albums, error := albumService.GetAlbums(); error == nil {
        ctx.IndentedJSON(http.StatusOK, albums)
    } else {
        ctx.IndentedJSON(http.StatusNotFound, gin.H{"message": error})
    }
}
Enter fullscreen mode Exit fullscreen mode

Adding database

First example from the tutorial was with data stored on an array, the next step was to add database access to improve the POC.
The way I've chosen to do it was by creating a global variable on a connector file, and creating a Getter method to access that variable on other places

I've implemented a first version with the raw database connector, using queries, etc. It was not hard, but, as usual when not using an ORM, it was too verbose.

For a final version, I've used GORM, which abstracts a lot the database usage. In my opinion, the final code ended up being quite readable.

connector.go

var db *gorm.DB

func ConnectToDatabase() {
    var err error
    db, err = gorm.Open(sqlite.Open("database.sqlite"), &gorm.Config{})

    if err != nil {
        log.Fatal(err)
    }

    fmt.Println("Connected!")

    db.AutoMigrate(&types.Album{})

    fmt.Println("Migrated successfully!")
}

func GetDB() *gorm.DB {
    if db == nil {
        ConnectToDatabase()
    }

    return db
}

Enter fullscreen mode Exit fullscreen mode

albumService.go

func GetAlbums() ([]types.Album, error) {
    var albums []types.Album

    result := connector.GetDB().Find(&albums)

    if result.Error != nil {
        return nil, errors.New("Could not find albums")
    }

    return albums, nil
}

Enter fullscreen mode Exit fullscreen mode

Conclusion

Starting this session with a shout out to Go team: what an amazing documentation. Gotta show some love to the people maintaining it. It's totally doable to learn the language only from the official docs, from their tutorials, tours and technical doc itself.

The language has a lot of quirks of its own, which is really messy at first sight. I feel that, for most of these, seeing it in action was enough to understand why it is there and what was the thought process of doing it that way.

Error handling and pointers seems to be two of the many things that will make this technology shine and worth choosing on a real use case.

What I've tried to explore the most out of the official tutorials was to create separate files for each concern, such as controllers, services and database connectors. Go packages and their scopes were not hard, but I've stumbled a lot on the beginning, when I've tried to understand what I could and could not access.

Given this, I feel that my first goal was accomplished. And, if I see myself on a situation where I need to use Go, I won't be totally lost and know where to look for some answers. On top of that, Go community seem to be quite supportive and growing, which will help on edge cases.

See you on the next learning endeavors!

You can find the source code of my POC here.

πŸ’– πŸ’ͺ πŸ™… 🚩
fricardi
FRicardi

Posted on October 3, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related