- Separar apresuradamente el código en microservicios en una startup temprana provoca una fuerte caída en la productividad del equipo y un aumento de la complejidad
- La arquitectura monolítica ofrece una implementación simple, lanzamiento rápido de nuevas funciones y optimización para sobrevivir mediante colaboración eficiente
- Los microservicios solo aportan ventajas de separación cuando existe escalabilidad a gran escala, cargas de trabajo distintas o requisitos de runtime separados
- La separación excesiva de servicios, la proliferación de repositorios, los entornos locales de desarrollo inestables y la falta de coherencia en el stack técnico se traducen en menor velocidad y peor moral del equipo
- Las startups deberían empezar con un monolito y separar solo cuando aparezcan cuellos de botella claros
Introducción y contexto
- La supervivencia de una startup depende de iterar rápido, entregar nuevas funciones y crear valor para los usuarios
- La arquitectura base del proyecto, el stack técnico y la elección del lenguaje de programación influyen en la velocidad del equipo
- Adoptar microservicios demasiado pronto puede verse elegante en teoría, pero en la práctica causa pérdida de productividad, servicios incompletos y exceso de complejidad
- Datos: aparecen muchos costos de desarrollo, como orquestación de servicios, problemas con Docker/scripts, CI/CD duplicado, acoplamiento entre servicios, costos de observabilidad y pruebas dispersas
- En vez de lanzarse sin cuidado a una arquitectura compleja, se resalta la importancia de una arquitectura pragmática
Fortalezas del monolito
- Ya sea un SaaS o un simple wrapper de base de datos, con el tiempo una app se vuelve compleja, pero la arquitectura monolítica es más fácil de mantener simple y flexible
- Es fácil de desplegar y se beneficia del soporte de frameworks populares como Django, ASP.Net y Nest.js, además de grandes comunidades open source
- Caso real: en una startup inmobiliaria, un monolito en Laravel permitió lograr con facilidad numerosas integraciones con terceros y ampliaciones funcionales
- Sin introducir infraestructura compleja ni dividir en microservicios, fue posible enfocarse en cumplir las necesidades del negocio y las expectativas
- Lección: la simplicidad de la arquitectura ayuda al equipo a concentrarse en desplegar, y mientras se evite fallar en la modularización interna, la escala puede ser suficiente
¿Los microservicios son siempre la mejor opción?
- Muchos ingenieros creen que los microservicios son la respuesta correcta, pero en realidad brillan solo cuando hay razones especiales, como escalabilidad
- Con pocos integrantes, poco tamaño y una etapa de cambios rápidos, suelen producir el efecto contrario: infraestructura duplicada, desarrollo local lento y ciclos de iteración más lentos
- Incluso empresas como Segment pasaron por transiciones provocadas por estructuras ineficientes
- Lección: los microservicios son una herramienta para resolver cuellos de botella, no una plantilla para el inicio
Por qué los microservicios fallan especialmente en etapas tempranas
1. Límites de servicio arbitrarios
- Al intentar dividir servicios por lógica de negocio tomando ideas de domain-driven design y clean architecture, los límites entre la lógica real y los servicios no terminan alineándose bien
- Ejemplo: separar usuarios, autenticación y permisos aumenta la complejidad del despliegue y la dificultad para desarrollar APIs
- Separar en una etapa en la que aún no existe un cuello de botella real vuelve el sistema inestable y lento
- Simular separaciones futuras con flags o toggles internos y explorar límites de manera orgánica resulta más efectivo que apresurarse con trabajo de infraestructura
- Lección: decidir separaciones en función de cuellos de botella reales, no de teoría
2. Exceso de repositorios e infraestructura
- El estilo de código, las pruebas, la configuración, la documentación y el CI/CD se multiplican según el número de servicios
- Si se usa una estructura de monorepo, toda la configuración puede gestionarse en un solo lugar, mejorando la consistencia del código y la colaboración
- En Node.js, herramientas como
nx o turborepo facilitan la gestión de dependencias y builds entre servicios internos
- Entre las desventajas están relaciones de dependencia complejas, necesidad de ajustar el rendimiento del CI y de herramientas de build más rápidas
- En el ecosistema de Go también puede administrarse todo en un solo workspace al principio, y recién al crecer evaluar separar módulos
- Lección: un equipo pequeño puede ganar tiempo con un monorepo y una infraestructura compartida
3. Entorno local de desarrollo inestable
- Tiempos excesivos para correr localmente, scripts complejos y dependencias específicas del sistema generan demoras en onboarding y menor productividad
- La falta de documentación, problemas de compatibilidad y hacks específicos de un OS, como scripts solo para macOS, se vuelven obstáculos
- En un proyecto, usar un proxy de Node.js alivió la complejidad de Docker y redujo el tiempo de onboarding de desarrolladores
- Lección: si la app solo corre en un sistema operativo, la productividad del equipo termina dependiendo de la confiabilidad de una sola laptop
4. Desalineación del stack técnico
- Node.js y Python son buenos para iterar rápido, pero en entornos de microservicios aparecen con frecuencia problemas de desajuste entre build y runtime
- Go ofrece ventajas con binarios estáticos, builds rápidos y simplicidad operativa
- Hay que elegir el stack técnico con cuidado desde el inicio y, si hace falta, mezclar lenguajes mediante protocolos como gRPC
- Salvo requerimientos especiales como ML o ETL, mezclar stacks solo aumenta la complejidad
- Lección: elige un stack que se ajuste a la realidad del equipo, no al ideal soñado
5. Complejidad oculta: comunicación y monitoreo
- En microservicios son indispensables service discovery, versionado de APIs, distributed tracing y gestión centralizada de logs
- Seguir bugs e incidentes en un monolito puede resolverse con un stack trace; en un entorno distribuido es mucho más complejo
- Para hacerlo bien, hace falta adoptar herramientas especializadas como OpenTelemetry y construir un stack de observabilidad
- Hay que entender que los sistemas distribuidos implican una inversión obligatoria en desafíos extra de ingeniería
Cuándo sí tienen sentido los microservicios
- Aislamiento de cargas de trabajo: separar tareas asíncronas específicas como procesamiento de imágenes u OCR puede ser eficiente
- Desequilibrio en necesidades de escalado: si una web API y una carga de ML requieren hardware y operación distintos, conviene separarlas
- Necesidad de otro runtime: componentes que no son compatibles con el runtime principal, como código legado en C++, pueden mantenerse como servicios separados
- Viendo casos de grandes organizaciones de ingeniería, como Uber, solo encajan cuando existe una necesidad organizacional clara y capacidad operativa madura
- Incluso en equipos pequeños, en raras ocasiones separar algo como un servicio externo de analítica puede ser práctico si su gestión es simple
- Lección: adoptar microservicios solo en cargas de trabajo donde el beneficio de separar sea realmente claro
Guía práctica para startups
- Empieza con un monolito y trabaja con frameworks probados para enfocarte en sacar el trabajo adelante
- Un repositorio único beneficia más a un equipo inicial en eficiencia operativa, administración y seguridad
- Simplificar el entorno local de desarrollo es clave; si resulta difícil, es indispensable ofrecer documentación y videos detallados
- Hay que invertir temprano en CI/CD para automatizar tareas repetitivas y reducir la carga mental del equipo
- Separa selectivamente solo cuando aparezcan cuellos de botella claros; de lo contrario, enfócate en modularizar dentro del monolito y fortalecer las pruebas
- El objetivo principal es mantener la velocidad de desarrollo
- Lección: empieza por la simplicidad y escala según la necesidad real de separar
Si de verdad tienes que usar microservicios
- Evaluar el stack técnico e invertir en herramientas de experiencia de desarrollador: hacen falta automatización por servicio, scripts claros y herramientas unificadas de gestión de despliegues
- Protocolos confiables y estandarización para la comunicación entre servicios: hay que considerar consistencia de esquemas de mensajes, documentación y manejo de errores
- Estabilizar la infraestructura de pruebas: las pruebas unitarias, de integración y E2E deben escalar de acuerdo con la separación de servicios
- Considerar librerías compartidas: el código común de observabilidad y comunicación debe mantenerse al mínimo para evitar rebuilds frecuentes de todos los servicios
- La observabilidad debe introducirse temprano: empezar por herramientas básicas como logs JSON estructurados e IDs de correlación
- En resumen, si se va a aceptar la complejidad, es importante diseñar un sistema gestionable y tratarla con total seriedad
Conclusión
- Adoptar microservicios de forma apresurada solo agrega carga, así que la simplicidad debe ser la prioridad
- No se debe separar nada sin puntos de dolor claros; lo importante es añadir solo la complejidad mínima necesaria para sobrevivir y crecer
- Primero hay que sobrevivir; escalar viene después
10 comentarios
En general, estoy de acuerdo con el texto original.
Creo que es un tema de experiencia de la organización.
Puede ayudar imaginar que pasas de vender comida en un food truck a convertirte en un restaurante.
Desde el principio, simplemente falta de manera absoluta la experiencia de las partes involucradas como para pensar en división del trabajo y especialización.
Creo que las startups deberían elegir métodos de menor costo para extender su tiempo de supervivencia. Los microservicios para nada son baratos. De hecho, cuando se aplican en la práctica, generan costos considerables. Siempre que sea posible, considero que diseñar una arquitectura que se ajuste al propio servicio de la empresa es una forma de lograr un efecto similar con menos costo.
No es que los microservicios sean malos. Es un modelo que requiere muchos recursos.
Creo que basta con tener solo dos: un monolito solo síncrono y un monolito solo asíncrono... Pienso que adoptar microservicios depende, al final, de la escala de las tablas que hay que gestionar en la BD. Si la cantidad de tablas es absurdamente grande y compleja, hay que considerar una arquitectura de microservicios; si es simple, el monolito es lo ideal.
Cuando todas estas olas hayan pasado, ¿cómo recordarán las generaciones futuras a esta época?
En ese momento también había una ola propia de ese tiempo...
También creo que los microservicios tienen muchas ventajas en una startup. De entrada, recomiendo muchísimo las ventajas de usar un monorepo.
Estoy de acuerdo en que, en la era del desarrollo impulsado por IA, es indispensable implementar en unidades pequeñas y con responsabilidad única.
Como se comentó un poco también en los comentarios, la línea de beam/otp se ve bastante flexible y buena. En el caso de Gleam, al sumar la estabilidad de beam a las buenas características de sintaxis tanto de Go como de Rust, se ha convertido en un lenguaje bastante impresionante. Ya me dan ganas de empezar a probarlo poco a poco en proyectos pequeños.
Si divides el equipo sin control, incluso reunirse para intercambiar opiniones se vuelve una carga enorme de trabajo.
Opinión de Hacker News
rule) en una ley (law).