Early impression of Go from Node programmer

Percy Pham
Nextzy
Published in
5 min readApr 10, 2020

I heard that it’s good, so I spent time checking it to see if it’s really good. Result …

I was bored, so I’d been looking around for something to do. And then I see that there are few projects written in Go at my company, I wanna join them and I heard that it’s a good language too. Therefore, I decided to dive into the Go world.

Note that I also have Java programming experience, so I’m familiar with OOP concepts

Go Introduction

In 2006, Intel released the first dual core processor, and then in 2007, Google started creating Go programming language, Google wanted to take advantage of multiple cores. Go is the first viable language written to take advantage of multiple cores to run and distribute to environments on multiple machines with multiple cores.

Google enlisted Robert Griesemer, Ken Thompson and Rob Pike as co-authors of Go, these guys are like legends, they helped create the C programming language, Unix operating system, and UTF-8, those are huge. And they’re on the mission to create a language to do what Google does, which is massive at scale, super performance web stuff.

That’s enough to inspire me to jump into the Go world.

Start the journey

The learning experience is comfortable, Google did a good job at introducing the language using A Tour of Go.

The first impression was the syntax, I have to say that it’s quite minimalistic, it cuts off some of the familiar syntax like: while, throw and try/catch. However, I can easily achieve those things in different ways, for example:

In Node, we use the while loop with:

But in Go, we can do it with “for”:

It utilizes the “for”, that’s why I say it’s quite minimalistic.

Note: I’ll talk about throw and try/catch later.

Go introduces Goroutines and channels to handle multiple threads, this is the selling point of Go, Go can use multiple cores for handling these threads. All the complex stuff for dealing with multi cores is handled by Go, we just deal with the syntax of channels to write programs. As in the tour said: “A goroutine is a lightweight thread managed by the Go runtime”.

Besides, I have to admit that, the first time I read the introduction, I didn’t understand it on first try, but with a help of below video, it’s easier to grab the concept:

Try it for real

When I used Go to create a sample project, the other aspects of Go started to show up.

Nice documentation

One of the things I like about Google is that they document their works very well. I previously tried Flutter once, I was pleased to read the documentation, come to Go, it’s the same. They documented packages, best practices, etc. For example:

Tools

Node world is flexible, we have various styles and conventions. To force the style, we come to use Eslint and Prettier, those are great tools helping to keep our code in manner. However, we need to config it (a bit) manually, maybe to use Airbnb style guide.

Come to Go, it has all the tools that come with Go. For example, I use VSCode, the only thing I need to do is to install Go extention. It helps me to install all the needed tools. Note that Go tools already configured to use universal convention.

Pointers

Go separates the pointer and the value that it holds. In Node, we blurred the meaning of pointer, but still use it, it’s the difference between value type and reference type. However, in Go, we need to explicitly specify which one we want to use.

To explain it clearer, let’s make an example: we have a function named haveBirthday() that takes a person, and adds one more year to his/her age.

In Node, we will do it like this:

In Go, if we do it like that:

The reason why Go program printed out 20, not 21 is that: the “p” passed in the function is a copy of the “person”, not the “person” itself. To make it work, we have to pass in the pointer of person:

Notice that in haveBirthday() function now receive a pointer (*). And in the main() function, we need to get the pointer of “person” by adding “&” in front of it.

You might think this is cumbersome. Yes, you are right. It should not be this cumbersome, in fact, we should not write this code at all. That Go function should be like this:

And the Node code should be something like this:

The reason is that we should eliminate the code that manipulates the pass-in data. We should try to make as many pure functions as possible.

Go makes it like that helps me to reduce the code, I don’t have to make a clone function, since Go already did it for me.

I don’t say that all pointer functions are bad, we still need to use it if the passing object is large, keep copying its value is bad for performance.

Speaking of pointers and performance, here is an interesting article about them: Go: Are pointers a performance optimization?

Not throwing errors nor using try/catch

Go doesn’t have error throwing, instead, Go has a concept of panic/recover. However, I would say that I will try to avoid using panic/recover, since it’s quite cumbersome, and it’s better to return the error and deal with it (thanks to multiple returning values of Go).

In Node, there’s a package named await-to-js that I’ve been using for a long time. Basically, what it does is to help me avoid using try/catch statements nesting. This is an interesting article from the package author:

How to write async await without try-catch blocks in Javascript

Packages

This reminds me of Java, it’s been a long time I haven’t dealt with packages like this. Go has something that I noticed while developing. The packages can not have circle dependency.

Let’s say we have two packages: a and b.
If package b imports something from package a, then package a cannot import anything from package b.

I’m glad that it checks it for me, if I accidentally do the circle dependency, Go will be there to throw an error at my face immediately. Don’t wanna break it, the Dependency Inversion Principle in S.O.L.I.D

Deployment

I was surprised, yes, after I built the production docker image of my Go app, it’s surprisingly small. Normally, for a Node project, the docker image would be a few hundred Mb, but for my Go app, the final result is just more than 20 Mb.

The reason is, for Node app, docker image has to contain the Alpine OS layer, Node version on its own, the node_modules, and then the code itself. However, for Go app, the docker image only contains the Alpine OS layer and the built file.

Conclusion

Go language is very different to Node. However, I find it a pleasure learning Go, it’s quite a simple and small language, and I have a sense that it try to make developer create good code. There are features and aspects of Go that I have yet to discover, but I can say that I’m looking for it.

During the learning time, I tried to convert things from a small Node project to Go project. In the next coming article, I will list them out.

--

--