I'd say Go is opinionatedly inelegant. It is minimal, I'll give you that, but has several non-orthogonal design decisions, smells, etc.
[1] - https://www.teamten.com/lawrence/writings/why-i-dont-like-go...
How is "being opinionated" and "making clear promises and delivering on them" equivalent?
I would not want to use Go for any codebase that's expected to last more than a couple of years. I'd put a lot more faith in languages that were able to adapt elegantly to the challenges of concurrency at the library level, without requiring language changes - that suggests those languages will be able to adapt similarly to the next revolution. And my impression is that languages that started with a solid theoretical underpinning, and/or a small core language with as much as possible pushed out into libraries, handled the transition a lot better than languages with the more ad-hoc, practical-problem-first approach to design that Go has.
> Go has been carefully designed to solve the problems of today.
I'd even argue it was "carefully designed" to be in the 70's. Other than "goroutines", the language is stuck in that decade. No generics, no expression based syntax, exposing system-dependent "int" type and encouraging its use, badly designed interfaces that can't be used for tagging, badly designed time package, the list is too long to mention here.
I say this as one who has basically mastered Haskell, so it's not like I'm not aware of all these things: Fans of all these complicated abstractions really need to take some time and grapple with that fact. It will improve your programming in the more complicated languages as well.
No, seriously. Stop for a moment and think about that. Consider the advanced features as a scientific prediction: "If you do not use these features, you can't have a good program come out the other end." This prediction is falsified by the concrete existence of a lot of good Go programs. This matters. It is something that should be grappled with intellectually, if you are a language fan.
It will bring you to a deeper understanding of all the fancy features. By a deeper understanding, I mean that quite directly, with no attempt to be subtly saying something like "Oh, you'll find they're all useless in the end." That would not be true. They are not even remotely useless. They are incredibly useful. I would even go so far as to say that the development of these complicated sorts of features is legitimately among some of the most simultaneously interesting and useful intellectual work being done in our time, and greatly contributing to our ability to hold our software world together. It's just that the shape of that usefulness is more complicated than a lot of people realize, and a deeper understanding of that complication is very useful for developers.
One of the things that I think really comes out of it is a yet deeper understanding of matching tools to problems. I use a lot of Go, because I write a lot of things that are at a size and complexity where those other language features just aren't that helpful. Yet, there are tasks I could be assigned where I wouldn't dream of using Go, because I know I would need all that fancy stuff to hold the program together. I can easily imagine ways in which my career trajectory would change in the next couple of years and I'd go primarily Rust; I can equally easily imagine ways in which I will stay primarily Go. I can imagine ways in which I'd need to go with some other language. I think a lot of programmers who find these fancy features and fall in love with them end up overestimating the scope of the set of programs where they can be helpful. To give a degenerate example, my six line shell script does not need to be written in the Rust type system. It is not only not helpful, it would be actively harmful. The scope of programs that don't really need those features and where they quite easily become actively harmful is larger than a lot of people think. Especially if you consider them in the context of a heterogeneous team of developers who may not all be in the 5+ years of experience range, or when you may not be able to guarantee that the project is going to stay in those hands.
I didn't mention anything about fancy features such as the likes of what Haskell and gang bring. I'm referring to much more "basic" things like generics, good error handling, non-nullable by default pointers, and so on. Things that one has come to expect in a modern language (which golang isn't in general).
Having the ability to provide abstractions does not mean must use them to write software, but that they are available when required, and when used correctly, they end up simplifying the overall system architecture. I think the world has moved on from writing abstractions for the sake of writing abstractions, and I agree that it's not the way to go if such code is still being written. But the solution is not to get rid of the ability completely, resulting in a different sort of mess. At least we have tools that make navigating large code bases easier.
I feel it's actually golang people end up reinventing things differently just for the sake of writing things differently. Take the builder pattern for instance. For some reason, golang code I see uses a different, more convoluted pattern of passing an options struct that gets returned in a closure to emulate that. It's a bigger mess to understand, and probably ends up generating more work for the GC since closures keep getting allocated.
I'd claim that programs built without those features have a ceiling on how complex a problem they can solve before maintainability collapses under its own weight. Go is popular for microservices, which makes a certain amount of sense (if you believe that microservices are an effective way of doing systems architecture - I don't, but I can see why people would). I've yet to see a Go system that I found genuinely impressive/innovative in terms of the functionality it provided.
> To give a degenerate example, my six line shell script does not need to be written in the Rust type system. It is not only not helpful, it would be actively harmful. The scope of programs that don't really need those features and where they quite easily become actively harmful is larger than a lot of people think.
Disagree. In my experience a significant proportion of production incidents happen because a six line shell script gets modified incorrectly, or does not handle an unexpected condition properly.
I've seen plenty of ineffective solving of business problems in e.g. Haskell, which I think boils down to a failure to appreciate how low the reliability requirements actually are in most businesses (exacerbated because many organisations are dishonest with themselves about such things, even in internal communications). I do think that someone who knows the advanced features but is willing to write "YOLO Haskell" (or similar language) will be more effective at solving business problems and creating value than someone using Go or similar (and at this point I've built my career on the effectiveness of fancier languages, even for 6-line-script-like tasks).
"My" six-line shell script isn't on production. It's something I wrote to rearrange my mp3 collection, or whatever. Then I deleted it.
My personal threshold for leaving shell is quite low. We may make fun of Perl, but it's really a lot, lot better than shell for any serious task. It's even lower for "production" tasks.
But whipping out the Rust because I want a shell script to increase the brightness of my screen through the /proc file system is massive overkill. I can write the thing in the amount of time it takes you to compile the Rust, and I'm not particularly trying to make fun of Rust here... it's just massive overkill.
Which is fine unless it deletes your mp3s, or dumps them all in the same folder, or something. A script inherently has the potential to do a lot of damage, because it can take a lot of actions very quickly. So it's worth being safe even if that means being a little slower.
> But whipping out the Rust because I want a shell script to increase the brightness of my screen through the /proc file system is massive overkill. I can write the thing in the amount of time it takes you to compile the Rust, and I'm not particularly trying to make fun of Rust here...
If your point is that a REPL or shell is a worthwhile feature then I agree with that. But you can have that in a safe language too.
It still runs today. I have Haskell and Python programs that are somewhat smaller from around the same time that no longer run.
More importantly, I can go into my source code and I can still understand it. I can't say the same for the Haskell and Python programs.
I wonder which is more maintainable in the long term.
You can find old C programs that compile and run fine now, so I don't really see the point of your argument.
No generics suck, unfortunately. I don't care that most things aren't expressions, and tbh, I don't know a lot of people that do. System-depdendent int is not a problem for me, but I recognize that it is a problem in some fields. I like how interfaces are designed and used in the language, so I don't share your opinion there. For the time package, the only thing that's badly designed is the American-centric parsing system. Everything else is, for me, ahead of the various package I've used in other languages.
This is why i'm sad that Rust has baked async/await into the language. Somewhere in the RFCs, it is stated that "async/await is now known to be the right way to do concurrency" or something like that, but to me it is clear that it is at least a decade too soon to say that.
Afaik only Go and Erlang currently meet (at least my) criteria. No JVM solution currently does.
Note that just because the recent tutorials out there mention Spring Boot, doesn't mean you can't wire together a Spring app either through config files or programatically.
What it is though is something that solves problems and has a great ecosystem, instead of reinventing the wheel.
I like Go for some things, but when using it I miss many things from Java:
* I can connect to the running JVM and change log levels, and other parameters live.
* I can debug a Java file that has compilation errors in it and fix them as I go in some cases. (In Go you can't even compile a file with an unused import)
* Java libraries and frameworks are mature. Some have been around for decades with all the testing and refinement that implies.
For some applications, like a REST server connecting to a database, why would I use Go and use all it's brand new, limited libraries when I could use dropwizard instead and get an easy to deploy JAR file?
Sure Java has some esoteric features, but you don't have to use them.
If you can't keep your team from being clever in Java, I doubt you'll be able to do so just because they use Go.
I've seen many Go libraries attempt to use introspection and backtick 'annotations' to very confusing and buggy effect.
I personally dislike Go, precisely for many of the reasons why those "people who are sick of programming languages" would like it!
I'm in that age of folks that did pascal in high school, C and Scheme in college, C++ and python in grad school while futzing around with ocaml and common lisp and sather and other fun things. Programming languages are fun.
But, oh, I have so much other stuff to pay attention to. I write C++ a few days a week, which is barely enough to keep move semantics in my head. I also write SQL and analysis docs and internal DSLs and configuration files and python.
At this point, C++ is barely earning its keep, in terms of mental complexity for reward. Go feels a lot nicer, since I can just get in, do my thing, get out, and it'll at least work and give me a compile error if one of the APIs change when I don't look at it for a year.
I'm not about to jump into rust.
So, at least for me, go hits a pretty good sweet spot.
[Edit: I'm not trying to point fingers at rust in particular. It looks fun. If I weren't still working on getting my hobbyist-Haskell better, I'd probably be playing with it. But that would be at home, for fun, not where I have to have the thing in my head for production issues.
It reminds me a bit of the old statement about perl, that it was a fantastic language if you used it every day, but not if you don't. And I don't get to use these things every day any more.]