- Feature Articles
- CodeSOD
- Error'd
-
Forums
-
Other Articles
- Random Article
- Other Series
- Alex's Soapbox
- Announcements
- Best of…
- Best of Email
- Best of the Sidebar
- Bring Your Own Code
- Coded Smorgasbord
- Mandatory Fun Day
- Off Topic
- Representative Line
- News Roundup
- Editor's Soapbox
- Software on the Rocks
- Souvenir Potpourri
- Sponsor Post
- Tales from the Interview
- The Daily WTF: Live
- Virtudyne
Admin
I would argue that this is a good example of "doesn't work" (especially the "high probability of collisions" part), and yet the article says that it does work...
But then again:
Why did it take until 2021 for JS to sprout a random-UUID function?
Why would we want to generate UUIDs in the browser rather than in the server code? (The WTF-ness of this question may explain why it took so long...)
Admin
The probability of collisions is very low. The built-in random functions are really good enough.
It's just a random id, nothing else. You can't send a 128 bit number in a url or json, so formatting it as a uuid is probably fine.
Nobody cares about the meta data in uuid, unless you mix different types (and I can't think of a reason why you ever would, although there's probably someone here who knows an obscure use case), but this code even takes that into account.
Admin
"Why would we want to generate UUIDs in the browser rather than in the server code?"
Some APIs require that the client generates the id of a newly created resource. It's bad, but at least someone else is to blame for it.
Admin
CQRS
When you have strict query/command separation, you don't really have return value(s) with your write operations. So if you want to create a new resource, you have to provide a unique identifier to find you resource again.
Admin
It is not bad at all when a UUID is used as an idempotency key, as to prevent creating duplicates on network hiccup.
Admin
the "4" in the string is the type of the identifier.
Admin
The proper thing to do is check whether
crypto.randomUUID
exists and use this only as a fallback.Admin
Many years ago, in the days of Java 4, I used Java's UUID generator as it was at the time to generate unique ID's for channel identifiers in a messaging system. If I remember correctly, the UUID was constructed from three elements: the current time/date in milliseconds, the NIC address, and the base address of the process. Of course time of day is not guaranteed to be unique, but every machine has its own unique network card and every process in the machine has a different base address.
The server consisted of several machines, processing messages in assembly-line fashion. Multiple instances of the components ran in parallel.
We upgraded the server to fast new machines. Each new physical machine ran two virtual machines for two instances of a given component. When powered on, the machine automatically loaded the components.
But now, messages started going to the wrong components. Because two channels got the same identifier. Two virtual machines shared the real machine's NIC. Each virtual machine loaded its first program at the same base address as the other one. And the new machines were so fast, both instances of the component made the UUID call within the same millisecond.
Admin
I want to hate every aspect of this, but it's actually fine. Not great, and only usable if security of the generated UUID isn't a concern (if it was, you shouldn't be doing it client-side). But modern javascript engines use a very good RNG with enough state-space that it can generate any valid UUID with uniform probability, and usually gets seeded itself with the OS's crypto RNG (e.g. dev/urandom or CryptGenRandom), so that's OK for just generating a non-secure ID. Using Math.random() % 16 hurts my soul, because that's what people do when they don't know about modulo bias, but in this case 16 is a power of 2, so again, that's fine. It's fine. It works. It would be more efficient to use 4 RNG calls to draw 128 bits (4 32-bit numbers) and adjust some bits in one (if it's really necessary to correctly identify these as V4 UUIDs, but I like Hanzito's point), and then turn each one into a hex-string. But this is OK. Unless efficiency or security becomes an issue.
Admin
The use of a "template string" that is then overwritten with the actual data in the corresponding places reminds me of BASIC's "PRINT USING" instruction where the format string looked more like the code presented than what we know from C's printf() and its descendants. But it's not that I haven't seen similar approaches in other languages for other purposes, but for UUIDs, and with regex, well, that's surely something...
Admin
Except that here it's multiplying by 16, not taking the modulo, because presumably JS's
Math.random()
returns a floating point number in [0,1). (But it does avoid the "lower bits are less random" problem of most simple PRNGs.) Heaven help us if the result is in [0,1]...Admin
Because JavaScript can also be your server! (Node.js and Deno)
Admin
Or this: https://m.xkcd.com/221/
Admin
More proof that there is no problem that cannot be solved by regular expressions.
Admin
Ah, that is true. However, there is still usually a bias of the same nature when multiplying a random floating point number by your desired range. You are mapping a value from a set of 2^53 possible values onto a smaller set, which only works uniformly when the range is a power of 2. As it is here. So still no problem.
Admin
"....there is still usually a bias...etc"
Yes, but with this many digits? Not a real problem.
Admin
The real WTF is that Javascript still has no easy way to replace a char in the middle of a string.
(even if it has to create a new string, there's still no function for that...)
Also: That str[0] = 'x' doesn't give an error, it just does nothing.
Admin
No one is going to comment the fact that they're searching for both
x
andy
in a string containing onlyx
and4
?Admin
:facepalm: Now I find the
y
.Admin
As another old timer (who's name I've forgot) put it: What do you expect, a KB article titled "GUIDs will kill you in your sleep"? That was in response to a question about the use of database UUIDs, which had been added to a MS database engine to support replication.
Except that they had been exposed as text strings, which required {curly braces} in some places, but not in others, and GUID tags in some places, but not in others, and broke indexing in some places, but not in others, and ....
They made the perfect Globally Unique Identifier for when you want your record Identifier to be broken and sometimes cause your queries or stored procedures to fail.