As someone without a ton of experience with Go, a good amount the Go code I have encountered "in the wild", has actually been more difficult to read and understand than code in more complicated languages because I have to read through and understand all of these patterns. Hopefully the addition of generics will help with that. But IMO the simplicity of go actually hinders readability.
My personal experience is very different. Of course I have seen bad Go code in the ~5 years I do Go development professionally.
But when compared to previous monstrosities in C++ or Java with exceptions cluttered everywhere, deep inheritance trees that are absolutely useless..
then Go code is an absolute breeze to read and work with. The one thing I see frequently and dislike a lot in Go code bases is the frequent usage of interfaces for single structs just for the sake of mocking for unit tests.
Often I see cases where you could just strip the whole layer of crap and unit test the real functions themselves. But nobody seems to think about that. It seems that this "write interfaces for everything and then mock/test this" pattern is dominating currently.
> But when compared to previous monstrosities in C++ or Java
Perhaps part of it is the languages we are comparing to? I'm comparing to languages such as rust and scala, and to some extent python and ruby.
> with exceptions cluttered everywhere
I prefer errors to be part of the return value to exceptions, but I also find repeating
if err != nil {
return nil, err
}
for almost every line of significant code in go functions pretty distracting. I much prefer rust's `?` operator. Or haskell's do notation (or scala's roughly equivalent for/yield).
> deep inheritance trees that are absolutely useless.
uh, you can have deep inheritance trees in Go, and not have them in Java or C++, I'm not sure what your point is.
> Perhaps part of it is the languages we are comparing to? I'm comparing to languages such as rust and scala, and to some extent python and ruby.
I think you should compare to languages that have a similar purpose / area of usage. In my experience that is C++ and mostly Java. I wouldn't dare compare dynamically typed and interpreted languages with Go.. what's the point? I don't have much experience with Rust so I cannot compare it and additionally it's rarely used in companies. Scala I just don't like personally. For my taste it just "is too much of everything".
> ... err != nil ...
In the beginning I was thinking the same. Over time I got used to it. When I write it I use a snippet. And clearly reading the flow of the error has been beneficial to me a lot of times. Yes it is verbose.
> uh, you can have deep inheritance trees in Go, and not have them in Java or C++, I'm not sure what your point is.
I am sure you know that there is no inheritance in Go so I am not totally sure what you are getting at. My point is that I think OOP by composition is a lot clearer than by inheritance. Also composition is not overused in Go as say inheritance is overused in Java.
> I think you should compare to languages that have a similar purpose / area of usage. In my experience that is C++ and mostly Java.
The languages I listed first were rust and scala, which serve very similar purposes to c++ and java. In fact, rust is closer to c++ (no GC, more direct memory control) and scala is closer to java (runs on JVM) than go is to either.
> Over time I got used to it. When I write it I use a snippet.
Which is my point. You have to get used to things like this, which probably adds about as much cognitive load as having something in the language to reduce this noise (although I think this is an known problem in go and may be improved in a future version).
> I am sure you know that there is no inheritance in Go
Fine.
Replace "inheritance" with struct embedding and/or interface hierarchies, and you can get a similar effect. My point is you can have overly abstracted designs in either language.
> The languages I listed first were rust and scala, which serve very similar purposes to c++ and java. In fact, rust is closer to c++ (no GC, more direct memory control) and scala is closer to java (runs on JVM) than go is to either.
The overlap in purpose and usage for Go and Java is gigantic. Also I don't understand why it matters whether Scala is closer to Java or whether Rust is closer to C++. We were comparing Go and X right?
This whole argument tree is a bit nonsensical.. I compared Go projects to Java and C++ projects which I have worked on. All of the mentioned languages are very common in companies these days and are used for similar topics. Why bring other languages in to this?
> Which is my point. You have to get used to things like this, which probably adds about as much cognitive load as having something in the language to reduce this noise (although I think this is an known problem in go and may be improved in a future version).
You always have to get used to some quirks in any language out there. It adds a few lines writing the code but reading it is way easier IMHO and not cognitive load. Opinions may of course vary on this.
> Fine. Replace "inheritance" with struct embedding and/or interface hierarchies, and you can get a similar effect. My point is you can have overly abstracted designs in either language.
As I already wrote, embedding is rarely used and was not a problem ever in my experience and yes interface spamming is a problem.
However Java e.g. has these abstraction complexities already baked into the standard library and encourages the overuse of abstractions IMO.
This is a bad article; struct embedding is not inheritance, and mistaking it for such is a classic case of "Java/Python programmer tries to use Go and shoehorns concepts from those languages in Go" that the post mentions.
This entire website seems pretty ... meh. It's like the W3Schools of Go.
Not the poster you're responding to, but practically every time someone wants to write code that mimics `map` or `filter` and gang is a 5-7 line function (at least). Something that would have been a 1 liner in languages like Java or C#. It gets tiring and distracting very quickly to jump around verbose implementations which amount to nothing more than standard streaming functions.
Another example is the lack of annotations for validations. In Java or C#, you'd annotate the function argument with something like `@Validated`, and it's taken care of. In golang, calling the validation code would have to be done manually each time that's another 3-4 lines (including error handling).
Yet another example is that golang lacks a construct similar to C#'s `Task`. You can't execute a function that returns a value asynchronously (if you care about that value) without creating a channel and passing it.
golang also lacks pattern matching and discriminated unions (aka algebraic data types). Java and C# are getting both (both have pattern matching, and ADTs are in the works as far as I'm aware).
this is why I have moved to Rust. I worked in Go a number of years ago, but after becoming proficient in Scala, I've decided sum types and pattern matching are where the sweet spot is. The JVM has its own issues though and I'd like to have a performance-conscious language in my toolbelt that doesn't sacrifice expressivity. Hence: Rust.