Hacker News new | ask | show | jobs
by Groxx 2211 days ago
CLIs are sorta my ideal use-case for Go. Goroutines are so error-prone to control since you don't have many options for abstraction, so it's relatively difficult to build long-running highly-stable programs...

But CLIs don't usually need that. They can be ctrl-C'd if they go off the rails, and any dangling goroutines just die when the process dies. The simple distribution, fast startup, simple type system, and yolo-concurrency really pay off in pleasantly small and performant tools. And the stdlib is cross platform, quite capable, and very friendly to use. It's almost exactly what you want when you need to go beyond a tiny bash script, to something that might be a up to a couple thousand lines.

I do wish the built-in flags lib wasn't so abhorrent though. Pulling in a replacement lib is step 1 for any CLI.

4 comments

"Goroutines are so error-prone to control since you don't have many options for abstraction, so it's relatively difficult to build long-running highly-stable programs..."

This comment does not really makes sense, Go #1 usage is for backend services, so it's indeed long running / stable program.

"They can be ctrl-C'd if they go off the rails, and any dangling goroutines just die when the process dies"

There are solution in Go to handle that case, using context and channel but ultimatly it's not a Go problem if you kill an app right away usually there is no way to clean-up everything in a clean way.

His comment makes sense. golang "goroutines" are finicky compared to other ways of doing concurrency (e.g. Futures/Tasks in Scala/C# or Java's upcoming green threads). There are several reasons to this, not limited to the fact that it's trivial to mistakingly ignore return values (especially errors) when executing `go foo()`. Also, there's a lot of boilerplate involved if you want to start several of them and wait until they're completed, or if you want to compose them. The other languages I mentioned, which have superior abstractions to golang, solve the issue in a much better way.
I'd also label it that much of go concurrency control is intrusive, in that you need to write control-flow code into whatever it is you're trying to accomplish, or (typically) give up type safety or understandability. That's unavoidably more error-prone than not writing your own control-flow code, and I spend quite a lot of time discovering and fixing issues around it in libraries, even from some very skilled and careful teams.

Of course there are ways to achieve both in any language, but the massive educational pressure of the official docs and tutorials and examples cannot be ignored, and has profound impacts on what the community ends up building in the language.

---

It's roughly equivalent to manual memory management, IMO. Terabytes have been spilled claiming that C is safe if you're careful enough or use safe patterns, and CVE after CVE provides evidence that nobody is sufficiently careful. It has its benefits, but it also has its downsides.

> Goroutines are so error-prone to control since you don't have many options for abstraction, so it's relatively difficult to build long-running highly-stable programs...

Oh? Building long-running microservices is literally my main use of Go, and in my opinion the language excels at it. What sort of issues are you having?

I'm not OP, but several come to mind: easy to mistakingly ignore return values (such as errors), difficult to compose, difficult to join, boiler plate heavy, no hierarchy/supervisor structuring.
As the typical SysAdmin who likes to automate stuff, I have to agree. I am not experienced enough to talk about language designs. But I can say, that writing some small CLI application and deploying it onto some server is way less work with go. Simply because you can crosscompile the application and generate a standalone binary.

Everytime I deploy some Python3.7 Flask Application on RHEL7 I start to scream.

You were talking about long running applications and broken goroutines: What is the best alternative? I liked to stumble around in Elixir but I feel bad about deploying some application probably nobody at my office will ever be able to 'fix/update'. Python feels too "sluggish". Since I am no Python Pro I have often the feeling, that I am doing something wrong because the language doesn't show any borders.

Alternative: I'd say Java (or similar), since it has the language abilities and sophisticated static analysis tools are readily available. But startup time is still not interactively-fast, so for CLIs it's sorta a no. For long-running processes tho I mostly like it, and stuff like compacting GCs keeps it running healthier much more easily than Go.

Beyond that, dunno - I usually reach for Python since I've written it professionally for a few years and it's pleasantly terse. But it's a fair bit of work to make actually fast and I don't generally think it's worth that effort. Go is much easier there... as long as it's kept simple.

I have some strong hope for Rust, but I think it's fair to label it as "still maturing", though it's already very far of ahead many langs in some areas. And I just don't have much experience with it yet, so have no real conclusions ¯\_(ツ)_/¯

Java has made some strides with startup time. It's still a little bit slower than python when loading the full vm.
> But startup time is still not interactively-fast, so for CLIs it's sorta a no

They're working on it, for example: https://openjdk.java.net/jeps/310

They've been working on it for quite a while, yeah :) I appreciate it and they've made quite a lot of progress... but it's still nowhere near Go, and I mostly doubt it ever will be.

    # time ./hellogo 
    hello world
    
    real 0m0.005s
    user 0m0.001s
    sys  0m0.005s
It's probably "good enough" for many cases nowadays tho, yes, e.g.: https://cl4es.github.io/2019/11/20/OpenJDK-Startup-Update.ht...
You might want to check out: https://quarkus.io/
go is great for long running programs. in fact a large portion of the modern cloudstack is written in it. think of k8s, docker, nomad, etcd...

of course one needs to understand how go routines work in order to use them correctly, but thats probably true for everything, right?

> go is great for long running programs

golang's gc is non-compacting. I wouldn't be surprised if there are cases where fragmentation becomes too much for a golang service to continue behaving properly. This becomes more likely in long running services.

Interestingly my current CLI project https://github.com/boyter/cs/ does need to be stable because I am putting a TUI mode into it... and yes dealing with the dangling goroutines in it for the TUI mode itself is especially painful.

Generally if you just stick to fan-out-in processing though I find goroutines not too bad.