1

This question already has an answer here:

I am considering a new scheme for order numbers for our ERP system. For reasons I'd like not to get into, the number must be fairly easy to remember and must say something about the time (or at least sequential order) the order was placed. This eliminates things like UUIDs as an option, since those are both very hard to remember and lack any time information.

Another constraint is that I'd like the scheme to be able to handle multiple users generating numbers without any collisions. This can be done with something like a ticket server (which is plan B if this fails). This is where UUIDs would be perfect, if they met the other criteria.

I'm looking for a balance between minimizing the likelihood of collisions and the ease of remembering the number. This sounds impossible, but our business is small and these collisions would be very unlikely to happen even if the ID were a simple timestamp.

One idea was to essentially generate a number that represented a timestamp down to the current second, and append another few random digits to significantly decrease the chances of a collision. The more digits I add, the lower the probability of a collision, but the angrier my coworkers would be at me.

Is this even in the ballpark of sane? This seems like a problem others have run into and I'm curious to know how they solved it.

marked as duplicate by gnat, Blrfl, Bart van Ingen Schenau, BobDalgleish, Robert Harvey Jul 24 at 2:52

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

  • Is this not the right place to ask such a question? – Hassan Jul 19 at 22:21
  • 1
    I don't see a distributed generation requirement. Why wouldn't a simple counter work? You can add a timestamp. – candied_orange Jul 20 at 0:25
  • Oh sorry I wasn't clear. That is a requirement. I would use UUIDs if I could but those aren't easy to remember and aren't remotely sequential, which is why I can't use them. – Hassan Jul 20 at 3:26
3

Since you say distributed generation is a requirement I'm going to argue for UUID. version 1.

the number must be fairly easy to remember and must say something about the time (or at least sequential order) the order was placed. This eliminates things like UUIDs as an option, since those are both very hard to remember and lack any time information.

UUID Version 1 has time information. It also has what you call

another few random digits to significantly decrease the chances of a collision.

I think we can do better than simple random here. Being unpredictable isn't a requirement. Being unique is. A unique location ID takes away any chance that another site in your distributed system collides with this one simply because they aren't communicating. If your system is on a network you already have a unique location ID in the form of a MAC address.

That leaves issues with time. Time is not a simple thing. Nothing measures it perfectly.

To resolve this what I think you need is the Clock Sequence (p8). In UUID v1 this is a 14-bit unsigned integer that is incremented or randomized whenever something goes wrong with the clock. When that happens you essentially get a "new clock" or at least a new ID for one. This prevents the resetting of the system clock from causing collisions. Every reset is a new clock.

You might be thinking UUIDs must be presented in a form that looks like this:

f81d4fae-7dec-11d0-a765-00a0c91e6bf6
ietf.org - rfc4122

Which is hardly memorable. But it could be presented like this:

enter image description here
realityripple.com - UUID Decoder

Which is far more human readable. If that's not enough you could sacrifice robustness and scale down the MAC address and sequence number to make them more human readable. This takes you away from the UUID specification but you understand your system far better than the UUID people did so you can do things like name your distributed locations after fruit.

As for your sequential requirement understand that the clock itself puts an ordering to these. One that would require adjustment when distributed clocks aren't synchronized. That will be an issue in any distributed system that doesn't communicate to synchronize. You can make the system synchronize the clocks or do it after the fact. "Yeah Apple is 5 minutes faster than Banna".

You can also adjust the precision of the clock if you'll give up the bits needed to record to the second, millisecond, or nanosecond. Whatever precision you set determines how often you can issue an ID.

Or you can simply increment a counter field when issuing more than one ID each second. That only works when you don't care about ordering within a second across distributed systems. If you do, and want to stick with seconds, your only choice is to delay issuing the ID until it has its own second to be issued in.

There is no level of clock precision that will prevent two sites from issuing IDs with the same time, or with the same random. If this is a problem and order is important you may as well reach for more clock precision rather than more random. But as you reach into the nanosecond range there starts to be little difference between them.

This can be trimmed down to be more memorable if your requirements allow. Maybe you don't need them to memorize the date in the time stamp because these numbers are only outstanding for one day. Maybe the distributed systems communicate so they can simply count up unique numbers even as they are issued remotely.

However you do it, I think studying how UUID solves this problem in the general case will at least point you to a reasonable design that solves your specific case.

1

Combine whatever information you need with a randomly generated number.

So your ID could look like this: John-Doe-2019-07-20-13:24-XUgve2wQ

If you include a timestamp, this is both readable and highly likely to be unique.

1
  • Build a table with 3 to 5 letter nouns that mean something (pear, dog, horse, brass, et cetera).
  • Segment them, so you can assign different parts to different users who are to generate ids. The meaning of the words is irrelevant, just make sure you have more pools to pick from. Segment randomly.
  • When you generate an id, pick a random word from your pool and append 1907201 for today's first id (generated by that particular user). Use 1907202 as a postfix for the next (which will likely have a different noun prefix).

The generator will have to keep state for one day, it must keep track of the number of ids issued that day. Any id will carry the day it was issued. Words are relatively easy to remember, so are dates. Then there is just a short number to remember in addition to the word and the date. Like shoe1907206. You will have a way to partly reconstruct it from context information yet it will be practically impossible to guess existing ids because of the number of words in a pool.

1

Is this even in the ballpark of sane?

Nope, not even remotely close to sane.

What kills it is the "fairly easy to remember" requirement. A number stops being easy to remember at 5 or 6 digits, which is simply not realistic for an order ID, and completely impossible given your other requirements.

Personally, I would strongly question the "easy to remember" requirement because if you have any kind of business process that relies on people remembering an order ID, that sounds like a recipe for disaster - people will misremember and enter a wrong ID. If you really cannot avoid it, you absolutely need some kind of builtin checksum.

In any case, if you still want the IDs to be short, forget about random generation, use your plan B: a central server assigning sequential IDs.

  • Haha I knew I'd get this answer. You're preaching to the choir. As I implied in my question, that is not up to me unfortunately. – Hassan Jul 20 at 17:55
1

You could use a flake, a "decentralized k-ordered unique ID generator". Flakes are

  • unique identifiers
  • generated without any coordination between machines
  • roughly time ordered.

Flakes don't directly give you "easy to remember", but I imagine it would not be terribly hard to map them into something easier to remember - a table of 10^2 adjectives and 10^2 nouns reduces a numbers's length by 2 + 2 = 4 already (assuming base10).

Not the answer you're looking for? Browse other questions tagged or ask your own question.