When it comes to random identifiers, the advantage of uuid4 is mainly that it's a standard thing that everyone understands well, and finding a lib that generates one securely won't require any thought. It's never the ideal solution, but it's often good enough.
Yeah I'm not a fan of the non-random UUID specs causing confusion. Seems like they mostly get used accidentally by someone who actually needed uuid4. "uuid5 is newer and better, right?"
The crux of this argument seems to be that UUIDs are too long? Which I disagree with. I can't memorize them, no, and it would be cumbersome to try to say one aloud, but these aren't situations I've ever found myself in.
Does it make the URL in the URL bar longer? Yeah, but does that matter?
Users aren't expected to manipulate URLs manually. If your URLs have extra stuff, that's what people are going to copy/paste into messages.
Amazon product URLs are looong, but maybe people don't share them enough for Amazon to care. YouTube and Twitter put more effort into making them short.
I wonder if this is something Unicode could address. You could have something like quote marks that mean "Anything between these is data that shouldn't be seen in digital media but should be printed"
So you could have urls like:
example.com?<a single icon>&productname=somethinghumanreadable
The browser would also have to understand not to copy that part by default. But HTTP disallows unicode chars in URLs. There could instead be some "sharable URL" web API, but it seems like a small enough problem that sites are content just providing a custom share button if needed.
Sure, if Amazon sold about 10 products, such a URL scheme would work great. Additionally, this constantly redirects to the latest version of the iPhone, whereas Amazon's URLs are pointing to a specific version.
A more "apples to apples" comparison (pun intended) would be the MagSafe charger:
Cause some links are more likely to be shared, meaning they'll appear in a comment or SMS rather than just in your URL bar. Like if I copy a link from YouTube into HN: https://www.youtube.com/watch?v=00Uw9kgZ4QM
I'm sure they put some thought into not making it ?v=f6dde15a-3485-4f36-b0b9-a3b56fbc12ae.
> Does it make the URL in the URL bar longer? Yeah, but does that matter?
Yes. That's one of the author's arguments.
) A simple ID like 3c6n63N is more than enough to represent any product while keeping it readable and making communication easier. A UUID alternative like a73ba12d-1d8b-2516-3aee-4b15e563a835 is just wasteful from an user’s perspective.
Sure — it's just a weird question to pose when the author specifically provides their opinion on it. It'd be different to say "I don't think it matters".
There is the rub. Readable for what purpose? Aesthetics? And why? It is meaningless in their example.
And what do they mean with communication? Reading it aloud? If the URL is too long to stick in a tweet or message, there are plenty of URL shorteners out there.
The point of a UUID is to have a unique machine ID that can be generated in parallel by separate, non-synchronized processes.
You don't need to make it a user exposed identifier, and you can have a centralized (but out-of-the-critical-path) process assigning friendly IDs if you can afford visibility delays (for either the whole item or at least the friendly ID, which if it is the only user-facing locator may mean that the individual item can’t be directly accessed even if it is visible in aggregates, until that is assigned; if you allow access by both the UUID and the friendly ID, with the latter presented as preferred once available, this is resolved but this may appear messier.)
Exactly. Also, not everything is going to be an URL, or human-visible at all.
Others have noted the usefulness of generating ids for user-created data without involving the server, while being able to post that data at a later time without worrying too much about collisions.
Suspenders-and-belt practice would of course dictate that the server do some type of collision detection and mitigation before storing the received data.
If UUID exists in database and user ID is different, tell client "Yo, we've got a collision here. Your new ID for this data is blah".
On the client end, when creating the data,
Generate new UUID. If I've ever used that UUID before, generate a new one.
When the client saves the data to the server
If the server rejects my UUID, switch to the new one provided by the server
In practice the collision mitigation code is likely never to be called, even in a very large system. The people who designed UUID went to great lengths to ensure that.
Personally, I'd look on home-brewed solutions for generating unique "friendly ids" with the same deep suspicion I look at home-brewed crypto, particularly if this were done client-side for multiple clients without involving a server round-trip. Getting it right is a Hard Problem. The perceived complexity of UUIDs is there precisely because it is a Hard Problem.
I guess in the rare instance where you're literally reading a URL out loud it would help. Most of the time you're sending a URL, at which point length is mostly irrelevant as you're "copy/paste" on both sides.
Agreed. Decorative URL slugs have been successfully used by everything from blogs to Amazon itself for over a decade. If anything, that should be the focus here. Short URLs aren't much of a help, especially when short is relative on something like a mobile device.
> Does it make the URL in the URL bar longer? Yeah, but does that matter?
No, it doesn't.
If you're using a central system to generate id's (UUID's or other), then you are indeed missing a lot of the benefits of UUID's and might as well use some other ID scheme.
The benefits of UUID are many systems can generate them, and your database can eventually accept them, all with a very high guarantee of uniqueness/no-collisions. Not to mention the other nice bits like non-sequential and non-enumerability.
Most modern databases have UUID/Binary types/functions to allow for more efficient storage/handling anyway.
For a simple practical example, it's awfully useful for a lot of systems to be able to generate UUIDs in an app while offline (think document creation, etc) and reconcile things later by shooting the blob of content off to the server, while knowing that you only need to handle the dance of getting IDs and updating stuff locally again in your error handling case.
They might if several sets of tracking information end up there, because people are blocking the cookies they might otherwise be in for instance, and each set of tracking info has an identifier or few. The length of UUIDs will multiply up quite quickly there.
Not that people will care. Once a URL is longer than a few words plus a code most users won't even look, even if they bother that far. You'll be in danger of starting to hit some browser/server/proxy limits though.
Not that I mind that sort of information being lost, I'm happy for the incessant tracking of everyone's everything these days needs to go to hell.
I noticed a recent change on YouTube where the "share" button now includes extra tracking stuff, making it longer than the actual URL in the address bar. Which is even funnier considering that they bought the youtu.be domain just to make shared URLs shorter.
I'm really reaching here, but an ID that omits special characters is easier to extract from a url, since it can be double-clicked in a URL bar to select it, whereas a GUID with hyphens forces the user to select the beginning and the end of the string.
Realistically I think this matters to developers more than users (I hope your application doesn't force users to interact with GUIDs in the address bar) but that's the only "waste" I can identify.
EDIT: Someone elsewhere noted that they can base64 encode their GUIDs to achieve this and I'm seething that I'd never thought to do that
To select an UUID, double click the first segment and drag the selection till the last segment before releasing. No need to aim for the exact beginning and end characters.
(Maybe that's what you meant, amd yes, it's still clunkier than simply double clicking, but not much)
> easier to extract from a url, since it can be double-clicked
Maybe the double-click logic needs to be less stupid then. Or have it progressive, e.g. double-click = alphanumeric, triple-click = stop at symbols, quadruple-click = stop at slashes only, quintiple-click = the whole URL.
Use the device microphone to listen for swear words and adjust algorithm with machine learning accordingly
As you said in your edit, you can of course base64 the GUID, but also don't most GUID libraries have an option to just omit the hyphens? I know .NET allows you to do that, and even correctly parse GUIDs that don't have any hyphens.
I usually did that in .NET simply because I thought it was prettier without the hyphens.
> I'm really reaching here, but an ID that omits special characters is easier to extract from a url, since it can be double-clicked in a URL bar to select it, whereas a GUID with hyphens forces the user to select the beginning and the end of the string.
The is-hyphen-part-of-a-word issue depends on the text control (browser, UI widget library, …) / terminal you use, which is not universal.
In any case, the hyphens/dashes are not required part of the representation, and one can use the “dashless” representation (exactly 32 hex digits) in URLs and in-code without any issues whatsoever, as far as I know; for example, Postgres accepts either “dashful” or “dashless” UUIDs the same.
It might, e.g. with embedded systems. I can neither confirm nor deny that we once BOFed our own devices because we assumed that 1200 bytes was a big enough buffer to hold a URL.
> Does it make the URL in the URL bar longer? Yeah, but does that matter?
I appreciate shorter URLs any time I copy and paste them, which always involves looking at them and sometimes involves scrolling to the end to remove tracking- and search-related fluff.
128 bits is an absurd amount for a unique ID within a single system. Even 48 bits is very, very large -- enough to provide a unique ID (MAC address) to every Ethernet device made for something like 100 years.
The purpose of a UUID is to provide a negligible probability of collisions between randomly-generated IDs in a global space forever. Almost no applications require that, so most of the time using a UUID is just needlessly taking up space.
Maybe I'm missing something, then? I'm having trouble thinking of applications where it seems like a good idea to generate a permanent ID number completely randomly at all, much less applications that need to let the whole world do so. I can see how Windows device drivers have that requirement, but the point of the article is that even a massive site like YouTube (which doesn't want videos to be randomly discoverable via URL manipulation) does not need anywhere close to 128 bits. What are these applications you speak of?
Basically, you want UUID's 122 bits (128 minus 6 wasted on variant + version) if you can't afford collisions. If you have some DB enforcing unique IDs at creation time, you can manage with a lot fewer bits if you want shorter URLs or something.
> 128 bits is an absurd amount for a unique ID within a single system. Even 48 bits is very, very large -- enough to provide a unique ID (MAC address) to every Ethernet device made for something like 100 years.
What you want is that the number of possible items to enumerate is significantly less than the square root of the cardinality of the ID range, means you can relatively safely randomly generate IDs with few collissions.
> A simple ID like 3c6n63N is more than enough to represent any product while keeping it readable and making communication easier. A UUID alternative like a73ba12d-1d8b-2516-3aee-4b15e563a835 is just wasteful from a user’s perspective.
I would challenge the premise we appear to be starting from, that the average end user cares to be dealing with any random string of numbers and digits. GUIDs work well, they’re implemented everywhere, and you won’t find out long after you go into production you made some mistake that is going to make it so you have to migrate away from them.
The official Base32 doesn't work for encoding UUID7, which is time-ordered, because its symbols for 0-31 are not in ascending ASCII order.
My own preferred format for UUID7 is one I call "id25". It's really Base35 because alphabets of 35 and 36 characters both need 25 characters to represent the 128 bits in a UUID. So I can start with Base36 and take out one of the next most ambiguous character pairs. The result looks something like '0pydgw5pifvapk5zyhmpso5tx'.
The two other advantages of using this id25 format rather than UUID7 are:
- The id25 format is quite distinct from UUID4. So if you have UUID7s being generated distributedly (rather than centrally) and the UUID7 time-ordering feature is important, it's nice to have a format that a trivial "if '-' in uuid_string..." check will spot.
- Because there are no hyphens or symbols, the whole id25 uuid can be selected in web page with a double click. Whereas a uuid will need a mouse movement to get all 5 parts.
Do many use cases need lexical ordering for the encoding of the UUID? (The UUIDs themself would still be ordered; it's just the human/URL/wire encoding that isn't.)
Most of the use cases I can think of where I'd want an ordered UUID, I probably wouldn't need to lexically compare the encoding of multiple such IDs (where I can see plenty of utility in the ability to compare the underlying IDs).
I've always seen the human encoding as the main point, so you can infer things about them while working with them. A database, for example, would have a datetime column that can be used instead most of the time.
For sure yes! There are tons of situations where you need to use the string form of an ID, e.g. filenames, and you definitely want the lexical ordering of files in a directory to be correct.
Some alphabets have the disadvantage of generating swears, which might be a problem for your use. Applying filters is a difficult approach. Hex has the advantage there.
I think a better argument is that that the identifier needs to be unambiguous in cases where e.g. an ID needs to be communicated over the phone between an end user and a customer service rep. But that is easily solved with encodings like Base58 that exclude ambiguous characters.
Once you get over about 10 characters the chance that the user will skip or repeat a character or misread one goes up.
Sometimes when I order parts for my car the site wants the VIN to verify that the parts are correct for that vehicle. I often have to make two or three attempts at entering it to get it right.
Although after reading that Babble link it sounds like a great idea for product id's. Scenarios where it is unlikely for people to have to read it out but when they do it's easy enough to convey.
I regret that there are scenarios that we should have converged on it but didn't.
When the encoding relies on differentiating between lowercase and capitalized characters, you’re hitting a high level of ambiguity. Hexadecimal UUIDs don’t have this problem.
> that the average end user cares to be dealing with any random string of numbers and digits.
A developer, which I took to be "the user" for the purposes of this writeup, cares. My small concern is that the rand is insufficient to generate a unique enough string (just use a lib like snowflake to get overkill entropy), but I'm sick of having the format at all for inconsequential ids (eg https://www.uuidgenerator.net/).
Also as a developer I really dislike UUIDs because the hyphens make it impossible to double-click copy.
It’s a small gripe, but I need to copy IDs multiple times per day and it adds up. Other ID formats like cuid or KSUID don’t have hyphens in their canonical representation, and it makes them far more pleasant to work with
Thats typically something you can configure in your terminals settings. Though avoiding requiring everyone know how to do this and actually do this is an improvement in developer experience so there's some merit here.. but is there any real standards around what characters get included in copying like this, or any best practices based on common defaults?
if not it might just become a situation of optimizing for your own workflow. and considering how ubiquitous uuids are and how common dash delimiters are outside of that(jira ticketscome to mind) maybe it would be better to fix places where double click selections do not include dashes instead of trying to avoid dashes in identifiers?
I like your thinking, but somehow fear that at some point in time in the future I'll get an ID like "S5o0QlI1" and my brain will automatically eject itself from my skull in disgust.
Sure, you don't need them, but why re-invent the wheel? At least UUIDs are not some one-off function in a helpers file that may need to be amended many times before you get it right, but are backed by a specification, are time-sortable, etc.
Use sequential IDs, but run them through a maximal linear feedback shift register.
They will be in a deterministic order, but will appear semi-random to the end user.
For things like product IDs or user IDs, etc you don't actually need them to be random. But perhaps you don't want them to simply start counting sequentially.
Isn't auto generating UUIDs "fast enough" in most situations that its negligible?
In particular databases (where UUIDs taking space was a big concern) they have largely switched to a packed binary format that makes the size of UUIDs over time a non issue for all practical purposes.
No, that shouldn’t be the criteria (common relational db) when deciding to use bigserial v UUID but the overall architecture and requirements of your system.
Whatever your overall requirements are, if you've already decided on a relational DB to solve them, you probably want bigserial PKs in said DB. The DBMS is optimized for that (as I've noticed in Postgres), and you don't gain anything by using UUIDs instead there. UUID in a secondary col or elsewhere in your system, that's fine.
If you have to look up by UUID from outside and have no foreign keys, UUID PKs can be faster. But that's the classic use case for a non-relational DB.
Doesn’t UUID have mechanisms to prevent collisions even if you start two processes simultaneously with the same initial seed? There are human readable tweaks you can make to them that preserve all of the good properties without limiting the pool much though.
There are so many nuances and edge cases not mentioned in the article. The author needs to do several projects in real life before making global pronouncements like this.
The lack of humbleness and respect for devs who have came before you and solved all these problems is coming through strong. But I myself was that way 15 years ago. It takes a lot of hard lessons to realize everything new is old and we truly stand on the shoulders of 7000 giants all standing on each others’ shoulders.
Did you even read beyond the title? To say that because of this choice of title, I lack humbleness or respect for peers who came before me is despicable.
My title is too presumptive. Yet, the reality for almost everyone who doesn't interface with other systems that already require UUID is that.
The brief article gives some points – backed by trustworthy sources – and shows some alternatives without further ado.
I didn't spend days writing it. I could cover many more scenarios but didn't invest my time in it. So what?
Someone else implied this in another comment but this line appears at the end of the article:
> If you click and buy any of these from Amazon after visiting the links above, I might get a commission from their Affiliate program.
When one wonders why that was included they might discover that the "short ID" example given near the top of the post is an Amazon link. One might then further wonder what the purpose of this article is.
I don't think it's a matter of not being able to index on it, but that mostly random UUIDs (like v4) can lead to some interesting index fragmentation you have to stay on top of somehow.
You already got multiple answers explaining the performance issue.
Now in many, typical applications you'd have to scale up quite significantly before this becomes a problem.
But if your application requires you to store small, new entries very quickly, you'll start to notice this even with moderate scale. Disk persistence is often the bottleneck already, and this might make it worse.
It's particularly interesting that Microsoft SQL Server was designed to optimize indexing for UUIDv1 machine IDs. That makes a certain amount of sense for a database cluster if IDs are sorted by machine. Of course, developers don't let developers use UUIDv1 in 2023 because those machine IDs are not secure in a general sense and can be a privacy/data leak in the worst cases.
Other databases sort/index UUIDs differently. There's no real "standard" and optimizing the storage of a UUID key is a game of playing to the strengths of your specific database.
(On one project I put some work into matching the much-better-defined ULID sort order to MS SQL Server uniqueidentifier columns for better database locality.)
I would use it anyway. This article misses some subtleties that make uuids really great, as well as some real points against uuids (impact of v4 uuids on index access and uuid v7 as a solution to that)
Sequential isn't always simple. If your system is distributed in the slightest way (even just multiple threads), it's a bit of a luxury to find sequential guarantees.
ULIDs can get you rough ordering guarantees even in distributed systems. Precision, of course, requires synchronization, which is usually a non-starter.
You don't "need" them, but they're almost universally understood and supported which makes them super convenient and a good starting point for many use cases. The point in which the "wasteful" nature of a UUUID really bites you is so far down the road that it is almost not even worth thinking about until you get there. Chances are you won't be dealing in petabytes at all and the 64 bit savings you are fretting over doesn't really matter.
A UUID is 128 bits, or 16 bytes. This code suggests IDs which are 11 bytes. That's not really comparable.
A UUID can also be encoded in any form, it doesn't need to be represented as the dashed string notation which is common, you can just as easily use the base58 alphabet suggested in the post.
But the code in the post doesn't encode to base58 correctly. You need to map 58 bits of the input, sequentially, to one character in the alphabet as output. You can't just mod each byte of the input by the alphabet length and use the corresponding alphabet element.
The base58 code in the post is wrong, but your version isn't right either.
Since the alphabet is 58 characters, each character contains log2(58) bits. Since that's not an integer, the encoding process is a bit more complex than just mapping bits to characters in a table.
I agree lines 12-14 doesn't do a proper encoding, but that's not what I was after.
Would you still say it's still wrong if you consider that my function is not really encoding the string per se, but using rand.Read to generate entropy for what I want to be the final output (random string with the base58 alphabet)?
Your IDs are []byte of len=11. Those bytes can be represented in many ways. You can represent them as hex strings via encoding/hex.EncodeToString(id), or base64 strings via encoding/base64.StdEncoding.EncodeToString(id), or base32 strings via encoding/base32.StdEncoding.EncodeToString(id), or etc.
But how you encode 11 bytes of data is kind of orthogonal to the important thing, which is that you have 11 bytes of data. Those bytes should be always be stored in memory (in your application, or in your DB, or wherever) as the actual 11 bytes of the ID, and not as a base58 or base64 or JSON or whatever other kind of string that can be decoded to the actual 11 bytes they represent.
Likewise, a UUID shouldn't be stored as a string like "64d3f2e0-a4dc-48d3-98ad-7f09eb3b082f", that's a specific encoding of the actual 16 UUID bytes, you should store, process, etc. those bytes directly.
Indeed. That's why I mentioned it's a 128-bit identifier format in the first line of the article, rather than 128-bit identifier. I probably spent 10min writing something to explain this, but then it wouldn't really be helpful so I removed it.
> Version 4 is completely randomly generated (hence, it has more entropy) and is what most web systems seem to use. It has 16^32 = 2^128 bits that guarantee uniqueness and has an insignificant risk of collision.
Small correction here but it is not 128 random bits entirely: 6 bits are reserved for the version marker.
UUIDs are great for when you have a distributed system where connectivity between the nodes is intermittent, and every node needs to be able to create new entities without ever having ID collisions.
For instance, UUIDs allow mobile apps to create entities while offline.
> This solution uses the human-readable base58 encoding scheme.
We could encode the 128 bit UUID integer in base58 as well if needed. Its textual representation won't conform to the standard but we'd get the same number of bits. Which would be 2^122 or 2^121 bits of uniqueness not 2^128 if it's a proper UUID.
11base58 character certainly doesn't have the 2^122 bits. So we could decided separately if we could either reduce the number of bits needed and/or use a different encoding.
> If you click and buy any of these from Amazon after visiting the links above, I might get a commission from their Affiliate program.
I’m not sure if this is accurate any longer, but it was bad practice to use UUID’s as PK’s in PostgreSQL for example due to indexing and performance. Is this still true? It’s really nice in PostgreSQL to just do:
> As Tom Scott shows in his video, 11 base58-encoded characters are enough for YouTube to serve content even when considering that private videos should be undiscoverable.
Nitpick: Google isn't concerned about the discoverability of private videos; those can only be viewed when granted access. You're thinking of unlisted videos.
uuids are ubiquitous and easy and implemented in many languages in the standard library - therefore a dev can get near-guaranteed uniqueness without thinking too hard about it.
Until another standard similar to what the article is suggesting becomes widely implemented in standard libraries then uuid isn't going anywhere, although in principle I agree with many of the arguments presented.
- Don't invent your own ID datatype (especially 11 byte one), this is almost guaranteed to cause dangerous bugs, because each integration will have to carefully implement/hack it.
- Use UUID (preferably the new v7). 128-bit UUID is implemented, for you, pretty much everywhere.
- Serial integers still work too, but you should choose them consciously to fit the data model.
- Implement "natural keys" if you want pretty/memorable/Cool URLs. Never use non-standard PKs to store custom semantic data, because inevitably you will get garbage PKs that need to be fixed, and migrating a PK value is extremely risky.
199 comments
[ 3.4 ms ] story [ 279 ms ] threadI agree. If there was a shorter standard, I would use that for most cases.
Does it make the URL in the URL bar longer? Yeah, but does that matter?
UUIDs are at least visually kind of white noise, companies have no problem+with+links?that=look&like=this, so why do they care about UUIDs?
You can't beat that. Or would you rather receive texts that include the following?
> companies have no problem+with+links?that=look&like=thisLet's not match the lowest common denominator, shall we?
https://amazon.com/dp/B09V3HZ8B5
As you have been told apple.com/iphone = www.amazon.com/dp/B09V3HZ8B5
The rest of what you posted on the Amazon link is tracking bullshit. Now, THAT is irrelevant !
Amazon product URLs are looong, but maybe people don't share them enough for Amazon to care. YouTube and Twitter put more effort into making them short.
So you could have urls like:
example.com?<a single icon>&productname=somethinghumanreadable
A more "apples to apples" comparison (pun intended) would be the MagSafe charger:
https://www.apple.com/shop/product/MHXH3AM/A/magsafe-charger...
I'm sure they put some thought into not making it ?v=f6dde15a-3485-4f36-b0b9-a3b56fbc12ae.
Yes. That's one of the author's arguments.
) A simple ID like 3c6n63N is more than enough to represent any product while keeping it readable and making communication easier. A UUID alternative like a73ba12d-1d8b-2516-3aee-4b15e563a835 is just wasteful from an user’s perspective.
"Does it matter" is a very reasonable response to someone expressing their opinion.
If I say "x matters and here's why" and you respond "yeah but does x matter?", you're either not paying attention or being rude and dismissive.
And what do they mean with communication? Reading it aloud? If the URL is too long to stick in a tweet or message, there are plenty of URL shorteners out there.
On link-sharing sites like this one, we care about the URL’s we share and will often strip off the tracking stuff.
And I bet that for most users 3c6n63N is as confusing as a73ba12d-1d8b-2516-3aee-4b15e563a835
You don't need to make it a user exposed identifier, and you can have a centralized (but out-of-the-critical-path) process assigning friendly IDs if you can afford visibility delays (for either the whole item or at least the friendly ID, which if it is the only user-facing locator may mean that the individual item can’t be directly accessed even if it is visible in aggregates, until that is assigned; if you allow access by both the UUID and the friendly ID, with the latter presented as preferred once available, this is resolved but this may appear messier.)
Others have noted the usefulness of generating ids for user-created data without involving the server, while being able to post that data at a later time without worrying too much about collisions.
Suspenders-and-belt practice would of course dictate that the server do some type of collision detection and mitigation before storing the received data.
On the client end, when creating the data, When the client saves the data to the server In practice the collision mitigation code is likely never to be called, even in a very large system. The people who designed UUID went to great lengths to ensure that.Personally, I'd look on home-brewed solutions for generating unique "friendly ids" with the same deep suspicion I look at home-brewed crypto, particularly if this were done client-side for multiple clients without involving a server round-trip. Getting it right is a Hard Problem. The perceived complexity of UUIDs is there precisely because it is a Hard Problem.
No, it doesn't.
If you're using a central system to generate id's (UUID's or other), then you are indeed missing a lot of the benefits of UUID's and might as well use some other ID scheme.
The benefits of UUID are many systems can generate them, and your database can eventually accept them, all with a very high guarantee of uniqueness/no-collisions. Not to mention the other nice bits like non-sequential and non-enumerability.
Most modern databases have UUID/Binary types/functions to allow for more efficient storage/handling anyway.
Nowadays many links are much longer because of referrer information and tracking parameters. So the UUID doesn't add much.
Not that people will care. Once a URL is longer than a few words plus a code most users won't even look, even if they bother that far. You'll be in danger of starting to hit some browser/server/proxy limits though.
Not that I mind that sort of information being lost, I'm happy for the incessant tracking of everyone's everything these days needs to go to hell.
Address bar: https://www.youtube.com/watch?v=SHWhKRKlG98
Share button: https://youtu.be/SHWhKRKlG98?si=gwQHHze3UnjTobJg
I'm really reaching here, but an ID that omits special characters is easier to extract from a url, since it can be double-clicked in a URL bar to select it, whereas a GUID with hyphens forces the user to select the beginning and the end of the string.
Realistically I think this matters to developers more than users (I hope your application doesn't force users to interact with GUIDs in the address bar) but that's the only "waste" I can identify.
EDIT: Someone elsewhere noted that they can base64 encode their GUIDs to achieve this and I'm seething that I'd never thought to do that
(Maybe that's what you meant, amd yes, it's still clunkier than simply double clicking, but not much)
Maybe the double-click logic needs to be less stupid then. Or have it progressive, e.g. double-click = alphanumeric, triple-click = stop at symbols, quadruple-click = stop at slashes only, quintiple-click = the whole URL.
Use the device microphone to listen for swear words and adjust algorithm with machine learning accordingly
I usually did that in .NET simply because I thought it was prettier without the hyphens.
The is-hyphen-part-of-a-word issue depends on the text control (browser, UI widget library, …) / terminal you use, which is not universal.
In any case, the hyphens/dashes are not required part of the representation, and one can use the “dashless” representation (exactly 32 hex digits) in URLs and in-code without any issues whatsoever, as far as I know; for example, Postgres accepts either “dashful” or “dashless” UUIDs the same.
It might, e.g. with embedded systems. I can neither confirm nor deny that we once BOFed our own devices because we assumed that 1200 bytes was a big enough buffer to hold a URL.
I appreciate shorter URLs any time I copy and paste them, which always involves looking at them and sometimes involves scrolling to the end to remove tracking- and search-related fluff.
128 bits is an absurd amount for a unique ID within a single system. Even 48 bits is very, very large -- enough to provide a unique ID (MAC address) to every Ethernet device made for something like 100 years.
The purpose of a UUID is to provide a negligible probability of collisions between randomly-generated IDs in a global space forever. Almost no applications require that, so most of the time using a UUID is just needlessly taking up space.
What you want is that the number of possible items to enumerate is significantly less than the square root of the cardinality of the ID range, means you can relatively safely randomly generate IDs with few collissions.
You've never needed to give an order number, member ID, account ID, invoice number, etc?
I would challenge the premise we appear to be starting from, that the average end user cares to be dealing with any random string of numbers and digits. GUIDs work well, they’re implemented everywhere, and you won’t find out long after you go into production you made some mistake that is going to make it so you have to migrate away from them.
While somewhat less dense, base58 or rfc 4648 base32 mitigate these issues.
My own preferred format for UUID7 is one I call "id25". It's really Base35 because alphabets of 35 and 36 characters both need 25 characters to represent the 128 bits in a UUID. So I can start with Base36 and take out one of the next most ambiguous character pairs. The result looks something like '0pydgw5pifvapk5zyhmpso5tx'.
The two other advantages of using this id25 format rather than UUID7 are:
- The id25 format is quite distinct from UUID4. So if you have UUID7s being generated distributedly (rather than centrally) and the UUID7 time-ordering feature is important, it's nice to have a format that a trivial "if '-' in uuid_string..." check will spot.
- Because there are no hyphens or symbols, the whole id25 uuid can be selected in web page with a double click. Whereas a uuid will need a mouse movement to get all 5 parts.
Most of the use cases I can think of where I'd want an ordered UUID, I probably wouldn't need to lexically compare the encoding of multiple such IDs (where I can see plenty of utility in the ability to compare the underlying IDs).
Sometimes when I order parts for my car the site wants the VIN to verify that the parts are correct for that vehicle. I often have to make two or three attempts at entering it to get it right.
[0] https://bohwaz.net/archives/web/Bubble_Babble.html
[1] https://iancoleman.io/bip39/
[2] https://web.archive.org/web/20090918202746/http://tothink.co...
Although after reading that Babble link it sounds like a great idea for product id's. Scenarios where it is unlikely for people to have to read it out but when they do it's easy enough to convey.
I regret that there are scenarios that we should have converged on it but didn't.
https://github.com/tttp/dxid
A developer, which I took to be "the user" for the purposes of this writeup, cares. My small concern is that the rand is insufficient to generate a unique enough string (just use a lib like snowflake to get overkill entropy), but I'm sick of having the format at all for inconsequential ids (eg https://www.uuidgenerator.net/).
It’s a small gripe, but I need to copy IDs multiple times per day and it adds up. Other ID formats like cuid or KSUID don’t have hyphens in their canonical representation, and it makes them far more pleasant to work with
if not it might just become a situation of optimizing for your own workflow. and considering how ubiquitous uuids are and how common dash delimiters are outside of that(jira ticketscome to mind) maybe it would be better to fix places where double click selections do not include dashes instead of trying to avoid dashes in identifiers?
ULIDs don't have this problem, for the record.
That's a terrible way to use it is all.
They will be in a deterministic order, but will appear semi-random to the end user.
For things like product IDs or user IDs, etc you don't actually need them to be random. But perhaps you don't want them to simply start counting sequentially.
In particular databases (where UUIDs taking space was a big concern) they have largely switched to a packed binary format that makes the size of UUIDs over time a non issue for all practical purposes.
If you have to look up by UUID from outside and have no foreign keys, UUID PKs can be faster. But that's the classic use case for a non-relational DB.
https://devblogs.microsoft.com/oldnewthing/20040211-00/?p=40...
My title is too presumptive. Yet, the reality for almost everyone who doesn't interface with other systems that already require UUID is that.
The brief article gives some points – backed by trustworthy sources – and shows some alternatives without further ado. I didn't spend days writing it. I could cover many more scenarios but didn't invest my time in it. So what?
Not the person you're replying to, but the end of the first paragraph in your article is
> and I want you to understand why you *certainly* don’t need it
(emphasis mine)
> If you click and buy any of these from Amazon after visiting the links above, I might get a commission from their Affiliate program.
When one wonders why that was included they might discover that the "short ID" example given near the top of the post is an Amazon link. One might then further wonder what the purpose of this article is.
Both of those solutions typically make it hard for a DB if you write new entries, assuming you have an index on the ID.
In addition it might be more calming to actually be sure that a particular ID is not in use without doing a round-trip.
Is it practical to pre-allocate empty entries and reserve a set of them?
This is only a problem with extremely big indexes.
Now in many, typical applications you'd have to scale up quite significantly before this becomes a problem.
But if your application requires you to store small, new entries very quickly, you'll start to notice this even with moderate scale. Disk persistence is often the bottleneck already, and this might make it worse.
One fun and useful reference: https://devblogs.microsoft.com/oldnewthing/20190426-00/?p=10...
It's particularly interesting that Microsoft SQL Server was designed to optimize indexing for UUIDv1 machine IDs. That makes a certain amount of sense for a database cluster if IDs are sorted by machine. Of course, developers don't let developers use UUIDv1 in 2023 because those machine IDs are not secure in a general sense and can be a privacy/data leak in the worst cases.
Other databases sort/index UUIDs differently. There's no real "standard" and optimizing the storage of a UUID key is a game of playing to the strengths of your specific database.
(On one project I put some work into matching the much-better-defined ULID sort order to MS SQL Server uniqueidentifier columns for better database locality.)
Lots of languages are catching up to UUIDv7, which solves the indexing issue.
I like its simplicity. It is sequential. It has a very low probability of collision. And it is of a more reasonable length.
Because it encodes the time, theoretically you could use it to grab the CreatedDate of a record without a need for another field.
https://github.com/ulid/spec
...because I am going to keep using uuid
A UUID can also be encoded in any form, it doesn't need to be represented as the dashed string notation which is common, you can just as easily use the base58 alphabet suggested in the post.
But the code in the post doesn't encode to base58 correctly. You need to map 58 bits of the input, sequentially, to one character in the alphabet as output. You can't just mod each byte of the input by the alphabet length and use the corresponding alphabet element.
Since the alphabet is 58 characters, each character contains log2(58) bits. Since that's not an integer, the encoding process is a bit more complex than just mapping bits to characters in a table.
https://digitalbazaar.github.io/base58-spec/#encode
I agree lines 12-14 doesn't do a proper encoding, but that's not what I was after. Would you still say it's still wrong if you consider that my function is not really encoding the string per se, but using rand.Read to generate entropy for what I want to be the final output (random string with the base58 alphabet)?
Looks like the most used base58 package is https://pkg.go.dev/github.com/btcsuite/btcutil/base58, but looking at the implementation [0] I'm not impressed, there's definitely a much better approach.
[0] https://github.com/btcsuite/btcutil/blob/v1.0.2/base58/base5...
But how you encode 11 bytes of data is kind of orthogonal to the important thing, which is that you have 11 bytes of data. Those bytes should be always be stored in memory (in your application, or in your DB, or wherever) as the actual 11 bytes of the ID, and not as a base58 or base64 or JSON or whatever other kind of string that can be decoded to the actual 11 bytes they represent.
Likewise, a UUID shouldn't be stored as a string like "64d3f2e0-a4dc-48d3-98ad-7f09eb3b082f", that's a specific encoding of the actual 16 UUID bytes, you should store, process, etc. those bytes directly.
not sure if this is duplicative but down the road i figure I can navigate whichever direction i need to go in
Small correction here but it is not 128 random bits entirely: 6 bits are reserved for the version marker.
For instance, UUIDs allow mobile apps to create entities while offline.
We could encode the 128 bit UUID integer in base58 as well if needed. Its textual representation won't conform to the standard but we'd get the same number of bits. Which would be 2^122 or 2^121 bits of uniqueness not 2^128 if it's a proper UUID.
11base58 character certainly doesn't have the 2^122 bits. So we could decided separately if we could either reduce the number of bits needed and/or use a different encoding.
> If you click and buy any of these from Amazon after visiting the links above, I might get a commission from their Affiliate program.
:-)
Nitpick: Google isn't concerned about the discoverability of private videos; those can only be viewed when granted access. You're thinking of unlisted videos.
Until another standard similar to what the article is suggesting becomes widely implemented in standard libraries then uuid isn't going anywhere, although in principle I agree with many of the arguments presented.
- Don't invent your own ID datatype (especially 11 byte one), this is almost guaranteed to cause dangerous bugs, because each integration will have to carefully implement/hack it.
- Use UUID (preferably the new v7). 128-bit UUID is implemented, for you, pretty much everywhere.
- Serial integers still work too, but you should choose them consciously to fit the data model.
- Implement "natural keys" if you want pretty/memorable/Cool URLs. Never use non-standard PKs to store custom semantic data, because inevitably you will get garbage PKs that need to be fixed, and migrating a PK value is extremely risky.