Hacker News new | past | comments | ask | show | jobs | submit login
Lies we tell ourselves to keep using Golang (fasterthanli.me)
748 points by 0xedb on April 29, 2022 | hide | past | favorite | 525 comments



The author writes well and makes compelling points. His "I want to get off Mr Golang's Wild Ride" post is good too.

But I don't find myself agreeing with his position, which is "you shouldn't use Go for production services" (he explicitly says this in one of his Go posts, I forget which one and don't have time to look right now).

The better alternative to Go is Rust. Okay, sure, I'm willing to admit that in the examples presented, Rust handles things better. But Rust isn't a panacea. Rust is complicated and hard, and often it's not worth taking on that burden just to theoretically handle cases that rarely occur and even more rarely cause any problem. Programming is a means to an end, and the cost of using Rust (hiring, increased development time) is often not worth it.

The reason Go is successful is because it's easy for companies to use to solve production problems with teams of varying expertise. Its stdlib is well-featured, its ecosystem is good. There's generally one correct way of doing things. The same doesn't appear true in Rust. For example, an _incredibly_ common thing to do in production code is to make a web request. In Go, there is no need for debate, you use the stdlib. In Rust, you have to use a crate, which requires a decision to be made. Even worse is the async story, in Rust you have to decide whether to use Tokio or whatever. That burden is just not present with Go.

Btw this article should not be flagged and it's pathetic that people have flagged it.


> Programming is a means to an end, and the cost of using Rust (hiring, increased development time) is often not worth it.

I agree with this. I learnt Rust before Go, and using Go makes me feel like The Oatmeal piracy guy[1]:

"I'm not sure if I should use Go to write this HTTP service. I'd lose immutability tracking, I'd lose compiler-enforced thread safety, I'd lose the powerful type system, I'd lose the comprehensive error handling, I'd suffer from a million little papercuts, I'd have to use the weird date formatting system, I'd have to check nil pointers, I'd...

...oh, it's seven days later and I've already accomplished more writing networking servers and clients in Go than I ever have in years with Rust."

This isn't to say the points raised about Go aren't true. They are true, and if a better language were available, I wouldn't stand my ground and argue their benefits, I'd switch to it. The last comment I happened to post on this website is about how Go is insufficient without its army of linting tools [2]! Yes, I'm incredibly happy to have learnt both Go and Rust as their combination has expanded my skillset and the range of programs I'm willing to write tremendously. But if someone said to me "you should just use Rust instead of Go for your production services", I'd think the "just" was doing some incredibly heavy lifting.

An article that I'd like to see is one comparing the two languages for this niche (networking servers and clients), contrasting not just the language pitfalls but the third-party libraries necessary, the iteration speed, and the choices you'll have to make up-front. My guess is that the languages would be judged more closely together.

[1]: https://theoatmeal.com/comics/game_of_thrones [2]: https://news.ycombinator.com/item?id=30749921


I don't really use Go, I think mostly because I'm not in the target market, but this article's complaints (and some of these comments) actually got me thinking that I should take another look at it.

A long time ago, in a Haskell community chat, I saw someone dismiss Go with a pithy comment along the lines of, "Go isn't a programming language, it's a DSL for writing network services." I think I may need to re-assess that comment as actually being a really compelling elevator pitch for the language.

Armed with that perspective, I'm seeing why I wasn't terribly convinced by the article's specific complaints about Go. "Traditional IPC is a PITA and forces you toward talking over a socket? Well, yes, exactly. That's kind of the whole point."

Sometimes I wonder if we are all suffering unnecessarily because of our incessant demanding that all languages try to be all things to all people.


> Sometimes I wonder if we are all suffering unnecessarily because of our incessant demanding that all languages try to be all things to all people.

Programmers aren't. Programmers are building stuff and talking about that. Opinion bloggers are suffering for clicks.


I was struck by ThePrimeagen[0] saying that it took him 5x longer to write a game server in Rust than in Go—despite having significantly more Rust experience. They performed about the same (I think Go actually did better due to how much easier it was to get concurrency working?).

Personally I lean towards strict compilers (I suppose years of JavaScript has traumatized me), but 5x dev time is a big tradeoff! Of course this is just one data point, but it did seem worth mentioning.

[0] - https://www.youtube.com/watch?v=Z0GX2mTUtfo


My experience in writing a small side project in both (on the order of 2-3 KLOC) was that the time to a working project is significantly shorter with golang. The time to the correctly working project was about the same between the two.

Golang gets out of the way in me doing what I want.

Rust actively resists me doing things I will later regret.

Also, unexpectedly, I have gotten some positive comments on my C coding style after I coded some Rust.

All of this is completely anecdotal and personal experience, of course.


99% of people don't need "correctly" working projects.

Trillion dollar companies run on "incorrect" software.


Then, it's time to move on.

It is impossible to run "correct" software, but we can do better, maybe?


The problem with:

"I'm not sure if I should use Go to write this HTTP service. I'd lose immutability tracking, I'd lose compiler-enforced thread safety, I'd lose the powerful type system, I'd lose the comprehensive error handling, I'd suffer from a million little papercuts, I'd have to use the weird date formatting system, I'd have to check nil pointers, I'd...

None of the modern language do it beside Rust so every language are then bad?


I think the quote marks were there to indicate that this was walking through a hypothetical thought process that someone might go through. (It proceeds on to the next line after that, where you see the closing quote mark.) The gist of the whole thing was basically to say, "Don't make the perfect the enemy of the good."


Sorry, I don't get what you mean. Could you elaborate or re-phrase?


None of the modern and popular language have immutability, compiler enforced thread safety, powerful type ( debatable ), same for nil...

Java / C# / Python / Ruby so they fall in the same bucket as Go I assume?


Java has immutability and more powerful types than go. Also considering how easy it is to intermix jvm languages you could add in scala or kotlin for truly powerful type systems without null.


I've grown a little disgruntled by the hype surrounding Scala's and Kotlin's null handling.

For starters "without null" is a myth. They both have null. They have to; there is no other practical option. The JDK uses null all over the place, so you need to have null in order to talk to the JDK.

Now, they do still have mechanism to make null easier to handle. And they're both pretty impressive designs. (Especially Kotlin's, though I haven't tried Scala 3 yet so maybe I'm missing something wonderful there. Aesthetically, I just prefer "we're going to openly acknowledge it and tame it as much as we can" over "we're going to try to sweep it under the carpet.") But there's a sort of Amdahl's Law analogue hiding in that situation: the upper bound on how much practical null safety you can achieve is constrained by how much you can avoid relying on modules that were written in Java. And I know that's basically true of languages like Haskell, too, because you often have to rely on at least a little bit of code that was written in languages like C. But it doesn't preoccupy me the same way it does in Scala or Kotlin, where interacting directly with Java code is a much more everyday kind of affair.


Kotlin is quite explicit about nulls.

Kotlin code requires you to use Type? if the value can ever be null.

Java code that is annotated by @Nullable/@NonNull will automatically map to Type?/Type (and it is up of course to the developer to not fuck up their nullability promises.)

Java code that is not annotated is a Type!, and encourages you to be wary about what could happen.

The nullability story is miles better than Java.


If you enable nullness checks, Java is the same.


No such thing as nullness checks in Java. At best, your IDE is taking the annotations into account and giving you warnings. At worst, you have to run ErrorProne and have it yell at you.

Additionally, all Java code (including the one you wrote) is only optionally null checked. All Kotlin code _is_ null checked, no matter what.


ErrorProne is part of the compiler suite.


??? Absolutely not. ErrorProne is a Google project that is not integrated into javac, and merely acts as a plugin to it. To have ErrorProne running on your project, you need to:

- Know about it (first, big problem for many java shops)

- Integrate it with Gradle/Maven/Ant/yourbuildtool

- Enable the null checks because they are not enabled by default.

Compare this with "it's already in the compiler"


Had the same experience with Scala. Oh, Option types? Cool! Wait, why am I getting NPEs??? Oh, we're using some java library, nulls galore!


I've come to the conclusion that, for the most part, option types make no sense in object-oriented languages. There are exceptions, but they tend to fall into "proves the rule" territory. OCaml, for example.

Not just because of the null problem. It's also that option types push you toward a "conditional logic everywhere" way of doing things, because that's how you handle the options. That's all well and good and holy in a functional language, and perhaps even a procedural one. But it's the opposite of good object-oriented design.

To quote Dr. Mark Crislip, when you serve cow pie with apple pie, it does not make the cow pie better. It just makes the apple pie worse.


How does an OO language handle a case like "Do you want fries with that?" Without conditional logic?

BurgerWithFriesMeal subclasses BurgerMeal?

"Object oriented design", in the religious sense, is an obsolete 1980s fad that took a good idea (encapsulation of mutable state) to comical extremes.


You're sort of telling on yourself with that "in a religious sense" jab. ;)

The original idea of OO design was to strive to eliminate stateful idioms. Which is a slightly different idea than what we're used to. The state existed, but the point was that you were supposed to design your system so that objects didn't need to know - or even attempt to infer - information about other objects' state.

The whole intellectual lineage that includes pervasive use of explicit state querying and manipulation methods such as getters and setters could be characterized as a whole lot of procedural programmers collectively missing the point. It's right up there with when people over-use the State monad in Haskell, effectively doing their darnedest to Greenspun imperaive programming on top of a lazy functional language because they haven't quite internalized this new paradigm yet.


> it's the opposite of good object-oriented design.

So what is good OO design? NPEs? Nil checks?


I have yet to encounter an OO-first language for which Optional provides any real difference from nil checks. Often, it actually makes it all worse. Layering optional types on top of a system that allows any value to be nil tends to just produce a situation where there are more conditions you have to consider if you want to code defensively. As many as four:

  - nil
  - None
  - Some(nil)
  - Some(non-nil)
As far as how to do good OO design, ideally you try to avoid explicit branching whenever possible, and instead use dynamic dispatch to decide what to do. In principle, if you've architected things well, you should generally be able to avoid conditional branching.

An ironically useful example of how this works is Smalltalk's implementation of Booleans and conditionals. Smalltalk doesn't actually have an if statement. Instead, it has a Boolean class that defines three methods: ifTrue:, ifFalse:, and ifTrue:ifFalse:. Each takes one or two blocks, which are effectively anonymous functions.

And then the implementation is that the True subclass as an ifTrue: that executes the block, an ifFalse that doesn't, and an ifTrue:ifFalse: that executes its first argument. And the False implementation does the opposite.

This isn't meant to be an example of "look, OOP doesn't need conditional branching, just use {library implementation of conditional branching}," so much as a small, self-contained example of the kinds of ways that you can achieve conditional-style logic without explicit branch statements. A more real-world example might be something like having separate NotLoggedInUser and LoggedInUser classes that behave differently in relevant situations, rather than having an isLoggedIn field to have to keep checking at every use site.

The big thing working against us on this is that most the popular OO languages - C++, Java, Python, C#, etc - come from the same approach of trying to layer object-oriented features on top of a procedural core. In my not-so-humble opinion, this has been about as successful as more recent efforts to support functional programming by pulling a mess of functional features into existing OO languages. Technically it gets you somewhere, but the resulting language is not an ergonomic pit of success.


Probably a better example is #at:ifAbsent:, which is a place I've seen all kinds of faffing about with default retutn valures in languages without closures/blocks.


I was pretty skeptical of this and yes I'd rather not have null at all. In practice though I've found the boundary with Java for my scala projects to be very small. This is definitely a function of what you're building but there are a lot of great scala libraries so we rarely need to reach for java.


Yeah, that's absolutely fair, a greenfield Scala project can avoid a lot of Java nowadays.

But, at the other end of things, teams that were already using Java and want to start incorporating Scala don't have that option. And 10 year old Scala projects didn't originally have that option, and doing something about it now may be a lift on the scale of a complete rewrite.


Yeah good point. I would not enjoy adding Scala throughout an established Java project unless I could really compartmentalize it


Java has a library for compile-time annotations static nullness checks, so if you use that, null only comes from legacy libraries, not new code.


Does Javascript not exist?


When talking about language design, it's the first one to be kicked out.


Checkout Elixir, I think it's better than GO for a lot of the use cases GO handles.


Oh man. The fake ads on that first link had me rolling around. Have an upvote!


Haha, your comment on the weird date formatting rings very true.


I haven't used Go or Rust seriously, but have written some Go toy code. This part of your post struck a nerve with me. I modified it slightly, to relate to Go's error handling, for me at least:

> often it's not worth taking on that burden just to theoretically handle cases that rarely occur and even more rarely cause any problem. Programming is a means to an end, and the cost of [Edit] adding if err != nil to every line of code [/Edit] (increased development time) is often not worth it.

I basically like Go, I really want to like Go, but as a Python person who has used exceptions with good success for 13 years in HashBackup, I can't see myself adding an if test to practically every line of Python code, just to catch an exception that might occur once in a blue moon.

A lot of software is not so mission critical that lives depend on it. If that is the case, sure - add error checking to every line of code. But for a lot of software, IMO, it's too much work for too little reward. If something blows up in production in an unexpected way, sometimes that's okay. You log the problem, fix it, and it's fine.

I re-read the Go error handling page before posting, because maybe it's not as bad as I had initially thought. Nope, still looks pretty cryptic to me:

https://go.dev/blog/error-handling-and-go


> If something blows up in production in an unexpected way, sometimes that's okay. You log the problem, fix it, and it's fine.

as the person on call for such events, it's really not fine.

would you rather handle these errors upfront during development time or unexpectedly and uncontrollably, during runtime? having been on-call in one way or another for ~10 years, i know which i'd prefer.

after having used golang in production, i will never go back to using a dynamically typed language if i can avoid it. almost 0 thought or effort is required to handle errors correctly in go, and it's still possible to ignore them (just use `_`). not that i'd recommend ever doing that.


It’s a big assumption that you can even handle the error at the callsite, or that you will actually handle it correctly there, or just write some low-effort attempt because the overall picture is more important for now, but later on you won’t notice how it is not correct and it will just silently fail.

Exceptions are in my honest opinion better on every single front. Checked exceptions would be the panacea but Java’s version is not the best due to subclassing. But overall bubbling up exceptions is the correct thing to do — in most cases a problem can’t be meaningfully handled at the call site. Let’s say you want to read from a file during a HTTP request but the read fails n methods deep. There can be any number of other error occurrences and the only sane choice here would be to return some error code to the web client requesting the site. Why do you want to handle it n times instead of only at the goal?


consider this example - one using dynamic code with exception-based handling (ruby), and one using golang's more explicit error handling:

ruby:

  begin
    res = Net::HTTP.post_form(APIURL, ...)
    puts res.body
  rescue e => e
    # do error handling
  end
go:

  response, err := http.PostForm(APIURL, url.Values{...})
  if err != nil {
    # handle PostForm error
  }
  
  defer response.Body.Close()
  body, err := ioutil.ReadAll(response.Body)
  
  if err != nil {
    # handle ReadAll error
  }
  
  fmt.Printf("%s\n", string(body))
Now, for which errors do you handle? In golang, you can see clearly where errors may occur. In Ruby, it's unclear whether HTTP.post_form is even capable of throwing errors, much less what they are. For the record, here are a few of the many types of errors that can be thrown by the ruby code. Here are a few:

  Timeout::Error, Errno::EINVAL, Errno::ECONNRESET, EOFError, Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError, ...
there's no way to tell _where_ the error will even come from - you might get a Net:: error, you might get a Timeout:: error, hell you could even get an Errno::! What most programmers wind up doing is handling no errors at all until they occur in runtime - or wrapping every single "suspicious" statement in a catch-all begin/rescue block, even when it's not needed.

In golang, each function capable of returning an error simply returns it, and you must handle it at that point in time. It is very straightforward. In my experience, it results in much more reliable code. In Ruby, you have no idea what's coming. Do you see what I mean?


> there's no way to tell _where_ the error will even come from - you might get a Net:: error, you might get a Timeout:: error, hell you could even get an Errno::! What most programmers wind up doing is handling no errors at all until they occur in runtime - or wrapping every single "suspicious" statement in a catch-all begin/rescue block, even when it's not needed.

