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.
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.
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.
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...
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.
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 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.
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.
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.
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.
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
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.
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.
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.
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.
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.
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.
This horse has been long flogged to death.
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.
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.
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.
> For example, in a language without generics, if you have 10 different versions of the same function that only differ by a type parameter,
Can you give an example of why you would need to do this? I use go everyday and have never had multiple copies of the same function as described here.
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.
Wouldn’t you just use sort.Slice?
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.
Sorting using generics is faster and more ergonomic. That's why they are adding generic based sort to the standard library.
https://pkg.go.dev/golang.org/x/exp/slices#Sort
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...
I'm not exactly sure what your second point is.
But go isn’t a language without generics, so I don’t understand the criticism
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.
Go is the epitome of "different people have different tastes."
I completely understand why Go is designed as it is now. I can see the principles and crafts behind it.
But I just can't bring myself to like it.
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 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.
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.
Haha that's fair! I do miss Rust semantics with .map(), .filter() and chaining them together.
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.
Thanks for writing this up.
> 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.
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.
[dead]
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.
go has excessive verbosity, poor error handling, rough edges for package/dependency management, and forces you to use interface for too many things.
it’s not a bad language, but i would not choose it for a new project or base my company around it
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.
I'm really curious, which language is better than Go in those regards?
Because I find Go is better than Javascript/Typescript, Java, Python, C++, C# on all of those.
C# runs circles around Go, imho.
What is it you find better in Go?
Go is limited. There are too many ways people in my company can fuck up C# code, it's much harder to spend time moving around letters with Golang.
Sure, that's a risk.
But force feeding everyone Go is worse.
Code reviews would be a more constructive approach to the same goal.
I can't code review every one of 150 devs under me. I can't depend on heroes saving the day. Heroes go do their own thing eventually.
if you think you need to code review for 150 people or your code base will get out of control then it sounds like there’s bigger problems going on
No, I don't think so - because I chose tools like Golang that do the job for me.
Most people would regards Standard ML as having some very sophisticated ideas in this regard.
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.
java and c# are great choices
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
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.
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.
You would probably like this talk by Andrew Kelley https://youtu.be/IroPQ150F6c?si=riT9hL3S2R7KXIWv
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.
I am sure C# is great not sure about less code part
They really committed an original sin by omitting generics in early versions of Go, it was added in more recent versions, but too late IMO.
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.
Not a library, but you can use Lucia auth (https://lucia-auth.com/) as a guide to make an auth system yourself
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.
Depends on your needs but Zitadel can do that for you.
We also have a good oidc library that helps you plug into systems that support open id connect.
Check authboss, casbin and casdoor.
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.
All of these points apply to modern dotnet as well
What exactly does Go have over C# other than being “sexy” and an emphasis on minimalism?
I’ve watched from the sidelines over the years. I hear more people talk about it than use it.
Minimalism is the biggest selling point, if you are comparing it to C#.
If you don't see a lot of people using it, maybe you're looking in the wrong place? I work with platforms, and Go is everywhere.
What do you mean by platforms?
Platform engineering. Think toolchains, devops, cloud, infrastructure...
[dead]
"because you want to work for Google" /s