The art, philosophy, and science of Golang
Back in 2013 when I first learned about the Golang programming language, I faced a kind of "to be or not to be" problem. Though it was not as life-defining as that of Hamlet, it still seemed almost metaphysical to me.
When there are technologies bundled with virtually everything for any project, why do we need another one? As a Java backend developer, I was professionally curious about this and decided to give it a shot.
It's always useful to keep one or more secondary languages in stock to easily handle side tasks, soGo — astatically typed, compiled programming language — seemed to be a fantastic candidate. But everyone has different standards, and there is not a clear-cut answer as to whether it will suit your project or not.
So the big question is to Go or not to Go? I will share my insights on why you should give Golang a serious thought and will explain (without sugarcoating) why it's a challenging, but beautiful language.
The Golang fan base is growing
Let's start with the facts: the chart below indicates that Golang is currently stealing the show.
In 2019, Go is rapidly becoming developers' favorite technology, thereby making its presence felt among the established technologies, such as C++, Python, Javascript, etc. GitHub states that Go was one of the top five languages according to the number of pull requests.
There are a couple of reasons for such popularity. I’ll give some examples.
What I particularly like about Go is that it favors composition over inheritance. Making a complex and multi-tiered class inheritance structure is not a good idea, because it makes your code less flexible and hard to scale. As such, the Golang interface (set of methods) system eliminates subclasses and type-based inheritance.
Still, the cornerstone of Golang success isconcurrency. Its concept is wrapped up in Go proverbs, a set of the Golang philosophical concepts.
Interfaces in Go are very different from those in Java. No explicit declaration is required by the types. Any type that provides the methods named in an interface can be treated as an implementation.
Go uses goroutines and channels instead of threads, consuming just 2KB memory. As a result, there is an opportunity to spin millions of goroutines with a much more lightweight and scalable deployment in comparison to Java threads.
The communication between goroutines is provided by channels, meaning that only one goroutine has access to the data at a certain time. This approach enables us to create asynchronous parallel programs, executing tasks much quicker than if they were written in a sequential manner.
However, everything about Go isn't so sweet. As I went deeper into Golang, it turned out to be full of surprises.
Golang development: From mystery to mastery in 5 steps
When you are starting to get into another language, there are always periods of frustration.
One of the major complaints about Go is its approach to error handling, which some find fulsome. Unlike many programming languages, it doesn't have the standard exception logic.
Go does not allow developers to wrap up the code in a try catch block. By convention, a function returns an error as its last return value. Accordingly, it is up to an engineer to handle it properly at each step, as a result of the if err != nil statement.
if err != nil {
// handle the error
}
A lot of developers don't like this seemingly constant nil checking. That's why I often compare the Golang learning curve with the five stages of grief.
Each line of Go code was followed by a feeling of disappointment. I thought, "There simply must not be so many error checks!"
But if we remember that Golang was created for Google, it's possible to find some logic in such a decision. Imagine: hundreds of projects, thousands of Go developers, millions of code lines. To ensure consistency and simplicity, creators got rid of some "redundancies." For instance, there are no generics, and that leads to a decreased level of reuse in the code.
As you see, simplicity appears to be rather complicated. If there are so many other languages that have "normal" error handling, why should I put up with this?
As angry as I was with Go, I decided to make a move towards "happily ever after." Creators recommend the following:
In theory, it sounds great, but in practice, there is often no appropriate context that allows developers to handle errors correctly.
If there were generics, that could help solve the puzzle. It's possible to implement some sort of a generic mechanism by leveraging the empty interface (interface {}) feature. Nevertheless, it brings much pain and the authors themselves admit that:
In this state of uncertainty, lots of developers break up with Golang. Personally, I consider it to be a colossal mistake, as you shouldn't be looking for the answer in the language itself.
And the answer is…
Now, I've been writing in Go for 3 years. I can say that one tricky thing about it is that the acceptance stage won't come until you go for a really big project where the language can prove itself.
Go is the art of the possible. It's not about what's best or what's right. It's not about the language. It's about what you can do to make it work.
Once you have tried this, you will see that it's a controversial, but beautiful in practice.