28 puntos por GN⁺ 2025-05-10 | 10 comentarios | Compartir por WhatsApp
  • 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

 
kuil09 2025-05-12

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.

 
dhlee0305 2025-05-12

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.

 
mhj5730 2025-05-12

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.

 
roxie 2025-05-12

Cuando todas estas olas hayan pasado, ¿cómo recordarán las generaciones futuras a esta época?

 
n1ghtc4t 2025-05-12

En ese momento también había una ola propia de ese tiempo...

 
bungker 2025-05-11

También creo que los microservicios tienen muchas ventajas en una startup. De entrada, recomiendo muchísimo las ventajas de usar un monorepo.

  • Cuando cambia la dirección del producto, en los microservicios queda más claro y son menos las partes que hay que modificar que en un monolito. Yo creo que esto es realmente importante.
  • En la era del desarrollo impulsado por IA, las unidades pequeñas de los microservicios son más fáciles de desarrollar con ayuda de la IA. (No estoy diciendo que con un monolito no se pueda)
  • Reconozco la carga de CI/CD, pero también hay servicios que se descartan en la etapa de definir la dirección. Incluso si se construye al final, cuando la dirección ya está definida, se puede montar en menos de una semana porque es casi de copiar y pegar.
  • Hay proyectos open source con fortalezas muy claras según el lenguaje. Por ejemplo, seguridad y lógica de negocio en Java, e IA en Python; en una arquitectura de microservicios se puede aprovechar al máximo la mayor cantidad posible de open source.
 
andone 2025-05-11

Estoy de acuerdo en que, en la era del desarrollo impulsado por IA, es indispensable implementar en unidades pequeñas y con responsabilidad única.

 
bus710 2025-05-10

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.

 
ndrgrd 2025-05-10

