I can’t stand go. It is painful and annoying to write compared to almost any modern language. Yes it’s simple, and makes it easy to write concurrent programs using one particular style of concurrency, which are about the only good things anyone can say about it.
The proponents of go seem to have an almost cult-like devotion to simplicity. They think adding any facility for abstraction makes a language into a complicated mess like C , and any type system feature that didn’t exist in C makes a language into an ivory tower academic plaything like Haskell. The way the author talks about spending all day writing a perfectly beautiful, inscrutable piece of Rust code is an example of that. Yes, there are a few things in rust that are a bit harder to understand, but not to such an exaggerated extent, and that strawman is really not the typical experience when writing Rust. It’s very unusual for an experienced user of any mainstream language (except C ) to have any real difficulty understanding what a given piece of code does.
I guess I'm part of that cult as I value simplicity greatly. Heck I was even against generics and iterators, though the former has grown on me a bit.
One question I ask in earnest, why do people not just use another language rather than try to get features jammed into Go? There are so many good ones out there now, it feels like a person can choose something to their own liking.
If it's being forced at work, I guess that makes some sense, but I'm also a big proponent of 'when in Rome.'
The thing about simplicity is making the language simpler often makes programs themselves more complex. For example, in a language without generics, if you have 10 different versions of the same function that only differ by a type parameter, you have to either write them 10 times (meaning anyone reading the code has to read 10 different functions), or you have to write some code generator (meaning anyone reading the code has to now understand your code generator). And, all this cost in the complexity of programs is to avoid something that, in my opinion, _barely_ makes the language any more complex.
So you're not uniformly increasing simplicity. I do agree that when there is a way to make a language simpler without any other downsides (e.g. making programs more complex or error-prone), it should always be done!
Most people, even Go programmers, would think it was silly if you couldn't define your own functions and had to copy-paste blocks of code everywhere, so clearly they aren't against abstraction in principle. And I don't think generics is a particularly more complex form of abstraction than the ability to define functions is! The fundamental difference is not the level of abstraction, but just that _it didn't exist in C_, and the version of it in C (templates) is extremely difficult and unwieldy. So presumably that's what the designers of Go were afraid of.
> One question I ask in earnest, why do people not just use another language rather than try to get features jammed into Go?
I have to use Go because I am working in an ecosystem that is entirely in Go. Rewriting it in another language would be much more effort than is feasible. When I work on personal projects not for work I don't use Go at all.
Also, not everyone uses Go because it lacks features for abstraction; there are other reasonable reasons to use it, for example if one likes the Goroutine-style concurrency model.
There are tons of examples. So here's a random one: a function that sorts an array. You either need generics, need to write it using runtime polymorphism (making it significantly slower), or need to re-write it for every type of element that you want to sort an array of.
The fact that Go has functions called sort.Strings, sort.Floats, sort.Ints, etc. is just silly duplication that wouldn't have happened in any other modern language.
Doesn’t go having such type specific functions mean you don’t have to? Feels like that makes your codebase _less_ complex since the core logic is handled by the language stdlib, not code written and maintained by your team.
That is what I meant by runtime polymorphism. It is slower. The fact that runtime polymorphism is so widely used despite being a crappy hack imitation of generics proves how useful generics is.
Edit: Nevermind, sort.Slice doesn't use runtime polymorphism. It makes you pass in a comparator function. So probably not slower (assuming the function can be inlined), but less ergonomic.
> Doesn’t go having such type specific functions mean you don’t have to? Feels like that makes your codebase _less_ complex since the core logic is handled by the language stdlib, not code written and maintained by your team.
I'm not talking about the complexity for people using the code, but for the people writing it. Realistically not everything is in the stdlib and at some point you have to actually write some code. And at that point the features that make it easier to write code, like generics, make your life easier.
(Also the Go sort package only has support for a few built-in types. What if you want to sort a slice of user-defined structs? Then you have to use runtime polymorphism via sort.Slice, which is slower for no good reason).
Sort on its own is maybe not the best example because it's relatively easy to work around, but those workarounds quickly break down. Write me a function that returns the keys of a map in order without using generics...
You were specifically asking about generics. If you wanted me to give an example of the usefulness of some other feature that Go refuses to add, I would.
Yes, Go finally added generics (years too late). But the fact that so many people were opposed to them for so long illuminates something about Go culture that is still relevant.
Well you were quoting a part that said "in a language without generics" and were questioning why that was bad, so that's what they responded to. But that used to be Go, and it got a lot of pushback when generics were introduced. It illustrates an issue people have where obviously good language features are rejected by a loud minority for seemingly no good reason.
I guess that depends on your definition of simplicity. I don't think of simplicity as 'easy to do' or 'less lines of code', but in terms of easy to immediately understand what the code in question is doing, both from explicitness of said code and size of language. Perhaps I should have used 'readability.'
For the record, I love Rust. It’s an amazing language and my example was not meant to discourage the use of Rust. But, it is verbose and generally takes longer time to write and understand compared to Go. For most projects, Go simply fits the bill for speed of development, ease of use, onboarding new people and performance.
> But, it is verbose and generally takes longer time to write and understand compared to Go.
I respectfully disagree, and I don't think I'm alone in that. I would be willing to bet that the majority of people who have used both languages professionally would agree with me.
Reading or writing N lines of Go is easier and faster than reading or writing N lines of Rust, true. But you have to repeat yourself so much in Go that doing the same thing takes a lot more lines of code than it does in Rust, so reading and understanding a whole program that does something useful is much harder. And that's just reading. Writing is even harder because Go has very few guardrails for protecting against important classes of bugs, so you spend way more time debugging issues that are just not a thing in Rust.
> For most projects, Go simply fits the bill for speed of development, ease of use, onboarding new people and performance.
I disagree about speed of development for the reasons I said above. Ease of use is subjective; I find Rust much easier to use than Go (no exhaustive match on tagged unions in 2024? Really?) As for performance, Rust is hard to beat. So you're left with onboarding new people. Sure, Go is easier to learn than Rust. But it doesn't really make sense to optimize a language for the first 100 hours spent learning it when for most people it's a tool they will use for years.
I agree with you. Go saves a lot of time by having an amazing standard library and tooling... but the tedious writing out of the loops man! I don't even mind `if err != nil` - that's just proper error handling, but writing out loops and maps by hand like a cave man... I can't go back to that.
It's not just Rust that has those, it's every modern language except for Go (because Go is the only one run by "simplicity" ideologues who reflexively refuse to consider adding modern features).
I can’t claim to have been paid to write rust, but I’ve written code professionally for many years now and most of them in Go. I have also written my fair share of rust code for web applications.
The repetition in Go, in my experience, mostly happens at the beginning and then you only have to deal with ‘if err != equal nil’, which to be fair is probably a good thing. Is it really more verbose and repetitive than error handling in rust?
I would love to have the type system rust has in go. It really allows you to be expressive and put in guard rails in a way you can’t using go. But I don’t think most applications need that.
My experience tells me something different than yours, maybe I’m wrong. But I can’t reconcile your arguments with my experience writing rust web applications. Even if I still miss writing my queries using sqlx and my views with asakama.
> Is it really more verbose and repetitive than error handling in rust?
Of course.
if err != nil {
return nil, err
}
is 34 characters in Go, counting a tab as one character. The Rust equivalent,
?
is one character.
But Go verbosity and repetition isn't limited to error handling. Another example is e.g. the lack of any metaprogramming capabilities (e.g. macros) which forces you to either copy and paste code or write a code generator in many cases (or use runtime reflection).
> I would love to have the type system rust has in go.
Unfortunately you will never get it, because Rob Pike's ideology is "if it didn't exist in C, it's too complicated and difficult for Go programmers to understand".
This isn't a joke or exaggeration -- programmers being too stupid to understand modern features has actually been cited as one of the main design constraints of Go.
> But I don’t think most applications need that.
Of course nothing needs it, just like nothing needs function calls (it was possible to write large applications in assembly language). But most applications (including all the ones I've ever written) benefit from it. Rust's type system is there to make it easier to write programs, not to make your life harder.
> My experience tells me something different than yours, maybe I’m wrong.
I wrote Rust professionally for 5 years and Go so far for about 6 months (and even that was not spent full-time on Go). So I don't claim to be an expert. But I am constantly running into things that Go makes difficult or impossible that would be a breeze in Rust.
My list: Mostly fits in my head, gc, not horribly slow, boring concurrency, low effort cross-compilation, good distribution story.
It's contentious but I like the "low abstraction ceiling". Go punishes people who want to turn everything into a framework or abstraction and rewards people who just knuckle down and write the code that solves the actual problem instance.
Is it the "best" programming language on any single axis? Absolutely not. Are the ergonomics right for getting stuff done? Yep, at least for this commenter.
Go is terrible for writing frameworks, because time and time again it picks "simple". Look at generics, people inside google were practically begging Pike to consider adding them, as it would make Go code a lot more flexible, but he held out for years.
It's "simple" if you're just gluing other people's code together, and don't get me wrong, having a single portable artifact run time is amazing, but as someone who's built a KV store engine with Go, you hit the rough edges very quickly.
Even if you do discover a better abstraction, I find Go's tooling makes inevitable refactoring less terrible than other languages. I can easily see where I "broke" code--gopls makes fixing things really easy.
The author here, thanks for posting this. I can see a lot of people not agreeing with Go, that’s fine, I still love writing it everyday. Taking choices away from you in terms of language features enables you to focus on the problem you’re solving. That makes it a great choice to me.
> Taking choices away from you in terms of language features enables you to focus on the problem you’re solving.
As someone that worked with Kotlin for a couple of years, I can agree with this. I actually enjoyed the language but there were so many, I'd say, obscure things or multiple ways you could do the same thing that I'd feel lost sometimes. As someone once said - Kotlin is easy to write, but somewhat hard to read. In the end I just wanted to solve problems and ship my product and I felt the language was getting in my way a lot of the times.
Anyway, in the end I guess it's about personal feeling and conformity with the language of choice.
This is a false dichotomy though. Not wanting to end up as a kitchen-sink language like C doesn't mean that you have to swing completely to the other extreme and refuse to add any modern feature (except possibly after years of fighting), even the ones that exist in every other modern language and have proven to have no real downsides and be hugely useful (like sum types).
There is no false dichotomy in my comment. I'm quite happy using Go. It was easy to pick up, the executables work fast and flawlessly and as a language it delivers the required results in what I do so far. Time will tell, but its simplicity does work great for me, and I've tried quite a lot of languages in the past 2 decades.
Yeah, personal feelings towards a language are a big factor.
I once did a short gig with a start-up that used Kotlin and the CTO was very enthusiastic about Kotlin. He showed all the things you could do in the languages like adding behavior to an integer that would be applied throughout the program. He was excited and I was a little horrified haha. But huge companies have been built using Kotlin so who am I to judge?
I'm in the same boat as you, I want to solve problems and build products.
It's very arrogant to imply that people who prefer other languages don't want to "solve problems and build products".
That's what everyone wants to do. They just think Go is not the best tool for doing it.
Again, you seem to think everyone else is some kind of academic egghead who enjoys other languages because they let them solve intellectual puzzles. That's not true, they prefer other languages because those other languages are better than Go for practical reasons.
Mate, come on. I've implied none of that. Just said that the simplicity of Go tends to shift my focus, at least, to the problem and product, not as much the implementation.
You like Rust and hate Go, that is very clear. But maybe before you call me arrogant and put words in my mouth, read back my comments. I haven't trashed other languages or told people that what they like is shit. Simply that I like Go, and that I don't agree with your arguments.
It's entirely understandable that you have a different opinion from me; I just don't like the implication that "caring about solving problems" makes one appreciate Go, since that is what nearly all professionals care about.
Btw, my opinion isn't just "liking Rust" -- Rust has plenty of problems. My opinion is that Go is uniquely bad among modern programming languages. Most of the major flaws in Go are fixed in every other modern mainstream language, of which Rust is merely one example.
But I'm not saying that. I'm not saying that professionals don't care about solving problems. I'm saying that by removing features from a language you tend to shift your focus more to solving a problem vs _how_ to solve a problem (in language space).
When you have lots of options you always have lots of opinions, just human nature. When working with low-level problems I get how having lots of options is good since you need to be precise. But, most people work on web-related problems. These have most likely been solved in one way or another before. I don't want to discuss in PRs if you should use x/y/z language feature, I don't think that's relevant for a lot of technical solutions.
No, because I'm not the only person writing code. If someone else chooses to use this feature, I will eventually have to interact with it and/or maintain it.
The parts of Go that make the most sense to me are the default static linking and the easy cross-compilation. rust does part of this, but C-dependent crates are easy to introduce (e.g. openssl-sys) and directly cause cross-compilation to be a disaster.
A personal project or small company, no. At small scale the only advantage is has is the concurrency primitives and for that I'd use a BEAM language.
But the verbosity and "one way to do it" is a plus for large enough teams. There's no need to decipher someone else's code when you come in to it. The way they did it is the way you'd do it, because there's just one way to do it.
Verbosity is less important for reading code than writing it, and on big projects you do a lot of reading.
It’s surprising you didn’t mention the most popular language to be invented in the last several years, which while having its own flaws, is superior to Go in all the areas OP listed.
I agree. I am using Java (and other languages) both for my day job and for side projects. Everything just flows smoothly and I don't encounter any frustrations or slow downs that can be attributed to Java the language (or the framework).
Kotlin is also an exciting language that I have started to like, so it could be an option for those who dislike nulls.
Golang frankly seems boring and doesn't have any features I feel is worth switching for. I do understand that others may feel differently and I respect that.
My next side project will probably use a Java backend and a Laravel frontend with HTMX. I'm getting tired of React
i'm at my point in my career (20 years xp) where i think every project should be built around pure functions and structs, sorted in modules. And only once you're sure there absolutely no other choices, add a bit of interfaces, class and inheritance. Which, imho should happen extremely rarely.
I've come to realize that the amount of useless abstractions we add just because the language lets us, instead of thinking more deeply about what exactly is the problem we're facing, is just insane.
Starting a new side gig with Go next month and I’m pretty excited. It’ll be my first big Go project. I’ll be using htmx to handle FE stuff and I’m still discussing with the UX designer (they use Webflow) if we can somehow take htmx into account at design time. MySQL as db (customer’s choice), so let’s see how that stacks up.
It highly depends on the nature of the project. I like Go, but after prototyping my side project in a bunch of lang. ended up using Python (FastAPI, SQLModel) because it was literally order of magnitude less code than say doing same thing in Go.
I bet that just using standard C# and first-party back-end and ORM would have been even less code that works an order of magnitude faster, is easier to deploy and significantly less brittle.
"Go is ripe for Web Development" - not really. See youtube videos by Web Dev Cody or Ben Davis who tried Golang in this context and went back to Ts.
I would say the major strength of Golang is practical community which tends to avoid elegant complexity. The downside is pointers and the lack of null-safety.
What do people use for authentication in Go web applications? To me that’s the big missing piece. Just about everything else is in the standard library.
I wrote my own. I know you're not supposed to do it, but I copied the django implementation as best I could so its probably OK. It's not much work actually.
Exactly, I am looking for a suitable authentication library in go since long time, but I cannot finding anything. Things like authboss are not really usable at all.
The proponents of go seem to have an almost cult-like devotion to simplicity. They think adding any facility for abstraction makes a language into a complicated mess like C , and any type system feature that didn’t exist in C makes a language into an ivory tower academic plaything like Haskell. The way the author talks about spending all day writing a perfectly beautiful, inscrutable piece of Rust code is an example of that. Yes, there are a few things in rust that are a bit harder to understand, but not to such an exaggerated extent, and that strawman is really not the typical experience when writing Rust. It’s very unusual for an experienced user of any mainstream language (except C ) to have any real difficulty understanding what a given piece of code does.