My twitter timeline also has tons of neat little crates pop up every month, and I have to thank my colleagues at Netlify (back when they were doing Rust) and now at fly, for showing me some of those I showcase in the article.
1,419 karma · joined August 8, 2014
My twitter timeline also has tons of neat little crates pop up every month, and I have to thank my colleagues at Netlify (back when they were doing Rust) and now at fly, for showing me some of those I showcase in the article.
I certainly didn't DDoS myself just to "game the system". It happened, I learned a bunch of things, did an extensive post-mortem, a lot of folks are finding it interesting, that's it - no smart trolling here, just content. I certainly could use a break from "the discourse" as well.
I was hoping for the discussion here to be around similar experiences, how DDoS really has become a commodity, how other folks's websites is architected, how various platforms fare against these threats (and what it costs), whether folks were are of Cloudflare's default caching policies, or its DDoS protection.
Anything BUT rehashing the discussions of the past few days: everybody is over that. If you do want to discuss those, you can move that conversation to my subreddit, or my twitter, or heck, send me an e-mail.
(Also, and I've stated this elsewhere many times: the Go community doesn't have to answer for that. This is one individual having well-timed fun, let's please PLEASE leave it at that)
As a treat, this is a testament to a logic error I made in the caching code (inserted uncachable versions of pages into the cache for a little while). Enjoy!
I've done most of what you mentioned (minus load shedding & connection metrics) and have posted about on Twitter, if you want to check out the thread again!
If I had to guess, they don't care about Go, they just thought I'd be a fun target (with me generally being a tryhard and everything).
Like any other DDoS, the goals are 1) take the site down temporarily, 2) cost me some money, 3) try to get whichever provider I'm using to boot me off their network.
They've achieved 1) for a few hours off today, the rest has been fairly entertaining honestly.
edit: Done removing some salt from the intro, DDoS still flaring up now and then, I'll be busy hardening some more.
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.
(If your point was about it being _built into the language_, then it definitely stands, see the other discussion in the parent comment thread)
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.
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.
It's important for individuals to be able to do that, and it's on everyone else to make the distinction.
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.
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.
Even if I accept the premise that "I'm challenging Go on things it doesn't promise to deliver" (which is disingenuous to begin with — correctness underpins /everything/, it's not a hobby), I can't help but notice you carefully use the word "attempt" when referring to the promises Go /does/ make.
One of the things I'm saying is that Go does not deliver on those. It does not deliver on "speed of coding", precisely because everyone, even seasoned Go developers, keep hitting its many design pitfalls.
It does not lower mental overhead, because it prevents you from building abstractions, and pushes complexity out of the language and into your head.
There's a lot to be said about safety and performance, which gets bleaker real quick once CGo enters the picture (hence why the Go team likes to remind folks that CGo is not Go).
But say we disagree there and you truly find it a breeze to write large amounts of Go code: as soon as you deploy something to production and others start to rely on it: you don't get to choose not to care about "correctness". If you don't, you're just pushing the problem onto someone else.
You may be pushing the problem onto ops people, other devs, or your customers, but it does land on someone. And nowadays that someone is often me: my frustration is fueled by years of real world use, I do not, like you seem to imply, enjoy thinking about these things in the abstract, just for the fun of it.
Of course, you can choose to ignore that too, and that's fine! But let's please drop the pretense that this kind of response is anything other than "I refuse to think about this".
If folks walk away with only one new thought from this, please let it be that: defaults matter. Go lets you whip something up quickly, but making the result "production-ready" is left as an exercise to the writer. Big companies that have adopted it have developed tons of tooling around it, use all available linters, do code generation, check the disassembly, and regularly pay the engineering cost of just using Go at all.
That's not how most Go code is written though. I'm interested not in what the language lets you do, but what is typical for a language - what is idiomatic, what "everyone ends up doing", because it is encouraged.
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.
Generics will not solve this. It is /neat/ that they found a way to sneak them into the language, but it's not gonna change years of poor design decisions, and it's definitely not gonna change the enormous amount of existing Go code out there, especially as the discourse around them not being the usability+performance win everyone thought they would be keeps unfolding.
As I've mentioned recently on Twitter, what makes everything worse is that you cannot replace Go piecemeal once it has taken hold in a codebase: its FFI story is painful, the only good boundary with Go is a network boundary, and there's often a latency concern there.
Lastly: pointing out that I have been teaching Rust is a lazy and dismissive response to this. For me personally, I have found it to be the least awful option in a bunch of cases. I am yearning for even better languages, ones that tackle the same kind of issues but do it even better. I like to remind everyone that we're not out there cheering for sports team, just discussing our tools.
If you're looking to reduce the whole discourse to "X vs Y", let it be "serde vs crossing your fingers and hoping user input is well-formed". It is one of the better reductions of the problem: it really is "specifying behavior that should be allowed (and rejecting everything else)" vs "manually checking that everything is fine in a thousand tiny steps", which inevitably results in missed combinations because the human brain is not designed to hold graphs that big.
No idea what HN's policy is on posting links to Twitter, but since you asked. Also if the consensus here is that that 2020 rant is "unfair and toxic", that twitter thread is not going to go over well either!
Of course if you reach a point where the only thing left to do is implement http/2, that... is no longer an evening project
The situation for a purely backend service (behind an existing reverse proxy) might very well be different — but as others have mentioned, the Rust http ecosystem has solidified around async, so even if you could get away with 1 connection = 1 thread, you might not want to, just because of where the ecosystem is.
One thing I didn't mention is that epoll isn't even state of the art: there's a lot of work going on around io-uring and thread-per-core runtimes nowadays, which I'm following rather closely because again, at my day job it does matter!
Most articles don't do that, and so they're "short and to the point", but only to a tiny audience that already has the same shared culture. There's always readers complaining that they knew half of it and so I "wasted their time", but they forget about the other half, and also other readers.
Ideally, to please everyone, I would have to write a tailored article /just for them/, filling just the gaps they have. I do that on occasion, but I charge a lot of money for it :)