Go is Productive
backstory (skip if only interested in technical explanation)
Yesterday I had a CS midterm from 8-10pm. I was somewhat stressed as I had basically gambled by not properly studying for it. However I finished early, and I was feeling pretty good. Even though it was a Monday night I felt it was cause for celebration.
So all of us CS kids gathered (and one engineering guy with a chem midterm at 9am the next day…) and broke bread, comforting those who lost their battle with Java/concurrency and decompressing until, perhaps, too late. I was super tired, I had a long day and once everyone dispersed back to their dorms I sat on my couch cracked open my laptop ordered some taco bell and started working on my pet project.
I awoke a few hours later, laptop sitting on the table next to me and half a crunchwrap that wasn’t exactly warm. I ate the rest of the crunchwrap, started some semblance of my morning routine with electrolytes and my vitamin d, and took a look at the project. To my surprise, I found significant progress. It wasn’t even like boilerplate, I had finished some complex code. There was properly implemented concurrency, and I basically solved a structural problem where the prompts I was using were half hardcoded, half programmatically generated in Go, and half awk parsed madness baked into the Makefile. I unified them to be in the same place, with the same extensible text format, and all easily accessible across the project in Go.
The reason for this was I basically knew how to implement it, I had worked that out on my walk back from my midterm, but I just needed to write code. And it turns out, even at my worst, most tired, Go makes it so I can.
I was so amazed I simply continued coding when I woke up and started replacing all occurrences of hard coding or other weirdness with this system. I tested it, and it worked.
technical explanation
Go is dead simple. It is imperative, has manual error handling, and very few non-obvious anti-patterns. There is no clean or “expressive” way to write highly abstracted code, you just take things and do stuff to them using the same basic, imperative, tools that have been there since C. I rarely have moments where I have to stare at the screen for a long time just to figure out what abstracted clusterfuck has been presented to my eyes. This happened back in my Java days with these insane class hierarchies, happens somewhat frequently in FP (especially point-free APL style languages, which I have a sort of infatuation with), with macros in C, everytime I see C++ templates, and in Rust with 1. Macros 2. FP 3. Basically a whole other language for async code. I am not saying any of those are bad languages, they certainly are fun and have beautiful, satisfying use cases (and I would be lying if I said I didn’t miss some features), but Go scratches a different itch.
For example, I wrote multiple API wrappers (clients, SDKs, whatever) for LLMs, like anthropic, openai, ollama, etc. I wanted to operate on the prompts/messages and have it be generic for all of them, despite the differing formats. Immediately I went to using a monad. Then I was thinking, let me make a generic LLMSdk that is somehow extended by the individual SDKs and the Message type will belong to the generic LLMSdk, And perhaps there is a generic way to do it in Go, but I like having the option to idiomatically not prematurely optimize. What I actually did was just write a bunch of util functions that translated the message types to each other. Is this the most scalable, abstract solution? no. Did it work and not increase the complexity of the project at all? yes.
I wrote the backstory because I feel like I can rip through 8+ hours straight of simple Go CRUD (more in the literal sense) using very little of my brain on how to express things “nicely/beautifully” using the language, but instead focussing on what I actually want the application to do. I almost never think “well, is this the most idiomatic way of doing this?”. Sometimes I just want to put the stuff into some structs, do some operations, throw it in the database and be done. You don’t have to be “smart” to write Go, and frankly, being “smart” is overrated.
I love coding and solving/doing hard problems, but when I am working on a product, I want to use my brain to solve product issues, not implementation issues. I want the inertia I need to do tasks to be low, so I don’t have to eat 1 million complicated, highly technical annoying frogs everyday. Coding in Go literally feels like folding laundry, basically doing the same thing repetitively with little mental overhead, things happening automatically, and I love it. This autonomical experience is basically hitting flow state for me. I don’t have to think about how do I do X, I just have to think I want my product to X and then start spewing code into my IDE.
limitations
Like all matters, there are some caveats. If your X (thing you want to implement in your product) is not something well suited to basic business logic CRUD (ok maybe a little more advanced than that) or is a specialized CS topic, Go probably is not for you. Like if you can take a masters level class in it, you probably don’t want to use Go. Some examples would be compilers/parsers, ML/AI, operating systems, etc. Though even then, concurrency and network IO are still pretty easy to do in Go. It also has some good built in crypto libraries and standard algorithms.
You can also make the argument this experience is just because I am more familiar with Go than those other languages, and the ease of it compared to the other languages is just a skill issue. I would say I feel as if there is an upper limit to skill, and most languages have a skill ceiling so high they there exists terse, syntactically correct statements that would take experts a long time to decipher semantically. I consider myself fairly proficient in Java, but some abstractions just take time to piece together how they work. The implementation has little to say with what it is doing (its goal) and a lot to say about the manner in which it will go about doing it. So it’s hard to figure what is actually going on, but easy to realize how “clean” and “extensible” and “DRY” it is. If you think about it, this is analogous to what point-free syntax is, you describe functions/transformations over your input, but never explicitly mention doing stuff to it.