The ramblings of a front-end developer (who’s trying to write Go)

I’m a front-end developer who spends most of his day writing HTML, CSS and Javascript, but more recently I’ve been spending my time writing Go. If you haven’t heard of Go (otherwise known as Golang) then it’s worth having a look at the fantastic Tour of Go tutorial. Very basically, Go is a server-side programming language developed by Google that has been quite heavily influenced by C. I’ve dabbled with Go before, but now I’ve had the opportunity to spend a good block of time writing it I thought I’d share my thoughts about what I’ve found useful or interesting about Go and what I’m not a fan of.

Before I start rambling I should probably apologise. No doubt I’ve shown some misunderstandings or lack of knowledge about Go that are completely unforgivable to anyone with more knowledge about server-side languages. However, this post is solely intended to express my experiences as a front-end developer (who is very new to Go) and how it compares to frontend technologies.

Go’s core library is powerful

Coming from the world of Javascript where there’s a library or a framework to solve every possible problem you could think of, it’s quite refreshing to use a language that can do so much without the need for extra dependencies. This is not to say that Go doesn’t have some great libraries but they feel as though they’re optional enhancements on top of the core library, rather than being a “must have” for building a good application with a nice workflow.

I’ve found it easy to build an application with just the core library; it has good enough templating, http server and test framework to serve even some quite complex needs  (although I have to mention that I’m not a huge fan of the default logging and the fact that a “panic” can shut your application down during runtime). Compare this with a NodeJS application, which usually means initialising with NPM and installing dependencies such as Express, http, Jest, Handlebars templating and Webpack to create what could still be a simple server.

Go is a low-level language

What I mean by this is that typically Go doesn’t try to abstract complexity away from the developer – which can be both negative and positive. For someone from a front-end background, who hasn’t had to deal with bytes, memory allocation or concurrency in much detail this has been a bit daunting. For those more experienced, I imagine it means the language can be powerful when used properly (so probably by someone other than me!) by being able to optimise exactly how code works, with very little being forced upon you by the language.

I’m still struggling to get to grips with just how low-level it is and I sometimes feel it’s more complex than it needs to be. For example, here is how we can take a request’s response body and turn it into a usable format:

// Make our GET request for some JSON
res, err := client.Get("/api/data")
if err != nil {
	fmt.Println(err)
	return
}

// Close the stream when we return out of this function
defer res.Body.Close()

// Create a slice (similar to an array, for the purposes of this example) 
// of the bytes that make up the body of our response
b, err := ioutil.ReadAll(res.Body)
if err != nil {
	fmt.Println(err)
	return
}

// Create a struct (similar to an object, for the purposes of this example) 
// that has the structure of the JSON data we expect our API response’s body to have 
var myData dataResponse
err = json.Unmarshal(b, &myData)
if err != nil {
	fmt.Println(err)
	return
}

Most of this makes some sense to me now but when you come freshly from Javascript, where a lot of this is assumed and done for you, it is a definite hurdle to overcome in order to have any idea how to write a Go application. Just for the comparison, here is how it can be done in Javascript:

fetch("/api/data").then(response => response.json()).then(response => {
	const myData = response;
}).catch(error => {
	log.error(error);
})

Error handling

Unlike Javascript, Go is quite strict in making sure that any potential errors are dealt with as soon as they could occur – this generally means no high-level error handling functions. A lot of Go functions will return an error type that has to be dealt with. This means your code contains a lot of code that looks similar to this:

if err != nil {
	fmt.Println(err)
	return
}

From what I’ve read this approach to error handling can be quite divisive among developers. Some people feel it is too verbose and causes lots of unnecessary duplication, whereas others think it helps make sure developers consider what errors could happen and deal with them appropriately.

Personally, I sit in the latter school of thought. I prefer being quite verbose and being reminded to consider what errors I might have to handle gracefully at each point in an application. I’ve started to incorporate this error handling pattern into the way I write Javascript. I’ve already seen benefits by getting more meaningful error messages when something has gone wrong at runtime, therefore having better control over what I should show the user.

Gophers are cool

People who write Go like to refer to themselves as “Gophers”. This may seem nerdy but …  well it is … but it does develop a great sense of community between Go developers. You also have an excuse to plaster your laptop with stickers of cute cartoon gophers like this:

Cartoon-style image of a gopher

Credit: Renée French

Strongly typed languages rock

There, I said it… I know it almost seems blasphemous to be a self-confessed Javascript nerd and admitting I liked writing strongly typed code. I’ve found the loosely typed nature of Javascript is great for quickly putting together code that just works; however, the safety net of a strongly typed language really helped me pick up obvious errors early on and made debugging quicker. It also integrates really nicely with text editors (I’m using VS Code at the moment) to quickly autocomplete and check for errors before you’ve even compiled or transpiled any code.

The benefits of using strong typing has felt like a lesson learnt that I can really apply to Javascript now that we have libraries such as Typescript. I’ve had Typescript on my “must-build-something-fun-with-this” list for a long time and it’s just jumped to the top of that list. Fundamentally, it just feels like an easy win for any Javascript application.

Will I always use Go instead of NodeJS now?

Most of the time … yes I will use Go instead of NodeJS, but there might be the odd occasion where NodeJS is more suitable. For example, I can build a prototype in NodeJS much quicker than I can in Go at the moment. I haven’t written huge amounts of server-side code, but in the past I would always use NodeJS (for obvious reasons) but I can really see that changing now. It’s quick to compile, the syntax is fairly common sense, it can be really performant and it teaches me new ways of writing code.

In the interest of preventing a developer flame war, I’m not going to go as far as to say that every developer who’s dabbled in NodeJS should now be dropping it for Go. However, if you’re a developer who’s only used to writing server-side code in Javascript then I would strongly recommend exploring Go on the occasional project. If not only to explore some of the common patterns in other languages and how they might improve your Javascript code.