Hacker News new | ask | show | jobs
by scndrycntct 1652 days ago
> I think Go people are allergic to writing code that does anything other than functionally work.

I think that's what Go was designed for, as a language. To be readable, usable. It's uncaring for your personal programming philosophies. I think that's why it's been successful.

4 comments

I'd agree that it was one of their design goals, but I wouldn't go as far as to say that it makes the language "readable and usable." That depends on what your values are.

Go's philosophy (which clearly flows from its creators being C-enthusiasts) is that the only thing that matters for reading, writing, and understanding a program is what it concretely does, i.e. what structures are created, where values are stored, how computations are performed etc. If that's also your philosophy, then of course it's going to jive with you.

But plenty of people also have different philosophies. Maybe you think the main thing that's important in crafting programs is developing a rich domain vocabulary that expresses concepts and how they interact. Maybe you think that what's important is formal proof of both logical and concrete correctness. In those cases, Go's rigorous opposition to abstraction (coming from its philosophy that what's important is concrete operations) will probably irritate and slow you down.

I couldn't say exactly why it got popular. I'd guess that some significant segment of programmers also share its philosophy, but I have no evidence to back that up. Certainly any reasonably uncontroversial language with a large suite of libraries backed by Google is bound to have some level of popularity.

> I couldn't say exactly why it got popular.

Probably because it has the backing of Google.

I disagree. Go provides a low-runtime way of writing programs, like C, without having to resort to managing memory and threads super carefully. No VM, no interpreter, fairly straightforward to imagine what the compiler is doing.

You can do the same work in Java but you can't statically link the JVM. You can sort of do these in Python, but the compiler story is murky at best, and the language isn't as type safe.

> No VM, no interpreter

That's not quite accurate; there is a runtime, it just gets statically linked into the binary instead of needing to be externally installed

No, Go literally doesn't have a VM or an interpreter. VMs and interpreters are runtimes, but not all runtimes are VMs or interpreters. Go executes native code.
Any language that performs work not directly specified by the user has a runtime. Go's runtime is minimal and concerned with two important aspects of the language: scheduler, and garbage collection.
Counterpoint: Dart.
I thought of Dart as a counterpoint, but if anything it's actually more proof. Dart kinda failed as a language in the browser because Google didn't really push it, and when they did it got pushback. Now that they've repurposed it for building mobile apps, it's surprisingly popular. Sure, not Go-levels of popular, but leaps and bounds more popular than if it were some scrappy OSS project. And it's in a similar camp to Go: reasonably uncontroversial (it's basically Java), large suite of libraries, backed by Google.
Google has never meaningfully "pushed" Go. From Google's perspective, Go is just a backend language that's a good fit for some internal Google applications. I don't think they care tremendously that other people use it, although they certainly don't mind. On the other hand, Google strategically wanted a robust frontend ecosystem (hence investing heavily in Dart and V8) because getting more applications off of PCs and onto the web meant more user data up to collect and more opportunity to serve ads.

In particular, I don't understand how Go is more Java-like than Dart.

    Feature            | Java | Dart | Go
    -------------------+------+------+----
    jit compilation    | yes  | yes  | no
    inheritance        | yes  | yes  | no
    classes            | yes  | yes  | no
    nominal subtyping  | yes  | yes  | no
    native binaries    | no   | no   | yes
    static artifact[0] | no   | no   | yes
    static typing      | yes  | opt  | no
    value types        | no   | no   | yes
   
What other features do Java and Go have in common that they don't also share with Dart?

[0]: For sanity's sake, we'll assume this means "are static artifacts common/default" and not "is it technically possible to produce a static artifact" because for some sufficiently broad definition of static artifact the answer can be yes for any language (e.g., Docker images).

Specifically, Go was designed to be effectively and safely writeable and readable by mediocre programmers.
Some of the best software developers I've seen are mediocre programmers :)
Mediocre programmers can still write bad Go code. Their code is neither safe or readable.
Don't take the obvious flamebait. HN's favorite comment on any Go article is "it's designed for bad programmers", implying that if you like it, you're bad at programming. I'm good at programming and like Go, so that implication is clearly false.
I'm a Go enthusiast, but I think the charitable interpretation is that you don't have to expend lots of mental energy to read and write Go code. Even if you have a lot of mental capacity, you can put the excess toward interesting problems rather than reasoning about object lifetimes or hidden control flow or complex interactions between obscure features. If anyone uses "Go is designed for bad programmers" as an insult to Go programmers, they're only arguing against themselves (and lacking the cognitive faculties to notice).
I don't find go readable in the slightest, the syntactic bureaucracy is just too high.

There is a forest full of code hiding a trees worth of business logic, always.

Go is one of the least expressive languages I've ever used.

> Go is one of the least expressive languages I've ever used

That is by design, and when it comes to "programming in the large" - a winning formula. I keep repeating this response: I worked on a Perl codebase with a medium-sized team. Perl is very expressive, and my teammates did not hold back. I can tell you that is a nightmare to debug or add a new edgecase to a "clever" Perl 1-liner, usually it involved making the code "less expressive". So, I'll take Go over the more expressive languages in a team setting any day.

