
I Do Not Like Go - Liriel
https://grimoire.ca/dev/go
======
danpalmer
> I can't speak for Go's genesis within Google, but outside of Google, this
> underanalysed political stance dividing programmers into "trustworthy" and
> "not" underlies many arguments about the language.

This summarises my opinion of Go that has been forming recently, that it's a
replacement for Java.

Java was the "safe" choice. Many engineers knew it, bad engineers couldn't be
_that_ bad in it and would manage to produce something. They could be handed
an architecture spec and implement it word for word without doing much
translation to the Java language. But I don't think good engineers could
"shine" with it.

It normalised all engineers around some median of productivity, and made
projects predictable.

I believe Go is doing the same thing in some ways. It's not supposed to allow
good engineers to find great ways of expressing complex architectures (however
necessary that may be), it's designed to let engineers of all skill levels hit
all problems with a Go shaped hammer and get something that looks inoffensive,
boring and predictable.

This is very unsurprising given that it came out of a large engineering
organisation. Google have many engineers of a wide range of skill levels _,
and normalising engineering is more important than doing it better.

_ I realise Google probably has a higher than average engineering ability,
maybe far higher than average, but they still have a wide range, and I also
include in this engineers who might be fantastic frontend engineers, who have
to get stuck into some system software, for example.

~~~
pm90
I don’t think this theory holds much water.

Go code is very opinionated but still flexible; it seems to be C but with
superpowers and great tooling out of the box. A whole bunch of complex
software is written and in production using go; I don’t think it limits the
productive/clever engineers from doing what they would do with Java.

~~~
danpalmer
Interesting. You could be right!

My experience with Go is very limited, but I tend to see interesting
abstractions built with other languages. Ruby, Haskell, Swift, JS, even some
Python – I see engineers building DSLs and architectures that strongly fit
particular use-cases. In Go, everything just tends to be functions and
structs, and the lack of expressiveness make it difficult to do anything with
nicer ergonomics.

I would agree that it is C with superpowers in some respects though.

> A whole bunch of complex software is written and in production using go

This is true, but my point isn't that you can't write the software, just that
it might have been better code in another language (easier to understand,
reason about, more reliable, more maintainable?). The biggest benefit along
these lines that Go seems to have is that lots of other software is written in
it, which comes back to a similar argument as Java.

~~~
vertline3
It's a replacement for c plus plus. Python, Ruby all those things are higher
level. Haskell is different paradigm. It's apples and oranges

~~~
danpalmer
>It's a replacement for c plus plus. Python, Ruby all those things are higher
level.

Ok then, Rust or Swift. These are both replacements for C/C++ and the same
applies.

> Haskell is different paradigm

I don't think this is a reason to reject it. That paradigm might allow for
better solutions to the problems.

~~~
vertline3
Ugh. Not going to wrestle with a pig, I'll get dirty and he'll enjoy it

~~~
danpalmer
I'm sorry, did I misunderstand your point? I'm not saying these things to
troll, this is my honest opinion.

I'll admit, Haskell is probably a poor choice for other reasons, but in many
ways I think Rust and Swift are better languages than Go for the things Go is
commonly used for.

~~~
vertline3
Youre okay it's 5 am I've been up all night. I agree with the thoughts that
Rob Pike can be opinionated, and that can be good and bad. There was a website
cat-v I used to go to and cat-v harmful stuff software.the site really likes
plan9 and go and Rob Pike.

I feel it gives some insight, but I think it's bad to be too opinionated as
this cat-v site can be

------
triodan
This must've been quite an old article, because lo and behold, nearly every
single complaint on that page is being addressed with gusto by the Go
community! Proposals on generics and error handling is well underway, and his
complaints regarding GOPATH and the go get has been solved with Go modules.

EDIT: As I expected, the linked page is written on Feb 2018[1], things indeed
have changed a lot since then.

[1]: [https://github.com/grimoire-
ca/bliki/commits/master/wiki/dev...](https://github.com/grimoire-
ca/bliki/commits/master/wiki/dev/go.md)

~~~
xg15
Sorry, but the language existed for how long? I remember hearing about the
same complaints about generics and error handling years ago - and they got
answers back then with about the same level of arrogant dismissal like the
quote about syntax highlighting in the article.

It's good if the community is at least starting to listen _now_ , but I don't
think that is sufficient evidence that the language is good.

~~~
tinco
There is no discussion if the language is good, it's already quite
convincingly proven it's good. The question was if generics would make the
language even better. Some people think that's a no brainer, others are not so
sure, and the latter group included the core maintainers.

People use the language because it is good, I think at this point one can
state that as objective fact. Once people use it, they'll complain when
something is not as nice as it could be, like the error handling, and like the
generics.

I wonder if in 2000 people felt the way about Java 1.3 people feel about Go
now. Java had a similar rise to prevalence, and it also lacked some features
we now consider crucial, such as generics. I personally would never want to go
back to Java 1.3. I feel I'd much rather code in Go instead, even if it lacks
generics. But I still think it's worth considering if Go would turn out to
become Java, if it now embraces generics.

~~~
edem
The language is crap. Just because people are using it does not mean it is
good. Take a look at javascript. Same deal. You did not state any "fact"s why
Go is good. Maybe it is good compared to Cobol or Fortran, but not compared to
pretty much everything else.

~~~
tinco
Oh come on. People are forced to use Javascript, I don't think it would even
exist today if it wasn't the only crossbrowser language.