Si divides el equipo sin control, incluso reunirse para intercambiar opiniones se vuelve una carga enorme de trabajo.

 
GN⁺ 2025-05-10
Opinión de Hacker News
  • Se dan cuenta de que, si no hay problemas reales de escalabilidad, equipos grandes o dominios que deban evolucionar de forma independiente, los microservicios solo agregan costo y no aportan beneficios; de hecho, Segment también revirtió su separación en microservicios por esta misma razón. La idea es que esto es un patrón organizacional, no una tecnología. Normalmente se opera primero un monolito único y luego solo se separan el frontend, el backend o tareas de larga duración (por ejemplo, generar PDF) como servicios aparte. Después, si aumentan los servicios, recién ahí empiezan la estandarización y las discusiones de arquitectura. Con menos de 200 ingenieros, la pérdida de productividad suele ser mayor. No se sobrevive gracias a los microservicios, sino a pesar de ellos.
    • Algunos desarrolladores tienden a introducir microservicios pensando en su futuro currículum para una gran empresa, pero en una startup real eso ayuda poco. Para frenarlo hace falta un liderazgo técnico realmente sabio.
    • Alguien vio un caso en una startup de unos 50 ingenieros donde dividieron todo en decenas de servicios. A cualquier persona nueva le tomaba al menos 6 meses entender el sistema, los usuarios eran apenas unos cientos, pero la complejidad era enorme. Quemaron $50 millones de capital de VC y al final quebraron. El producto era innovador y estaba bien diseñado, pero no sirvió de nada.
    • También existe una forma de dividir servicios sin separar el código: desplegar un monolito convencional por medio de flags de rol. Incluso los workers en background se ejecutan junto con el servidor web, usando health checks y métricas, mientras el balanceador de carga distribuye el tráfico según el rol.
    • Como en el caso de Khan Academy, una vez que el monolito ya se escaló lo suficiente, la experiencia acumulada permite decidir mejor los límites entre servicios. En ese momento sí tiene sentido adoptar microservicios.
    • Aunque se mencionan razones técnicas para separar, los servicios son algo difícil por naturaleza. Aun así, si de verdad hacen falta, es importante asumir la actitud de subir el nivel de habilidad. No hay que rechazarlos automáticamente solo porque sean una moda; hay que evaluar los trade-offs.
    • Solo porque existan “varios equipos” no hace falta dividir la organización. Hay directores que, apenas aparecen dos squads pequeños, ya quieren separar el monolito. Si los equipos se reorganizan seguido (cada 9 meses), fijar límites de arquitectura demasiado pronto puede ser un desastre. Solo vale la pena usarlo como límite arquitectónico si primero se comprueba que puede operar como un equipo estable por al menos unos 18 meses.
    • La definición original de microservicios trata sobre “dominios que pueden evolucionar de manera independiente”, así que no parece haber nada nuevo ahí.
    • Hubo un caso donde solo una URL muy específica tenía requerimientos distintos de tráfico y memoria, así que como no era adecuada para un servidor PHP, agregaron un único servidor en otro lenguaje. Obtuvieron una mejora de 1000x en rendimiento y costo. También sugieren pensar el concepto de servicio al estilo Java/Spring/Guava como algo implementado “fuera” o “dentro” del proceso. Si se estandarizan bien el stack, las versiones y la serialización, la productividad incluso puede subir; si no hay estandarización, aparecen errores de comunicación, problemas de compatibilidad y mucho caos.
    • Conway's law (la estructura del código refleja la estructura de la organización) realmente se cumple.
    • Se enfatiza que un servicio es algo que presta una persona, y que los microservicios son servicios dentro de la economía interna de una empresa.
    • Una experiencia de hace 15 años: un equipo pequeño operaba fácilmente una solución única, pero tras adoptar microservicios tuvieron que lidiar con arrancar y coordinar cada servicio, y sufrieron bastante. Ahí aprendieron la importancia de practicar YAGNI (no construir algo hasta que realmente se necesite).
    • Hay muchas razones técnicas para separar, como aislar solo rutas de alto tráfico o rutas críticas. En organizaciones pequeñas normalmente no es lo ideal, pero recortar únicamente los caminos de alta carga puede tener un gran efecto incluso en startups.
    • En la práctica, la principal ventaja de los microservicios es permitir que grupos pequeños trabajen de forma independiente sin estorbarse entre sí. Pero cuando varios equipos poseen sus propios microservicios, las reuniones de estandarización no terminan nunca, y por culpa de las dependencias externas termina siendo más importante la diplomacia de “no te metas en lo ajeno” que la cooperación.
  • En un equipo de 2 o 3 desarrolladores, pese a que se les aconsejó no adoptar microservicios solo porque se veían cool, igual lo hicieron. Recién 2 años después reconstruyeron el código existente, y aun 3 años más tarde siguen sin resolver problemas de despliegue y otras complicaciones. Si al principio hubieran elegido un monolito modular en vez de ignorar el consejo, se habrían evitado todo esto. Coinciden totalmente con el artículo.
    • Si alguien deja un historial de tecnologías/proyectos llamativos y luego se cambia rápido de trabajo, el costo posterior se lo dejan a otros.
    • Los microservicios solo valen realmente la pena cuando hay un equipo asignado a cada servicio. Nunca han visto un buen caso donde un solo equipo mantenga varios servicios.
    • Gran parte del problema viene de que el equipo sigue pensando los microservicios como si fueran un solo sistema, un monolito. Eso genera fricción en todo el proceso, desde el diseño hasta el despliegue. Solo puede funcionar si toda la organización comparte de verdad esa visión. Cuando se microservicializa un sistema existente, suele haber mucha resistencia interna.
    • Al final, la sensación es que en las startups todos terminan pasando por sufrimientos parecidos.
    • Incluso en un proyecto interno de UI compuesto por 8 a 12 microservicios, con apenas 5 a 10 usuarios reales, solo terminó aumentando la complejidad innecesariamente. No se entiende por qué.
    • Alguien adoptó microservicios + Java por influencia de consultoría de Thoughtworks. La consultora cobró y se fue, mientras la organización quedó dando vueltas reimplementando un monolito lleno de funciones como microservicios distribuidos. El proyecto al final fracasó y la empresa desapareció. Desde entonces desconfían de las grandes consultoras.
  • En modo cerebro grug, se preguntan por qué alguien elegiría deliberadamente una forma más difícil de construir sistemas, agregando además llamadas de red al problema.
    • Les parece como intentar añadir a un lenguaje algo como “monkey patch” cuando no lo trae, como Python.
    • Otra opinión es que las llamadas de red convierten una regla (rule) en una ley (law).
    • Con humor tipo grug: hay tantos grugs con cerebro grug que terminan creyendo que un supergrupo de 9 grugs puede hacer un bebé grug en 1 mes.
  • Los microservicios sirven en organizaciones grandes para resolver problemas humanos, eliminar trabas burocráticas y dar más autonomía a los desarrolladores. En startups pequeñas, el beneficio real no suele ser grande. Aun así, si en cierto dominio se mezclan stacks distintos (por ejemplo, Elixir con Python/Go), esa separación puede ser necesaria.
    • Si la app tiene cargas o requerimientos de recursos distintos, incluso en una startup pequeña puede ser útil crear servicios separados. Lo mejor es dejar la mayor parte de la lógica de negocio en un monolito y aislar solo tareas especiales, como las que requieren GPU. Pero hay que evitar que ese patrón derive en mantener 100 servicios; por defecto prefieren el monolito y separar solo cuando sea necesario.
    • Los microservicios, en realidad, agregan nuevas dependencias organizacionales y necesidad de coordinación. Por ejemplo, una política de “cualquiera puede tomar cualquier servicio” multiplica mucho el mantenimiento, porque para que todo funcione cualquiera tiene que aprenderlo todo. Al final se pierde tiempo buscando gente.
    • Si hay equipos en conflicto o que duplican trabajo, la ineficiencia se dispara.
  • Los microservicios en arquitectura de software se parecen a Conway's Law (la estructura organizacional influye en la estructura del código): cada límite entre equipos se vuelve un límite que hay que cruzar, y crear internamente grandes fronteras arquitectónicas de forma artificial casi siempre es improductivo. En cambio, prefieren gestionar todo como un monolito modular usando inyección de dependencias, diseño de límites modulares y el modelo de actores. Luego, si de verdad hace falta, separar servicios resulta más fácil. Dicen que este enfoque les dio una muy buena relación costo-beneficio, y que ya han recortado monolitos 3 o 4 veces con éxito.
    • Conway's Law es una ley sobre comunicación, es decir, sobre los límites de comunicación. No hace falta intervenir cada límite entre equipos. De hecho, suele ser necesario reorganizar la empresa para que encaje con el software; en otras palabras, cada vez que cambias la arquitectura tendrías que reorganizar la compañía. Ese enfoque profundiza la desconexión entre equipos y objetivos de negocio, así que no conviene idolatrar sin más el estilo de Amazon.
  • Técnicamente, los casos donde los microservicios encajan en una startup son: (1) cuando es indispensable usar un lenguaje distinto al de la app central (por ejemplo, Rails + R), (2) cuando solo algunos servicios tienen diferencias extremas de escala, y (3) cuando ciertos datos necesitan requisitos distintos de seguridad o de ciclo de vida (como información médica). Fuera de eso, casi no hay razones para subdividir, y en organizaciones pequeñas más bien se pierde.
    • Dividir unas pocas partes del sistema no es lo mismo que microservicios reales. En microservicios de verdad, incluso cosas que normalmente serían módulos dentro de una app también se separan.
    • No solo la escala: si las exigencias de confiabilidad y disponibilidad son radicalmente distintas, separar en servicios también puede ser razonable. Al aislar preocupaciones para mantener el SLA, se puede reducir riesgo y acelerar los despliegues.
    • Incluso en esos casos, algunos creen que no es muy distinto de operar por separado solo el servidor de base de datos.
  • El verdadero resultado de los microservicios está en lo organizacional: se divide el problema y cada equipo posee por completo una parte, haciéndose responsable hasta la entrega end-to-end, lo que permite especialización. Los cambios ocurren de forma incremental por diseño, y la API es la única vía de interacción. No se comparte una sola base de datos, sistema de archivos ni API. A cambio, la estandarización y las herramientas de gestión (incluyendo monitoreo, pruebas y CI/CD) son importantes, aunque eso también aplica en cierto grado a los monolitos.
    • Infraestructura, logging y autenticación se manejan empaquetándolos o con gRPC, colas de mensajes y similares. Crear nuevos servicios se vuelve rápido, y las merge requests dentro de cada equipo se hacen más pequeñas, reduciendo conflictos y mejorando la productividad. Cuando eran 5 a 10 personas, con monolito sufrían más por conflictos, despliegues y releases, pero al pasar a microservicios mejoraron productividad, colaboración y legibilidad. Aun así, las reglas sobre pruebas, documentación y endpoints eran clave.
    • También hay casos donde la separación técnica es necesaria por rendimiento, como dividir la base de datos, pero eso puede ser raro en una startup común.
  • Una fortaleza del ecosistema BEAM/OTP (Erlang, Elixir) es que permite mantener un monolito mientras se practica un diseño “tipo microservicios”, y luego pasar fácilmente a una separación real cuando haga falta. Mientras el tamaño es pequeño, se conservan las ventajas del monolito; cuando crece, se puede ganar escalabilidad e independencia al mismo tiempo. Eso sí, requiere aprender sobre objetos inmutables, comunicación concurrente y manejo de fallas, y además puede dificultar la contratación.
  • La mayoría está de acuerdo: en el entorno startup, casi es imposible definir bien los límites entre servicios. Aun así, hay casos donde un equipo pequeño sí gana con microservicios por APIs externas o dependencias complejas. En esos casos, como el límite de red ya es obligatorio, hacer un servicio aparte no aumenta tanto la complejidad. También, cuando hay complejidad de build o despliegue, separar puede simplificar el monolito.
  • Los microservicios solo son adecuados cuando hace falta escalar mucho o cuando se necesita microgestión de equipos. No hay que renunciar a tener límites modulares claros. Es posible aprovechar dentro del monolito las ventajas de los microservicios con un estilo orientado a objetos basado en message passing. Hace falta disciplina para no tocar la base de datos directamente. En lenguajes como Java, se puede modularizar, usar namespaces en el esquema de la base de datos y exponer solo interfaces mínimas, permitiendo pruebas y monitoreo independientes. También facilita desplegar varios servicios al mismo tiempo.
    • Si se entienden bien los límites lógicos, incluso se pueden imponer con herramientas como ArchUnit.