Arquiteturas Modulares: 10 Princípios para Construir Sistemas Evolutivos

Waldemar Neto¹, William Calderipe¹

¹TechLeads.club


Abstract

A indústria de software enfrenta um dilema fundamental de granularidade: monólitos tradicionais sofrem com alta complexidade local e escalabilidade limitada, enquanto microsserviços introduzem complexidade operacional prematura que frequentemente supera seus benefícios. Evidências empíricas recentes, incluindo pesquisas conduzidas por equipes do Google (Ghemawat et al., 2023), demonstram que microsserviços geram perda de performance, visibilidade reduzida, dificuldades de gestão, congelamento de APIs e desaceleração no desenvolvimento. Este trabalho apresenta Arquiteturas Modulares como um framework formal posicionado entre esses extremos, baseado na separação consciente entre fronteiras lógicas (módulos) e fronteiras físicas (deploy). Propomos 10 princípios fundamentais que formam um framework coeso para construir sistemas que evoluem de forma sustentável: Limites Bem Definidos (Well-Defined Boundaries), Componibilidade (Composability), Independência (Independence), Isolamento de Estado (State Isolation), Comunicação Explícita (Explicit Communication), Substituibilidade (Replaceability), Independência de Deploy (Deployment Independence), Escalabilidade Independente (Individual Scale), Observabilidade (Observability) e Falhas Isoladas (Fail Independence). Nossa contribuição principal é a formalização desses princípios como um modelo arquitetural que permite evolução gradual da granularidade, reduzindo carga cognitiva e maximizando velocidade de entrega sem incorrer em complexidade prematura.

Palavras-chave: arquitetura de software, modularidade, monorepos, microsserviços, Domain-Driven Design, granularidade de software


Índice

  1. Introdução e Contextualização
  2. Estado da Arte e Limitações
  3. Arquiteturas Modulares - Definição Formal
  4. Os 10 Princípios Fundamentais
  5. Padrões de Implementação
  6. Governança Organizacional
  7. Análise Comparativa e Trade-offs
  8. Trabalhos Relacionados
  9. Conclusão
  10. Referências

1. Introdução e Contextualização

A evolução das arquiteturas de software nas últimas décadas reflete mudanças profundas tanto em infraestrutura tecnológica quanto em práticas organizacionais. Desde os monólitos tradicionais dos anos 1990-2000, passando pela Service-Oriented Architecture (SOA) dos anos 2000, até os microsserviços que dominaram a década de 2010, cada paradigma trouxe promessas de melhor organização, escalabilidade e manutenibilidade.

1.1 O Problema da Granularidade em Software

Granularidade define o tamanho e a coesão das unidades que compõem um sistema — sejam elas funções, classes, módulos ou serviços. Esta é uma das decisões arquiteturais mais críticas, pois impacta diretamente:

Podemos classificar granularidade em três níveis:

1.2 Mudança de Paradigma: Cloud e Ferramental Moderno

O advento da computação em nuvem, containers, orquestração (Kubernetes) e serverless modificou fundamentalmente as possibilidades arquiteturais. Pela primeira vez, tornou-se viável:

Paradoxalmente, essa flexibilidade criou um novo desafio: a complexidade migrou do código para a arquitetura distribuída. Como observado por Khononov (2023) em “Balancing Coupling in Software Design”, a complexidade em sistemas modernos emerge principalmente da comunicação entre componentes, não do código interno de cada um.

1.3 Complexidade Local vs Global

Em sistemas monolíticos tradicionais, a complexidade era local: mudanças em infraestrutura (banco de dados, frameworks) impactavam todo o sistema. A resposta foram camadas rígidas de abstração e padrões como Hexagonal Architecture e Clean Architecture.

Em sistemas modernos distribuídos, a complexidade é global: o desafio não é proteger o domínio do ORM, mas garantir contratos claros entre serviços, gerenciar consistência eventual, observabilidade e orquestração de deploys.

1.4 Objetivo deste Trabalho

Este paper propõe Arquiteturas Modulares como um framework intermediário que:

  1. Mantém a visibilidade e colaboração de monólitos
  2. Oferece a autonomia e escalabilidade de microsserviços
  3. Evita a complexidade operacional prematura
  4. Permite evolução gradual conforme maturidade organizacional

Formalizamos este conceito através de 10 princípios fundamentais validados empiricamente em projetos enterprise de empresas como Atlassian, BuildOps e diversas startups de alto crescimento.


2. Estado da Arte e Limitações

2.1 Monólitos Tradicionais

Características:

Benefícios:

Limitações:

2.2 Microsserviços: Promessas vs Realidade

A arquitetura de microsserviços foi amplamente adotada com promessas de:

2.3 Evidências Empíricas dos Problemas

O artigo “Towards Modern Development of Cloud Applications” (Ghemawat et al., 2023), publicado no HotOS e desenvolvido por pesquisadores do Google, incluindo Sanjay Ghemawat (cocriador do MapReduce e Google File System), identifica cinco problemas sistêmicos em microsserviços:

2.3.1 Perda de Performance

A serialização de dados e chamadas via rede adicionam overhead significativo comparado a chamadas locais. Quanto mais fragmentado o sistema, maior o custo de comunicação.

