If you’re a Java dev, and you try to force Java-isms into Go, you’re gonna have a bad time.
The Go philosophy http://go-proverbs.github.io/ pays off less in the short term, within a single file, or a single stdlib function, or with syntactic sugar to code golf 3 lines into 1 - it pays off in the long term, across time and people - and this makes all the difference
I've found that often people who have been deep in the JVM ecosystem really struggle to enjoy Go, and vice versa.
It's like the JVM ecosystem commits deeply to the complete opposite of idiomatic Go, and once you've built those neural pathways, it's hard to unlearn it all.
I spent around 15 years doing Java exclusively, and after discovering Go (around 2012) I couldn't wait to adopt it and have never looked back since. I don't think Go is perfect, but I find it a much better default pick for most things I've worked on compared to Java. Of course Go has limitations, especially in the type system and error handling, but rather than go back to Java for those cases where it matters most to me, I tend to choose Rust these days. It shares some of the advantages of Java (compared to Go) and also comes with its own set of other major advantages too.
I hate Java just as much, but at least it’s trying to improve and grow beyond its past limitations, instead of promoting bad design decisions as good for the programmer.
I have worked with many languages - from Java, Delphi, C/C++, Assembly, PHP, Go, Rust etc. I don't really understand the hatred for Java. The build system in Java is not complicated .. whether Gradle, Maven or whatever unless your requirements are very complicated (multiple builds etc).
In my opinion the most complicated system out there is Javascript and all of the myriad tools needed to support that ecosystem. It has approached the complexity of C++ and perhaps even exceeded it
I'm a committed Kotlin shill and a very experienced Gradle user but I'm the first to admit that it is absolutely arcane for those new to it. Once you know all the incantations it's really flexible and performant but good luck writing a plugin for the first time.
My favorite thing about gradle is that the build file is written in the same language as your code. This gives you the great power of easily adding a little hack into your build file, so it's pretty rare you actually have to make a plugin.
The downside is that every build file is a little bit unique, but IME it's not that much worse than what happens in golang. In golang people usually slap a makefile on top of the go commands, and then you have to read the makefile to figure out what targets you need to run, and if it gets a little complicated then they start calling out to shell scripts and things like that. ech.
Very interesting. Bulk of my career has been writing Kotlin/Java and after a year of Go I am _still_ really struggling. Nice to know I'm not alone!
I see the benefits (I've have seen some absolute Java ee monstrosities that would be impossible to build in Go) but why am I getting paged at 3am because someone forgot to set a field on a struct. Similarly all the codegen to workaround the lack of inheritance - who cares how fast the compiler is if you've got to do 30s of codegen on top.
That's a culture issue, not a language issue. And no, the language doesn't attract these type of people, but rather language is so good that it is prevalent in domains that hire those people.
A distinction that belongs in a dictionary perhaps. To a programmer the ecosystem and the language are one and the same. One cannot rewrite every piece of code out there to suit their fancy.
That's not good, it means the language is effectively two languages now and you do not know what to expect when you open a supposedly "Java" codebase.
If you've known Java for years from the Spring POV and the codebase in written in the "modern" style, you're lost in the woods now.
Worse yet, choosing between the two styles is now a decision that every single project and company needs to make. Endless, pointless bikeshedding akin to which code formatting is to be used or Maven vs Gradle.
Such decisions should be made higher up, at the language design/culture level. It should be obvious which options are the correct ones by just looking at the feature set of the language, the ecosystem of code already written in it, the style guides, etc. If changes are needed, the few language creators should bless a single way forward and push for the ecosystem to all move to it instead of deferring the decision to the millions of users of the language.
Are you sure there such an entity as "the JVM ecosystem"? What is the common thread you can run through Kotlin Android jockeys, Clojure scientists, and Enterprise Fizzbuzz Java 11 types?
Yes who needs generics and a proper error handling system.
When you can have Go where the boilerplate is so bad you literally have to rely on generating source code files in order to maintain a sane level of productivity.
I use idiomatic Go every day and it's like being back in the 90s.
In our entire codebase, Go's generics have been used, like, 3 times, even though they were introduced almost 3 years ago. It's unsurprising: generics are most useful for writing your own custom containers, and generally, most projects don't need their own custom containers. It felt somewhat anticlimactic, considering all the anticipation.
You often don’t need custom containers, but you need containers! I shouldn’t have to write my own custom method to map or for each over a list of items, etc.
Its generics aren't as advanced as Java's or any other language with generics for that matter. Plus most things are now only adding support for generics, so there's a fragmented ecosystem of code before and after generics were introduced.
Try writing Go without generics. No typed maps, arrays, slices, channels or function types. Only `interface{}`. Go always had generics, you just weren’t allowed to write your own until recently.
I don't know about other people's experience, but from mine, I see a lot (most) devs abstracting too early in the name of clean code. I guess engineers gonna engineer when simple boring repetition is sufficient and those premature abstraction are unnecessary.
Yea lets build a whole docker setup for this little Sudoku app that never will have more than 100 users. I mean, for fun overengineering small projects can be a great learning experience but for work? Keep it simple, stupid.
(In case it wasn't clear, im agreeing with your point and just giving some example)
> lets build a whole docker setup for this little Sudoku app that never will have more than 100 users.
Looks good on the CV though and managers who hire-by-cv-not-sense love that kind of thing. You'd be amazed at how many interviews I've failed by pointing out that following the latest trends and over-engineering isn't always a good plan.
Also means there's a constant supply of work for contractors who can unpick that kind of gibberish back into reliable systems which is nice.
But do you really want to work at a company with managers that have zero technical experience? To me it always has been extremely annoying working with people that can't imagine the magnitude of work, that some "small" changes come with.
My current boss and company owner is also a programmer and its far easier and good for my nerves. He just doesnt have the time to code anymore.
If I had a penny for every time I try to dissuade a dev from busing a huge k8s system for a business that does not have a single user yet - I would have a bunch of pennies
I work for a Kubernetes Certified Service Provider and I dissuade people as well, it's so anti-climatic when embarking on a k8s journey and then having more pods which are overhead than the actual customer pods.
Yeah but what does simple mean? I struggle with that a lot. In my experience, keeping it simple means not being flexible when requirements change. Adding new features becomes tedious or even a mess. Keeping things simple is an art, certainly not an easy one.
Its extremely easy. Just dont overthink, implement the stuff you gotta implement and move on. Simplicity generates flexibility. Its also easier to refactor if your app isnt a architectural docker mess.
Boring repetition is a bad fit for the human brain. Working memory is very small. Mistakes per line are frequent. It wants to see patterns that are not quite there. Even when it works out, it's millions of times slower than having the computer fill in grunt work from a more concise and readable spec of the problem.
Go is at a weird place where the standard library is big that third party libraries aren't really required but not that big that it can do everything. So like OP says there is a huge thing with Go projects (and devs) about reinventing the wheel for each project. While sometimes this is fine (and even welcome because it offers you flexibility and customization), it is mostly really slowing down someone who wants to write a full-featured application with auth/ORM/web security etc.
You either have to write your own or try to use something that is actually really behind from what you're used to. And coming from a Python, all batteries-included ecosystem it's actually nuts. Our small team would have to dedicate a huge chunk of dev cycles to write our own plumbing. Dev cycles that we could have used writing business logic that actually made us money instead of writing yet another auth.
But having said that, I don't think Go is the language to write these kinds of apps in. So if you're trying to use Go to do that, you're obviously going to run into roadblocks. It's like trying to cut through metal with a pair of gardening shears. Can it be done? Yes. Can I choose the size and design of the shears? Yes. Can I modify or create my own shears? Yes. But is it the most efficient or appropriate tool for the job? Probably not.
IMO Go is ideal for server/CLI applications or even for web apps that interact with other services completely behind your network. But for most other things you're better using something else. Or you use it if your customer really wants to use Go and wants to pay you.
Go is like a tool used to build the plumbing and internal systems of your house, but not the house itself. Using Go is similar to casting and forging your own water pipes. Some people enjoy getting into the details of crafting those pipes, but most of us just want to install them and focus on the rest of the construction.
> Go is like a tool used to build the plumbing and internal systems of your house, but not the house itself. Using Go is similar to casting and forging your own water pipes. Some people enjoy getting into the details of crafting those pipes, but most of us just want to install them and focus on the rest of the construction.
It actually gives me the house, it just doesn't do decoration. I hate doing decoration anyway. Other languages + their frameworks usually force me to care about that.
Plenty of people who love meat go to vegan restaurants, because they serve good food but without meat in the dishes. I have a bunch of language features I like but still use and enjoy languages that don’t have them because they’re still good at other things.
Go is kind of like a vegan restaurant that offers you iceberg lettuce and cherry tomatoes as the main course. It’s just not very good.
It's more like an aggro soylent of programming languages. It's functionally equivalent to other food intake products, but it will only ever have one flavor, and if you complain about it, they just tell you to drink more soylent because soylent is the One True Solution.
Now contrast that to rust, where rust is more "We know you like python, but did you know python and rust taste even better together?"
> The biggest challenges faced were most definitely not related to the choice of programming languages, but after cursing and fighting with Go’s mechanics and philosophy for years, I’m ready to throw in the towel.
I think that is the problem right there. Instead of cursing and fighting, you could have tried to understand, embrace, and adapt.
My opinion is that Go has the same problems as UNIX:
- Reactionary in the face of Multics' (resp. Java/C#) complexity, but overshooting to the point of "worse is better".
- Basically confusing "no complexity" with punting of said complexity to users who will solve it in multiple horrible and/or incompatible ways; like a badly designed R5RS Scheme.
- Some decent ideas but poorly and non-uniformly implemented compared to Plan 9 (whatever will fix Go).
Which is quite logical, knowing who made both of these...
I don't know enough about Java to comment on that switch (as modern Java seems to have gotten a lot of cool stuff like pattern matching and https://openjdk.org/jeps/485) BUT Java's runtime (which also powers Clojure and Scala) is evolving at an impressive rate compared to Go's: especially GraalVM and generational ZGC.
My personal experience of moving to using Go, along with building a small team using the language, all of us basically Java Devs, was that it was perfectly fine to go from Java to Go.
Code structure and package management were slightly sticky but getting a decent starting point on development was pretty trivial. Build, test and deploy were easy. A lot of style questions got answered by go fmt, vet and eventually golangci-lint.
I recognise some of the discussions but in all honesty we just tried to be consistent in our choices. Similarly, I recognise the complaint about dead 3rd party libs but I've seen that plenty in Java too, just some of the big hitters in Java are incredibly well maintained - Spring, Hibernate etc but in 20 years of Java I've been stung plenty by unmaintained libs too.
Go for us was quick to get started and proficient and whilst it's certainly not perfect a lot of the comment in the article appear to be more to do with team discussions than language choices. I've certainly had similar discussions on teams about Java and how to approach things.
Anyway, no longer in that team and now in one who's main language is Python, happy to use any of Python, Java or Go and for more than just system programming but really most sorts of problem spaces.
Of the 3 Go would be my default as it just works for me and love the build/test speed and even like the explicit error handling.
I have to agree with author. I don't see what people like about golang. It seems like people use it because it is cool but after a while people realize they are less productive with it.
Go is not cool, it's boring and readable. I don't need a diagram to understand what the code is doing compared to Java. I say that with deep respect for the JVM and all the problems that are solved with it. It's an incredible ecosystem.
I'm productive in Go because I realise most of my time isn't spent typing, it's thinking. I shy away from over abstraction and lean heavily towards composition.
If you're solving a problem that requires complicated type system - don't use Go. If you're writing a UI - don't use Go. If you like 20 layers of abstraction - don't use Go.
If you're writing a product like I am, with similar constraints, then Go is an excellent fit.
People for some reason like to pretend everyone is working on the same problem that they are, and have the same requirements they do.
This person doesn't like Go, and that's fine. I have no doubt I'd be able to solve their problem in Go, and I have no doubt they'd be able to solve my problem in Java.
Thats fair! I just don't agree with the readable part and thinking. I personally get tired having to look at all the archaic boilerplate to find the actual logic that I want to reason about.
I won't disagree with that. At the same time, I loathe code where I cannot comprehend what's going on unless I'm an expert in the syntax and esoteric language features. I spend more time looking at other people's code than my own.
Go's advantage here is that everyone's code has a much higher similarity score than other languages, both in syntax and semantics
Go was written primarily for software engineering over implementing programming language research ideas. It's more than the language, it's also the tooling, automation, and simplicity around it.
Having a standard formatter certainly helps. But not having rich modern features built-in means more custom/non-standard code, not less, that you have to read.
I haven’t used go in a few years so not familiar with how it’s improved. But not having basic container functions like ‘map’ was absolutely bonkers.
Go code just keep working with minimal maintenance. The last major maintenance that was required was the addition of go.mod, and for the most part of your project was using one of the community modules systems is was a completely automated maintenance.
Go has the least maintenance of any language I’ve used(or had to maintain), save some C/Cpp projects that target libraries with essential frozen APIs.
That doesn’t mean you don’t get to keep things up to date; go wants you to run the oldest possibly written go code with the newest go compiler tool chain w/ no effort. Just upgrade go and run your 10yo code probably without any changes needed.
I still like Go, but I never cared much about the language itself. If you do things the way they want you to do them, it works fine.
I learned go on release for the full featured devtool in the `go` executable, the ease of building and deploying a single executable, and the relatively good speed.
Many more languages have good toolchain and deployment stories now, so I reach for go much less often as a result.
Im going to go out a limb here and say: if you’re going to respond to this with “lol Java” or “but you’ll like go if you try it for long enough”, you’re doing yourself and your community a disservice.
Responding to detailed critique with trite offhand dismissal just comes off as a massive Kool Aid Drinker. Don’t be that guy!
Anyway, here my take!
Go! It is beyond frustrating that the core team has walked back on a number of stubborn decision that they were wrong about and that they appear to have made in a stubborn opinionated way based on good intentions and a deep failure to listen to people who really do know what they’re talking about.
…until it becomes overwhelming apparent that they were wrong; buuut, I still use it, and I don’t dislike it that much and maybe taking a long time to get to a good position isn’t a bad thing?
It is frustrating; but what do you want? There’s a good package system now. Some of the missing tools are there now. Generics. That’s good right? Why is that a bad thing?
Frustrating? Ok. But bad? Bad enough to not use go?
How is having good things now a reason not to use them?
Also, when you look at other kitchen-sync languages that are eager to embrace new things, there’s a bloated complexity that comes with it. That’s also frustrating and draining.
You can’t have everything.
A lot of people use go and it’s fine.
If you’re building a big complicated ERP system, maybe Java is a better choice for you. It’s a good choice for some people. Java is also a great programming language and it has a massive, excellent third party ecosystem.
…
If go makes you sad, don’t use it.
Some of the critique is probably fair, but it’s still a great language with an excellent set of tools around it (not debugging, or c ffi, but static binaries and cross compiling :)
The critique of the “go way” and the go core team is probably unfair; it can feel frustrating. I get frustrated. …but you get a pile of shiny crap when you design by committee. These people are doing a lot of work and it’s going… pretty ok, I think?
It will take some time because there is a lot of work to be done for C# language features.
I think they are partially overrated because 1. C#'s type system is quite expressive already and 2. C# has excellent pattern-matching support. Sure, union type definition is a nicer experience in F#, but outside of it there are surprisingly few differences in terms of user experience.
Coming from the Haskell world, I sorely miss the speed of nailing a precise and elegant data model with sum types.
Exhaustiveness checks are a big one for me. For each default case I wish that my type checker would be smarter. I know that records can have multiple constructors, but it escapes my why we cannot seal those records so exhaustiveness checks are free.
A default case is somewhat like a final block for an exception, whereas I want compile time cursing.
F# Sums are indeed nicer (also tons better syntax than Typescript uses).
I would argue JVM right now is by far the best platform.
Virtual Threads is making its way through the ecosystem and Scala is serving as the R&D platform demonstrating how cutting edge features can be implemented e.g.
It is strictly not cutting edge. Maybe it would have been about 10 years ago. The tooling is nowhere near as productive and the language selection leaves a lot to be desired.
.NET as a platform has far superior implementation of asynchronous and concurrency primitives both performance and UX-wise, and there are more performance wins down the line too.
This site is obsolete/irrelevant, it is best to ignore Miguel de Icaza's criticism of .NET as of the last 3 or so years. He went off to (supposedly?) greener pastures of Swift in Apple lands. Take from that what you will.
This is a good quality because it means that the language is very conservative in features. The authors quite deliberately chose to keep a minimal featureset, which is shockingly difficult to do in practice. Languages that cram every feature under the sun are behemoths that are difficult to develop and, more importantly, use. Any experienced programmer can read the Go language spec in an afternoon, and be proficient with it in a week. You can't say the same about most other languages.
Those missing "bare essentials" like maps, filters and contains are just syntactic sugar, and hardly essential. I've worked with Go for nearly a decade now, and have never heard of samber/lo, nor needed it. This mentality that developers need helper functions for every task is what leads to ridiculous ecosystems of micro-libraries that are popular in the JS world, which is a huge supply chain security risk.
I mean, take a look at this example from samber/lo:
How is this better than a standard for loop with `append`? One uses standard language features and is obvious to anyone reading it, and the other depends on an external library and everyone being familiar with it to understand. If I saw this code in the real world I would strongly vouch for removing it.
To be honest, I'm _not_ a fan of such helper functionality creeping into the language. I'm not a fan of generics either, and I'm not sure they're a net benefit to the language.
> In Go, there's only one way to do things. [...] this part of Go’s boringness is just untrue.
This is untrue is most other languages as well, but at least Go authors strive to stick to this as much as possible. Whereas this is not even a core principle of other languages, or they even encourage the opposite. If we agree that TIMTOWTDI is a mistake, then the best we can do is to consciously reject it. How well this succeeds in practice is debatable because it is a very hard design problem.
I have many more fundamental disagreements with the author, but can't be bothered to address each one. To me Go is a breath of fresh air in a sea of broken languages and ecosystems. It's far from perfect, of course, but it's many times more enjoyable to use than anything else I've come across in the last ~20 years, most notably Python, JavaScript and Java.
the author also complains that There is only one way to loop (for). that seemed odd to me. i thought is go really that limited? for loops used to be the bane of programming. that can't be true, and it isn't.
it just happens that things like while or foreach or however they are called in your favorite language are all done with the same for keyword. is that bad? i don't know.
as for map/reduce, in most languages that i am familiar with those are functions. and nothing prevents go to have these functions too. if they are not in the standard library, add them. there are multiple implementations available. eventually one will make it into the standard library.
while-loops are also seldom used in Java code. At least from my observations. For-each and stream functions have deprecated for/while in modern Java code.
As a Java dev, I love Go by the way. Recently adopted it and I find it anything but boring.
agreed, i use while very rarely in any language. iterating lists is really the main use of looping, so some form of for-each is my preferred tool. even when a traditional for loop is better, my first instinct is to try for-each first. it's a pity that javascript's forEach is so awkward to use, needing a callback. i remember when pike's foreach was extended from only handling arrays to also supporting mappings and anything else iterable, it felt like a massive improvement. go's for/range syntax is a bit different, but it does the job. i could not ask for anything more.
Actually Go is great to read. And as we know it’s more important for a language to be readable than writable, since that’s where most of your dev time is usually spent. https://news.ycombinator.com/item?id=19542574
I don't like these category of articles that put the name of a language into its title if the article is in fact not about the language itself but its entire ecosystem. So this one. It's mashing up things that should be kept/viewed/discussed separate.
What is more, as with any (formal) language, the test of time doesn't show how "good" a language is. It shows how a language and the entire ecosystem around is able to adapt to current needs. In other words, whether a "language organism" is "good" or "bad" is subject to personal preferences/opinions. Whether a "language organism" survives the test of time shows how viable the entire organism is. It's the same evolutionary process as in nature.
The Go philosophy http://go-proverbs.github.io/ pays off less in the short term, within a single file, or a single stdlib function, or with syntactic sugar to code golf 3 lines into 1 - it pays off in the long term, across time and people - and this makes all the difference