Disclosure
This post is moreso just a rant for me to get some frustrations off, and also
some praise towards a new choice I’ve made.
If you’re not interested in a whole page of nerd ramblings, just wait for my
next post.
What is she on about now?1?!
If anyone has paid attention to my project list on Gitlab, they’d see I’ve
switched languages a decent amount.
My main reasons were just wanting to get away from (Java/Type)Script since I was
getting increasinly frustrated with the experience using the language to do what
I wanted.
In a typical Typescript project, I would most likely clone from an earlier
project just because I have a decent setup with my import aliases configured the
way I wanted, my default packages installed, and I can get to work.
This always works fine, until it gets to deployment.
Suddenly, some modules might fail to resolve, errors that you don’t get during
development now creep up on you in production, and you spend a whole day trying
to make your chosen deployment platform accept your code.
For this asinine trade just to get a working prototype, I was now dealing with more
headache trying to make the code useful than I could have been making it
actually work.
“Yea, well I don’t have that issue because I just use React CRA | NestJS | x !”
Understandable, but for the way I code, I probably don’t. I want it to be
completely my own without the need for a framework to make decisions for me.
At this age, when I have a full time job, I don’t want to waste my weekends
researching x framework, making Docker configs or messing with language
semantics just to get the result I wanted.
So I knew I needed a change. Something simple, performant enough
for me to get on, without a crazy syntax or packages that feel like they change
the entire dynamic of the language.
Immediately, I knew Python was not what I wanted.
Why I settled on Go.
With Go, I realised I didn’t have to care about any of it anymore.
Developed by Rob Pike (admittedly a very odd character with even stranger
opinions) at Google, it crossed into a perfect blend of simplicity and
non-caringness.
I can just, write code. A whole codebase in 4 files if I wanted to.
I can compile to any target, made even easier with tools like go releaser,
which makes the entire experience of software release a breeze.
The syntax is simple and never deviates from its own standard, which I really
enjoy.
I don’t have to learn a specific framework’s syntax like I do with Typescript or
Python (espeically with the weird decorators both languages poorly implement)
and differences in mindset even when using the same codebase.
Being away from the Javascript ecosystem makes you think that you’d never be
able to write as much varied software as you did before - no electron is coming
to wrap up your website into a 2GB desktop application anymore.
No v0 or chatGPT AI is coming to whip you up a new Next.JS B2B slop in 30 mins.
When you write Go, you’re learning the language, and adapting it to the problem.
I’ll also include a nice list of all the cool Go packages I’ve found and use
too, it even has very nice things like PDF printing, charts, very good web
frameworks, HTMX and really easy secure development.
Need a frontend? You can serve one with Templ and HTMX. A newer technology,
which is surprisingly not a pain. I rather like it 😃
Want a CLI? Bubble Tea is right up
your alley, and has a variety of surrounding libs like lipgloss
which is just CLI prettiness cheat codes.
Want a good logger? Zerolog is configurable,
easy and works with context seamlessly so you can pass it around your code
very neatly.
Also has the option to specify keys- i.e:
func (m Module) DoStuff() {
// get our logger
log := middleware.GetLogger(m.ctx)
// some stuff
if err != nil {
log.Error().
Err(err).
Ctx(m.ctx).
Str("user_id", user.ID).
Msg("an error occured!")
return
}
}
It looks verbose, but you can wrap it in a function if you like, or keep it
as-is, which I prefer to do.
You get to go closer to the metal than you do with Javascript, which means you
can optimise every database query, without having to use overbloated tools like
Prisma, which I’ve become firmly against.
Main reasons being -
- Only supporting CJS
- Each query has to refetch and revalidate every row in every JSON no matter the
query - Ulterior .prisma file which uses its own standard and requires its own coaxing
to work in deployment - Recompiling for node-gyp in production is still a pain 5 years later
Things I like about Go
Functionally simple
Functionality of the runtime is simplified, split into separate packages.
Unlike Rust, concurrency is built-in, not relying on third party libraries like
serde or tokio just to achieve what Go does in its standard library.
We also don’t have to think about debug or release compiling - it’s much faster
in Go, and you’ll have the same binary no matter whether you’re in dev or prod.
No higher level abstractions
Everything is just how you get it in Go. Again, unlike Rust, you don’t have to
learn a whole new dialect (Rust Macros I’m looking at you) just to write good
code.
Things like errgroup, part of the sync package make concurrency super simple, whereas in Javascript it’s
a job of either spawning worker threads, clusters (if you’re on v24+) to achieve
the same result, with marginal success.
func main() {
Google := func(ctx context.Context, query string) ([]Result, error) {
g, ctx := errgroup.WithContext(ctx)
searches := []Search{Web, Image, Video}
// since we know the length of the array, we can pre-define the length
// with `make`, which saves the program creating new array copies and
// unduly performing CPU operations.
results := make([]Result, len(searches))
for i, search := range searches {
i, search := i, search // https://golang.org/doc/faq#closures_and_goroutines
// start it
g.Go(func() error {
result, err := search(ctx, query)
if err == nil {
results[i] = result
}
return err
})
g.Go(func() error {
// do some more stuff
})
}
// wait for it to finish
if err := g.Wait(); err != nil {
return nil, err
}
return results, nil
}
results, err := Google(context.Background(), "golang")
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
for _, result := range results {
fmt.Println(result)
}
}
Random list of my thoughts on different languages I’ve tried
OCaml
I tried it thinking it was a better Rust. And for the most part, I was
right. For the most part, I was actually right! I didn’t have to deal with
verbose syntax, each symbol felt like it had a purpose, it felt very
mathematical, and the ML style declarations for functions and variables was
quite nice. Just being able to do a let binding that magically solves a whole
task for you, is really, really rewarding.
To cut it short, the only downside was a lack of standardisation, really bad
library support, no solid or well documented way to spin web servers and start
making code useful. It remainds theoretical - in this paradigm of elegance and
mathematical purity which it just, kind of stays in. Never progressing to much
more beyond an exercise in self gratuity over one’s own intelligence.
Then I tried Crystal again
And it hasn’t progressed in the last 5 years since I tried it.
Still no Windows support either. Not that it’s important to me, but I don’t
think it’s going to really get anywhere anytime soon.
Then I did try Rust!
And, I’m not going to lie I really didn’t have time for that.
C#?
Really boring. Feels like I’m coding enterprise. No joy, kind of heavy runtime,
bad linux support. Depedencies only working on certain forms of Dotnet is also a
pain in the ass. I found it worse than Typescript.
Lisp?
No one writes Lisp anymore, so really not nice experience making software
anymore. Not like how I used to back in 2018 back in school.
Good memories, but that’s all it’ll ever be.
Backlinks
No backlinks found.
Go back