Módulo 8: Proyecto — diseña Enlace de punta a punta

8. Proyecto: diseña Enlace de punta a punta

Descripción

Llegó el final del recorrido de vuelta, y con él el entregable que corona la guía entera: el diseño completo de Enlace, de punta a punta. En este proyecto no se agrega ninguna herramienta; se juntan las siete de los módulos anteriores en un solo artefacto defendible, recorriendo el marco de 4 pasos de corrido. Es exactamente lo que produces —y defiendes— en una entrevista de system design o en una revisión de arquitectura real: un diseño con requisitos, tabla de capacidad ejecutada, diagrama, y una lista de tradeoffs justificados con números.

La lección tiene tres partes. Primero, el enunciado del proyecto —lo que tienes que producir, con tus manos, antes de mirar la solución—. Segundo, la rúbrica —los criterios con los que se evalúa un buen diseño, para que sepas qué distingue una propuesta sólida de una que solo parece completa—. Y tercero, dentro de un <details>, la solución de referencia completa: el diseño de Enlace hecho, con su diagrama mermaid, su tabla de capacidad corrida en Python, y su lista de tradeoffs, para que compares tu diseño con uno defendible. No es la respuesta correcta —otro hit ratio objetivo, otro número de shards, otra política de TTL también se defienden—, pero es una propuesta sólida con cada decisión atada a un número. Al final, la guía cierra: el resumen de los ocho módulos como un arco, y hacia dónde seguir en el ecosistema.

Conexión con el módulo: este es el capstone del capstone. Usa el paso 1 (lección 2), el paso 2 (lección 3), el paso 3 (lección 4) y el paso 4 (lecciones 5, 6, 7) —todo a la vez— para producir el artefacto final. Es también el cierre de la guía: al terminarlo, habrás recorrido el mapa completo que el módulo 1 abrió, y tendrás en la mano la habilidad que la guía promete —tomar un enunciado vago y producir un diseño distribuido defendible con números—.

El examen práctico del oficio

Piénsalo así. Un piloto no obtiene su licencia respondiendo preguntas de opción múltiple sobre aerodinámica. La obtiene en el examen práctico: sube a la cabina, con el examinador al lado, y vuela de verdad —despega, navega, maneja una emergencia simulada, aterriza—. El examinador no le pregunta "¿qué es la sustentación?"; observa si sabe volar, si recorre el checklist en orden, si toma decisiones correctas bajo presión, si sabe justificar por qué viró cuando viró. Todo lo que el piloto estudió por separado —meteorología, motores, navegación, procedimientos— se pone a prueba junto, en una sola sesión, produciendo un vuelo real.

Fíjate en qué evalúa el examinador. No busca la maniobra "perfecta" —no existe—; busca criterio: ¿el piloto tomó decisiones razonables para las condiciones que tenía?, ¿puede explicar cada una?, ¿siguió el método sin saltarse pasos?, ¿anticipó los problemas en vez de reaccionar tarde? Dos pilotos pueden volar la misma ruta de formas distintas y ambos aprobar, porque lo que se evalúa no es que coincidan con una respuesta única, sino que cada decisión esté justificada y el método se respete.

Este proyecto es tu examen práctico de system design. No te preguntamos "¿qué es una caché?"; te pedimos que diseñes Enlace entero —requisitos, estimación, diagrama, profundizar, tradeoffs— produciendo un diseño real. Y como el examinador del piloto, la rúbrica no busca que coincidas con la solución de referencia palabra por palabra; busca criterio: que cada caja tenga su número, que recorras el marco en orden, que sepas defender cada tradeoff, que anticipes el día malo. Un diseño distinto al de referencia puede ser igual de bueno, si cada decisión está justificada. Eso es lo que hace de esto un examen del oficio y no de la memoria.

Conviene decirlo con todas las letras:

El proyecto final evalúa criterio, no coincidencia. Un buen diseño de Enlace no es el que copia la solución de referencia; es el que recorre el marco de 4 pasos en orden, justifica cada componente con un número, defiende cada tradeoff con su "gano/pago", y anticipa el día en que las cosas fallan. Como el examen del piloto: no hay un vuelo perfecto, hay decisiones justificadas.

El enunciado del proyecto

