<turbo-stream action="append" target="posts_list"><template>    <div class="postbit" id="370011" data-post-id="370011">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="jswanner" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/jswanner/120/24585_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  jswanner
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="garrison" data-post="10" data-topic="71724">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/letter_avatar_proxy/v4/letter/g/3bc359/48.png" class="avatar"> garrison:</div>
<blockquote>
<p>It’s fine to use them as DOM ids, but apparently it means you have to escape CSS selectors because they can’t start with numbers. I can see how that would be annoying, but in practice you rarely scope CSS to ids. Maybe for a weird case where you are using <code>querySelector()</code> with an id selector. I’ve never run into this before, personally.</p>
</blockquote>
</aside>
<p>You’re right, as of HTML 5 the specification of the <code>id</code> attribute has been loosened: must be unique, must contain at least one character, and it cannot contain any spaces. With HTML 5, it is only <em>recommended</em> that the values of the <code>id</code> attribute be a valid CSS identifier (therefore should not start with a number).</p>
<p>Prior to HTML 5, <a href="https://www.w3.org/TR/REC-html40/types.html#type-name" rel="noopener nofollow ugc"><code>id</code> and <code>name</code> attributes needed to start with a letter</a> and I guess I have internalized that old rule</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="370011" data-batch-url="/posts/batch_likers">
                        2
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/excuid2-elixir-implementation-of-cuid2-collision-resistant-unique-identifiers/71724/12">Post #11</a>
	                </div>
	            </div>
              <div id="likers-container-370011" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="370011"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #11"></div>
  </section>
</div>
    <div class="postbit" id="370065" data-post-id="370065">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="juliolinarez" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/juliolinarez/120/28395_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  juliolinarez
                    <span class="op-star" title="Thread Starter">
                      <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                    </span>
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>I just published a new version. I fixed the problem with the Agent’s global state. I also introduced performance improvements. The counter now uses <code>Process.put</code> , which is local to the process’s memory. Additionally, the way of choosing the prefix is now uniform and cryptographically secure.</p>
<p>I learned and reviewed some concepts that I had forgotten from university. Module bias. <img src="https://forum.elixirforum.com/images/emoji/apple/grinning_face.png?v=15" title=":grinning_face:" class="emoji" alt=":grinning_face:" loading="lazy" width="20" height="20"></p>
<p><a href="https://github.com/juliolinarez/ex_cuid2/commit/e598c54695d8d624e3eeac1965bf46a0bf04a19e" class="onebox" target="_blank" rel="noopener nofollow ugc">https://github.com/juliolinarez/ex_cuid2/commit/e598c54695d8d624e3eeac1965bf46a0bf04a19e</a></p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="370065" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/excuid2-elixir-implementation-of-cuid2-collision-resistant-unique-identifiers/71724/13">Post #12</a>
	                </div>
	            </div>
              <div id="likers-container-370065" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="370065"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #12"></div>
  </section>
