Golang - when?

Team leader, CTO or a software engineer - you’re at a decision point: “What language should I use for our next project?”

Although selection and benchmarking of different technologies is a common process in the initial phase of a project, when talking about development languages - many of us tend to choose the one they already familiar with. In this article I’ll specify a few distinct use cases in which Go might be an interesting option.

Go Language (GoLang)

Go is an open-source, high level development language and a set of tools, developed by Google and has been around since 2009. It is basically a strictly-typed, functional language but yet offers a few facilities to support classic OOP. As Go is a compiled language, rather than interpreted one, or running on a virtual machine (such as JVM) it’s running natively on the host platform, offering great performance. In this article I’ll enlight a few key features of this language and refer to some distinct use-cases where using Go might be a good idea.

Why? When!

Many articles deal with the question “Why Go?”. There is no concrete answer for this question, as there are many subjectives reasons why, and why not to use a specific language or technology. These reasons might be a simple matter of coding style, organisational skill-set or other logistic reasons. The main question should be asked is more like: “When might GoLang be a leading candidate, according to the constraints of my project?”. Putting aside all operational-aspects such as skill-set, style and popularity, these are some use-cases where I find GoLang a good candidate for my project, from pure-technical aspects.

“We need performance! (And simplicity…)”

Let’s admit - we don’t like to code things that are not pure business logic. We don’t like to deal with memory management, pointer-safety and manual garbage collection. Let us code pure business logic! This is where popular high-level languages like Java, Javascript and Python take place. But what if we need much better performance than these languages give us? A distinct example is cases when we use native-libraries running from high-level applications. These native libraries like shared-objects in Java-JNI, or web assemblies are usually coded in C/C++ and give much higher performance in pure calculation like image, audio and video processing. Coding C/C++ is hard and is the very opposite to what we like to do! So much memory management, a hell of preprocessor directives and complicated linkage. Well, GoLang is your pal! As Go is a compiled language, running natively on the underlying OS, you enjoy from its amazing performance and coding simplicity. Golang toolkit has a cool functionality to build a C compatible shared object or archive. You use it from the CLI this way:

go build -buildmode=c-archive

or

go build -buildmode=c-object

Using this binary you can create a Windows DLL or a JNI library. Check this out for more info.

“We want easy deployment”

This is not always a requirement but deploying a golang application is summarised by copying a single binary file to production environment. There are no Virtual-Machines involved such as JVM, and no runtimes or interpreters such as NodeJS or Python. No dependencies - nothing. Of course - there are a few cons in this section such as target platform compatibility (Go must be compiled to the specific platform on which it should run) but again - the question here is When rather than Why. The main issue that actually makes technical decision-makers prefer JVM is the platform-independence.Well, this is true, and Go solved this issue with a cross-platform compiling features as an integral part of Go toolkit.

“We just love functional programming!”

Hi! What about classic OOP? Why the hell did we spend years practicing OOP concepts for? Well, times change. In early ages the concept of event-oriented-programming was the realm of languages such as Visual Basic. This concept was then knocked-out by the pure Object Oriented languages led by C++. Indeed - in big organisation and scary-as-the-devil monolithic application, OOP is an decent way to maintain millions lines of code, shared by hundreds or thousands of engineers. Well, this is not the case in modern Multi-Service based architecture. We try as much as we can to avoid massive code bases. We don’t want to maintain monsters anymore and ideally - a very small team will maintain a single service with no more than a few hundreds or thousands of code lines.

What about good-ol’ OOP? In this case - it’ll bring us much more complexity than we need, and simple functional (and/or reactive) programming would help us more. GoLang is a functional language with some OOP-like concepts such as interfaces and structs. It is designed in such a way that it orients us to code simple, to prefer composition over inheritance, and as we’ll see in the next session - to handle parallel tasks in a much simpler way than we use to. So if simplicity is your thing rather than a pure OOP - GoLang might be your choice.

Concurrency AND simplicity (can they live together?)

You know the story - you wanna do “Multi Tasking”! Yeah! Do many things at once and utilize your CPU to its peak. You pay for CPU time anyway don’t ya? Different technologies bring different approaches how to do things parallely. For instance - PHP spawns a new process to handle each incoming request. Node.js is a single threaded server but introducing a complex callback mechanism, using the underlying OS to handle I/O tasks. In Java - you extend a Thread (or implement a Runnable) and launch as many as your VM let you. I find all the approaches above suffer from (at least) one of the following problems:

  • Complex code
  • Bad performance
  • CPU time wasted for nothing

This is due to some reasons:

  • The need to synchronise threads. This is hard!
  • Callback hell. Javascript is the major candidate of this problem but Java suffers from this as well, especially since Java 8
  • Launching many threads that do almost nothing except waiting for some I/O

Go introduces a built-in mechanism to do parallel work: Go-routines. According to Google formal documentation: Goroutines are functions or methods that run concurrently with other functions or methods.Goroutines can be thought of as light weight threads.“ What is actually happening is that Go manages an internal, off-stage, thread-pool. Each thread is assigned to a goroutine which actually needs some CPU time to perform calculations. This means that if a goroutine is currently waiting for a network response or a DB query-result, the CPU is not interrupted by this goroutine and no thread is allocated to it. In a single application, hundreds of thousands of goroutines might run parallely on a small 4 CPU-Cores machine.