Eres el ingeniero a cargo de diseñar Enlace, un acortador de URLs, desde cero. El equipo te da el enunciado vago —"diseña un acortador de URLs que aguante escala"— y las suposiciones de partida (los números que en un problema real le sacarías al cliente con preguntas):

  • 100 millones de URLs nuevas al mes.
  • Ratio lectura:escritura = 100:1 (la gente visita mucho más de lo que crea).
  • Retención 5 años; URL larga promedio ~500 bytes; registro completo ~1 KB.
  • Latencia de resolve < 100 ms; disponibilidad 99.9%.

Tu entregable son los cuatro artefactos del marco de 4 pasos:

  1. Requisitos (paso 1): funcionales, no funcionales con número, y tabla de alcance.
  2. Tabla de capacidad (paso 2): QPS, almacenamiento, ancho de banda, memoria —ejecutada, no citada—.
  3. Diseño de alto nivel (paso 3): el diagrama de la arquitectura distribuida, con cada caja justificada.
  4. Profundizar + tradeoffs (paso 4): el camino de escritura y el de lectura, el escalado de datos y de cómputo, y la lista de tradeoffs con su "gano/pago" numérico.

Hazlo tú primero, con tus manos, recorriendo el marco en orden. Cuando termines, abre la solución de referencia y compara —no para ver si coincides, sino para ver si tu criterio se sostiene—.

La rúbrica

Así se evalúa un diseño de Enlace. No es una lista de componentes que deben aparecer; es una lista de cualidades que un buen diseño tiene. Úsala para revisar el tuyo.

CriterioQué se buscaSeñal de que falta
Requisitos explícitosLos tres artefactos del paso 1, con no funcionales numéricos y tabla de alcance en las dos direcciones"Que sea rápido y escalable" (sin número); no se dice qué queda fuera
Números ejecutadosLa tabla de capacidad corrida, reproduciendo los anclas (~40, ~4,000, 6 TB, 62⁷, 333 MB)Números citados de memoria; no se puede reproducir la salida
Cada caja justificadaTodo componente del diagrama señala la fila de la tabla que lo exigeUna caja sin número detrás; un componente de otra guía (colas, microservicios)
Simplicidad disciplinadaEl diseño más simple que cumple los requisitos; ni sobra ni faltaDiseño inflado (Kafka, Elasticsearch) o incompleto (una sola BD para 6 TB)
Tradeoffs con "gano/pago"Cada decisión importante con su beneficio, su costo y su número"Elegí X" sin decir qué se paga; consistencia elegida por gusto, no por el dato
El día maloAnticipa el miss masivo, el fallo de un nodo, el crecimientoSolo describe el caso feliz; no dice qué pasa si la caché se vacía
Fronteras respetadasMenciona y enlaza lo que es de otras guías (failover, eventos, estilos) sin invadirloDiseña event sourcing o circuit breakers como si fueran de esta guía

Un diseño que cumple los siete criterios es defendible ante cualquier pregunta. Fíjate en que ninguno pide "usa esta tecnología"; todos piden justificación, disciplina y honestidad. Eso es lo que se evalúa en el oficio.

Solución de referencia

Ver la solución de referencia completa (diseño de Enlace de punta a punta)

Aquí está un diseño completo y defendible de Enlace, recorriendo el marco de 4 pasos. No es la única respuesta correcta, pero cada decisión está atada a un número.

Paso 1 — Requisitos

FUNCIONALES
  F1  shorten(long_url) -> short_code   (base62, 7 chars; enla.ce/<code>)
  F2  resolve(short_code) -> 302 Location: long_url
  F3  short_code inexistente -> 404

NO FUNCIONALES (con numero)
  escrituras   ~40/s        lecturas   ~4,000/s (100:1, LECTURA PESADA)
  almacenamiento ~6 TB (5 anos)         latencia   resolve < 100 ms
  disponibilidad 99.9% (<=8.76 h/ano)   consistencia eventual OK para resolve

ALCANCE v1
  DENTRO: shorten, resolve, 404, redireccion 302
  FUERA:  analitica de clics, URLs personalizadas, expiracion, auth, rate-limit

Decisión clave de alcance: diferir la analítica, porque incrementar clicks en cada resolve convertiría cada lectura en escritura y dispararía las escrituras de ~40/s a ~4,040/s (×100), cambiando el sistema entero.

Paso 2 — Tabla de capacidad (ejecutada)

