Hacker News new | past | comments | ask | show | jobs | submit login

The author fundamentally misunderstands language design. He picks an arbitrary design constraint, in this case correctness, and argues that any language that does not provide 100% correctness is bad. He uses Rust for his examples, a language that has correctness as one of its top design goals, and contrasts it with Go, for which correctness is not that important. So of course Rust will come out on top when the only metric you care about is correctness.

As usual with such one-sided rants, the downsides to the supposed clearly right alternative are omitted. How long would it take for me to learn Rust + write a given program vs Go? How long does it take to model problems 100% correctly vs merely well-enough?

> It [Go] constantly lies about how complicated real-world systems are, and optimize for the 90% case, ignoring correctness.

Yes, exactly. Optimizing for the 90% case, not simplicity, is the primary design goal of Go. In other words, pragmatism or the 80/20 rule. Go attempts to provide 80% of the benefit for only 20% of the cost.

This is pervasive throughout the language:

- the author's examples,

- a GC,

- merely good-enough error handling.

The sweet spot Go attempts to strike between speed of coding, correctness, safety, performance, and mental overhead is the reason it's so polarizing. You may like this approach or not, but let's not pretend that Go is all bad or that say Rust is some perfect holy grail that will save us all.




What an extremely convenient template to dismiss any nuanced argument against "worse is better". You even get to question my credentials a couple times! (I apparently pick metrics that are convenient to my argument, and fundamentally misunderstand programming language design).