Almost no one is forced to use Go, and yet people flock to it. I don't feel I
need to state the things that make Go good because it's already been done a
thousand times, and everyone in this thread already knows why it is good.

Have you ever built something in Go? I'm almost as productive in Go as I am in
Ruby, and that was within a week of learning it. It's crazy good for a
language that lacks so much expression.

~~~
YeGoblynQueenne
>> Almost no one is forced to use Go, and yet people flock to it.

Well, at some point people "flocked" to javascript, and they weren't forced
to. So it's a good language, then? Or sub javascript for java, or your
favourite bashable language.

~~~
hollerith
I will assume you're referring to Node. The browser explains why many coders
know Javascript well; the fact that many coders know Javascript well explains
the popularity of Node --without our having to resort to the hypothesis that
Javascript is a good language.

~~~
YeGoblynQueenne
I'm referring to the adoption of javascript as the scripting language for
browsers. Why else do "many coders know javascript well"?

~~~
kazinator
The story of how we got Javascript in browsers has absolutely nothing to do
with "adoption".

~~~
YeGoblynQueenne
But there wasn't anything stopping early browsers from using a different
scripting language. They stuck with javascript. Was that because it was a good
language?

And what about Java, for example? And why don't people "flock" to LISP, say,
or Haskell? Are those "bad" languages, now? And what about software, like
windows- is windows widely used because it's a great operating system?

Adoption is a rotten bad measure of quality. Not just in programming
languages- in everything.

~~~
kazinator
> _But there wasn 't anything stopping early browsers from using a different
> scripting language._

You mean "nothing stopping the other browser, Microsoft Internet Explorer,
from adopting Netscape's Javascript too".

~~~
YeGoblynQueenne
Well yes. Don't the other browser vendors count as adopters?

------
danpalmer
An interesting tidbit I learnt from a former colleague:

He wrote a small but non-trivial project in Go, and ended up re-writing in
Python. Over time, he and his team measured both codebases and found that they
had roughly the same number of bugs per line of code, but the Python codebase
was 1/3rd of the lines of code, therefore had far fewer bugs.

I wouldn't attribute this to inexperience either, this is one of the best
engineers I've worked with.

~~~
defertoreptar
So during the rewrite, he had the providence of the go codebase to look back
on, and the Python version still had as many bugs per lines? That sounds like
an argument for go, if anything.

~~~
danpalmer
This is true, I don't know the specifics, but I would trust that my former
colleague wouldn't make such a claim based on such incorrect data. My guess
these bugs were "code" bugs rather than "product" bugs, if that distinction
makes sense.

------
luord
I can get past most of Go's weird idiosyncracies... Except for the odious
error handling. Reading go code makes my eye twitch, and the biggest reason is
its error handling.

And sadly I'm now stuck with it, and not even the changes for Go 2 are
encouraging because, even though its new error handling is saner, it is still
needlessly different for the sake of it.

~~~
weberc2
I quite like Go's error handling. It adds visual structure and makes it
apparent which things can fail and how they're handled.

It's a welcome relief from the likes of Python where you only see (and
consequently think about) the happy path. This is definitely a big driver of
our 500s in our production Python services. While there are many who are
genuinely aggrieved by the number of keystrokes, I think a lot of people are
annoyed at error handling in Go simply because you have to think about error
handling.

~~~
ernst_klim
>simply because you have to think about error handling.

until you write

    
    
       x, _ := some_code ()
    

Besides, Go errors are used in pair with the return value, so you have to
check 4 possible combinations of value/nil and error/nil instead of 2 due to
the absence of sum types.

Oh, and no generics, so your errors are either string or you have to check the
interface in runtime which and can't statically check which exact errors could
your code return.

Oh, and no monadic chains/exception mechanism, so feel free to write

    
    
       x, err :=
       if (err != nil) {
          return err
       }
      
       y, err = ...
       if (err != nil) {
          return err
       }
    

instead of

    
    
        do x <- fun1 ()
           y <- fun2 ()
           ...
    

and then just check the proper subset of possible errors, carefully inferred
by the type system.

There are a bunch of different possible approaches for error handling:
exceptions, monads, erlnags failures as possible case, Go crowd had just
invented the worst and least error-prone one.

~~~
atombender
It's also suprisingly easy to mess up error returning. I've accidentally done
things like:

    
    
      a, err := run()
      if err != nil {
        b, e2 := cleanup()
        if e2 != nil {
          return err  // Whoops
        }
        return e2  // Double whoops
      }
    

Since you generally test the happy path more diligently, subtleties like these
tend to show up later than desirable (compile time would be the most
desirable, of course).

The := semantics is partly to blame here, as well as Go's lack of laziness
around unused values. Go is curiously strict about unused _variables_ , which
never hurt anyone, as opposed to unused _values_ , which absolutely can hurt.
For example:

    
    
      a, err := foo()  // This err is never used
      b, err := bar()
    

This is much worse! And the compiler doesn't complain. Fortunately there's a
linter called ineffassign that tracks ineffective assignments, and it's part
of gometalinter and golangci-lint. But not "go vet". And there's no linter
that can detect the first example that I gave.

Shadowing is a pet peeve of mine. Go is one of the strictest, most opinionated
languages in mainstream use, but it's amazingly lax and unopinionated in
certain areas. "go vet" can check for shadowing, but doesn't do so by default,
and of course it doesn't test the subtype of shadowing that := causes.
Shadowing is usually a bad idea, but Go encourages it through its :=
assignment semantics.