2.3.2 Perda de Visibilidade

Com múltiplas versões de múltiplos serviços em produção simultaneamente, torna-se extremamente difícil prever comportamentos emergentes. A maioria das falhas críticas ocorre na interação entre versões diferentes de serviços.

2.3.3 Dificuldade de Gestão

Cada serviço vira um binário independente com processo próprio de build, teste e deploy. O esforço para manter tudo funcionando em conjunto cresce exponencialmente.

2.3.4 Congelamento de APIs

Ao publicar uma API entre serviços, você congela sua evolução. APIs antigas persistem indefinidamente porque não há visibilidade de quem as consome, criando débito técnico cumulativo.

2.3.5 Desaceleração no Desenvolvimento

Alterações que afetam múltiplos serviços não podem ser feitas atomicamente. Desenvolvedores precisam orquestrar mudanças entre N serviços com versões desalinhadas, reduzindo drasticamente a velocidade de entrega.

2.4 O Erro Fundamental

Segundo Ghemawat et al. (2023), o erro dos microsserviços está em conflitar fronteiras lógicas (código) com fronteiras físicas (deploy):

2.5 Tabela Comparativa: Granularidade

Critério Grossa (Monólito) Média (Modular) Fina (Microsserviços)
Complexidade Operacional Baixa Média Alta
Velocidade Inicial Alta Alta Baixa
Escalabilidade Limitada Flexível Máxima
Visibilidade do Sistema Total Alta Fragmentada
Deploy Único Por app Por serviço
Acoplamento Alto Controlado Distribuído
Governança Necessária Baixa Média Alta
graph LR
    A[Monólito<br/>Complexidade<br/>Média] --> B[Modular<br/>Complexidade<br/>Mínima]
    B --> C[Microsserviços<br/>Complexidade<br/>Alta]

Figura 1: Sweet Spot da Complexidade Operacional
As Arquiteturas Modulares ocupam o ponto de mínima complexidade operacional, equilibrando os benefícios de monólitos (simplicidade) com os de microsserviços (autonomia), evitando os problemas de ambos os extremos.

2.6 Gap Identificado

Não existe framework formal que permita:

Arquiteturas Modulares preenchem esse gap.


3. Arquiteturas Modulares - Definição Formal

3.1 Definição

Arquitetura Modular é um sistema de software que estabelece separação explícita entre fronteiras lógicas (módulos) e fronteiras físicas (processos/deploys), permitindo que a granularidade evolua de forma incremental e reversível conforme necessidades do negócio e maturidade organizacional.

3.2 Características Fundamentais

3.2.1 Modularização em Monorepo

Todo o código vive em um único repositório versionado, organizado em:

3.2.2 Deploy Independente como Opção

Módulos podem ser deployados juntos (monólito modular) ou separados (apps dedicadas), sem exigir refatoração do código. A decisão de deploy é operacional, não estrutural.

3.2.3 Evolução Gradual

A arquitetura suporta transições naturais:

Monólito Modular → Módulos com Fronteiras Claras → 
Apps Dedicadas → Microsserviços (quando justificado)

3.3 Componentes Arquiteturais

3.3.1 Apps (Pontos de Bootstrap)

Apps são executáveis que importam e inicializam módulos. Não contêm lógica de negócio.

apps/
  monolith/              # Importa todos os módulos
    main.ts              # Bootstrap
    monolith.module.ts   # Orquestração
  billing-api/           # Importa apenas Billing
    main.ts
    billing-api.module.ts

3.3.2 Packages (Unidades Lógicas)

Módulos de Domínio: encapsulam regras de negócio de um Bounded Context (DDD)

packages/
  billing/
    core/               # Entidades, casos de uso
    persistence/        # Repositórios, migrations
    http/              # Controllers, DTOs
    __test__/          # Testes isolados

Módulos de Infraestrutura: fornecem capacidades técnicas reutilizáveis

packages/
  shared/
    logger/
    config/
    database/

3.3.3 Grafo de Dependências Explícito

Ferramentas como Nx constroem automaticamente um grafo mostrando como módulos se relacionam, permitindo:

monorepo-root/
│
├── apps/                          [Apps = Bootstrap]
│   ├── monolith/                     ← Importa todos os módulos
│   │   ├── main.ts
│   │   └── monolith.module.ts
│   │
│   ├── billing-api/                  ← Apenas Billing
│   │   ├── main.ts
│   │   └── billing-api.module.ts
│   │
│   └── content-worker/               ← Apenas Content/VideoProcessor
│       ├── main.ts
│       └── content-worker.module.ts
│
├── packages/                      [Packages = Lógica]
│   │
│   ├── DOMÍNIOS
│   │   │
│   │   ├── billing/                  ← Bounded Context
│   │   │   ├── core/                 (entidades, casos de uso)
│   │   │   ├── persistence/          (repositórios, migrations)
│   │   │   ├── http/                 (controllers, DTOs)
│   │   │   └── __test__/
│   │   │
│   │   ├── content/
│   │   │   ├── catalog/              ← Submódulo
│   │   │   ├── video-processor/      ← Submódulo
│   │   │   └── admin/                ← Submódulo
│   │   │
│   │   └── identity/
│   │       ├── core/
│   │       ├── persistence/
│   │       └── http/
│   │
│   └── INFRAESTRUTURA
│       └── shared/
│           ├── logger/               (sem lógica de negócio)
│           ├── config/
│           └── database/
│
├── tools/
│   └── scripts/
│
├── nx.json                           [Configuração Nx]
├── package.json
└── tsconfig.base.json