# Solucion de referencia: la tabla de capacidad de Enlace.
writes_per_month = 100_000_000
seconds_per_month = 30 * 24 * 3600
qps_write = writes_per_month / seconds_per_month
qps_read = qps_write * 100
records = writes_per_month * 12 * 5
storage_tb = records * 1024 / 1e12
code_space = 62 ** 7
read_bw_mb = qps_read * 500 / 1e6
working_set = (writes_per_month / 30) * 0.20
cache_mb = working_set * 500 / 1e6

print(f"escrituras/s   = {qps_write:6.1f}  (~40)")
print(f"lecturas/s     = {qps_read:6.0f}  (~4000)")
print(f"registros 5a   = {records:,}")
print(f"almacenamiento = {storage_tb:5.2f} TB  (~6 TB)")
print(f"62^7           = {code_space:,}  ({records/code_space:.2%} usado)")
print(f"ancho banda    = {read_bw_mb:.2f} MB/s lectura (red NO es cuello)")
print(f"working set    = {working_set:,.0f} entradas = {cache_mb:.0f} MB")

Salida (Python 3.14.0):

escrituras/s   =   38.6  (~40)
lecturas/s     =   3858  (~4000)
registros 5a   = 6,000,000,000
almacenamiento =  6.14 TB  (~6 TB)
62^7           = 3,521,614,606,208  (0.17% usado)
ancho banda    = 1.93 MB/s lectura (red NO es cuello)
working set    = 666,667 entradas = 333 MB

Señales: ~40/s → escritura tranquila (un primary); ~4,000/s → cuello, caché + balanceo; 6 TB → sharding; 62⁷ con 0.17% → IDs sobran (7 chars); 2 MB/s → red no importa; 333 MB → caché baratísima.

Paso 3 — Diseño de alto nivel

graph TD
    C[Cliente / Navegador] -->|HTTP| LB{{Balanceador<br/>round-robin + health checks}}
    LB --> S1[Servidor 1<br/>sin estado]
    LB --> S2[Servidor 2<br/>sin estado]
    LB --> S3[Servidor 3<br/>sin estado]
    S1 --> CACHE[(Cache Redis<br/>~333 MB, hit 0.90)]
    S2 --> CACHE
    S3 --> CACHE
    CACHE -.miss 10%.-> ROUTER[Router de shards<br/>consistent hashing + vnodes]
    S1 -->|escritura| ROUTER
    ROUTER --> P0[(Shard 0 PRIMARY)]
    ROUTER --> P1[(Shard 1 PRIMARY)]
    P0 -->|repl. log| R0[(replicas x2)]
    P1 -->|repl. log| R1[(replicas x2)]

Cada caja, su número: balanceador + servidores sin estado (99.9% + 4,000 lecturas/s), caché (4,000 lecturas/s + <100 ms), sharding (6 TB), consistent hashing (crecer sin tormenta), primaries (40 escrituras/s), réplicas (386/s residuales + redundancia).

Paso 4 — Profundizar

Camino de escritura (shorten, ~40/s): servidor sin estado → contador global → base62_encode (1000000 → '4c92') → router → primary del shard. Unicidad por construcción (contador, sin verificar colisiones); 7 caracteres porque 62⁷ = 3,521,614,606,208 da 587× la demanda (6 raspa, 8 desperdicia). El camino tranquilo.

Camino de lectura (resolve, ~4,000/s): servidor → caché (hit 90% → 1 ms; miss 10% → router → réplica → 50 ms → poblar). Latencia media 0.9·1 + 0.1·50 = 5.90 ms (8.5× vs sin caché). Working set 333 MB (regla 80/20, 0.005% de los 6 TB). Residual a la BD: 0.1 × 3,858 = 386/s (promedio), ~1,157/s (pico ×3). Evicción allkeys-lru; TTL 24 h + jitter.

Escalar datos: réplicas (1–2 mínimas para 386–1,157/s, 2–3 en producción por N−1 y por el miss masivo de 3,858/s); sharding por short_code con consistent hashing + vnodes (crecer remapea 130,623 / 13.1%, no 888,920 / 88.9%). Escalar cómputo: balanceo round-robin sobre servidores sin estado + health checks. Consistencia: eventual/async para resolve (dato casi inmutable; única inconsistencia = 404 fugaz benigno; CAP → disponibilidad, PACELC → latencia); SLO 99.9%.

La lista de tradeoffs

