El árbol de decisión: las preguntas que eligen por ti
Elegir almacenamiento en el edge no se resuelve memorizando el catálogo de productos, sino interrogando la forma del dato y su patrón de acceso. Cinco preguntas en un orden deliberado —¿son bytes grandes?, ¿la base ya existe?, ¿hay que coordinar?, ¿la consulta describe un conjunto?, ¿basta con recuperar por clave?— convierten una decisión difusa en un árbol con hojas inequívocas. Por qué el orden importa, por qué las dos primeras preguntas son restricciones del mundo y no preferencias, cómo detectar las trampas de elegir por rasgo superficial, y por qué la respuesta honesta casi nunca es una sola pieza.
Llegas a este nivel con el catálogo entero en la cabeza: KV, R2, D1, Durable Objects, Hyperdrive. Sabes qué hace cada uno y aun así, frente a un proyecto nuevo, la elección se vuelve resbaladiza, porque casi cualquier pieza podría almacenar casi cualquier cosa si te empeñas lo suficiente. Ese es justamente el problema: la pregunta no es qué puede guardar cada producto, sino qué forma tiene tu dato y cómo se accede a él. Un árbol de decisión bien construido no te obliga a recordar cinco fichas técnicas; te hace cinco preguntas sobre tu propio problema y la herramienta cae sola.
- Formular las cinco preguntas que discriminan entre las piezas de almacenamiento.
- Entender por qué su orden no es arbitrario, sino de más a menos eliminatorio.
- Reconocer las trampas de elegir por rasgo superficial en vez de por forma del dato.
- Aceptar que la respuesta correcta suele ser varias piezas a la vez, no una sola.
Cinco preguntas y por qué van en ese orden
El orden de las preguntas obedece a un principio único: primero lo que excluye más, y dentro de eso, primero lo que no se puede cambiar después. Un buen árbol de decisión no es una lista de criterios bonitos, es una secuencia en la que cada paso reduce el espacio de opciones tanto como sea posible, de modo que el recorrido sea corto y el resultado no dependa del humor de quien lo recorre.
La primera pregunta es la más brutal y la que más candidatos elimina: ¿son bytes grandes u opacos? Un vídeo, una imagen original, un PDF, una copia de seguridad, un modelo entrenado, el fichero que sube un usuario. Si la respuesta es sí, la conversación se acaba: van a R2. No es una cuestión de gusto, es de física del sistema: KV admite hasta 25 MB por valor, D1 unos 2 MB por fila, el almacenamiento de un Durable Object trabaja con valores muy por debajo de eso. R2 acepta objetos de terabytes con subida por partes. Ninguna elegancia de diseño te salva de un límite duro.
El corolario práctico es que esta pregunta se contesta con una cifra, no con una intuición. Si el percentil alto del tamaño de tus elementos se mide en megabytes, ya sabes la respuesta; si se mide en kilobytes, la pregunta no aplica y pasas a la siguiente sin más deliberación.
La segunda pregunta tampoco es una preferencia tuya, sino una restricción que te impone el mundo: ¿ya existe una base relacional en producción? Con su esquema, sus migraciones de años, sus extensiones, su ORM y un equipo que la conoce. Si existe y no se va a mover —porque es enorme, porque hay cumplimiento normativo de por medio, porque migrarla sería un proyecto en sí mismo—, entonces no estás eligiendo dónde poner datos: estás eligiendo cómo alcanzarlos desde el edge, y esa es exactamente la pregunta que responde Hyperdrive.
La tercera entra ya en la semántica del acceso: ¿pueden dos peticiones concurrentes pelear por el mismo dato? Si el resultado depende del orden en que lleguen —un contador exacto, el último asiento libre, un lock, una sala en vivo, una cuota por usuario—, necesitas serialización sobre esa entidad, y eso solo lo da un Durable Object. Ni KV ni D1 te ofrecen un punto único donde el cómputo y el estado vivan juntos y las operaciones se ejecuten de una en una.
Merece la pena insistir en por qué esta pregunta va antes que la de las consultas, y no después. La coordinación es la única propiedad que no se puede añadir más tarde. Un índice se crea cuando descubres que hacía falta; una caché se pone el día que la latencia molesta; una réplica se activa cuando el tráfico crece. Pero un dato que necesitaba orden y no lo tuvo no se puede reparar retroactivamente, porque las escrituras que se pisaron no dejaron rastro. Todo lo que se puede añadir después va después en el árbol; lo que no, va antes.
La cuarta discrimina entre las dos piezas que más se confunden: ¿tu pregunta describe un conjunto o una clave? Si necesitas filtrar, ordenar, agregar o cruzar —los pedidos de este mes cuyo estado sea pendiente, ordenados por importe—, estás haciendo una consulta, y las consultas viven en D1. Si en cambio ya sabes la clave exacta antes de preguntar y solo quieres el valor que hay debajo, no necesitas un motor relacional.
Nótese que esta cuarta pregunta no se responde mirando cómo accedes hoy, sino cómo accederás cuando el producto madure. Casi todo empieza pareciendo una recuperación por clave —dame el usuario con este identificador— y casi todo termina necesitando una pregunta —dame los usuarios que no han entrado en treinta días—. Si las relaciones entre tus datos ya existen en el dominio, tarde o temprano alguien querrá consultarlas, y tenerlas en un motor que sabe recorrerlas cuesta mucho menos que descubrirlo después.
La quinta es, en realidad, el resto: ¿basta con recuperar un valor por su clave, muchísimas veces, tolerando que durante unos segundos sea el anterior? Ahí KV es imbatible, porque su lectura caliente se sirve desde el punto de presencia más cercano al usuario sin cruzar la red.
Conviene notar que las cinco preguntas no versan sobre el mismo plano. Las dos primeras hablan de restricciones: el tamaño de unos bytes y la existencia de un sistema previo. La tercera y la cuarta hablan de semántica: qué garantías necesita la operación y qué expresividad necesita la pregunta. La quinta no habla de nada, porque es el residuo, y ese lugar en la cola es deliberado: KV es la opción por defecto solo cuando todo lo demás ha fallado en excluirla, jamás porque sea la más rápida de poner en marcha.
| La pregunta | Si la respuesta es sí |
|---|---|
| ¿Son bytes grandes u opacos? | R2 |
| ¿La base relacional ya existe y no se mueve? | Hyperdrive |
| ¿Dos peticiones pueden pelear por el mismo dato? | Durable Objects |
| ¿La pregunta describe un conjunto, no una clave? | D1 |
| ¿Solo hay que recuperar un valor por su clave? | KV |
Fíjate en la asimetría del orden. Las preguntas uno y dos las responde la realidad: el tamaño de un vídeo no admite negociación y una base heredada tampoco desaparece porque a ti te apetezca otra arquitectura. Las preguntas tres, cuatro y cinco sí son decisiones de diseño, y por eso van después. Poner primero lo que no puedes cambiar evita gastar deliberación en caminos que ya estaban cerrados.
Antes de entrar en el árbol, pregúntate si ese dato necesita persistir. Una parte notable de lo que se guarda en producción es en realidad un cálculo que podría rehacerse, una respuesta que la caché del edge ya sabría servir, o un estado efímero que muere con la petición. El almacenamiento más rápido, más barato y más fácil de operar sigue siendo el que no existe, y descartar hechos falsos antes de clasificarlos es el paso que más simplifica una arquitectura.
El árbol, dibujado
flowchart TD A[bytes grandes u opacos] -->|si| R2[R2 objetos] A -->|no| B[ya existe una base relacional que no se mueve] B -->|si| HD[Hyperdrive acelera el origen] B -->|no| C[hay concurrencia sobre la misma entidad] C -->|si| DO[Durable Objects] C -->|no| D[la consulta describe un conjunto] D -->|si| D1[D1 con SQL] D -->|no| KV[KV clave valor] style R2 fill:#f9e2af,color:#11111b style HD fill:#89b4fa,color:#11111b style DO fill:#cba6f7,color:#11111b style D1 fill:#a6e3a1,color:#11111b style KV fill:#94e2d5,color:#11111b
El diagrama tiene una propiedad que conviene subrayar: no hay ramas que vuelvan atrás ni nodos que dependan de dos respuestas a la vez. Cada pregunta corta el espacio en dos mitades y descarta una para siempre, lo que significa que el recorrido termina siempre en cinco pasos como máximo y que la hoja alcanzada no admite recurso. Esa rigidez es una virtud: un criterio que permite reinterpretarse en cada bifurcación no es un criterio, es una excusa para elegir lo de siempre.
El árbol se recorre una vez por cada hecho que tu aplicación guarda, no una vez por aplicación. Esa distinción es la que separa una elección madura de una ingenua. Un mismo producto tiene decenas de hechos distintos —el vídeo de una lección, la fila que lo describe, el número de espectadores en directo, la bandera que activa una función— y cada uno entra por la raíz y sale por una hoja diferente.
En código, el resultado de haber recorrido el árbol varias veces se ve de golpe en el tipo de tu entorno, que es el mapa de decisiones ya tomadas:
interface Env {
MEDIA: R2Bucket; // bytes grandes: video, imagenes, copias
DB: D1Database; // el modelo relacional: usuarios, cursos, pedidos
SALA: DurableObjectNamespace; // coordinacion en vivo por entidad
CONFIG: KVNamespace; // lectura masiva, cambio raro, desfase tolerado
LEGACY: Hyperdrive; // el Postgres corporativo que no se mueve
}
Un ejemplo de recorrido múltiple lo deja claro. Una lección de un curso en vídeo produce cuatro hechos distintos que salen por cuatro hojas: el fichero de vídeo, que es bytes grandes y va a R2; la fila que lo describe con su título, su duración y su curso, que es una entidad relacionada y va a D1; el número de espectadores conectados ahora mismo, que exige un árbitro y va a un Durable Object; y la bandera que decide si esa lección está publicada para todos, que se lee en cada petición del planeta y va a KV. Un mismo objeto del dominio, cuatro decisiones independientes.
El resultado de recorrer bien el árbol nunca es una pieza, sino un reparto. Que D1 sea la respuesta para las entidades no descarta KV para la configuración, ni R2 para los bytes, ni un Durable Object para el aforo. Quien sale del ejercicio con una sola caja en el diagrama casi siempre ha recorrido el árbol una vez, para el proyecto, en lugar de una vez por hecho.
Las trampas de elegir por el catálogo
La trampa más común es elegir por el rasgo superficial que comparten. Los cinco guardan datos, luego cualquiera sirve, luego tomo el que mejor conozco. De ahí nacen las arquitecturas que se pudren despacio: el KV que simula una base de datos manteniendo listas de claves a mano y recorriéndolas con list en cada petición, reinventando peor un índice que D1 ya tiene; el D1 al que se le pide una configuración global un millón de veces por segundo, pagando una fila leída y un turno en un hilo único por cada lectura que KV habría servido desde la caché del punto de presencia.
Ese anti-patrón tiene una variante especialmente insidiosa, porque empieza siendo razonable. Alguien guarda un puñado de objetos en KV con claves compuestas, y funciona. Añade un segundo criterio de búsqueda y mantiene un segundo juego de claves espejo, y sigue funcionando. Añade un tercero, y ahora hay tres escrituras que deben ocurrir juntas sin que exista transacción alguna que lo garantice. Nadie tomó nunca la decisión de construir una base de datos a mano; se llegó ahí por acumulación de pasos individualmente sensatos, que es como se construyen casi todos los sistemas insostenibles.
La segunda trampa es elegir por la métrica equivocada. Preguntar cuál es más rápido o cuál es más barato antes de preguntar cuál encaja produce respuestas sin sentido, porque la velocidad y el coste solo son comparables dentro del mismo patrón de acceso. KV es más rápido que D1 para leer un valor por clave y es sencillamente incapaz de responder una consulta agregada. Comparar sus latencias sin fijar antes la pregunta es comparar un martillo con un destornillador por su peso.
La tercera trampa es más sutil y aparece en equipos con experiencia: elegir por inercia de otra plataforma. Es la más difícil de detectar porque no se manifiesta como una duda sino como una certeza, y las certezas no se someten a examen. Quien viene de un backend regional tiende a meterlo todo en la base relacional, porque allí eso era lo razonable —una sola base, un solo viaje, transacciones para todo—. En el edge esa costumbre convierte cada lectura trivial en una peregrinación a la primaria, y desperdicia justamente lo que la plataforma regala: la posibilidad de que el dato más leído viva a milisegundos del usuario.
Hay una cuarta trampa que merece mención aparte porque no es un error de elección sino de momento: decidir demasiado tarde. El almacenamiento es la parte más costosa de cambiar de cualquier sistema, no por el trabajo de mover bytes, sino porque toda la lógica que lo rodea asume su semántica. Un servicio que lleva un año contando con la consistencia fuerte de D1 no se muda a KV sin auditar cada lectura; un contador que lleva meses viviendo en KV no gana exactitud retroactiva al mudarse a un Durable Object, porque los incrementos que se perdieron no están en ningún sitio. Recorrer el árbol al principio cuesta media hora; recorrerlo después de haber elegido mal cuesta una migración.
Todas estas trampas comparten una raíz: sustituyen una pregunta difícil sobre el dominio por una fácil sobre la tecnología. Es un atajo mental barato y muy humano, porque la pregunta fácil tiene respuesta inmediata y la difícil obliga a admitir que aún no entiendes bien tu propio problema. El árbol no es más que un dispositivo para impedir esa sustitución: al obligarte a describir el dato antes de nombrar el producto, deja la pregunta difícil sobre la mesa hasta que la contestas.
No suele haber un error ni una caída; hay fricción. Escribes bucles para cruzar a mano datos que un JOIN resolvería. Mantienes a mano un índice invertido sobre claves de KV. Metes un switch gigante sobre un campo de estado para simular coordinación. Vigilas dos copias del mismo hecho rezando por que no diverjan. Cuando el código empieza a construir laboriosamente una capacidad que otra pieza da gratis, la elección estaba equivocada tres decisiones atrás.
La pregunta que el árbol no hace
El árbol nunca pregunta cuál es tu favorita, ni cuál conoce mejor el equipo, ni cuál sale más barata. No porque esas consideraciones sean ilegítimas —lo son, y mucho, a la hora de planificar—, sino porque solo tienen sentido después de haber acotado las opciones viables. Comparar el coste de dos piezas que resuelven problemas distintos es un ejercicio vacío; comparar el coste de dos formas de resolver el mismo problema es ingeniería. El árbol existe precisamente para llevarte del primer ejercicio al segundo.
Hay una segunda ausencia deliberada: el árbol no pregunta cuánto crecerá el sistema. Podría parecer una omisión grave, porque la escala es la obsesión clásica al elegir almacenamiento, pero en el edge esa pregunta ha cambiado de sitio. Ninguna de las cinco piezas se aprovisiona ni se dimensiona por adelantado; lo que sí varía con la escala es cuánto duele haber elegido mal, y por eso el criterio correcto sigue siendo la forma del dato. Un contador impreciso con cien usuarios es un detalle; con un millón es una incidencia. La escala no cambia la respuesta, cambia el precio de equivocarse.
Tampoco pregunta cuántas piezas quieres usar, y esa omisión también es intencionada. Existe una presión cultural, casi estética, hacia la simplicidad entendida como usar pocas cosas, y en el edge esa presión juega en contra: un sistema que mete cinco tipos de hecho distintos en un solo almacén no es más simple, solo ha trasladado la complejidad del diagrama al código, donde es más difícil de ver. La simplicidad real es que cada hecho esté en el sitio donde su modelo se explica en una frase.
Recorrer, no memorizar
El árbol se aplica a cada hecho, no al proyecto entero. La misma aplicación entra por la raíz una vez por cada tipo de dato que guarda.
La respuesta suele ser plural
Que una hoja gane para un hecho no descarta las demás para el resto. Una arquitectura sana casi siempre usa tres o cuatro piezas a la vez.
Decidir pronto es barato
El almacenamiento es lo más caro de cambiar, porque toda la lógica que lo rodea asume su semántica. Media hora de árbol al principio ahorra una migración después.
Queda una última observación sobre el uso del árbol, y es que su valor no está solo en el resultado sino en la conversación que fuerza. Un equipo que responde en voz alta las cinco preguntas descubre, casi siempre, que no estaba de acuerdo sobre el dominio: uno creía que el aforo era orientativo y otro que era vinculante, uno daba por hecho que el catálogo podía ir unos segundos por detrás y otro no. Esas discrepancias existían antes y habrían aparecido igualmente, pero mucho más tarde y en forma de incidente. El árbol no las crea, solo las adelanta al momento en que todavía son baratas.
Lo que distingue a un árbol de decisión de una tabla de características es que el árbol se interroga a sí mismo antes de interrogar al catálogo. Una tabla te dice qué hace cada producto y te deja a ti la parte difícil, que es traducir tu problema a esas columnas; el árbol invierte la dirección y te obliga a describir tu dato con precisión, de modo que la herramienta aparece como consecuencia y no como elección. Por eso el orden de las preguntas es la parte más importante y la que casi nadie mira. Las dos primeras no son preferencias sino restricciones del mundo —el tamaño de unos bytes y la inercia de un sistema que ya existe—, y ponerlas delante te ahorra deliberar sobre caminos que la realidad ya cerró. La tercera es la más profunda, porque pregunta por la concurrencia, que es la única propiedad que no se puede añadir después: un dato que necesita orden y no lo tiene no falla al escribirlo, falla más tarde y de forma intermitente, y ninguna caché ni ningún índice arreglan luego lo que faltó en el momento de la escritura. La cuarta separa recuperar de preguntar, dos verbos que el lenguaje coloquial confunde y que la ingeniería no debe confundir jamás: recuperar es seguir un puntero que ya tienes, preguntar es describir un conjunto que aún no conoces, y solo lo segundo necesita un motor relacional. La quinta es el residuo, y que sea la última tiene su gracia: KV es la opción por defecto solo cuando todas las restricciones anteriores han fallado en excluirla, nunca porque sea la más cómoda de empezar. Interiorizar este recorrido cambia la naturaleza de la pregunta que te haces frente a un proyecto. Dejas de preguntar qué base de datos uso, que es una pregunta sobre tecnología y por eso admite respuestas de moda, y empiezas a preguntar qué forma tiene cada hecho que voy a guardar y quién compite por él, que es una pregunta sobre tu dominio y por eso tiene una sola respuesta honesta. Cuando esa pregunta se hace bien, la elección de almacenamiento deja de ser una discusión de equipo y se vuelve casi mecánica; y lo que queda de trabajo intelectual se traslada al sitio donde de verdad hace falta, que es modelar bien el dominio.
- Enumera cinco hechos concretos que guarde una aplicación que conozcas y recorre el árbol con cada uno por separado.
- Explica por qué la pregunta sobre bytes grandes va la primera y no la última.
- Describe un caso donde la respuesta a la segunda pregunta cambie por completo la arquitectura sin que tú lo hayas decidido.
- Encuentra en un proyecto propio una fricción del tipo el código construye a mano lo que otra pieza daría gratis, y di qué hoja del árbol correspondía.
- Argumenta por qué comparar la latencia de
KVyD1sin fijar antes el patrón de acceso es una comparación vacía.