MÓDULO 1.2

🏢 Estilos Arquiteturais

Monolito, microsserviços, serverless — quando usar cada um. Entenda os principais estilos arquiteturais e aprenda a escolher o certo para cada contexto.

7
Tópicos
40 min
Duração
Básico
Nível
Teoria
Tipo
1

🧱 Monolito

Single deployable unit — o ponto de partida inteligente. O Shopify processa US$175B/ano em GMV com um monolito Ruby on Rails.

Conceito

O que é um Monolito?

Aplicação onde todo o código roda como uma única unidade deployável. Um processo, um banco, um deploy. É o estilo mais simples e frequentemente o mais eficiente para começar.

Vantagens: Simplicidade operacional, debugging direto, transações ACID nativas, time pequeno mantém tudo, latency mínima entre componentes.

Quando usar: MVP, startups, times < 20 devs, domínio bem definido, quando não se sabe ainda as fronteiras do sistema.

Dados

Monolitos em Números

58%
dos apps em produção ainda são monolitos (JetBrains 2024)
$175B
GMV/ano do Shopify com monolito Rails
3x
mais rápido para MVP vs microsserviços
Fazer
  • Começar com monolito em projetos novos
  • Manter separação interna de módulos desde o dia 1
  • Usar monolito quando o domínio ainda não é claro
  • Investir em testes e CI/CD sólido
Evitar
  • Big ball of mud — sem estrutura interna
  • Monolito com 50+ devs sem modularização
  • Deploy de 2h porque tudo está acoplado
  • Ignorar sinais de que o monolito precisa evoluir
2

🧩 Monolito Modular

O melhor dos dois mundos. O Basecamp usa módulos independentes dentro do mesmo app Rails — cada domínio (projects, messages, files) é isolado.

Conceito

Bounded Contexts Internos

Um monolito modular mantém limites claros entre módulos. Cada módulo tem sua interface pública, seus dados privados, mas tudo roda no mesmo processo. Você ganha modularidade sem a complexidade distribuída.

Regra de ouro: Módulo A não acessa tabelas do Módulo B diretamente — usa a interface pública.

Dica Prática

Como Modularizar seu Monolito

  • 1.Identifique bounded contexts no seu domínio (pagamentos, usuários, catálogo)
  • 2.Crie pastas/namespaces por módulo com interfaces públicas explícitas
  • 3.Use linters/regras para impedir imports cruzados entre módulos
  • 4.Cada módulo tem seus próprios testes unitários e de integração
Timeline de Migração

De Monolito a Modular

Fase 1 — Mapeamento

Identifique domínios e dependências. Desenhe o grafo de acoplamento atual.

Fase 2 — Extração de Interfaces

Crie interfaces públicas para cada módulo. Substitua acessos diretos por chamadas à interface.

Fase 3 — Isolamento de Dados

Cada módulo controla suas tabelas. Proibir JOINs entre módulos.

Fase 4 — Enforce com Tooling

Linters, ArchUnit, dependency-cruiser para impedir regressões de acoplamento.

3

🔗 Microsserviços

Autonomia de times, não de tecnologia. A Amazon migrou para microsserviços quando tinha 1000+ devs e deploys bloqueavam uns aos outros.

Conceito

Independência de Deploy

Cada serviço é independente: deploy próprio, banco próprio, equipe própria. Comunicação via API ou mensageria. O objetivo principal é permitir que times diferentes façam deploy sem coordenar entre si.

Princípio: “Microsserviços resolvem problemas organizacionais, não técnicos.”

Componentes: API Gateway, Service Discovery, Circuit Breaker, Service Mesh, Database per Service

Alerta

Complexidade Operacional

Microsserviços trocam complexidade de código por complexidade operacional. Você precisa lidar com: rede, latência, consistência eventual, tracing distribuído, deploy de dezenas/centenas de serviços.

Prerrequisitos mínimos: CI/CD automatizado, monitoramento centralizado (Datadog, Grafana), tracing distribuído (Jaeger, Zipkin), infraestrutura como código. Se você não tem isso, não vá para microsserviços.

Fazer
  • Usar quando times precisam de deploy independente
  • Database per service — cada serviço é dono dos seus dados
  • Investir em observabilidade antes de migrar
  • Definir contratos claros entre serviços (OpenAPI, protobuf)
Evitar
  • Microsserviços com < 10 devs (overhead desnecessário)
  • Distributed monolith — serviços que precisam fazer deploy juntos
  • Nano-serviços — 200 funções com 10 linhas cada
  • Migrar sem observabilidade e CI/CD maduros
4

☁️ Serverless

Pay per execution, não por servidor. A Coca-Cola usa Lambda para processar vendas de máquinas automáticas — zero custo quando ninguém compra.

Conceito

Functions as a Service (FaaS)

Funções que executam sob demanda, sem servidor dedicado. O cloud provider gerencia toda a infraestrutura: scaling, patching, availability. Você só escreve a lógica.

Providers: AWS Lambda, Cloudflare Workers, Vercel Functions, Google Cloud Functions, Azure Functions

Modelo: Stateless by design — cada execução é independente. Estado vive em serviços externos (DynamoDB, S3, Redis).

