- read

How Go fixed everything that was wrong with programming

Jan Kammerath 41

Why do you write software? I write software to build computer programs that solve real world problems. Software that solves very specific problems such as searching for a holiday, finding something I’d like to eat, writing a job application, cleverly investing money, paying for goods, measuring my energy consumption at home or simply entertaining me with music. Yes, I also do write software to simply learn and improve my skillset, but that never ends up being used by anyone else than me.

Is Go the perfect language for dummies?

When I want to write software, I decide what best suits my goal. I decide on whether I’d be a web server, a daemon running on a box, an API or serverless function running in the cloud or a software embedded on a chip (SoC). I define the output before I determine what language and toolchain to use. When I have the output defined, I create a shortlist of components, tools and languages I could achieve that outcome with.

If my outcome is supposed to be an embedded application on a single chip, my options for toolchains and languages are extremely limited. If my outcome is supposed to be a Restful API, then my options are almost endless. That means I need to be able to write good software with a variety of components, toolchains and languages to be able to achieve the best possible outcome to solve my real world problem.

My personal preference doesn’t matter

I have a personal preference for the C language, because of the wide range of programs I can write with it and I prefer compiled machine code over interpreters or VMs. With C, I can write apps from embedded devices to desktops apps, web apps and GPU-accelerated CUDA apps. Writing a web app in C however is, in almost all cases, the most uneconomic approach. It takes even an experienced software engineer significantly longer to write a web app in C than it would take in a language like JavaScript or TypeScript.

I need to make compromises all the time: With the desired outcome, with the toolchain and with the programming language. I permanently exchange performance for time-to-market and vice versa. Software engineering is a permanent compromise between cost, time and performance.

Go is the perfect compromise

Writing web apps or serverless apps in JavaScript is really fast in terms of time-to-market. I can write a simple app in JavaScript within minutes and deploy it serverless on AWS in no time. That fast time-to-market however comes at the cost of an interpreted language required to carry along its runtime (Node), thus causing higher operating cost and lower performance as compared to an implementation in C. An implementation in C takes significantly longer and requires more thorough testing. Further it requires a few more tweaks to safely run it on a box or in a serverless environment.

Java and C# offer slightly better performance than JavaScript while also providing very good developer ergonomics. Both languages however still need to bring along their, sometimes heavyweight, runtime environment.

There’s a German term for the perfect compromise: “Goldene Mitte”. It translates to “golden center” and would refer to “hitting the bullseye right in the middle”. I personally think that, at the moment, Go is absolutely that “Goldene Mitte”, the “center of the bullseye”. Go brings along advantages of a compiled language with the ergonomics of simple languages like JavaScript or Python. The consequence of these advantages however are the disadvantages Go is often criticized for.

Garbage collection, but compiled!