Even if I accept the premise that "I'm challenging Go on things it doesn't promise to deliver" (which is disingenuous to begin with — correctness underpins /everything/, it's not a hobby), I can't help but notice you carefully use the word "attempt" when referring to the promises Go /does/ make.

One of the things I'm saying is that Go does not deliver on those. It does not deliver on "speed of coding", precisely because everyone, even seasoned Go developers, keep hitting its many design pitfalls.

It does not lower mental overhead, because it prevents you from building abstractions, and pushes complexity out of the language and into your head.

There's a lot to be said about safety and performance, which gets bleaker real quick once CGo enters the picture (hence why the Go team likes to remind folks that CGo is not Go).

But say we disagree there and you truly find it a breeze to write large amounts of Go code: as soon as you deploy something to production and others start to rely on it: you don't get to choose not to care about "correctness". If you don't, you're just pushing the problem onto someone else.

You may be pushing the problem onto ops people, other devs, or your customers, but it does land on someone. And nowadays that someone is often me: my frustration is fueled by years of real world use, I do not, like you seem to imply, enjoy thinking about these things in the abstract, just for the fun of it.

Of course, you can choose to ignore that too, and that's fine! But let's please drop the pretense that this kind of response is anything other than "I refuse to think about this".


>because it prevents you from building abstractions,

Replying to just this part of your comment, but building abstractions can be as much a source of new complexity and cognitive overhead as it can reduce them. I think Go is wise to be on the side of less abstraction, because most of the abstractions it makes hard end up hurting more than they help.

>What an extremely convenient template to dismiss any nuanced argument against "worse is better". You even get to question my credentials a couple times! (I apparently pick metrics that are convenient to my argument, and fundamentally misunderstand programming language design).

I think if you want to make an argument that Go has the wrong values, you should make that argument. But your essay is not that argument. In your essay the claim that the values are wrong is implicit and unexamined, and you spend most of the words on demonstrating that Go has different values than you.

It would be more persuasive if you were to examine why Go has adopted these values and explicitly explain why you think they are mistaken. Instead it comes off as though you simply don't understand Go.


There's nothing stopping you from building bad abstractions in Go, and I find it pretty common. Here's an example:

Debug(msg string, keyvals ...interface{})

The keyvals interface assumes you are passing in both a key and a value but if you don't, it doesn't work correctly and in fact in our code I think it blows up.


Definitely. Go is not the last word in the conversation on programming language design, and it hasn’t solved the problem of prohibiting harmful abstractions. But I do think the conservativeness around abstraction is an improvement, at least culturally, over the way many language communities view software development.


> because most of the abstractions it makes hard end up hurting more than they help.

You got any proof for that?


No proof, you're free to disagree. Just my experience.


> What an extremely convenient template to dismiss any nuanced argument against "worse is better".

Nuance is exactly what I'm arguing for, there's none in the article.

> You even get to question my credentials a couple times! (I apparently pick metrics that are convenient to my argument, and fundamentally misunderstand programming language design).

You're right, I apologize. I usually try hard to never directly address whoever I'm responding to on HN, but figured it was fine since it's the linked article itself. It's clear to me now that reasoning makes no sense, I should have taken the time to reword it.

> I can't help but notice you carefully use the word "attempt" when referring to the promises Go /does/ make.

It's an acknowledgment that there's space to discuss Go failing to adhere to its design principles. I'd love to read an article on small changes to Go that would provide immense benefits. However, I don't see much value in an one-sided rant on the less-valued principles not being valued highly.

> correctness underpins /everything/, it's not a hobby

> [...]

> you don't get to choose not to care about "correctness". If you don't, you're just pushing the problem onto someone else.

Correctness isn't binary. It's perfectly valid to trade off correctness for gains elsewehere.

The classic example is companies switching from dynamic languages like Ruby to Go/Java once they hit scaling issues. Does that mean Ruby is a bad language and the company should have used Go/Java from the start? No. Using Ruby gave them the development velocity that let them get to scale in the first place.

If you do need strong correctness guarantees, by all means stay away from Go and use Rust/Ada/etc. Just remember that it's not free, something had to be traded off to achieve it.


> It's perfectly valid to trade off correctness for gains elsewehere.

Agreed, but no-one is disputing that, right? The problem is that very often saying correctness was given up in order to gain velocity and simplicity is simply a lie. Incorrectness can easily lead to slow development and tons of complexity.

It’s only fun when the trade-off is actually a trade-off.


Agreed. I just want to make clear that Rust/Ada/etc. don't give correctness guarantees! Their compiler is just more enforcing. It's all not black and white.

Rust is promoted for its correctness, but those correctness related bugs Rust prevents are an extremely low fraction of real world bugs (comparing to managed memory languages). I mean, how many type-system related bugs are there in real world projects with Java, C# or Go?

Rust is promoted with "fearless concurrency". Does it prevent your code from deadlocks, which are among the most tricky bugs?


I mean, just yesterday while I was running the JetBrains Rider install workflow, I hit a NullReferenceException (or whatever it's called in Java). That is a type-system related bug which arises only because Java's type system trivially represents illegal state.


Null pointer bugs are prevented by idiomatic use of Option in Rust, so that’s at least one case where Rust’s focus on correctness prevents memory-safety bugs.


Yet many Rust code bases are littered with .unwrap(), which undoes that benefit.


A great deal of the benefit of Option comes from where it isn't used - you know most things can't be null and simply don't have to think about the possibility.

unwrap() bugs are annoying, yes, but at the end of the day they're just a fancy assert(), helpfully spelled out in the code and confined to bits of it where the value is Option<T>. This is a much better situation than a language where nulls can in principle turn up anywhere.


but it's explicit; you can easily tell which lines of code will panic.


> Just remember that it's not free, something had to be traded off to achieve it.

I don't think that is clear at all in the general case. There's no reason why we should believe that "something had to be traded off to achieve it". In some cases probably that's what happened, maybe even explicitly, but in other cases there are just some designs that are better than others.


>> even seasoned Go developers, keep hitting its many design pitfalls

I'm a professional dev for 14 years. Started with Python, C# (WPF and ASP.NET), Qt, Java (Spring), Kotlin, Frontend with React, Angular, Vue, ... even Rust, so I've seen a lot.

Honestly, in the last 2 years using Go for backend services and some CLIs I never hit any of those design pitfalls you're writing about. Every language has it's quirks. Even Rust. But Go is not decisively better or worth than the other. For example, Kotlin is easier and more fun to write, but writing code is just a small part of a project. The whole spectrum needs to be considered. That's where Go shines.


> It does not deliver on "speed of coding", precisely because everyone, even seasoned Go developers, keep hitting its many design pitfalls.

Well that’s a subjective statement. Are you basing that data or just your own feeling?

I love writing Go and I’m way faster in Go than Rust. If I need more acceleration, of course Rust is the place to be, but if I just need to hammer out an API, Go is going to be much easier to do that in. Also my code will be far more consumable than Rust because it’s way less complex and has enforced opinions.

> If you don't, you're just pushing the problem onto someone else.

Really? Maybe that happens occasionally but I’ve never had that happen. My Go services have been incredibly stable and easy to develop on.

With Rust your are pushing onto others code that’s very hard to understand because it’s a kitchen sink like c++. Go believes community is greater than the individual so it’s opinionated.

In general, I found this post incredibly inflammatory. Different tools are good at different things. Rust isn’t a panacea, neither is Go, but yes Go hits a sweet spot of lower level with rapid development. Why is that controversial to you?


As someone who don't work actively in both Go and Rust, I perceive Rust to be readable and I feel more comfortable writing in Rust due to how strict it is in term of correctness.

If I have to write go, I need to have an IDE well setup. And I had to do it a couple of times to tweak a simple restapi. Rust is surprisingly faster to write more complex things, down to the details such as when I want strings to be obfuscated in the resulting binary.

Reading is also so much easier in Rust, surprisingly, despite the complex syntax. It is easier to swallow complex concepts such as how ethernet packet is shaped, or how entitiy component system stores data and execute systems, compared to reading a simple API in Go.

But again, this is just me.

> I love writing Go and I’m way faster in Go than Rust.

The problem is, not every go developer is you.


> The problem is, not every go developer is you.

This is pretty common sentiment, the borrow checker is hard, you will be slowed down by it


The generalization of anecdotal experience is a flaw in any argumentation. We see it every day everywhere.

You *assume* that Go creates sooner or later problems everywhere it runs. I have another anecdotal data point: At my workplace the most troublesome services are the ones written in Java. The Go services are much easier to manage and run much more reliably. Actually I can't remember of any issues with Go services.

So, you need to take more data points into account to come to a justified verdict. Your generalization of Go leading systematically to huge problems is far away from reality. There's already a huge amount of services written in Go. Networking stuff, backend APIs, CLIs, databases, ... do they all fall apart? No, just the opposite: They are some of the most successful projects in the last years.

Your analysis of the (tiny) problems is correct. Your conclusion that people shouldn't use Go is very wrong.


> correctness underpins /everything/

Correctness is a spectrum, not a boolean. Failures of correctness are, equally, a spectrum of risk. And risk is measured primarily by impact on business goals. Consequently an incorrect program that satisfies its business-level responsibilities is definitionally better than a correct program which does not.


I think it's a matter of different goals. What you describe is pains of a very senior developer who has worked on a lot of very subtle bugs and never questioned their desire to deliver the best software possible.

Parent comment, however, talks about a situation where you have to hire dozens (if not hundreds) of $10/hour developers to ship software that is just good enough. I mean folks who may be great people and deserving overall respect, but who can't actually solve FizzBuzz. For such a situation, this:

> You may be pushing the problem onto ops people, other devs, or your customers

is quite alright and much more preferable than paying the market rate for developers who are actually capable of learning Rust.


I'm not fond of this framing, which suggests that go is for bad programmers and rust is for good programmers. If Go makes it easier for bad programmers to write decent code, it also makes it easier for good programmers.

Good programmers aren't good because they're insanely clever and whip up brilliant combinations of abstractions. They're good because they write maintainable, understandable, simple, and effective code.

Or: they write code that understands the problem and solves it, not code that is stylish.

Go helps good devs do this.


> I'm not fond of this framing, which suggests that go is for bad programmers and rust is for good programmers.

Right, go is for inexperienced programmers.

> The key point here is our programmers are Googlers, they’re not researchers. They’re typically, fairly young, fresh out of school, probably learned Java, maybe learned C or C++, probably learned Python. They’re not capable of understanding a brilliant language but we want to use them to build good software.

Or so Rob Pike thinks. However, as I get more and more experienced, the shortcomings of go become too much to bear.


> go is for inexperienced programmers.

I am an extraordinarily experienced programmer, and I vastly prefer Go to Rust.


That doesn’t really have anything to do with a statement about Rob Pike’s design intent.


Before rust started being used in crypto, rust salaries weren't great - probably targeting people happy to get less money to use their favourite language


> What an extremely convenient template to dismiss any nuanced argument against "worse is better".

You say that like its a bad thing.

If there is an easy template to dismiss your argument, it means you did a bad job arguing. Part of making a good argument is anticipating likely objections and addressing then in your argument


Note that a "dismissal" is not the same as an actual rebuttal. A template can just as easily generate a tricky-to-dissect fallacy or bad-faith argument as actual logic.


I disagree - if its a template that is commonly used, someone only has to dissect it once.

Regardless, what exactly is tricky to disect or falacious about this template? The rebbutal is basically:

* go is trying to optimize for different things

* go makes no secret that its trying to optimize for different things

* some people like the things that go optimizes for (and some people don't).

* [with an implied] if you intentionally used a tool that made choices you don't like, and its not a secret they made those choices, is it really the tool's fault or your fault? Its like ordering ice cream and being mad the ice cream is cold.

If the original argument was more phrased as the types of design choices go makes are bad, it would probably be more palatable (but also less interesting, because whether worse really is better is flame war that has been going on for decades)


You're too optimistic about defusing tricky BS. And I was deliberately avoiding making a claim about the article, only about the idea that the existence of a template to "dismiss" your argument implies anything about your argument. It does not.


I think there are 2 senses of the word argument here. After all, how good your argument is (i.e. how good a job you do at convincing people of your view) has no bearing on how good your argument is (i.e. how true it is).

When i claim that failing to address a criticism that is so common it has a template form and thus should easily have been anticipated, makes for a bad argument, i mean in the first sense not the second. To be clear, by a template i mean a template response that people believe in good faith - like what was used in this discussion. I don't mean a template for making an ad hominem attack or something bad faith along those lines. But ultimately if there is some "tricky bullshit" that is commonly believed in good faith by the audience, then yes an argument that doesn't defuse it is a bad argument.


Can you see the value in being able to create software more quickly, at the expense of the software's stability?


Yes, but that is definitely not achieved by checking for errors every second line.


I think checking for errors every line makes my go programs easier and faster to produce at a higher level of quality.


Some languages achieve error checking by type transforms and pattern matching, which are much more effective and efficient than error checks after every function call


Sure, but is writing the error check by hand what creates the benefit? Or is it having the error check?


It is thinking about what to do for each operation that can fail. This thought is what separates the applications that recover when the network glitch is over vs. the applications that need to be restarted.


The value here is the few seconds of human attention given to the error at hand. The thought is irreplaceable. Like others mention, 90% of the, end up if err != nil { return nil, err } but thinking about it will, in my experience, make the system more robust to failure. At the very Least for your process you will decide on a goal of carrying on in the face of failures and repairing when things work again vs. just bailing out and letting something else worry about it.


What if the return nil, err was the sane choice at the time of writing but there are changes downstream that mandate a new error handling mode there? Also, there are plenty of “writing this code at 3AM” where I would question the validity of such thoughts.


No, the compiler needs to save us from ourselves. What if we get a runtime nil? Oh God, the horror!

I understand correctness, I do not understand why we're making languages a nanny state where if we're not completely focused on correctness and zero copy interfaces it's not worth using.

I don't want to always care about memory allocation strategies when I want to have some fun on a project. I don't understand why a vocal group tends to dismiss some languages because they're not always doing the PERFECT thing.


I used to prototype in PHP and nowadays I prototype in JS.

I also ship JS in production and it's a painful experience compared to rust or haskell.


I think describing this article as a one sided rant isn't really fair. The author shows that Go makes a few design decisions that make it easy to shoot yourself in the foot. This is generally a bad idea. Rust may be the summum of correctness. In my view that makes it an ideal candidate for comparison. It shows the reader what a better solution would look like. And that this can work in practice. Does that mean you shouldn't write code in Go? No of course not. But I think the author has done a great job of showing why they don't want to use Go anymore.


It’s one sided when it points out the pitfalls without bothering to describe why they’re there, and what the upside is. There are sloppy mistakes in Go, just like in anything, but many of the common criticisms of go are about trade offs not about mistakes.


Sure, but the way I read the article, that's what the author shows. They don't like trade-offs that are made.

Maybe the tone of the article feels a little aggressive towards Go, I don't know. To me it felt more like an outcry of frustration with the chosen trade-offs.


The author clearly does understand language design. He probably even agrees with your description of go above, but simply describes it really doesn’t work for him.


> He picks an arbitrary design constraint, in this case correctness, and argues that any language that does not provide 100% correctness is bad

I'm sorry, WHAT? This is not about correctness (and IMHO if you have something that makes this tradeoff you should not use it anyway), it's about pretending that correctness does not matter and that unexpected bad behavior is okay... cause you know 80/20.

IMHO Go has its use cases but it's definitely not a panacea. I don't mind people pragmatically picking it and using it. I am bothered by the zealots that think this is the best thing since sliced break (spoiler alert: it's not). Its authors and the community also seem to have an elitist / better than you default attitude when being humble and open would actually serve them better (package management and generics come into mind - what disasters)




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: