5 ms·
This is neat, and a testament to the simplicity of Go. I normally point people to this tutorial if they want to learn Go quickly, it is interactive (able to na
by cfors 6y ago
This is neat, and a testament to the simplicity of Go.
I normally point people to this tutorial if they want to learn Go quickly, it is interactive (able to navigate straight to go playground) and very well done in my opinion.
https://gobyexample.com/ https://gobyexample.com/
- mynameisash 6y ago> the simplicity of Go As someone who's not written any Go, I found fasterthanlime's critique of the language[0] damning enough that I likely won't ever touch the thing. Maybe he's cherry-picked examples, but his article was thorough and technical enough to convince me that the Go mantra of simplicity is just surface-level. [0] https://fasterthanli.me/articles/i-want-off-mr-golangs-wild-ride https://fasterthanli.me/articles/i-want-off-mr-golangs-wild-...
- jrockway 6y agoHow is this damning, exactly? It's a very specific set of library quirks that are kind of expected -- Chmod doesn't do much on Windows. Arguably, maybe Chmod shouldn't be in the core library if it can't do everything on every OS/architecture combination, but I am not sure that damns the language. It does the best it can, but doesn't deliver a POSIX overlay for Windows. (The complaint continues into a discussion of build tags, to make Windows-only code compile only on Windows. Again, what's the alternative here? If you want your program to do different stuff depending on the platform, there's going to be some sort of conditional to apply that.) There is then a discussion about monotonic time. The author immediately knows they want monotonic time, but there is no method that specifically returns that. Instead, go embeds the wall clock and monotonic time into a time.Time when you create one with time.Now. It uses the wall clock time for display, and monotonic time to compute the difference between two timestamps. This is not what the author expected, but it ultimately allows them to do what they want. (There is then a complaint about how when you boot a Raspberry Pi without giving userspace any time to start up, the time is set incorrectly, and Go doesn't help. Well... yeah. You can add a hardware RTC if you want the time to be correct as soon as the i2c subsystem comes up, or you can wait for NTP, or you can live with the wrong time. Not sure how any of this involves Go -- it does expect the OS to do OS things for it.) If you were going to write a damning critique of why to never use Go, it would probably be something like "this dumb library uses channels, sync.Mutex, and atomic.AddInt64 all in the same code and it deadlocks and runs out of memory" or "I installed the most popular ORM on Github and it prints colored text to the console when there is a database error rather than returning an error from the function". I think the linked article totally misses the mark on what problems people are likely to encounter with Go. Let's be honest -- 99% of programmers have no idea that their OS has a monotonic clock, and are quite surprised (and have no idea how to fix it) when start := time.Now(); time.Sleep(time.Second); fmt.Println(time.Since(start)) prints a negative number. But... with Go they don't have that problem. Pretty interesting.
- jrockway 6y agoI guess I ignored the section on resolving the long dependency graph, and that's important to discuss. The community could do a better job of splitting their clients and servers into separate modules (writing to InfluxDB should not require downloading the code for an InfluxDB server). (I do love using servers written in Go, though, because my integration tests can just start one up at the beginning of the test and talk to it. No setup/teardown required outside of "go test"; no extra dependencies to make developers install. It's nice!) The language could do a better job of letting you choose "plugins" at runtime; if you use Prometheus for monitoring and not InfluxDB, it's not ideal to have a bunch of 'if UseInfluxDB { send to InfluxDB }' compiled into your binary. The alternative is to dlopen something that provides monitoring functionality; been there done that with Nginx and OpenTracing, and it's hugely painful. (There simply aren't binaries that work together; you can't wget a prebuilt plugin into your Nginx docker image. You have to build both from scratch.) Or, you can at least defer the monitoring library selection from library to application with an abstraction layer like OpenTelemetry. The cost to the code author is high, and it still doesn't let the operator choose the backend at runtime. Overall, this is something that a programming language should choose to take on, but it's also exceedingly difficult to get right. I haven't seen it done right, anyway; so all you have to go on is a list of ways to get it wrong. It is annoying that there are 600 different logging libraries. But people are VERY particular about logs, and one person's treasure is another person's "that is so horrible I can't even use it". If there is a programming language where everyone uses the same logging library and that library provides structured logging, the log levels are [trace, debug, info, warning, error, fatal], has built-in support for sending to third-party services (Sentry), rate-based sampling, and metrics generation... then that sounds great to me and I'll definitely take a look. But for some reason, I kind of doubt it. People have a lot of thoughts here, and are very committed to their thoughts. In the Go world, libraries with wonderful authors let you inject your own logger, and it mostly works well. GRPC, pgx, Jaeger, etc. all do a good job here. K8s's client_go does a bad job here, but they're working on fixing it :) Wasn't planning to get sucked into this discussion, but the article does raise some good points. I'll be very honest and say rants like this sound to me like a pre-rant for next year when it's "why I quit programming forever and became a beet farmer". To succeed at programming, you will have to endure in the face of minor problems with your tools. You will have to use those tools to program better tools, after all. And even then, it still won't be perfect, and you'll see a new set of problems to be mildly annoyed at. Such is life! Ultimately, for me, Go has supported my efforts to make stuff. I run it on STM32 microcontrollers. I run it on Beaglebones. I ran it on thousands of servers at Google. It just kind of gets out of the way and lets you turn your ideas into things that you can use. Who can complain.
- bird_monster 6y agoIt sounds like you've made up your mind, but I might suggest reading less overwhelmingly biased critiques. That post makes incorrect assumptions about go, and then exhibits the result of their incorrect assumptions, and then brings up how, when making the correct assumptions in Rust, the outcome is different. Can you see how this is a flawed strategy? Go isn't for everyone, and that's okay, but it seems kind of silly to make a judgement based off of a negative review hinging on a pretty poor understanding of a language.
- sundarurfriend 6y agoThanks for sharing this. I'm halfway through it, and it is indeed damning, if only mildly so (compared to, say, phpsadness). As the author says, the specifics are not the point, rather the overall picture they build: that simplicity in language design has its own price, and sometimes all it means is that the underlying complexity is passed on to you to handle in your program yourself; and the damning part is, Go does not seem to do a good job of making that process as smooth and clear as it could.
- fwip 6y agoReally? I'm halfway through "I don't like Go's abstractions over file permissions on different operating systems" and rolling my eyes. When the author is talking about how great Rust's error handling is (by forcing you to decompose the Result type), they also forget to mention things like "the go linter that everyone uses will let you know that you are ignoring the error." It's not a "Rust is always safer" scenario like is implied, it's a deliberate tradeoff for a less-fussy compiler, because sometimes you're prototyping and want to ignore the fact that you're not handling everything perfectly. Yes, Rust has better typing, and Result types are a great pattern, but the article makes it sound like the Go situation is uniquely bad. Similarly, with the complaint: "Rust Paths, however, are... arbitrary byte sequences. [...] See, there's no "path" type in Go. Just "string". And Go strings are just byte slices, with no guarantees what's inside." If you program in Go for a week, you know that strings are "just byte slices." If you want to see if it's got utf-8 contents, just run `utf8.Valid(mystr)` - it's in the standard library, easy to find, and the obvious solution. Imagine telling a new programmer "ah, you see, the FilePath doesn't implement the `Display` Trait, so you have to write `println!("(dir) {:?}", path)`, and this is much better than in Go, where you write `fmt.Printf("(dir) %q", path)`". But the author doesn't show the Go solution, because that would reveal that they're essentially quibbling about syntactical choices made in the built-in string formatting library. Nearly every single complaint is like this. For example, the author seems to be unfamiliar with basic Go naming conventions: "(Can I just point out how hilarious that "Extension" was deemed long enough to abbreviate to "Ext", but "IsPathSeparator" wasn't?)" - yes, because Ext is a much more common thing for calling-code to use, and IsPathSeparator is rare to need. "Familiarity admits brevity" is the saying in the Go community - and as a corollary, the more you use it, the shorter the name can be. And once you get past the nitpicking of the file stdlib, the author's main complaint is "there's too many dependencies downloaded for some packages", as if they don't believe that the go compiler can do basic dead-code elimination like every other real compiler? Monotime itself has 0 dependencies, which, again, the author knows, because they pasted the entire source into their article verbatim. If you are stuck on dial-up or something and hate downloading bytes just to throw them away - just copy these two files (12 lines of code) into your project! One of the Go proverbs is literally "A little copying is better than a little dependency." This isn't a piece with real criticisms, this is a "rant" (self-described by the author) because they're honeymooning with a new, prettier language now (Rust). I find it impossible to believe that the author literally does not know these things after working with Go for "thousands of hours." I'm by no means a Go expert - I haven't written a line of Go for about 2 years, and the biggest project I ever worked on in Go was 499 lines - but the only thing I had to research for this comment was running `cloc` to get those 499 lines. And indeed, the author started another article about Rust 6 months later, "Learning Rust is... an experience. An emotional journey. I've rarely been more frustrated than in my first few months of trying to learn Rust." When trying to explain how to write a function to add two numbers (the hello-world of functions), they write "We're getting dangerously close to flirting with academic papers at this point, so let's go for an example immediately." Go isn't Rust. Go is made for building things that the kid 30 days out of coding bootcamp can jump right into and start fixing bugs. If you like Rust, more power to you. But it's not built to be what Go is built to be.
- capableweb 6y ago> testament to the simplicity of Go Depends on who reads it I guess. Lispers would not see simplicity in Go, they would see all the different characters you need to use, how some things are statements and others are function calls, conditionals, type definitions and they all have different syntax for themselves, instead of being the same. Both have their places for sure, but I wouldn't go so far to say Golang is simple because of this example. At least it's not Rust, I give you that. pub fn metadata<P: AsRef<Path>>(path: P) -> Result<Metadata>
- deleted 6y ago[deleted]