~~~
sickcodebruh
Go’s lax attitude about shadowing jumped right out at me, too. Coming to Go
recently from TypeScript, where the combination of the compiler and tslint
will aggressively bark at me, was jarring.

Coukd you point me towards any crash courses on using the Go linters you
mentioned to increase safety of my code? I’ll look them up, too, but if you
have any resources handy or think there’s work for me beyond RTFM, I’d
appreciate it.

~~~
atombender
First, I recommend golangci-lint [1], just because it's much more performant
(and designed to be from the start) than gometalinter. It uses much of the
same code.

Some of the more useful linters, like deadcode, can be a little too slow to
run in an editor like VSCode. We run the full linter list as part of our CI
tests, and then in development we run it with "\--fast", which runs only the
fastest one. I've disabled megacheck, which didn't work with Go modules the
last time I tried it.

Among the prominent ones I use, all enabled by fast mode, are ineffassign (as
mentioned), deadcode (detects unused code), govet (runs "go vet"), errcheck
(checking for calls where you ignore the error result), structcheck (finds
unused struct fields), varcheck (finds unused variables and constants),
typecheck (this does the same thing as "go build", basically), and unconvert
(detects unnecessary type conversions). The slower ones that are worth turning
on are staticcheck (performs lots of static checks) and unused (checks for
unused variables etc., but is slower than varcheck and structcheck,
apparently).

[1] [https://www.github.com/golangci/golangci-
lint](https://www.github.com/golangci/golangci-lint)

~~~
sickcodebruh
Thank you! This is great. For all of Go’s warts, it lived up to every single
hope and expectation I had for it in this last project. I’m looking forward to
improving it with these suggestions.

------
kureikain
These are author opinion and I respect and understand where he came from.
People should have ability to share about their opinions with the world.
That's great. But argue about the syntax highlight are silly to me. Argue
about leadership though on that syntax highlight is fine.

Below are mine. Let's look at Go from 2 angles:

\- Go the language \- Go the leadership

Go, the language is great to me. In the article, OP talk about `go get`,
GOPATH, Error Handling. To me they are fine. I love `go get` because it was so
easy to install binary that way and get update too. It fall short when have
conflict because you have a single global tree which thing depend on. This is
obviously not gonna work in long run, and in fact they always said they use it
different way at google and expect community standarize and find ways through
it. Which eventually lead to where we are now with go module.

But let's take a step back. Let's say if everything work great, do you like
`go get`. It's just feel like `homebrew` and a game changer to me. What if we
can abstract everything out, make `go get` works great as it's without
population the global tree. Technologies will evolve. Look at how JavaScript
evolve and become a great language and platform as it's right now. Give Go
time.

Same with error handling. Exception is just as annying too. You either handle
it or just swallow up or let's it buble up. I prefer Go style. Read Go code
force me to think about error right at that point.

I would love Go to have thing like Result or Maybe :( instead of return
multiple value which is just a convention right now.

Go bring lots of toolchain and interesting idea. gofmt gofix etc...

However, Go the leadership isn't up to Go the language. I think they feel to
the trap when they made a language which many big project use(influxdb k8s
docker...) and they get defensive when people talk about Go or criticize it.
Look at how friendly Jose of Elixir or Matz of Ruby is. I would love Go
leadership reach that. I read in other thread where someone say `Golang` and
one of Go core dev just dismiss because he written `Golang` instead of `Go`.

I think eventually the leadership will change. Go is opensource after all. And
we will see a day where Go is great both at language and leadership.

------
lkramer
As have already been pointed out most of these points ARE being addressed by
the Go community, but it kinda reminded why I look towards Go 2.0 with some
dread. Most of these things that he is asking for are things that will make
the language harder to read, Generics and Exceptions (and not least this weird
chimera that they have come up with in to Go 2 proposal last time I checked),
will undoubtedly create popular libraries, which are almost impossible to
understand for the uninitialised.

The main strengths of Go is that it's easy to pick up for almost anyone with
basic programming skills and be productive. The rigidity of the style, and the
relative simplicity means that I can get a very fair idea about how almost any
3rd party library on Github works in an hour, and probably tweak the bits I
may need to tweak. (The obvious exception to this is any library using a lot
of reflection which can fulfill anyone's deepest desires to make code
unreadable). C++ (which is my other main work language), have all these
advanced features (often added in haphazard fashion late in the language
specs), and I love writing C++ code, but I dread looking at other peoples
code, because it can be almost impossible to figure out what is going on.

I am tempted, when I see all these complaints about Go and comparing them to
languages with different feature sets, to tell people that in that case they
should use those. Of course, you might have the language dictated by an
employer, but in that case there was probably a rationale behind choosing Go,
and trying to change the language into being a clone of every other language
will probably just result in someone else coming up with a new simple,
statically typed compiled language, because I honestly believe the world needs
that.

~~~
xg15
> _... often added in haphazard fashion late in the language specs_

Agreeing with this point. I feel, there seems to be a vicious cycle in
"pragmatic" language design that goes something like this:

1) Let's design language n. It will be like language n-1 in spirit but much
more lightweight and without all the historical baggage!

2) In particular, let's leave out generics. They have been a never-ending
source of bugs and confusion in n-1 development, with all the gotchas and
awkward special cases you need to remember - and we can't really think of any
compelling real-world use-cases for them anyway...

(... some years later ...)