DecisiónGanoPagoNúmero
Caché ante la BD5.90 ms; BD ve 386/sdato viejo (mitigado)hit 0.90; 333 MB
Réplicas de lecturareparten lecturas; redundanciareplication lag (404 fugaz)386/s; N−1
Sharding por short_codereparte 6 TB; sin hotspotsconsultas cruzadas (Enlace no tiene)6 TB / N
Consistent hashingcrecer mueve 13.1%tabla del anillo (vnodes)130,623 vs 888,920
Servidores sin estado + LBescala horizontal; tolera fallosestado compartido es el cuello99.9%
Consistencia eventuallatencia baja; escala de lecturalecturas ven dato de hace msdato casi inmutable
Redirección 302puerta a analítica futurano cachea el navegadoralcance v1

El día malo

Si la caché se vacía (reinicio, despliegue), el hit ratio cae a 0: latencia → 50 ms, la BD recibe 3,858/s de golpe (×10). Mitigaciones: precalentar la caché escalonadamente, jitter en los TTL, y dimensionar las réplicas para el pico (2–3 por shard). La caché protege el 99% del tiempo; las réplicas son la red debajo de la red.

El resumen de la guía: los ocho módulos como un arco

Con el diseño de Enlace terminado, cierra la guía entera. Recorriste ocho módulos, y cada uno resolvió una grieta que el anterior dejó al descubierto —las mismas cuatro grietas de la caja única del módulo 1—:

  • Módulo 1 — Cómo abordar. Entender antes de dibujar; el marco de 4 pasos; Enlace en una sola caja, con sus grietas medidas.
  • Módulo 2 — Estimación. La matemática de servilleta: ~40 escrituras/s, ~4,000 lecturas/s, 6 TB, 62⁷ —los números-ancla que gobernaron cada decisión—.
  • Módulo 3 — Modelo de datos e IDs. El registro Link; el short_code con contador + base62; por qué 7 caracteres alcanzan.
  • Módulo 4 — Caché. Cache-aside; hit ratio 0.90 → 5.90 ms; working set ~333 MB (regla 80/20).
  • Módulo 5 — Escalar la BD. Réplicas (primary/replica, lag); sharding; consistent hashing (13.1% vs 88.9%).
  • Módulo 6 — Balanceo y stateless. Balanceador con health checks sobre servidores sin estado; el estado vive fuera.
  • Módulo 7 — Fiabilidad y consistencia. Redundancia; CAP/PACELC; eventual vs fuerte; SLA/SLO como número.
  • Módulo 8 — Proyecto. Las siete piezas juntas en un diseño distribuido defendible.

La habilidad que sale de aquí es la que el módulo 1 prometió: tomar un enunciado vago —"diseña un acortador de URLs"— y producir un diseño defendible con números, diagrama y tradeoffs explícitos. Ya no te congelas ante la página en blanco; recorres el marco de 4 pasos, y cada paso te dice cuál es tu siguiente movimiento. Y —lo más transferible— el método no es de Enlace: es de cualquier sistema. Cambia los números del enunciado, y el mismo marco produce el diseño de un pastebin, un servicio de fotos, un contador de "me gusta". Enlace fue el caso; el marco es lo que te llevas.

Hacia dónde seguir: el ecosistema

Esta guía enseñó los fundamentos de diseño y escalado, y a propósito dejó fronteras con sus guías hermanas del ecosistema. Ahora que dominas los fundamentos, esas guías son el siguiente paso —cada una profundiza en un tema que aquí solo tocamos como límite—:

  • architectural-styles-and-boundaries-guide — el debate que evitamos: monolito vs. microservicios, DDD, bounded contexts. Enlace fue un servicio sin entrar en cómo trazar los límites entre servicios. Si te preguntaste "¿debería partir Enlace en microservicios?", la respuesta está ahí.
  • event-driven-architecture-guide — lo que difirió el alcance: colas de mensajes, event sourcing, CQRS, streaming. La analítica de clics de Enlace —esa que sacamos de la v1 porque disparaba las escrituras— se diseña aquí, con colas y procesamiento asíncrono.
  • resilience-and-reliability-patterns-guide — lo que mencionamos sin profundizar: circuit breaker, bulkhead, retry con backoff, el failover a fondo (cómo se detecta un primary caído, se promueve una réplica y se evita el "split brain"), idempotencia. Cuando dijimos "la réplica toma el relevo", esta guía dice cómo.
  • api-design-and-integration-guide — el contrato que dejamos mínimo: versionado, paginación, contratos REST/gRPC. El shorten/resolve de Enlace fue un contrato de dos operaciones; diseñar APIs de verdad, con su evolución y sus garantías, es el tema de esa guía.

