Módulo 2: Estimación de servilleta (back-of-the-envelope)
7. Redondeo inteligente y sanity checks
Descripción
Ya tienes los cuatro números de Enlace —QPS, almacenamiento, ancho de banda, memoria—, cada uno calculado con su cuenta. Pero un número calculado todavía no es un número confiable: cualquiera puede teclear mal un cero, arrastrar un decimal de más o confundir una unidad, y salir con una cifra que parece rigurosa y está mil veces equivocada. Esta lección enseña la disciplina que convierte un montón de cuentas en una estimación en la que puedes confiar y que aguanta preguntas: el redondeo inteligente y los sanity checks (chequeos de cordura).
Son dos hábitos que van juntos. El redondeo inteligente es reportar cada número con la precisión que de verdad tienes —una cifra significativa, pensando en potencias de 10— y no fingir decimales que no sabes. Los sanity checks son las verificaciones rápidas que confirman que un número no es un disparate: cruzar dos caminos distintos para llegar al mismo resultado, compararlo contra referencias conocidas ("los números que todo programador debería saber"), y aplicarle el smell test —el olfato que dice "esto no puede ser"— cuando una cifra cae en la marca equivocada. Al terminar sabrás redondear como un estimador maduro y detectar un número imposible antes de que contamine todo un diseño.
Conexión con el módulo: esta es la lección-disciplina. No calcula un número nuevo de Enlace; toma los cuatro que ya produjiste y les aplica el filtro de calidad que los vuelve defendibles (la palabra clave de la lección 1). El redondeo formaliza lo que venías haciendo a mano desde la lección 1 (38.58 → ~40); los sanity checks son la red de seguridad que usarás en la lección 8, cuando armes la tabla de capacidad completa y necesites confiar en cada fila. Piénsalo como el paso de "revisar el trabajo" que separa una cuenta hecha a las prisas de una estimación profesional.
La cuenta del restaurante
Imagina que sales a cenar con tres amigos y llega la cuenta: $1,240. Antes de pagar, haces algo automático en dos segundos, sin recalcular cada platillo: piensas "somos cuatro, pedimos cada uno un plato de ~$200 y una bebida de ~$80, más o menos $280 por cabeza, por cuatro son ~$1,120... sí, $1,240 con la propina cuadra". No verificaste la suma exacta línea por línea; hiciste un chequeo de orden de magnitud: ¿el total cae donde debería para lo que pedimos? Si la cuenta dijera $12,400, saltarías de inmediato —"imposible, comimos, no compramos el restaurante"— aunque no supieras exactamente dónde está el error. Y si dijera $124, también sospecharías —"demasiado barato para cuatro personas"—. Tu olfato ubica el total en la marca correcta (miles, no decenas de miles ni cientos), y con eso detectas el disparate sin auditar cada renglón.
Eso es un sanity check, y fíjate en las tres cosas que hiciste, porque valen para cualquier estimación de sistemas:
- Redondeaste para poder pensar. No usaste "$198.50 el plato"; usaste "~$200". Los números redondos te dejaron hacer la cuenta de cabeza. La precisión falsa (el .50) habría estorbado sin aportar nada.
- Cruzaste dos caminos. El total impreso ($1,240) lo comparaste con tu estimación independiente (~$1,120 + propina). Dos rutas al mismo número; si coinciden en la marca, confías; si no, investigas.
- Usaste referencias conocidas. "Un plato cuesta ~$200" es un número que traes de memoria, tu clase de referencia. Sin él no podrías juzgar si el total tiene sentido.
Estimar sistemas es la misma disciplina con otros números. Un ingeniero maduro nunca suelta una cifra sin este reflejo: redondearla para poder razonarla, cruzarla con un segundo camino, y compararla contra lo que sabe que es normal. Esta lección convierte ese reflejo en método.
Parte 1: el redondeo inteligente
Una cifra significativa
La regla central del redondeo de servilleta es brutal y liberadora: reporta una sola cifra significativa. Una cifra significativa es el primer dígito distinto de cero; todo lo demás es ruido que finge precisión. 38.58 tiene una cifra significativa útil (el 4 de ~40, tras redondear); los .58 no los sabes. 6.144 TB se reporta ~6 TB. 1,929,012 B/s se reporta ~2 MB/s.
¿Por qué una sola cifra? Porque tus datos de entrada tienen una cifra. "100 millones de URLs al mes" no es 100,000,000 exactos: es "del orden de cien millones", con un margen enorme (¿y en diciembre?, ¿y si crece?). Si la entrada tiene una cifra de precisión, la salida no puede tener tres: reportar 38.58/s a partir de "~100M/mes" es inventar precisión que nunca existió. La regla de oro de la propagación de incertidumbre: el resultado no puede ser más preciso que el más impreciso de sus insumos. Y todos tus insumos de servilleta son de una cifra.
Ejecutemos el redondeo a una cifra significativa sobre los números crudos del módulo, para ver la disciplina en acción:
from math import log10, floor
def one_sig(x):
# Redondea a UNA cifra significativa.
if x == 0:
return 0
d = floor(log10(abs(x))) # el orden de magnitud (la potencia de 10)
return round(x, -d)
crudos = {
"qps_write (100M/2.592M s)": 38.58,
"qps_read (x100)": 3858,
"bandwidth lectura (B/s)": 1_929_012,
"storage 5 anios (B)": 6.144e12,
"working set (B)": 333_333_333,
}
for nombre, valor in crudos.items():
print(f"{nombre:<32} {valor:>16,.0f} -> {one_sig(valor):>16,.0f}")
Qué esperar.
qps_write (100M/2.592M s) 39 -> 40
qps_read (x100) 3,858 -> 4,000
bandwidth lectura (B/s) 1,929,012 -> 2,000,000
storage 5 anios (B) 6,144,000,000,000 -> 6,000,000,000,000
working set (B) 333,333,333 -> 300,000,000
Cada número crudo colapsa a un dígito por una potencia de 10: ~40, ~4,000, ~2 MB/s, ~6 TB, ~3×10⁸ B. Fíjate en el último: 333,333,333 redondea a 300,000,000 (3×10⁸) porque el primer dígito es 3; en la práctica lo reportamos como "~333 MB" o "cientos de MB" —el redondeo a una cifra dice "3×10⁸", que es la marca, y "333 MB" conserva un poco más para la tabla, ambos honestos—. La disciplina no es que el número sea feo, sino que comunica cuánto sabes: ~6 TB dice "unos pocos terabytes, marca de 10¹²", que es exactamente lo que tu cuenta justifica.
Redondear desde el principio, no al final
El segundo hábito: redondea al entrar, no al salir. Arrastrar 2,592,000 segundos por mes en tres pasos y redondear solo el resultado final es trabajo desperdiciado y una invitación al error de tecleo. Redondea antes de operar: "un mes son ~2.6 millones de segundos" (o incluso ~2.5 × 10⁶ si quieres redondear más), y opera con eso. Como viste en la lección 2, el redondeo de las constantes (30 días, base 10, 86,400 → 10⁵) mueve el resultado un porcentaje pequeño que desaparece en el redondeo final. Operar con números redondos desde el inicio es lo que te deja hacer la cuenta de cabeza, que es todo el punto de la servilleta.
Hay una excepción de higiene que ya viste en la lección 3: cuando un número alimenta a otro (encadenamiento), conviene arrastrar el crudo un paso más antes de redondear, para no acumular el error del redondeo. Por eso la lección 3 calculó qps_read = 38.58 × 100 (crudo) y redondeó al final a ~4,000, en vez de 40 × 100 = 4,000 —dan casi lo mismo, pero arrastrar el crudo es más limpio—. La regla combinada: redondea las entradas del enunciado desde el principio; arrastra los resultados intermedios sin redondear cuando alimentan otra cuenta; redondea a una cifra al reportar.
Pensar en potencias de 10
El redondeo inteligente y las potencias de 10 (lección 2) son la misma disciplina vista de dos formas. Redondear a una cifra significativa es escribir el número como dígito × 10^n. ~6 TB es 6 × 10¹²; ~4,000/s es 4 × 10³; ~333 MB es ~3 × 10⁸. Pensar así tiene una ventaja para el sanity check que viene: cuando un número está en notación científica, comparar dos números es comparar sus exponentes (sus marcas), y un error de "mil veces" salta a la vista como una diferencia de 3 en el exponente. 6 × 10¹² contra 6 × 10¹⁵ —6 TB contra 6 PB— es una diferencia de exponente de 3, un factor de mil, imposible de pasar por alto si piensas en marcas. Redondear a potencias de 10 no es solo estética: es lo que hace que los errores de marca sean visibles.
Parte 2: los sanity checks
Redondear te da números limpios; los sanity checks te dicen si esos números son creíbles. Hay cuatro técnicas, y un buen estimador aplica al menos una a cada cifra importante antes de confiar en ella.
Técnica 1: cruzar dos caminos independientes
La verificación más poderosa es llegar al mismo número por dos rutas distintas. Si dos caminos independientes aterrizan en la misma marca, es muy improbable que ambos tengan el mismo error; el número es sólido. Si divergen, hay un bug en uno de los dos y lo encontraste antes de que hiciera daño. Probémoslo con tres números del módulo:
# CAMINO A vs CAMINO B para tres numeros de Enlace.
# 1) QPS de escritura: dividir de golpe vs bajar la escalera de tiempo
a1 = 100_000_000 / 2_592_000 # ÷ segundos/mes de golpe
b1 = 100_000_000 / 30 / 86_400 # ÷30 (dias) luego ÷86400 (seg/dia)
print(f"qps_write A={a1:.2f}/s B={b1:.2f}/s")
# 2) Lecturas por dia: desde el QPS vs desde el total mensual
a2 = 4000 * 86_400 # 4000/s x segundos/dia
b2 = 100_000_000 * 100 / 30 # (100M x100 lecturas) / 30 dias
print(f"reads/day A={a2:,.0f} B={b2:,.0f} (misma marca ~3.x x10^8)")
# 3) Almacenamiento a 5 anios: por registros totales vs por meses
a3 = 6e9 * 1000 # 6 mil millones de registros x 1KB
b3 = 100_000_000 * 60 * 1000 # 100M/mes x 60 meses x 1KB
print(f"storage A={a3/1e12:.0f}TB B={b3/1e12:.0f}TB")
Qué esperar.
qps_write A=38.58/s B=38.58/s
reads/day A=345,600,000 B=333,333,333 (misma marca ~3.x x10^8)
reads/day ...
storage A=6TB B=6TB
Los tres pasan. El QPS de escritura da idéntico por los dos caminos (era la misma división descompuesta). El almacenamiento, idéntico. Y las lecturas por día dan 345.6M por un camino y 333.3M por el otro —no son iguales, pero caen en la misma marca (~3×10⁸), y la pequeña diferencia (un ~3.7%) tiene una explicación conocida: viene de redondear 38.58 a 40 en el camino A. Un estimador maduro reconoce esa diferencia como esperada (sabe de dónde sale) y no se alarma: ambos números dicen "del orden de trescientos y pico millones de lecturas al día", que es la conclusión. Cuando dos caminos difieren, la pregunta no es "¿cuál es el correcto?" sino "¿la diferencia cae dentro de lo que explica mi redondeo, o revela un error real?". Un 3.7% lo explica el redondeo; un factor de 10 sería un bug.
Técnica 2: comparar contra referencias conocidas
Un número en el vacío no se puede juzgar; contra una referencia, sí. Los estimadores veteranos cargan en la cabeza un puñado de números de referencia —tamaños, latencias, capacidades típicas— contra los que contrastan sus resultados. "4,000 lecturas/s" no dice nada hasta que sabes que "una base de datos modesta hace miles de lecturas/s" (entonces: cargable, pero hay que cuidarla) y que "un gigante hace millones/s" (entonces: Enlace está lejísimos de eso). La referencia es la que convierte un número en un juicio.
La colección de referencias más famosa es la tabla de latencias que todo programador debería conocer (atribuida a Jeff Dean, actualizada por otros). No hay que memorizarla al dígito —son órdenes de magnitud que cambian con el hardware y el año—, pero las proporciones entre capas son estables y valiosísimas. Calculémoslas en vez de citarlas:
# Latencias de referencia (ORDENES DE MAGNITUD, no valores exactos; varian por hardware/anio).
mem_ns = 100 # leer de memoria (RAM) ~100 nanosegundos
ssd_us = 100 # leer aleatorio de SSD ~100 microsegundos
disk_ms = 10 # seek de disco duro ~10 milisegundos
print(f"memoria (RAM): ~{mem_ns} ns")
print(f"SSD (aleatorio): ~{ssd_us} us = {ssd_us*1e3:.0f} ns")
print(f"disco (seek): ~{disk_ms} ms = {disk_ms*1e6:.0f} ns")
print(f"disco / memoria = {disk_ms*1e6/mem_ns:,.0f}x mas lento")
print(f"SSD / memoria = {ssd_us*1e3/mem_ns:,.0f}x mas lento")
dc_ms, cross_ms = 0.5, 150
print(f"round trip mismo datacenter ~{dc_ms} ms | cruzar continente ~{cross_ms} ms ({cross_ms/dc_ms:.0f}x)")
Qué esperar.
memoria (RAM): ~100 ns
SSD (aleatorio): ~100 us = 100000 ns
disco (seek): ~10 ms = 10000000 ns
disco / memoria = 100,000x mas lento
SSD / memoria = 1,000x mas lento
round trip mismo datacenter ~0.5 ms | cruzar continente ~150 ms (300x)
Estas proporciones son oro para los sanity checks. Que la memoria sea ~100,000 veces más rápida que el disco es la referencia que confirma, de golpe, por qué el working set de la lección 6 vale la pena: mover las lecturas calientes de disco (10 ms) a RAM (100 ns) las acelera cinco órdenes de magnitud. Que cruzar un continente sea ~300 veces más lento que un round trip local es la referencia que, más adelante en la guía, justificará poner servidores cerca de los usuarios. No necesitas los nanosegundos exactos; necesitas saber que memoria ≪ SSD ≪ disco ≪ red-lejana, cada capa uno o dos órdenes de magnitud sobre la siguiente. Con esa jerarquía en la cabeza, muchos números se validan (o se descartan) en un vistazo.
Otras referencias de tamaño que conviene tener, del mismo espíritu:
| Cosa | Tamaño de referencia |
|---|---|
| Un carácter (ASCII) | 1 byte |
| Una URL / una línea de texto | ~cientos de bytes (Enlace: ~500 B) |
| Un libro de texto (solo texto) | ~1–5 MB |
| Una foto (comprimida) | ~1–5 MB |
| Una película en alta definición | ~1–5 GB |
| Segundos en un día | ~10⁵ (86,400) |
| Segundos en un año | ~3 × 10⁷ (≈ π × 10⁷) |
Contra estas referencias, "un registro de Enlace pesa ~1 KB" se valida al instante (una URL son cientos de bytes, más metadatos, ~1 KB cuadra), y "Enlace guarda 6 TB" también (6 mil millones de registros de ~1 KB = 6 TB, y 6 TB es "unos cuantos discos", nada monstruoso). Un número que choca con estas referencias —"cada URL pesa 5 MB", "Enlace necesita 6 PB"— enciende la alarma sin más análisis.
Técnica 3: el smell test (detectar lo imposible)
El smell test es el reflejo de la cuenta del restaurante: mirar un número y sentir de inmediato que "no puede ser", porque cae en una marca absurda para lo que representa. No prueba que un número sea correcto, pero atrapa los errores gruesos —los de factor 1,000, típicos de un cero de más o una unidad confundida— que son justo los que arruinan un diseño. Formalicémoslo con dos casos:
# Caso 1: alguien afirma que Enlace necesita 6 PB de almacenamiento.
records = 6e9 # 6 mil millones (leccion 4)
real = records * 1_000 # x 1 KB
claim_pb = 6e15 # 6 PB afirmados
print(f"almacenamiento real = {real/1e12:.0f} TB = {real/1e15:.3f} PB")
print(f"afirmacion (6 PB) esta {claim_pb/real:.0f}x inflada -> IMPOSIBLE")
# Caso 2: alguien afirma que Enlace hace 4 millones de lecturas/s.
claim_qps = 4_000_000
servers = claim_qps / 2000 # a ~2000 req/s por servidor
print(f"4M lecturas/s pediria ~{servers:.0f} servidores (real: ~6)")
print(f"la afirmacion esta {claim_qps/4000:.0f}x inflada -> IMPOSIBLE para esta escala")
Qué esperar.
almacenamiento real = 6 TB = 0.006 PB
afirmacion (6 PB) esta 1000x inflada -> IMPOSIBLE
4M lecturas/s pediria ~2000 servidores (real: ~6)
la afirmacion esta 1000x inflada -> IMPOSIBLE para esta escala
Los dos casos son errores de factor 1,000, la firma clásica de un cero de más o una unidad mal traducida (el "billón" español contra el "billion" inglés de la lección 2, o confundir TB con PB). El smell test los atrapa preguntando "¿tiene sentido esta marca para lo que representa?": Enlace guardando 6 PB implicaría que cada URL pesa un megabyte (absurdo para texto), y Enlace con 4M lecturas/s implicaría 2,000 servidores para un acortador de URLs (absurdo para su escala). Ninguno pasa el olfato. La técnica: cuando un número te sorprenda, no lo aceptes ni lo deseches a ciegas —tradúcelo a algo tangible (bytes por URL, servidores necesarios) y pregunta si ese algo es creíble—. Los errores gruesos casi siempre se delatan al traducirlos.
Técnica 4: razonar por órdenes de magnitud
La cuarta técnica es la actitud que envuelve a las otras tres: juzga la marca, no el dígito. Como martilló la lección 1, lo que decide el diseño es la potencia de 10, no los decimales. Un sanity check no busca confirmar que el número es 40 y no 38.58; busca confirmar que es "decenas" y no "miles" ni "unidades". Por eso los chequeos se hacen sobre marcas: dos caminos que caen en la misma marca (aunque difieran 4%) confirman; una referencia en la misma marca valida; un número tres marcas fuera de donde debería es imposible. Preguntar siempre "¿en qué marca cayó y es la que esperaba?" es el sanity check más barato y el que más errores atrapa, porque los errores que importan son los de marca.
Ejemplo trabajado: verificar toda la tabla de Enlace de un vistazo
Juntemos las técnicas en un chequeo rápido de los cuatro números de Enlace, como lo harías antes de entregarlos. Para cada uno: la marca esperada y una referencia que lo valida.
checks = [
# numero, valor, marca, referencia que lo valida
("QPS escritura", "~40/s", "10^1", "una BD modesta hace miles/s -> trivial"),
("QPS lectura", "~4,000/s", "10^3", "miles/s: cargable, pide cache"),
("Almacenamiento", "~6 TB", "10^12 B", "6e9 registros x 1KB; ~unos discos"),
("Ancho de banda", "~2 MB/s", "10^6 B/s","<5% de una NIC de 1 Gbps (125 MB/s)"),
("Memoria (WS)", "~333 MB", "10^8 B", "0.006% de 6TB; 2% de 16GB RAM"),
]
print(f"{'numero':<16}{'valor':<10}{'marca':<9}referencia")
for n, v, m, r in checks:
print(f"{n:<16}{v:<10}{m:<9}{r}")
Qué esperar.
numero valor marca referencia
QPS escritura ~40/s 10^1 una BD modesta hace miles/s -> trivial
QPS lectura ~4,000/s 10^3 miles/s: cargable, pide cache
Almacenamiento ~6 TB 10^12 B 6e9 registros x 1KB; ~unos discos
Ancho de banda ~2 MB/s 10^6 B/s <5% de una NIC de 1 Gbps (125 MB/s)
Memoria (WS) ~333 MB 10^8 B 0.006% de 6TB; 2% de 16GB RAM
Cinco números, cada uno en una marca distinta y con una referencia que lo respalda. Ninguno choca con una capacidad conocida, ninguno cae en una marca absurda, y las relaciones entre ellos son coherentes (la lectura es 100× la escritura; el working set es una fracción diminuta del almacenamiento). Esta tabla mental —número, marca, referencia— es el sanity check final antes de entregar, y es justo la estructura que vas a llenar en la lección 8. Si cualquier fila no tuviera una referencia que la valide, o cayera fuera de su marca esperada, ahí estaría el error a investigar.
Errores comunes
Reportar falsa precisión (de arrastrar decimales que no sabes). Qué pasa: alguien entrega "38.58 escrituras/s" o "6.144 TB" y se siente riguroso por los decimales, cuando la entrada ("~100M/mes") solo justifica una cifra. Por qué pasa: en la escuela más decimales era más nota; en estimación es al revés, porque los decimales fingen una precisión que no existe. Cómo detectarlo: si tu resultado tiene más cifras significativas que tu insumo más impreciso, inventaste precisión. Cómo corregirlo: redondea a una cifra significativa (~40/s, ~6 TB). Un número redondeado comunica honestamente cuánto sabes; un decimal preciso miente. Regla: el resultado no puede ser más preciso que el más impreciso de sus insumos, y en servilleta todos son de una cifra.
Confiar en un solo camino (de no cruzar la cuenta). Qué pasa: la persona calcula un número una vez, lo teclea, y lo da por bueno sin verificar —y no nota que puso un cero de más o dividió entre el número equivocado—. Por qué pasa: la cuenta "se ve bien" y verificar parece trabajo extra. Cómo detectarlo: si no puedes llegar a un número por una segunda ruta, no lo has verificado, solo lo has calculado. Cómo corregirlo: para cada número importante, encuentra un segundo camino (bajar la escalera de tiempo en vez de dividir de golpe; partir del total en vez del ritmo) y comprueba que caen en la misma marca. Si divergen más de lo que explica tu redondeo, hay un bug. Dos caminos que coinciden es la verificación más barata y poderosa que existe.
Aceptar un número sin traducirlo a algo tangible (de saltarse el smell test). Qué pasa: alguien ve "Enlace necesita 6 PB" o "hace 4M lecturas/s" y lo anota sin sentir la alarma, porque el número "suena a sistema grande". Por qué pasa: las cifras enormes impresionan y se aceptan por inercia, sobre todo bajo presión. Cómo detectarlo: si aceptaste un número solo porque "suena importante" sin preguntarte qué implica, te saltaste el olfato. Cómo corregirlo: traduce todo número sorprendente a algo tangible —bytes por elemento, servidores necesarios, comparación con una referencia— y pregunta si ese algo es creíble. 6 PB implica 1 MB por URL (absurdo para texto); 4M lecturas/s implica 2,000 servidores (absurdo para un acortador). Los errores de factor 1,000 —un cero de más, una unidad confundida— siempre se delatan al traducirlos.
Ejercicios
Ejercicio 1 — Redondea y ubica la marca. Para cada cuenta cruda, (i) redondea a una cifra significativa, (ii) escríbela como dígito × potencia de 10, y (iii) di en qué "marca" cae en una palabra: (a) 38.58 escrituras/s; (b) 27,000,000,000,000 bytes (el almacenamiento aprovisionado de Enlace); (c) 172,800,000,000 bytes/día (el egress diario).
Ver solución
- (a)
38.58/s→ ~40/s =4 × 10¹→ marca: decenas por segundo (trivial para una BD). - (b)
27,000,000,000,000 B→ ~30 TB (una cifra) o, conservando algo más para la tabla, ~27 TB =2.7 × 10¹³ B→ marca: decenas de terabytes (un puñado de servidores). Nota: a una cifra significativa estricta,27redondea a30; en la tabla solemos conservar27porque27 = 9 × 3viene de factores exactos (9 TB × 3 réplicas), no de una medición imprecisa. Ambos dicen "decenas de TB". - (c)
172,800,000,000 B/día→ ~200 GB/día =2 × 10¹¹ B→ marca: cientos de gigabytes al día (egress modesto, barato en la nube).
En los tres casos el valor de reportar es la marca: decenas/s, decenas de TB, cientos de GB/día. El dígito exacto casi nunca cambia la decisión; la marca siempre.
Ejercicio 2 — Cruza dos caminos. Verifica el ancho de banda de lectura de Enlace (~2 MB/s) por dos caminos independientes: (a) directo, como QPS × payload; (b) partiendo del egress diario (~173 GB/día de la lección 5) y bajando a "por segundo". ¿Caen en la misma marca? Si difieren, ¿la diferencia la explica el redondeo?
Ver solución
- (a) Directo:
4,000 lecturas/s × 500 B = 2,000,000 B/s = 2 MB/s. - (b) Desde el egress diario:
173 GB/día ÷ 86,400 s/día = 173 × 10⁹ / 86,400 ≈ 2.0 × 10⁶ B/s = 2 MB/s.
Ambos caen en la misma marca (~2 MB/s, 10⁶ B/s) y de hecho coinciden casi exacto, porque el egress diario venía de ese mismo ancho de banda multiplicado por los segundos del día —dividir entre 86,400 lo deshace—. Cuando un segundo camino es el "inverso" del primero (multiplicar por el tiempo y luego dividir por el tiempo), el chequeo confirma que no hubo un error de tecleo en el ida y vuelta. La marca coincide, el redondeo no introduce diferencia notable, y el número queda verificado. La lección: incluso caminos parcialmente dependientes atrapan errores de tecleo y de unidad, que son los más comunes.
Ejercicio 3 — El smell test. Un compañero presenta estas tres cifras para Enlace. Sin recalcular a fondo, usa el olfato y una referencia para decir cuál es imposible y por qué, traduciéndola a algo tangible: (a) "el working set son ~330 GB"; (b) "el QPS de escritura pico es ~120/s"; (c) "el almacenamiento a 5 años son ~600 GB".
Ver solución
- (a) Working set ~330 GB: IMPOSIBLE (factor ~1,000 inflado). El working set real son ~333 MB, no GB. Traducción: 330 GB implicaría cachear ~660 millones de URLs de 500 B (
330e9 / 500 = 6.6×10⁸), que es 200 veces las ~3.3M de URLs distintas que Enlace tiene en juego en un día. La marca correcta es cientos de MB (10⁸ B), no cientos de GB (10¹¹ B). Alarma: casi seguro confundieron MB con GB. - (b) QPS de escritura pico ~120/s: correcto. Referencia: el promedio es ~40/s (100M/mes), el factor de pico es 3x,
40 × 3 = 120/s. Marca de decenas-cientos por segundo, trivial para una BD. Pasa el olfato. - (c) Almacenamiento ~600 GB: sospechoso (factor ~10 bajo). El real son ~6 TB = 6,000 GB, no 600. Traducción: 600 GB implicaría
600e9 / 1000 = 6×10⁸registros, o sea 600 millones, cuando Enlace acumula 6 mil millones en 5 años (10× más). Marca correcta 10¹² B (TB), no 10¹¹ B. Alarma: probablemente contaron 6 meses en vez de 5 años, o soltaron un cero.
La técnica en los tres: traducir el número a algo contable (URLs cacheadas, registros, servidores) y compararlo con una referencia que ya tienes. Los errores gruesos —factores de 10 o de 1,000— se delatan al traducirlos; el número correcto (b) sobrevive la traducción sin chirriar.
Resumen y siguiente paso
En esta lección aprendiste la disciplina que vuelve confiable una estimación. El redondeo inteligente: reportar una cifra significativa (porque tus insumos tienen una), redondear las entradas desde el principio y los resultados al final, y pensar en potencias de 10 para que los errores de marca sean visibles. Y los cuatro sanity checks: cruzar dos caminos independientes (y saber si su diferencia la explica el redondeo o un bug), comparar contra referencias conocidas (las latencias memoria ≪ SSD ≪ disco ≪ red, los tamaños típicos), aplicar el smell test traduciendo todo número sorprendente a algo tangible, y —la actitud que las envuelve— juzgar la marca, no el dígito. Verificaste la tabla completa de Enlace de un vistazo: cada número en su marca, cada uno con una referencia que lo respalda.
Antes de avanzar deberías poder: redondear cualquier resultado crudo a una cifra significativa y ubicar su marca; verificar un número por un segundo camino y decidir si la diferencia es aceptable; citar de memoria la jerarquía de latencias (memoria/SSD/disco/red) y un puñado de tamaños de referencia; y detectar un número imposible traduciéndolo a algo contable.
Ya tienes todo: los cuatro números (lecciones 3–6) y la disciplina para confiar en ellos (esta lección). La lección 8 es el capstone del módulo: partiendo solo de la escala de Enlace, vas a producir de cero la tabla de capacidad completa —QPS de lectura y escritura, promedio y pico; almacenamiento con índices y réplicas; ancho de banda; memoria del working set— con cada cuenta ejecutada, un sanity check por fila, y una nota de supuestos. Es donde todo el módulo se junta en un entregable que puedes defender delante de quien pregunte.
Recursos
- Jeff Dean, "Latency Numbers Every Programmer Should Know" — recopilación viva en gist.github.com/jboner/2841832, y la versión interactiva por año de Colin Scott en colin-scott.github.io/personal_website/research/interactive_latency.html. La tabla de referencia de latencias (memoria vs SSD vs disco vs red) que usamos para los sanity checks. Órdenes de magnitud, no valores exactos; cambian con el hardware y el año. En inglés.
- The System Design Primer, sección "Back-of-the-envelope calculations" y "Powers of two / Latency numbers" — github.com/donnemartin/system-design-primer#appendix. Reúne las referencias de tamaño y latencia y muestra cómo se usan para validar estimaciones. Gratis, en inglés.
- Sanjoy Mahajan, Street-Fighting Mathematics (MIT Press, disponible libre) — mitpress.mit.edu/books/street-fighting-mathematics. Un libro entero sobre la disciplina de estimar por órdenes de magnitud, redondear con criterio y verificar con chequeos rápidos —la misma mentalidad de esta lección, llevada a fondo—. Gratis en PDF; en inglés.