Encoding and Decoding
In one line: the forward direction is obvious. The reverse direction is the one that matters architecturally, and it exists for a reason the conversion itself does not reveal.
Base 10 to base 58
Process: Continuously divide the base-10 number by 58 and record the remainder. The sequence of remainders, mapped to our base-58 character set, forms the new string. The last remainder becomes the first character.
Working the chapter's example, 2468135791013:
2468135791013 % 58 = 17 2468135791013 / 58 = 42554065362
42554065362 % 58 = 6 42554065362 / 58 = 733690782
733690782 % 58 = 4 733690782 / 58 = 12649841
12649841 % 58 = 41 12649841 / 58 = 218100
218100 % 58 = 20 218100 / 58 = 3760
3760 % 58 = 48 3760 / 58 = 64
64 % 58 = 6 64 / 58 = 1
1 % 58 = 1 1 / 58 = 0
Reversing the remainders gives the indices, and the character table maps them:
Indices: [1] [6] [48] [20] [41] [4] [6] [17] Chars: 2 7 q M i 5 7 J Base-58 = 27qMi57J
Base 58 to base 10
Process: Multiply each character's value by 58 raised to the power of its position (starting from 0 on the right). The sum is the base-10 number.
2 -> 1 x 58^7 = 2,207,984,167,552
7 -> 6 x 58^6 = 228,412,155,264
q -> 48 x 58^5 = 31,505,124,864
M -> 20 x 58^4 = 226,329,920
i -> 41 x 58^3 = 7,999,592
5 -> 4 x 58^2 = 13,456
7 -> 6 x 58^1 = 348
J -> 17 x 58^0 = 17
------------------
2,468,135,791,013
Which is the integer we started with. The round trip is exact.
Why decoding exists at all — it is not symmetry, it is custom aliases
The forward direction is obviously needed: every new short URL requires it.
The reverse direction is less obvious, and the naive assumption is that redirection uses it — decode the short URL to an ID, look up the ID, return the long URL.
It does not. Redirection is a database lookup keyed by the short string itself. There is no need to decode anything; you have the key.
Decoding exists for exactly one reason, and Lesson 11 covers the mechanism: custom aliases.
When a user claims /coffee, the system must ensure the sequencer never later generates the integer that would encode to coffee. So it:
1. Decode "coffee" -> a specific base-10 integer 2. Mark that integer as USED in the database 3. The sequencer can now never issue it
Without custom aliases, decoding would be dead code.
A bijection is only useful in both directions when something outside the system can propose values in the codomain. Custom aliases are exactly that — users handing you strings, which you must translate back into the integer space where uniqueness is managed.
That is the deeper point: uniqueness is enforced in the integer space, so anything arriving as a string must be converted before it can participate.
Two things about decoding the design does not address
Not every string decodes to a usable ID. A user could request a 3-character alias like abc, which decodes to a small integer — well below the 1-billion floor Lesson 9 establishes for the sequencer's range. Or an 11-character alias decoding above 2⁶⁴. The design mentions validating "a maximum of 11 characters" but not the numeric range, and both ends need checking.
Invalid characters must be rejected. A user requesting /hello is fine, but /heIlo contains a capital I, which is not in the alphabet. It cannot be decoded at all. So custom-alias validation needs a character-set check before any decoding — and the error message should be specific, because "invalid character" on a URL that looks fine to the user is confusing.
That second point is a small usability consequence of Lesson 7's decision. Removing characters from the alphabet makes URLs easier to read and makes some plausible-looking custom aliases impossible. Illinois cannot be a short code.
The cost of encoding is nothing, and that matters for the latency requirement
Both directions are a handful of integer operations — at most 11 divisions or 11 multiply-adds for a 64-bit value.
The chapter's evaluation says so: "The URL generation process, including encoding, is computationally fast and adds negligible delay." That is correct and worth being concrete about: this is nanoseconds, against a Lesson 2 requirement measured in milliseconds.
Which means the entire generation path is:
sequencer: allocate an ID <- the only part with any cost encoder: ~11 divisions <- free database: one write <- the actual latency
The component the chapter spends the most words on is the cheapest thing in the system. That is worth noticing, because it is a common shape: the intellectually interesting part of a design is often not the expensive part, and an interview answer should be clear about which is which.
Worth being explicit, because it is a common confusion: base conversion is reversible and order-preserving. Encoding a counter does not obscure it — consecutive ids still produce adjacent codes, which is exactly why the requirement conflict in Lesson 10 is real.
Key takeaway
Both conversions are exactly correct and round-trip precisely — encoding by repeated division where the last remainder becomes the first character, decoding by positional powers of 58. Decoding exists only for custom aliases: redirection is a lookup keyed by the string itself, so without user-supplied aliases the reverse direction would be dead code. A bijection is needed in both directions only when something outside the system proposes values, and uniqueness is enforced in the integer space, so strings must be converted before they can participate. Validation needs both a numeric range check and a character-set check — Illinois cannot be a short code, which is a small usability cost of Lesson 7's alphabet. And encoding is nanoseconds: the most-discussed component is the cheapest thing in the system.
Next: how long the identifiers must be, and how long they will last.