It's a spectrum, though. A language can be between 0 expressiveness (Go) and 100 expressiveness (Perl, maybe Lisps), and claiming that the only way to avoid the mysterious evil team member who will wreck your codebase is to patronizingly limit them "for their own sake" is insulting
Often times the developers moaning about complex code basically learned if statements and for loops and then were done learning.

But we still have to write code that these people understand. It makes no damn sense.

Sometimes, sure, people write horribly complex code, but sometimes it's just developers who have stopped learning. They see something that isn't immediately familiar and discard it as too complex and make no attempt at trying to learn.

What I don't get is why we have to pander to these people.

This is a mischaracterization. We write simple code not for simple people, but because grokking gratuitously abstract code isn't a good use of anyone's cognitive resources--no matter how smart you are, you will have more mental capacity to put toward real problems if you're working in a simple codebase rather than an unnecessarily abstract codebase.
Not for their sake - for mine. I avoid people and places that make my life unnecessarily difficult, especially if I have to do support and can be called at 3am to resolve urgent issues.

My needs are pretty basic: I like code that is easy to understand and easy to change more than writing code that leaves a smug smile on my face. I read more code than I write, so YMMV.

The fewer surprises, the better for me, and so far, the collaborative codebases I've encountered the least number of surprises have consistently been in Go (the other languages I've been paid to work with are Javascript, Perl, Python, Java, and Scala).

> the syntactic bureaucracy is too high.

Huh? What do you consider syntactic bureaucracy? Go has like 25 keywords and no sigils -- the least "syntactically bureaucratic" language I'm aware of!

> Go is one of the least expressive languages I've ever used.

This is definitely true. Of course expressiveness is not strictly a virtue!

> What do you consider syntactic bureaucracy?

I would assume "amount of syntax required to express a given concept," with the use of the word "bureaucracy" implying that some concepts require too much syntax relative to their complexity (something that depends on your values). The classic example being mapping over a slice.

Ah, so in this framing, syntax is another way of saying amount of code?

Here's some Rust code

    pub fn read(&self) -> u64 {
      self.counts.values().fold(0, |acc, x| acc + x)
    }
Here's some analogous Go code

    func (w *Whatever) Read() uint64 {
        var total uint64
        for _, v := range w.values {
            total += v
        }
        return total
     }
The former is certainly fewer characters than the latter. But to me it represents _more_ syntactic bureaucracy, not less. There are more sigils, more language concepts I need to understand, more _types of syntax_ to express the same thing. It's 20% of the SLoC, but parsing it requires more implicit knowledge, and takes no less time, versus parsing the latter.

YMMV, of course. None of this is objective.

Ah, that's interesting! I'm not the person who used "syntactic bureaucracy" but I did interpret it roughly like that, yes. I'm not sure what phrase I would use to describe "more syntactical constructs" as you're saying, but it's interesting how we saw the term differently.

Similarly, even though I'm not a big fan of Rust, I would personally prefer to encounter the Rust snippet. The way I read code, I'm already building up mental models of things in my head, so adding more (e.g. what fold is) isn't that big of a deal to me. I think I'm a person who is able to look at a function call and not have the desire to dig into its source, though, which I don't think is the way everybody (and most certainly not the designers of Go) feels. Plus once I understand the concept, even if it's a lot less universally applicable than fold, I can reuse my understanding of it throughout the system and possibly throughout multiple systems.

Like you said, I think this is largely a subjective thing. I just find it objectionable when people, on either side of the fence, come in and say "abstracting over concepts and possibly making them first class is always better" or "...always worse."

One interesting thing about Go is that functions are more or less the only way to build abstractions and encapsulate computational complexity. So when you're reading code, if it's not a function call, you can more or less predict it's (fixed) cost. And good function signatures, good program design, where dependencies are explicit and side effects are minimized, does I think let you reliably make assumptions about functions without reading their source. But yeah I see your perspective!
> To be readable, usable.

Go doesn't particularly value readability or usability. For example, the short variable name convention makes it harder to read code you're unfamiliar with, and there are a number of noticeable usability shortcomings, some of which are mentioned in the article.

I think Go's design goals were really to (1) reduce compilation time, which explains why Go has human programmers do work that compilers do in other languages, (2) be statically typed and compiled, so you can use it conveniently for microservices, and (3) have syntax somewhat similar to Python.

I think of Go as the successor to Java. Go is to Python as Java was to C++. That, plus the integration with many libraries is why it's taken off in some niches.

Honestly the biggest selling point of Go to me was that it's simple and consistent. It enforces strong opinions that I may disagree with, but it means everyone does things generally the same way which is an important component in readability. With respect to short variable names, the convention is to only use them for very local scopes (e.g., using `i` as a loop index variable). In particular, I don't need to learn a new language or run a daemon just to compile code with a few dependencies and ship a static binary. Similarly, I don't need to configure CI pipelines just to publish packages or documentation. I don't need an IDE, I don't need to shop around for a test framework or an external web server process because they're built in. I don't have to think about what version of the runtime and/or dependencies are installed on my target system. Plus performance is good and the ecosystem is substantial. Personally from experience, I weight these kinds of concerns a lot higher than whatever bells and whistles are available inside of the language.