Home Thoughts on GoLang - Part 1
Post
Cancel

Thoughts on GoLang - Part 1

Couple of years ago, one of my friends wanted me to look at golang. Back then, golang was a shiny language and there was a lot of hype around it. I briefly look at the language and I had two primary concerns back then:

  1. Lack of generics: No longer exists now as generics were added in go 1.181.
  2. Better ergonomic error handling: This problem even exists at the time of writing. Most of the times I see a common pattern mentioned below:
1
2
3
4
5
// common pattern
result, err := fetch_value()
if err != nil {
    return nil, err
}

​ I wish there was a way2 in which I can return an error if I don’t want to deal with it. Something along the lines of:

1
2
// Inspired from rust
result := fetch_value()?

? at the end is not actual go code. This is only for functions which return error as the last argument and if there are any other arguments they will be set to their “zero” values.

Overall

Go hits a sweet spot between feeling like a dynamic language and at the same time being a statically compiled language that is fast enough for most of the applications. This language competes with java rather than trying to be a substitute for c, c++ or rust. For the remainder of this post, I will focus on how the generation of static binaries by golang languages eliminates a whole lot of issues and I will discuss golang features in future posts.

Static Binaries3

I can’t emphasize how important is the generation of static binaries in today’s cloud environment and it’s nice that go makes it very easy to generate static binaries for supported platforms.

Static binaries provide the following advantages:

  • Dependency Management and Deployment:

    • No need to manage dependencies. Makes it easy to dockerize the application by just including the binary.
    • Binary artifacts usually take less space4, thereby making builds easier and faster to deploy.
  • Saving Costs

    • In the long run, we would cut down on our storage costs as these artifacts consume less space.
    • If you are using something like lambda functions, you save money as go applications don’t have to spend time JITing the bytecode which typically happens in JVM and ruby world. Although, JITing the bytecode may produce more efficient code5 than static binaries in some scenarios, this process always consumes both memory and cpu cycles on the machine on which the application runs.
      • If your application or code runs for a very short time, then all the JIT complication is wasted.
      • Every time your applications restarts, the JIT compilation process needs to be repeated.
      • If you deploy 100 instances of these microservices, then JIT compilation process needs to be performed at all of these 100 instances.






  1. This even plagues today in many of the libraries written in go before 1.18. Take for example god’s library arraylist implementation, we can create an arraylist holding different types which completely bypasses static checking. 

  2. However, I can live with a little bit of syntactic sugar that can make error handling less verbose. 

  3. This is applicable to any languages that can generate static binaries like c, c++, rust, crystal etc. Recently, java has been making strides in native compilation using graalvm

  4. For java applications, shipping all the jar files along with java runtime results in large file sizes. 

  5. Several arguments made in favour of JIT:

    • Runtime can examine hot code paths and only JIT these hot paths aggressively
    • Runtimes can possibly generate better assembly code as it is aware of all capabilities and features of underlying hardware.

This post is licensed under CC BY 4.0 by the author.