When performance benchmarked, Go apps often lack behind C as the garbage collection process is eating into the runtime performance. Still, Go constantly and by far beats any interpreted (JS, Python) or intermediate language (C# in MSIL, Java in ByteCode) while being en par with their developer ergonomics, thus time-to-market. It, almost perfectly, hits the performance center between C#, Java, JavaScript, Python and C or Rust. Remember that memory management and debugging in C is the challenge that eats up a large chunk of the time it takes for writing apps in C.

What even is an object? Structurally wrong.

Go lacks something almost all other languages have: object orientation with inheritance. C#, Java, JavaScript, TypeScript and Python all have it. Some do it nicely (C#, Java) and some in a really awkward fashion (JavaScript). The missing object orientation however has never stopped anyone from using the C language in favour of a language like C++ (sometimes considered a monstrosity). Object orientation is a wonderful concept, but might often not be the most economical approach to writing software.

/* this is as far as it gets, really */
type Location struct {
Latitude float64 `json:"latitude"`
Longitude float64 `json:"longitude"`
Name string `json:"name"`
}

Go stripped OOP down to the bare necessities: a structure or interface with functions that allow you to use composition instead of inheritance. It thus enforces simplicity by design. A perfect compromise between the C language and Java or C#.

Better be typesafe than type-sorry

Go is not always about developer ergonomics. Being statically typed improves performance, readability and maintainability. It however requires more work and thus potentially reduces developer ergonomics. It prevents you from becoming “type-sorry”: regretting not to have used static types in your code. There’s a reason why TypeScript was invented and developers are moving from JavaScript to TypeScript. It’s almost as if the inventors of Go foresaw these events. Go compromises developer ergonomics for better maintainability and preventing you from becoming “type-sorry”, another smart compromise.

Exception, you say? Err is not nil!

Go’s mantra of “You can’t just throw up here” and “do something about your problems” is unheard of. The latter however is more or less strict given that you can just ignore an error return value.

/* Go-style #1: handling, but essentially ignoring */
doc, err := xmlquery.Parse(strings.NewReader(xmlString))
if err != nil {
fmt.Println("That did not XML very well: ", err)
}

/* Go-style #2: burn the whole place down */
doc, err := xmlquery.Parse(strings.NewReader(xmlString))
if err != nil {
panic("Just explode")
}

/* Go-style #3: Error? Always wondered what _ is for */
doc, _ := xmlquery.Parse(strings.NewReader(xmlString))

Exception handling and throwing exceptions up the callstack (“throwing up”) is worth a book on its own. It’s a complicated matter and in reality often leads to apps throwing up all over the place. Not a very delightful experience. Go forces you to handle errors and pass them up the callstack, when required. It again makes a compromise between developer ergonomics (“throwing up everywhere”) and maintainability — in an awkward, yet cute fashion admittitly.

What software can you not write in Go?

It depends on the Go compiler what you can compile your code into. More and more target platforms are supported or are in the making (especially embedded platforms). There are a lot of things that you’d not write in Go at the moment: mobile apps (Pretty much TypeScript’s domain at the moment with React Native), embedded software or GPU-accelerated apps (C is still king for both). Apart from that, anything is possible. Epecially for server software, Go is the perfect compromise at the moment. When that’s the case, do you really always need all the features that Go does not have?

Go’s inventors publicly admitted several times: They designed the language for young engineers, mostly those that just joined Google. They wanted to stop them from making the same mistakes over and over again while still being productive. They essentially build it for dummies.

I love being a dummy!

The “For Dummies” book series is a well-known collection of educational books that are designed to provide introductory or basic information about various topics. The name “For Dummies” is not intended to be insulting, but rather is meant to be a lighthearted and humorous reference to the idea that the books are written for people who are new to the subject matter and may not have any prior knowledge or experience. The goal of the series is to make complex topics more accessible to a wider audience by breaking them down into simpler, more understandable concepts. While the word “dummy” in isolation can be an insult, in the context of the book series it is not intended to be derogatory or offensive.

Go, to me, feels like a programming language designed exactly like a “For Dummies” book. It’s quite restrictive on how you can do things while still leaving it up to you what you want to do with it. Like with the books, the results you can get out of Go are amazing. The “For Dummies” books are extremely popular. It’s publisher, Wiley, is a very renowned publisher. The books are far from being just for entertainment and provide an extremely valuable educational benefit. They give you what you need in a very optimized fashion and for that, they make compromises. Almost perfect compromises. And so does Go as a programming language.

Go fixed programming very well

I started programming and building software over 25 years ago, in the late 90s. During my journey I’ve built tons of web apps, server software, desktop apps, embedded apps in robots, payment processing apps, video streaming apps and a ton of other things I’m sometimes proud of and sometimes not.

In the last 25 years, I’ve seen code with miserable performance that caused unheard of financial damage to those running it. I’ve also seen code with such a beauty that no one knew how to maintain it and no one ever wanted to touch it. I’ve seen code throwing up exceptions everywhere and code not handling errors at all, causing segfaults whenever possible. I’ve seen code that damaged hardware, that caused fires and scared the hell out of anyone trying to even touch it.

Code is there to get a problem solved over a period of time until that problem changes and someone (often someone else) needs to adjust the code. Code is written and updated by numerous people over a long period of time, sometimes a COBOL-long period. Go does not improve the science of writing computer code, it does not provide major advances in computer science as we understood them in the past. What Go does is being a dummy language in the most beautiful interpretation possible and thus solving the social and human problems involved with writing software.

Go fixed practical issues in computer programming that arose over the last 20+ years. It, first and foremost, fixes problems that weren’t caused by technology, but problems caused by humans and their social behaviour. It stops you and me from overthinking and overdoing by saying: “Hey dummy, this is as close as it gets, mkay?”.

Try being more like Go.

Go, as a language, is a compromise in everything it does and provides. But, it is also a compromise between you and me. Between the guy who loves to optimize his algos to pure perfection, the guy that never handles exceptions, the guy that just doesn’t care about formatting, the guy that loves to explore the most awkward of language features and put them in production, the guy that excels at algorithms but fails to manage network connections and the guy who just wants to get it over with.

On a philosophical level, I could argue that Go is more than just a programming language and that Go is more about how we write code, especially how we write code together. It is almost as if the inventors of Go found the root of all evil in computer software today and fixed it.

I would personally like to thank Ken Thompson, Robert Griesemer, Rob Pike and all other people involved in Go for their amazing achievements for programmers.

Thank you.

What do you think of Go? What type of software engineer are you? Was there criticism that you could identify yourself with?