3.4 Ferramental Habilitador

Arquiteturas Modulares são viabilizadas por ferramentas modernas:

Tecnologia Capacidade Exemplos
Monorepo Tools Gerenciamento de dependências, builds incrementais Nx, Bazel, Turborepo
Frameworks Modulares Composição via módulos, injeção de dependências NestJS, Spring Boot, .NET
Modularização Nativa Sistemas de módulos em linguagens Java Modules, Go packages
Soluções Integradas Deploy flexível mantendo modularidade Ktor, Maven Packages, Java Modulith

3.5 Diferenciação Fundamental

Aspecto Microsserviços Arquiteturas Modulares
Decisão de Deploy Definida na arquitetura Separada da arquitetura
Granularidade Fixa desde o início Evolui gradualmente
Reversibilidade Difícil Natural
Complexidade Inicial Alta Baixa
Visibilidade Fragmentada Total (monorepo)
graph TB
    subgraph apps [Apps - Bootstrap]
        monolith[monolith/]
        billing_api[billing-api/]
        content_worker[content-worker/]
    end
    
    subgraph packages [Packages - Lógica]
        subgraph domain [Domínios]
            billing[billing/]
            content[content/]
            identity[identity/]
        end
        
        subgraph infra [Infraestrutura]
            shared[shared/]
        end
    end
    
    monolith --> billing
    monolith --> content
    monolith --> identity
    monolith --> shared
    
    billing_api --> billing
    billing_api --> shared
    
    content_worker --> content
    content_worker --> shared
    
    style monolith fill:#4A90E2
    style billing_api fill:#4A90E2
    style content_worker fill:#4A90E2
    style billing fill:#50C878
    style content fill:#50C878
    style identity fill:#50C878
    style shared fill:#9CA3AF

4. Os 10 Princípios Fundamentais

Este framework é estruturado em quatro categorias de princípios, cada uma abordando um aspecto fundamental da modularidade.

4.1 Princípios Estruturais

Definem a base da organização modular.

4.1.1 Well-Defined Boundaries (Limites Bem Definidos)

Definição: Cada módulo possui responsabilidades claras alinhadas a um Bounded Context (DDD), sem expor detalhes internos para outros módulos.

Justificativa: Limites claros reduzem acoplamento acidental, facilitam manutenção e permitem evolução independente. Seguem o princípio de encapsulamento estendido para nível arquitetural.

Implementação:

Os exemplos a seguir mostram o setup de um módulo em diferentes linguagens. O conceito se aplica a qualquer tecnologia - módulos podem ser implementados com ou sem frameworks, usando convenções de organização e encapsulamento nativas da linguagem.

NestJS (TypeScript) - com framework:

// packages/billing/billing.module.ts
@Module({
  imports: [TypeOrmModule.forFeature([SubscriptionEntity])],
  providers: [BillingService],
  controllers: [BillingController],
  exports: []  // Nada exportado - comunicação via HTTP/eventos
})
export class BillingModule {}

Go (sem framework) - apenas convenções:

// packages/billing/module.go
package billing

// Setup do módulo - função pública de inicialização
func Setup(router *mux.Router, db *sql.DB) {
    // Componentes internos (não exportados)
    repo := newRepository(db)
    service := newService(repo)
    
    // Apenas rotas HTTP são expostas
    setupRoutes(router, service)
}

Ktor (Kotlin) - convenções + extension functions:

// packages/billing/BillingModule.kt
package com.example.billing

fun Application.billingModule() {
    // Componentes internos
    val repository = BillingRepository(database)
    val service = BillingService(repository)
    
    // Apenas rotas são expostas
    routing {
        billingRoutes(service)
    }
}

Princípio universal: O módulo é uma unidade organizacional que:

Violação comum: Módulos que exportam repositórios ou entidades internas permitem que outros dependam de detalhes de implementação.

4.1.2 Composability (Componibilidade)

Definição: Módulos são projetados como blocos reutilizáveis que podem ser combinados para formar diferentes aplicações ou funcionalidades.

Justificativa: Maximiza reuso, reduz duplicação e permite evolução incremental sem reescrever código.

Implementação:

// monolith.module.ts (importa tudo)
@Module({
  imports: [BillingModule, ContentModule, IdentityModule, LoggerModule]
})
export class MonolithModule {}

// billing-api.module.ts (importa apenas billing)
@Module({
  imports: [BillingModule, LoggerModule]
})
export class BillingApiModule {}

Benefício: Mesmos módulos podem ser orquestrados de formas diferentes sem duplicar código.

4.1.3 Independence (Independência)

Definição: Módulos são autônomos em código e infraestrutura, comunicando-se apenas via APIs explícitas, eventos ou mensagens assíncronas.

