> Pre-generics, Go has been a very limited language. On the downside it’s verbose and error-prone, on the upside it’s very uniform.
Except that this kind of uniformity inherently tends to disappear in larger projects, to be replaced by increased complexity. Java was also designed to be a "simple" language, one trivially understandable by hordes of low-skilled code monkeys, and yet look at the added layers of complexity in many Java enterprise frameworks. More full-featured languages, when properly designed (especially, avoiding the feeping creaturitis of something like Scala), make it easier not harder to manage inherent complexity at a larger and larger scale of development. But Go is now basically stuck with its constrained feature set, and Go developers cannot easily avail themselves of these tools. This is why so many devs criticize this particular design goal; it's pretty much incoherent.
In my experience, that happens when people consciously manage the way they use their language, or have the trained instinct to do so unconsciously. At a certain scale choice of language doesn't really influence this all that much (as long as the language isn't Perl I guess, I've never seen that done cleanly.)
I've worked on really neat big Scala codebases and really terrible big Go codebases – a determined developer can make a mess regardless of language, and for some cases it's actually easier to end up in that place with Go than with a more expressive language with a more comprehensive stdlib. Go isn't well-equipped for a number of things, and if you have to do those a lot, generated code and workarounds like the pseudo-sets people build from maps really become liabilities.
From what I've seen as far as complex codebases are concerned, I'd say Go can be very readable for small-ish programs that lend themselves well to Go's opinionated standard library and way of doing things, but I'd definitely want to use something more expressive at scale or for anything that doesn't fit into Go's limitations well.
I couldn't disagree more. Everything I've read in Java was a huge messy pile of spaghetti code. C++ and C can definitely become unreadable very quickly. Rust, on the other hand, I find harder to mess, although there are still lots of ways to do it. And then there's Golang, I've read so much Golang code that I'm surprised when I run into something that isn't readable. Happened to me once, obviously the code had been written by Java developers (factories lol)
> when properly designed (especially, avoiding the feeping creaturitis of something like Scala)
What I find interesting here is that Scala has the reputation of being a complex language, while its syntax and grammar are among the simplest and most straightforward there is: https://images.app.goo.gl/K1NTGUP4G9T6wfY48
I believe that this is what "scalable" means in the eyes of its creator: it offers very powerful abstractions to be adequate for mundane tasks (e.g. file-level scripting) up to complex systems and problem spaces.
Yes, as a consequence, people have created libraries and codebases with Scala that are inadequately complex and abstract for the problem at hand, but that's not something one should blame on the language but on the project/company culture. Same is true for any language: C++ templates can be abused in ludicrous ways, some of Java's design patterns make you wish inheritance would be forbidden, python's module imports potentially overwriting globals and other footguns.
No language can be dumbed-down so much that the resulting codebase becomes immune to some amount of "abstraction management", not go, not even python. Once this is understood and accepted, it becomes obvious that it's not worthy to castrate a language on the basis of "simplicity", because eventually this complexity will be warranted at a point in the future or for some aspect of the project.
I think the go designers did the right thing here, I don't think this will bring dramatic changes in how the language is used, and will actually help with "managing abstraction" where it's due.
Java code got complex after adding generics, not before. In a big Go codebase, even if it’s complex, the styling and patterns are the same, so it’s easier to follow. That might change to some degree with the addition of generics.
That's not true. Java was notorious for AbstractFactoryProducerArtifactFactory and awful inheritance-based patterns long before that.
You can't dumb down a language and expect the complexity of the problem space to go away (developers will have to cope with it one way or another), and you can't expect the programming language alone to be the sole judge of what's an acceptable level of abstraction (or architects would have been made redundant by now).
Except that this kind of uniformity inherently tends to disappear in larger projects, to be replaced by increased complexity. Java was also designed to be a "simple" language, one trivially understandable by hordes of low-skilled code monkeys, and yet look at the added layers of complexity in many Java enterprise frameworks. More full-featured languages, when properly designed (especially, avoiding the feeping creaturitis of something like Scala), make it easier not harder to manage inherent complexity at a larger and larger scale of development. But Go is now basically stuck with its constrained feature set, and Go developers cannot easily avail themselves of these tools. This is why so many devs criticize this particular design goal; it's pretty much incoherent.