That's from someone who did a bunch - Perl, Ruby, Python, Java, C++, Scala.
Syntax is one thing, assembling an application with maintainable code is something else.
Code generation in Golang is something I've found removed a lot of boilerplate.
Also, refactoring my logging statements so I could see the chain of events seemed like work I rarely had to do in other languages.
It's a language the designers of which - with ALL due respect - clearly have not built a modern large application in decades.
I think the reason people find go a bit annoying with the error condition is because go actually treats errors as a primary thought, not an after thought like Python, Java.
My preference is a language like Elixir where most methods have an error-code returning version and a ! version that might raise an exception. Then you (the programmer) can choose what you need. If you're writing a controller method that is for production important code, use explicit. If you're writing tests and just want to catch and handle any exception and log it, use exceptions. Or whatever makes the most sense in each situation.
Access forbidden? Log a warning and show a 403 page. Is is JSON? Then return JSON.
Exception-handling in general is a pretty small part of most applications. In Go, MOST of the application is error-handling, often just duplicate code that is a nightmare to maintain. I just don't get why people insist it's somehow better, after we "evolved" from the brute-force way.
I agree on the logging point but my experience was the explicit error handling and with good test coverage meant we rarely got into situations were we had non-deterministic situation were we relied extensively on logging to resolve. But we also went through several iterations of tuning how we logged errors. It's definitely a rough edge in what is readily available in the language.
This sound a lot of like Apple user arguments about iPhone 1 missing copy & paste over a decade ago.
I am very pedantic about checking responses for errors, but from my experience when working with a team and existing project I see that people notoriously forget to check the result. TBH it is a pain to essentially repeating the boilerplate `if err !=nil ...`.
What's worse is that even documentation skips checks. For example `Close()` method. It's almost always returning error, but I almost never seen anyone check it.
The reason for it, is if you want to use `defer` (which most people do) you would end up with very ugly code.
The other alternative would be to then making sure you place (and properly handle error) close in multiple places (but then you risk of missing a place).
And other solution would be using `goto` in similar way as it is used in Linux Kernel, but there are people who have big problem with it. I had a boss who religiously was against goto (who did not seem to understand Dijkstra's argument), and asked me to remove it even though it made the code more readable.
That said, in practice I see it following a similar philosophy to java checked exceptions, just with worse semantics.
Personally, I don't like high-boilerplate languages because they train me to start glossing over code, and it's harder for me to keep context when faced with a ton of boilerplate.
I don't hate go. I don't love it either. It's really good at a few things (static binaries, concurrency, backwards and forwards compatibility). I hate the lack of a fully-fleshed out standard library, the package management system is still a bit wonky (although much improved), and a few other aesthetic or minor gripes.
That said there's no language I really love, save maybe kotlin, which has the advantage of the superb java standard library, without all the structural dogma that used to (or still does) plague the language (OOO only, one public class per file, you need to make an anonymous interface to pass around functions, oh wait now we have a streaming API but its super wonky with almost c++ like compilation error messages, hey null pointers are a great idea right oh wait no okay just toss some lombok annotations everywhere).
End of the day though a lot of talented people are golang first and sometimes you just gotta go where the industry does regardless of personal preference. There's a reason scientists are still using FORTRAN after all these years, and why so much heavy math is done in python of all things (yeah yeah I know Cython is a thing and end of the day numpy etc abstract a lot of it out of the way, but a built in csv and json module combined with the super easy syntax made it sticky for data scientists for a reason)
> I am not used to writing code where 2/3 of it is "if err" statements.
I don't write Go, but I have seen this a lot when reading Go. It seems hard to escape. The same is true for pure C. You really need to check every single function output for errors, else errors compound, and it is much harder to diagnose failures. When I write Java with any kind of I/O, I need careful, tight exception handling so that the exception context will be narrow enough to allow me to diagnose failures after unexpected failures. Error handling is hard to do well in any language.Which kind of proves my point. Even Google struggled to write clean, idiomatic Go.
Not a gopher by any stretch, but to my way of thinking code generation is literally boilerplate, that's why its generated. Or does Go have some metaprogramming facilities I'm unaware of?
So unrelated to code generated, if that makes sense. The generated code I'm sure had lots of boilerplate, it's just not code we needed to consider when developing.
If you are looking at OpenAPI in Golang I can recommend having a look at https://goa.design/. It's a DSL that generates OpenAPI specs and provides an implementation of the endpoints described. Can also generate gRPC from the same definitions.
We found this removed the need to write almost all of the API layer and a lot of the associated validation. We found the generated code including the server element to be production ready from the get go.