La regla mecánica para elegir a dónde ir: si la pregunta es "¿monolito o microservicios?", es la de estilos; si es "¿cómo proceso eventos asíncronos?", la de eventos; si es "¿cómo evito que un fallo tumbe todo?", la de resiliencia; si es "¿cómo diseño y verso mi API?", la de APIs. Los fundamentos que aprendiste aquí —estimar, cachear, escalar, razonar tradeoffs— son el cimiento sobre el que todas ellas construyen.

Errores comunes

Entregar un diseño sin haberlo recorrido en orden. Qué pasa: alguien salta directo al diagrama (paso 3) y a los tradeoffs (paso 4) sin escribir los requisitos (paso 1) ni ejecutar la tabla (paso 2), y presenta un diseño que "se ve completo" pero cuya justificación no se sostiene —no puede decir por qué tres réplicas, ni por qué sharding por short_code, porque no hizo el paso 2—. Por qué pasa: el diagrama es lo visible y lo divertido; requisitos y estimación se sienten como trámite. Cómo detectarlo: si tu entregable no tiene los cuatro artefactos, o si el diagrama no puede señalar la tabla, saltaste pasos. Cómo corregirlo: recorre el marco en orden, aunque conozcas Enlace de memoria. El paso 1 justifica el paso 2, que justifica el 3, que justifica el 4. Un diseño sin esa cadena es un dibujo bonito sin cimiento.

Optimizar para coincidir con la solución de referencia. Qué pasa: alguien mira la solución de referencia y ajusta su diseño para que coincida —mismo hit ratio, mismo número de shards, mismas palabras— pensando que "coincidir" es "acertar". Pierde la oportunidad de ejercer criterio propio. Por qué pasa: se confunde el examen del oficio con un examen de memoria. Cómo detectarlo: si cambiaste tu diseño solo para parecerte a la referencia, sin una razón numérica, estás copiando. Cómo corregirlo: la rúbrica evalúa criterio, no coincidencia. Un hit ratio de 0.95 en vez de 0.90, o cuatro shards en vez de dos, es igual de válido si lo justificas con números. Como el piloto: dos vuelos distintos aprueban si cada decisión está fundada. Defiende tu diseño con tus números; no lo dobles para imitar el ajeno.

Cerrar el diseño en el caso feliz. Qué pasa: alguien entrega un diseño que funciona perfecto el día bueno —caché caliente, todos los nodos vivos, tráfico plano— y no dice una palabra de qué pasa cuando la caché se vacía, un nodo se cae, o llega un pico viral. El diseño se ve robusto y es frágil. Por qué pasa: el caso feliz es el que se piensa primero, y anticipar fallos es incómodo. Cómo detectarlo: si tu entregable no tiene una sección "el día malo", está incompleto. Cómo corregirlo: incluye siempre qué pasa a hit ratio 0 (el miss masivo: 3,858/s a la BD), qué pasa si cae un primary (failover, un shard afectado), qué pasa en el pico (×3). Un diseño que solo describe el día bueno es media propuesta —la otra media es demostrar que sobrevive el día malo—.

Ejercicios

Ejercicio 1 — Autoevalúa tu diseño con la rúbrica. Toma el diseño de Enlace que produjiste (o, si no lo hiciste, la solución de referencia) y pásale los siete criterios de la rúbrica, uno por uno. Para cada criterio, di si tu diseño lo cumple y con qué evidencia concreta (qué número, qué caja, qué sección). Identifica el criterio más débil de tu diseño y cómo lo reforzarías.

Ver solución

No hay una respuesta única —depende de tu diseño—, pero así se ve una autoevaluación rigurosa de la solución de referencia:

  • Requisitos explícitos: ✅ Los tres artefactos del paso 1 con no funcionales numéricos y alcance en dos direcciones.
  • Números ejecutados: ✅ La tabla del paso 2 corre y reproduce los anclas (38.6, 3858, 6.14 TB, 62⁷, 333 MB).
  • Cada caja justificada: ✅ Cada componente del diagrama señala su fila de la tabla.
  • Simplicidad disciplinada: ✅ Sin colas, microservicios ni motor de búsqueda; sin esconder la BD en un cilindro.
  • Tradeoffs con "gano/pago": ✅ La tabla de tradeoffs, cada fila con su número.
  • El día malo: ✅ La sección del miss masivo con mitigaciones.
  • Fronteras respetadas: ✅ Se enlaza failover (resiliencia), analítica (eventos), etc.

