If you are new to coding, you may wonder if it's worth learning. Go's not the most in-demand language. It doesn't even break the top ten most used programming languages, according to Stack Overflow. If you ask Google about Go, you’ll get results like: “Go is a compiled statically typed general purpose language…”. It’s all too easy to get lost in the sea of terms when you're trying to understand one thing: what's the point?
Go ahead and exit out of those search tabs. Here’s all the information you’ll need to make an informed decision on whether to or not to learn Golang. We’ll cover its upsides and downsides and discuss how it’s used in every-day situations.
To Go or Not to Go?
Golang belongs to the C language family. Its creators worked with C and Unix in Bell Labs during the late 1970s and kept their programming preferences in mind while creating a new language. The inspirational leader, Rob Pike, was particularly interested in concurrency, so he started working on the Newsqueak language to implement his developments on the topic. Although the language didn’t become quite popular, the ideas behind it were not forgotten. In 2007, with his fellows now working at Google, Rob Pike embarked on the creation of Go based on his previous efforts with Newsqueak.
Go was a huge success. Large companies picked it up, and its popularity is still ever-growing. To give you a few examples, Google uses Golang for indexing search results; Alibaba uses Golang for its container engine “PouchContainer”, and Go powers Dropbox’s performance-critical backends.
Why do big brands like Golang? Mainly because it has seamless concurrency patterns. Also, many developers enjoy its syntax and patterns of work with memory. Let’s take a closer look at these stand-out features.
Go Simple Syntax
Golang’s syntax is much simpler than other high-level languages. Rob Pike prioritized ease of reading to assist when identifying mistakes. He thought it should be as simple as if you make a mistake, you can find and fix it quickly. That’s why there are few language primitives in Go. To name some that are present in other languages but missing from Golang:
- The ‘while’ and ‘until’ loops. They are easily replaced with ‘for’.
- Enums. There’s an idiomatic way to implement them with existing primitives.
- Conditional operator (x?y:z). It makes things look tangled.
- Double assignment (a=b=c). Missing for the same reason.
Additionally, semicolons are added automatically before compilation, so there’s no need to place them manually. Go formats the code for you in a standardized way, so you don’t have to argue with colleagues about which coding style is neater.
Go's approach to handling errors and inheritance align with the simple syntax paradigm. They are discussed further in the text, but to give you a quick background: the code is easy to read but verbose. True, clarity comes at a cost. But it has benefits: legacy code is easier to support, and you will understand the language and learn to write programs quickly.
Go Concurrency Tools
Golang was one of the first languages to focus on simple yet efficient concurrency – the ability to handle several tasks simultaneously by switching between them. Switching usually occurs when the procedure is waiting for the input.
Concurrent execution can dramatically increase efficiency. For example, it allowed Google to solve the C10K problem and maximize the number of active server connections.
There are two approaches to concurrency: “share by communication” and “communicate by sharing”. The "share by communication" approach processes send signals to each other. To implement this paradigm, Go introduced two primitives: goroutines standing for concurrent processes and channels for inter-routine message buffers. Under the hood, channels are based on arrays and behave like a pipeline. As a side note, if you ask Go's authors, "share by communication" should be the preferred approach.
On the other hand, in the “communicate by sharing” paradigm, processes modify the same variable. To ensure that several processes aren’t doing so simultaneously, you should lock the variable before reading from or writing into it and unlock it afterward. Forgotten memory protection may result in corrupt variables, leading to faulty program behavior. So, Go’s default approach is safer. But in fact, you can employ either paradigm: there are also mutexes in the language.
Communication through channels was introduced in 1985 and is not unique to Go, even though its implementation in the language is very elegant. But there’s a trait that makes Golang really stand out: routine switching occurs fast. Why? One of the steps in procedure scheduling is copying the stack to a memory buffer. Goroutines have tiny stacks which don’t take much time to copy. So, the throughput of the program increases.
Go Runtime is used to schedule goroutines. It incorporates optimizations compared to the system scheduler. For comparison's sake, Java uses OS native threads which are heavier and take more time to switch.
Go Garbage Collection
Each variable in your code is assigned a value. There are two ways to store it in memory – on the stack and in the heap. The stack is a dedicated place where the variables local to a function live until the end of the function’s execution. Afterwards, the stack is deleted.
To share a variable between two functions or to allocate memory for a big or dynamically sized object (the stack’s maximum size is fixed), you need a heap. But compared to the stack, the heap has a problem: its memory must be freed in a more complex way since it’s used by many functions simultaneously.
In the era of low-level languages, developers freed the heap manually by placing specific instructions in the code. But now garbage collectors have come to help. These are smart procedures that let the program know that specific memory bits are no longer used. GCs are based on different algorithms. The mark-and-sweep algorithm that's used in Go functions as follows: it walks through the object graph, marks the memory where reached objects are stored as reachable, and records all the unmarked memory as free. But it has to stop your program’s flow for a bit. Go’s GC is unique because such pauses are shorter than in other GCs.
There are also disadvantages to Go’s GC: it loads the CPU heavily and slows down the program. Additionally, it scales poorly. However, Go’s GC isn’t necessarily bad. In fact, there’s no best GC: different tasks require different algorithmic optimizations. For example, fewer pauses at the cost of more processors are optimal for the financial market or networked apps. But for batch processing, program throughput is more critical.
Golang Pros and Cons
Like any language, Go comes with a list of pros and cons. There are a handful of points where the community splits.
Go Error Handling
Many modern languages approach errors with exceptions. They behave like a grenade: you throw it upon error, and if someone catches it, then you’re safe. If no one does, your program will crash. In Go, there are no exceptions. Although there is a similar language construction called “panic”/“recover”, it’s recommended to use it only in certain cases. In the majority of cases, however, you must specify your error in a return value and have an error check on each level of the function stack until you process the error:
if err != nil {
return err
}
Chances are, you’ll see the code above thousands of times. And yes, error handling makes your Go code lengthy.
Another inconvenience: often, the error value is not the only return value. In case things go awry, you return zero for other values. But if you have five return values, and five places in your code may cause errors, then you’ll have to copy and paste the string “return nil, nil, nil, nil, err” five times!
Many developers discharge Golang for the error-handling boilerplate. But don't jump to conclusions! What now sounds ridiculous, some think is beneficial.
Unlike exceptions, errors are more trackable: errors are more visible in code, and it’s easier to notice that an error check is not in place. Also, you can modify an error and add context at each step, which will help to find the place that caused the error. Lastly, errors as values are easier to understand for a newcomer.
Silver lining: the community will probably fix the problem of lengthy error handling soon because it’s such a big turn-off. There are already proposals on how to do it.
Is Golang Object-Oriented?
Go is not an object-oriented language (OOP). Yet, you may find people who believe it is. Why? Even though Golang does not have classes, it has ‘structs’ with instances (objects). But to be object-oriented, it’s not enough to have objects. A language should also follow specific requirements. Let’s untangle this.
Inheritance is the most prominent OOP principle. Imagine you have squares and circles. You’d like to deal with them as figures (calculating areas in a loop), but it’s impossible because they have different types, and you can’t mix them. So, you tell the compiler that squares and circles are figures by creating a class called ‘Figure’ and inheriting them from it.
Golang does not have inheritance. Instead, it has composition. Parent and child objects are combined in one, and this solves the same problem. Similarly to inheritance, all the other three OOP principles have a corresponding one in Go. The ‘replacements’ are not equal to the original mechanisms, but different understandings of OOP allow for different opinions on the topic.
The Go Generics Dilemma
The word ‘generic’ in English refers to a non-specific characteristic relating to a larger class. The word ‘generic’ in Go means the same. Generics are types that can be used as a placeholder for any other type. Generics allow for the creation of functions handling many different types at once. For example, if you need to count objects, you don’t care if those objects are rubber ducks or bicycle wheels. You need them to be countable. A generic will represent ducks, wheels, and other countable objects.
Go introduced generics in May 2022 with the release of Go v. 1.18, but not everyone in the community uses them. Some developers claim generics hinder Golang’s inherent clarity. Conversely, developers who come from Java or C++ struggled without generics. Before v1.18, empty interfaces were used in place of generics but doing so was unsafe. Generics on the other hand have safety mechanisms.
As for code clarity, the verdict depends on the evaluation standards. Too many generics may result in ‘messy’ code. But with generics, you can have general-purpose data structures like trees with easy manipulations like sorting the data.
Where is Golang used?
Go is a general-purpose programming language. It’s not limited to a single problem domain. Remember, though, that Go is a cloud software language at its core.
Scripting and DevOps
The Google employees designed Go for the company’s needs, particularly managing the cloud infrastructure. Go is not a scripting language, but using the same language for multiple purposes was easier than switching between languages.
Despite not having all the benefits of a scripting language, Go has one crucial advantage for DevOps: you can compile a program quickly, deploy the binaries to machines, start the execution, and drink your beer.
In Go, everything needed is shipped in the binary. Conversely, in Python, you’ll need to install all the required dependencies on each server. Also, when compiling binaries, you don’t care much about the OS type: cross-compilation in Go is effortless.
Even though Go doesn’t support the REPL loop, the compilation process doesn’t take much time, so you won’t notice any differences with interpreted languages. On the downside, Go’s tools for string manipulations are far from optimal. But DevOps engineers still love the language, and business owners as well: there are many open job positions.
Backend Development
Business logic and APIs are by far the largest area of Golang usage. You need to process incoming requests quickly, so your clients don’t have to wait. These are excellent use cases for Golang’s concurrency benefits in the cloud.
Blockchain
Golang is prevalent in blockchain development. Blockchain apps are networked and distributed and benefit from concurrency support. Ethereum and other popular blockchain networks provide a Go framework, so you can quickly build a distributed app. In fact, Ethereum's most popular client is written in Go. Crypto coins based on Go are Avalanche, Fantom, Elrond, and Algorand.
eCommerce
Another prominent area is eCommerce. The main need here is to create and maintain APIs easily. Go supports REST APIs, GraphQL, GRPC, and protocol buffers, which makes it suitable for dealing with loads of API calls. Here are some eCommerce platforms written in Go: Flamingo commerce, QOR, GOyave, and Iris Web Framework.
Go is used in many other business areas, such as file hosting or booking, and others.
Other Uses
Other uses for Go include:
- Developing a desktop or mobile native apps
- Writing databases (Check out CockroachDB)
- Writing programs that interact with operating systems like Docker and Kubernetes
- Gaming (occasionally) but more complex games require calls to C libraries, and these are easier in C++
- Machine learning
Conclusion
If you’re looking for a new language to learn and want to try something different from the usual suspects, take some time and check out Golang. While Go isn't one of the most used languages, it is in the top five languages that developers are interested in learning. With its broad range of industry uses, emphasis on readability and simplicity, and seamless concurrency patterns, Go is a tool you should have in your tool belt.
Try out some beta Codewars kata below to start training on Go.