3) Sigh... the community keeps pestering us about generics... so alright,
we'll think about some way to add generics to the language so you guys finally
stop complaining.

4) Behold: We made n', a language extension to n with generics. However,
because all of our existing ecosystem is written in the old way, without
generics, we had to prioritize backwards compatibility over all else during
the design. That's why you'll have to live with counter-intuitive behavior A,
awkward special case B and arbitrary-looking restriction C when using them.
We're sorry, guys!

5) Let's design language n+1. It will be like language n in spirit but much
more lightweight and without all the historical baggage! Especially generics!

How about for a change designing a language where generics are part of the
initial design instead of just getting bolted on later?

~~~
eitland
Well, C# and TypeScript both seems to have gotten a whole lot more right (I'll
cut TypesScript some extra slack here since it has to take extra care not to
step on JavaScripts toes now or in the future.)

~~~
SideburnsOfDoom
Generics came to C# in version 2.0. Although it was done well, there is no
doubt that some things would have been different if there were generics in
Version 1.

------
dragonfly02
I am a total beginner in Go but I feel like the enforced uniform formatting is
actually a good thing because it makes everyone's code consistent and more
readable.

It can be extremely difficult to read other people's code if they use a
totally different style even if both of you are good at the same language.

And I feel there is litter point in telling people not to use one language
simply because you don't like it. Everyone is different, if you don't like it
just use something you like (maybe change job if you have to use it at your
current job). There is and will never be a language that EVERYONE likes. Oh
did I forget javascript? LOL...

~~~
tinco
Yes it is, I don't think anyone disagrees with that enforced formatting is a
good thing.

~~~
dragonfly02
Why am I not surprised:D

------
i_phish_cats
My first Go project was a PDF parser. Rewrote it in C a similar number of
lines because Go's capacity for polymorphism is as primitive as in C.

~~~
martingxx
Can you explain more about why you re-wrote?

You seem to have said you rewrote from Go because it has poor polymorphism,
into C which is equally bad in this regard.

If you find some language feature important, surely you would not rewrite into
a language that doesn't have that feature?

~~~
i_phish_cats
C is equally bad, but it can be used anywhere -- it can be compiled into a
dynamic lib and used in any language/framework, which is exactly what we did.

------
tempodox
Good article, and I admire the author's patience.

You don't bind yourself to the inner politics and philosophy of something like
Google except when you _are_ Google. Anyone's good taste should have prevented
them from using a language with such severe and ludicrous restrictions, but
that filter obviously didn't work.

------
Sean1708
> syntax highlighting, or as I prefer to call it, spitzensparken
> blinkelichtzen

Google Translate reckons this means "peak parking", is that a correct
translation? If so would somebody mind explaining what parking has to do with
syntax highlighting? And if not, what is the correct translation?

~~~
rarestblog
Not a native German, but probably this:

"spitzen sparken blinken lichtzen" -> "pointed sparkles flashing lights"

~~~
ncmncm
No, it means "spitting sparks". Like you see coming out of the control panels
in the original Star Trek, when they got shot by Klingons.

I guess they remrnbered about circuit breakers when they built the later
Enterprisen.

------
crististm
As Richard Hamming used to say ~"You can pretty much ignore those who
discovered a field".

Do not worry _at all_ that Rob Pike is finding colors juvenile. His opinion is
just that.

If it's worth anything, I'd put it in the same category as Linus's distaste
for debugging tools.

~~~
tokai
I love how childish it is to think that his personal experience of learning
arithmetic, is worth anything regarding syntax highlighting. In some way it
even undermines him.

Why did he use coloured rods as a child? Because it helps reduce cognitive
load! To define easier things as childish and harder things as adult, is
elitist and hostile to other people.

~~~
thatswrong0
Rob Pike also thinks abstractions like map, reduce, and filter are pointless
because you can just write a for loop.

Hence, we have Go.

------
SideburnsOfDoom
Seems to be from Feb 2018 [https://github.com/grimoire-
ca/bliki/commits/master/wiki/dev...](https://github.com/grimoire-
ca/bliki/commits/master/wiki/dev/go.md)

But I have seen similar sentiments before that

------
sebchris
My expectations surrounding Go were born from my intense admiration for
Python, which has grown so much as a language from its humble genesis at
Google and proudly stood the test the time. Needless to say, I was beyond
disappointed. Barring its concurrency module, which is some half-backed
mixture of STM and async, I was astonished at the absurdity of the language.
It reminds me of JavaScript, which as I recall was originally written as a
sort of joke. So yeah, Go's like a bad joke.

~~~
dustycat
Python did not have a genesis at Google. It existed before Google did.

JavaScript was written by Brendan Eich as the browser-side scripting language
for the Netscape browser, originally based on Lisp I believe. It was not meant
to be a joke.

------
oxplot
I've learnt that programming languages, just like food and fashion, are a
matter of taste to a high degree. You can point at _awful_ smelling, _too_
sugary meal and call it _crap_. Someone else spends years perfecting it.

One's taste however can change: food with high sugar leads to heart disease
and diabetes, so I better stop eating that favorite dish of mine. You keep
doing that for a while and taste of sugar (or salt, or fat) becomes
_disgusting_.

Statements like "Go is crap, it has no generics" originate from one's taste in
programming languages so there is no arguing with that. However, talks about
what generics (or exceptions etc.) does to the health of the programs you
write that span time and other contributors, are no longer subjective matter,
but an argument worth having. This is, where I think, Go's strength comes in:
its careful development process that puts programs' and programmers' health at
the top of the priority list.