El criterio típicamente más débil en un diseño propio suele ser "el día malo" (es el que más se olvida) o "cada caja justificada" (es fácil copiar el diagrama canónico sin atar cada caja a un número). Refuerzo: por cada caja, escribe la línea "esto está aquí porque el paso 2 dio X"; y añade una sección explícita de qué pasa a hit ratio 0, con un nodo caído, y en el pico ×3. La autoevaluación honesta con la rúbrica es, en sí, una habilidad del oficio: saber dónde tu propio diseño es débil antes de que te lo pregunten.

Ejercicio 2 — Adapta el diseño a un requisito nuevo. El equipo cambia un requisito: ahora la analítica de clics entra en la v1 (hay que contar cada visita). Sin rehacer todo el diseño, describe: (a) qué número de la tabla de capacidad cambia y cómo; (b) qué componente nuevo hace falta y por qué; (c) a qué guía hermana pertenece ese componente.

Ver solución
  • (a) Cambia el número de escrituras. Contar cada visita convierte cada resolve en una escritura (incrementar clicks). Las escrituras pasan de ~40/s a 40 + 4,000 = ~4,040/s —×100—. Enlace deja de ser lectura pesada y se vuelve lectura-y-escritura pesada; el camino de escritura, que era el tranquilo, se convierte en un cuello.
  • (b) Hace falta un componente para absorber esas escrituras sin contención. Incrementar un contador 4,000 veces/s sobre la misma fila crea contención de bloqueos. La solución no es escribir cada clic directo a la BD, sino agregar los clics en memoria y volcarlos periódicamente, o encolar los eventos de clic y procesarlos de forma asíncrona (un consumidor que actualiza los contadores en lotes). Eso desacopla el camino de lectura (que sigue rápido) del conteo (que se procesa aparte).
  • (c) Ese componente —cola de eventos + procesamiento asíncrono— pertenece a event-driven-architecture-guide. Es exactamente la frontera que Enlace marcó al diferir la analítica: contar a escala es un problema de arquitectura dirigida por eventos, no de los fundamentos de esta guía.

La lección: cambiar un requisito de alcance (meter la analítica) se propaga por toda la tabla de capacidad y obliga a un componente nuevo —y ese componente vive en otra guía—. Por eso la v1 de Enlace la difirió: no porque no importe, sino porque su diseño correcto cruza la frontera del ecosistema. Un buen diseñador ve esa propagación antes de decir que sí.

Ejercicio 3 — Defiende tu diseño ante tres preguntas de entrevista. Un entrevistador cuestiona tu diseño de Enlace. Responde a cada pregunta en un par de frases, con números: (a) "¿Por qué una caché y no simplemente más réplicas de base de datos?" (b) "¿Por qué 7 caracteres para el short_code?" (c) "¿No te preocupa la consistencia? ¿Qué pasa si dos usuarios leen el mismo link y las réplicas están desincronizadas?"

Ver solución
  • (a) Caché vs. más réplicas: una caché resuelve un hit en ~1 ms desde RAM, mucho más rápido que una réplica que va a disco (~50 ms), y una instancia de Redis (~1 GB, ~333 MB de working set) cuesta bastante menos que una réplica con copia completa de 6 TB. La caché absorbe el 90% del tráfico barato y veloz (dejando 386/s a la BD); las réplicas aguantan lo que la caché no cubre (la cola fría, el pico, el día malo). Se complementan, y la caché va primero porque es la capa más barata y rápida. Quitar la caché para "resolver todo con réplicas" sería reemplazar la capa barata por la cara.
  • (b) 7 caracteres: porque 62⁷ = 3,521,614,606,208 (3.5 billones), y la demanda a 5 años es 6,000 millones, así que uso el 0.17% del espacio —un factor de 587× de holgura—. Con 6 caracteres (62⁶ ≈ 56,800 M) alcanzaría raspando, usando >10% sin margen para crecer; con 8 desperdiciaría brevedad. 7 es el mínimo que da holgura cómoda: la respuesta es una cuenta, no un número mágico.
  • (c) Consistencia: no me preocupa, y por la naturaleza del dato: el mapeo short_code → long_url es casi inmutable —no hay UPDATEs que puedan divergir—, así que dos réplicas nunca mostrarán destinos distintos para el mismo código. La única inconsistencia posible es un short_code recién creado que se resuelve desde una réplica atrasada: da un 404 de milisegundos (no el dato equivocado, sino "todavía no lo tengo"), es rarísimo (el creador no visita su link al instante desde otra máquina) y se recupera solo. Elegí consistencia eventual porque el dato no cambia, y esa tolerancia es la que me compra las réplicas de lectura y la escala. Consistencia fuerte me obligaría a leer todo del primary y perdería la escala, para proteger contra algo que casi nunca ocurre y es benigno.

