Skip to content
SP StackPractices
advanced

Guía de Arquitectura de Software

Una guía para diseñar arquitectura de software: monolitos vs microservicios, arquitectura en capas, flujo de datos y criterios de selección de tecnología.

Overview

La arquitectura de software define la estructura de un sistema, las relaciones entre componentes y los principios que guían el diseño y la evolución. Una buena arquitectura permite a los equipos moverse rápido sin romper cosas.

When to Apply

  • Inicias un proyecto nuevo o una reescritura mayor
  • Escalas un sistema que está alcanzando límites de performance
  • Organizas un equipo grande alrededor de ownership de código
  • Migras de infraestructura legacy a moderna

Estilos Arquitectónicos

Arquitectura Monolítica

Estructura: Unidad desplegable única que contiene toda la funcionalidad.

Cuándo elegir

  • Equipo pequeño (< 10 desarrolladores)
  • Dominio simple con baja complejidad
  • Fase de prototipado rápido
  • Requerimientos de latencia estrictos entre componentes

Pros: Despliegue simple, testing fácil, bajo overhead operacional. Contras: Alto acoplamiento, más difícil escalar componentes individuales, riesgo de fallas en cascada.

Arquitectura de Microservicios

Estructura: Servicios independientes que se comunican por red.

Cuándo elegir

  • Equipo grande (> 20 desarrolladores)
  • Dominio complejo con contextos acotados claros
  • Necesidad de escalar y desplegar independientemente
  • Múltiples stacks tecnológicos requeridos

Pros: Despliegue independiente, autonomía de equipo, persistencia políglota. Contras: Latencia de red, complejidad operacional, dificultad de debugging distribuido.

Monolito Modular

Estructura: Unidad desplegable única con módulos internos bien definidos.

Cuándo elegir

  • Equipo mediano (10–30 desarrolladores)
  • Quieres postergar la complejidad de microservicios
  • Límites de dominio claros pero infraestructura compartida

Pros: Operaciones más simples que microservicios, mejor estructura que big-ball-of-mud. Contras: Requiere disciplina para mantener límites de módulos.

Arquitectura en Capas

Modelo Clásico de 3 Capas

┌──────────────────────────────┐
│ Capa de Presentación         │
│ - Controllers, Views, DTOs   │
├──────────────────────────────┤
│ Capa de Lógica de Negocio    │
│ - Services, Domain Models    │
├──────────────────────────────┤
│ Capa de Acceso a Datos       │
│ - Repositories, ORM, Queries │
└──────────────────────────────┘

Regla de Dependencia: Las capas internas no deben depender de las externas.

Patrones de Flujo de Datos

CQRS (Command Query Responsibility Segregation)

Separa los modelos de lectura y escritura.

Cuándo usar

  • Las cargas de lectura y escritura difieren significativamente
  • Los modelos de lectura requieren datos denormalizados/optimizados
  • Event sourcing ya está en uso

Trade-off: Agrega complejidad; úsalo solo cuando lecturas y escrituras escalan independientemente.

Arquitectura Event-Driven

Los componentes se comunican mediante eventos asíncronos.

Cuándo usar

  • Se requiere desacoplamiento entre servicios
  • Las acciones pueden procesarse asíncronamente
  • La trazabilidad de cambios de estado es valiosa

Opciones de Event Bus: Apache Kafka, RabbitMQ, AWS SNS/SQS, NATS.

Framework de Selección de Tecnología

Matriz de Criterios

CriterioPesoOpción AOpción BOpción C
Experiencia del equipoAlto534
Soporte de comunidadMedio543
PerformanceMedio354
Costo operacionalAlto425
Score Ponderado4.23.34.1

Registro de Decisiones

Documenta cada elección tecnológica significativa con contexto, alternativas y consecuencias. Usa la Plantilla de ADR.

Patrones de Escalabilidad

Escalado Horizontal

Agrega más instancias detrás de un load balancer.

Client -> Load Balancer -> [Instance 1, Instance 2, Instance 3]

Requerimiento: El estado debe externalizarse (base de datos, cache, object storage).

Escalado de Base de Datos

PatrónCaso de uso
Read replicasCargas de lectura intensiva
ShardingEscritura intensiva, datasets grandes
Connection poolingMuchas instancias de aplicación
Caching (Redis)Datos calientes, storage de sesiones

Comunicación entre Componentes

Síncrona (REST / gRPC)

  • Pros: Modelo mental simple, feedback inmediato.
  • Contras: Acoplamiento fuerte, posibles fallas en cascada.
  • Usar para: Operaciones orientadas al usuario que requieren respuesta inmediata.

Asíncrona (Events / Message Queues)

  • Pros: Desacoplada, resiliente, escalable.
  • Contras: Consistencia eventual, más difícil de debuggear.
  • Usar para: Procesamiento en background, notificaciones, analytics.

Anti-Patrones

  • Big Ball of Mud: Sin arquitectura, todo acoplado
  • Microservicios prematuros: Dividir antes de entender los límites
  • Golden Hammer: Usar la tecnología favorita para todo
  • Not Invented Here: Reconstruir en vez de comprar/adoptar
  • Over-Engineering: Resolver problemas que todavía no tienes

Mejores prácticas

  • Empieza simple: Comienza con un monolito modular; extrae servicios cuando sea necesario
  • Define contextos acotados: Usa Domain-Driven Design para encontrar límites naturales
  • Diseña para observabilidad: Cada componente debe exponer métricas, logs, traces
  • Automatiza todo: CI/CD, infraestructura, testing, escaneo de seguridad
  • Documenta decisiones: ADRs para cada elección arquitectónica significativa

FAQ

Q: ¿Cuándo debería dividir de monolito a microservicios? A: Cuando los equipos se pisan durante los despliegues, o cuando el escalado independiente de componentes se vuelve crítico. La mayoría de los equipos debería empezar con un monolito modular.

Q: ¿Cómo elijo entre REST y gRPC? A: REST para APIs públicas y clientes de navegador; gRPC para comunicación interna servicio-a-servicio que requiere performance y type safety.

Q: ¿Debería usar un event bus o llamadas HTTP directas? A: Usa HTTP para operaciones que requieren consistencia inmediata y feedback al usuario. Usa eventos para trabajo en background, notificaciones y cuando necesitas desacoplamiento temporal.