Health is not the same as _comfort_. Taste of a dish you've had for years is
comforting. You're not going to feel comfortable when the ingredients you've
come to expect are taken away. But if you can get past that, you may end up
living longer and healthier. Similarly, your programs may become more
maintainable and long lasting.

No one, who is familiar with the philosophy and motivation behind Go, can
claim that what I've said above is false. You can say that Go team is slow in
progress, but that's what methodical and evidence based approach is like:
slow. You need time to experiment, learn and evolve. You other favorite
languages act like the general public who at hearing in the news that "coffee
is good for you", starts drinking 10 cups a day. Go's approach is more along
the scientific way.

~~~
opless
Sugar is not a direct cause of diabetes. So you might want to rethink your
analogies in future.

[https://www.diabetes.org.uk/guide-to-diabetes/enjoy-
food/eat...](https://www.diabetes.org.uk/guide-to-diabetes/enjoy-food/eating-
with-diabetes/diabetes-food-myths/myth-sugar-causes-diabetes)

~~~
Valmar
Right ~ sugar, namely fructose, is an indirect cause of diabetes.

Fructose over-consumption -> insulin resistance -> diabetes. Heart disease
follows.

Cholesterol is just the scapegoat for fructose over-consumption's horrifying
effects. Cholesterol is used by the body to try and patch up all of the damage
it causes. Cholesterol is used almost literally everywhere in the body, from
hormones, to cell linings, etc.

------
kerng
Been working with Go a bit and also reviewed and saw tons of production code
at places. The one thing that stands out is how messy and unorganized code is
written often. It's more of a "write only" language to me it seems. Java or
Python are much more readable.

