Sure, but does that means that we, Linux users, can't go on the web anymore ? It's way easier for spammers and bots to move to another user agent/system than for legitimate users. So whatever causes this is not a great solution to this problem. You can do better CF
I'm a Linux user as well but I'm not sure what Cloudflare is supposed to be doing here that makes everybody happy. Removing the most obvious signals of botting because there are some real users that look like that too may be better for that individual user but that doesn't make it a good answer for legitimate users as a whole. SPAM, DoS, phishing, credential stuffing, scraping, click fraud, API abuse, and more are problems which impact real users just as extra checks and false positive blocks do.
If you really do have a better way to make all legitimate users of sites happy with bot protections then by all means there is a massive market for this. Unfortunately you're probably more like me, stuck between a rock and a hard place of being in a situation where we have no good solution and just annoyance with the way things are.
The method is the same, it just looks different when n=1. I.e. the method is "wait until you see something particularly anomalous occuring, probe, see if the reaction is human like". The more times you say "well you can't count that as anomalous, an actual person can look like that too and a bot could try to fake that!" the less effective it becomes at blocking bots.
This approach clearly blocks bots so it's not enough to say "just don't ever do things which have false positives" and it's a bit silly to say "just don't ever do the things which have false positives, but for my specific false positives only - leave the other methods please!"
This is one of the most absurd comment I've read in a while. I love it, thank you.
Fwiw, cervelat is also very common in France, I grew up eating that stuff. Maybe that's why I liked the article so much. There's something to dig up there
In JS it’s not an issue as long as you just fire and forget. Because calls to async functions essentially fork off tasks. No way to synchronise on them though.
Python (and rust) are coroutine based so calling an async function does essentially nothing, you need to acquire a runtime handle in order to run and resolve the coroutine.
I was quite shocked to read this, as in it never brushed my mind that it could be. I personally doesn't feel like it is and is one of the reasons why I try to avoid working with that stack at all cost.
I don't think the neon sign is a good excuse for the mess colored functions are. You easily can create a synchronous O(n^4) function, and there are probably tons of quick async functions.
Moreover, your comment might be read as a free pass for using functions and methods that you're not really understanding the behavior off, it obviously doesn't sound like a good thing
The information is only hidden with colorless methods if you consider the documentation to be a place to hide information (o^o).
Unlike Go or Ruby, JavaScript is a single-threaded language. Synchronization constructs such as mutexes and semaphores are uncommon and not part of any standard library. When you are calling a synchronous function, you can be completely assured that no race condition can develop while the function is running, but the same guarantee is not true for asynchronous functions.
That's why knowing which function is running asynchronously is even more useful for languages like JavaScript.
"Now you have two problems." Adding async/await was a hack to avoid having to tackle the hard problem of real concurrency, so now you have a) no real concurrency, and b) coloured functions.
There is a parallel universe where JS added almost any other concurrency primitive and got a better trade-off than async/await.
Having interacted with a bunch of other concurrency models in a bunch of other languages, I call. Concurrency is hard, every concurrency model has flaws, and which flaws you want to live with is largely a matter of personal preference and what type of problem you are working on.
For myself, I happen to agree with OP that single threaded plus async/await has honestly been my favorite concurrency model I've ever worked with for the types of programs I tend to write (IO-bound web apps with lots of network requests and no hot loops). The property that they described of having no race conditions of any kind except where you opt into them by calling out to an explicitly tagged async function is an enormous unnecessary mental burden removed.
In other contexts with higher compute demands, a full threading model or something like Go can make a ton of sense. But it's not worth the overhead for your average web app where what you really want is to just resume when that web request finishes.
Use the right tool for the job, don't get dogmatic about programming language features in the abstract.
There is a parallel universe in which Brendan Eich was given more than 10 days to hack on JavaScript, and in which he presented the language with full-blown stackful coroutines instead of hacky callbacks for concurrency. There might be even a parallel universe in which '[] + 0' produces an error rather than the string "0".
Unfortunately, we do not live in that parallel universe, and JavaScript had to evolve the way it did. When callbacks have already been established as the standard concurrency mechanism, promises were a big improvement. When promises became standard, async/await was the natural evolution rather than breaking existing programs by introducing stackful coroutines.
Other languages which chose async/await (Rust, C#, Kotlin) had their own reasons. In all of the cases above, the language designers wanted to give the user more control over the scheduler (Colorless Stackful coroutines require a global scheduler).
In Rust's case, it's async/await state machines are just not wasting memory and unnecessarily copying it like stackful coroutines do (not to mention that Rust doesn't have a garbage collector and pointer rewrites, so it cannot just copy stacks around when they grow). In fact, Rust did have garbage collection and green threads, but they were both removed early on, as the language changed its focus to became a language where you can expect performance that are _at least_ on par with C or C++.
In case of Kotlin, this all mostly had to do with finding an abstraction that can run on pre-Loom JVMs, JavaScript targets and native targets. Kotlin does not own the runtime.
Saying everybody should follow Go here is silly. Not all languages share the same background and design constraints. Go-style Stackful coroutines require garbage collection, full control of the runtime and generally a language that is designed from scratch to have them - or a 6-year project to adapt your language and runtime to have them, like Project project Loom did.
Async/await imposes some costs, but the benefits (compatibility, performance, flexibility) often outweigh these. After working with both async functions and stackful coroutines in multiple languages, I cannot say I ever felt concurrency in Go to be more ergonomic than Kotlin. If anything, it was the reverse for me in that particular case (owing to Go's lack of reification for goroutines and verbose syntax). Deciding in advance what color is my function (i.e. whether it needs to deal with I/O), is pretty simple and it rarely changes during the lifetime of a program (and even when it does, refactoring is not hard unless your design is bad).
The only case where I did feel some pain using async/await, was Rust, and this has more to do with Pin, competing async runtimes (for a while), lack of support for async traits (for a while) and other areas where Async Rust still needs some work.
> The information is only hidden with colorless methods if you consider the documentation to be a place to hide information (o^o)
That's exactly the mindset of quite a number of programmers nowadays, sadly. Two anecdotes: First, there was a blog post (probably even featured on HN) about problems in the design of the API of... Python's requests library, I think? It was quite a bizarre reading, complaints made almost no sense to me until I got to about the middle of the article when it clicked: the author was trying to figure out how to use the API by just reading the names of the classes, methods, and parameter names and making guesses as how it all would connect together instead of, you know, reading the docs. Which do exist, by the way.
The second example happened just yesterday at my job. In the essence, some fellow programmer added a call to function foo() which he thought would do some particular thing and return a particular answer while in reality it did not quite do that, and the return value is essentially meaningless (the function basically always returns "yep, I've scheduled do_foo() to run asynchronously some time soon"). Now, this foo() dunction is not documented, and if you read it's source (3 lines of code), it's quite obvious that its return value is useless... so why did they think it works the way they wanted it to work? When asked about it, the answer was "Well, it's named foo(), so I just thought that's what it would do". Sadly, calling strange third-party functions and hoping them to work they way you'd like them to work is no basis for writing the working programs.
And of course, these developers will also complain that the project lacks documentation. Often this is the case for projects that are actually well documented, its just that the dev didn't read it.
Was also going to say this. I've seen so many people fumble around figuring something else, then write a doc for how to do it, just to find that someone else wrote effectively the exact same doc 5 months ago.
Async/await is clearly a feature in JS, though not for the reason the previous poster mentions. Async/await wasn't part of the language until 2017. If you don't like it, you can just use Promises. If you do that, there are no "colored function" (functions of color?).
As far as the article goes, I think the pattern in Ruby is great. I prefer it to JS. But the JS approach works fine and the whole controversy about colored functions is a little silly.
I would be interested in understanding why JS can't enable await from inside non-async functions. I (maybe naively) wonder if the compiler couldn't just figure out which functions to treat as async rather than making the programmer do it.
> Any function that calls another that returns a Promise will have to return a Promise to represent completion correctly
No, it doesn't, closures let you update values in the wcope of the parent in .then() callbacks and then you can loop in the function and wait for completion and return a non-Promise value.
With a well-configured dev env with typescript, prettier, eslint and the appropriate config, async/await does feel like a feature. The IDE adds the async keyword for you if you forget it. If you enable errors in the whole project, it will tell you of any file/function that has an inconsistency in that regard.
So yes the compiler can figure it out, but only with Typescript. For javascript, a promise it a promise, but it doesn't know that a function will return a promise until it does. You can try compiling some async/await codebase to an old ES5 version and see the mess.
> The information is only hidden with colorless methods if you consider the documentation to be a place to hide information (o^o).
No, source code is where you hide the information, documentation is where you hide misinformation (or accurate information about how the function worked 3 versions ago, which is much the same thing).
The code tells you what the code _does_. The documentation (which can include comments in the code) tell you what the code is intended to do. Either one of those can be wrong. If the code doesn't match the documentation, then there is a bug in the system.
Not having documentation just removes the ability to determine if what the code _does_ is what the code is _intended to do_.
> If the code doesn't match the documentation, then there is a bug in the system.
Then I'd say the vast majority of Ruby libraries are buggy.
> Not having documentation just removes the ability to determine if what the code _does_ is what the code is _intended to do_.
But usually there isn't any intent when it comes to async-or-not. Library authors usually just write a method that results in the right value; whether that method can yield or not isn't even something they thought about, much less had a specific design in mind for.
I've worked on multiple large Ruby codebases with many engineers contributing (ex: meta).
There are many large Ruby projects out there, your one-developer-language opinion is simply not supported by facts
How is grep not solving this problem ?
I've met this pattern across many codebases but a simple call to grep (or equivalent) usually answers those questions pretty quickly
First, you cannot grep when the function is generated at runtime.
Second, what happens when the code is in a different repo and there are zero imports so you have no clue where it’s getting loaded from?
We’ve got multiple gems and microservices so I can’t even grep one codebase, I basically have to grep our entire gh org to find the function because ruby has terrible tooling to help with “go to definition”.
reply