Justificativa: Previne acoplamento acidental, permite evolução tecnológica independente e facilita testes isolados.

Implementação:

Regra: Se módulo A precisa de dados de módulo B, usa API ou evento — nunca importa classes de B diretamente.

4.2 Princípios Operacionais

Definem como módulos interagem.

4.2.1 State Isolation (Isolamento de Estado)

Definição: Cada módulo gerencia seu próprio estado (banco de dados, cache, filas) sem compartilhamento direto com outros módulos.

Justificativa: Previne falhas em cascata, permite escalabilidade independente e facilita evolução de schemas.

Implementação:

graph TB
    subgraph "Módulo Billing"
        BillingService[Billing Service]
        BillingRepo[Billing Repository]
    end
    
    subgraph "Módulo Identity"
        IdentityService[Identity Service]
        IdentityRepo[Identity Repository]
    end
    
    subgraph "Banco de Dados"
        subgraph "Schema/DB Billing"
            BillingTables["Tabelas:<br/>• subscriptions<br/>• payments<br/>• invoices"]
        end
        
        subgraph "Schema/DB Identity"
            IdentityTables["Tabelas:<br/>• users<br/>• sessions<br/>• roles"]
        end
    end
    
    BillingService --> BillingRepo
    BillingRepo --> BillingTables
    
    IdentityService --> IdentityRepo
    IdentityRepo --> IdentityTables
    
    BillingRepo -.->|❌ Nunca acessa| IdentityTables
    IdentityRepo -.->|❌ Nunca acessa| BillingTables
    
    style BillingService fill:#4A90E2
    style IdentityService fill:#50C878
    style BillingTables fill:#FFE5B4
    style IdentityTables fill:#E0FFE0
    style BillingRepo fill:#4A90E2
    style IdentityRepo fill:#50C878

Figura: Isolamento de Estado entre Módulos
Cada módulo acessa exclusivamente suas próprias tabelas, sem compartilhamento direto de estado. A comunicação entre módulos ocorre apenas via APIs ou eventos.

Estratégias de banco:

4.2.2 Explicit Communication (Comunicação Explícita)

Definição: Toda comunicação entre módulos ocorre via contratos bem definidos (interfaces, DTOs, schemas de eventos).

Justificativa: Evita acoplamento implícito, permite versionamento de contratos e facilita testes com mocks.

Implementação:

Local (mesmo processo):

// Interface pública
export interface BillingAPI {
  createSubscription(userId: string, planId: string): Promise<Subscription>;
}

// Implementação
@Injectable()
export class BillingService implements BillingAPI {
  async createSubscription(...) { /* lógica */ }
}

Remoto (processos separados):

@Controller('billing')
export class BillingController {
  @Post('subscribe')
  async createSubscription(@Body() dto: CreateSubscriptionDto) { /* ... */ }
}

Assíncrono (eventos):

@OnEvent('billing.subscription.created')
handleSubscriptionCreated(payload: SubscriptionCreatedEvent) { /* ... */ }

4.2.3 Replaceability (Substituibilidade)

Definição: Módulos podem ser removidos, alterados ou substituídos sem afetar o restante da arquitetura.

Justificativa: Permite experimentação tecnológica, reduz vendor lock-in e facilita refatorações.

Implementação:

Exemplo: Trocar ORM (TypeORM → Prisma) dentro de um módulo sem impactar consumidores.

4.3 Princípios de Deploy

Definem flexibilidade de implantação.

4.3.1 Deployment Independence (Deploy Independente)

Definição: Cada app pode ser versionada e implantada isoladamente, sem obrigar deploys de outras apps.

Justificativa: Reduz risco de mudanças, permite ciclos de release diferenciados e facilita rollbacks.

Implementação (Exemplo):

# CI/CD Pipeline (exemplo GitHub Actions)
name: Deploy Billing API
on:
  push:
    branches: [main]
jobs:
  check-affected:
    runs-on: ubuntu-latest
    steps:
      - run: npx nx affected:apps --base=origin/main
      - if: contains(steps.affected.outputs.apps, 'billing-api')
        run: npx nx build billing-api && npm run deploy:billing-api

Estratégia: Usar nx affected para detectar mudanças e deployar apenas apps impactadas.

4.3.2 Individual Scale (Escalabilidade Independente)

Definição: Cada app pode escalar horizontalmente conforme sua demanda específica, sem afetar outros.

Justificativa: Otimiza uso de recursos e previne que gargalos locais impactem o sistema inteiro.

Estratégia: Métricas por app determinam escala independente.

4.4 Princípios de Resiliência

Definem operação confiável em produção.

4.4.1 Observability (Observabilidade)

Definição: Cada módulo possui logs, métricas e tracing próprios, permitindo diagnóstico isolado.

Justificativa: Identifica problemas rapidamente sem vasculhar o sistema inteiro.

Implementação:

// Logs com contexto de módulo
logger.log('Subscription created', { 
  module: 'billing',
  userId, 
  planId 
});

// Métricas por módulo
@Metrics({ module: 'billing' })
export class BillingService { /* ... */ }

Ferramental: Prometheus (métricas), Grafana (dashboards), Jaeger (tracing distribuído).

4.4.2 Fail Independence (Falhas Isoladas)

Definição: Falhas em um módulo não se propagam, garantindo degradação controlada do sistema.

Justificativa: Maximiza disponibilidade e facilita recuperação.

Implementação:

// Circuit Breaker
import CircuitBreaker from 'opossum';

@Injectable()
export class BillingClient {
  private breaker = new CircuitBreaker(
    () => this.callBillingAPI(),
    { timeout: 5000, errorThresholdPercentage: 50 }
  );
  
  async getBillingData() {
    try {
      return await this.breaker.fire();
    } catch (err) {
      // Fallback
      return { status: 'degraded', data: null };
    }
  }
}

Estratégias: Circuit breakers, timeouts, retries com backoff exponencial, fallbacks.

Os 10 princípios organizados

graph TB
    subgraph resilience [Resiliência]
        P9[9. Observability]
        P10[10. Fail Independence]
    end
    
    subgraph deploy [Deploy]
        P7[7. Deployment Independence]
        P8[8. Individual Scale]
    end
    
    subgraph operational [Operacionais]
        P4[4. State Isolation]
        P5[5. Explicit Communication]
        P6[6. Replaceability]
    end
    
    subgraph structural [Estruturais]
        P1[1. Well-Defined Boundaries]
        P2[2. Composability]
        P3[3. Independence]
    end
    
    P1 --> P4
    P2 --> P5
    P3 --> P6
    
    P4 --> P7
    P5 --> P8
    P6 --> P7
    
    P7 --> P9
    P8 --> P10
    
    style resilience fill:#EF4444,color:#fff
    style deploy fill:#F97316,color:#fff
    style operational fill:#3B82F6,color:#fff
    style structural fill:#10B981,color:#fff

5. Padrões de Implementação

5.1 Tipos de Módulos

5.1.1 Módulos de Domínio

Representam Bounded Contexts (DDD) e encapsulam regras de negócio específicas.

Exemplos: billing/, content/, identity/

Estrutura típica:

billing/
├── core/              # Entidades, serviços, casos de uso
├── persistence/       # Repositórios, migrations
├── http/              # Controllers, DTOs
└── __test__/          # Testes unitários e E2E

5.1.2 Módulos de Infraestrutura (Shared)

Fornecem capacidades técnicas reutilizáveis, sem lógica de negócio.

Exemplos: shared/logger/, shared/config/, shared/database/

Regra: Nunca incluir regras de negócio em shared. Se dois domínios compartilham lógica, isso indica fronteira mal definida.

5.2 Submódulos

Quando domínios ficam muito grandes, dividem-se em submódulos mantendo coesão do Bounded Context.

Exemplo:

content/
├── catalog/           # Submódulo: gerenciamento de catálogo
├── video-processor/   # Submódulo: processamento de vídeos
└── admin/             # Submódulo: administração de conteúdo

Benefícios:

Regra: Submódulos podem compartilhar entidades e repositórios, mas nunca services ou lógica de aplicação.

5.3 Design Patterns de Apps

5.3.1 Padrão 1: App Compartilhada + Apps de Domínio

Estrutura:

apps/
  monolith/            # App compartilhada (todos os módulos)
  billing-api/         # App dedicada (apenas Billing)
  content-worker/      # App dedicada (apenas Content/VideoProcessor)

Quando usar:

Vantagens:

Desafios:

5.3.2 Padrão 2: Apps por Domínio

Estrutura:

apps/
  billing-app/         # Apenas módulos de Billing
  content-app/         # Apenas módulos de Content
  identity-app/        # Apenas módulos de Identity

Quando usar:

Vantagens:

Desafios:

5.4 Estratégia de Evolução

Fase 1: Monólito Modular

Fase 2: Módulos com Fronteiras Claras

Fase 3: Apps Dedicadas

Fase 4: Extração para Microsserviços

timeline
    title Evolução de Arquiteturas Modulares
    
    section Fase 1
        Monólito Modular : 1 app
                          : Todos módulos
                          : Velocidade máxima
    
    section Fase 2
        Fronteiras Claras : Enforce boundaries
                          : Observabilidade por módulo
                          : Feature flags
    
    section Fase 3
        Apps Dedicadas : 2+ apps
                       : Deploy independente
                       : Escala seletiva
    
    section Fase 4
        Microsserviços : Muitos times
                       : Rede obrigatória
                       : Máxima autonomia

6. Governança Organizacional

6.1 Arquitetura Conway Invertida

A Lei de Conway estabelece que sistemas refletem estruturas organizacionais. Em Arquiteturas Modulares, invertemos isso: a estrutura do código influencia a organização.

Módulos bem definidos naturalmente criam:

6.2 Responsabilidades dos Tech Leads

Líderes técnicos em arquiteturas modulares devem:

  1. Estabelecer Diretrizes de Separação
    • Quando criar novo módulo
    • Quando promover módulo para app dedicada
    • Critérios de coesão e acoplamento
  2. Garantir Observabilidade por Módulo
    • Dashboards dedicados
    • Alertas direcionados aos times responsáveis
    • Playbooks de incidentes
  3. Balancear Autonomia e Coerência
    • Autonomia: times escolhem implementações
    • Coerência: contratos e padrões são consistentes
  4. Gerenciar Evolução Arquitetural
    • Revisar grafo de dependências periodicamente
    • Identificar acoplamentos acidentais
    • Facilitar refatorações de fronteiras

