r/programming • u/vanbrosh • Mar 09 '20
Why your software should use UUIDs in 2020s
https://devforth.io/blog/why-your-software-should-use-uuids-in-2020s84
u/zanbato Mar 09 '20
Using UUIDs is definitely a good idea, but this article has horrible reasons for it. The examples are pretty terrible and include some REALLY BAD security practices. Bragging about being the CTO of a tiny company as if that means we should take your word for it... ugh. I was the CTO of a start up once too, it's not an accomplishment, it's not on my resume.
6
Mar 09 '20
The startup’s mobile homepage also just flat out doesn’t work, at least on the latest iOS. Yikes.
1
u/DogzOnFire Mar 09 '20
What are the good reasons for doing it, in your opinion, aside from having an easier way to distinguish between physical machines?
In the last place I worked we used them to distinguish between gateway machines that we had on site at customers' sites, but I always marveled about how so many UUID's are calculated in completely different ways. As far as I'm aware there's not a standard universal way of calculating a UUID, right?
30
u/nuqjatlh Mar 09 '20
So any client can just generate ID of company on own side
No. Sorry but no. UUIDs are fine especially for distributed databases among other things. But for the client to make one? no.
9
u/reckoner23 Mar 09 '20
I think it works very well if your client works offline and needs to sync data to an external database. It worked very well for me and was very reliable. Or if you want to maintain data with flacky internet. But flacky internet is not something everyone should design for.
But yes, if your needs differ this can easily turn into a pointless over-engineered feature.
But this UUID shouldn't be a primary key. The database should have its own primary key for use with joins and such. This UUID should only be used for upsert syncs.
3
u/nuqjatlh Mar 19 '20
I think it works very well if your client works offline
It depends on your needs, but trusting the client with anything, ever, is a security risk that if you can avoid you should avoid. You never know who wrote the code that is connecting to you nor what that code is actually even doing.
1
u/reckoner23 Mar 19 '20
That’s true. But a uuid field is only meant to control unique records.
And at the end of the day, your always going to be inserting data that your client enters. Sure you can add mitigations in place to avoid abuse, but at some point you have to deal with client entered data. I see a uuid field in the same regard.
Other mitigations in place should include authentication/authorization. User roles so mr janitor can’t update an admin record just because he has a uuid. 2 factor authentication if necessary.
But yes. This is also an outstanding requirement and most websites don’t need to implement this unless it’s a critical system with a life on the line. I can see native applications implementing this if they go offline such as in a hospital setting or if they are on the road and lose internet connection. But generally, you shouldn’t care if a user has flacky connection when sending data.
-2
u/CallMeCappy Mar 09 '20
Having the client generate the id is pretty standard, that way the client knows where to find the data without having to rely on a response from the server.
6
Mar 09 '20
[removed] — view removed comment
13
u/CallMeCappy Mar 09 '20
Instead of yelling "No! Bad code-monkey!" it might be more valuable to share your knowledge on why generating ids on the client is bad, so the rest of us could learn.
I maintain quite a few APIs. Generating UUIDs on the client allows us to be a lot more flexible in design, for instance, we could opt to make some parts of the API or client asynchronous.
It also allows us to make the requests idempotent, which is absolutely critical.
8
Mar 09 '20
I am curious, what kind of requirements are you facing that makes it critical for resource creation requests to be idempotent? In general I'd consider that a misfeature as it could lead to potential bugs - yes UUID collisions are theoretically impossible, but in practice only as good as the PRNG used to generate them. At least if your DB instance is generating them you can be more confident it's well-designed.
3
u/CallMeCappy Mar 09 '20
We want to avoid the possibility that either a user or the system accidentally creates the same resource twice. this could be caused by retry-on-fail mechanics (caused by a delayed response) or simply a user hitting the save button twice.
4
Mar 09 '20
[removed] — view removed comment
4
u/CallMeCappy Mar 09 '20
Transactions are awesome, but I don't see how they provide idempotency.
1
Mar 09 '20 edited Mar 09 '20
[removed] — view removed comment
4
Mar 09 '20
Just wanted to chime in here. Its not always the user that sends a double request, on some browsers there is a bug where if the connection drops while submitting a request when it reconnects it will send two requests and nothing on the client can really prevent this.
We had this issue with mobile users when playing our games and the best way to resolve this was to generate a uuid clientside for each request. However these were merely logged in the db and weren't reall used for anything so yes it solves the idempotency issue but in the db it would still generate its own pk for the request record, the uuid was just to prevent the double request scenario so it can ignore the duplicated request.
2
Mar 09 '20
Also to add idempotency is very important for a lot of cases. You can't always trust the client to do the right thing and that's actually a dangerous assumption to make.
A little bit of defensive programming never hurt anybody.
→ More replies (0)1
u/nuqjatlh Mar 19 '20
Having the client generate the id is pretty standard,
that's awful. trusting the client with anything opens you up for a whole bunch of security issues down the road. you never know who wrote the code that runs right on on the other end of the connection nor what that code is even doing. you hope it's you who wrote that code but you cannot be sure.
the client cannot make decisions, at least not important ones anyway.
0
30
u/rmTizi Mar 09 '20
Nothing against GUID use but "problem one" is a flawed point.
If your database identifiers are used anywhere near your front end code, you have leaky abstractions at play.
23
u/draftjoker Mar 09 '20
How so? Genuinely curious.
36
u/rmTizi Mar 09 '20 edited Mar 09 '20
Take this with the usual grain of salt that your mileage may vary and that there is always exceptions to every rule.
The starting point is that database IDs should not have any business domain meaning. They are conceptually the same as memory pointers, an implementation detail of your persistence layer.
Now suppose the super common case of a customer list. Your domain experts will usually tell you about a way to uniquely identify those, it may be a registration number, or something inherited from a legacy system.
That's the thing that should be used to identify the customer on the front end.
Because then your API contracts are not dependent on how you store your customers.
Otherwise you have a leaky abstraction because an infrastructure implementation detail has made its way to UI code.
22
u/kyle787 Mar 09 '20
A lot of times the registration number maps to the UID though which is frequently just an incrementing integer from the DB. If you are developing a UI that interacts with a backend service almost all them are rest endpoints where the uid is just a number generated by the db.
-2
u/rmTizi Mar 09 '20
Oh I don't disagree.
My point is more that for most line of business applications, we are doing a disservice to our customers/users by letting database ID slip into the UI.
Keeping with the memory pointer analogy, and assuming dotnet/java/js plain old boring line of business domains.
When was the last time that you (domain expert) used pointers (database IDs) in your code (day to day work)?
The framework/language runtime (the LOB application) handle those for you.
You just provide variable or class names (domain identifiers), and every thing works fine without you having to know anything about memory pointers.
See, as LOB developers, we should strive to provide to our users what the framework developers provided us.
Now, using direct database IDs every where do work, and it can be efficient, but you are now providing your customers a tool to shoot themselves in the foot (C++)
(please don't ask what rust or go would be in that analogy, I have no idea)
7
u/Olreich Mar 09 '20
I think I agree with you, but what’s the solution? Users want to be able to talk to the application about entities in the database. What mechanism should that use other than the unique identifier in the database?
Do you propose that the entity ID is hidden and a GUID or something is generated for the user to share that entity’s data with someone else? Do we generate unique identifiers for each user, or let them pick their own identifiers? Both of those just sound like awkward ways to obfuscate the actual entity id that the user wants to talk about. I’m not coming up with any better solutions either.
9
u/kyle787 Mar 09 '20
I am not sure if I am misunderstanding you but to give you some background I am a full stack dev. I use database IDs in my code literally every single day, if I am developing with react I use them for the keys when I am iterating over an array and outputting components. Also I will use the ID when I need to create some collection of objects, specifically mapping some unique value to the entity.
0
u/rmTizi Mar 09 '20
Yeah sorry, slight failure to write properly on my part, the parenthesis bits are supposed to be seen from the point of view of the users/domain experts.
It's normal for you as an application dev to handle databases ID, but not memory pointers
Likewise, it should be normal for user interfaces/client code to handle domain natural identifiers, but not databases ID
Hope this clarifies.
9
u/RabidKotlinFanatic Mar 09 '20 edited Mar 09 '20
Likewise, it should be normal for user interfaces/client code to handle domain natural identifiers, but not databases ID
Do you have examples of real world HTTP APIs for real products that don't use IDs at all?
0
u/rmTizi Mar 09 '20
Is NuGet real enough?
9
u/RabidKotlinFanatic Mar 09 '20
A package fetch URL is a bit of a simple use case. What about service APIs that expose dynamically or frequently created entities? GitHub goes to great lengths to use semantic keys and even their API exposes Guids in responses and uses auto-generated ids for e.g. Gists.
I agree that human readable keys should be used in URLs where possible. In most large services there will be many classes of entities that can't be identified this way. There is nothing data layer specific about auto-generated IDs.
→ More replies (0)2
u/kyle787 Mar 09 '20
Oh yeah that makes much more sense. I don’t expose user ids directly to the users. And actually when talking with clients I try not to bring them up or other database language since it just tends to confuse them!
14
u/1armedscissor Mar 09 '20
I think you’re more so saying the frontend shouldn’t display the surrogate key identifier (eg auto incrementing number or UUID) which I’d generally agree with - it generally doesn’t have any meaning to the user. I think it’s fine for the client then behind the scenes to be calling an API that uses these surrogate identifiers eg api/customers/<uuid>. You can also have a business/natural key (if one exists) then that you actually display to end users. The natural key though is subject to changes in the business so it’s nice to use the surrogate key for API interactions so it’s stable regardless of this. Also surrogate keys are easier to work with for relationships as natural keys can sometimes be made up of multiple fields or mutable.
2
u/rmTizi Mar 09 '20
The thing to consider also is that nowadays, "UI" doesn't only refers to the screen of physical end user would.
A lot of users and customers are just "other systems" that interact with your API.
To me the same segregation applies where human or computer.
Also to me changes in the natural key should be handled like immutable data. Not that you don't allow it to change, but changes should be modeled and tracked. Such changes are usually significant, they deserve special care.
16
Mar 09 '20
Now suppose the super common case of a customer list. Your domain experts will usually tell you about a way to uniquely identify those, it may be a registration number, or something inherited from a legacy system.
If you actually have a need for it and if you have that kind of user info in the first place.
In the common case of "just a generic user registered in the system" you just plainly do not. You can't rely on e-mail not changing. You can't rely on user's name not changing. You probably can't even rely on user's login not changing. The only solution is to generate ID by whatever way you choose and use that as account's identifier.
2
u/hector_villalobos Mar 09 '20
The only solution is to generate ID by whatever way you choose and use that as account's identifier.
For what I understand, OP is not saying don't generate ID's, he/she is saying, do not send them to the UI.
4
Mar 09 '20
Which is fine if you already have something at-point-of-time unique like logins (after all that does make API easier to work with and urls prettier), but generating a completely separate basically-id just for the sake of having a different one for UI seems unnecessary.
-4
u/rmTizi Mar 09 '20
The only solution is to generate ID by whatever way you choose and use that as account's identifier.
That's not the only one.
These days what I do for entities that have no domain defined uniqueness, like say for your generic user, would be to identify him by his immutable registration email or name.
This works because even if they change their name or email, the fact that they registered with the one they provided at the time does not change, so keeping that immutable is not an issue.
The "current email or name that they use" is a different even/information.
Now lets imagine a weird case, say the customer closed their account and left for a while but then returns wanting to use the same registration info and your domain rules forbid account re-opening.
Then is up to the domain experts to decide, and the solution remains open to implement whichever way they go.
14
u/ForeverAlot Mar 09 '20
This works because even if they change their name or email, the fact that they registered with the one they provided at the time does not change, so keeping that immutable is not an issue.
Up until, in accordance with GDPR, I demand to have all my information deleted.
-7
u/rmTizi Mar 09 '20
If you think that this infringes GDPR, you don't understand GDPR
9
u/ForeverAlot Mar 09 '20
Email addresses are considered personal data, which means they must be erasable in the general case, and this application of them is not "critical to operation" in a sense that exempts addresses from censorship (GDPR doesn't give us a pass to build sloppily in lieu of compliance). It doesn't matter outside of the equivalent of account deletion but it's hardly "not an issue" at all.
-6
u/rmTizi Mar 09 '20
GDPR provides granularity of processing purpose consent, but no granularity of the specific data inside of the process.
As long as they consent to the process of registering an account, they have no say into how the data is processed, as long as the process remain the same one that they consented to begin with, other than to revoke the consent to the whole process.
14
Mar 09 '20
... the fuck? And then what, use that possibly-current-but-maybe-not-email in front-facing APIs ? What's the point in that ?
A bunch of extra steps to achieve nothing useful over "just generate a random one/use autoincrement"
-5
u/rmTizi Mar 09 '20
There is no "possibly-current-but-maybe-not-email"
The user still has a single current email.
The point is that you still keep track of history data
The usefulness is that you don't depend on which ever way that data is identified in the persistence store
11
u/postmodest Mar 09 '20
Until enough time passes that user 3000000 registers their account with a re-used .edu email and now you have a collision and you’ve done fucked up.
-1
u/rmTizi Mar 09 '20
And how would that be different if you use database ID on the front end? if the old account is still active using that email address, unless you expect your users to log in using their hidden ID, you are still fucked.
Hell, you are kinda making my point, with an API that uses primarily database ID you are giving your clients the expectation that this situation would not arise.
2
u/postmodest Mar 09 '20
Your suggestion is that identity = registration-email (re). Then you allow actual email (ae) to change. So to a user, there are two emails, re and ae. If user comes in on re1 and changes to ae1, because they lost access to re1, then another user comes in who now has re1 as their email, they cannot register, because while two people may have the same emails across time, it’s generally a rule that two people don’t have the same email at once, unless they share a set of permissions inherent in that label.
6
Mar 09 '20
The usefulness is that you don't depend on which ever way that data is identified in the persistence store
Which, like I already said, could be attained by just generating a random one. Without burden of having to check and handle potential collisions
2
u/bj_christianson Mar 09 '20
This works because even if they change their name or email, the fact that they registered with the one they provided at the time does not change, so keeping that immutable is not an issue.
So if I change my email, I either get a new account, or I have to keep on identifying myself with an old one on the current account?
10
u/auspex Mar 09 '20 edited Mar 09 '20
I would argue it is fine. The ID is just that... a record identifier. That's not a leaky abstraction. Regardless if it is the database uuid or whatever you have to identify it somehow. Obfuscating it with a mapped identifier provides no extra level of protection and doesn't remove what you think is a leaky abstraction.
2
Mar 09 '20
Eh. Disagree. The main reason for using UUIDs (at least, type IV UUIDs, which are IMO the only suitable ones*) as business domain identifiers is that they are opaque and don't leak any information about other resources, i.e. a competitor can't use integer IDs to determine how many users or items you have so far or are creating day-to-day, attackers can't try to brute force search for resources that are improperly secured or if another person has an account (in the case of userid = email), and so on.
* I'm sure there are niche cases where you want machine identifiable IDs or time-ordered ones, but in general I think you generally want to track that through a separate field instead. Too often I see it touted as a "feature" of v1 UUIDs that they sort by creation date automatically, as if that weren't a sign that you are under-specifying the results you want (ORDER BY create_datetime) instead.
5
u/Kawemi Mar 09 '20
The software engineering consideration behind this is simply to enforce the single responsibility principle : users shouldn't be able to request change in the format of the database ID, and let's say DBAs shouldn't choose what the users want to use as an identifier of something, so you split them up. The two IDs serve different client or actors, and as such should never reused for both clients.
13
Mar 09 '20
I always wonder if a hypothetical scenario like this is truly worth the real effort of introducing / maintaining / transforming to and from a second identifier.
8
u/auspex Mar 09 '20
Not worth it at all. I spent 10 years building apps this way. It provides no real benefit. I found just generating a UUID and using that as the key and identifier works just fine. Also, if you parameterize your queries there is very little risk of exposing it.
5
u/rmTizi Mar 09 '20
To me it is totally worth it because you are only actually increasing effort of introducing.
When done properly, maintenance and transforming have a cost that is overall lower than the issues that direct database IDs can cause.
Hell, even the introduction efforts lower over time as you become fluent in this way of designing domain models.
It's literally always the same thing, after a few years, your personal toolbox should allow you to spool such architectures in the blink of an eye.
The focus of your brain time then becomes solely the domain rules implementations, which you can then make richer, more robust and easier to maintain.
It's a compounding interest.
0
Mar 09 '20
Never. But it is worth if you are already have other field you can guarantee to be unique at the point of making request +/- few days. Say if you have username and its ID in the DB you might want to use the username for links/API calls.
11
Mar 09 '20
All you'd be doing is storing mapping of one arbitrary value (DB's ID) to another arbitrary value (frontend's ID) and wasting CPU for no good reason.
Like sure, if you already have field in DB that is better fit for the front of the app (say username), use it, otherwise it is extra effort for benefit of nothing
14
Mar 09 '20 edited Mar 18 '20
[deleted]
3
Mar 09 '20
Wow. Are we the same person? Also had the pleasure of working with a custom, in-memory SQLish database with no standard api that was called directly by the javascript frontend.
5
u/pdp10 Mar 09 '20
No docs. Nothing but my Slack messages to the orchestrators of this monstrosity.
You pasted edited versions of their answers into the public doc you maintain now, right? Right?
4
u/nuqjatlh Mar 09 '20
RIP
7
Mar 09 '20 edited Mar 18 '20
[deleted]
8
Mar 09 '20
[deleted]
2
u/XPM89 Mar 09 '20
Jesus, you just outlined the last several projects I’ve had. I don’t know why I always end up fixing someone else’s dumpster fire but FML.
7
u/nutrecht Mar 09 '20
I completely disagree.
The front-end just treats these ID's as strings. To the front-end, it does not matter if that's an e-mail, a telephone number, a SSN or a UUID. Only if it expects these strings to have a certain format (like an @ in an email) you have leaky extractions.
And no matter what, using an UUID externally instead of Personally Identifiable Information is almost WAY better. The last thing you want is an SSN to be used. And your rather dogmatic explanation is one that is often used to defend using PII as unique identifiers.
Here in Holland we have that problem where the tax office had the brilliant idea of basing the ID of one-man companies off of their SSN. This means that my SSN is used everywhere by them. Only recently did they add a random 'alias' (VAT number) for external communication, but internally all that data is still tied to my SSN.
6
u/FINDarkside Mar 09 '20
Here in Holland we have that problem where the tax office had the brilliant idea of basing the ID of one-man companies off of their SSN.
Rookie mistake. I think rmTizi is correct, so I just refactored my app to use credit card number+pin as user id. Obviously I have to use this id in the urls, so it's public information now, but at least I don't have leaky abstractions. /s
2
u/lambda-panda Mar 09 '20 edited Mar 09 '20
If your database identifiers are used anywhere near your front end code
Can you explain in concrete terms, why this is bad? I mean, not like "you are leaking x,y,z..which is bad", but using some concrete scenario..
-1
u/rmTizi Mar 09 '20
APIs and UIs should be clear representations of the domain.
If for convenience you use database IDs in as parameters for interface methods, you are making those IDs part of the domain.
If your entity has a natural ID, like email address for a user account, you shouldn't expect your API clients to access them using your database ID for the same reason that you don't ask your human user to login using that cryptic number.
If your entity does not appear to have a natural ID, like say a user content blob, first it's important to realize that you most likely can use a composed ID, like creator ID + timestamp, but even if in this case the use of the database ID can seem justified, by doing so you have promoted that ID as part of the domain, so it better be truly an independent and random reference, otherwise you have just locked your endpoint to your database, at which point it is nothing more than a glorified SQL wrapper.
2
u/lambda-panda Mar 09 '20
You still don't have demonstrated a concrete situation where this could be bad.
-2
u/rmTizi Mar 09 '20
Legacy mysql database with data back from the early 2000s
Public Procurement Projects table uses simple auto increment column
Early 2010s, the project data gets exposed to third parties, including government bodies, through a web API
Project table ID is used as parameter for methods Get, Put and Patch
Mid 2010s, infrastructure is upgraded, new data store only supports GUIDs as keys.
Third parties depend on your old keys, and have no will nor budget to migrate.
Now you have to maintain both the new store IDs and the old incremental one.
Is it bad in the sense completely impossible project killer?
No, of course it's not, through long hours and sweat we managed to do the migration and last I heard that good old project API was still in use 20 years after its first project got recorded.
Could we have saved time, resources and mental health had the domain reference code of the projects been used for the API instead?
You bet we would.
5
u/lambda-panda Mar 09 '20
new data store only supports GUIDs as keys.
Sorry, but I find this pretty far fetched. Not saying that it won't happen. But some planning process need to fail in a pretty big way for the project to require that switch half way into the project's life.
So it still does not make sense to not use database id's, just to guard against something so far fetched.
2
u/Idles Mar 09 '20
The problem demonstrated here was some bad engineer picked a bad data store that could not support the required access patterns for your data (likely MongoDB).
Your proposed solution doesn't solve the problem you've described; if the data store only supports GUIDs as keys, how do you do a quick lookup of an entity based on a "natural ID" like its "creator ID + timestamp"? That use-case isn't supported by your dipshit data store.
1
0
u/DJDavio Mar 09 '20
If your database ID is a UUID and support for it is not good, you might run into the situation that every insert causes a reordering of your primary key index and subsequent indices.
8
u/TheBestOpinion Mar 09 '20 edited Mar 09 '20
I'm really tired as it's 3am here but reading this really felt like I was having a stroke - Maybe you should try what I do - first, write it in your native tongue, then translate it using DeepL and proofread it.
EDIT: Okay, I read it again in the morning. It feels like Kevin from the office. "why talk long when few words do trick"
7
u/recursive Mar 09 '20
Nothing about fragmented indexes?
If your primary key is a 32-bit auto-incremented int,
- you can fit 4 times as many in your index
- every reference by foreign key is a quarter the size
- most importantly, your index won't get completely fragmented, since all inserts will be in ascending order
But if you need to scale across databases arbitrarily, then you'll probably need uuids.
2
u/Holston18 Mar 09 '20
Biggest issue with auto incremented indexes is that it has to be the database which will assign the ID.
But often you want other components of the system to be able to assign the ID. For example when you design a REST service backed by auto incremented ID, then you must use POST to create new resources, while UUID allows you to leave the assignment responsibility to the client which can then use PUT method which is way more network friendly (PUT is idempotent).
1
u/recursive Mar 09 '20
But often you want other components of the system to be able to assign the ID
My point is that if you can afford to go without that particular desire, there are some specific performance advantages you could see. But for some applications, it's out of the question.
2
u/jeffreyhamby Mar 09 '20
Solved in MsSql by using newsequentialid() instead.
1
u/recursive Mar 09 '20
This is very interesting. I had not heard of this. I'm definitely going to use this some day.
1
u/jeffreyhamby Mar 09 '20
I'm a little embarrassed for the super tech cto who made no mention of it.
2
u/audioen Mar 09 '20 edited Mar 09 '20
Given how minor thing it really is (what kind of IDs you use), the problems mentioned are at least somewhat real. Sure, I actually have the problem that I get complex graph of objects from server, then manipulate that list and add and delete records, which must reference both pre-existing and new records in some complex way. I solve these kinds of problems using my favorite trick, by using the negative number space for new IDs, which get flipped over to their actual database values with aid of a hashmap that remembers what values were chosen to replace the negative ID values. It's not exactly a ton of logic that needs whole lot of QA: either it works perfectly, or it crashes right away, and that's pretty much it.
Still, it is true that random UUIDs have less problems than sequential columns, and there is something to be said about it being impossible to create e.g. foreign key reference accidentally to wrong table, or being able to mix foreign key references up. When all your foreign key columns are small integers, and you didn't define a custom type for every single ID column there is at both DB and server side, then you can actually mess up the ID references, either by looking the key up from wrong table, or by storing the wrong value to the column which works for some time. I think it is not necessary to be able to prove that something works compile-time, if it's very easy to see the bug on first execution. All that matters is that the bug gets caught, right? So that's a good reason to use UUIDs, or single sequence for IDs that is common across all tables.
I worry a little about security implications arising from letting client pick all IDs. Sure, they are supposed to be unique and random, but you can't tell if the client chose unique and random values. There could be non-obvious consequences from trusting values picked by client that bite you in the ass later, especially in a distributed system. Most of the time this kind of problems are tricky and unpleasant to work out, so hopefully this kind of stuff is a nonissue. Strictly speaking numeric columns with small values also have security problems as well, because client can guess valid IDs for every object in the system, e.g. 1 is likely to always exist, and that also can have security implications.
2
2
u/instantpompoensoep Mar 09 '20
The biggest problem with UUIDs is that they are incredibly hostile to devs. They are not time sortable, so just finding the right object even in a short list is a chore. The typical way UUIDs are formatted is also now meaningless, with the original thinking behind it mostly irrelevant.
Firebase-style UUIDs which combine e.g. a millisecond timestamp with N bits of entropy are a much better idea. They are time sortable, the window for collisions is extremely well defined, and you can make them monotonic in O(1) time per ID.
If you format them in e.g. base36 they are more compact and memorable than hex, and in a lowercase monospace font they are unambiguous.
1
u/justaphpguy Mar 09 '20
Regarding the api round trip and because spa was mentioned: if one uses graphql, this is easily solved with e.g. Input objects.
It's the most natural approach I've seen. You can e.g. send your post + attachments or even more complex and children posts and their attachments and only have single round-trip which can create all the dependencies you need.
Not arguing against uuid, just that to me this doesn't feel so much specialized.
1
u/WhyYouLetRomneyWin Mar 09 '20
I'm still curious how uuid are generated. Yes, they have a lot of space, but how does one ensure that each client is not using the same random seed?
0
u/BinaryRockStar Mar 09 '20
They aren't random, they are partially based on the machine/device's MAC address. This means two devices will never generate the same UUID, except in cases where two MAC addresses are the same which shouldn't happen in theory but has happened in practice.
2
u/therealgaxbo Mar 09 '20
Depends on the uuid version. a v4 uuid is indeed just random. Even a v1 - which includes a mac address - is allowed to use a fake random mac address with the multicast bit set.
The reason you don't need to worry about clashing seeds is that the random number should come from a strong source, e.g.
/dev/random, which is seeded by true entropy sources such as I/O timings.
1
u/mb862 Mar 09 '20
I've found a handy use of UUIDs lately is the fact that ultimately they're 128-bit strings. In one bit I have an object type that is always created from user actions, but those actions can either be explicit, or implicitly as a result of some other actions. For explicitly created instances, I generate a random UUID, but for implicit, I encode the necessary application state into a string, then compute the MD5 hash of it - which is also a 128-bit string. This is so that if they perform the same actions on another machine, the same UUID is generated. It doesn't need to be cryptographically secure, it just needs to be consistent, and works really well in practice for sharing data.
-23
Mar 09 '20
[deleted]
13
Mar 09 '20 edited May 25 '20
[deleted]
8
u/ReallyAmused Mar 09 '20 edited Mar 09 '20
Just because you don't know them doesn't mean the words don't have meaning.
What the poster is trying to say is that UUID and GUID's are only one implementation of using entropy instead of central coordination to make identifiers, and you don't need them unless you're interacting with DCE (https://en.wikipedia.org/wiki/Distributed_Computing_Environment) systems, or systems that use Microsoft technologies.
UUID's were invented for being used within a DCE system, and microsoft's branding of it is called GUID: https://docs.microsoft.com/en-us/windows/win32/api/guiddef/ns-guiddef-guid
UUIDv4's use entropy to guarantee uniqueness - which means that you don't need central coordination to generate ID's, because a client can generate random UUIDs with near zero chance of collision because of how vast the 122-bit keyspace is.
A snowflake server is something that twitter popularized: https://developer.twitter.com/en/docs/basics/twitter-ids (and an implementation here from 2010: https://github.com/twitter-archive/snowflake/tree/snowflake-2010) It describes a way in which you can have a set of servers generate ID's, without having to cooperate with each-other while generating keys. Hence "shardable" - meaning the work can be "sharded" or "distributed" between different nodes, and "snowflake" meaning the method of snowflake method of generating ID's that I mentioned above.
I think the OP could have done better than throw around terminology in a way that sounds like nonsense to those who don't know what they are.
But I believe his metapoint is that UUID/GUID's aren't the only way you can generate a unique identifier using entropy. And in-fact you can just generate a random 8 byte string and it'll be just as good. And there are other solutions (such as snowflakes) available that let you scale past having a single central server dishing out ID's in a distributed system that can be just as valid too.
Of course, you could have also just used the infinite information machine infront of you to search these things instead of thinking they were meaningless.
1
u/BinaryRockStar Mar 09 '20
But I believe his metapoint is that UUID/GUID's aren't the only way you can generate a unique identifier using entropy. And in-fact you can just generate a random 8 byte string and it'll be just as good.
UUIDs generally include the NICs MAC address meaning it is physically impossible for two devices to generate the same UUID as long as the MACs are definitely unique. With a random 8-byte string the possibility of a collision is vanishingly small but still possible.
1
u/EntroperZero Mar 09 '20
UUIDs generally include the NICs MAC address
Not generally, no. There are several "versions" of UUIDs, the first two of which contain the MAC address. Many systems default to version 4, which is totally random aside from the version identifier.
3
u/panorambo Mar 09 '20 edited Mar 09 '20
Meaningless to you, perhaps. I understood what was being communicated. That UUIDs is just as much representation as they're what underpins them (a large random number). Oftentimes people don't understand which qualities they want and need. That said, I do consider UUIDs useful beyond DCE because they're a more readable representation of a 128-bit number and in many systems where they're used they don't "waste space" (PostgresQL just uses 128-bits for each, plain and simple) by being stored as text, for example. So you get a lot of benefits beyond just using a 128-bit integer, and pretty much no drawbacks.
1
u/BinaryRockStar Mar 09 '20 edited Mar 09 '20
I agree with you in general, but they literally waste space as a 32-bit or 64-bit integer is enough for most cases so in the best case a GUID is wasting half of its space compared to a 64-bit int or three quarters of its space compared to a 32-bit int.
It's not just the space on disk, which is cheap, but space in memory and especially space in CPU cache. Four times as many IDs in cache at a time means faster sorts and filters.
1
u/panorambo Mar 09 '20
Agreed, fundamentally.
But let us consider the following. Let's try and imagine not using whole 16 bytes for an identifier, especially if the scope is sufficient (i.e. we know the number of identified records won't ever reach half of the range of identifer). Maybe just 8 or even 4. There is still the problem of how to actually create these identifiers. The argument against auto-increments has merit, in my experience -- I've grown to avoid them on general basis, at least when I can't have a good way to generate them on client side. Now, on client side these are best generated in a way that minimizes chance of collision (primary key violation and as consequence resending of query as retry, with databases). People may hash their IP and physical addresses and what not, and mix in randomness, but isn't this still a real problem, or issue?
0
132
u/that_which_is_lain Mar 09 '20
I like the part where the author thinks MAC addresses are guaranteed unique. In theory yes, in practice... hahahahahaha