La lección: cada respuesta ata la decisión a un número y a la naturaleza del problema, no a una preferencia. Eso es defender un diseño —y es exactamente lo que la rúbrica y el examinador del piloto buscan—. Un diseño que no puedes defender con números no es tuyo; es copiado.

Resumen y siguiente paso

En este proyecto —el capstone de la guía— diseñaste Enlace de punta a punta, juntando las siete herramientas de los módulos anteriores en un solo entregable defendible. Produjiste los cuatro artefactos del marco de 4 pasos: los requisitos (con alcance que difiere la analítica), la tabla de capacidad ejecutada (~40, ~4,000, 6 TB, 62⁷, 333 MB), el diagrama de la arquitectura distribuida (balanceador → servidores sin estado → caché → primaries sharded con réplicas), y el profundizar con la lista de tradeoffs justificados. Y viste, con el examen práctico del piloto, que lo que se evalúa no es coincidir con la solución de referencia sino ejercer criterio: cada caja con su número, el marco en orden, cada tradeoff con su "gano/pago", y el día malo anticipado.

Cerraste la guía: los ocho módulos como un arco causal, la habilidad que sale de aquí (tomar un enunciado vago y producir un diseño con números, diagrama y tradeoffs), y el método transferible a cualquier sistema. Y viste hacia dónde seguir —las guías hermanas del ecosistema: estilos arquitectónicos, arquitectura dirigida por eventos, patrones de resiliencia, y diseño de APIs—, cada una profundizando en una frontera que aquí solo tocamos.

Antes de dar la guía por terminada deberías poder: recorrer el marco de 4 pasos de corrido para diseñar Enlace (o cualquier sistema) desde cero; producir los cuatro artefactos del entregable; autoevaluar un diseño con la rúbrica; y defender cada decisión ante preguntas, con números y con la naturaleza del problema.

El siguiente paso ya no está en esta guía: está en el ecosistema. Con los fundamentos de diseño y escalado dominados, elige la guía hermana que responda tu próxima pregunta —"¿monolito o microservicios?", "¿cómo proceso eventos?", "¿cómo hago esto resiliente?", "¿cómo diseño mi API?"— y sigue construyendo sobre el cimiento que acabas de terminar. Sabes abordar un problema abierto, estimarlo, modelarlo, cachearlo, escalarlo, distribuirlo, razonar sus tradeoffs, y diseñarlo entero. Eso es diseñar sistemas.

Recursos

  • System Design Primer — "Design a URL shortener" (ejercicio completo) — el mismo caso de Enlace resuelto de punta a punta en el Primer (como pastebin/acortador), con requisitos, estimación, diseño y escalado. La segunda voz ideal para contrastar tu diseño de referencia con otro camino defendible.
  • Designing Data-Intensive Applications, de Martin Kleppmann — sitio oficial — el libro de referencia del oficio, que te acompañará más allá de esta guía. Habiendo terminado el capstone, sus Capítulos 5 (Replication), 6 (Partitioning) y 9 (Consistency and Consensus) profundizan cada decisión que tomaste en Enlace, y son el puente natural hacia las guías hermanas.
  • System Design Interview – An Insider's Guide, de Alex Xu — la colección canónica de diseños completos de sistemas (acortador, feed, chat, notificaciones), con la misma estructura de requisitos → estimación → diseño → profundizar de esta guía. El recurso para practicar el marco de 4 pasos sobre casos nuevos, ahora que lo dominas con Enlace.