Moreover - the approach of Go to Parallelism is similar to a distributed system. Each goroutine is considered as an isolated ‘micro-service’ which communicates with the rest of the system via Channels: build-in, blocking task queues with configurable sizes.

This is how it looks:

func fibWorker(input chan int, output chan int, stop chan bool) {
	for {
		select {
		case value <- input:
			output <- fibCalculate(value)
		case <- stop:
			return
		}
	}
}

for i := 0; i < workerCount; i++ {
	go fibWorker()
}

In the code above, fibCalculate is a function somewhere else in the code, calculates the fibonacci value of an integer. By calling fibWorkerwith the go keyword (line 13) we assign a new goroutine to this function. fibWorker is responsible of consuming values from the input channel (line 4) or from the stop channel (line 6). Whatever comes first. It’ll loop forever, blocked by both of these two mentioned lines (4 and 6). If the input channel contains one or more values - line 5 will execute the fibonacci calculation, putting the result in the output channel, and continue looping forever. If a single value exists in the stop channel - the loop breaks and the worker stops.

A single application might launch potentially endless fibWorker-goroutines, limited only by RAM. They will be assigned to a number of threads allowed by the machine resources. No more, no less.

What do we get from this approach:

  • No synchronization hell - this way as every goroutines is actually separated worker
  • No callback hell - no callbacks at all as we just don’t care blocking a goroutine!
  • No excess CPU time or threads as allocated. An idle goroutine doesn’t bother the CPU! Distinct equivalents to this approach are Akka actors (scala) and Vert.x worker-verticles (Java)

Also as distribution and scale are in the core of Go language - no too much extra work is needed to use the very same code, and distribute it over different VMs or containers, but this is beyond the scope of this post. In the meantime - Go helps you wasting your CPU time, only on the right things.

“We’ll start simple and scale later…”

You develop a MVP. Only a minimal, simple product which is… (for instance) a web crawler. It receives a URL, downloads a piece of data from the web, stores it in a DB, then extracts some other URLs from it to continue the process. “This is only a POC” you say, “let’s keep it simple”. After all - you have to show a working product at a quite short time. So you (or your team) write a very simple application. Only a single service or two. And know what? This service is working! From this point things happen fast. You have a few more customers, more traffic and load on your cute system and THEN - it doesn’t work anymore. Not because of your amazingly-simple design, but because making this service horizontally-scalable is not so simple as you thought. Well, Go might be the good news for you. This language is with scale in its core. It doesn’t matter if your application is aimed to run on a simple windows laptop or on a 64-cores Linux server - Go will orient you to write a code with scalability in mind. How does it work? As mentioned before - Go uses goroutines to perform parallel tasks, and channels to communicate between them. Each goroutine is considered a totally separated worker. No resources should be shared between then. The channels are internal message queues - they should contain every piece of data required to describe the task for the goroutine to perform. Sounds great? Wait for this: A go-channel can be easily connected to a message queue service like Kafka, ActiveMQ, RabbitMQ, SQS, Google PubSub and more. A good example for such a connector is vice project, but many more are out there. This way your service becomes distributed with no extra work as it was coded this way from the first day. That’s just the way it works!

“We cannot find Go experts, we have good Java guys here”

I promised pure technical aspects, but this is just a must: The on-boarding process of this new technology, and the learning curve. True, today finding a Go expert is quite harder than finding Java, Node or Scala experts. This is a distinct con. However, and this is a big “however”, Go is a very easy language to learn and be experienced in, for beginners or experienced developers of any other high-level language such as Java, Javascript or PhP, and the way GoLang orients you to design and write your application is much simpler than other candidates. The documentation of GoLang and the appealing getting started tour are detailed and clear, backed up by many examples, and of course - the playground.

We love open source but… can we rely of that?

Go is an open-source language. In the old ages - open source suffered from a bad reputation, mainly due to lack of formal support and backup from a big company. Of course, the situation is different as it quite hard to find a software project which doesn’t use one of more open source dependencies. We all love open source. It’s free, it’s well known, and it is maintained by the “community”. Yet, the lack of a formal support is still an issue tough. What if the contributors stop maintaining a library my whole project based on? Hi! This is not so rare, look what happened to AngularJS. The good news about Go is that although it is open source, it still mainly support by Google. The odds that Google will be still around in the next few years are pretty good.

Go offers an impressive ecosystem. Not yet as large as the ecosystem of Node or Java, but it is growing, and looks promising these days.

Summary

In this article I tried to enlighten the key features of Go language:

  • Simple coding
  • High performance
  • Scale in mind
  • Simple deployment
  • Fast on-boarding.

Using or not using Go, like any other technology, strongly depends on the requirements and the important perspectives of your organization or project. In my opinion - the main news Go language brings are fresh and different thinking patterns of the entire process of software development. Go proves that a complex and robust system CAN be also simple to develop, simple to deploy and give you the high performance you need. Almost all that it takes is rethinking obvious patterns like OOP, concurrency and memory management.

As I find creating coding - an art, I find Golang a big leap in a journey of efficiency, after which the artist focuses on “what’s important”, what the product should actually do, without the hassle of too-low-level engineering in order to gain some performance. Having said that, I recommend taking Go as a candidate in your next benchmark.

Good luck!

Thank you for your interest!

We will contact you as soon as possible.

Send us a message

Oops, something went wrong
Please try again or contact us by email at info@tikalk.com