6.3 Versionamento: Fast Forward vs Time Machine

6.3.1 Fast Forward (Monorepo)

6.3.2 Time Machine (Polyrepo)

Recomendação: Fast Forward para arquiteturas evolutivas.

6.4 Desafios Operacionais

6.4.1 On-Call Compartilhado

Problema: Quem atende alertas quando múltiplos times compartilham uma app?

Solução:

6.4.2 Gestão de Dependências

Problema: Módulos podem criar dependências circulares ou indesejadas.

Solução:

// nx.json - enforce-module-boundaries
{
  "tags": {
    "domain:billing": ["domain:billing", "shared"],
    "domain:content": ["domain:content", "shared"],
    "shared": []
  }
}

Regra: Domínios só dependem de shared, nunca entre si.

6.4.3 Feature Flags para Deploys Conjuntos

Problema: Deploys de app compartilhada afetam múltiplos times.

Solução:

if (featureFlags.isEnabled('billing-new-checkout', userId)) {
  return newCheckoutFlow();
}
return legacyCheckoutFlow();

7. Análise Comparativa e Trade-offs

7.1 Tabela Comparativa Detalhada

Critério Monólito Modular Microsserviços
Complexidade Operacional Baixa Média Alta
Velocidade Inicial Alta Alta Baixa
Escalabilidade Vertical Horizontal seletiva Horizontal total
Visibilidade Total Total (monorepo) Fragmentada
Deploy Único Por app Por serviço
Acoplamento Alto Controlado Distribuído
Carga Cognitiva Alta (local) Média Alta (global)
Custo Operacional Baixo Médio Alto
Autonomia de Times Baixa Média-Alta Alta
Reversibilidade Difícil Fácil Muito difícil

7.2 Quando Usar Arquiteturas Modulares

Sim, quando:

7.3 Quando NÃO Usar

Considere alternativas quando:

Preferir Monólito Simples:

Preferir Microsserviços:

7.4 Limitações Identificadas

  1. Requer Disciplina de Governança
    • Sem enforcement, fronteiras se degradam
    • Necessita líderes técnicos ativos
  2. Ferramental Específico
    • Nx, Bazel ou equivalente são necessários
    • Curva de aprendizado inicial
  3. Banco de Dados Compartilhado
    • Se usar banco único, depende de disciplina para isolamento
    • Sem garantias físicas de separação
  4. Cultura de Monorepo
    • Times acostumados com polyrepo podem resistir
    • Exige mudança cultural

8. Trabalhos Relacionados

8.1 Domain-Driven Design (Evans, 2003)

Contribuição: Conceito de Bounded Contexts como unidades de modelagem.

Relação: Arquiteturas Modulares implementam Bounded Contexts como módulos de domínio, com fronteiras técnicas além das conceituais.

Referência: Evans, E. (2003). Domain-Driven Design: Tackling Complexity in the Heart of Software. Addison-Wesley.

8.2 Towards Modern Development of Cloud Applications (Ghemawat et al., 2023)

Contribuição: Evidências empíricas dos problemas sistêmicos de microsserviços.

Relação: Valida a necessidade de separar fronteiras lógicas de físicas, base conceitual deste trabalho.

Referência: Ghemawat, S., et al. (2023). Towards Modern Development of Cloud Applications. HotOS ‘23.

8.3 Java Modulith (Spring Ecosystem)

Contribuição: Modularidade no ecossistema Java Spring Boot.

Relação: Implementa princípios similares de Bounded Contexts em monorepos Java.

Diferença: Específico para Java; este trabalho generaliza para múltiplas linguagens.

8.4 Balancing Coupling in Software Design (Khononov, 2023)

Contribuição: Análise de complexidade global vs local em sistemas distribuídos.

Relação: Fundamenta o argumento de que complexidade moderna está na comunicação, não no código interno.

Referência: Khononov, V. (2023). Balancing Coupling in Software Design. Addison-Wesley.

8.5 Nx Documentation (Nrwl)

Contribuição: Práticas e padrões de monorepo com foco em modularidade.

Relação: Ferramental que viabiliza implementação prática dos princípios.

Referência: Nrwl. (2024). Nx Documentation. https://nx.dev

8.6 NestJS (Kamil Mysliwiec)

Contribuição: Framework Node.js com arquitetura modular inspirada em Angular, promovendo separação clara de responsabilidades via módulos, injeção de dependências e decorators.

Relação: Exemplo prático de framework que facilita implementação de arquiteturas modulares, demonstrando como estruturas modulares podem ser implementadas de forma nativa em ecossistemas modernos.

Referência: Mysliwiec, K. et al. (2024). NestJS - A progressive Node.js framework. https://nestjs.com

8.7 Strategic Monoliths and Microservices (Vernon, 2021)