</div>
    <div class="postbit" id="380784" data-post-id="380784">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="jvantuyl" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/jvantuyl/120/26664_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  jvantuyl
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p><strong>TL;DR:  CUID is designed for a specific kind of solution to problems you may have never had yet.</strong></p>
<p>I know I’m dropping in a bit after the fact, but I didn’t see anyone directly address your questions about the weird vibes given off by the CUID spec.  It turns out that the short attention spans and pervasive mediocrity of our field makes it reasonably likely that you wouldn’t have been in a situation where you would need this.</p>
<p>The stilted ranting of the CUID spec doesn’t help, for sure.  They do a terrible job explaining what they mean.  Then again, once you’ve learned how to solve certain problems, it sometimes becomes very difficult to even discuss it with people who haven’t already learned what you know.</p>
<p>That’s essentially what’s going on with the CUIDv2 spec and its arguments.  It turns out that all of their reasoning is sound, but won’t make any sense unless you are writing your application a certain way.  And they can no longer conceive of building things any other way.</p>
<p>There are particular assumptions that you find in Phoenix and most MVC-esque frameworks.  You typically find them in most HTTP APIs as well.  Why that is the case involves… well… a lot of history.</p>
<p>Allow me, if you will, to take you on a <em>strange</em> journey.  (Apologies.  This will be <em><strong>long</strong></em>.)</p>
<h2><a name="p-380784-a-history-lesson-1" class="anchor" href="#p-380784-a-history-lesson-1" aria-label="Heading link" rel="nofollow"></a>A History Lesson</h2>
<p>Note that I didn’t say <em><strong>REST</strong></em> APIs.  That’s important.  What you’re probably used to doing is writing a REST-like (or RESTish?) APIs.  Basically, JSON-over-HTTP with a few conventions about methods and maybe status codes.  There’s nothing wrong with this.  It’s works just fine for 98% of projects.</p>
<p>It turns out that these “conventions” are not at all what REST was originally concerned with.  It often surprises people to discover that REST as originally defined is not really the blueprint for making APIs we struggle with today.  It was really more of the distillation of the wisdom that came out of designing HTTP itself.</p>
<p>HTTP was born trying to solve a problem that has sometimes been referred to as “anarchic scalability”.  Basically, how to build apps and APIs in a world where everything is moving fast and nobody can claim to have absolute authority to dictate how it works.</p>
<p>Out of this, he created this idea of “Hypertext As The Engine Of Application State”—usually referred to by the world’s worst acronym: HATEOAS.  REST was a set of principles that grew and blossomed as HTTP was first designed and implemented.</p>
<p>This version of REST has been largely lost in modern API discourse.  It’s actually pretty fascinating and well worth learning.  You can read the original paper <a href="https://roy.gbiv.com/pubs/dissertation/top.htm" rel="noopener nofollow ugc">here</a>.</p>
<p>That’s only half of the story, though.  The gory details of how it got lost to history are a whole tale of their own.  If you really care, you can read more about it <a href="https://twobithistory.org/2020/06/28/rest.html" rel="noopener nofollow ugc">here</a>.</p>
<p>(You see this a lot, actually.  It’s pretty common.  For example, Object Oriented Programming as conceived by Alan Kay is very different than what people have turned it into.  Ironically, his version of OOP is closer to Elixir than C++.  Though maybe that’s not so surprising because Erlang had strong influence from Smalltalk.  But, I digress…)</p>
<p>If you dig into the original REST paper, you’re going to find out that it hardly even mentions most of the things you think of as REST.</p>
<h2><a name="p-380784-some-modern-assumptions-2" class="anchor" href="#p-380784-some-modern-assumptions-2" aria-label="Heading link" rel="nofollow"></a>Some “Modern” Assumptions</h2>
<p>Coming back to the problem at hand, consider the following assumptions you probably have about how to design an HTTP API:</p>
<ul>
<li>IDs are generated on (and arbitrated by) the server (probably the database itself).</li>
<li>You’re probably going to have to strap some sort of idempotency keys onto your API to make it resilient in the face of transport failures.</li>
<li>Retry and recovery logic may end up being fiendishly complex.</li>
<li>Caching is only for browsers.  APIs use <code>Cache-Control: no-cache</code> liberally.</li>
<li>Creation requests should only use the <code>POST</code> method.</li>
<li>Only update requests will use the <code>PUT</code> method.</li>
</ul>
<p>As it turns out, these assumptions (regardless of how common they are) create problems that don’t need to exist.  They are largely ignorant of the benefits or a more classically RESTful approach.</p>
<p>Commonly we end up using HTTP verbs in ways that not only make things ambiguous, they often end up using these methods in ways that clearly conflict with how they’re defined to be used in the HTTP spec.</p>
<p>In doing so, we make applications less reliable, less predictable, more complex, and harder to scale.  It doesn’t have to be this way.</p>
<p><strong>CUID v1 and v2 are designed to provide a minor but very important missing piece of an approach that entirely avoids creating <span class="bbcode-u">any</span> of these problems.</strong></p>
<h2><a name="p-380784-feel-my-pain-3" class="anchor" href="#p-380784-feel-my-pain-3" aria-label="Heading link" rel="nofollow"></a>Feel My Pain</h2>
<p>Anyone with much experience almost certainly has trauma here.  There’s this story that repeats itself every new startup you work for.  Every time you try to avoid it.  But, like the Classical Greek story of Cassandra, you tragically can only predict the crisis, but never avert it.</p>
<p>It starts when you try to ask for a little forethought before designing an API.  There’s a kind of “get it done” personality that insists that “Do it the ‘normal’ way.  Everything is fine.  There are no decisions to make.  Something something Best Practices.  Everybody knows this is settled.”  Their tragic lack of imagination and woeful inability for introspection thoroughly suppress any chance for innovation and will doom us all.</p>
<p>They’ll immediately roll their eyes when you suggest “This isn’t really that RESTful, maybe we should take a second to actually define some terms.  How about we actually design something for a minute?”  They shriek “Big Up-Front Design BAD!  That’s not agile!”</p>
<p>They insist that REST == CRUD and dismiss any attempt at deeper understanding as “bike-shedding”.  Their assumptions are rapidly baked into the codebase.  For a time, it seems like it will be fine.  They crank out code at a prodigious rate.  The KPIs look good.</p>
<p>Then… things break.  Who knew the network isn’t perfect?  What do you mean it succeeded but we didn’t get the response?  Somehow the find the idea to naively implement retries lurking somewhere within their smooth brains.</p>
<p>Oops, now we’re sometimes doing creation or updates <em><strong>twice</strong></em>.  Then they’ll generate massive amounts of “defensive programming” code in clients.  They’ll generate this web of custom code for each request just so clients can figure out the ID of whatever they may or may not have created.</p>
<p>Invariably their confused and befuddled retry logic will start hammering other services into the ground retrying in tight loops.  Here they begin excitedly rambling about circuit breakers and exponential backoff and rate limiting because they heard about it on YouTube or at the coding bootcamp they went to.</p>
<p>They’ll e-mail the team blog posts about a million half-measures.  Many of them don’t even fit the problem.</p>
<p>Meanwhile, the SREs are becoming just as restless as your app is RESTless.  Just ignore the fact that your dashboards are full of errors that aren’t errors and the useful signals lost in “normal” bursts of errors-that-aren’t-really-errors.  Who needs actually meaningful error metrics?</p>
<p>Is this monstrosity generating tons of inconsistent or even incorrect data?  We can manually clean up any junk that gets left behind in the melee.  What’s a little toil between friends?  The SREs now begin to exhibit the “500 yard stare” in Zoom meetings.  At least remote work means you don’t have to listen uncomfortably to their anguished sobs (so long as they remember to stay muted).</p>
<p>Every day’s standup starts with “Oh, yeah, we can fix that.  All you’ve gotta do is… ”  At this point, you can’t really make headway.  They’ve created a beast so complicated that nobody can understand it—least of all them.  Not that stops them from <em>thinking</em> that they understand it.</p>
<p>Consequently, nobody can make the case for how or why it’s busted.  The system develops <strong>“behavior”</strong>.  They blithely coast along with the momentum of someone who has mastered being confidently wrong.  They’ve made into more than just a profession, it’s their way of life.</p>
<p>Invariably they start throwing around the word “idempotent”.  They double-down and insist on adding yet-another-key to the request.  Maybe it’s field in the JSON body.  Maybe it’s a header.  Could be a query parameter!  Regardless, it becomes just more metadata that requires infrastructure to develop, maintain, and scale.</p>
<p>You see, it’s just to prevent consistent updates from corrupting state.  Clearly that’s a different, new, and entirely separate problem.  It can’t be because we’re taken an oversimplified approach to building an API such that it can’t even make consistent updates.  Clearly, one more middleware is all it needs!</p>
<p>Now you’ve got this giant mess where you need to track these new keys consistently; despite the fact that you already have a single ID that you can’t track consistently.  The client still has to read tea leaves to divine this elusive object ID for the resources it may or may not have created successfully.</p>
<p>The retries and recovery queries are absolutely hammering your services, now.  A million requests, made by an idiot, full of sound and fury, signifying nothing.</p>
<p>Then they have an insight: “The clients can get back the object ID that was in the response they missed if we save the original response and replay it.  <em>All you’ve gotta do is</em> save the response under the idempotency key somewhere.”</p>
<p>It turns out that replaying cached responses provides no guarantee that the response even corresponds to the same request.  And how long do we save those responses?  Nobody knows.</p>
<p>Maybe it’s an hour.  That works fine until the fiber between regions goes down for an afternoon.  Now all of the hung up requests start retrying.  They end up changing things out-of-order multiple times because we didn’t save the cached responses.</p>
<p>Or better yet, their code starts generating duplicate idempotency keys for unrelated requests (because they invented some half-baked scheme for generating the keys).  Maybe we’re trusting the client too much here.</p>
<p>Or maybe they’re accidentally sending subsequent requests with the same key, but different parameters, because they vibe coded a bit too deeply and greedily.  Now what comes back depends on timing, ordering, and the phase of the moon.</p>
<p>Or maybe caching the whole response takes too much storage.  We’ll just reconstruct the response.  Oops!   Some data was only available at creation time and it’s missing now.  Surely the client won’t care if there are subtle differences between original responses and the ones that we’re now synthesizing.</p>
<p>Eventually Mr. Get-It-Done gets all defensive when concurrent updates start to drastically corrupt state.  The same guy that complained about “know-it-alls whining about the meaning of REST” start using terms like “phantom reads”, “the last update problem”, and “serializability”.  Apparently it’s “pedantic” when you tried to talk about it up-front; but it’s “state-of-the-art” when they do it.</p>
<p>Since they’ve unerringly missed the point for months, they then desperately start trying to layer on more half-measures and hardly considered “fixes”.  Let’s bundle multiple requests in a single <code>POST</code>.  Or try distributed transactions (because they read a blog post about that a year ago).  Maybe they’ll discover “sagas”.</p>
<p>All the while insisting this unmaintainable mess was inevitable.  They’re like some kind of software-engineering Thanos… they just snap their fingers and half of your velocity turns to dust.</p>
<p>Eventually they push to do an entire rewrite.  Or maybe they want to move to NoSQL (since your relational database is spouting flames from all of the superfluous work they’re piling onto it).  They’ll probably end up being promoted for building such a high-tech “solution”.  It’s not clear if that’s good because they’re not working directly on the codebase anymore or bad because they’re now a “tech lead” or “architect”.</p>
<h2><a name="p-380784-can-we-maybe-learn-anything-from-http-itself-4" class="anchor" href="#p-380784-can-we-maybe-learn-anything-from-http-itself-4" aria-label="Heading link" rel="nofollow"></a>Can we maybe learn anything from HTTP itself?</h2>
<p>Let’s start with some highlights from RFC9110:</p>
<ul>
<li><code>GET</code>
<ul>
<li>§9.2.1: The <code>GET</code> method is “safe”.</li>
<li>§9.2.2: They <strong>are</strong> guaranteed to be idempotent.</li>
<li>§9.3.1: Responses are cacheable and update caches on the way through.</li>
</ul>
</li>
<li><code>POST</code>
<ul>
<li>§9.2.1:
<ul>
<li>The response <code>POST</code> method is <strong>not</strong> safe (implied).</li>
</ul>
</li>
<li>§9.2.2:
<ul>
<li><code>POST</code> is not guaranteed idempotent.</li>
<li>Unless it is.</li>
<li>But you’ve got to know.</li>
<li>Good luck.</li>
</ul>
</li>
<li>§9.3.3:
<ul>
<li><code>POST</code> responses are not cacheable.</li>
<li>Except when it is, but only if some extra metadata is returned.</li>
<li>But not for <code>POST</code> requests; because they’re allowed to be “unsafe”.</li>
<li>But, sure, for <code>GET</code> requests… if you want to.</li>
<li>Oh, and it doesn’t necessarily create resources, though it might.</li>
<li>In fact, it can even create things without explicitly telling you if it wants.</li>
<li>For that matter, nothing about a <code>POST</code> guarantees that it’s going to create what you asked it to.</li>
</ul>
</li>
</ul>
</li>
<li><code>PUT</code>
<ul>
<li>§9.2.2: <code>PUT</code> requests <strong>are</strong> guaranteed to be idempotent.</li>
<li>§9.3.4:
<ul>
<li>Responses are not cached and invalidate caches on the way through.</li>
<li>If they create resources, they MUST tell you.</li>
<li>If it returns successfully, you can be sure that the state has been updated to exactly what you requested.</li>
</ul>
</li>
</ul>
</li>
<li><code>DELETE</code>
<ul>
<li>§9.2.2: <code>DELETE</code> requests <strong>are</strong> guaranteed to be idempotent.</li>
<li>§9.3.5: Responses are not cachable and invalidate caches on the way through.</li>
</ul>
</li>
</ul>
<p>Notice a pattern there?  <code>POST</code> is the wild west.  It has no strong semantics.  It’s whatever it wants to be. Nobody in their right mind should use it.  If you do, don’t expect anything sane out of it</p>
<p>We can at least use <code>GET</code>, <code>PUT</code>, and <code>DELETE</code> sanely.  They’re tightly defined.  That’s great.  But how do I map four operations to only three methods?  And what about retries and double creation and concurrent updates and all of the other problems we ran into?</p>
<h2><a name="p-380784-be-the-change-you-want-to-see-in-the-database-5" class="anchor" href="#p-380784-be-the-change-you-want-to-see-in-the-database-5" aria-label="Heading link" rel="nofollow"></a>Be The Change You Want To See In The Database</h2>
<p>If only there was a way we could make sure that a retried request (or an update) is operating on the state we expect to be there.</p>
<p>Going back to RFC9110, let’s learn about conditional requests:</p>
<ul>
<li>§13.1:
<ul>
<li>There are “preconditions” you can specify to ensure that your state doesn’t get thrashed because other requests (retries, other clients, etc.) changed something out from under you.</li>
</ul>
</li>
<li>§13.1.2: <code>If-None-Match</code>
<ul>
<li>Want to ensure you’re creating something?</li>
<li>Use <code>If-None-Match: *</code> and your <code>PUT</code> won’t turn that create into an update.</li>
<li>Suddenly.. you don’t need <code>POST</code>!</li>
</ul>
</li>
<li>§13.1.4: <code>If-Unmodified-Since</code>
<ul>
<li>What if you’re doing a read-update-write cycle?</li>
<li>If there are dueling requests with other clients, your updates might step on each other!</li>
<li>But, if you know the date returned when you did the read, you can say to only do the request if it hasn’t changed!</li>
<li>Now retries are safe without corruption due to “the last update problem”</li>
</ul>
</li>
<li>§13.1.1: <code>If-Match</code>
<ul>
<li>Time is kind of imprecise here.  Maybe you’re nervous about using modification dates to prevent accidents.</li>
<li>If only we could use a hash of the data or something?</li>
<li>That’s what the <code>etag</code> is for.</li>
<li>Now you can use <code>If-Match: &lt;etag&gt;</code> and you’ll get consistent updates based on the actual content.</li>
<li>This even works if retried <code>PUT</code> requests update the timestamp twice without changing the data.</li>
</ul>
</li>
<li>§15.5.13: <code>412 Precondition Failed</code>
<ul>
<li>There’s a dedicated <code>4xx</code> series error code just for this.</li>
<li>No longer do I have to figure out if I should return a <code>400 Bad Request</code>, a <code>401 Unauthorized</code>, a <code>403 Forbidden</code>, a <code>404 Not Found</code>, a <code>410 Gone</code>, or <code>418 I’m A Teapot</code> (if you support the HTCPCP extensions from RFC2324).</li>
</ul>
</li>
</ul>
<p>Well, that’s neat and all; but does it really help that much?  It kind of eliminates the need for idempotence keys and eliminates lost updates and the last read problem.  But it doesn’t help with the problem we started with: Getting the ID that the server used if we lose the initial response.</p>
<p>Well… do we <em>really</em> need the server to do that for us?  Maybe it doesn’t have to?  Can we have the client-side just submit one of their own?  Then they already have it before the server even gets started.</p>
<h2><a name="p-380784-trust-the-awesomeness-6" class="anchor" href="#p-380784-trust-the-awesomeness-6" aria-label="Heading link" rel="nofollow"></a>Trust The Awesomeness</h2>
<p>At first, this sounds questionable.  What if people intentionally create collisions?  How can you keep IDs consistent without arbitrating on the server?  How can I trust the client?</p>
<p>Then you start to realize suddenly that client-side IDs would demand significantly less from your database.  By itself, it takes a huge load off for no other reason that the server no longer needs to maintain a consistent ID counter.  Now that you think about it, could you do sharding without even consulting the server?</p>
<p>Next you realize that you can also use a client-side ID itself as the idempotency key. You can use conditional requests to instruct the server what to do if there’s a conflict.  They give you all you’ll need to ensure that you’re manipulating the state you expect to be there.</p>
<p>Not only is this safer, you no longer have the risk of giving a duplicate idempotency key</p>
<p>You also get a clean recovery workflow for clients.  Now retries are safe.  And if you get “Precondition Failed”, you can do a <code>GET</code> to see if your create succeeded or if there was an intervening update you didn’t expect.</p>
<p>If you only care about success or failure, you don’t even need a <code>GET</code>.  You can just do a <code>HEAD</code> and look at the <code>etag</code>.  And if you do decide to do a <code>GET</code> you update the cache in-between consistently automatically.</p>
<p>Hey… you get caching in there, too.  You can deploy something like Squid and your API will actually work with it, not against it.  Bonus points if all of your microservices perform better because there’s a giant, consistent, shared cache sitting in front of them.</p>
<p>Whoa.  Now that I look at it, Squid even has facilities for me to make this work across our WAN.  It turns out that ICP is about more than clowns (i.e. Inter-Cache Protocol &gt;&gt; Insane Clown Posse).</p>
<p>This improves <em><strong>everything!</strong></em></p>
<h2><a name="p-380784-uuids-to-the-rescue-7" class="anchor" href="#p-380784-uuids-to-the-rescue-7" aria-label="Heading link" rel="nofollow"></a>UUIDs to the Rescue!</h2>
<p>Theoretically, if you have them use UUIDs, then collisions are statistically unlikely.</p>
<p>Of course, there are so many to choose from!:</p>
<ul>
<li>UUID v1 ensures no collisions by using timestamps and MAC addresses.</li>
<li>Nobody talks about UUID v2.  It’s like IPv5.  We just skip over it.</li>
<li>UUID v3 lets us throw in a “namespace” and “identifier” to hash for more uniqueness.</li>
<li>UUID v4 lets us just go with pure randomness.</li>
<li>UUID v5 lets us use a stronger hash function than UUID v3… progress!</li>
<li>UUID v6 lets us basically do UUID v1 again, but now they sort by time!</li>
<li>UUID v7 sort, too; but they’re random like UUID v4.</li>
<li>UUID v8… well… it can be anything we want!</li>
</ul>
<h2><a name="p-380784-uuids-to-the-rescue-8" class="anchor" href="#p-380784-uuids-to-the-rescue-8" aria-label="Heading link" rel="nofollow"></a>UUIDs to the Rescue?</h2>
<p>Well, okay… it turns out all of those break in one way or another.</p>
<ul>
<li>MAC addresses get duplicated all the time in VM clusters and containers.</li>
<li>Lots of embedded systems reset to a predictable date on bootup until NTP or something kicks in.</li>
<li>In tests it’s even worse, because now some UUID typesl generate the same UUID in each test because they seed the RNG predictably.</li>
<li>Or maybe it works but your test are nondeterministic because of time values.</li>
<li>But then you mock it out and now you broke the rest of the UUID generation, too.</li>
<li>Even with pure randomness, you’re something stuck with a busted client.</li>
</ul>
<p>Oof, now that I’m trying to use them, it’s a real pain.</p>
<ul>
<li>They can’t be used in some contexts that don’t like leading numbers or hyphens.</li>
<li>They’re leaking my MAC address.</li>
<li>They’re leaking when I created them with that timestamp, too.</li>
<li>Even the sorting is killing my database because it causes current updates to hammer a tiny spot in my BTree index.</li>
<li>Sorting is also making it easier for someone who might try to cause a collision, too.</li>
</ul>
<p>So they perform worse, they’re bad for privacy, they might be bad for security, embedded systems cause problems, testing gets weird, and now every client can naively create problems with bad PRNGs.</p>
<p><strong></strong></p>
<h2><a name="p-380784-lets-look-at-scalable-cloud-databases-for-inspiration-9" class="anchor" href="#p-380784-lets-look-at-scalable-cloud-databases-for-inspiration-9" aria-label="Heading link" rel="nofollow"></a>Let’s Look At Scalable Cloud Databases for Inspiration</h2>
<p>Hmmm, MongoDB has an <code>ObjectID()</code> function!  What do <a href="https://www.mongodb.com/docs/manual/reference/method/ObjectId/" rel="noopener nofollow ugc">the docs</a> say it does?</p>
<ul>
<li>A timestamp</li>
<li>Some randomness</li>
<li>A client-side session counter</li>
</ul>
<p>This sounds familiar…</p>
<h2><a name="p-380784-so-thats-what-that-cuid-manifesto-was-rambling-about-10" class="anchor" href="#p-380784-so-thats-what-that-cuid-manifesto-was-rambling-about-10" aria-label="Heading link" rel="nofollow"></a>So <em>That’s</em> What That CUID Manifesto Was Rambling About!</h2>
<p>And now you’ve got CUID:</p>
<ul>
<li>Leading letters for easier use in more places.</li>
<li>Strong randomness.</li>
<li>Uses client info but hashes it for privacy.</li>
<li>Salting also gives us some security, too.</li>
<li>Lack of order helps performance.</li>
<li>Has that session counter in there, too.</li>
</ul>
<p>CUID gives you a client-side key that you can generally trust.  You’re freed from dealing with idempotency keys.  You get consistent updates in the face of concurrent changes.  You can prevent double-creation or deletion.  The server is no longer a bottleneck for ID creation.  You can shard statelessly.  You get potentially global caching almost for free.</p>
<p>Maybe the real treasure was the HTTP features we met along the way!</p>
<h2><a name="p-380784-conclusion-11" class="anchor" href="#p-380784-conclusion-11" aria-label="Heading link" rel="nofollow"></a>Conclusion</h2>
<p>So there you have it.  It’s not about the server generating better UUIDs for IDs.</p>
<p>It’s about a system where it doesn’t have to.  It’s an entirely different paradigm.  It’s about shared-nothing scaling.  It’s about correct functioning despite malicious or very broken clients.  It’s about keeping your data consistent.  It’s about robustness, resilience, and recovery.  It’s about security and privacy.</p>
<p>But, mostly, it’s about building the kind of systems that are possible if you’re willing to question the assumptions that everyone else is making.</p>
<p>P.S. Thank you for coming to my TED talk.<br>
P.P.S.  No, I didn’t use any AI to generate this.  I write like this.  Always have—just… em-dashes… everywhere.<br>
P.P.P.S.  It’s 4am and I’m very tired.  I hope this makes any sense at all.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="380784" data-batch-url="/posts/batch_likers">
                        5
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/excuid2-elixir-implementation-of-cuid2-collision-resistant-unique-identifiers/71724/14">Post #13</a>
	                </div>
	            </div>
              <div id="likers-container-380784" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="380784"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #13"></div>
  </section>