Been programming Ruby for 8 years and have never seen anyone do that, so no... If that block of code can really throw so many different types of exceptions (usually - it can't) you can always catch StandardError.


I’m not familiar with Ruby, but in java you can just specify the try-catch block’s scope as explicitly as you want.

``` try { var response = http.postForm(APIURL,) } catch (Exception e) { # handle PostForm error }

try { var body = ioutil.ReadAll(response.Body) } catch(SomeSpecificExceptionType e) { # handle specific exception differently } catch(Exception e) { # run for every other kind of error }

If a given method is defined as `void postForm(…) throws IOException` you have to handle the exception at the call site, or mark the containing call itself with a similar throws clause.

I really don’t see anything not handled by these. Also, the defer part can be done by a try-with-resources construct that will clause the resource in every case, whether exited without exception or with one.


For reliability, the absolute best discipline I've ever experienced, is "Either handle the error at (or very close to) the callsite, or crash the process." But only if you make sure that everyone on the team understands that (A) this is the only way to do it, and (B) there is no other way to do it, and (C) you will do it no other way.

I think because it sets up the right psychological incentives. Because almost any option other than those two ends up looking like, "Hmm, I don't know how to handle this, but maybe someone else will, so let's bubble it up and hope they do," in practice. It's just the way we humans are.

And that sets up an intractable moral hazard situation. It creates this middle ground where two different owners of two different parts of the code can finger-point and blame and try to pass the buck. And, knowing that (though probably only unconsciously), they won't just become sloppier about handling errors. They will become sloppier about allowing errors to happen in the first place, and doing things that make it harder to handle errors. And they won't even know they're doing it.

That's what I think of when I read your hypothetical, "Let’s say you want to read from a file during a HTTP request but the read fails n methods deep." That sounds to me like code that's been structured in a way that, on this team I was alluding to above, probably wouldn't have happened in the first place and definitely wouldn't have made it past code review. The pushback would be something along the lines of, "Why on earth are you doing both file and network I/O within a single business operation but at two very different depths in the call stack? Did you even notice what you were doing here?"


> For reliability, the absolute best discipline I've ever experienced, is "Either handle the error at (or very close to) the callsite, or crash the process."

Here's a counterexample from HashBackup (I'm the author):

A filesystem is being backed up. Some weird error occurs, let's say it tries to read an extended attribute and gets some goofy error that raises an exception and it's not in a try/except. That error bubbles up to the try/except for "save a file", prints the exception message, and continues by backing up the next file.

Is it more reliable to crash when reading an extended attribute, aborting the whole backup? Or is it better to just tell the user about the error, finish the backup, fail at the end of the backup with a non-zero exit code, and report it in an email?

At the time of failure, the only way I can see that the error could have been handled at the call site would be to return an empty extended attrbute. To me, that's more like the "silent but wrong" solution. And there are many of these situations for saving a single file: get the flags, read the extended attribute, read the permissions and times, figure out if it's sparse, etc. Instead of having error handling at each of these steps, they can have no error handling and just raise exceptions and the high-level "save a file" handler will do everything.

Of course, along the way there are some low-level try/except blocks around code that needs cleanups, like:

  fd = None
  try:
    fd = os.open(...)
    do some stuff
  finally:
    if fd != None:
      os.close(fd)
But you have the same thing with defers in Go.


I just gave you an example from the top of my head. Here is another more realistic one, which occurred to me during the time I wrote a toy JVM: a Java class file contains a constant pool with different kinds of types. During the loading process this pool can be references by other entities as well, but they require the necessary type. Assuming verified byte code, this will be the case, but if we care about verification as well then you will quickly get into the situation where you simply can’t handle “during the loading of this class’s nth method, one of the constant pool references were of incorrect type”. It can’t be handled at method loading (or even more nested), and panicking is not the correct behavior (you only don’t want to load the given class). So you have to manually bubble it up for no benefit.


I could believe that, but implementing JVMs is such a very specific use case, far removed from what most programmers do day-to-day. Not just because it's a VM. Because you're implementing a pre-existing specification, so you're not at liberty to make your own design decisions around something like classloader semantics. It feels like a red herring example to me. "Here's how we should think about dealing with error conditions in 2022." "But what if I've got a spec that forces me to do it 1994-style?"


There is nothing inherent to JVMs here, it is just the all around most common error type. It simply don’t make sense to handle many type of errors at call site, because it misses the big picture and for these, return types are not a good fit.


So, the idea is basically that of the impureim sandwich: push everything that can fail out to the periphery. If it's difficult to handle errors at the call site, it's a sign that the call site is in the wrong place.


With the basic idea that you should never crash due to something outside your process call stack (whether that be disk full or network problems or bad messages or bad values in a database) and always abort immediately with an email and stack trace to yourself or equiv on internal logic errors.


But people write "low-effort attempts" at exception handlers all the time. So using exceptions instead of error values doesn't actually change the situation.


Defaults matter. Exceptions give me the question whether I want to worry about this piece of code here, or just go on and be reminded that it is actually important at runtime with an unmissable runtime error which has exact character number for the origin of the mistake. Even Java’s checked exceptions can be just added to the method signature.

(Ab)using Result types without good syntax for dealing with the very common case of “handle it higher up” (Rust’s ? macro is ok, not perfect but it is a much better compromise) is coming from a wrong angle imo.


> If something blows up in production

The problem is if it doesn’t quickly blow up, but instead silently corrupts data or causes other problems down the line that are hard to backtrack to that specific missing check.


But because exceptions bubble up the stack frame, there can be no missing checks. I'm not suggesting things be coded as:

  try:
    do something
  except Exception, err:
    pass
If a piece of code is has a try/except, then it's because there is the expectation that it might fail and certain kinds of failures can be handled. If a failure is not one of the expected failures, then do a raise and let the exception go higher up. It's either going to hit a handler in the main program or will exit to command level. In either case there's a stack trace to see where the problem occurred. Exceptions tell you exactly where things blew up, whereas the "if err return" paradigm only does that if the test at each level adds identifying information.

I've seen some Go stack traces. Talk about hard to backtrack: the ones I've seen go on and on. I understand it's because there are multple Goroutines running and each one has a stack trace, but they look pretty daunting to me.


I was responding to your scenario of having to “add error checking to every line of code” due to the absence of an exception mechanism, and your assertion that “it's too much work for too little reward”. My point was that in that situation (no exception mechanism available) it’s often irresponsible to not do that work, because the possible consequences are unpredictable. I fully agree that having an exception mechanism is the way to go, so that adding error checks every other line isn’t necessary anymore.


>you use the stdlib

* First you construct a request, and check the error on that

* Then you "Do" the request and check the error on that

* Then you check the status code (you did check it, right?)

* Then you deserialize the response and check the error on that

* Then you close the response body (you did remember to close it, right?) and check the error on that

Actually making an HTTP request with Go stdlib is a many-stage process and it is very easy to screw up or forget one of the steps. I see it all the time. Actually I have seen outages related to people being too zealous and reporting errors related to closing the response body on otherwise successful requests.


> Actually I have seen outages related to people being too zealous and reporting errors related to closing the response body on otherwise successful requests.

I kinda get it though, because the compiler or linters will show that as a warning or error going "bruh you forgot to handle this error", and as a perfectionist one wants to get rid of all of those.

I mean IMO those should be logged anyway, if only so you get some data on how often it happens, if there's anything that can be done about it, and if it's harmless, to ignore the error - but make it explicit.


The content is mostly ok, but the title suggests that there's some obvious alternative to Go that we should be using. If he's implying it's Rust, then he's totally disconnected from reality.


It's buried in the article, but I think the suggestion is "use almost any language other than Go" rather than Rust specifically.

The takeaway - if you gloss over the ranting and look for the good bits - seems to be that you should choose a language that handles a lot of the boilerplate for you (e.g., no verbose error handling) and has FFI.

It's not a bad argument, and it's making me think about how and when I use Go. For that, at least, it's worth reading.


It's really not, and it's even saying so explicitly in the article.


Definitely.

Go and Rust both have strengths and weaknesses.

And I think they both have a love/hate dynamic because they make pretty strong choices in their own ways, and so people react strongly in response. Personally I'm a fan of both.


> For example, an _incredibly_ common thing to do in production code is to make a web request. In Go, there is no need for debate, you use the stdlib.

And yet, Go's HTTP client doesn't have a good default [1] because of zero values, which are argued harmful in the article.

[1]: https://medium.com/@nate510/don-t-use-go-s-default-http-clie...


> The better alternative to Go is Rust

Nope, a better alternative is Java/C#/Kotlin/etc. Those offer sum types, async programming, while being more productive than golang, and provide superior tooling and a superior developer experience.


Why not Node? Or Typescript if you really have to have types? Or even plain old PHP/Ruby (for people that just use Go to build web backends) - doesn't Kubernetes kinda solve scaling?


I agree with you, however I think it's even simpler than that: the author is comparing Go to rust, but it's not comparing it to the places where it shines, that is, where Java, ruby, js, python are used.

Now suddenly we go from a poor type system (Java) to a decent one in Go (this is my personal opinion). Or from no type system to SOME type system. On top of this, we are getting all the benefits of a compiled language.

Essentially this is looking Go as a system language, while I think of it as an application language.

Aside from that, the author is right in some ways.


> The better alternative to Go is Rust

No, the better alternative is thousands of different languages.

HN is just hype-driven as usual and can see only Go and Rust.


> "Even worse is the async story, in Rust you have to decide whether to use Tokio or whatever."

I think this is going to change. I couldn't find the relevant blog post now, but I believe to remember there was an initiative to provide a standard async runtime.


No. Rust may provide some small async runtime for tutorials etc., but it'll never provide a rich async runtime like tokio because different people have different requirements from their runtime and Rust wants to satisfy them all.

What is planned is to standardize the API: that is, provide common traits for IO, tasks, etc. so libraries can be runtime-agnostic and you can change your runtime by only touching Cargo.toml (hopefully).


> The reason Go is successful is because it's easy for companies to use to solve production problems with teams of varying expertise.

It would've never got to where it's at if it wasn't for Google, that's the most important reason why its successful.


> increased development time

In my experience it is only increased initial development time.

I find that initial development time is frequently conflated with development time overall.

So obviously worse is better languages will be preferred.


I agree with this overall.

It seems that C is a language/compiler/toolchain combo that lets you shoot yourself in the foot, but gives you enough access to stuff to be maximially performant in a random (i.e. not specialized) use case. (C++ is in this camp too).

Rust is a language/compiler/toolchain combo that tries its best to not let you shoot yourself in the foot by presenting those footguns for you to fix up front, without giving up much of the access to stuff (C++ tried some things in this camp like destructors and smart pointers. GC is also something that's in this camp)

Golang is a language/compiler/toolchain combo that lets you shoot yourself in the foot in some circumstances, and does not give you enough access to be maximally performant in every random case, but rather it seems to posit to give you opinions that will get you really, good performance in most random cases (if you need to tune the GC, for instance, you're probably worse off, like here: https://blog.twitch.tv/en/2019/04/10/go-memory-ballast-how-i...). Meaning it's making the tradeoffs of upfront complexity vs runtime issues, and Tim Toady vs The One True Way for you, because in the general case those are the most optimized tradeoffs. I don't disagree, especially when the closed-world ecosystem is good enough to not need to reach out to external tools whether those are via cgo or in the build toolchain.

In general, I think that if you reach the point where Golangs admittedly major warts are hindering your progress you're doing better than most companies, so its succeeded in not getting in the way of progress at least until that point.

In particular since the article keeps comparing Golang to Rust, for personal projects I do like the correctness of Rust, but some things are frustrating, like async being basically unusable without Async Drop, an uncertain future for completion apis, and apis that really want HKT but can't use them (yet?). I having to make up a lot of opinions that Go makes for you adds risk and uncertainty to a project where the most likely failure modes are not, in fact, those opinions.

I'm excited for the future of Java, with Loom and Valhalla coming to address as what I see as two core problems of Java in particular and other languages in general. I'm also excited for the present of js/node.js/maybe Deno. typescript has become good enough that I also think it's a really good competitor to Golang in the "just write code" arena, especially since there's significant synergy between the front end and the back end to help with build tooling, validation logic, and programmer expertise.


Flagging this post strikes me as shameful censorship of an unpopular opinion.

You may say it's the snark/anger/frustration that got flagged, but I suspect it would not have been flagged if the topic were different.

Presuming the author is making bad-faith arguments for internet blog points goes against the spirit of HN. I prefer to draw my own conclusions, thank you. I normally expect HN to take the higher ground with calm and reasoned counter arguments of the content but not today I guess.


> You may say it's the snark/anger/frustration that got flagged, but I suspect it would not have been flagged if the topic were different.

HN has had plenty of threads about Go over the years. What's different here is that there was just a big Go flamewar yesterday (https://news.ycombinator.com/item?id=31191700), from the same site. Having another big Go flamewar the next day is a really bad idea, because then on top of shallow ragey flameposts (boo) the thread will fill up with fluffy ragey metaposts (double boo). More explanation here: https://news.ycombinator.com/item?id=31207126

"Shameful censorship" is one way to put it, but front page space is the scarcest resource that HN has (https://hn.algolia.com/?dateRange=all&page=0&prefix=true&que...) and the amalgam of upvotes, flags, software weightings, and mod actions is what determines which stories end up / stay there vs. which stories fall off. This is the cycle of life on HN—it's always been that way and always will. One psychological effect is that everybody feels like their favorite topic is under-represented (or shamefully censored!) and in a way everybody is right.

I've often joked by adding "even Rust hackers feel that way" but maybe that's not the best line to use in this case :)

p.s. I feel like it's been a long time since HN had a passionate explosion about flagging and censorship (side note: ctrl+f misinformation...yup, that too) around a programming language. In a way it feels like a healthy sign. Like a family fight at Thanksgiving - at least it's about, say, a board game or something.


This strikes me as very odd. The post yesterday is about a 2-year-old article. This post is about a brand new article, from the same author, written more or less as a response to all of the responses to the original article over the past 2 years.

If a flamewar is a problem, then that's what moderation is for, including potentially locking. I know you've posted comments on divisive articles before cautioning everyone about not wanting the comments to devolve into a flamewar, that would have been a great first step here.

But instead of doing that, you're saying that because of the old article popping up again yesterday and rehashing the same old flamewar, you've chosen to suppress the author's own response. I would think that the old article popping up yesterday makes this new post especially timely and even more important. It's not a rehash of the old flamewar, it's the author's own words with a well-written and fairly comprehensive response to the common criticisms, and it's highly relevant to the HN audience. And especially in the context of the discussion yesterday it seems a good idea to ensure visibility of the author's own response so anyone who saw yesterday's flamewar can see this. It took 2 years from the old post for the author to write this response, I'm pretty sure you don't have to worry about having a third post tomorrow.


The guiding logic here is 'it would be boring to have a discussion of X on the front page every day'. For many X, there's infinitely many things to say but the front page is finite and has a goal of not being boring. HN's been moderated like that for ages and it seems to work reasonably well.


I don't think it's necessarily the HN moderation team's job to tell us what we should and should not find interesting. It's a crowdsourced news aggregation site and discussion forum, not a magazine with an editorial board.

The sheer number of upvotes on this article, despite the attempt at suppressing it, is a clear indication that, regarldess of what dang thinks, a lot of people in the HN community think that something that is most definitely not boring and worth reading has been said.

I'm inclined to agree? I personally do tend to agree that golang in and of itself is kind of a boring horse that's been beaten to death at this point. But this article was interesting, anyway, because it had an interesting and thoughtful perspective on what kinds of things matter when choosing a language ecosystem more generally. One that I, as a hobby language designer, was glad I read. Even the bits I don't think I agree with. Even some of the bits that seemed unnecessarily invective.


I don't think it's necessarily the HN moderation team's job to tell us what we should and should not find interesting. It's a crowdsourced news aggregation site and discussion forum, not a magazine with an editorial board.

That's fundamentally not how HN works, though. It's neither just crowdsourced nor just editorially curated. This thing ends up being a dupe fairly straightforwardly, it's not some weird edge case. Any big front page discussion naturally has a lot of people interested in keeping the discussion going.


I don't see how one can say that this ends up being a straightforward dupe, unless you're just observing that it's criticism of Go by the same author and with a similarly provocative title.

I admittedly haven't read "Mr Golang's Wild Ride" since it first hit HN a couple years ago (and I don't really intend to, I have my doubts that it would be an edifying use of my time) but, based on what I remember of it, this new article is a much more nuanced and thoughtful position on the subject that definitely adds a different perspective to the conversation. It focuses on higher level questions about how one designs (or chooses) a software platform and ecosystem, where the original one was a fairly shallow fisk of language design issues. Wasn't it mostly drumming on syntax?


I think you're getting somewhat hung up on the content of the piece and the moderation in this case doesn't have much to do with it. Critique pieces of popular languages are themselves popular and get frequent and regular coverage on HN. This one had one significant discussion yesterday, last year and also the year it was published. That's a pretty good run and it will undoubtedly appear again, along with its update. But not on the front page for two days straight because almost nothing gets to sit on the front page for two days straight, that mostly being the point of a front page of daily links.


I really don't see how "two critical articles about a particular programming language on consecutive days are flamebait and detrimental to the site" can be squared with the handling of US political and COVID articles over the last two-three years. Programming content should be the bread and butter of the site, and popular language critique is par for the course on any hacker-themed board. And tomorrow we'll have moved on to something else, unlike the other topics I mentioned.


two critical articles about a particular programming language on consecutive days are flamebait and detrimental to the site

I'm not sure who you're quoting here but it's not me.

US political and COVID articles

These also get moderated quite a bit but it's a little different with ongoing hot topics - many more submissions, angles, etc. One person's take on Go, however interesting, is not an ongoing hot topic. Plus it's had a pretty good life on the site!


It was meant as a summary of what you and dang seem to be saying, rather than a direct quotation; I probably shouldn't have used quote marks in this context. Apologies for the confusion.


No, I'm more saying that the treatment of this article, and dang's explanation for it, seems to suggest a weirdly arbitrary and paternalistic mindset on the subject.

I'm not sure what "weirdly hung up on the content of the piece" is supposed to mean. Isn't the whole point of Hacker News to share and discuss interesting content? If it's not about digging into full, long-form content, then we might as well take this to Twitter.

I'm also not sure what you mean by "this one had significant discussion yesterday, last year, and also the year it was published." The article was posted on Friday, April 29, 2022 - today, to be precise.


What I mean is that you can figure out the logic of this kind of moderation without litigating the quality of the pieces submitted. As to the 'significant discussion' bit, it's basically the same article - the first article has had multiple big discussions on HN. The second article is a response to the most recent such discussion, from yesterday. It's also framed, in some ways, as a direct response to people who said mean things about the author on HN. This is a true and righteous use of blogging but makes for a poor HN post.

A really simple but slightly different way to think of it is, if you write a piece and it gets good traction on HN (where you've also participated in the discussion, in this specific case), you don't usually get to put a megacomment reply on the front page the next day as well. There are exceptions, of course but 'things someone likes and dislikes about a popular programming language' are generally not the exceptional type of thing.


But at this point, we're no longer debating whether TFA is "a dupe fairly straightforwardly"; you've now moved the goalpost quite far from where we started.

Perhaps you didn't personally get much out of the article. I did. I didn't love the invective aspects of it very much, either, but there were still some interesting take-aways and new things to say. Apparently enough so that 593 people so far thought it worthwhile to click the "upvote" button, which is really quite a staggering number when you consider that it had been banished from the front page. When you've got that many people seeing value in it - that's really quite a lot more than most of the rest of what's been on HN today - even if you don't personally see why, maybe it's enough for you to simply not see why, and leave it at that.

And that is what I am getting at. I can see the logic of the moderation just fine, but I think that the logic in question is wrong and perhaps even edging toward paternalistic or mean-spirited. And my interactions with dang on it elsewhere in the thread strike me as being mostly just defensive. Which doesn't really jive all that well with the stated purpose of elevating the quality of conversation on HN. I'm more impressed with what the broader community has done: largely looking past the flamebait, eschewing "shallow dismissals", and instead choosing to "respond to the strongest plausible interpretation of what someone says."


you've now moved the goalpost quite far from where we started

I don't follow. You weren't familiar with the rules of HN dupery and I've tried to explain them. That's not moving the goalposts. Followups are almost always dupes. Metaish follow-ups the very next day dupely so.


A rule and its implementation are two separate matters.

With all due credit to rmasters, "I suspect it would not have been flagged if the topic were different."


Well, yeah, that's your suspicion but it is not an argument, it's just a suspicion that something nefarious is going on. I don't think you've really responded to any of the explanations of why HN works this way. That doesn't mean the way HN works is right but you have to bring something more to it than aspersions if you want to argue for change.


"nefarious"? "nothing more to it than aspersions"?

Please don't strawman me like that. If you're going to make "the rules of HN dupery" the place where you want to make your stand, then this seems like a peculiar response. These rules for HN dupery are not actually published anywhere outside of HN mod team comments when debates like this come up. By contrast, though, the published commenting guidelines clearly state "Please respond to the strongest plausible interpretation of what someone says, not a weaker one that's easier to criticize. Assume good faith."

Which, I realize that this whole tangent is then in contrast with the very next guideline in the list, which exhorts us to "Avoid unrelated controversies and generic tangents." But, since HN lacks the meta-discussion channels that other comparable community sites have, these sorts of frustrations can't really do aything but boil over into public every so often, so I'm self-consciously allowing myself the conceit. In my defense, I've also been following and engaging in what I thought was some of the more interesting HN discussion I've seen in a minute. Including having my opinion on a programming language and its community go through some positive changes. So I do somewhat feel, then, that HN moderation deciding to flag the article and then bury it on the 2nd page because they think it's just a flamewar is tacitly an unfair accusation against which I must defend myself. And, frankly, the alternative defense that it's because it isn't interesting comes across as dismissive and condescending.


Many of the rules of HN aren't published in a straightforward list; you learn them by following the log of moderator comments. That, too, has been has been explained innumerable times on HN: it's a common law system, not a civil law one, because if you build a site for nerds around a rigid set of enumerated statutes, the nerds will spend most of their time looking for clever loopholes (I'm not disparaging them; I'm one of them).

From the way you've written on this thread, it seems pretty clear that you're not the kind of message board nerd that makes 'dang's comments a daily read. That's fine! You have to be a pretty extreme nerd to do that, and there other, probably better things to spend those nerd points on. But you should take 'pvg's word for it on this stuff. He's not messing with you: he's trying to explain to you how the site works.


I learned a great deal from the article. Thankfully I discovered it from twitter. If flame wars are the issue, then the thread should be locked, rather than pulling it from the front page. Really disappointed in this move.


> Having another big Go flamewar the next day...

I haven't read all the comments on this one yet - there are quite a lot of them already - but reading this makes me think that perhaps we don't see the same comment section. (Perhaps because I'm not tasked with moderation, so I don't have much reason to go look at the 2nd page.) They've mostly been very thoughtful and balanced. It strikes me as some of the highest quality discussion on the subject of Go that I've seen on this site in years. It's a shame it was flagged and then buried on the 2nd page. A pinned comment reminding us not to get our hackles up in response to the author's abrasive style seems like it would have been plenty sufficient. I fear that, in your haste to head off an anticipated flamewar, what you've actually done is suppressed a potentially healing example to the community that it really is possible to have a mature conversation about Go.


I don't have the impression that interesting technical discussion about Go has been particularly scarce on HN over the years? But if you think that today's thread is different enough from yesterday's thread to be significantly higher-quality and not just generic (i.e. about something specifically interesting in the OP, rather than just another generic discussion of Go, even if it's a good generic discussion of Go), then I'd be willing to take another look - in that case the best thing would be to link to the subthreads that you think make the best case for it.

The and in the previous paragraph is important, though, because a core moderation principle is to de-emphasize generic discussion (and follow-up threads, and repetition generally) in favor of significant new information. Past explanations on all that, if anyone cares:

https://hn.algolia.com/?dateRange=all&page=0&prefix=true&que...

https://hn.algolia.com/?dateRange=all&page=0&prefix=true&que...

https://hn.algolia.com/?dateRange=all&page=0&prefix=false&so...

https://hn.algolia.com/?dateRange=all&page=0&prefix=false&so...


If you'll excuse me for not taking the time to gather hyperlinks, I think just scrolling down would suffice. Basically any of the next-most-highly-ranked top-level comments seem like decent candidates to me.


It's not clear to me that the discussion isn't still rather generic, but ok - if you or someone else wants to suggest an accurate, neutral, non-flamebaity title, we can give this thread a second chance.


I appreciate the extra context. For what it's worth, I was not aware of the previous discussion and I just thought it was an interesting post. (I really don't have any feelings about golang one way or another.)

I can appreciate your point about having limited resources to moderate posts that have a track record of generating big flamewars. But I didn't get the impression from the comments (many being ad-hominem) that the post was flagged for that reason and my use of the word "shameful" was directed at those comments.


As someone coding in Go (and having doubts about the language) I find articles like this professionally valuable.

They don't have to be correct, they just need to provoke meaningful discourse, which for me means crowdsourcing the insights of hundreds of fellow devs.


Yes. The problem here is that there was a big one of those just yesterday. HN does poorly with repetition, and throwing in the indignation aspect and the meta aspect (can you believe what an HN commenter said yesterday? the nerve!) guarantees that the thread will get high and go crazy. None of that is intentional, but it's a well-known failure mode, so the flags in this case were helpful. We've taken the [flagged] stigma off the title above, so as not to rub salt in any wounds.

The system has checks and balances to prevent such things from dominating discussion here. (Flags are part of that system; so are software bells and whistles; so are moderators). If we didn't have those, the front page would consist of nothing but sensational flamewars and endless towers of meta!


> We've taken the [flagged] stigma off the title above, so as not to rub salt in any wounds.

Sending it to page 2 when it's only 3 hours old and has more upvotes than almost everything on page 1 /and/ removing the [flagged] marker feels weirder to me than not doing anything, but eh.


The ranking aims for interestingneses, not points so it makes sense to rank down a discussion of the merits Go a day after the front page has had a long discussion of the merits of Go. Taking off the flagged helps with the 'why was this flagged' meta (a little late now but still) since fewer people assume there is something wrong with the post, other than it happening to be a dupe on HN.


There's nothing I can say about "this is not actually the same article" and "the two comment sections do not say the same thing at all" that hasn't already been said by many other HN users in response to this moderation thread, so, I'll leave it there, still disappointed.


I haven't read them all and it's not wrong that they aren't the same article or the same discussion but it's HN-wrong. It's definitely disappointing if you have a big J. Winnfieldean 'allow me to retort' lined up but it works that way for pretty decent, time-tested reasons which I think have also been explained in great detail in the various moderation parables and proverbs.


Is there anything that can be done the next time the old 2020 post goes FP, to direct people to consider the 2022 followup as well? Or is that burden of “seriously, stop rehashing 2020 content instead of keeping up with the discussion” exclusively the author’s to bear?

Given the options I know of today for authors, if they’re still reading comments here, I’d recommend they replace the 2020 post with a redirect to the 2022 post, and include the 2020 post at the end of it fully intact. At least that would ensure the flamewars cycle on the complete conversation and not just half of it.


I agree. The signal to noise ratio of these "Rust vs Go" post comments is so bad they border being mostly a pile of anecdotes.

Also not meant to diminish the blogger but if you check their posts, it almost seems they feed on Go flamewar.

I could read every one of the 443 comments and still come out with zero knowledge gained because that's the kind of comment these posts incentivize.

Startups were built with less man-hours than what was collectively wasted on this thread.


I am also surprised that a reasoned discussion like this gets flagged while comments calling it a "shitpost" are not.


It's like this: when the input is a soup of reasoned discussion plus sensational flamebait, the flamebait will always dominate, and will always determine the output. Sad, but reliable.


Because people learn to cling emotionally to hyped-up topics.

Any criticism of sacred icon is taken like an aggression to the reader's sense of self.


[flagged]


What's "inappropriate" about the post? I for one wish that we had more posts like these instead of typical stuff that has been getting to the front page lately.


[flagged]


That post also got flagged initially FWIW.


I've used Go and Rust professionally and in side projects, and I had used Go first before Rust. When I first used Go, I was like "oh wow, this is so simple and easy", and I didn't realize that I was putting up with the language. Learning Rust was relatively harder, but once I did and wrote some non trivial programs in Rust, it was like a pathway in my brain opened up and was previously blocked, and then when I went back to Go, I was painfully aware of issues that I the programmer had to keep in mind (or write a LOT of boilerplate code to keep track of). Issues that Rust's type system just solves.

The way `nil` can seep into your codebase in Go and how bad the FFI is in Go will prevent me from ever choosing it for a project going forward. And I personally would not feel confident modifying Go code written by someone else, and would not feel confident accepting PRs into my Go codebase unless I understood every line inside and out.

Rust is a breath of fresh air in that regard.

All that said, I think the author here is idealistic in a certain sense. In the scale of "solving a problem by hand (or using Excel/a proprietary tool etc)" to "writing a computer program to automate it", both Go and Rust are very close to each other. And once someone learns Go and knows it well enough, the incremental cost of learning Rust or even thinking about the problems Rust solves for you becomes not worth it. I think that it's sad that this is the way it works, but that's just how it is. It's easy for settle for a local optima like Go when taking into consideration family, pets, salary, time, effort etc.

I do think on a long enough timescale, programmers will eventually move to a "better" language. But in my opinion, that time scale exceeds the lifespan of a human :)


I will say that playing around with Rust was an enjoyable experience, but it still has some warts where I think it's not quite ready for serious work yet (even though serious work is being done with it).

These days I find myself leaning heavily on either Haskell or Elixir/Erlang's ecosystem (with a preference for the latter). Or JavaScript (there's just an order of magnitude more jobs)...


I find it difficult to see a standard where Rust is not ready for "serious work" but Haskell is.


I can install a working Haskell toolchain with my package manager instead of the farcical `curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh`.

If you're an automation-oriented kind of person like it's my job to be, setting up repeatable toolchians based around the above is a total crock of shit.


Rust/rustup is in every package manager like ever. As someone who is "automation-oriented" you sound like you don't have the faintest idea what you are talking about.


Which package manager do you use that doesn't have rustc and cargo packaged yet?


If you think this is one of your stronger arguments, I think my point has been made.


Getting this right should be table stakes.

Every non-Rustacean who has suddenly had Rust forced into their workflows asks for this to be solved, specifically, and the Rust community keeps digging its heels in.

Haskell has its warts but it's not 101-level shit like this.


"Getting this right" is a matter of opinion, and either way, rust can be installed a variety of ways. Your argument is literally nonsensical and demonstrates a seriously arrogance and lack of familiarity with what you're talking about.


What is your threat model that isn't solved by some combination of a rust-toolchain file and using your package manager (nix or whatever) to install rustup?

If you want to isolate your build machines from the internet entirely, you're either going to use a hermetic build system and have some equivalent of vendoring your compiler, or manage your own internal package repository in which case you can just add your own Rust + Cargo build to it.

If you're paranoid about building the Rust compiler from source, you can even put in the effort into bootstrapping your own lineage. But given that you're ok relying on your package manager for Haskell, it seems like this isn't a huge problem for you.


What did you think those warts were?


I use Rust for just about everything and I can definitely think of plenty of warts, but none of them make it "not quite ready for serious work" for my definitions of "serious work". I guess my point is that I'm curious what serious work this user is doing that Rust is unsuitable for - that kind of information is useful for language evolution, among other things.


> I do think on a long enough timescale, programmers will eventually move to a "better" language. But in my opinion, that time scale exceeds the lifespan of a human :)

Zig exists and is here today.


I didn't care in the last post and I don't care about this one either. I care about my productivity, I care about my team's productivity, and I care about getting stuff shipped. Those are the things I care about, and go works great for that. If you care about those things too, and you're using go, you shouldn't stop using go.

My whole career people have been telling me to stop using languages or tools I've been productive with. I've built successful companies where everything was written in python, the whole time people on HN telling me how I was using a lowly language because of things like whitespace significance or strings that were not unicode by default.

If you care about other stuff, fine. If you don't think go works for you, don't use go. Just stop telling people who are using go (and other productive languages) to stop using them because of obscure language design issues or obscure API choices that people rarely encounter day to day. That isn't what matters to most people, and it's actually bad advice.

The problem is that there are a ton of less experienced people reading stuff on HN (just as I once was) who will take this to heart but have nothing actionable to gain from it, except to think they're a bad developer using a bad language. They aren't, and they're not.


I use Go. I'm not a Rustacean. I've also used a whole bunch of things that are not Go.

In reading this article, I'm finding myself agreeing with 100% of the author's criticisms. I've seen every specific problem mentioned be a thing that bogs companies I've worked for down and erode productivity. A lot of time the ops peoples' (aka: my) productivity specifically.

I haven't worked at a single company where teams of developers using Golang have been able to get the basic networking stuff right.

"Why are my TCP connections not closing? Why am I encountering port exhaustion?" Go's frustrating inability to inter-op matters quite a lot at the end of the day. GRPC and protobufs are f'in messy and full of footguns.

Thing is, I've been around the block. I know that these problems don't have to be problems. We have a tremendously bad tendency in this field to join cargo cults.

When looking for my next gig, if the company is big enough, I'm likely to start seeing Go as a negative, unless they've got that Tailscale kind of expertise.


> GRPC and protobufs are f'in messy and full of footguns.

Distributed data modeling is inherently messy and IME gRPC is one of the least messy, most scalable solutions to it. Or do you have a better alternative?


protobuf has issues with optional fields, as was pointed out in the post. Couple that with a language with a weak type system like golang (no sum types), and it's very verbose and slow to develop in. Targeting better languages helps alleviate the latter.


Ok, what's your alternative?


Because all protobuf fields are optional, they should be translated into optional fields in the target language (e.g. Optional<T>).


> "Why are my TCP connections not closing? Why am I encountering port exhaustion?"

So… why?


"Why are my TCP connections not closing? Why am I encountering port exhaustion?"

This has nothing to do with Go. You're implying Go has a bug in its TCP implementation which I assume is false.

Networking works just fine in Go and it's actually easy to use.

https://pkg.go.dev/net

Edit: I'm getting downvoted but please share with TCP issues in Go.


The author of the blog post literally covered it in the article he wrote two years prior that's linked in the first sentence.

It's not "TCP issues in Go" it's "Go leaves you to figure these things out for yourself and write bad code that doesn't work if you don't thoroughly understand its gotchas."

Also, if you've been following Go over the years, you'll know that there's basically _always_ open issues (https://github.com/golang/go/issues/39063) in net & net/http about how Timeouts get mishandled and connections end up not being closed.

Cloudflare even had to write a whole (now old and outdated as hell) article explaining how to "do it properly" https://blog.cloudflare.com/the-complete-guide-to-golang-net... so that you don't footgun yourself.


They really need to add a deprecation note to the default http server and client. I have seen SO many people trip over this.


Hmm not really, the only thing is the default http client that has no time out which is the case in many languages. The only issue I had was about idle connection and DNS resolution.

And the ticket you show does not show any issues on the Go side.


> You're implying Go has a bug in its TCP implementation which I assume is false.

No, the parent is implying that Go's TCP implementation is easy to use incorrectly. Specifically in ways which cause the aforementioned issues.


I need examples, I used it for TCP/UDP and HTTP and beside the gotcha that clients have infinite timeout I don't see anything.


Read the article maybe?


I believe that you are perfectly productive with Go, the article hasn't claimed otherwise.

I used to be quite productive with PHP. That does not mean PHP is a good language.

> The problem is that there are a ton of less experienced people reading stuff on HN (just as I once was) who will take this to heart but have nothing actionable to gain from it, except to think they're a bad developer using a bad language. They aren't, and they're not.

You are replying to an article mentioning many of Go's problems, without rebuking any of the article's points. Perhaps these poor people are using a bad language? (Also perhaps some people reading this are "bad developers", whatever that means? Perhaps I am! What does that matter?)


The article's author has written and shipped tons of quality Go code that is still used in production by many people, myself included.

Sometimes, a poor language is a good tool for specific task despite of being generally a poor language. Sometimes, knowing and liking a bad language makes you use it for tasks it's not suited for. Go is in the same category as JavaScript and PHP there, which have their valid uses, but also a lot of valid reasons to stay away from. You only learn how and when to choose them once you become experienced enough in several languages to notice the differences between them over long term usage and project maintenance.


I mean, this is Hacker News. Not corporate programmer news. Building a successful company has very little to do with tech choices. But that doesn't mean we shouldn't discuss these things as tinkerers and hackers.


> Building a successful company has very little to do with tech choices.

This is what Hacker News doesn't want to hear, and so needs to hear.

Like obsessing over the school supply list at the beginning of the year and getting everything perfect; it's not the whole of success, nor is it even really a huge part. But it can be fun.


So many companies succeed _despite_ their tech choices and so many fail also despite their tech choices.

In the end, even at mostly software companies, if you don't have a good sales model, a good sales team, a good marketing team, its likely you will out of business soon.


Two step profit plan:

1. Get a sales team that could sell shit on a stick.

2. Get a programming team that can do a bit better than shit on a stick.


I don't think that the author is telling anyone to stop using Go. They are suggesting that there should be a better alternative, and there are lessons to be learnt.

I don't think we should be so cynical as to just lie down and accept that some things are just too hard to get right


Especially when other languages got them right.


> I didn't care in the last post and I don't care about this one either. I care about my productivity, I care about my team's productivity, and I care about getting stuff shipped. Those are the things I care about, and go works great for that.

If your definition of "productivity" is the time spent in programming, I think you and the author are not in disagreement. The point that the author makes is that using a language with sophisticated type systems prevents some categories of bugs to happen in the first place. That means less time spent in debugging and fixing the code.


As a beginner learning Go for the past 3 weeks, thanks for the last paragraph.

I was looking into a new language to learn outside of JS and Python. I wanted to learn a hot language. I did some digging between Rust and Go and found out that Go is more suitable for web backends, CLI apps, etc. while Rust was more of a contender to C/C++, as it was primarily was made to be used as a memory-safe, correct, strict language to write low level software.

I don't generally involve myself in the latter so I chose Go. I definitely want to learn Rust someday but is it worth it if I don't get into that low level of things?

What are Go's and Rust's target applications according to readers here?


Rust is a general purpose programming language. It can do low level systems programming but it's also highly capable of doing web backends, web frontends (wasm), game design, small utility scripts, etc.

A big thing people learning Rust do my mistake is to try and use all of the low level features straight away. Rust has tools like Rc, RefCell, Arc, and RwLock that let you have a garbage collected language (well, reference counted) and not worry about any of the low level memory management details.

See things like https://ggez.rs/ for games and https://www.arewewebyet.org/ for web stuff.

Although honestly I think if you're looking for a "hot" backend web language I'd say Elixir is the more well designed one than Go.


With your and the sibling commenters comment, I've made up my mind:

I'll definitely learn Rust one day and make stuff with it when I have proper time and I'm not learning anything else.

Thanks for the insights!


Rust is indeed a general purpose programming language, but unlike the sibling poster I'm not going to sell it for low-level systems programming _and_ other things just because it can and has some (hit-or-miss depending on the domain) crates for them.

Rust is a complex language and its APIs tend to reflect the underlying domain complexity nearly 1:1. It also does not have a GC. Rust interops with native code well. When you're writing code that needs to be very correct especially in complicated problem domains, Rust is a great language to reach for because it bubbles up that underlying complexity so well. If you really need the lack of GC pausing then Rust is also IMO much better than most other non-GC languages in common use (c.f. C, C++). If you need C interop, then Rust is great. If you're a fan of writing elegant abstractions, Rust is also a great tool as its macro processor and language constructs make it easy to write abstractions (compared to other imperative languages at least). But its use for other areas is, IMO, a bit fraught.

Go is a lot more opinionated as a language. Its stdlib hides the complexity for certain interfaces. It has a simple-to-use concurrency model that the whole language opts into. It compiles quickly. It produces a no-nonsense static binary and has a great cross-compilation story. Go code is repetitive but simple to read. Go's tooling is stellar and because of how easy it is to write third-party tooling, people often build useful tools for themselves. I find it really easy to hack on or debug other Go projects if needed. Overall, Go is opinionated, and if the applications you're writing and the style you're writing them in fall into Go's opinions then you'll love it. If you don't like Go's style, you'll hate it. Go is my go-to (pun not intended lol) language for hobby coding because when coding as a hobby I'm often working on a constrained problem and don't need Rust's complexity.

To offer a concrete example, the OP in his previous blog post wrote a diatribe about Go's filepath handling on Windows, but when I recently used Rust to write something that templated a few filenames, the whole thing took incredibly long. The complexities of Rust filepaths accurately reflect all the edge cases available for different platforms but was ridiculous overkill for my simple app that I was hacking on that was only ever going to run on a single Linux x64 platform.

IMO to just "get things done" use Go. If you find yourself fighting Go's idioms, then Go isn't for you. If you really enjoy writing elegant abstractions, Go isn't for you. If you need to go deep into an API that Go simplifies and will spend most of your logic doing just that, then Go isn't for you. If you can't tolerate the GC pauses then Go isn't for you. Otherwise just use Go to get stuff done.


Thank you for the detailed explanation! That actually clarifies a lot of things.

Indeed, there's no straight-forward answer to the question "Should I learn Rust as a web backend developer?". It depends on all of the above things you mentioned here.

Go: Trades off correctness with opinions and abstractions. Has a GC. Has a simple, dare I say old or not-modern, type system. Easy to pick up. Hard to have full control over the program.

Rust: Reflects and embraces the actual system with its complexity. Correctness is first and foremost as it deals with all the edge cases. Not easy to pick up. But worth it for critical projects.

In a realisation, why do people even compare these two? :)


> In a realisation, why do people even compare these two? :)

That's the puzzling thing. While the author doesn't explicitly call out Rust as the better alternative, if you look at his Twitter, it's fairly obvious his community is thinking of Rust. But I don't understand why. They're different languages with different strengths and weaknesses. If I'm writing a net service I'd rather write it in Go. If I'm writing something in OpenGL, I'd rather write it in Rust. There's no need to insult one another.


I think your POV works in your very specific world view. As a head of an agency, hiring a developer that knows mainline languages serves a lot of good in hiring, keeping teams happy, and low turnover. We've all seen the agencies that hop on a new, hip language - only to go up in flames 6 months later because they couldn't find talent for their narrow viewpoint.

This isn't an argument against Go, moreso that your perspective is objectively elitist.


As people have remarked, Amos's style can be grating and hyperbolic. That doesn't make a lot of his complaints about Go as a language incorrect.

I do think he's misunderstanding that the design intent is "networked C" and that Go + Protobuf is much better than he thinks. A lot of his complaints with the language and runtime boil down to:

- It's got a primitive type system (yep, nobody disagrees)

- It leaves a lot of problems to you (yep, just like C)

- you can't integrate it into existing binaries (yep, distributed systems connected by RPC)

He comes to terms with the last one and admits it, but it is not only the thing Go is good at but it was the design intent. If you start from "we want a language and runtime for writing distributed systems that would otherwise be written in C or Java" then Go is pretty good!

I'm a happy Go, Rust, C, and C++ person. They're each for different things. That Rust worked out (is working out?) despite being an incredibly powerful and complex language (compared to C) is awesome. In the mid-2000s, it's not clear that you'd bet on a language like Rust. It is clear you could do better than Java or C++ for distributed systems programming, and Go hit that pretty reasonably (I do wish the language had a better type system, and I'm glad to see Ian finally land generics, but I'd absolutely reach for Rust when writing code in a small group that can handle the "language complexity" in exchange for the benefits).


What I don’t generally get is why Go when there is Java already? Like other than the somewhat smaller memory footprint that is not inherent to the language, but the runtime — in what way is Go better that could not have been a Java library? Hell, with Google’s resources one other GC/mode could be added to OpenJDK that prioritizes memory footprint (at the expensive of throughput - there is no free lunch).

Sure, Java has some warts but it is a very easy and small language, the reflection-based frameworks are not at all mandatory, Java can be quite expressive without those as well and it is extremely performant. Once value types get included it will be really hard to get ahead of Java.


There are a few things, mostly due to the runtimes but also because the JVM bytecode assumption has real implications for system behavior.

Let's start with bytecode. It "requires" (except for AOT work) a warm-up / JIT phase that tends towards slower start times. This isn't hard and fast, but in practice it's true. (And when you search for "jvm startup", you end up at lots of pages about how to tune things to try to make this better). For some people, just as bad or even worse (remember, distributed system) is the impact that JIT-compilation and warm-up has on tail latencies. The static nature of most compiled languages mean this isn't a thing you worry about. You've got enough tail latency problems in your life, you don't need "oh hey, I just saw this loop for the Nth time, I took 10ms to hot compile it!".

That leads into the runtime and some of the language choices around it. Java GCs are generally fighting a harder problem than Go's GC, and with a very different tuning point. Java making everything an object and support classloading and so on, has real knock-on effects for the amount of work required to get high-quality, low-pause GC to work. This is much better today than it was in 2008 when the Go team started, but it's still the case that Go has an out-of-the-box better GC experience. Yes there exist special, tuned GCs (e.g., Azul's C4, Shenandoah) but Java GCs have to really be super clever compared to the fairly simple strategies that work in Go; I applaud the ingenuity in Java GC work, but if what you care about is "reasonably good at collecting memory, never pauses for long", the Go language decisions made the GC problem easier.

I think it's fair to ask "Shouldn't Google have just improved Java?", but I think you miss out on lots of the concurrency ergonomics. Again, this has to be compared to a decade ago. Especially post 2010 (Oracle acquisition) it was super unclear that you'd want to attempt to "bet on Java".

To be clear, I do think Go is at the wrong point on the language/type-system sophistication curve for my tastes. That said, I find myself shaking my head at most Java code, while looking at the Go code and thinking "sigh, lots of repetition. I hope one day that gets better, but at least it's obvious".


> Yes there exist special, tuned GCs (e.g., Azul's C4, Shenandoah) but Java GCs have to really be super clever compared to the fairly simple strategies that work in Go;

It doesn't matter at the end, when those GCs work. There's also ZGC by the way, which has been consistently improving release over release, with sub ms pauses in the latest release for TB sized heaps, something that golang's gc cannot match.

> I applaud the ingenuity in Java GC work, but if what you care about is "reasonably good at collecting memory, never pauses for long", the Go language decisions made the GC problem easier.

Now if you want to have high throughput and willing to sacrifice some latency, Java's GC selection allows you to do that. Where as in golang you're stuck with the single gc implementation and have to resort to finicky code changes.


I have barely touched Go, but, from what I've seen, I think I might be able to add a couple more to that:

Java is more intimidating to get in to. It starts with "Oh dear, which JDK do I use?", proceeds to, "Oh dear, now I have to pick a build tool and every single one has a near-vertical learning curve by modern standards." Then you're on to, "I want to do X. Why are there 28 competing libraries for X, and why are the most popular ones invariably the most hated?" And so on.

There's a strong case to be made that procedural is a better paradigm than object-oriented for a lot of the niche that Go targets.

You mentioned concurrency ergonomics, but I just wanted to emphasize that I doubt that Java's concurrency story can ever be a match for Go's. There's too much legacy baggage that can never be unloaded.


While I think it is overstated how hard it is to choose a JDK (pretty much just get the first OpenJDK release you see, which is packaged everywhere), I do see the advantage of a default build tool. Though for beginner use cases both maven and gradle is just a copy-pastable few lines and you are ready to .. java (sorry for the joke).

I don’t really agree about the 28 competing library thing though. First of all, Java has a really good standard library. Sure, it shows its age at some places but it’s not like you have to grab a new dependency for everything, I pretty much only grab deps for very specialized tasks, and in case of Java I now there will always be a match. The only difference in go here is that a bit more network-related code is in the standard library than in java, but that’s hardly that big of an advantage.

Regarding concurrency: the most unique feature of go is unarguably go routines, but the language has an otherwise quite dumb concurrency model hindering its usefulness. Sure, locking should not be the primary mechanism here, but it is painfully bad with defer being function scoped, not block scoped — while java has synchronized blocks since forever. And with the already mentioned coming of Loom, the JVM platform will again rise to the top with regards to concurrency.


> it is overstated how hard it is to choose a JDK

It's not hard to choose if you know Java well, but this sort of thing is a huge barrier to entry for someone who is just getting into it, or trying to decide what platform to use.

The community doesn't help here. If you go Googling to try to figure it out, you'll find a mess of conflicting advice being argued with varying levels of passion. By definition, a newcomer doesn't have enough background knowledge to make their own decision, and they aren't necessarily in a position to know whether or not they really need to wade through all that dreck before deciding.

re: frameworks, it's a similar story. Java has a pretty big standard library compared to a lot of smaller programming languages, but it's really not much different here from other platforms that punch in its same weight class, and I believe that includes golang. But the standard library is background noise; if Go's on the table then I've clearly got a job to do, and that job is probably something like writing Web services. And 28 is probably an undercount of the number of Java service and microservice frameworks out there. With a lot of vigorous discussion among proponents of each. It's got to be just stupidly intimidating to face down when you're first getting started. By contrast, I wouldn't be surprised if, by choosing Go, one could have the whole job done in less time than it would take to compile a list of all the information it seems like you have to read before you can even dip a toe into Java.

Disclaimer, I don't think this translates into "Go is good, Java is bad." Personally, I would absolutely pick Java if it were a project I were getting paid to do. For several reasons, but mostly because I already know Java quite well and I know it can get the job done. And I suspect that Java has more general-purpose value than Golang does. But I don't think "Is Java a good platform?" was really the question. It was, "Why might someone choose Go over Java?" and that's a very peculiar question; one that I think you can only answer in an interesting way if you put yourself in the shoes of someone for whom it's a real decision to make - most likely someone who isn't too familiar with either.


> but I just wanted to emphasize that I doubt that Java's concurrency story can ever be a match for Go's

Project Loom is already targeted for preview for JDK19. Not only does it match golang's concurrency story, it is superior to it.


It's technically very impressive and I'm looking forward to it.

But my point around ergonomics still stands. There will still always be all the legacy stuff, and there's not necessarily any way around having to understand how that works, too, because there's generally going to be some pre-existing library or legacy code or whatever that forces you to.


The whole point of Loom is to keep using legacy (blocking) calls, and the JVM will automatically take care of things for you.

> and there's not necessarily any way around having to understand how that works

Same with golang, you have to understand how things work. The entire narrative that golang is "simple" is just not true. The moment things start to go wrong, you're going to have to understand how things are working behind the scenes.


> Let's start with bytecode. It "requires" (except for AOT work) a warm-up / JIT phase that tends towards slower start times

This is true, but relatively easily solved by AOT compilation which has been tried 2 decades ago as well as now and many times in-between. With a closed-world assumption done by Graal it is not a hard thing to do.

Re: GC

What language decisions do you mean? Other than having value types and some form of pointers, I really don’t see that much of a win. Sure, in some basic networking case allocating on the stack manually almost everything may be possible, but my experience shows that general purpose programs simply live or die by heap allocations and you can’t generally avoid them. And here the complex, but state of the art GCs of Java demonstratedly win big times, and this is the reason why the performance advantages of Go are not so pronounced or even existing for more complex use-cases.

But I will give you that the Oracle acquisition is indeed a good point - though it fortunately turned out to be a good thing for the Java ecosystem in hindsight.

Do you mean complex reflection-heavy java code or even simple explicit one? Because while I agree the latter is not the most common one in some areas, I find it to be surprisingly readable and simple, while still being expressive enough when needed.


> If you start from "we want a language and runtime for writing distributed systems that would otherwise be written in C or Java" then Go is pretty good!

C and Java are far from the same. I'd argue that Java addresses or solves many of the criticisms he listed for golang (sum types, pattern matching, immutability with records, superior error handling with exceptions, nullability tracking with annotations, resource handling with try-with-resources, etc.).


The author obviously doesn't like Go. Ok, he can have his own opinions.

I've been coding professionally since 1987, using everything from mainframe assembler, Fortran, C, VB, Java, C++, to most recently Go. IMHO, the language itself plays a smaller role in its usefulness than most think. As important is the tooling, stdlib, ecosystem, community and "StackOverflow"-ability.

Go has a few warts, like every language, but not that many, and they are more than made up for by how easy it is to assemble and run a project using it. It's that that makes it the most productive language I've used so far.


From the article: "[...] as developers get more and more senior, they tend to ignore more and more problems, because they've gotten so used to it. That's the way it's always been done, and they've learned to live with them, so they've stopped questioning it any more."


As developers get more and more senior, they have a different perspective on what constitutes a "serious" problem. Also, as developers get more experience with a language, they get better at doing things in ways that are idiomatic for that language - they work with the language instead of against it.

Take Haskell. If I were a Haskell novice, and tried to do everything procedurally with do notation, and then complained that Haskell had all these problems, would that make Haskell a bad language? No. Would it mean that all Haskell programmers were telling themselves lies in order to keep using it? No. It would mean that I was using it badly.

If I were a brand new programmer, and took up Java, I might well complain about "public static void main(String[] args)". But an experienced programmer would brush that off, telling me that that's just syntax - there are real problems with Java, but that isn't one.

So this particular statement, that senior and more experienced devs ignore more and more problems, isn't proof of anything. It's particularly not proof that developers have to keep lying to themselves in order to keep using Go. (They may, but this isn't proof.)


As developers get more and more senior they tend to ignore more and more problems because they realize the majority of them actually don't matter very much to doing useful work.


Or, perhaps more frequently, they can quickly see that any possible fix for it would be penny wise and pound foolish.


He made some good points in the article but this particular paragraph stuck out as being hypocritical. The entire motivation of him writing this was because he felt people dismissed his previous article out of hand. And then he makes a remark that preemptively dismisses any rebuttal out of hand (and as others have pointed out, can equally apply to any language so hardly a point worth complaining against Go specifically).


> as developers get more and more senior, they tend to ignore more and more problems, because they've gotten so used to it.

I've been coding professionally since the 90s. The last project I worked on was in Go. It was pleasant and surprisingly productive. A few warts, like the parent said, but all told it was a great experience. I'm now working on a Typescript project. It is painful. Typescript itself is quite nice, but the deep problems with the rest of the ecosystem have not gone unnoticed.


Hmm won't this apply to any language and therefore not a valid argument? A: language FOO is a great language! B: You are telling lies because you are fluent in this language and ignore the problems in the language.


IME there are sort of two kinds of people here. People who are "fans" and defend "their" toy and people who don't. For example, I've been using Python for a very long time. I'm a "Senior Python Developer" so to speak. I quite like it for various purposes, but I can also talk your ear off about problems with Python.

I'd say if you run into someone who says they're experienced with X or love X etc., but they can't give criticism of it, they're most likely either not that experienced with X, or fanboys.


Yes. This is true of any environment. That's why I ask new hires to write down every WTF moment, every question and every idea for improvement they have as they get up to speed on our systems. Just because I'm used to avoiding a problem doesn't mean the problem must exist.


It seems to me there are two ways to evaluate the "beauty" of a language: there's the people who love the language theoretically (well constructed, coherent, nice typing, etc) and then there's people who love the usefulness/utility of the language.

For example, I hate python as a language (spaces syntax? Self,self,self, lack of static type, etc) but I've been using it lately and it's nice using it due to libraries, community,etc.


Just speaking abstractly, whether problems are ignored has no bearing on the existence, size or count of the problems.


This has perhaps been my biggest pain-point with Golang..

Woe unto those who do not follow the idiosyncrasies of how golang handles versioning, package management, tooling etc.

if this is really your most important part of a language I would whole-heartedly recommend looking at rust which has been a breathe of fresh air in terms of package management and tooling.


As an operations person who cares about deploying repeatable systems at scale, Rust's package management (and the toolchain's "packaging" itself) is an absolute nightmare. But at least I with MUSL can I have a 100% statically linked binary, which really should have been easier but that's another argument.

Seriously though, Rust team needs to have its Come To Jesus moment about not piping shit off the internet to sh.


I'm interested if you could elaborate on that?

My company deploys many Rust (web) applications to production and I've not experienced these issues with cargo


It's either a problem that you have or you don't, but also one that you have to have a specific mindset to even recognize.

To start off with, please read this: https://lwn.net/Articles/889924/

As you start having to worry about deploying to 10^5 scale machines you want your mindset to be more like the longtime kernel development folks. You want minimal dependencies. You want to build with minimal pulls to the internet. You want repeatable static binaries built from a source tree you can reasonably audit.

At that scale of deployment your "business risk" goes up significantly.

Rust's approach to tooling/packages looks very similar to the Node.js ecosystem. It's a total free for all and dependencies are managed really poorly (in the sense that they grow in number completely out of control).


You can use cargo vendor to import specific versions of your dependencies into your project for easy auditing, or cargo fetch to simply be more explicit about when to download from remote repositories (when combined with the --offline flag). The typical Rust "dependency" is small; it's more like a single .c or .cxx file than a conventional "library", except that it also plays nice with generic code unlike these languages.


I agree that Rust does suffer a similar problem to NPM where there are many small packages that people will use together.

I do wonder what the solution is though because Go has the same problem as far as I can tell. It has a bigger stdlib so there's less need to reach out. But when you do, you're in the same state with lots of tiny packages that do 1 thing well.

I don't have much experience outside of Go/Rust/Node so I can point to maybe a few languages which I can see being the opposite:

C++ has a large stdlib, and boost. With C++ managing dependencies is your problem so I guess it's easier to have few megapackages.

Python feels the same for mathematical computing. Numpy, TF, Pandas are all huge. Conda is an event bigger bundle, again I think because using the standard pip tools is rather cumbersome and usually not what people want to do

So as far as I can see, it's either easy to share code for others to use, in which case you get dependency hell, or you make it hard to share dependencies, but you have larger more refined ones as a result.

Hard to say what's better


rustup is available in your package manager's repository


No, it isn't. There is a package but it just symlinks to rustc & cargo. You still need to have run the installation manually.

And if you're still running something like CentOS 7, everyone just tells you to go download a Snap for it. eff that.


Go tooling is awesome compared to other language ( Rust included ). Everything is built it and you don't need something external, everything works out of the box dependencies included, it has been the case for 4 years with go mod.

The fact that you can cross compile a win10 .exe on a raspberry pi with a single command as easy as "GOARCH=amd64 GOOS=win go build ." it's very powerful and I don't know a single language that does it out of the box like go does.

Go tooling is one of the strongest point of Go you have all of that built-in:

- compilation

- testing

- benchamark

- dep managment


> it's very powerful and I don't know a single language that does it out of the box like go does.

zig build -Dtarget=x86_64-windows


I'm talking about mainstream language not stuff in dev. And go has been doing that for 10years+


well, not exactly. Zig is also crosscompiling C/C++ code, not just Zig. CGo doesn't do cross-compilation.


I love Rust as a language but its packaging mechanism is as flawed as all the others. I don't really see what breath of fresh air it brings.

I suppose you can define feature flags in your Cargo.toml but that's about it.


Golang has the most hilarious approach to date formatting


Lol, I thought it was some sort of Joke when I first learnt it. And kept hunting for the 'proper' way. When I realised this was serious, I banged my head against the wall.


+100. I found a lot of the points in the post pretty silly/arbitrary, but if he had talked about date formatting I would be all aboard.


You might enjoy https://golangti.me which I wrote to help with my inability to remember it!


For me, the goroutines + channels + select is what makes Go leagues above any other popular language.

As far as I know, no other popular language allows you to read from multiple queues at the same time, which is an extremely useful pattern in concurrent programming. The only way to "select" from multiple sources in other languages is to use some kind of poll/select syscall on file descriptors - and even that is very limited, since kernel (at least Linux) does not allow userspace programs to create private file descriptors for intra-process communication - they must always be bound to some file/pipe/socket.


> As far as I know, no other popular language allows you to read from multiple queues at the same time

Off the top of my head, that's certainly possible in Rust, C++ and Java - probably many others I just don't know about.

That particular bit of concurrency goodness comes from the 70s, so you can be sure other languages picked it up.


As I understand it, he's talking about select/alt (i.e. guarded commands from CSP) being a native feature of the language rather than callback-based approaches. It's possible to implement CSP channels in most languages, but they're not first-class like go.


> It's possible to implement CSP channels in most languages, but they're not first-class like go.

But does that matter? In all my experience, I can't think of any instances where that wouldn't be a distinction without a difference. (Perhaps I'm missing something, though.)


It matters a lot IMO. Most systems programming languages can implement whatever concurrency primitives you care to use, but most people default to whatever is provided by the OS/language because concurrency is hard. Having first-class syntactic sugar over a concurrent runtime bakes in a certain programming style in the language, which strongly determines how the language is used and the programming style. Go comes out of the Newsqueak/Aleph/Limbo family which has a very different style of programming compared to a lot of other languages.


I think there's a difference between 'in the standard library' and 'in the language', though. They seem to be praising Go for doing the latter. And the technical language in which it was expressed gave me to think there was some technical motivation for that, as opposed to sociological - but if what they meant is what you said, then I certainly wouldn't disagree with that.


I'd argue that Go is explicitly sociological. Most of the novel ideas in Go (process calculi/guarded commands in a concurrent language) were originally embedded in Cardelli and Pike's Squeak back in the 80s. The rest is trying to standardize the way scalable web applications are built.


Defaults matter because friction matters, but friction there is largely removed by having a decent package manager, so I personally don't think it matters (though the topic of "what batteries should be included" has far from run its course).


The minute you put language constructs in the base syntax and runtime of the language, it's a lot more than friction. Love it or hate it, Go is inextricably tied to CSP.


It's the opposite - pointing out that X can just as well be implemented in language Y is the irrelevant point because anything can be implemented in any turing complete language.

Where languages differ is what they make easy to use, or first class.

As an example consider Go's autoformatter gofmt. It got released with the language, pushed and marketed as the way to format your code - first class. As a result, virtually all Go code is uniformly formatted. Contrast that with autoformatters in other languages pre-Go. They existed, but often multiple per language, each with hundreds of configuration options, all with minimal uptake in their ecosystems.


If you could spare some time, would you please demonstrate an example? Any language of those mentioned would be OK.


Here's a Rust example, with tokio: https://play.rust-lang.org/?version=stable&mode=debug&editio... - I don't have time to come up with Java/C++ examples, but I'm sure others will.

(If your point was about it being _built into the language_, then it definitely stands, see the other discussion in the parent comment thread)


Yeah, I guess I overestimated the complexity of such mechanisms. I mean, still, you need some kind of runtime for the asynchronicity, but the Rust version seems fairly OK (apart from the function coloring, but that's another story).

I guess I just like it being built into the language. Plus no function coloring (everything is asynchronous, but appears synchronous) really makes it easy to build complex systems.



Ada too, I think.


Ada has had this built-in for decades, and even allows selecting from one of multiple waiting queues (entries) using a `select` keyword.


If that's all you want, Haskell has had goroutines (forkIO, yes it's called "fork" but it doesn't spawn an OS level process, that's forkOS), channels, and select since 1996. https://www.microsoft.com/en-us/research/wp-content/uploads/...


People also want a programming language they can easily read and that has enough market share to work well in team environments.


nobody should ever write haskell


here's some documentation on how to do it in C++ with boost in 2008, before go even existed: in this example two threads pull events from a single queue.

https://www.boost.org/doc/libs/1_35_0/doc/html/boost_asio/tu...

(of course it was possible before)


I'm not really experienced with Boost so I'm having a hard time understanding what that snippet does. Is there any example that is completely self-contained (or at least limited to STL)?


Boost's io_service (since then renamed as io_context) is an implementation of a thread-safe event queue. Threads can put events in the queue (timer events, asynchronous read and write requests for networking, but one can also just push a generic lambda).

This example sets up two timers which will regularly push events in the queue, while two threads processes these events. It's from before c++ had lambdas - nowadays it can be written much more tersely.

I'll try to write a short example after when I'm not on my phone - it should be reduceable to 5-6 lines of setup at most


=> very dumb example of processing messages from ten threads

    #include <boost/asio.hpp>
    
    #include <atomic>
    #include <iostream>
    #include <thread>
    
    int main() {
      boost::asio::io_context io;
    
      using work_guard_type = boost::asio::executor_work_guard<boost::asio::io_context::executor_type>;
      work_guard_type work_guard(io.get_executor());
    
      std::vector<std::jthread> t;
      for(int i = 0; i < 10; i++)
        t.emplace_back(std::jthread([&io] { io.run(); }));
      
      std::atomic_int counter{};
      while(counter < 100)
        io.post([&] { 
            std::cerr << std::this_thread::get_id() << '\n'; 
            counter++; 
        });
      
      io.stop();
      return 0;
    }


>read from multiple queues at the same time

That's a trivial thing in javascript.


If you could spare some time, would you please demonstrate an example?


You can use Promise.race to wait for the first resolved promise.


Abusing notation a bit,

var a = new Queue();

var b = new Queue();

a.read(() => some callback);

b.read(() => some callback);

And code continues here without blocking.

To be honest, I think you could do the same in any (slightly) modern language.


Is the read() call running a task in the background? In that case, that's equivalent to launching two threads. For n queues, you'd need n tasks, and they'd hang in the background in case they never get a result and take up memory.


How? Javascript is single threaded run loop.



>read from multiple queues at the same time

Agreed, and things happening "at the same time" are possible only with parallelism. Hence my question =)


I interpreted "at the same time" as "without blocking",

But sure you could also add parallelism using a few built-in Node modules (there's cluster and worker threads, also don't know if atomics are already in Node, they are in V8),

It's not trivial anymore but also not that hard. A newcomer could figure it out in ~30 mins from the docs.


Gotcha, sounds like we interpreted it differently. I appreciate you taking the time to clarify, I am an old hand as JS but didn't know true parallelism had become feasible these days. Thank you, sincerely!


Don't worry, JS has come a long way.

During my PhD we had to crunch some numbers and my group usually makes use of C++ with libs for that. I tried doing it in Node using cluster and let it spread through our whole cluster of nodes (funny how it plays on words) and performance was worse obv. but not that bad, it was about 2x slower, but with that I was able to write code and test it in hours instead of days, and it didn't matter to me if a program that was going to take 2 hours was now taking 4 as I was going home anyway and check it out next morning ¯\_(ツ)_/¯. Plus, my experiment had a REST API for free (well, like 8 lines of code) and when I showed that to them they were :O.


Lots of languages have similar async, channel and pattern matching syntax these days. Kotlin, C#, off the top of my head. Probably a lot more.


Yeah, it's pretty obvious to me the author doesn't like Go and some of the arguments raised really aren't concerns in (my very limited part of) the real world.

I've written a fair amount of Go and I am not bothered at all by the general ergonomics of the language. Some of the issues the author points out (like accidentally copying structs with embedded synchronization primitives) are caught by linters which you should be using regardless of what language you are coding in.

Edit: I dabble with Rust from time to time as well.


A couple of things to add to this: the language spec is like a page long and very readable. Also the entire compiler toolchain and everything is written in Go and doesn’t depend llvm etc. This doesn’t help the developer but is a pretty unique aspect of Go.


The language spec (https://go.dev/ref/spec) is about 96 pages when printed on A4 paper. Certainly not a page long.


If a language spec is only a page long, it's leaving a bunch of important things unspecified.


Can you clarify further? Otherwise this seems like a shallow dismissal, which is against our HN community guidelines, and makes for uninteresting discussion.


Programming languages have a large amount of irreducible complexity. A page long spec for a language more complex than Brainfuck cannot represent the critical distinctions correctly.

Without that clarity, you end up with incompatible, spec-compliant implementations. This is a disaster, and so below a certain point relative to language complexity a shorter spec is simply wrong.


> Without that clarity, you end up with incompatible, spec-compliant implementations.

The Go team officially maintains two implementations, gc and gccgo, to ensure that implementation doesn't end up ruling over the specification as has happened in other languages. There are also other third party implementations, including tinygo.

Which spec-induced incompatibilities across these implementations are you referring to?


Go doesn't have a one-page spec, so what do you expect the GP to point to? You are proving his point.


Looks like one page to me: https://go.dev/ref/spec


Yeah, no.


Feel free to show us the second page.


It starts about 2/3 of the way through the table of contents.


A link is fine.



That points to the same page.


It's now become abundantly clear to everyone that you're using a different definition of "page" than everyone else in this conversation.


The only other person in this conversation is you, so not exactly the most representative of samples, but it is an interesting perspective. I've not heard anyone else consider the same HTML resource to be more than one page before. In fact, the term "single page application" hinges on a single HTML resource in the same way. The application may have more than one screen of content, but it is still considered one page.


oxnrtr is in this conversation too. And when describing the length of a document, "pages" universally means the number of printed pages it would occupy, not the number of computer files it's stored in.


There is no sign of anyone else participating in this conversation. Else we'd have heard their input by now. A page referring to a single HTML resource is standard nomenclature. Paper is antiquated technology, not how the Go specification is distributed, and carries no relevance to this discussion.


I hope you receive the help you need and deserve.


Are there nasty divergences between official go and cgo?


As it turns out, Go's spec is 105 pages long, not just one as was claimed upthread: https://go.dev/ref/spec

So the answer to your question is "not that I know of", but that's not evidence that a one-page spec is workable after all.


Can you describe a coherent and consistent multithreaded model completely in 100 pages?


Thank you for showing us the light, jospehcsible!


> Also the entire compiler toolchain and everything is written in Go and doesn’t depend llvm etc.

Depends on which implementation you're talking about. One of the stated goals of the Go project is that there must not be just one implementation. gc does not, but tinygo depends on llvm. gccgo depends on gcc.


Tailscalar here.

Go made prototyping our product easy. We have relatively rarely needed Go expertise on the team to make the product better, when we did it was for the exotic iOS environment (not normal iOS, the Network Extension).

It’s far from perfect (and I really should write an experience report about all the times Go has let us down!), but it gives us less trouble than Node and Swift do, for our relatively minor uses of those languages. I don’t think any other language would have been a better choice, even putting our expertise aside.

On the whole I would say you don’t need Go experts on your team to build products in the language.


Author's criticisms are valid, but

"There's two types of languages, languages people complain about and languages no one uses"

Is author being serious about all people who write Go for production would be waking up at 3am to fix issues? If this is happening, software engineers are being abused, enough said

And not recommending C/C++ because it is easy to shoot yourself in the foot, apparently the devs enter hospitals so many times when memory-related vulnerabilities happen in Windows/Linux/Android/MacOs/iOS and Chrome/Safari/Firefox

people should stop idolizing programming languages


I just don't see the issue with Go. After dealing with inscrutable errors in some python code that interfaces with OpenSSL. Or dealing with impossible to trace errors in Spring Boot. Or Javascript? An absolute nightmare from start to finish. There's something extremely nice to get an error, place a breakpoint and trace exactly (even if it's a third party library) that error is happening.

I will take all the footguns in the world for that ability. Plus in general the tooling is just amazing. I know there is other Unix tooling out there but I'm sorry, they kinda suck and are terrible to use. They're for the type of person who can use vim with their eyes closed and unfortunately that's not me.

The other footguns he mentioned? Valid. A linter will catch a chunk of them though. I just generally don't think they matter half the time. I think of it like the iPhone. It's a pleasure to use like 80% of the time maybe 85% and 10% it feels hacky and terrible to get something working and 5% you just can't or shouldn't do it.

So for the 80% use case (backend crud apps or backend web apis) I'd take Go every time. Plus it compiles almost instantly versus multi minute turnaround times in a lot of other languages.


> Or dealing with impossible to trace errors in Spring Boot.

Spring Boot is not Java. You can debug Java just as easily. On the upside, you can probably get the same stuff done in probably one third less code + use the vast ecosystem. On the downside, compilation may be a bit slower and you don't get a nice little executable out of the box.

I wrote a tool in Golang and while it did everything as advertised, the boilerplate just bogged me down. Any new changes is just so much more LOC compared to Java (or Python or Rust...). To be clear, I would prefer Java or Rust compared to Python any day. Either way, I just don't want to write so much verbose code anymore.


I don’t think I’ve ever seen Java used in isolation without spring boot


Not a CS, but a damn good technical accountant and well self-taught developer.

I led a team that wrote an accounting & reporting software for a specific technical problem. We had an architect who only knew Spring, and hasn't been out there pretty much in a decade.

I clashed severely with him, to the point where he made an arrogant argument about something he was clearly wrong with. He said "I bet my salary that you're wrong" in front of people. I bet mine too, and the following day I demonstrated that he was wrong. I gave him my bank account (it was pay day). It was a hard bet to lose, so I said he didn't need to pay it, and I asked him to be removed from the team (because he showed that he wouldn't learn).

We went on to build the system without Spring, without TomCat and with more freedom to write SAL where an ORM couldn't solve the problem better.

Interestingly, we used grpc between the front-end and the backend JVM microservices.

As other people say, check out projects in GitHub. Look at what new Java, Kotlin, Scala projects look like.

There's a lot of interesting stuff in JVM-land that don't touch Spring.

Interestingly on the software that we wrote, compute was the biggest bottleneck. I rewrote some parts in Rust, but ended up canning the work because nobody else would be able or willing to touch the code.


Y'all need to get out more often! ;)

Yes, Spring Boot is very popular, but there is a whole world of Java outside Spring, even if you confine yourself to just web apps (which is far from the only domain in which Java is used).


It’s worth remembering that Spring Boot didn’t exist for the first nineteen years we used Java.


This comment is hilarious ^


How is Spring Boot not Java? Spring Boot is a simple Java library.


Spring boot is not, in any way shape or form, a "simple" java "library". Not only is it a complex framework, it also uses features very few java programmers are exposed to, such as runtime code generation.


You can use runtime code generation with mere java.lang.reflect.Proxy. Yes, Spring is slightly more powerful than that, but it's not something magical. Runtime code generation is a simple concept.


I seriously doubt that Go would compile faster than Java. Like, neither does any reasonable amount of optimization, and I have never heard Java considered slow in compile time. Sure, one can do some very cryptic module-graph with their chosen build tool, but otherwise it should be as fast as it gets.


I generally like go and also see its problems as the author does.

However, with respect to the points about Go as a prototyping/starter language, there is not better language to start writing a project with in my opinion. Lots of languages have big communities of packages of various levels of maintenance but almost no other language has a standard library that is as usable as Go with the same guarantees between versions. I think its the biggest downfall of all these new languages like Rust/Zig/Hare etc, they all go for these minuscule standard libraries. I have no wish to start a project with any of them as all of them would involve I hunt down the 'best' http library and the 'best' async library and weigh their upsides and downsides, so I just reach for go and crack out the code I need to get it done, nothing else lets me do that half as easily, maintenance may be harder but at least I'm probably going to spend less time maintaining the list of packages that are still usable.


If you want a big standard library why not use something like Java or C#? I mean, you even have UI toolkits available from the get go


I dont know them as well as I do Go but the libraries (java especially) don't feel as coherent as the go libraries do, though that may be subjective and to do with my lack of experience with them. In addition both of these languages are large enough and have projects structured in such a way as to make it difficult to just use a text editor, which i consider a barrier to me just 'cracking out' a project.

C# also had pretty middling linux support the last time i worked with dotnet. and java tooling is not as out of the box as go is where I have to know is gradle good or still used or should i just use maven. Its all part of me not wanting to have to choose the best dependencies for my project and being handed for the most part good enough dependencies by the language standard library.

Another thing to appreciate in go is it produces good enough binaries and produces them very very quickly -- i've worked on several massive go projects and the build/test turnaround time is quite good.


With Go you can develop a web service with few to no external deps or frameworks, compile it into a single, static binary and then deploy it in a minimal distroless container.

With Java and C# there's a lot of other fuss involved with figuring out deployment. The code, build, test cycle is also much slower in C#/.NET ime. That's starting to improve a bit with the newer dotnet, but still feels behind other everything but the kitchen sink frameworks like Rails, which I would more compare C# to since C# without .NET/dotnet is uncommon.


Thats a lot of nonsense. The developer loop is way faster now in C# with the introduction of hot reload.

> fuss involved

The commands are almost the same from the go tooling, dotnet build , dotnet run, dotnet format, dotnet test…

Anything outside of hellow world for a web sevice in go, you will use a third party library while in .NET its given to you.


Java can literally hot-swap classes, how does it have a slower code-build-test cycle? It also has possibly the best debug mode and observability.


Sorry if it was unclear, I was specifically commenting about C# with regards to build, test, deploy cycle because I don't have much experience with Java. It's good to hear that it's not slow or cumbersome.


We have tens of microservices written in Go.

Go is good for onboarding new devs because it's simple. Our existing PHP devs were taught Go and it was painless. Jumping from PHP straight into Rust would be pretty painful, I think. Finding Rust devs isn't easy in our town.

But I agree with most of the points. You got to be very careful when writing in Go, because there are many gotchas. So many gotchas that I had to write a large document describing all the conventions and rules to remember to write bug-free (hopefully) Go. This "Go with conventions" reminds of the days when you'd try to simulate OOP in C - it works but error-prone.

Many of the problems are caught early with good unit and integration testing, however, just like with scripting languages. In my experience, most of the bugs in production in our Go microservices come from logical mistakes, not from misusing Go.


That means Go was easy for those devs to pick up, not that Go is simple.

Rich Hickey gave an all time classic presentation about this seemingly nitpicky but important distinction https://www.youtube.com/watch?v=SxdOUGdseq4


Interestingly, I have always heard Go is simple, but not easy.


I readily believe that PHP devs struggle with anything more complex with Go, but that makes me question how people end up with the lack of will to learn and improve in this profession.


can you shoot me the doc?


I'm honestly surprised at the response to this article. I'm not involved in the Rust or Go spaces enough to have any strong opinions. This article was, yes, a little aggressive in tone but presented very honest and accurate information about a language that the author clearly has experience in. It seems like a lot of the people complaining in the comments didn't actually read the article. The author even explains how those who have bought in to Go may not want to hear what they're saying and it's right. No one wants to hear that their baby is ugly but sometimes it's the truth.

To those who do use Go: someone can call your baby ugly and you can still love it.


I couldn't agree more. Some of the comments on this post are way out of line, straying into personal attacks on the author or their intentions. It's clearly touched a nerve and the reaction seems wildly out of proportion to the content.


It's always sad to see when someone's favorite tool gets criticized that they fail to realize that there is no perfect tool and that we're just talking about tools.

It always plays out that way though.


One thing to consider is that there is now a lot of Go out there, especially in the ops world thanks to k8s, Terraform, etc. A lot of people have put a lot of effort into learning it, and may have even built their career around it. So it's not surprising (even if it's a little sad) that people react very strongly to criticism of it. You sometimes see similar reactions to criticism of JS.

Just this week I've been dealing with a random crash when we run `terraform plan` which turned out to be a data race in Terraform itself. I honestly can't understand why something like Terraform, dealing with critical infrastructure, secrets, etc, would be built in a language like Go, apart from that all the other ops-adjacent stuff was being built in Go. The discussion in TFA about not selecting your tools solely based on what other companies are using is cogent.


When the author make such claim:

"It may well be that Go is not adequate for production services unless"

Who is exactly the author to tell us to not use a language that was proven to be just fine and successful. What actually OP shipped in production to be able to make such claim? Does it means also that Java / C# / Python, Ruby ect have the same fate since they're not up to part with Rust?

Kubernetes is everywhere and is built 100% in Go, it solves real complex issues, so was Go the wrong choice for it?

You can find many tools built in Go that are used by pretty much every compagnies now days, was Go the wrong language for those tools as well? Kuberentes, Docker, Grafana, Prometheus, esbuild etc ... the list is actually long.

Yes Go is not a perfect language, but saying that you should not use it production where the last 10years has shown that it deliver value is wrong.


"Not being adequate != don't use it ever". Plenty of situations where pragmatism leads us to building things with "inadequate" tools.

Besides that, you do realize that your comment is a perfect embodiment of "Others use it, so it must be good for us too", which is the very first "lie" that he is describing?


I gave example of very successful tool used, Kubernetes works fine, did you ever heard about Kuberentes gone bad or full of bug or unusable? It's very stable and it's used by millions of people.


> Kubernetes works fine

At what cost? How many man-hours did it take? How many bugs could have been avoided? How much faster could it be done with other languages? Most importantly: if Google stops backing its development, who else could replace it?

Redis/SQLite are written in C, and it is also used by millions of people. They are also not known to be bad or full of bugs. You don't see that being used as an argument to claim that C is an "adequate" language for most people nowadays.

And if you did see anyone using that argument, we probably would say that this is just a lie they tell themselves to keep using C.


> At what cost? How many man-hours did it take? How many bugs could have been avoided? How much faster could it be done with other languages? Most importantly: if Google stops backing its development, who else could replace it?

Same question can be asked when Rust or C/C++ are being used to write k8s

> And if you did see anyone using that argument, we probably would say that this is just a lie they tell themselves to keep using C.

A bad programmer is a bad programmer. If all you have is a hammer, everything looks like a nail

People who did read this article should be aware of the shortcomings of Golang by now, and some of them will still be using it, and I am very sure of that


a) calm down

b) please read the article before complaining


Let's not pretend that some flagging of this article represents all or most developers who use Go, and also not pretend that this post represents all or most developers who use Rust.

What kinda gets me from this genre of post, is that it sounds like writing good software in any language besides Rust is impossible, or even impractical. Like 10 years ago it was impractical for anyone to enjoy writing good software. (Or maybe Haskell or Ocaml would be acceptable?)

I've written a fair bit of Go, lots of Python and C, lots of bash and posix sh ... and I've written good and reliable-for-purpose software in all these languages, and I've enjoyed it much of the time. (In college I also wrote a chess playing engine in java, a malloc implementation and a trivial unix-like OS kernel with fork and threads in C of course, also a mips and z80 cpu implementation in verilog for fpga ... does that make me a "blub" programmer?)

Is it really an unacceptable flaw to have a program that only works with printable paths, and only makes sense to run on one's own files? Or which runs fine on both unix and windows, but doesn't do anything with file permissions? Or which only operates on file permissions on unix, but only runs on our servers and VMs?

I like high quality software, I really do. But I think that people writing these blog posts want something more, something impossibly pure. They want a messiah, and if everyone just believed, the world would be perfect. I like high quality software which has been possible and practical for 20+ years.


I didn't get that desire for purity that you gleaned from it.

The fact is that (as the author pointed out) Golang is missing basic language features that other languages have adopted since the creation of C that eliminate whole classes of errors, and it's pretty easy to accidentally do the wrong thing as a result.

Nil pointer exceptions, for example, don't have to exist anymore.. and yet they do in Go because they couldn't be bothered to add sum types. Its type system is barely a step above a dynamic language. You have to write the same imperative looping code over and over because Rob Pike would rather just use a for loop than something mildly expressive like map or filter (https://github.com/robpike/filter). Every function that does meaningful work is littered with if err != nil { return err }. Etc.

It is easy to write code in Go, but IMO it's not easy to write and maintain a production grade system with any amount of complexity in Go because you _have_ to be careful, you can't encode invariants explicitly and let the compiler find problems for you, and you have to repeat yourself so often.


> I didn't get that desire for purity that you gleaned from it.

'Folks who develop an allergic reaction to "big balls of mutable state without sum types" tend to gravitate towards languages that gives them control over mutability, lifetimes, and lets them build abstractions.'

This mutability argument is present throughout the article. Seems like nothing sans Rust or niche functional languages is enough.

> Nil pointer exceptions, for example, don't have to exist anymore..

The language most notorious for those is Java due to almost everything being passed via a nullable reference. When everything can be nullable, how can you know where to check for it? Go addresses this to an extent by explicitly separating pointers from values. Values are the default and cannot be nil, so the opportunity for null dereferences is greatly diminished. It's not a perfect solution, but it's not nothing either.

> and yet they do in Go because they couldn't be bothered to add sum types.

Damn those lazy Go devs!

> Its type system is barely a step above a dynamic language.

Turns out even a basic type system is a huge improvement over none. Just being able to restrict values to concrete types goes a long way.

> You have to write the same imperative looping code over and over because Rob Pike would rather just use a for loop than something mildly expressive like map or filter (https://github.com/robpike/filter).

There are arguments to be made either way, but I definitely agree generics (along with iterators) should have been there since day 1.

> Every function that does meaningful work is littered with if err != nil { return err }.

One big positive of this that I don't see in other languages is every `return` in a function must be on the start of a line. That is, every single exit path of a function is easily findable by visually scanning the start of each line for `return`.

> you can't encode invariants explicitly

I'm curious, are there any limitations here besides enums/sum types?


> What kinda gets me from this genre of post, is that it sounds like writing good software in any language besides Rust is impossible, or even impractical. Like 10 years ago it was impractical for anyone to enjoy writing good software. (Or maybe Haskell or Ocaml would be acceptable?)

I think what we are seeing here is that the expectations are growing and people demand more from their tools.

This is a good thing, even if some languages cannot keep up with the higher standards and fall behind.


This is the second day in a row where a post about Go in a negative light was flagged. The first one was an extremely detailed criticism, maintained the front page, and was flagged like crazy. What gives?


This is the second day in a row where a post about Go _from the same blog_ has been posted. I think that's enough, especially since it's mostly a knee jerk reaction from that very HN post from yesterday.

https://news.ycombinator.com/item?id=31191700


> This is the second day in a row where a post about Go _from the same blog_ has been posted.

Unless you consider this post either spam or off topic (and I personally don't believe it falls into either category), then flagging the post is not in keeping with my understanding of the site guidelines.

Just don't upvote it.


This post is (sort-of) a response to yesterday's discussion. I think it's fair to post it today.


No sort-of about it. The author directly quotes from yesterday's HN discussion. It's a continuation of the dialogue.


The article is over two years old and posted by random people regularly.

The timing is a coincidence.


The author is active on HN, he was active on yesterday's thread. Shall we post tomorrow's response as well?


Anyone can post it if they want to. If it gets enough upvotes it will be on the front page for a while, just like this one...


And users are free to flag if they deem the content spammy.


Yes, exactly, although I personally don't see how a substantive post, responding to a well-discussed issue from the previous day, could possibly qualify as "spam". I guess others agree, since the post did not remain flagged.


And others are free to disagree with your opinion. I read the content as lacking maturity, emotionally loaded and not the kind of content that fosters productive conversation in HN (as can be evidenced by the caliber of most comments in this thread).

The post is not explicitly flagged but nowhere to be seen in HN first pages. Take that as a hint.


> The post is not explicitly flagged but nowhere to be seen in HN first pages. Take that as a hint.

It's been almost 24 hours since it was posted, a majority of posts are buried by then. The post seems to have followed a fairly normal lifecycle.

I am not a huge fan of the tone of the OP either, but it does have substantive content and discusses genuine issues (though it probably is not the best way to trigger discussion of those issues), some of which have bitten people at my workplace (dealing with bugs in two different very popular products written in Go, the kind of bugs that are simply not possible in other languages) in just the last week.

It would be interesting to see the response to a less inflammatory article discussing the same issues — I have noticed in general that criticism of Go is often badly received around here regardless of its tone.


> It's been almost 24 hours since it was posted, a majority of posts are buried by then.

No. Here's a post with much less upvotes, much less comments still on page 2: https://news.ycombinator.com/item?id=31205139

There are many other examples if you care to compare.

Meanwhile this post is nowhere to be seen because most conversation here is not up to HN standards.

Flagging is detrimental to post ranking. And rightfully so.


... really? Come on. As of this writing, 29 out of 30 posts on page 2 are younger than this post. 30 out of 30 posts on page 3 are younger than this post. 29 out of 30 posts on page 4 are younger than this post. I could keep going. The fact that you can find one outlier and then wave your hands and say "there are many more" doesn't make your argument reasonable.

> Flagging is detrimental to post ranking. And rightfully so.

As I understand it, flagging is to get moderator attention to posts that don't follow the HN guidelines. It's not the general way to punish posts that upset you, that's called downvoting. Treating flags as a "stronger downvote" basically makes the very concept of flagging worthless.


You should have kept going on.

There are multiple posts older than this one that are listed within the first 9 pages, some of them 2 days older even. While this one isn't.

Take a guess why :)


> The post is not explicitly flagged but nowhere to be seen in HN first pages.

The flag was removed by moderators, but by then the algorithm already did its thing.

> Take that as a hint.

As a hint that sometimes you should do you research before making claims? Agreed.

> I read the content as lacking maturity, emotionally loaded

The article is perfectly fine, but what I gather from the reactions of Go fans is that they are lacking in maturity and become too emotional if their toy is criticized.

Something the author explicitly mentioned in his article. You should read it.


Who cares if it is a legitimate criticism and makes unique points in both cases (also, they were both written two years apart!)? Some call it "inflammatory" but it has scientific and critical value nonetheless.


> Who cares if it is a legitimate criticism and makes unique points in both cases?

Clearly, the people flagging it care, whether because they disagree with your assessment of it providing legitimate criticism and unique points in both cases, or because they think some other quality it has outweighs that in assessing it against the bar for belonging on HN.

> Some call it "inflammatory" but it has scientific and critical value nonetheless.

Value is subjective and people clearly disagree with you on this point.


If you find it does not have value to you, don't upvote it and ignore it. Don't flag it to try to hide it from people who it may have value for. It's clearly not spam, so it's not your job to determine whether it has value for other people.


Flagging posts that would not fit on HN or would just cause pointless flamewars is acceptable. Given the state of this thread, I think it's even more justified.

"Users [flag] post as breaking the guidelines or otherwise not belonging on HN."

https://news.ycombinator.com/newsfaq.html


I've seen far more inflammatory commentary/criticism in the tech community over the years. This post is honestly pretty mild if you look at it objectively.

The fact that a small subset of the Go community is triggered by this post and can't behave in a civil manner isn't a reason to flag it.


> I've seen far more inflammatory commentary/criticism in the tech community over the years.

That it isn't the most inflammatory commentary (even if one agrees with that, which is, of course, subjective) in the tech community doesn't mean that people assess that it “gratifies one's intellectual curiosity.” The latter, not the former, is the criteria for being on-topic at HN.

Naturally, people will disagree with what is within and outside of this boundary, and use flags or not accordingly.


Can we do without the finger pointing as well? I am not part of the Go community, and I would prefer not seeing any reaction posts and divisive opinion pieces on this forum, whatever the language or topic.

Honestly I just hope @dang nukes this thread from orbit, and maybe it'll be posted again and get a cooler reaction from everybody.


> I would prefer not seeing any reaction posts and divisive opinion pieces on this forum, whatever the language or topic.

Eh, unless there's evidence a submission is genuinely shitposting--i.e. trolling the community by being intentionally divisive while not actually believing what they're saying--or is outright offensive, I really don't agree.

Writing provocative critiques, like this, has been a standard in the tech world for as long as I can remember. If the rule is "don't post anything that runs the risk of upsetting someone", we'd have to ban half the leaders in the community, including Linus Torvalds.


> cause pointless flamewars

So the worse the (Go) community behaves, the more careful authors have to be?


What makes a reaction knee jerk? Is it just not liking it?


To play devil's advocate: this author is known for often having a combative style. There's usually lots of good substance alongside that style, but the tone is what it is, and you could argue that it's needlessly incendiary. (Though in their defense, the post yesterday was self-described at the very top as "a proper rant")

HN is a powder keg of emotions about programming languages, and fasterthanlime's posts tend to be... shall we say, "sparky"


But that is literally one of the oldest logical fallacies in the book - Ad Homenem - defined as "(of an argument or reaction) directed against a person rather than the position they are maintaining."


I'm not saying people were right to react this way, I'm just explaining.


Could you link? I must have missed it.



Ah OK just the author's 2020 post. Thanks!


Many people say Go is a better language to scale a codebase than Python, mainly because of typing, but I really doubt it. I can't tell for sure, because I haven't done a lot of Go coding. But to me the stated problems and the general lower-level nature suggest a productivity loss compared to Python, on average.


I've written lots of python. Biggest codebase had ~100Ksloc of it.

I currently have a ~80Ksloc codebase in Go.

I like python. I dislike go.

I still hold the position that scaling a codebase is easier in go than in python.

* Goroutines + channels are generally easier for someone besides the author to reason about than their python equivalents, leading to a more consistency and better boundary definition.

* Python has a lot of magic in it - and that stuff is really cool, powerful and fun - but.. it also makes it incredibly easy to write stuff that works well together until it breaks in some wierd corner of a seemingly unrelated object somewhere.

* As python codebases grow, duck-typing becomes much less pleasant - you start seeing a bunch of `if isinstance(...)` in the code and eventually someone will come along and start implementing parts of a type system on top of the python code that exists (see also the previous point).

Those are the primary reasons for me, but there's also just a certain lack of friction in the go codebase (compared to python anyway) that I can't really describe well.


For me it is hard to attribute such differences to a programming language rather than the people creating and maintaining the code.

At the moment I am maintaining a C# codebase which doesn't feel maintainable at all, and I don't think C# is the only problem there.


> This article was, yes, a little aggressive in tone

A little?

"[...] but I remember fondly the time an audience member asked the Go team "why did you choose to ignore any research about type systems since the 1970s"?"

"Unless you're out for confirmation bias, that whole article is a very compelling argument against using Go for that specific problem."

"[...] and tooling that would make C developers jealous, if they bothered looking outside their bubble."

"[...] and most importantly, you adopted a language that happened by accident."

"Evidently, the Go team didn't want to design a language. [...] "And so they didn't. They didn't design a language. It sorta just "happened"."

"And breaking down an argument to its smallest pieces, rebutting them one by one, is a self-defense tactic used by those who cannot afford to adjust their position in the slightest. "

"We've reached the fifth stage of grief: acceptance."

"Because it has been decided that abstractions are for academics and fools [...]"

> [...] but presented very honest and accurate information about a language that the author clearly has experience in.

It's biased flamebait, just like the original article.

> It seems like a lot of the people complaining in the comments didn't actually read the article. The author even explains how those who have bought in to Go may not want to hear what they're saying and it's right. No one wants to hear that their baby is ugly but sometimes it's the truth.

>

> To those who do use Go: someone can call your baby ugly and you can still love it.

Sure, I'd love to read such a well-considered article. Please link any you know of below.

Here's an exemplary article that managed to criticize Go without evoking a flamewar ([1]): https://gitlab.com/esr/reposurgeon/-/blob/master/GoNotes.ado...

I pose that if you present valid arguments in a reasonable, intellectually-curious way, people will respond positively. But if you set out on a holy war instead, well...

[1]: https://news.ycombinator.com/item?id=29494136


It only hurts because it's true.


Sure, the baby is ugly. That's perfectly fine. The problem is when you continuously insist that the only reason anybody could ever love the baby is because they're delusional and in denial.


To put it shortly, the tone is so pointlessly aggressive that it obscures what accurate information the post contains. The information itself is also presented in a haphazard manner, seemingly chosen to maximize the critical intention as opposed to clarifying things for the reader. Some info that would be potentially valuable to the reader is simply not there, purely because it doesn't fit the "bad Golang!" overall emphasis of this post. E.g. what about pointing at newer novice-friendly prototyping languages with a better FFI story than Go? There's quite a few of them: Nim, Crystal, the new language Hare etc. But you won't find any serious mention of them here, or any comparison of their benefits and drawbacks.


I use Go heavily cross-platform developing DataStation [0] and dsq [1]. I am not an expert. And I don't have proof for it but on some rudimentary benchmarks the Linux-specific file idioms in the Go standard library definitely don't seem to translate well to even macOS let alone Windows. For example some good streaming techniques for reading large files on Linux that work really well there seemed to be pretty bad on macOS.

I think Amos has presented more proof than I can on the topic of just how Linux-influenced Go is. And I think it is fine for the majority of Go users because the majority users of Go are building server apps or Linux CLIs.

Amos has spent some time building cross-platform desktop systems with Go for itch.io and I think I'm seeing some of the same things they are in that scenario.

I think this is a reasonable article. I didn't notice anything too flame-y myself but if for you Amos gets flame-y at any point I think that's worth ignoring because there does seem to be something up with Go in cross-platform applications. Amos does have good experience here. (Go look at itchi.io's github like wharf [2] or butler [3] where they are/were the main contributor.)

I like Go a lot and for most things I'd keep using it still. Just sharing some observations.

[0] https://github.com/multiprocessio/datastation

[1] https://github.com/multiprocessio/dsq

[2] https://github.com/itchio/wharf

[3] https://github.com/itchio/butler


I'm not emotionally attached to Go, I want to learn rust, and I'm old enough to realize the search for the perfect tool is utter folly. So the inevitable religious wars that surround critiques like this don't move the needle for me.

So while this article didn't really convince me of anything, I have to admit I did learn a thing or two (or five). Kudos to the author, who is a fantastic writer and communicator. Even if you aren't neck deep in the language wars, it's worth reading.


I feel like go hits a sweet spot between productivity and correctness.

Working in Python, I constantly run into errors that static typing could have caught. Working in Rust, I feel like I'm constantly fighting the borrow checker. Maybe a more experienced Rust programmer would feel differently, but one of the strengths of Go is that it's relatively easy to learn


The sweet spot is something like StandardML. You get an actually sound type system (with genetics that aren’t a hack), but skip the complexities of direct pointer manipulation.

It can do this while also being easier to learn than go too (designed so students could learn it and implement it too).

The only reason go is popular is because google put thousands of man years and countless millions of dollars into it.


I use Go. I love Go. The reason why is pretty simple for me: It gets things done in a way that feels comfortable and has strong tooling. I am well aware it has shortcomings. I occasionally even run into them. However, as someone who doesn't particularly /like/ writing code, and instead sees it as the inevitable requirement of creating things that do something for me, I really appreciate that Go for the most part doesn't get in my way so I can make things that do something and move on.

I generally heavily preference scripting/interpreted languages over compiled languages, because compiled languages have a bevy of stuff that qualifies as "getting in my way". Go is refreshingly not like that, and therefore is the primary compiled language I use these days, and largely the primary language I use at all. Then again, I'm not an SWE. I'm a SysOps/SRE turned PM-T. So it's unlikely I would ever dig deeply enough to care about the particulars of a language's design other than knowing which problems it is best at and which problems a better choice can be made to solve.

Both this article and his previous article, I've read thoroughly. I understand and appreciate the criticism. But fundamentally there's seems to be an implicit assumption within both articles that other developers who use Go don't already know (most of) these things. Anyone who uses Go long enough will eventually run into some of its shortcomings. I'm not sure exactly why it rubs me the wrong way, but it feels like there's something subtlety insulting in the way the author presents his arguments. Like if we weren't all stupid rubes we'd just use whatever his preferred language is (Rust, presumably?).

The way people get zealoted about languages these days (especially some pretty terrible ones for getting things done) tempts me to just go back to writing Perl. In all the languages I've used over the years, I've probably got more raw work done in Perl than anything else, and it's still near and dear to my heart, despite being objectively a badly designed language.


Yes, this is a really good article, I think the tone is warranted! I'm writing a Go course at the moment - all the basics on channels, slices, pointers with all their warts - and am not shying away from saying "sorry this doesn't make any sense, you just have to know it and beware".

I appreciate the nil method receivers, the zero value meanings, the types that are actually hidden pointers, but if you're not coming from C, a lot of it sounds inconsistent and counter-intuitive. And I'm not sure there's a way to justify it to programmers who have grown up on better, safer, clearer abstractions, even with the potential performance gains.


I'm not sure why choice of programming language is such a heated topic. "Want to use Java? Over my dead body", said a ex-Uber employee. "Let's rewrite Kafka in Rust to avoid using Java in our team", said an employee in a $10B+ unicorn. "Go is a plague. Let's use Rust", said an employee in another $5B+ unicorn. Doesn't language itself contribute just a small portion to our productivity? The platforms and ecosystems of programming languages usually matter more? And it's simply childish to argue that GC sucks when your services handle merely 100s of QPS (even if millions of QPS, so what? It really depends on what you try to achieve), or to argue that language X sucks because it does not have feature Y. I hate to break the news to language fanatics: your program is slow most likely because you didn't choose the right data structures or algorithms instead of using the wrong language. You productivity sucks most likely because you didn't write simple, correct, or operable software.


> I'm not sure why choice of programming language is such a heated topic.

I think there are two reasons.

First, languages live or die by their ecosystems. If you love a language, it's very much in your interest for other people to use it, so they write code that you can use.

Second, most programming happens at work. Most people don't get to choose what programming language they write at work: they're locked into whatever choice somebody else made. The more popular your language is, the more likely that choice is to be made in your favor (or alternatively, the easier it'll be to find a job where that choice has been made in your favor). If I want to write Idris at work, well, tough luck.

Both of these are largely zero-sum, which makes things worse. It's not 100% zero-sum, in that if you manage to light a passion for <language> in somebody they might write code (in that language) that might not have been written at all. But mostly language evangelism won't change the total number of programming hours per year (or the number of available programming jobs), so all that's left is to fight over who gets how much.

So if you care a lot about which programming language you write, I don't think it's odd to come at it from combative angle: it's a fight! Some will lose and some will win, so you better try and be one of the winners.


> I'm not sure why choice of programming language is such a heated topic.

Because the market identifies job suitability by years of experience with a particular tool, so the popularity (in the market) of tooling a programmer has experience with is intimately tied to their job opportunities and financial prospects.

If you are an “X programmer“, attacks on X are attacks on your livelihood. Conversely, if there is an abundance of Y programmers, convincing people that X, which far fewer are proficient in but where you are one of them, is superior for some high-value domain, is enhancing your livelihood.

You’ve seen informercials exaggerating the negatives of alternatives while hyping a product in order to sell it? Well, while it's framed as being about tooling that's one step removed, that's basically what programmers are doing in language flamewars.


The flagged feature needs to be tweaked on HN; it's being used far too often to censure opinions others simply do not agree with.


It's pretty much the whole culture now, not just HN. Anything I don't agree with is an evil and must be stopped at any cost.


It's also being used to try and avoid another flamewar, which this article seems practically guaranteed to cause.


Go fans misbehaving shouldn't be a reason to avoid submitting articles.


> Why does the Go compiler suddenly care if we provide explicit values now? If the language was self-consistent, it would let me omit both parameters, and just default to zero.

Without analyzing the rest of the post (which I read without having the skill to fully comprehend), this stuck out to me.

Perhaps the language behaves one way and not another by design? It's abstraction. By using a Struct, I'm telling the function "don't worry what is in this one box of data, just take it and process it as best you can" while defining two inputs to a function says "I demand that two pieces of data be present".

I don't think it's an inconsistency to see this behavior.


It is a very minor point and could easily be removed from the article, but I had that realization while writing those samples and it stuck with me.

I really think that if we follow the "zero values by default" philosophy, it wouldn't be shocking for Go to accept omitting function arguments and just zero them.

The fact that it doesn't, and insists on you passing the right number of arguments, makes the point that you can't in fact, just afford to zero out everything that isn't explicitly specified.


that's a trade-off with catching user errors, are you more likely to forget to pass an argument or need to pass a zero value?


why isn't it inconsistent to allow creation of a record with missing components but to deny creation of a stack frame with missing components


I don't know nothin' about Go. But this complaint really surprised me:

> Go not letting you do operator overloading, harking back to the Java days where a == b isn't the same as a.equals(b)

Does this guy really not understand that in a mutable language, (eq ...) is not the same as (equalp ...) and should never be confused with it?

Also: operator overloading is the spawn of Satan.


> operator overloading is the spawn of Satan

I used to agree with you, because of the abuse of operator overloading like iostreams and making DSLs with it. D does support it, but in a way that discourages non-arithmetic uses (such as it won't allow < <= >= > to be overloaded separately).

Operator overloading allows for things like complex numbers, arbitrary precision numeric types, etc., to be done with a library module.


> Operator overloading allows for things like complex numbers, arbitrary precision numeric types, etc., to be done with a library module.

Why is this desirable vs. implementing those types in the language itself?

I think we've gone down a weird path where implementing things "in userspace" is seen as an inherent good -- why?


> Why is this desirable vs. implementing those types in the language itself?

That's a very good question.

1. It's simpler. In D, we transitioned from a builtin complex type to a library type. It was a happy experience. The simpler the compiler, the easier it is to deal with.

2. Most any programmer can create a library type. Relatively few can modify a compiler to add a new type.

3. It takes the pressure off the compiler team to develop more arithmetic types.

4. Users can add arithmetic types without needing anybody's consent, and can do it right now.

5. It tests and verifies the metaprogramming abilities of the language.


Elaborating on 3/4: the domain experts don't need to be compiler experts too.

There are always going to be more numeric-like types (int, float, complex, bigint, rational, symbolic-comp types etc.). Numeric vectors that act like numbers are useful (see: numpy), and trying to stick those all into the language is far harder than allowing extensibility.


This is probably the best talk ever on the general topic: https://m.youtube.com/watch?v=_ahvzDzKdB0 [Growing a language by Guy Steele], seriously give it a look if you have the time and do put up with the seemingly strange start.

But at around the end it asks this (paraphrasing): Should a language have complex numbers implemented natively? Should it have numbers module n implemented natively? What about intervals, or rational numbers?

I also dislike the ridiculous overloading of cryptic symbols, but neither extreme is good. Not allowing overloading will give you BigDecimal.of(3).add(BigDecimal.ONE).divide… , while allowing it unrestricted will give you things like msg #!! something. But perhaps a sane middle ground is to allow only basic operators (+,-,*,/) to be overloadable.


The author definitely understands that. The point is: when you don't have operator overloading you get stuff like that which does demonstrably confuse many people

In languages with operator overloading this just isn't a concern at all because == does the obvious thing


> In languages with operator overloading this just isn't a concern at all because == does the obvious thing

And what is the obvious thing? It varies wildly among languages, even within C++ itself.


The obvious thing is to check if the contents are equal. I don't know what cursed C++ you're looking at if you're finding a ton of string implementations not doing exactly that...


== should do the obvious thing. But with operator overloading, it's not clear that it does, unless you need to read the implementation of == very carefully.


How is that any different to some opaque method call? By the same logic `a.equals(b)` might be doing something funky under the hood


True. But people think about it a bit differently. People don't always expect == to be a function call.


Sure, but I think '== might be a function call' is a lot less confusing than '== sometimes compares for equal value and sometimes doesn't'


I don't get the problem with operator overloading. Yes, it can be implemented badly, but so can the equals() override. You can't even call a.equals(b) safely in many programming languages because either a or b could be null. I've run into so many null pointer exceptions in Java because someone wrote a.equals(b) when they clearly meant a!=null && a.equals(b).

Every time I have to write `BigDecimal sum = one.add(two).add(three).minus(four)` I cry a little. This is effectively no different from operator overloading and it's what special number implementations in all languages without operator overloading seem to end up doing out of necessity.


Usually you do want to compare by value, so it should get the obvious syntax. When you want to compare by reference, you should write if(&a == &b) or ReferenceEquals(a, b) or something.


Without operator overloading, it is basically impossible to adapt a language for numerical computing/data science applications. Yeah, operator overloading is a powerful tool that's easy to abuse; no, it's not optional if you want the language to succeed at all in a whole bunch of applications.


Mathematica works just fine without user-defined operator overloading.


> Also: operator overloading is the spawn of Satan.

It's necessary for "powerful" generic programming. In fact, the entire reason user-defined data types can be easily used in C++ libraries like CGAL, Eigen, fmt, Kokkos, ranges-v3, etc, is because of operator overloading.


> Also: operator overloading is the spawn of Satan.

It is. And I'm glad Zig has none of that. `==` only works for primitives and you will never be confused.


Not sure that's a good idea. The concept of some types being special should not be something exposed to the user.


I use go at my ${DAY_JOB} and I love go. I think it’s a little too aggressive on our part as a community to flag this post. Although, I do not agree to all the opinions shared by the author. Let's agree to disagree :)


Why's this flagged? It's not poorly written and makes good points. I don't agree with many of them, yet I still up-voted because it makes good points.


This article should not be flagged.


Yeah, unfortunately sorta shows that this community is becoming like a lot of communities: anything they don't like == toilet.


Unrelated (though a fun read) to the content: Thank you for making your blog readable. The typography choices are exemplary.


This shouldn't be flagged...


I flagged it because it appears to be written to mostly elicit outrage, as opposed to informing the reader.

For example the headline "Mom smokes, so it's probably okay" and then 8 paragraphs of lead-up to the argument that the Go standard library has an inelegant IP type. Afterwards the author equates people using custom types to "build a whole new type system".

"Evidently, the Go team didn't want to design a language." is also pretty insulting if you consider how much the Go team wrote and talked about why they designed things in this way.

And to make a lot of weird arguments work, the author then refuses to treat any cgo feature as part of the Go language ecosystem. That's the point where I was convinced that the author wrote the summary before researching the arguments.


The headline and the paragraphs lead up to an illustration how the IP type in Go is inelegant because of several shortcomings in Go. It's a perfectly acceptable instrument to the argument.

It immediately follows up with interesting discussion about how it's acceptable for a team of experts to use Go. I think he's wrong, Go is perfectly powerful in the hands of novices. And I actually think a team of experts like Tailscale would probably be much better served by choosing Rust.

But that's all besides the point. The article is excellent, fits our forum and is a great basis for discussion. You are not using the flagging feature as it's intended to be used.


Are those issues really so egregious? There is a tremendous amount of content geared towards "informing the reader" and I'd prefer to draw my own conclusions about the author's intent rather than having a censor (who is assuming bad-faith) try to protect me from a rather mild rant (in my opinion).


[dupe]


Is this a bot? The last 6 posts of the account are copy/paste spam.


No, not a bot. Just using the same response to the same question posed by different people.


I have a hard time judging the "actual quality" of the article, but considering the quality of the discussions it generates, I don't think something like that is a good fit for HN.

There's something that I think is important to mention: there's a difference between theorical ways to make bugs and bugs that happen in reality. The author spends more time talking about theorical ways to make bugs than bugs that happen in reality. I'm all for the "we should be using good tools", but there's also a point where you shouldn't use a tool just to use it.

An example of that: at work we have a very huge codebase that's a pile of C++, C#, JS and TS. The codebase is more than 20 years old. Typescript is a relatively recent addition. I've seen part of the adoption, and talked a lot with the people that adopted it. And the conclusion is that it didn't really reduced the errors we have in production. We already have processes to cover for that: being careful during development, pair programming, code reviews, automated tests, manual tests. However, it made the development way easier, since Typescript has a better IDE support. But it didn't lead to use reducing our processes.

A lot of the article seems to be rationalizing bad experiences with Go due to bug happening in production. I don't want to reject the criticism entirely, but I think the language isn't the only thing you can blame here. And my own experience is that processes matters more than the language when try to write good code. It seems like the author has a different experience compared to mine, and I don't want to fall into the fallacy of "it's possible to write bad code in every language". But I think the author should recognize that people can have widely different experiences, and that there isn't always someone that's right and someone that's wrong.

I've read lots of thing about Typescript adoption and lots of people/companies mention a reduction of bugs in production. This didn't happen for us. That doesn't mean they're wrong, and that also doesn't mean that Typescript is useless for reducing bugs in production. It means we have different experiences. I think it would be more productive to talk about our experiences, and try to find out why they are so different. This way we could learn a bit more about software engineering, and develop more empathy for each others.


> there's a difference between theorical ways to make bugs and bugs that happen in reality

On a large enough (time)scale, no there isn't.

But also, all this is rooted in years of running and/or watching someone run Go in production. These bugs aren't theoretical, they cause incidents and outages, and occasionally wake me up. I don't like being woken up.


I'd appreciate it if you wouldn't ignore most of my post and my experience. As I've said, our codebase is more than 20 years old (which is a large time scale for most code), and the vast majority of errors are logic errors and not TypeError: Thing is undefined. You seem to think that only your vision of things is valid, which is a terrible attitude to have. If you don't like being woken up, find a job where you're not on call.


This article should get unflagged. This is an eloquently written article and a good discussion about Golang. I think we need more articles critical of Golang.

Edit: I'm really shocked by the downvotes. Can someone explain why my comment is worthy of being downvoted?


The recent paper from Go core devs, "The GO PL and its Environment" highlights that a major aspect of Go is its environment/ecosystem, from the very start.

But the OP, in either article, zeroes in on narrow language/STL design choices and never zooms out to consider the ecosystem and how Go works in an actual software engineering team. Pardon the vulgar analogy, but this is like zooming in on a dog's asshole and going "what the fuck is this? It looks gross and shit comes out" without considering that it is an integral part of a well-functioning whole.

It all comes down to misunderstanding each other's positions.


So much Go hate and arguments over language design details. Meh. Back to producing fast, well-organized, maintainable, bullet proof code in Go for real-world problems.


> bullet proof

Based on the article, I doubt it.


You guys flagged this? That is not the move of a vibrant, growing, confident community. I’m no fan of the Rust jihad myself, but this isn’t spam or hate speech or whatever.

That is a super weak move.


It's normal for users to flag meta follow-ups to recent big threads, especially when they contain a lot of flamebait.

If users didn't flag these, HN's front page would largely consist of meta flamebait follow-ups.

Here's the principle: curiosity withers under repetition and fries under indignation; also, meta is the crack of internet forums. Repeat+indignant+meta is definitely worth flagging.


@dang you moderate this forum very well, arguably better than any forum out there.

You and I know perfectly well that some kind of tribal loyalty around loyalty on a programming language (they all suck) is an IQ test.

I’ll look the other way on Siebel committing outright fraud, and you let these idiots argue about go vs Rust without displaying any bias.

Everyone knows that Thompson invented UTF-8. And I’m smarter than Pike, who was always a pity hire.


Discussion from yesterday on the same topic from the same author: https://news.ycombinator.com/item?id=31191700

This is in response to that post from yesterday. It's worth flagging this one, or else it's going to be an infinite loop of knee jerk reactions. We can do without these.


Flagging articles that criticize popular tools seems to be common. Particularly so with Go specifically.


Go and Rust seem to have some of the most rabid fan bases of all programming languages and this article mentions both. A perfect HN storm.

I think all the arguments against Go in this article are fair and I think you can write articles just as long about any programming language of your choosing. It's very strange to see the level professional programmers will stoop to if their favourite tool gets criticised.

The fanboys of programming languages are the worst part of a language community. The "why not rewrite it in Rust" and the "you're golanging it wrong" crowds only drive people away from their respective languages.


I guess it's because it's not anything that hasn't been said before. Go is easy to start with and gets harder as you debug deep problems. Rust is very hard to start, then it gets easier over time. This has been said in many other threads, and we all know it's true.


So the reason for the censorship is they read the entire article and saw nothing "new" about something you "all know is true"? That's indeed a "new" way to discourage reasoned discussions.


Dang explained it many times, that HN is optimized for interesting things instead of just reasonable discussions, particularly if they are repetitive / predictable.

Also it's not a ,,new'' way to discourage reasoned discussions, it was already like that when you decided to join HN in 2016.


So you have nothing "new" to say after all, but repeating what "everyone" should know already. HN should now censor your comment.


I didn't post this. Posts and comments have different criteria.

But if I would be censored, that's OK, it happened multiple times before, but I still prefer it compared to other web forums, because I deserved it.


Right now our only mechanism to indicate that we don't think a post is appropriate is to flag it. We don't have the ability to downvote posts that we don't feel meet the quality bar for being featured on HN.


Why is it flagged then? It is clearly an appropriate posting.


> the Rust jihad

As a Rust jihadist myself ... yeah I can't disagree with this description. Even I get sick of all the Rust chatter/evangelism on HN sometimes. I love it and it's my preferred tool, but I wouldn't mind hearing about some alternative topics at least some of the time.

(As for the article: I wrote Go for several years professionally, and what he says, well - rem acu tetigit. I know a lot of people on that former team who were converted to Rust by the experience of writing Go. And then I know others, with a natural propensity to cultishness, who just responded the way so many people are responding in this thread.)


wtf is rem acu tetigit


Sorry - 'hit the nail on the head'. Literally: (you touched == tetigit (tangere)) ([the] point == rem (res)) (with [a] needle == acu (acus))'.[0] 'Point' (res) is already abstract - 'matter', 'thing' - not being used figuratively like the rest of the phrase.

It's one of those phrasoids which is permanently stuck in my head from Latin classes when I was a teenager, but I might've been wrong in thinking it was one of the more widely-recognised ones.

[0] 'You' is implied by the second-person verb ending on 'tetigit', 'with' is implied by the ablative case ending on 'acu' (the 'ablative of means'), while 'the' and 'a' are filled in altogether since Latin has no concept of definite/indefinite articles.


2014 Story Time, when I was a phd student working on programming languages (apologies for my broken English, non native speaker here).

The multidisciplinary lab I was in had a "Go or Rust" dilemma. As the language guy, I was asked for my opinion.

I had no experience with Go, and a small bad one with Rust: there was weird stuff going on with pointers, and even seemingly simple programs would fail to compile due to a less than happy borrow checker. Working with Rust required a heavy learning investment. On the other hand, Go looked simple, with amazing goroutine, fast compilation time (great for the code/compile loop), and backed by a big company, which is reassuring for then still young languages.

As I could not form my opinion on significant coding experience, I looked at the principles. It appeared to me that Rust design was guided by language principles, whereas Go was guided by system/engineering requirements. For example, Rust had generic and sum types, which Go lacked. Rust error are "naturally" dealt with using sum types, whereas Go relied on error codes. Go had that "operating system flavor", with features usually closed to the OS directly implemented in the language (goroutines, which are great). Rust had that "things are complicated flavor", in both the language (borrow checker, several kind of pointers), and the library (several kind of string?!) which at first is of-putting.

Being a language guy, I argued for Rust's good use of language principles over Go's more practical approach. My bet was that Rust usability would improve. A mix of Java/Scala was chosen. I now code in C++...

--- --- ---

A note on simplicity. Simplicity is a lie. Things (not only programming languages) are not simple, they are messy, hard. Truly hard. In my experience, simplicity claims are usually superficial, and show their limits when going a bit deeper. As programmers, we like to have simple, generic, abstracted constructs, because it makes our life easier. But the world is not generic; it is full of special cases, corner cases, situations that do not fall in a nice hierarchy, which is its beauty. It took me too long to "accept" this beautiful complexity, and to stop fighting it. If you are still looking for simplicity, maybe check that you are not fighting the world's complexity.


Rust was very much half-baked in 2014. Version 1.0 was released in 2015, and critical features for dev UX like non-lexical lifetimes or async weren't supported at all until late 2018. In fact, Rust would've been a terrible choice back then. Lots of people seem to miss that, but it's also why this whole anti-Golang flamewar is so pointless: a lot of the Golang stuff out there is not greenfield, but was written back when there was hardly any reasonable alternative to it, and certainly nothing like modern Rust was available.


I guess that, like everything, it depends on what you're using it for and which compromises one is willing to do.

I'm not proficient nor use at $DAY_JOB C, Go or Rust. However, I wanted to write an Emacs dynamic module and those were my main choices AFAIK.

I've picked Go to write a grunt work module (fetching JSON, parsing it, transform it, send back to Emacs) and it's been smooth sailing.

I then found the benefits of writing client glue code between Minikube, direct K8s and Docker and Emacs a breeze.

What lie am I telling myself?


Not a fan of articles that attempt to speak for me or say that I have stockholm syndrome. It’s super gaslighty and a pernicious form of contempt culture in the tech community. Instead of just saying how they feel about a language, they try to claim a moral high ground.


What's up with the anti-Golang shitposts lately? I liked fasterthanlime better when he didn't just sound like a card-carrying Rust zealot. This isn't even about the practicalities of his argument really; optics matter, and it's especially bad since the Rust community used to be known for its politeness and always being fair to other language communities.


The last time his "I want off" article was reposted[0], the comments were pretty rough, ranging from ad-hom attacks to (at best) misunderstandings of the arguments he was making.

I see this article being an address to these criticisms (which are not limited to this forum, I've seen similar arguments on twitter, etc.).

Pointing out shortcomings isn't really impolite or unfair. The author specifically mentioned shortcomings of Rust as well.

[0]: https://news.ycombinator.com/item?id=31191700


Pointing out shortcomings isn't impolite - writing that Go wasn't designed, but happened by accident is however (IMHO).


> writing that Go wasn't designed, but happened by accident is however [impolite]

That's one of the most mild and inoffensive criticisms I've ever read on the internet. You can't seriously be indignant about that.


Especially since it was designed by computer science luminaries who are almost certainly better programmers/engineers than the author of this blog.

It's also more accurate to say that Rust wasn't designed / was an accident since it was technically a side project of one guy at Mozilla.


Both languages were designed by probably better programmers than most in this thread. For that matter, the vast majority of successful programming languages surely were. I'm utterly lost at how that relates to anything.

One can plainly be a good programmer and yet create a bad language. I'm sure you are well-informed enough to analyse his argument on its merits, even if it were written by a gang of monkeys with typewriters.


The truth cannot be impolite.


> The last time his "I want off" article was reposted[0]

Of note: the last time in question was yesterday, the flagging and ad-hominems pretty obviously made lime's cupeth runneth over.


I might not agree with fasterthanlime's opinion on Go (9/10 times I would opt to use Go over Rust), but calling this post a "shitpost" is unnecessarily dismissive. The post, like his previous post on Go, contain well thought out points that add to the discussion at the very least. Also I like his sense of humour :)

Edit: though, I suppose saying Go is not designed is also equally unnecessarily dismissive and hyperbolic.


> Portland Oregon, the capital of grunge, coffee, poor weather and whiteness

it's kinda a shitpost


It's sarcasm, dumb humor - not trying to be inflammatory, or provocative - i.e. not shitposting.

And let's face it, Portland kinda takes itself too seriously.


I moved from Austin TEXAS to Portland to get away from the heat and forced conservitism. I also moved to Portland for the weather (cool and wet vs hot as hell and dry). I don't have to use my air conditioner!

As for Portland taking itself too seriously, are you serious? Portland has so many quirky things that the conservative states don't have(much less putting walls up and making some people, making 2nd class citizens ((yes, voting rights)), and you say Portland is too serious? Good luck with that gaslight.


They're funny(ish) asides which is pretty normal for lime.


I'm not complaining. I get the joke. I'll leave this for the Seattleites to argue.


yeah the actual titleholder to those is seattle


Well-thought out, how? It's flogging a dead horse in a transparent, deliberate attempt to create controversy and flamebait. That's a shitpost pretty much by definition.


I don't think it's obvious this was done in bad faith, even if the author is at times flippant.


Reminder that I'm not part of /any/ Rust teams, not part of the Rust foundation, etc. etc. My site is my space, and it is specifically designed to let me post my point of view without having to bear ( ) the responsibility of speaking for entire communities at once.

It's important for individuals to be able to do that, and it's on everyone else to make the distinction.


Thanks for your article. I hope you can ignore all the vitriol. It's embarrassing to see what I thought was a generally intelligent community having a collective tantrum because someone was mean about its favourite toy.


> the Rust community used to be known for its politeness and always being fair to other language communities

I have no particular affinity for Go or Rust. As an outsider this is not how I’ve ever perceived the Rust community, because the most present and visible parts of the Rust community were people showing up and complaining that Project X didn’t use their preferred silver bullet


Also honestly it's very toxic to anybody right of center. It's the type that says "we're so accepting" when really they only are of certain stuff. Lots of pronoun people and making the mascot "non binary" is needlessly shoving their ideology down people's throat. Not a problem in the U.S. because it fits with the corporate woke ideology but sure as hell gonna be if they want more worldwide community.

It's also way too hugboxxy and tbh that feels just as toxic some times as the alternative. Positivity to the point where it's obviously fake and forced and insincere.

Edit: howinteresting I can't reply to your comment but you are proving my point. At least you people are being more honest that it is intended to exclude a bunch of people.


As someone who both loves the Rust language and is very right of center, I've never found politics to pose much of a problem for the Rust community in practice. Yes there is occasional virtue signalling here and there but people don't let it get in the way of making programs that work.


Yeah, as someone who's gay and left-wing but equally irritated by the 'virtue signalling' stuff (my ideology is basically r/stupidpol), I don't find the Rust community too bad.

(FWIW, I appreciate your open-mindedness. I think that's the main thing I find objectionable on (parts of) both sides of the aisle: an inability to regard those who disagree as fundamentally well-intentioned human beings who happen to hold different beliefs.)


"pronoun people"

What, you cant handle queer people existing?


[flagged]


> Their comment is about the (almost universally straight) people who demand to be called 'xe' or 'qwerty' or whatever.

The vast majority of people I’ve seen using neopronouns, or “it” or “they” pronouns (either exclusively or alternatively with classical gendered pronouns, e.g., “she/they”) have nonbinary gender identity or agender identity, and the vast majority of the exceptions are trans, and all the rest (i.e., the cisgender ones) I’ve encountered are one of bisexual, pansexual, asexual, or same-gender attracted, usually also with gender non-conforming presentation.

I have yet to encounter a cisgender heterosexual with nontraditional pronouns for their gender, though I am sure there are some somewhere doing it.


> The vast majority of people I’ve seen using neopronouns, or “it” or “they” pronouns (either exclusively or alternatively with classical gendered pronouns, e.g., “she/they”) have nonbinary gender identity or agender identity, and the vast majority of the exceptions are trans, and all the rest (i.e., the cisgender ones) I’ve encountered are one of bisexual, pansexual, asexual, or same-gender attracted, usually also with gender non-conforming presentation.

Yes, I'm talking about sexuality, not gender. Most of the people I know, and/or have met, who identify as 'xe' and suchlike, are straight and usually cis (in the sense of 'not actually trans' - they do often have 'gender identities' like 'genderqueer' which amount to 'I wear heels sometimes').

It's predominantly - in my experience - straight people who covet the counter-cultural aspect of being 'queer', but who face the small problem of not actually being gay or trans or anything else, which is easily remedied by adopting one of those slightly-meaningless 'gender identities' which uniformly amount to 'I'm a teeny bit [masc/femme] sometimes'.

(I literally had a conversation with someone once who argued that watching porn didn't mean they weren't asexual. They also happened to be in a long marriage with a husband they no longer slept with, though they once had. It took all my strength not to say "lady, you're not asexual or queer, you're just a bored housewife in a dead marriage".)


There's still a lot of people out there who consider 'they/them' to be nonstandard when used for a specific person (as opposed to 'they/them' as a replacement for the generic 'he'; almost everybody opposed to that has come around or died).


Yeah, I should have clarified that I don’t consider that non-standard. Well, it’s semi-standard, I suppose. But yeah, I had in mind the ones more like ‘xe’ and ‘xer’.


I know many trans people who use nonstandard pronouns like xe, ze or it.


Sorry, that's true, I didn't mean that literally no trans people (or gay people, black people, etc) use non-standard pronouns. I meant that it has nothing to do with their being gay or trans. Certainly some people may happen to be trans and also happen to use those pronouns.


I hope they are not expecting normal people to use these silly words.


good


Calling a well documented blog post, even one you disagree with, a "shitpost" should be an embarrassment to you.

Guy makes a blog post about Go a few years ago. It gets posted here time and time again, not of his doing. A bunch of people challenge his premises, so he makes another post diving deeper into his arguments.

So what?

What's up with the literal hundreds of "Golang is amazing" posts this site has had? Is someone attempting to express dissent clearly that much of a bother?


But he doesn't dive deeper! If anything, he's more shallow. This just doesn't read like an honest appraisal of Go's pros and cons to me, he already has his mind set from the beginning (ok, we knew that two years ago already) and is just heaping on invectives: "one really good bit does not a platform make", "Evidently, the Go team didn't want to design a language", "Go is not adequate for production services unless your shop is literally made up of Go experts (Tailscale) or you have infinite money to spend on engineering costs (Google)" etc. etc.

What makes me angry about all this Go-bashing is that it might influence decision makers against moving from things like PHP or Node to Go - which I think would be an improvement, no matter how many flaws Go may or may not have.


> What makes me angry about all this Go-bashing

It's just a language! Take it easy.

The guy is not "heaping on invectives" - he's not criticizing you or someone you care about. He's pointing out some flaws in a language in a sarcastic way.


Oh just some sarcasm:

"Mom smokes, so it's probably okay"

"I remember fondly the time an audience member asked the Go team "why did you choose to ignore any research about type systems since the 1970s"? (Emphasis his, not mine)

"It doesn't matter who points out that "maybe we shouldn't hit ourselves in the head with a rake repeatedly""

"Or you can be horrified, as you realize that those complex problems only exist because Go is being used."

"you adopted a language that happened by accident" (a direct criticism at Go users)

"Evidently, the Go team didn't want to design a language."

"Because it needed to be familiar to "Googlers, fresh out of school, who probably learned some Java/C/C++/Python" (Rob Pike, Lang NEXT 2014), it borrowed from all of these."

I just have up here. Do you really think a production conversation can start from this? ESR has flamed less haughtily.


It only hurts, because it is true.


I would consider "Evidently, the Go team didn't want to design a language" to be at least borderline invective. From dictionary.com, definition 3: "an insulting or abusive word or expression". Yeah, that's pretty clearly insulting.


Oh just some sarcasm:

"Mom smokes, so it's probably okay"

"I remember fondly the time an audience member asked the Go team "why did you choose to ignore any research about type systems since the 1970s"? (Emphasis his, not mine)

"It doesn't matter who points out that "maybe we shouldn't hit ourselves in the head with a rake repeatedly""

"Or you can be horrified, as you realize that those complex problems only exist because Go is being used."

"you adopted a language that happened by accident" (a direct criticism at Go users)

"Evidently, the Go team didn't want to design a language."

"Because it needed to be familiar to "Googlers, fresh out of school, who probably learned some Java/C/C++/Python" (Rob Pike, Lang NEXT 2014), it borrowed from all of these."

I just gave up here. Do you really think a production conversation can start from this? ESR has flamed less haughtily.


I'd choose Node or PHP over Go for a greenfield project. (Although I can't think of a case where I'd choose them over Python.) All of those languages at least give me an FFI escape hatch in case I need it that isn't absolutely horrendous, both from a dev experience standpoint and a performance standpoint.


Yeah, preach. I wrote Go professionally for a couple of years, and I write Python now (I know, I know, but they pay me a ridiculous amount to do it). I would choose almost anything, including JS, over Go. It's a good language if you need to write highly concurrent high-level code with low-skill devs, but not for much else, and even then it requires an inordinate amount of menial boilerplate work to get simple stuff done. Having said that, I would still choose it – indeed anything - over Python.


Just a small reminder: fasterthanlime is not the Rust community


From the outside the Rust community seems so defensive about Go that it makes me very reluctant to dive deeper into Rust.


I use both & like both. Ignore the noise!


Yeah, same. They’re both nice languages, they both have great tooling, and they both have areas where they shine. I don’t see them as competitors really, but “You can also implement X in Y” is a fairly useless statement, of course you can.

I’m glad we have as many languages options as we do, and I enjoy writing a variety of languages for a variety of different projects. Sure, I have moments where I think “ugh why can’t I do X in language Y” or “C is cleaner in Y” etc etc.

I’ve found helpful people, critics, and fanatics in every language community. Don’t let that dissuade you from learning Rust (or Go, or …)


One person is not the community


Im a go noobie so I had a question about the following.

> Go's lack of support for immutable data — the only way to prevent something from being mutated is to only hand out copies of it, and to be very careful to not mutate it in the code that actually has access to the inner bits.

I thought everything was handed out as copies in go by default unless a pointer was being passed. So this would make it “easy” to tell whether you are mutating a object or not.

would appreciate if anyone can clear that up for me.

side notes:

since Im still a junior, not too interested in language wars and feel like everything i touch i learn something from no matter how old/new it is.

honestly, i would never have the confidence to critic this <language> in that fashion. i cant convince myself that i know enough about language design/systems to critic anything that harshly.

maybe its my shortcoming as a junior :)


They mention it elsewhere in the post, but there are a few types that are essentially pointers but don't look like pointers. Slices, maps, interfaces, and channels (and also functions, but that isn't that important here). So you cannot just think that anything that doesn't have an asterisk is a copy.

Besides that, there is also the fact that slices share underlying array storage, and `append` doesn't make a copy unless there is still capacity, which means that you should be careful when working with subslices that get appended to.

https://go.dev/play/p/Iqd84_eAMNF


I see! Thank you for the example that was helpful.

I read through the example regarding the struct containing the map. I recently ran into that when working on something.

slightly meta: So how can one evaluate whether that is a good decision or bad?

Does forcing the programmer to use make explicitly for maps help prevent errors or is it tedious and better off having the zero value of map not cause errors?


I actually agree with the author that nils are a massive pain in the arse most of the time, and that Go would be much better off without them.

There is no precise, mathematical answer to your question, since it's always contingent on many things, but one way to evaluate a “correctness” of a design choice is the old adage that a good interface is hard to misuse. If your code can handle a nil map okay, and not requiring a non-nil map brings significant ergonomics advantages, you may not need to check it. Otherwise, I personally would err on the side of caution and design an API that either doesn't give the user a choice (i.e. creates the map itself) or returns an error if they provide invalid data.


> I thought everything was handed out as copies in go by default unless a pointer was being passed. So this would make it “easy” to tell whether you are mutating a object or not.

The first bit is correct.

The point the article makes is that, to know whether a variable is potentially mutated, you have to go look at the signature of any function called on it. E.G. you can't just look at main and "know" whether a will get mutated or not, you have to also look at the signature of `Changed`. In C, with the following code

    #include <stdio.h>
    struct test {
 int value;
    }

    int main() {
        struct test a = test { value: 1 };
        Change(a);
        printf("a.Value = %d\n", a.Value);
    }
I can be 100% sure that a is never mutated, because it is passed to change value, and won't get automatically turned into a reference. Had Change be called with `&a`, then I'd know that a potentially gets mutated.

In Rust, `a` would have to be declared mutable to start with, e.g.

    fn main() {
        let mut a = A { value: 1 };
        a.Change();
        println!("{:?}", a);
    }
The above, I know that Change can potentially mutate a. And if a had been declared `let a`, I can be 100% sure that change cannot mutate it.

The direction go took is in line with many other languages (I think C++ behaves this way, it automatically turns values into references based on function signature).


i feel like that C example isnt fair cause you cant have functions bound to types right?? youre not calling change(a) but instead calling a.change(). i havent learned any rust yet, im waiting till im a little better at go so i can be comfortable at work before doing so:) whats the advantage of creating a function of type struct a rather than creating the C equivalent of change(obj structAtype) ? to me now, it seems that it should be expected that an a.Change func will mutate A i see what you’re saying that with Go it cant always be easy to check if its mutating what you’re calling or not. its giving the developer more options to use stuff by ref/val which gives more power but more room for mistakes.


> it seems that it should be expected that an a.Change func will mutate A

But you can make functions that have copied receivers:

    type Foo struct {
        bar int
    }

    func (f Foo) mutate() {
        f.bar = 2
    }

    func main() {
        f := Foo{bar: 1}
        f.mutate()
        fmt.Println(f.bar) // 1
    }
> whats the advantage of creating a function of type struct a rather than creating the C equivalent of change(obj structAtype)

types need to have methods in order to fulfill interfaces, that's all. (Well, and all the downstream benefits of using interfaces, such a polymorphism).


Okay, I haven’t worked with Go enough yet to need inheritance so I stupidly overlooked that :) even though ive used it extensively in java.

i can definitely see how that is wacky. i wonder what the upsides of being able to do that is.

really appreciate the explanation! thank you


The problem is that you can still mutate a copy. But does the person mutating the copy realize it's a copy, and that it won't propagate?

It's also hard to keep a mental model of which builtin primitives are values (copy semantics) and which are references (reference semantics).

Arrays are values. Slices are references, but might be a reference to some dynamically allocated slice or an array. Appending to a slice makes a copy _of the slice_, but which might modify the array it came from. It's not possible to tell from the type if it references an array or not.

Maps have reference semantics too. Why is it that maps and slices are the only references that don't have a pointer star to denote that?


Having followed language wars for a while as a relative newcomer to programming (longtime lab rat type), my present conclusion is that languages are just tools, comparable in my experience to different laboratory techniques and instrumentation. Different tools are appropriate for different purposes. Some are a lot less convenient than others to set up and use. Some are so obscure that nobody really supports them anymore, and if you want to use them you'll have little help with troubleshooting. Some are popular fads that come and go, as people realize there are better options available for particular jobs.

Once you learn how to use one set of tooling well, it's not so hard to jump over to another one if you get a job in a lab that relies heavily on it. Same with languages.

Fanatical adherents of one option or another often have some ulterior motive ... like the lab who spent $2 million on that high-field NMR spectroscopy machine and is always trying to get people to use it so they can can get some co-author publications. Often the most vitriolic fights are over some technical detail or other that doesn't apply to the vast majority of use cases.

Conclusion: meh. Of course Python and C++ are the superior options, however. Plus C for things like writing low-level code for firmware etc. The fact that these are the only languages I have any experience with is entirely incidental to the truth of this claim.


I definitely see that languages are just tools and you pick the right one for the job.

I guess the confusion for me is, languages often have overlapping usecases with slightly different semantics/syntax.

How do we objectively evaluate what is better? is it industry adoption? academic praise? im sure theres an answer to that but i havent went down that rabbit hole yet


“Languages are just tools.”

This is the most healthy take.


I'm just a simple dev in a 3-man team building an app and a back-end to go with it. Our company is default dead. Maybe some day I will regret choosing Go for our back-end. But right now it is the right balance of scalability, easy async, good tooling, great back-end infrastructure (Google App Engine and Firestore) and productivity.

I read articles like this, and think to myself ... some future CTO will curse my choices today. But then I feel that future CTO will curse any choices I make, and it won't be fair for her to curse my choices ... because I'm just trying to get us from default dead to default alive without running out of the small amount of money we raised.

Rust is absolutely not an option for us. We don't have the skills or time to write a Rust backend right now.


Why is HN flagging this article? Just because it exposes the (debatable) flaws of a language that the HN crowd love? Justifications must be provided.


One more thing to note (on this post that is already on page 2 of HN after 47 minutes):

To me, as a scripter-ops kind of person, Go is useful as a Python variant. You get types, you get a huge standard library, and much of ops is network-based communication and glue code. The last job I had, I was tasked with rewriting a moderate Python lambda into golang as a POC for ease of use, and performance.

I relearned the basics of go in about two days, used google and docs copiously, but otherwise did not change the structure of the program.

The execution time was cut in half! It's an easy language to get using quickly and serves that purpose well. I wonder if the author could acknowledge the comparison to Python.


I really don't know enough about Python to discuss it, so I usually don't. There have been some semi-recent developments re typechecking Python (see https://dropbox.tech/application/our-journey-to-type-checkin...) that have made me interested in trying out for real.


> Go's confusion between "type aliases" and "newtypes". The only way to make a newtype in go is to make a separate package with an opaque type and use interfaces for indirection, which is costly and awkward.

It's very unclear what this is supposed to mean. 'type Foo int' in Go creates a new 'Foo' type that can't be used as an int without casting (a̶l̶t̶h̶o̶u̶g̶h̶ ̶y̶o̶u̶ ̶c̶a̶n̶ ̶a̶s̶s̶i̶g̶n̶ ̶a̶n̶ ̶i̶n̶t̶ ̶t̶o̶ ̶i̶t̶). If you don't want to allow that, you can just wrap it in a single member struct.


> 'type Foo int' in Go creates a new 'Foo' type that can't be used as an int without casting (although you can assign an int to it).

You can't, in fact:

    type Foo int

    func main() {
        var foo Foo = 1
        var bar int = 2

        foo = bar // cannot use bar (variable of type int) as Foo value in assignment
    }
The reason you can do things like:

    var foo Foo = 1
is that because numeric literals in Go are not ints, they are untyped [0].

[0] https://go.dev/blog/constants


Ah yes, good point. Thanks for the correction.


I moved some words around to make the nit less confused - thanks for the feedback!


Still not seeing it. You don't have to use interfaces to make an opaque type. A package boundary is sufficient.

Not sure why you would want a fully opaque type internally to a package anyway. A regular `type Foo Bar` declaration is sufficient to give you a `Foo` that can't be accidentally interchanged with a `Bar`.


One impediment is that Go cannot prevent the construction of invalid values, because every type has an implicit zero value:

  type NonZeroInt struct {
    v int
  }

  func (n NonZeroInt) Get() int {
    return n.v
  }

  var n NonZeroInt  // invalid!
You could of course validate on read:

  func (n NonZeroInt) Get() (int, bool) {
    if n.v == 0 {
      return 0, false
    }
    return n.v
  }
…but that's hardly good design.

You can improve on this marginally with an interface, because an interface's zero value is at least nil, which is, at least, explicit about whether there is a value or not. But it's not very elegant:

  type NonZeroInt interface {
    Get() int
  }

  type nonZeroInt struct {
    v int
  }

  func (n nonZeroInt) Get() { return n.v }

  func ToNonZeroInt(v int) (NonZeroInt, bool) {
    if v == 0 {
      return nil, false
    }
    return nonZeroInt{v}, true
  }
The biggest problem with this approach is that it adds overhead. It can also force values to be heap-allocated, though I believe Go will still optimize single-word interface values to avoid this.

Note that since Go interfaces use structural typing, naming the method Get() can cause issues:

  type AnyInt struct {
    v int
  }

  func (n AnyInt) Get() int {
    return n.v
  }
Now AnyInt fulfills the NonZeroInt interface, which is of course not something we want. So for types like these, it's a good idea to name the method explicitly:

  type NonZeroInt interface {
    GetNonZero() int
  }


Using interfaces here seems unnecessarily complex. If the default zero value were an issue in practice, I would just define

    type NonZeroInt *int

    OR

    type NonZeroInt struct { v *int } // (if you want it to be fully opaque)
so that the program would panic on an attempt to do arithmetic on the nil value. That achieves the same effect as your code, but without the unnecessary interface definition and the resulting naming issues. (Though note that Go does make it possible to export an interface from a package that no-one outside the package can implement. All you need to do is add a dummy private method to the interface.)

It's true of course that the pointer adds runtime overhead, but two points:

(1) Go is not really advertised as a zero cost abstraction language (in contrast to e.g. C++, Rust). So yes, building nice abstractions in Go will sometimes have a runtime cost. If that is unacceptable in a given application, then Go is not the right tool for the job. I'm not a Go zealot. If you need to do this kind of thing all over the place in your code base, then sure, don't use Go.

(2) If you are dealing with large arrays of non-zero ints (such that the overhead of boxing would be significant) then you could always define NonZeroIntArray.


That's not the only/main reason to want a newtype though - it's also about restricting what the value can be, see something like NonZeroU64: https://doc.rust-lang.org/stable/std/num/struct.NonZeroU64.h...

numeric literals (mentioned by paskozdilar in a parent comment) being untyped is another footgun I hadn't even thought of including - it makes it impossible to achieve in TypeScript/Java-level enums.


You can define NonZeroU64 in Go exactly the same way it's defined in Rust – as a struct with a private field. No interfaces required.

But I was wondering why you would want an opaque type internally to a package. Presumably not to ensure that the value has passed some validation, since in that case you would want to encapsulate that validation logic in its own package. It's not like Go imposes a tax on packages. Packages are the unit of encapsulation in Go, just as modules are the unit of encapsulation in Rust.


> But I was wondering why you would want an opaque type internally to a package.

You can have a public function (a constructor) returning an instance of a private type. This way you ensure it's not zero-initialised by default (you can't do "var f privateType", you need to call the constructor).

But it's annoying to do. For every type you'd ever want to protect against zero-initialisation, you'd need to declare it private in some other package, and create a constructor. Therefore, most people just don't bother and prefer to live with the increased risk of bugs.


Zero initialization is a pretty fundamental concept in Go. I can see why people might not like it, but if you are trying to prevent a large number of types from being zero initialized then you are just going against the grain of the language. In most cases you can arrange to make the zero value valid.

To me it seems extremely weird to phrase this kind of criticism by saying that Go lacks proper support for newtypes, which simply isn’t true. If the author’s real complaint is with zero initialization then it would be a lot easier to understand their point if they made this explicit.

> But it's annoying to do. For every type you'd ever want to protect against zero-initialisation, you'd need to declare it private in some other package, and create a constructor.

How is this annoying? You’ll need a constructor anyway if you’re doing validation on the value. Apart from that you’re just complaining about having to make a package, but that’s really simple. I don’t see how Go would be improved by layering additional privacy mechanisms on top of the package system.


> Zero initialization is a pretty fundamental concept in Go.

I don't get it. There's nothing particularly special about it other than it being an explicit choice (I suspect Go's developers were lazy and did whatever was easier to implement). If, instead of automatically initializing to zero, the compiler said "error: uninitialized struct field", we wouldn't be having this conversation, and we wouldn't have this class of bugs. I would consider it "fundamental" if there was an obvious benefit from this choice, but I think a more appropriate word is "arbitrary".

> In most cases you can arrange to make the zero value valid.

Valid doesn't mean correct. Corrupting the DB with zero-initialized data can be worse than crashing early due to an unitialized (nil) pointer.

> If the author’s real complaint is with zero initialization then it would be a lot easier to understand their point if they made this explicit.

They did, it's mentioned in several places. E.g.:

---

Go fails to prevent many other classes of errors: it makes it easy to accidentally copy a mutex, rendering it completely ineffective, or leaving struct fields uninitialized (or rather, initialized to their zero value), resulting in countless logic errors.

---

> Apart from that you’re just complaining about having to make a package, but that’s really simple.

In order to prohibit direct struct initialization (which can be a source of unintended bugs) and enforce using the constructors, two types "related" to each other would have to live in different packages. E.g., if a type A's method constructs a type B, you'd segregate them and keep only the constructors public. In the context of a medium-sized project, you will end up with MANY packages. Sure, it's simple to create packages, but it can becomes painful to manage once you need to understand the code. So at the end of the day, people don't do it and instead elect to be "more careful", which isn't a good method of preventing bugs.


>There's nothing particularly special about it other than it being an explicit choice

Yes, this is what I meant. Go is explicitly designed according to the philosophy that it is beneficial overall for every type to have a default zero value. You may disagree with this, but if you find you are constantly fighting zero initialization, you should probably just use a different programming language.

>Valid doesn't mean correct.

I understand that. However, in most cases, you can arrange for zero to be a valid value. It may require a little creativity, but it's rare for it to be impossible in my experience.

As to packages, I still don't see the issue. The related types can be in subpackages of a parent package. And as you say, it's simple to create packages.

>So at the end of the day, people don't do it and instead elect to be "more careful", which isn't a good method of preventing bugs.

I don't think this choice has anything to do with the overhead of packages. Most people just don't like the style of 'bondage and discipline' coding where the type system is maximally exploited to enforce every possible invariant. Again, this is just fundamental to Go. It was designed by people who have explicitly said that they don't see value in using the type system this way.

By the way, I am no stranger to the possibilities in this space, having been paid to write Haskell code for a while. I've even done absurd things with the type system like this: https://adrummond.net/posts/cooper However, I tend to think the Go folks are right on this. It's good to have a basic type system, but there are rapidly diminishing returns on the fancier stuff.


You generally want newtypes as proofs that a value has gone through some validation.


And what prevents you using them this way in Go? Just make a package and export a constructor function that does the validation.


I think that was the author's point. You _can_ use them this way but it's a hassle and most people don't do it. The language itself doesn't protect you against zero-initialisation errors, even though it could.


Yeah, his complaint about newtypes is just incorrect.


I use Go for simple CLI apps and it's pretty dang good for that. They're used by coworkers, contractors, and clients so the fact I can just send over an executable for any OS is really nice.

I wouldn't use it for anything too complex, or requiring a GUI. Mainly because I'd be much better off using the languages in my day job that I'm more familiar with.


how boring? Don't wanna use Go? Use something else. What's the point? Invest your time on questioning your knowledge and improving it instead of this.


The point of these articles and other opinion-making (such as right here on HN) is that we don’t choose tools. We are given the popular tools. They are popular because other developers chose them at the companies were we work. And they chose them because they thought they would be suitable for the purpose.

So if you want to do everything in your power to prevent a tool you think is terrible from being more popular - you can do very little apart from writing opinion in blogs or forums, improving the tool, or provide better alternatives.

Shitting on a technology might seem like the least noble of the 3, but it’s likely quite time-efficient compared to the other two. It’s certainly not useless.


Why should I care if Go/Rust/anything else becomes popular? I don't expect that if I don't "fight" against a language I'll be forced to use it in 2 years: there will be space for different techs, tools and so on.

I can agree with you if we talk about "tools" that attacks our privacy, our rights and our freedom: spend you time convincing people to abandon facebook or something similar and you'll do something good.

But in this case, it doesn't change much, imho.


> I don't expect that if I don't "fight" against a language I'll be forced to use it

I didn’t used to worry about this until it started happening to the sharp, experienced Scala/Java team I’m on by preference. Other teams are now deploying half-finished platforms on which only Go is supported fully, or sometimes at all.


I don't understand all the attention these articles are getting. If you don't like it, stop using it. Why are you going to so much effort to complain?

You can write bad code in any language. You can write difficult to read code in any language. Every language has pitfalls and downsides.

Personally, I work in golang full time, and I adore it. Development is painless, and our codebase feels very easy to read.


> You can write bad code in any language.

Some languages make it much easier to write bad code. Some languages introduce safety checks that eliminate entire classes of bugs. So your claim that all languages are the same is very far away from the truth; not all tools are the same.


It's the matter of one's opinion, I personally love it. The design has +n years of experience behind it and stands on shoulder of some serious people (yea you already know who they are).

Every language has its own gotchas, and if you are not satisfied with it, coding some Java might help you gain a little perspective.


Coding in Java is outright ok, compared to Go.

Also, you should read the article, it mentions reactions like yours.


This post should not have been flagged, just because people don't like hearing criticism of a language.


Meh, this blog post is a rather subjective rant. I can offer the opposite opinion, although I'm not sure that's helpful. The more I use Go, the more I like it. I'm very productive with it, similar to -- though not quite on a par yet -- the productivity I had when I was programming in REALBasic. Most of the benefits of Go result from the tooling and the availability of 3rd party, open source libraries with permissive licenses that are "good enough" for my purposes. I could probably also use Python instead and benefit from even more 3rd party support, but there would also be downsides to it. I appreciate Go's compact executables and easy deployment.

Quite honestly, in what concerns choices of languages, my experience is that it's not so much the language per se that counts, but rather the tooling, developer community, and the availability of 3rd-party libraries.


Why is this flagged? Come on


Did someone take down his server because of this blogpost?


Does anyone know the guidelines of when to flag submissions?

For me, submissions that spread misinformation should be flagged. But just because you don't agree or like the article, doesn't mean that you should flag it. I guess this submission is flagged because some people don't like it but HN doesn't have downvote button, so they use the flag button as an alternative.


I believe he wrote a binary diff/patch system in it. If I had to do such a thing in Go, I would also hate Go.

He should just own up to trying to shove the square peg into the round hole and move on with his life, rather than blame the peg. There is no shame in it. At one point or another, we've all done it.


[flagged]


I agree that this article is low-quality and self-contradictory, and flagged it too.

However,

> It reads as an asshole college sophomore who rips on plebs who dare to have different perspectives than them

This is going a bit too far, don't you think?


One quick question as a TLDR: did he write about Rust being better?


couldn't agree more!


Author should have used this article to propose Go 2.0 changes. For me, I read it like a rant.


I guess this is mostly a Rust fanboy virtue signalling in their eternal war against Go and C. sigh


Oh no, here we go again. So you don't like Go (no idea what this "golang" thing is everybody keeps talking about)? That's cool! You don't have to write yet another blog post saying that you really, really don't like it, with more strawman arguments and again quoting that quoted-to-death quote by Rob Pike about Go being designed for stupid developers, we got you the first time!


I don't have a horse in this race, but as for "Go" vs. "golang" - I imagine people use "golang" as it's a bit more clear that you're talking about a specific thing (the programming language), as opposed to a fairly common English word (and a board game, and probably some other uses).

From https://go.dev/doc/faq#go_or_golang:

Is the language called Go or Golang? The language is called Go. The "golang" moniker arose because the web site was originally golang.org. (There was no .dev domain then.) Many use the golang name, though, and it is handy as a label. For instance, the Twitter tag for the language is "#golang". The language's name is just plain Go, regardless.


BTW The official github organization is literally "golang"

https://github.com/golang


Yeah, "golang" is the standin for when "go" is already taken (https://github.com/go). But still, the official name is "Go", and there's no good reason to not use it in the title of a blog post (other than SEO I guess)...


My site has its own search engine (just sqlite full-text search, nothing fancy) and searching for "go" is entirely unhelpful. So yes, external and internal SEO.


> no idea what this "golang" thing is everybody keeps talking about

The Go FAQ can help you understand where this is coming from: https://go.dev/doc/faq#go_or_golang


I'm surprised this isn't mentioned, but "golang" is much easier as a keyword to search for then 'go' as well.


I'd just to point out that I think fanboys are not that useful and you have the right to don't read the article as much as he has the right to write it..


I dunno, aren't you just as guilty of not moving on? If Go is garbage, you defending it isn't going to suddenly correct that. Also, it's called golang because that's what a lot of people call it (i.e. https://www.reddit.com/r/golang/)


Then you could also say "He's called a [insert ethnic epithet here] because that's what a lot of people call him" - but I hope we can all agree that would be a bad idea?


I am not sure what you mean by your completely disconnected analogy.


Easier to search for things online with a unique moniker. I would use "golang" whenever I would talk about the language to IT people who may not know about it.


> rustlang

Rust is a chemical reaction, not a programming language. HTH. GLHF.


Blog post is just one part, This person is whining about critical feedback received on HN at Twitter. Screenshotting users and comments for Twitter likes. For someone who doesn't like Go , they surely obsesses a lot about it.


This is an opportunity piece written for no reason other than to ride the wave from a recent re-post of a 2 year old blog article. It offers nothing over the original blog post and it's difficult not to be cynical about the authors intent with this article.


>ride the wave from a recent re-post of a 2 year old blog article

You've been here a decade! This is part of the HN experience. I'm sure we'll have an Atlas Obscura submission about the scintillating history of Serbian skin-contact white wines later today.


I'm just wondering why the author keeps making those articles about strongly disliking Go, ok we get it your favorite language is Rust, you don't like Go. Why does the author does not move on, exactly?

"Fine. It may well be that Go is not adequate for production services unless your shop is literally made up of Go experts (Tailscale) or you have infinite money to spend on engineering costs (Google)."

This is really wrong on so many level especially coming from someone that has shipped what exactly in production? What is the expertise of OP to tell people to not use a language that was proven to be very successful.


As far as I can tell he has made.......2

One of them a couple of years ago, detailing his experiences with using Go to accomplish something, contrasting it with how it would work in Rust.

And then this new one, which seems like a semi-response to that previous article hitting the HN front page again.

I wouldn't say he "keeps making" them, he's made two, and they're not coming out of nowhere. As he said in a comment of the most recent submission of his previous article (https://news.ycombinator.com/item?id=31193260):

> Author here: I wrote this in 2020, have changed jobs twice since. Both jobs involved Go in some capacity, where it's supposed to shine (web services). It has not been a pleasant experience either - I've lost count of the amount of incidents directly caused by poor error handling, or Go default values.

> Because that's the kind of code I inevitably end up being on-call for, and I'm tired of being woken up because of the same classes of preventable errors, all the time. It doesn't matter that I don't personally write Go anymore: it's unescapable. If it's not internal Go code, it's in a SAAS we pay for: and no matter who writes it, it fails in all the same predictable ways.

It's not that it's not his favourite language, it's that he's experiencing actual day to day issues at work caused (in his opinion) by the design of the language. I think that's fair to write about.


> I'm just wondering why the author keeps making those articles about strongly disliking Go, ok we get it your favorite language is Rust, you don't like Go. Why does the author does not move on, exactly?

He made a post two years ago in 2020 that was attacked by zealots yesterday when it hit the front page of hn and a post today that was a reply to that. It would be like if you were to post an opinion about perl two years ago, respond to people who attack you because they love perl more than their own children, and then be dismissively accused of crusading against perl when in reality all you did was post a response to people attacking you based on your two year old post. It's insane to say that two posts written two years apart is a crusade; I imagine most people who flagged the article and downvote its defenders simply can't accept legitimate criticisms of something they love too much to admit it has any flaws. So, I'll ask you your own question: "Why don't you move on, exactly?"


I thought the criticism was pretty balanced. I've seen worse articles here about other languages. Pretty used to getting this feeling about the Python articles. It's almost always about the lack of some feature that exists in other languages.

It seems to be part of the cycle of a language that gets widely adopted. I think the next step is that people stop fighting over it and just accept that it has some nice features and some bad parts.

Articles like this helps me (as a dev who's not using go very often) getting a feeling for what types of problem go might be good for and not. If it's well-written like this one, I think it's a good balance to the many positive articles that I've read.

Clearly the author cares a lot about language design. I get that he might be coming from a different background with different tastes. The fact that he doesn't like go isn't saying your time spent learning the language has been for nothing. Clearly a lot of code is being written in it, don't worry!

Here's some stuff he's done: https://fasterthanli.me/about I think he's entitled to an opinion either way though. Very interesting to see the response. Had no idea it was this touchy. I can get a bit weary seeing the millionth article saying that Python sucks because it doesn't have a feature of another language - but it also makes me want to try out that other language for myself.


this article was written specifically to address the comments that came up when the two-year old article made the rounds again.

that's why he didn't move on; we resurrected the topic.


The author doesn’t fundamentally misunderstand programming language design, but rather misunderstands programmers.

Most programmers don’t need someone to tell them which tools to use. Of those green enough to need it, they certainly shouldn’t look to the internet for advice and they absolutely shouldn’t look to HN or random blogs for advice. Instead they should find a local community which can offer them support when they stumble and point them to interesting job opportunities. Because those people are real and they can build relationships and connections which will be much more valuable than some measly programming language.

Many online authors - even if technically skilled - have quite an over-inflated sense of importance. What makes somebody think that their experience in domain X and country Y apply in any way shape or form to the hundreds and thousands of industries, countries and cultures all over the planet?




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

Search: