For me personally, those aren't a big of enough of a win. I would rather have simple code that is fast to scale and fast to understand.
Dealing with something like a thundering herd of traffic is much more difficult when your application can take upwards of an entire minute to start up, and to optimize itself to run at decent speeds.
There is likely a sweet spot however. My good experiences with go are working on high scale projects with a handful of other senior level developers. Some other projects I am involved in are with more enterprise shops with many more developers with a wider array of skill levels. In projects like these the other aspects of JVM like how well supported it is and how there is so many other tools for it, it might still win in one of these enterprise environments.
But for many of my use cases, the JVM just feels like it has everything-and-the-kitchen-sink, and sometimes you just want a small, nimble solution that does a few things well.
1. Go's over-fitting to Google's development style, especially the over-reliance on dependencies as source-code.
2. Go's lack of hackability that might bite you down the line when you need something that Go really can't provide. Go's only hack-hook is source-code manipulation (which brings us back to point #1), and at this early a stage we already see too many tools going down that ugly road.
Go is probably the least hackable mainstream language I've encountered. In C/C++ you can always poke around the implementation details when there's no other choice; with Rust there's unsafe; with Java (and other JVM languages) there's full bytecode control; with scripting languages there's metaprogramming. All those "backdoors" should, of course, be used sparingly if not rarely, and then are best done by experts and hidden from sight, but they're always there for when you need them -- and you invariably do for that last 1%.
With Go -- there's absolutely nothing. You can't even drop down to C to muck about because you'll mess up the delicate runtime. So Go is indeed a descendant of C, Java and Python, but neglects to provide the hackable escape hatches from the plain language semantics all of them do.
Those two things scare me (not that I'd give up on deep monitoring or polyglotism otherwise, but still) because not only are they risky, they're exactly the kind of thing that people don't notice when the project is young. I feel like there's a very important lesson here that seriously bit people in the ass that Go failed to learn (well, that and no support for immutability of any kind).
Least hackable is a hard thing to define, but as you've defined it I suppose I agree, albeit in this context it often comes across as a feature to me.
Monkey patches are always monkey patches, and in golang your forced to fork a library to modify how it works. To me this is a good thing. It means that as the codebase evolves, the amount of "hacks" (if you will) are more often than not more clearly defined, and to maintain these hacks its easier to collaborate back and make a pull request, rather than just build up a collection of hacks that have to be maintained separately.
The fact that there is a higher barrier to entry to make these kind of changes, is simply not always a bad thing. Choose your poison, I guess. Golang is all about trade offs. In this case the trade off is its harder to simply add arbitrary code all over the place, but in exchange the culture of golang is more simple.
The only one that actually seems decent is the metaprogramming, which, in my experience, tends to lead to overcomplicated code and worse performance.
All in all, the only times I've ever needed an escape hatch is when I've been writing hacky things, or trying to be too clever. Too much "clever" is bad when programming.
Why are they brittle? They're not brittle at all, they just have looser semantics than the core language. They have their own semantics, which the runtime guarantees to uphold.
> that binary will always run the same... If you aren't testing your code before deployment, that's your fault.
Why work in such a primitive way? We're very familiar with what happens when source-code is overly dependent on a specific compiler version. Besides, dropping to C/assembly in a language with such a high-level runtime (not only a GC but its own global scheduler) is not an escape hatch; it's just using power tools to break through a hatch-free thick wall, which might work if you're careful not to break the foundations by mistake. You could do the same in all languages that do provide an escape hatch, too (if you'd rather break through the wall instead of using the hatch).
> Too much "clever" is bad when programming.
Absolutely, but sometimes just the right amount of clever can let you do truly powerful things that would otherwise be beyond the reach of the language. It's there just for those moments when you're stumped[1].
Experience (and I've been doing this for twenty years) shows that this point where some cleverness is necessary, always arrives at some point in the project's lifetime, and that cleverness often saves you a whole ton of work. Remember, the average codebase lifetime is about 10 years.
[1]: Plus some truly powerful stuff, like the ability to inject tracing code into a running application and then take it out.