Contribuição: Análise pragmática sobre quando e como usar monólitos versus microsserviços, enfatizando arquitetura orientada a propósito (purposeful architecture) e a importância de decisões arquiteturais alinhadas ao contexto de negócio.

Relação: Complementa este trabalho ao reconhecer que nem todo sistema precisa de microsserviços e que monólitos bem estruturados (modulares) podem ser a escolha mais estratégica. Vernon destaca a importância de Bounded Contexts e modularidade interna, conceitos centrais em nosso framework.

Referência: Vernon, V. (2021). Strategic Monoliths and Microservices: Driving Innovation Using Purposeful Architecture. Addison-Wesley Signature Series.

8.8 Enterprise Monorepo Angular Patterns (Nrwl/Nx Team)

Contribuição: Padrões práticos para organização de monorepos em ambientes enterprise, com foco em escalabilidade de times, compartilhamento de código e governança de dependências.

Relação: Valida na prática os conceitos de modularização em monorepo apresentados neste trabalho. Demonstra como ferramentas como Nx viabilizam arquiteturas modulares em projetos enterprise de larga escala, com exemplos concretos de estruturação de projetos, bibliotecas e apps.

Referência: Nrwl. Enterprise Monorepo Angular Patterns. Nrwl Press.

8.9 Fundamentals of Software Architecture (Richards & Ford, 2020)

Contribuição: Formalização acadêmica de diferentes estilos arquiteturais, incluindo modular monoliths como padrão arquitetural válido. Apresenta framework para análise de trade-offs e características arquiteturais.

Relação: Fornece base teórica para classificação de arquiteturas modulares como estilo arquitetural distinto. Valida a importância de características como modularidade, deployability e testability que fundamentam nossos 10 princípios.

Referência: Richards, M., & Ford, N. (2020). Fundamentals of Software Architecture: An Engineering Approach. O’Reilly Media.

8.10 Software Architecture: The Hard Parts (Ford, Richards et al., 2021)

Contribuição: Análise profunda de trade-offs em arquiteturas distribuídas modernas, questionando quando microsserviços realmente compensam e explorando alternativas como modular monoliths.

Relação: Complementa este trabalho ao fornecer metodologia para análise de trade-offs arquiteturais. Reforça a mensagem de que decisões arquiteturais devem ser baseadas em contexto e necessidades reais, não em hype.

Referência: Ford, N., Richards, M., Sadalage, P., & Dehghani, Z. (2021). Software Architecture: The Hard Parts: Modern Trade-Off Analyses for Distributed Architectures. O’Reilly Media.

8.11 Building Evolutionary Architectures (Ford, Parsons, Kua, 2017)

Contribuição: Conceito de fitness functions e arquiteturas que evoluem incrementalmente ao longo do tempo, suportando mudança constante através de práticas de engenharia.

Relação: Fundamenta diretamente a proposta de evolução gradual deste framework. O conceito de fitness functions pode ser aplicado para validar que módulos mantêm seus limites (via enforce-module-boundaries) e que princípios são respeitados ao longo do tempo.

Referência: Ford, N., Parsons, R., & Kua, P. (2017). Building Evolutionary Architectures: Support Constant Change. O’Reilly Media.

8.12 Team Topologies (Skelton & Pais, 2019)

Contribuição: Framework para estruturar times de tecnologia com base em fluxo de trabalho, definindo padrões como stream-aligned teams, enabling teams e platform teams.

Relação: Essencial para a seção de Governança Organizacional deste trabalho. Arquiteturas modulares se alinham naturalmente com stream-aligned teams, onde cada time possui um ou mais módulos de domínio, com plataforms teams fornecendo módulos de infraestrutura (shared).

Referência: Skelton, M., & Pais, M. (2019). Team Topologies: Organizing Business and Technology Teams for Fast Flow. IT Revolution Press.

8.13 Monolith to Microservices (Newman, 2019)

Contribuição: Guia pragmático sobre decomposição de monólitos, reconhecendo que nem todos os sistemas devem se tornar microsserviços e apresentando padrões para transição incremental quando necessário.

Relação: Valida a abordagem de evolução gradual proposta neste framework. Newman demonstra que a transição deve ser consciente e incremental, exatamente o que arquiteturas modulares facilitam ao estabelecer fronteiras claras desde o início.

Referência: Newman, S. (2019). Monolith to Microservices: Evolutionary Patterns to Transform Your Monolith. O’Reilly Media.

8.14 Diferenciação deste Trabalho

Este paper vai além ao:

  1. Formalizar 10 princípios como framework coeso
  2. Propor padrões de implementação validados empiricamente
  3. Incluir governança organizacional como parte integral
  4. Estabelecer estratégia de evolução gradual entre paradigmas

9. Conclusão

9.1 Síntese

Arquiteturas Modulares representam um “meio-termo consciente” entre monólitos tradicionais e microsserviços, fundamentado em:

9.2 Contribuições Principais