Dados

Cold Start e Limites

100-500ms
Cold start típico (Node.js/Python)
15 min
Timeout máximo AWS Lambda
10 GB
Memória máxima por função
Dica Prática

Quando Serverless é a Escolha Certa

  • Sim: Workloads spiky/imprevisíveis (webhooks, processamento de imagens, ETL)
  • Sim: APIs com tráfego variável (startups com zero a viral)
  • Sim: Event processing (S3 trigger, DynamoDB Streams)
  • Não: Workloads constantes e previsíveis (mais barato com EC2/containers)
  • Não: Aplicações que precisam de estado em memória ou conexões persistentes
5

📡 Event-Driven Architecture

Reagir em vez de perguntar. O Uber usa EDA para coordenar corridas — eventos disparam mapa, notificação, rota e billing em paralelo.

Conceito

Pub/Sub e Event Sourcing

Componentes se comunicam através de eventos assíncronos. Um publica, vários consomem — desacoplamento máximo. Event Sourcing armazena cada mudança como evento imutável, permitindo reconstruir qualquer estado passado.

Padrões: Publish/Subscribe, Event Sourcing, CQRS (Command Query Responsibility Segregation)

Brokers: Apache Kafka, RabbitMQ, Redis Streams, AWS EventBridge, NATS

Dados

Throughput Comparison

1M+
msg/seg Kafka (cluster)
40K
msg/seg RabbitMQ (single node)
<1ms
latência Redis Streams
Fluxo de Evento

Corrida no Uber — Event-Driven

Evento: ride.requested

Passageiro solicita corrida. Evento publicado no barramento.

Evento: driver.matched

Serviço de matching encontra motorista. Dispara eventos paralelos.

Paralelo: 4 consumers

Mapa (atualiza posição) + Notificação (push ao passageiro) + Rota (calcula ETA) + Billing (inicia tarifação).

Evento: ride.completed

Cobraça, avaliação, analytics — tudo reativo, sem polling.

6

🌐 Arquitetura em Camadas

Separação clássica de responsabilidades. A maioria dos apps Django/Rails segue esse padrão — controller, model, service layer.

Conceito

Layers — Camadas com Responsabilidades Distintas

Sistema dividido em camadas horizontais: apresentação, lógica de negócio, acesso a dados. Cada camada só fala com a adjacente — a UI não acessa o banco diretamente.

Presentation

Controllers, Views, API endpoints

Business Logic

Services, Use Cases, Domain

Data Access

Repositories, ORM, Queries

Fazer
  • Respeitar a dependência unidirecional (cima → baixo)
  • Service layer para lógica de negócio — não no controller
  • Usar para apps CRUD e domínios simples
  • Testar cada camada isoladamente
Evitar
  • Anemic domain model — lógica toda no service, model vazio
  • Controller gordo — regras de negócio no controller
  • Pular camadas (UI acessando banco direto)
  • Usar para domínios complexos sem adaptar
Dica Prática

Variações do Padrão

MVC: Model-View-Controller — o padrão clássico de Django, Rails, Spring MVC.

MVP: Model-View-Presenter — comum em apps Android legados. View passiva.

MVVM: Model-View-ViewModel — usado em WPF, SwiftUI, Vue.js. Two-way binding.

7

🏗️ Hexagonal / Clean Architecture

Negócio no centro, infraestrutura nas bordas. O Nubank migrou de Datomic para PostgreSQL sem tocar na lógica de negócio.

Conceito

Ports and Adapters

O core da aplicação (regras de negócio) não depende de framework, banco ou API externa. Tudo é plugável via ports (interfaces que o domínio define) e adapters (implementações concretas).

Domain Core

Entities, Use Cases, regras puras

Ports

Interfaces definidas pelo domínio

Adapters

DB, HTTP, Queue, File System

Dados

Testabilidade

90%+
cobertura de domínio sem mocks de infra
10x
mais rápido rodar testes unitários de domínio
0
dependências externas nos testes de core
Fazer
  • Usar quando lógica de negócio é complexa e central
  • Domínio puro — zero imports de framework
  • Dependency Inversion — domínio define interfaces
  • Ideal para fintechs, healthtechs, domínios regulados
Evitar
  • Over-engineering em CRUDs simples
  • Criar 15 camadas para um TODO app
  • Ignorar o custo de indireção para times juniores
  • Domínio anêmico disfarçado de Clean Architecture

✅ Resumão do Módulo 1.2

Monolito — ponto de partida ideal para 95% dos projetos. Simplicidade operacional é vantagem real.

Monolito Modular — o stepping stone entre monolito e microsserviços. Bounded contexts internos sem complexidade distribuída.

Microsserviços — resolvem problemas organizacionais. Exigem maturidade operacional (CI/CD, observabilidade, infra como código).

Serverless — pay per execution. Ideal para workloads spiky e event processing.

Event-Driven — desacoplamento máximo via eventos assíncronos. Kafka, RabbitMQ, Redis Streams.

Camadas — separação clássica (presentation, business, data). Funciona bem para CRUDs e domínios simples.

Hexagonal/Clean — domínio no centro, infraestrutura plugável. Ideal para domínios complexos e regulados.