------
dsirola
I feel like The Blub Paradox should be the mandatory read here
[http://www.paulgraham.com/avg.html](http://www.paulgraham.com/avg.html)

------
sershe
One thing I definitely dislike are value/reference semantics, where arbitrary
nested object structures are passed by value by default, but maps and slices
are somehow magical and are passed by reference. I don't even care which one
it is, but either everything non-primitive should be by reference by default,
or by value.

~~~
hu3
Nope. Everything is passed by value including maps and slices.

Here's an article from 2011 that might help you understand that:
[https://blog.golang.org/go-slices-usage-and-
internals](https://blog.golang.org/go-slices-usage-and-internals)

------
weberc2
This article lists a few issues, some valid, others not, but all exaggerated.
No mention whatsoever of the many advantages Go brings much less a comparison
between the pros and cons. There are a lot of interesting critiques of Go;
sadly, this isn't one of them.

------
tmaly
I was just having a discussion yesterday with a co-worker on Go. He deals with
security and encryption and does not do development work.

While I enjoy Go for its strengths, it was his opinion that Go did not offer
anything above and beyond other languages.

~~~
kjeetgill
Well yeah, I'd agree that he wouldn't. Most of the specialness comes at the
application level: He gets nothing out of specific blend of garbage
collection, allocation options, typing, and green threading that sorta defines
go.

------
dishwasher1999
Correct me if I am wrong but does Go enforce the curly brace (opening) of a
function definition be on the same line as the function's name?

------
yazr
Off topic:

Can i ask Go developers if the compiler is fast enough (for now), or is this
still a (major) pain point ?

Disclosure: i work on build systems and optimizers.

~~~
remus
What do you mean by 'fast enough'? As compiled languages go I think it's
generally accepted that go compiles relatively quickly, especially for large
projects with lots of dependencies (as it has saner dependency rules than
c/++).

------
watergatorman
If anyone who has tried Modula-2, Go appears to be very close, at some core
level, to m2, but m2 has a cleaner syntax, IMHO?

~~~
atombender
Go was influenced by Modula-2, but even more so by Oberon, which one of Go's
designers, Robert Griesemer, worked on with Wirth at ETH Zürich. Oberon is in
many ways a minimalist version of Modula-2.

------
abtinf
For quite some time, I’ve taken to wrapping the most common err case with a
simple function:

    
    
      func dieOnErr(err error) {
           if err != nil {
                log.Fatal(err)
           }
      }
    

It makes the code much easier to read (due to efficient use of vertical space)
and much less tedious to write:

    
    
      dieOnErr(foo())
      _, err := bar()
      dieOnErr(err)

~~~
skohan
What kind of application would you use this in? Just exiting on every error
seems you're just punting the whole problem of error handling, and wrapping
every fail-able function in another function doesn't seem like the best thing
for readability either.

Also this doesn't really solve the problem sited in the article: it requires
that all your functions return exactly two values with the error in the second
place. What if you need to return two non-error values?

~~~
abtinf
I primarily use this in three areas:

Command line tools: if any part of the command fails, you usually don't want
to continue, unless it is a long-running batch process. In that case, I
usually also write a logOnError() function to keep track of problematic work
items.

Servers: during server initialization, there are many circumstances where it
doesn't make sense to continue, such as template compilation failure or
failing to open the socket.

Other: I use dieOnError anywhere it would otherwise make sense to use panic()
- situations where continuing the program would mean running in an unknown
state, like out-of-memory conditions.

I've built systems with complex error handling before, but my teams have
always run into the problem of trying to reason about complex, unpredictable
program state. If the requirements can allow for the program to fail fast (as
you say, "punting the whole problem"), then the code itself can be kept much
simpler and easier to reason about. When errors do crop up, it is easier to
look at logs to debug a simple program (or infrastructure issue) than to debug
a complex program where you aren't sure how earlier errors affected state.

In languages with exceptions, this is sort of the default - if you don't
handle an exception, the program will crash. Often there will be a main level
exception handler that logs otherwise uncaught errors. But a problem in Go is
that programs are default-alive on errors. If you don't check the error status
of every single function call that returns errors, then the program can get
into unknown state. So in production code, especially code that just combines
a few libraries, every function call ends up taking 3 or 4 lines (1 line of
call and/or 3 lines of error checking).

Regarding the number of return values, my dieOnError/logOnError only handles
functions that return error and nothing else. If the function returns multiple
values, I first call it, then call dieOnError with the err:

    
    
      foo, bar, err := baz()
      dieOnErr(err)
      //assume foo and bar are valid
    

I suspect I could write a variadic error checking function that assumes the
last parameter is error:

    
    
      func dieOnError(a ...interface{}) {
        //do some reflection magic?
      }
      func foo() (bar int, baz int, err error) {
        ...
      }
      //maybe needs some type assertions or something?
      bar, baz := dieOnError(foo())

------
hardwaresofton
tl;dr - they said go was going to be simple. It is.

Preface: It's perfectly OK to dislike languages, especially when you know of a
better one that you're _not_ using. I personally cannot help but think of all
the better languages I could be using when I have to write some verbose bad
abstraction in a less expressive/powerful language. Also, as I re-read this,
the notion has struck me that I might be a Golang apologist. Also, as others
have noticed, the Go 2 drafts mention just about every point in this article.

That said, I think OP misses the point of Go -- it's meant to be simple,
productive, and production-ready. Many of the points that OP makes about the
mistakes I kind of shrugged at.

> I've never met a language lead so openly hostile to the idea of developer
> ergonomics.

I'm not sure I believe this C++/Java have similarly bad ergonomics, just in a
different way -- they give/saddle you with abstractions that are easy to use
wrongly and let you build a shit castle with amazing speed, while keeping
yourself open to to a hornets nest of mistakes and pitfalls. Go sacrifices
these features for a reason, and they stated it up front.

That said, I do think they made a huge mistake not having proper union/sum
types (AKA Algebraic Data Types/ADTs), but I can forgive them because building
an excellent type system might have gotten in the way of their stated
simplicity goals.

> In Go's case, the language embodies an extremely rigid caste hierarchy of
> "skilled programmers" and "unskilled programmers," enforced by the language
> itself.

I think this is a reflection of the Go, Google, and programming community in
general. Whether it's the "10x engineer" or working-at-big-companies-means-
you're-a-good-engineer mentality, this mindset is pervasive. It's the
difference between a Senior Staff Software Engineer II and a Senior Engineer
who just moved in from some other company -- it's trust.

> Again, the Go team's "not our problem" response is disappointing and
> frustrating.

Sucks that they didn't solve those problems up front, but I personally do not
blame them for focusing on _shipping_ , and fixing as they go. Honestly with
the amount of work they've put in, they have built a runtime and language that
have comparable performance and are more simple than Java + JVM. The JVM has
_millions_ of man hours dumped into it over decades. This is insane.

Also, there's the fact that whether it's a complete farce or not, they have
left open an avenue for changing the language. People could fork Go and change
it if they really felt that strongly about this stuff. The thing is, people
for the most part don't -- if you want a better type system go use (and
convince your team to use) a better language.

> The standard Go approach to operations which may fail involves returning
> multiple values (not a tuple; Go has no tuples) where the last value is of
> type error, which is an interface whose nil value means “no error occurred.”

Yes, error handling in Golang is less than ideal, but I prefer the forcing of
this as a default over the C++/Java approach -- this default makes it very
hard to write code that doesn't deal with errors _at the place you 're most
able to correct/work around them_. Again, I'm also giving Golang a pass for
not having errors-as-values in the way a language with a good type system
would... because Go sacrificed their type system for simplicity.

I don't think Go is a good programming language, but I _do_ think it delivers
on what it promises. It does what it set out to do -- be simple, productive,
and production-ready (this is mostly because they hammered out all the bugs
with tons of buy in from developers inside and outside google, and it's still
not perfect of course).

I've said it before and I'll say it again -- I think Go will supplant Java as
the language most companies use on the backend in <10 years. Fundamentally,
because of the developer fungibility benefits of Go -- it's going to be easier
than ever to swap out Golang programmers than ever -- you won't even have to
be a JVM master (which is normally one of the border points between Java
amateurs and pros) to write good-enough code.

Business thrives on good-enough code, not good code -- Golang is excellent for
that, and gets proven more and more right every day with all the companies
that are writing performant, statically compilable (thus easier to ship) code
and just getting shit done.

[0]:
[https://go.googlesource.com/proposal/+/master/design/go2draf...](https://go.googlesource.com/proposal/+/master/design/go2draft.md)

~~~
skohan
> I'm not sure I believe this C++/Java have similarly bad ergonomics, just in
> a different way -- they give/saddle you with abstractions that are easy to
> use wrongly and let you build a shit castle with amazing speed, while
> keeping yourself open to to a hornets nest of mistakes and pitfalls. Go
> sacrifices these features for a reason, and they stated it up front.

So what this immediately makes me think is what about Swift? Swift has many
similar goals as far as avoiding the common pitfalls of C++ and Java, and
moving more of the work of problem detection from runtime to compile-time, but
it manages to do so while embracing the advancements in programming language
design over the past 20 years. The go way seems to throw out an awful lot of
baby out with the bathwater.

~~~
hardwaresofton
I would love to hear from someone who actually uses Swift day to day, but
everything I read about Swift disappoints me (in the "why was that even a
problem in such a modern language??" sense) along with some brief
conversations with an iOS developer from a startup I was at for a while. I
don't have any specific blog posts I can point to right now but a more
defensible point might be why would I pick Swift over Rust, if I _wasn 't_
forced to (by doing recent iOS development)?

Features seem to be very similar, but without Rust has/is:

\- A more expressive compiler + type system

\- Better memory management via the borrowing/ownership paradigm

\- More F/OSS friendly, community steered

\- Usable from embedded (no runtime) to web services tiers (maybe I just don't
know a lot about embedded Swift outside of iOS)

\- No cost abstractions

Swift is indeed a huge step forward from Objective-C or some other languages
like C++/Java but I don't personally try and use it outside iOS because there
are better options. If I'm going to bring a long a runtime why not use Haskell
or Golang?

These days if I get to choose my language I spend my time trying to decide
between Rust or Haskell -- then again most of my projects are small, and make
no money.

~~~
skohan
> everything I read about Swift disappoints me (in the "why was that even a
> problem in such a modern language??" sense)

Can you be specific? I would love to understand which type of problem you are
speaking about. As someone who also got into Swift because it is the only game
in town for iOS, it's become my go-to language for everything from
tooling/orchestration to back-end infrastructure simply because I find it very
nice to work with.

Admittedly I'm not an expert in Rust, but the best way to explain why I prefer
working in Swift is that I find it to be a permissive language, where Rust is
an opinionated language.

For example, I find Rust's memory management paradigm to be super interesting,
and I can see the advantages it has in terms of safety (especially with regard
to concurrency, where Swift has some things to figure out), but it is
something which puts some limitations on the design patterns which are
available to you.

Swift, by contrast, has deep toolbox which you can use to implement OO
patterns, functional patterns, Protocol Oriented design etc.

So I think Swift and Rust have slightly different goals, and where the worst
piece of Rust code you can write which will compile will be a bit safer/more
performant etc than similar with Swift, to me Swift strikes that balance where
it's still giving me a huge advantage over most languages in terms of compile-
time checking, but I can be incredibly productive and expressive.

~~~
hardwaresofton
> Can you be specific? I would love to understand which type of problem you
> are speaking about. As someone who also got into Swift because it is the
> only game in town for iOS, it's become my go-to language for everything from
> tooling/orchestration to back-end infrastructure simply because I find it
> very nice to work with.

Sorry I tried to look through my browser history for a specific example but
couldn't find one... All I found was a page on AlamoFire
([https://stackoverflow.com/questions/29131253/swift-
alamofire...](https://stackoverflow.com/questions/29131253/swift-alamofire-
how-to-get-the-http-response-status-code)) that I think I was looking up when
trying to help debug some iOS mobile code. I think I was looking over the
shoulder of an iOS dev on my team and just didn't like the code I was
seeing...

I also saw an SO thread on JSON parsing in swift
([https://stackoverflow.com/questions/24013410/how-to-
parse-a-...](https://stackoverflow.com/questions/24013410/how-to-parse-a-json-
file-in-swift)) so maybe I was annoyed with how seemingly not-easy parsing
JSON into a known class was? might make sense with the AlamoFire thing).

I don't think I can defend that point very well but it's just a feeling I've
held on to over time.

> Admittedly I'm not an expert in Rust, but the best way to explain why I
> prefer working in Swift is that I find it to be a permissive language, where
> Rust is an opinionated language.

Well I'm not either -- I've been writing it for fun but it's not my main
workhorse at this point (nevermind finding a corporate codebase in it). This
might make it a bit clearer were we differ -- I'm really into opinionated/not-
permissive languages right now. The more feedback I can get from a
compiler/type system the better as far as I'm concerned as long as the
language lives up to it's promises to make me better/safer/whatever (for Rust
& Haskell they mostly deliver).

> Swift, by contrast, has deep toolbox which you can use to implement OO
> patterns, functional patterns, Protocol Oriented design etc.

I personally don't actually want OO design in backend languages I use if I can
avoid it -- I've found that a good type system along with
typeclasses(haskell)/traits(rust)/protocols(swift)/duck-type
interfaces(golang) and basic structs is all I need. If the language allows
constraints on the generics (i.e. requiring one typeclass/trait/protocol to
satisfy another) that's all the composability I need without all the OO
boilerplate and cruft.

Swift might be the more flexible language since it doesn't have the
ownership/borrowing system but I also don't feel like I spend my time reaching
for too many design patterns per say -- maybe I write too many of the same
kind of application (backend web services). I generally use the component
model (like in
[https://github.com/stuartsierra/component](https://github.com/stuartsierra/component)),
sprinkle some DDD and I'm good to go for most things.

> So I think Swift and Rust have slightly different goals, and where the worst
> piece of Rust code you can write which will compile will be a bit safer/more
> performant etc than similar with Swift, to me Swift strikes that balance
> where it's still giving me a huge advantage over most languages in terms of
> compile-time checking, but I can be incredibly productive and expressive.

Personally the langauge (if you can call it that) which fits this mold for me
is Typescript. Of course Javascript is the wild wild west where the most
reckless code seems to be written but Tyepscript gives me just enough of a
type system and some assurance that everything isn't going to break at
runtime. The projects where I'd use node (basically so I can ensure smooth
hand off to another developer) I can't use Swift, and the projects where I
might use Swift I'd rather use Rust or Haskell.

I think the biggest difference is that I don't write Objective-C/Swift iOS
apps, if I was maybe I'd have a chance to give Swift a more thorough look
over. That said, I basically never intend to write fully native apps because
I'd rather pick "close-enough"/"good-enough" options like Nativescript.

~~~
skohan
> AlamoFire

Ah yeah, so AlamoFire is a monstrosity of a library which was originally
implemented in Objective C back when iOS's native networking tools were pretty
bare bones. I thought it was bloated and overcomplicated then, and it's worse
now.

> JSON parsing in swift

This is a solved problem since Swift 4. Now you can declare conformance to
Encodable/Decodable protocols on any one of your types, and in many cases the
compiler can generate a default implementation of the protocol methods, so
that's all it takes to make a type parsable from/serializable to JSON.

What's better, these "Codable" objects work with "Encoader/Decoder" protocols,
so you can provide your own JSON parser implementation, or for instance, you
could implement a TOML parser which conforms to Decoder, and all your existing
Codables would already work with it.

Swift definitely has some warts remaining, but it's gotten a lot better over
time, and the upcoming features and priorities seem promising as well.

~~~
hardwaresofton
> Ah yeah, so AlamoFire is a monstrosity of a library which was originally
> implemented in Objective C back when iOS's native networking tools were
> pretty bare bones. I thought it was bloated and overcomplicated then, and
> it's worse now.

OK, glad I wasn't imagining it

> This is a solved problem since Swift 4. Now you can declare conformance to
> Encodable/Decodable protocols on any one of your types, and in many cases
> the compiler can generate a default implementation of the protocol methods,
> so that's all it takes to make a type parsable from/serializable to JSON.

This is _exactly_ what I was expecting it to be like which is why I think I
was disappointed -- the ToJSON typeclass (haskell) and the Deserialize (rust)
trait are the analogs I was expecting to find but didn't.

Honestly I think Swift is a good language, my opinion on it really isn't too
relevant except for why I normally don't reach for it outside of iOS
development.

Also does swift compile to a static binary fairly easily? That's another
feature I really like from the recent crop of languages (Haskell excluded, it
can be a bit tricky) -- Rust and Golang compile statically super easily, and
you can get even more portability if you build in alpine (since it uses musl
libc).

------
knan
you don't have to like go, I'm not "liking it" per say, but what's the
alternative if you want static typing/compile language, Java, well the compile
time is to big for my taste, do a change wait 30 seconds, also it needs to
munch ram, Net core could not get it to run.

~~~
vbezhenar
You can use Java in a lightweight manner. That's what I'm doing lately. Use
built-in com.sun.net.httpserver or add undertow dependency. Enough for HTTP,
uses few MB memory (I'm running one app on a 256 MB OpenBSD server), starts in
a fraction of second. Use JDBC without all those ORM nonsense, you'll have
somewhat verbose but pretty obvious code. It's pretty productive environment
for me.

~~~
vram22
>Use built-in com.sun.net.httpserver or add undertow dependency.

Haven't used Java for a while, but IIRC, (some of) those star.sun.star classes
(as opposed to star.java.star ones) used to be mentioned as liable to be
deprecated, so not to be relied on (long term at least). Is that still the
case now?

~~~
vbezhenar
I don't think that this module is deprecated.
[https://docs.oracle.com/en/java/javase/11/docs/api/jdk.https...](https://docs.oracle.com/en/java/javase/11/docs/api/jdk.httpserver/module-
summary.html) here's documentation for latest Java without any mentioning of
deprecation. It's a bit strange module because it was located in that package,
but it was always documented, so I'm considering it safe to use for the time
being. Probably not the most performant (uses good old blocking I/O), but good
enough for many tasks.

~~~
vram22
Thanks.

------
black-tea
I've done lots of work in C, Python and Common Lisp. I've done a fair bit in
go and for me it's just not _fun_ to use. I feel like I'm playing in a little
sandbox with a few prescribed tools.

------
gaius
_the language embodies an extremely rigid caste hierarchy of "skilled
programmers" and "unskilled programmers," enforced by the language itself._

Scala also has this approach, a sharp distinction between library-writers and
application developers.

~~~
blablabla123
In my opinion this is a misconception that I saw in other people approaching
the language as well. The thing is: nobody should use "advanced" features.
Using `reflect` should be reserved for exceptional case where it's not
possible to solve the problem differently. This has been pointed out in the Go
website and the mailing list bizillion times.

That said, the language doesn't have many features. So if you want to show off
your skill, it's probably by structuring the code concisely which can be
challenging at times. Using reflect is actually the easy way out and most
functions of that package can panic easily...

------
divan
This article is a bit outdated and has invalid claims and a lot of ad hominem
and other fallacies, so I'd recommend to stick to the textbook for complaining
about Go for maximum clicks:

[https://divan.github.io/posts/go_complain_howto/](https://divan.github.io/posts/go_complain_howto/)

~~~
hu3
You're not wrong. The article is at least 10 months old:

[https://old.reddit.com/r/golang/comments/7zmt8u/i_do_not_lik...](https://old.reddit.com/r/golang/comments/7zmt8u/i_do_not_like_go/)

