C4 Model na prática: Container Diagram (Parte 2)

C4 Model na prática: Container Diagram (Parte 2)

Arquitetura
Repositório de exemplos: todos os diagramas desse post estão em github.com/wander4747/c4model

No post anterior vimos o Context Diagram: o sistema como caixa preta, mostrando só quem usa e com o que ele se comunica. Agora vamos abrir essa caixa.

O que é o Container Diagram

O Container Diagram responde: como o sistema é composto tecnicamente?

Aqui “container” não tem nada a ver com Docker. No C4 Model, container é qualquer coisa que precisa estar rodando pra o sistema funcionar: uma aplicação web, uma API, um banco de dados, uma fila de mensagens, um serviço mobile. O diagrama mostra:

  • Containers que compõem o sistema (aplicações, serviços, bancos, filas)
  • Tecnologia de cada container (linguagem, framework, protocolo)
  • Relações entre eles, incluindo a tecnologia de comunicação
  • Os atores e sistemas externos do Context Diagram, agora se conectando a containers específicos em vez de ao sistema como um todo

É o diagrama mais útil no dia a dia de um time técnico. Onboarding de um novo engenheiro, discussão de uma mudança de infraestrutura, revisão de arquitetura: o Container Diagram costuma ser o ponto de partida.

As macros do Container Diagram

A biblioteca C4-PlantUML usa C4_Container.puml em vez do C4_Context.puml visto na Parte 1. Person, System_Ext e Rel continuam do jeito que já vimos. Três coisas novas entram em cena.

Container

Container(alias, "Label", "Technology", "Description")

Representa uma aplicação ou serviço: um frontend, uma API, um worker.

  • alias: identificador interno, sem espaços
  • "Label": nome exibido
  • "Technology": stack usada (ex: "Vue.js", "PHP / Symfony")
  • "Description": o que esse container faz
Container(api, "API Service", "PHP / Symfony", "Endpoints REST pro frontend e pro CMS")

ContainerDb

ContainerDb(alias, "Label", "Technology", "Description")

Mesma coisa que Container, mas renderizado com o ícone de cilindro: a convenção visual pra banco de dados ou qualquer armazenamento persistente.

ContainerDb(content_db, "Content Database", "PostgreSQL", "Artigos, posts, categorias e comentários")

Existe também ContainerQueue, pro caso de fila de mensagens (Kafka, RabbitMQ, SQS). Mesma sintaxe, ícone diferente.


System_Boundary

System_Boundary(alias, "Label") {
    ' containers aqui dentro
}

Agrupa visualmente os containers que pertencem ao seu sistema, desenhando uma borda ao redor deles. Não é obrigatório, mas ajuda a deixar claro onde termina o seu sistema e onde começam as dependências externas, principalmente quando o diagrama tem vários containers.

System_Boundary(sb, "Blog Platform") {
    Container(frontend, "Frontend SPA", "Vue.js", "Interface pública de leitura")
    ContainerDb(content_db, "Content Database", "PostgreSQL", "Artigos e comentários")
}

Rel, de novo

Rel já foi coberto na Parte 1, mas aqui o parâmetro de tecnologia importa de verdade:

Rel(frontend, api, "Busca artigos e comentários", "HTTPS/REST JSON")

No Context Diagram, tecnologia era ruído. No Container Diagram, é a informação mais importante da relação: é o que diz pra um engenheiro como as peças conversam entre si.

Exemplo completo: Blog

Pegando o mesmo sistema da Parte 1 e abrindo a caixa:

@startuml blog
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Container.puml

title "Blog Platform - Container Diagram"

Person(reader, "Reader", "Pessoa que lê os posts do blog")
Person(author, "Author", "Pessoa que escreve os posts")

System_Boundary(sb, "Blog Platform") {
    Container(frontend, "Frontend SPA", "Vue.js", "Interface pública onde leitores navegam pelos artigos")
    Container(cms, "CMS Admin", "Vue.js / Nuxt", "Painel administrativo onde autores criam e gerenciam conteúdo")
    Container(api, "API Service", "PHP / Symfony", "Endpoints REST pro frontend e pro CMS")
    Container(cdn, "CDN", "Cloudflare", "Serve assets estáticos e mídia em cache pros leitores")
    ContainerDb(content_db, "Content Database", "PostgreSQL", "Artigos, posts, categorias e comentários")
    ContainerDb(storage, "File Storage", "Amazon S3", "Imagens e arquivos de mídia")
}

System_Ext(email, "SendGrid", "Serviço de envio de e-mails de notificação")

Rel(reader, frontend, "Lê artigos e posts", "HTTPS")
Rel(author, cms, "Cria e gerencia conteúdo", "HTTPS")
Rel(frontend, api, "Busca artigos e comentários", "HTTPS/REST JSON")
Rel(cms, api, "Cria, atualiza e publica conteúdo", "HTTPS/REST JSON")
Rel(api, content_db, "Lê e escreve artigos, posts e comentários", "TCP/SQL")
Rel(api, storage, "Envia e busca arquivos de mídia", "HTTPS/AWS SDK")
Rel(api, email, "Envia e-mails de notificação de comentários", "HTTPS/REST")
Rel(cdn, storage, "Busca e cacheia arquivos de mídia da origem", "HTTPS")
Rel(frontend, cdn, "Carrega assets estáticos e mídia via CDN", "HTTPS")

@enduml

O que era uma caixa única no Context Diagram virou seis containers: dois frontends, uma API, uma CDN e dois armazenamentos. Reader e Author continuam presentes, mas agora cada um fala com um container específico, não com “o Blog” genericamente. E aparece um detalhe que não existia antes: o SendGrid, que na Parte 1 nem chegou a aparecer, porque quem se comunica com ele é a API, um detalhe interno demais pro nível de Context.

O que colocar e o que deixar de fora

Coloca:

  • Todo container que roda de forma independente (aplicação, serviço, banco, fila)
  • A tecnologia de cada container
  • A tecnologia/protocolo de cada relação
  • Sistemas externos que se conectam a containers específicos (agora fica claro qual container conversa com eles)

Não coloca:

  • Múltiplas instâncias do mesmo container (load balancer com 5 réplicas da API é 1 Container no diagrama, não 5)
  • Classes, funções, estrutura interna de um container (isso é nível de Component)
  • Detalhes de infraestrutura de deploy (Kubernetes, VPC, região): isso não é C4, é diagrama de infraestrutura

A regra prática: se a resposta pra “isso precisa rodar separado dos outros?” for sim, é um container. Se não, é detalhe demais pra esse nível.

O que vem a seguir

No próximo post entro no Component Diagram, abrindo um container específico (a API, por exemplo) e mostrando como ele é organizado por dentro: controllers, services, repositories.

Os exemplos desse post estão no repositório github.com/wander4747/c4model, na pasta container/.


Container Diagram é onde a maioria das conversas técnicas realmente acontece. Não é abstrato demais pra perder o ponto, nem detalhado demais pra virar código. É o meio-termo que funciona.

Tags: c4model arquitetura diagramas plantuml documentação