</div>
    <div class="postbit" id="380787" data-post-id="380787">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="garrison" src="/assets/icons/user-9f439610.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  garrison
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>I appreciate that you have very strong opinions about REST APIs (I do too).</p>
<p>It has been possible to <a href="https://developer.mozilla.org/en-US/docs/Web/API/Crypto" rel="noopener nofollow ugc">generate crypto-safe random numbers</a> in JS for a decade. I understand that this CUID format maybe predates that, so whatever, but that does not mean you should be using it now. And either way Elixir has <code>:crypto.strong_rand_bytes()</code>. Use that.</p>
<p>Your points against UUIDs do not make sense.</p>
<aside class="quote no-group" data-username="jvantuyl" data-post="14" data-topic="71724">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/jvantuyl/48/26664_2.png" class="avatar"> jvantuyl:</div>
<blockquote>
<ul>
<li>They can’t be used in some contexts that don’t like leading numbers or hyphens.</li>
<li>They’re leaking my MAC address.</li>
<li>They’re leaking when I created them with that timestamp, too.</li>
<li>Even the sorting is killing my database because it causes current updates to hammer a tiny spot in my BTree index.</li>
<li>Sorting is also making it easier for someone who might try to cause a collision, too.</li>
</ul>
</blockquote>
</aside>
<ul>
<li>A UUID is 16 bytes. You can encode it however you want. Or add a letter in front!</li>
<li>Do not use UUIDv1 (for anything). Use v4 or v7.</li>
<li>Only if you use v7! That is a choice, with tradeoffs.</li>
<li>Actually, they love to be hammered that way. It keeps the pages in cache.</li>
<li>You are generating ids on the client, you cannot stop them from causing collisions lol. But again, v4!</li>
</ul>
<p>If you have a legacy system using this id format then of course you might want a library, but there is no reason this library needs to actually follow the (completely unhinged) “spec”. You can just call <code>:crypto.strong_rand_bytes()</code> and then encode the bytes into a CUID.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="380787" data-batch-url="/posts/batch_likers">
                        4
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/excuid2-elixir-implementation-of-cuid2-collision-resistant-unique-identifiers/71724/15">Post #14</a>
	                </div>
	            </div>
              <div id="likers-container-380787" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="380787"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-last-post cat-last-post" title="Last post!"></div>
  </section>
</div>
</template></turbo-stream><turbo-stream action="replace" target="load-more-container"><template><div id="load-more-container" class="load-more-container">
    <span class="all-loaded">— All posts loaded —</span>
</div></template></turbo-stream>