Por qué elegimos WebAssembly antes que APIs en la nube
Por qué elegimos WebAssembly antes que APIs en la nube
Una noche, ya tarde, nuestro equipo miraba una hoja de cálculo con facturas de la nube e histogramas de latencia. Cada pico de tráfico significaba otra conversación sobre autoscaling, cold starts y si de verdad necesitábamos enviar PDFs al otro lado del océano solo para fusionar dos páginas. Esa noche nos hicimos una pregunta simple: ¿y si el navegador pudiera hacer el trabajo pesado?
El momento que cambió nuestra arquitectura
Ai2Done nació de la convicción de que las herramientas de productividad no deberían exigirte confiar en un servidor de terceros para tus contratos, facturas o fotos familiares. Las APIs en la nube son potentes, pero introducen una dependencia permanente: tus bytes salen de tu máquina, atraviesan redes que no controlas y aterrizan en discos que nunca auditarás. Para muchos flujos eso es aceptable; para nuestros usuarios era inaceptable.
WebAssembly nos dio un camino creíble para ejecutar código real — compilado desde Go, el mismo lenguaje que usamos en el servidor — dentro de la pestaña del usuario. En lugar de esbozar un cliente fino que sube archivos a una caja negra, podíamos enviar un binario portable que se ejecuta localmente, con rendimiento predecible y sin sorpresas en las facturas de egress.
¿Por qué no "simplemente" usar JavaScript?
Amamos JavaScript para UI y orquestación, pero mover megabytes de lógica de PDF o de criptografía a JS escrito a mano habría sido más lento de entregar y más difícil de mantener sincronizado con nuestro tooling Go. WASM nos permite reutilizar librerías probadas en batalla (piensa en pipelines tipo pdfcpu) y compartir tipos y tests por todo el stack. El navegador se convierte en un host, no en un objetivo de reescritura.
Un puente mínimo en JS carga el módulo .wasm, pasa file handles y callbacks de progreso, y renderiza resultados. El resto se queda en Go:
// Forma conceptual: WASM expone una API delgada; el trabajo real vive en internal/tools.
func ProcessPDF(input []byte) ([]byte, error) {
// fusionar, dividir, cifrar — todo determinista, todo local
return merged, nil
}
Lo que ganamos
Privacidad por construcción. Cuando el procesamiento sucede en WASM, no necesitamos una política de privacidad que diga "podríamos procesar tus archivos" — podemos decir "no podemos", porque los bytes nunca abandonan el dispositivo. Eso no es marketing; es física.
Latencia donde importa. Para operaciones por lotes, el round-trip de red suele dominar. WASM local elimina esa variable por completo. Las barras de progreso reflejan trabajo real de CPU, no la profundidad de cola en la región de otra persona.
Predictibilidad de costes. Nuestra factura de infraestructura escala con el tráfico al sitio, no con los gigabytes de documentos del usuario. Esa alineación nos mantiene centrados en la calidad del producto en vez de en medir cada conversión.
Compromisos que aceptamos con honestidad
WASM no es gratis. El tamaño de descarga inicial importa, así que comprimimos con Brotli, hacemos lazy-load por herramienta y fijamos límites de archivo sensatos para que los usuarios reciban mensajes amables en vez de caídas de pestaña. Los topes de memoria del navegador son reales; los documentamos y mostramos el progreso para que los usuarios sepan que la app está trabajando, no congelada.
Seguimos usando el servidor para lo que le toca: autenticación, indexación de búsqueda y entrega de assets estáticos. La división es intencional: servidor para identidad y descubrimiento, cliente para transformación.
Mirando hacia adelante
Elegir WASM en lugar de APIs en la nube no fue una apuesta en contra de la nube — fue una apuesta por la soberanía del usuario. Cada vez que lanzamos una herramienta nueva nos preguntamos si puede correr localmente primero. Esa disciplina mantiene a Ai2Done rápida, honesta y alineada con las personas que confían en ella cada día. Si construyes en este espacio, esperamos que nuestro camino te dé permiso para cuestionar el pipeline por defecto de subir-para-procesar — y para dejar que el navegador haga más de lo que se le suele reconocer.