Cómo construimos nuestra arquitectura de microservicios
Dirora es API-first, construida sobre más de 40 microservicios en Go: un servicio por dominio, cada uno responsable de una porción concreta de la plataforma de comercio: productos, pedidos, pagos, escaparates, suscripciones, analítica y mucho más. Este artículo es un recorrido honesto y de alto nivel por las decisiones que hay detrás de ese backend: por qué elegimos las herramientas que elegimos, cómo evitamos que decenas de piezas móviles se conviertan en un caos, y qué le diríamos a cualquier equipo que construya un producto SaaS multitenant desde cero. Está escrito para ingenieros que sienten curiosidad por lo que hay bajo el capó, pero debería entenderse aunque nunca hayas escrito una línea de Go.
Nada de esto es arquitectura por el gusto de la arquitectura. Cada decisión que sigue se remonta a algo que el comerciante percibe: páginas que cargan rápido, procesos de compra que no cobran dos veces, subidas de archivos que nunca se quedan sin espacio, y una plataforma que sigue funcionando mientras publicamos cambios por debajo. Si quieres ver cómo se traducen esos cimientos en lo que realmente puedes hacer con una tienda, nuestra visión general de funciones es el complemento de este artículo orientado al comerciante.
¿Por qué Go?
Al principio evaluamos en serio tres lenguajes —Node.js, Rust y Go— porque la elección del entorno de ejecución condiciona todo lo que viene después. Cada uno tenía virtudes reales y ninguno era un perdedor evidente.
Node.js tiene un ecosistema enorme, una amplia bolsa de talento para contratar y una sintaxis familiar para cualquiera que haya escrito código frontend. Pero el trabajo intensivo en CPU —procesamiento de imágenes, cifrado, generación de informes grandes— compite con la gestión de peticiones en un bucle de eventos de un solo hilo, y la falta de seguridad de tipos en tiempo de ejecución tiende a manifestarse como errores sutiles en producción en lugar de errores en tiempo de compilación.
Rust ofrece un rendimiento de primer nivel y seguridad de memoria sin recolector de basura. Los compromisos en nuestra etapa eran tiempos de compilación más lentos, una curva de aprendizaje más pronunciada para los nuevos colaboradores y un ecosistema asíncrono que aún se estaba asentando cuando empezamos. Para un núcleo de sistemas, Rust es soberbio; para una gran superficie de lógica de negocio ordinaria que cambia cada semana, el coste nos pareció alto.
Go nos dio un modelo de concurrencia que es genuinamente agradable de usar —las goroutines son lo bastante baratas como para lanzar miles sin pensar en pools de hilos—, además de tiempos de compilación rápidos y un lenguaje deliberadamente pequeño que los ingenieros nuevos pueden leer y al que pueden contribuir en cuestión de días. Su biblioteca estándar cubre la mayor parte de lo que necesita un backend web sin arrastrar una dependencia para cada tarea.
Go ganó porque optimiza lo que más importa cuando construyes con amplitud y avanzas rápido: la velocidad de desarrollo sin renunciar al rendimiento en tiempo de ejecución. Una base de código pequeña y legible por la que un ingeniero nuevo puede moverse al segundo día vale más, a lo largo de la vida de un producto, que exprimir el último puñado de puntos porcentuales de rendimiento. Ese backend en Go de alto rendimiento es también la razón por la que nuestros escaparates se renderizan rápido bajo carga, algo que profundizamos en nuestra guía sobre optimización del rendimiento de la tienda.
Un servicio por dominio
El principio organizador central es sencillo: cada servicio es dueño de exactamente un dominio de negocio, y es dueño de su propio esquema de base de datos. El servicio de productos posee los productos; el servicio de pedidos posee los pedidos; pagos, suscripciones, renderizado de escaparates, analítica y el resto viven cada uno tras su propia frontera. Ningún servicio accede a las tablas de otro servicio. Si el servicio de pedidos necesita datos de productos, se los pide al servicio de productos a través de una interfaz definida: nunca ejecuta una consulta directamente contra las tablas de productos.
Este aislamiento es la disciplina que mantiene mantenible un sistema en crecimiento. Como nadie puede depender de forma silenciosa de la forma interna de las tablas de otro, podemos refactorizar el almacenamiento de un servicio, cambiar sus índices o rehacer su lógica sin romper otros cinco servicios por accidente. La frontera es el contrato. Cuesta un poco más al principio —escribes una API donde un monolito escribiría un join— pero se amortiza cada vez que un dominio necesita evolucionar de forma independiente. Como la plataforma es API-first, esos mismos servicios de dominio se exponen a los desarrolladores a través de una API REST pública, webhooks neutrales respecto al proveedor, una CLI y el editor de temas: las aplicaciones de escaparate y de administración son simplemente clientes de la misma API sobre la que puedes desarrollar. Si estás construyendo sobre Dirora, nuestro artículo sobre comercio API-first y headless cubre esa faceta orientada al desarrollador.
Cómo se comunican los servicios entre sí
Los servicios se comunican por HTTP usando JSON, autenticados para las llamadas internas de servicio a servicio con una clave interna compartida. Elegimos REST en lugar de protocolos binarios más pesados de forma deliberada, al menos mientras el sistema tomaba forma: cada endpoint es inspeccionable con herramientas corrientes, fácil de razonar y sencillo de depurar cuando algo se comporta mal a las 2 de la madrugada. Tiene un valor real poder reproducir a mano una llamada de producción en lugar de necesitar herramientas especiales para descodificarla.
Cuando dos servicios necesitan de verdad mantenerse sincronizados —un pedido que se paga, una suscripción que se renueva— nos apoyamos en eventos y webhooks en lugar de en cadenas de llamadas síncronas y acopladas. La regla a la que volvemos una y otra vez es que una petición no debería ramificarse en una larga cadena de dependencias donde un servicio lento arrastre todo lo que hay aguas arriba. El acoplamiento débil no es solo un tópico de arquitectura; es lo que impide que un tropiezo en un rincón de la plataforma se convierta en una caída general.
Acceso a datos con seguridad de tipos y migraciones versionadas
Para el acceso a la base de datos generamos código Go con seguridad de tipos a partir de SQL escrito a mano, en lugar de recurrir a un ORM pesado. Escribir nosotros mismos el SQL mantiene las consultas transparentes y ajustables, mientras que la generación de código detecta clases enteras de errores —una columna renombrada, un tipo equivocado, un argumento que falta— en tiempo de compilación en lugar de en producción. Es el punto óptimo entre las consultas en cadenas de texto y un ORM que oculta lo que realmente sucede.
Los cambios de esquema pasan por migraciones versionadas y de solo avance. Cada cambio en la base de datos es un paso numerado y revisado que puede aplicarse de forma predecible en todos los entornos, de modo que el esquema que hay delante de un cliente nunca es un misterio. Combinado con la propiedad por servicio, esto significa que cada equipo puede hacer evolucionar su propio modelo de datos a su propio ritmo sin una gigantesca publicación coordinada.
Multitenencia sin el problema del vecino ruidoso
Dirora es multitenant por diseño: muchas tiendas independientes comparten la misma plataforma manteniéndose estrictamente aisladas unas de otras. Lograr bien ese aislamiento —de modo que una tienda con mucho tráfico nunca pueda ver, ralentizar ni afectar a otra— es una de las partes más difíciles e importantes del sistema, y merece su propio tratamiento. Escribimos sobre el modelo en detalle en cómo gestionamos la multitenencia, donde explicamos cómo fluye la identidad del inquilino por toda la pila y cómo mantenemos los datos de cada tienda amurallados.
El mismo diseño permite que una única tienda opere a través de fronteras —varias divisas, varios idiomas y escaparates localizados— sin bifurcar los servicios subyacentes. Si eso es relevante para tu negocio, nuestra guía multidivisa y multiidioma y el artículo sobre la traducción con IA en un clic muestran cómo se ve eso desde el lado del comerciante.
Arquitectura de almacenamiento
Todos los archivos subidos —imágenes de productos, recursos de temas, descargas digitales— viven en almacenamiento de objetos privado compatible con S3, y no en el disco de un único servidor. El diseño tiene en cuenta la capacidad: los recursos de cada tienda están lógicamente separados, y un paso de selección dirige las nuevas subidas hacia el almacenamiento con más margen disponible, de modo que podemos ampliar la capacidad de forma fluida a medida que los comerciantes añaden más productos y contenido multimedia. Los recursos a nivel de sistema se mantienen separados de los datos de los inquilinos.
La consecuencia práctica para los comerciantes es que el almacenamiento no es un muro con el que chocas. Subir imágenes no compite con el tráfico en vivo de tu tienda, los archivos se sirven de forma eficiente, y la plataforma puede escalar su huella de almacenamiento entre bastidores sin caídas ni una migración que llegues a notar. La optimización automática de imágenes se apoya sobre esto para que las fotos grandes que subes se sirvan en versiones de tamaño adecuado y carga rápida.
Renderizar escaparates rápido
Los escaparates de cara al cliente se renderizan en el servidor, lo que significa que lo primero que recibe el navegador del comprador es HTML real y listo para mostrarse, en lugar de una página en blanco esperando a JavaScript. Eso importa por dos razones: es más rápido para el comprador y es legible para los motores de búsqueda, lo que explica en buena parte por qué los escaparates de Dirora vienen con sólidos cimientos de SEO y datos estructurados integrados. La velocidad no es una métrica de vanidad en el comercio: está directamente ligada a cuántos visitantes se convierten en compradores.
Observabilidad y fiabilidad
No puedes operar un sistema distribuido que no puedes ver, así que las métricas, el registro estructurado y el seguimiento de errores formaron parte de la plataforma desde el principio, en lugar de añadirse a posteriori. Cuando algo va mal en una docena de servicios, la diferencia entre una solución de cinco minutos y una investigación de cinco horas depende casi por completo de si invertiste en observabilidad antes de necesitarla.
La fiabilidad también proviene de una disciplina sencilla y poco glamurosa: haz que todo sea idempotente. Los manejadores de webhooks, los trabajos en segundo plano, las devoluciones de llamada de pagos y las migraciones se escriben todos de modo que ejecutarlos dos veces sea seguro. Las redes reintentan, los mensajes se reentregan y los usuarios hacen doble clic. Asumir que cada operación podría ocurrir más de una vez —y asegurarse de que no haga daño cuando ocurra— es lo que evita pedidos duplicados, cobros dobles y estados corruptos.
Qué significa esto para los comerciantes
La arquitectura es invisible cuando funciona, que es justo lo que se busca. La recompensa de todo lo anterior es una plataforma que se mantiene rápida bajo carga, mantiene aislados los datos de cada tienda y nos permite publicar mejoras de forma continua sin pedirte que migres nada. Es también lo que nos permite mantener limpio nuestro modelo comercial: Dirora no cobra comisiones por transacción en ningún plan. Lo único que nos llevamos es una pequeña tarifa de plataforma que disminuye a medida que creces —1,5 % en el plan gratuito Starter, 0,75 % en Pro, 0,25 % en Business y 0 % en Enterprise— de modo que cuanto más vendes, menos nos llevamos. La buena ingeniería es lo que hace que un modelo de precios justo y sencillo sea sostenible en lugar de una promesa de marketing que no podemos cumplir.
Lecciones aprendidas
Invierte en cimientos compartidos. Una biblioteca interna común para middleware, gestión de errores, ayudantes de base de datos, almacenamiento y comprobaciones de estado hace que cada servicio se comporte de forma coherente. A escala, la coherencia entre servicios vale más que la independencia de cada equipo.
Prefiere el acceso a datos generado y con seguridad de tipos. Escribir SQL a mano y generar código tipado a partir de él es más rápido de manejar y más seguro que las consultas en cadenas de texto en bruto o un ORM pesado.
Añade observabilidad antes de necesitarla. Las métricas, los registros estructurados y el seguimiento de errores desde el primer día ahorran mucho más tiempo del que cuestan. No puedes depurar lo que no puedes ver.
Haz que todo sea idempotente. Si una operación puede ejecutarse dos veces —y en un sistema distribuido acabará ocurriendo— haz que ejecutarla dos veces sea inofensivo.
Traza fronteras y defiéndelas. Un dominio por servicio, un esquema por servicio, sin saltar el muro. La disciplina es molesta el primer día e impagable el día doscientos.
Si quieres ver la plataforma que produjeron estas decisiones —desde el editor visual de temas hasta los dominios personalizados con SSL automático— la página de funciones es el lugar por donde empezar, y si nos estás comparando con alternativas, nuestra honesta comparativa de plataformas expone los compromisos.
Preguntas frecuentes
¿En qué lenguaje está escrito el backend de Dirora?
El backend de Dirora está construido en Go, organizado como una plataforma API-first de más de 40 microservicios —uno por dominio— sobre los que los desarrolladores pueden desarrollar a través de una API REST pública. Elegimos Go por su concurrencia ligera, sus tiempos de compilación rápidos y su base de código legible, que juntos nos permiten construir una plataforma amplia con rapidez sin sacrificar el rendimiento en tiempo de ejecución.
¿Por qué usar microservicios en lugar de una única aplicación?
Dividir la plataforma en más de 40 servicios por dominio —productos, pedidos, pagos, escaparates, etc.— significa que cada parte puede evolucionar, escalar y arreglarse de forma independiente sin poner en riesgo al resto. Cada servicio es dueño de su propio esquema de base de datos y nunca consulta directamente las tablas de otro servicio, lo que mantiene el sistema mantenible a medida que crece y nos permite exponer toda la plataforma a través de una única API REST pública coherente.
¿Dónde se almacenan las imágenes y los archivos de mi tienda?
Los archivos subidos viven en almacenamiento de objetos privado compatible con S3, con los recursos de cada tienda lógicamente separados y la capacidad gestionada automáticamente. El almacenamiento escala entre bastidores, de modo que subir más productos y contenido multimedia nunca compite con el tráfico en vivo de tu escaparate.
¿Cómo mantiene Dirora aisladas las distintas tiendas entre sí?
Dirora es multitenant por diseño, con un aislamiento estricto para que una tienda nunca pueda ver ni afectar a los datos o el rendimiento de otra. Cubrimos los detalles en nuestro artículo dedicado sobre cómo gestionamos la multitenencia.
¿Afecta esta arquitectura a lo que pago?
Sí, para bien. Dirora no cobra comisiones por transacción en ningún plan. Lo único que nos llevamos es una pequeña tarifa de plataforma que disminuye a medida que creces: 1,5 % en Starter, 0,75 % en Pro, 0,25 % en Business y 0 % en Enterprise. La ingeniería eficiente es lo que hace sostenibles esos precios.