Este trabalho oferece:

  1. Framework Formal com 10 Princípios
    • Estruturais: Boundaries, Composability, Independence
    • Operacionais: State Isolation, Communication, Replaceability
    • Deploy: Deployment Independence, Individual Scale
    • Resiliência: Observability, Fail Independence
  2. Padrões de Implementação Validados
    • Tipos de módulos (domínio vs infraestrutura)
    • Submódulos para domínios grandes
    • Design patterns de apps (compartilhada vs dedicada)
  3. Modelo de Governança Organizacional
    • Responsabilidades de tech leads
    • Versionamento Fast Forward
    • Gestão de desafios operacionais
  4. Estratégia de Evolução Gradual
    • 4 fases: Monólito Modular → Fronteiras Claras → Apps Dedicadas → Microsserviços
    • Decisões reversíveis em cada fase

9.3 Posicionamento

Arquiteturas Modulares não são revolução, mas evolução natural de:

9.4 Trabalhos Futuros

Direções de pesquisa:

  1. Métricas Quantitativas de Carga Cognitiva
    • Formalizar métricas para medir complexidade percebida
    • Comparar com monólitos e microsserviços
  2. Estudos de Caso Longitudinais
    • Acompanhar evolução de sistemas reais ao longo de anos
    • Validar hipótese de redução de débito técnico
  3. Validação em Diferentes Ecossistemas
    • Java, Go, .NET, Python
    • Identificar padrões universais vs específicos de linguagem
  4. Ferramental de Governança Automatizada
    • Análise estática de violações de princípios
    • Sugestões automatizadas de refatorações

9.5 Abertura

Este trabalho é uma contribuição aberta para a comunidade. Encorajamos:


Referências

  1. Evans, E. (2003). Domain-Driven Design: Tackling Complexity in the Heart of Software. Addison-Wesley Professional.

  2. Ghemawat, S., Grandl, R., Petrovic, S., Schwarzkopf, M., Whittaker, M., & McKinley, K. S. (2023). Towards Modern Development of Cloud Applications. In Proceedings of the 19th Workshop on Hot Topics in Operating Systems (HotOS ‘23). ACM. https://doi.org/10.1145/3593856.3595909

  3. Khononov, V. (2023). Balancing Coupling in Software Design: Successful Software Architecture in General and Distributed Systems in Particular. Addison-Wesley Professional.

  4. Newman, S. (2021). Building Microservices: Designing Fine-Grained Systems (2nd ed.). O’Reilly Media.

  5. Nrwl. (2024). Nx: Smart Monorepos · Fast CI. Retrieved from https://nx.dev

  6. Mysliwiec, K. et al. (2024). NestJS: A progressive Node.js framework. Retrieved from https://nestjs.com

  7. Google. (2023). Service Weaver: A Framework for Writing Distributed Applications. Retrieved from https://serviceweaver.dev

  8. Spring. (2024). Modulith: A Modular Monolith Toolkit for Spring Boot. Retrieved from https://spring.io/projects/spring-modulith

  9. Fowler, M. (2014). Microservices: A Definition of This New Architectural Term. Retrieved from https://martinfowler.com/articles/microservices.html

  10. Vernon, V. (2013). Implementing Domain-Driven Design. Addison-Wesley Professional.

  11. Vernon, V. (2021). Strategic Monoliths and Microservices: Driving Innovation Using Purposeful Architecture. Addison-Wesley Signature Series.

  12. Nrwl. Enterprise Monorepo Angular Patterns. Nrwl Press.

  13. Richards, M., & Ford, N. (2020). Fundamentals of Software Architecture: An Engineering Approach. O’Reilly Media.

  14. Ford, N., Richards, M., Sadalage, P., & Dehghani, Z. (2021). Software Architecture: The Hard Parts: Modern Trade-Off Analyses for Distributed Architectures. O’Reilly Media.

  15. Ford, N., Parsons, R., & Kua, P. (2017). Building Evolutionary Architectures: Support Constant Change. O’Reilly Media.

  16. Skelton, M., & Pais, M. (2019). Team Topologies: Organizing Business and Technology Teams for Fast Flow. IT Revolution Press.

  17. Newman, S. (2019). Monolith to Microservices: Evolutionary Patterns to Transform Your Monolith. O’Reilly Media.

  18. Richardson, C. (2018). Microservices Patterns: With Examples in Java. Manning Publications.


Sobre os Autores

Waldemar Neto é cofundador da TechLeads.club e possui experiência em arquitetura de software em empresas como ThoughtWorks e Atlassian e startups de alto crescimento. Especialista em sistemas evolutivos e práticas de engenharia de software.

William Calderipe é cofundador da TechLeads.club com experiência em desenvolvimento enterprise na Atlassian e outras organizações de larga escala. Foco em arquiteturas escaláveis e práticas de DevOps.


Contato:

Licença: Este trabalho está licenciado sob Creative Commons Attribution 4.0 International (CC BY 4.0).

Você é livre para:

Sob os seguintes termos:

Mais informações: https://creativecommons.org/licenses/by/4.0/

Como citar este trabalho:

Neto, W., & Calderipe, W. (2025). Arquiteturas Modulares: 10 Princípios para 
Construir Sistemas Evolutivos. TechLeads.club Whitepaper, v1.0.

Versão: 1.0
Data de Publicação: 13 de Outubro de 2025
Status: Publicação Inicial — Feedback bem-vindo