Learning Golang
Welcome back to Aria's Corner. I'm Aria ๐ท and today I'm talking about...
So I've just sat down to snack on some freshly burnt almonds (don't ask, let's just say baking isn't always my forte ๐).
Anywho, I wanna talk about golang, or "Go" if you're into terrible naming ๐.
So... I've loved JavaScript for years. Simple, age old stuff. It's like bash but for the web. Now I know, everybody and their neighbor's pet unicorn has aโusually negativeโopinion of js. I still can't fathom that. The language was built in 2 weeks flat. I find it fun.
Anyways, new tech is always on the blindingly bright horizon ๐. So, there's these new (I know... I'm late to the game but meh...) shiny toys I hear keep hearing about. New-fangled tech like rust, dart, and of courseโgolang.
So I decided to see what all the hullabaloo was about. And let me let youโand I think this is way better than leaving you in suspense until the end of the postโI sorta like golang.
I mean, I'm not saying I like everything about it, but there's stuff it does that I thought was kinda neat.
Java Meets JavaScriptโ
So, we all know js lets you get away with murder. Throw whatever into whatever variable and away you go until the codebase starts collapsing under a ton of Uncaught TypeError: undefined is not a function. Not fun. So you start littering the code with type check conditions ๐ฌ.
Of course, people think TypeScript will put those fires out ๐งฏ. So you spend a day configuring and refactoring for that. Alls well... least until your buddy decides to :any all the variables 'cos they can't be asked to faff with type warnings that breaks their dev build ๐.
Of course, the solution there is to draw up some ground rules. But that brings us to Golang. It's compile-time, so more like the heavy duty big boys like Java. But Java is ugly and lagging. Kotlin takes a few style tips outta js's book. Go is sorta like that.
Check this:
var x int = "hello" // Error.
var y int = "world" // All good.
Explicitly typed! But the syntax is still short and modern like js. Yet no verbose Java syntax ๐.
AND... you can get ts-like type inference BUT even shorter syntax ๐คฏ๐คฏ:
x := "hello" // Automatically a string.
Now that's python levels of simplicity ๐.
Always Erroringโ
In JavaScript, error handling seem optional. You can throw, catch, ignoreโwhatever you're in the mood for.
golang, meanwhile, makes you deal with your problems like a real, adult, dev. No exceptions (pun intended ๐)
// Hello pythonic tuples, what a crossover!
data, err := os.ReadFile("cookies.json")
if err != nil {
return err
}
I know what you're thinking. That looks like someone forgot how to try-catch. Yeah... that's not it chief. golang has no try-catch ๐ฑ.
It seemed mad. Like... how can the language even work without something so essential that's it's been a staple since C?
At first, I hated it.
Then again, I kinda got it. A lot of coding conventions say something like "always handle your errors". It's common sense but the fact that standard libraries like node's fs package can return null errors... Combined with the fact that you can just try-catch and throw away the error... The whole forced handling of errors makes more sense now.
To be honest, there's nothing stopping a rogue dev from naming the error _, which discards it ๐ฌ.
So... it's an interesting idea. Take away the staples so you gotta deal with your problems. But this smells like syntactic sugar to me ๐.
So yeah, I'm not the biggest fan of this no-try situation in golang but I get what they were going for. I like the tuples though!
101 Ways To Asyncโ
Alright, this is where things get different.
So we know js is juggling it's history with promises becoming async syntax sugar. Not bad sugar, mind you. Oh, and let's not forget callback hell ๐ฌ. Only old school Android async could rival it.
Golang takes a different route here. It takes page outta kotlin's coroutines (which were invented to wrangle the processes eating into UI lag).
Basically, golang gives you goroutines (original naming, huh? ๐) and channels.
go buyMeAUnicorn()
That's it ๐ฎ๐ฎ.
No "new Promise()." No "async function." No "suspend coroutine" And especially, no returning a promise because you forgot an async keyword.
Basically it just runs in the background and some goroutine elf handles it ๐.
Of course, that seems too good to be true. Always is with the 2nd most difficult problem in programming (or has that changed with the advent of AI bots? ๐ซค)
Anyways...
Enter channels. I'm not gonna lie, they're weird things at first...
package main
import (
"fmt"
"time"
)
func buyMeAUnicorn(ch chan string) {
time.Sleep(1 * time.Second)
ch <- "๐ฆ"
}
func main() {
ch := make(chan string) // What in the heck is this?
go buyMeAUnicorn(ch)
unicorn := <-ch // Basically `await`.
fmt.Println(unicorn)
}
Now, if you're anything like me, you're probably wondering "what even is the point of CHANNELS?"
They're basically a cross between js's await and Java threads. So... you can string a bunch of operations together on one channel, and do another on another channel.
Seems golang has a thing for syntax sugar...
Least there's no callback pyramids. No promise chains. No "why did my API call return [object Promise]?" debugging situations. But then you end up with this whole threads and coroutines with sugar on top situation.
Now... I prefer js's good old promises and async. It works and it's flexible... and tons of languages seem to enjoy reinventing it with different flavours of syntax sugar. But then again, I'm kinda biased... ๐
It's Not a Raccoonโ
So... I've got nothing against raccoons. Actually they're kinda cute with their little builtin bandit cosplay. But... then I gotta talk about the big mean green elephant (also kinda cute when they're "little") in the room.
We node developers are basically raccoonsโrummaging through npm, grabbing shiny packages, hoping they don't bite us later.
But the BIG question is why? Why do we keep doing this to ourselves? As much as I hate to admit it... it's because unlike other languages like java and python, which had time to mature. JS was rushed together to make the web work. So it's understandable that it lacks a standard library.
And node.js gives us a sort of standard library *cough* not in the browser without bundler-hell *cough*. Plus it bundles npm, which gives us a fantastic candy store of packages.
Security and module density memes aside, npm is great (despite being reinvented for "speed demons", yarn and pnpm).
Dependency hell sucks. Maintaining stuff sucks too. But something that's sorta simple and easy to understand (albeit heavy and unoptimised ๐ฌ)... that's basically npm.
Now... golang, like most modern languages that had time to think through their development... got a proper builtin standard library. Otherwise kotlin woulda put it outta business. So of course, it's a complete library.
You want HTTP?
http.ListenAndServe(":8080", nil)
That's it. No node. No npm. No Express. No body-parser. No seventeen middlewares to fix something that shouldn't have been broken.
Of course, golang has it's own package manager. Except they call it a module manager and it's sorta part of the runtime via the go command. Nice. Although I'm still not on board with the generic naming of everything being "go". But that's just me being a fussy toffee ๐.
A Compiler That Cares?โ
So... build errors... You know the deal. JS errors be like:
"Undefined is not a function."
[insert the longest most irrelevant stack track that's referencing at least 2 of your dependencies, possibly missing any reference to your actual code]
Been there done that ๐.
Meanwhile, golang's compiler is a little more helpful:
"Line 14. You declared a variable you never used. Fix it."
Now this. It's something I really like about not just golang but modern tech like rust โค๏ธ. They're trying to improve the DX and it's actually helpful ๐.
I've love to see this kind of love poured into js errors and ts type warnings. You know. As opposed to the wall of text that they currently spew.
It's like a stern librarian tapping your wrist with a ruler whenever your code smells weird. Rather than someone lobbing a book at your head.
Annoying, sure, but you ship fewer bugs. Andโgod help meโit just feels good ๐ฅฐ.
You Want A Struct?โ
So... js objects are basically shapeshifters. They grow, mutate, fall apart, whatever.
Now, you could use ts's evaporating types/interface hybrids or kotlin's snazzy but picky data classes.
But golang gives us structs:
type Planet struct {
Name string
Color string
MassKg float64
}
Doesn't seem too impressive... yet. Right now, that struct looks no different than your run-of-the-mill ts type.
*Channels Morpheus* But what if I told you, you can initialize it, and even add methods to it... yeah, just like a class. You'd be right ๐.
func (p Planet) Describe() string {
// Unfortunately this seems to be the best string interpolation that golang can do.
return fmt.Sprintf("%s is a %s planet with a mass of %d.", p.Name, p.Color, p.MassKg)
}
func main() {
p := Planet{Name: "Mars", Color: "Red", Mass: 6.4171e23}
fmt.Println(p.Describe()) // Hello, my name is Bob
}
Now if you're thinking that looks like a kotlin data class with an extension function... you'd be right, again ๐.
But I guess that's just how it is. You know, with all these new languages copying from each other... it's inevitable that we'd end up with samey features.
Just to say... don't get me wrong. I love ts, but... kotlin dataclasses are kinda how I wished ts's classes would work. Rather than mix and matching types and classes, and doing that weird readonly thing with verbose constructors... ๐ซ .
All The Batteriesโ
Alight, this part's kinda cool ๐.
Usually when I gotta do some automatic file changes like formatting or testing a build... I'd throw together a script to make it happen. Small, big... doesn't matter.
But with golang, things are different... seems the batteries aren't just included. They're duct-taped to your hands ๐ช.
See, like we mentioned earlier... golang's runtime includes a bunch of commands (yeah, package managements is just one of them ๐ฎ).
Things like:
go fmt: Instant formatting, forget the editor.go vet: Catches your build issues.go mod: Creates a module.
Now... we know npm includes a bunch of commands too. But golang seems to provide a few more that're more specialized. Like it could become a standard lib of commands to make your pipelines just a little easier to hobble together. Plus no yml involved ๐.
Gotta Go Fastโ
This one's a doozy. Golang's a compiled language, so at scale it's gonna be way faster than an interpreted language like js or even ts with it's transpiler ๐.
Now it's one thing to say golang's fast but to actually run it and see how fast it can go is a whole other thing.
So... like, summing 100m integers runs in milliseconds ๐.
Plus apparently goroutines are lightweight (like kotlin's coroutines). So you could probably run thousands without too many memory issues.
And I mean... modern simplicity and speed are supposed to be golang's bread and butter. So it's cool it checks out on both of those, for the most part ๐.
It's Still Weirdโ
There's some things that golang does that are just strange for me.
Stuff like uppercase for exporting things? My fingers protest every time.
Just look at this:
// Exported function.
func FindTheCookie() {
fmt.Println("I found a cookie :D")
}
// Unexported function.
func findTheDoughnut() {
fmt.Println("I couldn't find a doughnut :(")
}
I mean, I get the whole less-typing argument but casing controlling exports is just plain strange.
And then golang didn't have generics at first, which was weird... ๐ค
There's the walrus operator, which was cool when I introduced it earlier. But it does give me flashbacks to the mad assignment hell in AHK ๐ฌ.
And... I've already touched on the no-try thing. I think I definetely prefer having the option to try-catch. Plus I keep finding myself wanting to try-catch then having to do the mental gymnastics of doing it the "golang way" ๐
Time To Switch?โ
Well... you probably know the answer to this one. I'm a die-hard js fan girl. It was my first language... it's simple and flexible... and I'll just always have a soft spot for it ๐ฅฐ.
Now, golang does some cool stuff. It's clearly trying with things like the walrus inference and super flexible structs.
You probably don't wanna hear this ๐ but when deciding whether to switch to golang... it really comes down to what you're doing, your team, and preferences.
So... for me... I might use golang in some cases. But I'd probably prefer to stick to js just 'cos that's what I like ๐.
So yeah... Go and I? We're getting along.
Til next time. Your friend, Aria ๐ท
