Diagrama de Code C4 (Nível 4): quando você precisa dele e quando não - Archyl Blog

O diagrama de Code C4 (nível 4) mostra as classes, interfaces e funções dentro de um component. A maioria das equipes deveria pulá-lo -- mas nem sempre. Este guia cobre quando o nível 4 do modelo C4 vale o seu lugar, quando um diagrama de classes UML é esforço desperdiçado e como a geração automatizada muda o trade-off.

Diagrama de Code C4 (Nível 4): quando você precisa dele e quando não

O diagrama de Code é o nível mais incompreendido do modelo C4. É o nível que a maioria das equipes pula, o nível que o próprio Simon Brown descreve como opcional e, ainda assim, é também o nível que gera o maior número de perguntas: "A gente realmente precisa desenhar nossas classes?" "Isso não é só UML?" "Quem mantém isso quando o código muda?"

A resposta curta: na maior parte do tempo, você não precisa de um diagrama de code C4. A resposta mais longa é mais interessante, porque os casos em que o nível 4 de fato compensa são exatamente os casos em que as equipes perdem mais tempo sem ele -- algoritmos densos, domínios regulados e onboarding em código que ninguém mais entende por completo.

Este guia cobre o que um diagrama de code C4 de fato mostra, por que desenhá-lo à mão é quase sempre um erro, as situações específicas em que o nível 4 do modelo C4 vale a pena e como a geração automatizada inverte por completo o cálculo de custo-benefício.

Se você é novo no modelo C4, comece pelo nosso guia completo do modelo C4 primeiro -- este artigo pressupõe que você conhece os quatro níveis.

O que é um diagrama de Code C4?

O diagrama de Code é o nível 4 do modelo C4 -- o nível de zoom mais profundo. Onde o diagrama de Component (nível 3) mostra os principais blocos de construção dentro de um container, o diagrama de Code dá zoom em um único component e mostra seus detalhes em nível de implementação:

  • Classes e suas relações (herança, composição, dependência)
  • Interfaces e os tipos que as implementam
  • Funções e métodos, incluindo assinaturas-chave
  • Estruturas de dados como entidades, value objects e DTOs

Na prática, um diagrama de nível 4 do C4 geralmente é renderizado como um diagrama de classes UML ou um diagrama de entidade-relacionamento. O modelo C4 não prescreve uma notação para este nível -- ele delega explicitamente a padrões existentes, porque o problema de desenhar classes foi resolvido décadas atrás.

Duas propriedades definem o nível de Code:

  1. Escopo: um component. Um diagrama de Code nunca abrange um container inteiro, muito menos um sistema. Ele abre exatamente um component -- o OrderRepository, o PaymentService -- e mostra o que há dentro.
  2. Granularidade: símbolos reais de código. Toda caixa em um diagrama de Code corresponde a uma classe, interface ou função real no código-fonte. Não sobra abstração. Este é o nível em que o diagrama e o código devem ser a mesma coisa.

Essa segunda propriedade é precisamente o motivo de o nível 4 ser tão frequentemente pulado, como veremos. (Para uma referência rápida, veja a entrada de diagrama de code no nosso glossário.)

A própria recomendação de Simon Brown: não o desenhe

Aqui está a parte que surpreende quem encontra o modelo C4 pela primeira vez: seu criador recomenda contra criar diagramas de Code à mão. A orientação de Simon Brown é que o nível 4 é opcional e, quando você de fato precisa dele, ele deve ser gerado sob demanda a partir do código-fonte -- pela sua IDE, por ferramentas de documentação ou por qualquer outra coisa que leia o código de verdade -- em vez de desenhado e mantido manualmente.

O raciocínio é difícil de contestar:

  • O código muda constantemente. Um diagrama de classes desenhado à mão é preciso por aproximadamente o tempo que alguém leva para fazer merge do próximo pull request. Cada renomeação, cada método extraído, cada novo campo o torna um pouco mais errado.
  • A informação já existe. Diferentemente de um diagrama de Container -- que captura decisões que não vivem na cabeça de ninguém nem em arquivo algum -- um diagrama de Code duplica aquilo que o código-fonte já afirma com precisão.
  • As ferramentas fazem melhor. IDEs modernas (IntelliJ, Visual Studio e companhia) geram diagramas de classes a partir do código em segundos. Eles são sempre precisos porque são derivados, não desenhados.

Então a posição padrão de qualquer equipe que adota o C4 deveria ser: modele os níveis 1-3, gere o nível 4 quando necessário. Diagramas de Contexto, Container e Component capturam conhecimento que não está no código. O nível de Code é o código.

Quando um diagrama de Code C4 de fato vale a pena

"Geralmente pule" não é "sempre pule". Existem situações reais em que uma visão em nível de código merece seu lugar na sua documentação.

1. Algoritmos complexos e designs intrincados

Alguns components implementam uma lógica que é genuinamente difícil de acompanhar lendo arquivos de cima a baixo: um motor de precificação com estratégias encadeadas, uma máquina de estados governando ciclos de vida de pedidos, um parser com uma hierarquia profunda de visitors. Quando a estrutura do código é o insight -- quando entender qual classe delega para qual é a batalha inteira -- um diagrama de Code comprime horas de leitura de código em uma única figura.

O teste: se um engenheiro sênior precisa de um quadro branco para explicar o component a outro engenheiro sênior, esse esboço no quadro branco é um diagrama de Code esperando para ser capturado.

2. Domínios regulados e auditados

Em finanças, saúde, aviação e outras indústrias reguladas, auditores e avaliadores frequentemente exigem documentação em nível de implementação: qual classe trata dados do portador do cartão, onde a criptografia é aplicada, como a trilha de auditoria é escrita. Aqui um diagrama de nível 4 não é um "seria bom ter" -- é evidência. O mesmo se aplica a revisões de segurança e modelagem de ameaças, onde o fluxo de dados por classes específicas importa.

3. Onboarding em código denso e de vida longa

Components legados com anos de decisões acumuladas são brutais para novos integrantes. Um diagrama de Code dos três ou quatro components mais assustadores do seu código -- aqueles em que o conhecimento tribal está concentrado -- pode reduzir drasticamente o tempo de onboarding. Novos desenvolvedores veem a forma do component antes de mergulhar em 8.000 linhas dele.

4. Documentar contratos públicos e design patterns

Se um component expõe uma superfície de API contra a qual outras equipes constroem, ou implementa um padrão (Strategy, Observer, ports-and-adapters hexagonais) em que a estrutura é a documentação, uma visão em nível de código torna o contrato explícito.

Quando você não precisa dele (que é na maior parte do tempo)

Seja honesto sobre os casos inversos, porque eles cobrem a maioria dos components em qualquer sistema:

  • O código é legível. Um component bem nomeado com pacotes claros não precisa de um diagrama. A árvore de pastas é o diagrama.
  • O nível 3 já responde à pergunta. Se alguém pergunta "como o order service fala com pagamentos?", essa é uma pergunta de diagrama de Component. Desenhar classes adiciona ruído, não sinal.
  • O component é um CRUD simples. Um handler, um service, um repository, um model. Todo mundo já viu esse formato mil vezes. Documentá-lo em nível de classe não documenta nada.
  • Ninguém pediu. A documentação deveria responder a perguntas que as pessoas de fato têm. Se ninguém jamais precisou de uma visão em nível de classe de um component, criar uma é esforço gasto em material de prateleira.

O princípio orientador da abordagem C4 mais ampla se aplica aqui com força total: todo diagrama que você cria é um diagrama que você precisa manter. Nos níveis 1-3, o custo de manutenção te compra conhecimento que não existe em lugar algum. No nível 4, ele geralmente te compra uma cópia ligeiramente mais bonita e ligeiramente desatualizada do seu código-fonte.

Como a geração automatizada muda a equação

Tudo acima pressupõe que alguém precisa desenhar e manter o diagrama. Essa suposição é o que tornou o conselho "pule ou gere" de Simon Brown a escolha certa -- o custo do nível 4 manual quase nunca justificava o benefício.

A automação remove o lado do custo dessa equação. A descoberta por IA da Archyl analisa seu repositório conectado e extrai elementos em nível de código -- classes, interfaces e funções -- diretamente do código-fonte, anexando-os aos components corretos no seu modelo C4. Em vez de um desenvolvedor desenhar o PaymentService e seus colaboradores em uma ferramenta de diagramas, o modelo é populado a partir do que de fato existe no código e permanece conectado ao repositório de onde veio.

Isso muda a pergunta de "vale a pena manter o nível 4?" para "vale a pena ter o nível 4?" -- uma barra muito mais fácil de superar. Quando a visão em nível de código é gerada e atualizada em vez de desenhada à mão:

  • Ela nunca mente, porque é derivada do código-fonte e não da memória que alguém tem do código-fonte.
  • Ela é navegável em contexto: você desce de sistema para container, para component, para code em um único modelo, em vez de caçar um PNG em uma wiki.
  • Os casos que eram "valiam a pena apesar do custo" (auditorias, onboarding, components complexos) passam a valer a pena trivialmente, e os casos marginais ficam de graça.

Você ainda aplica julgamento sobre quais components merecem atenção no nível 4 -- uma visão gerada de um component CRUD trivial ainda é ruído. Mas o modo de falha muda de "diagrama desatualizado engana a equipe" para "visão não usada que não custa nada".

Um exemplo resolvido: dentro de um component de processamento de pagamento

Vamos tornar isso concreto. Suponha que seu diagrama de Component (nível 3) mostre um component PaymentProcessor dentro do seu container de API backend. Dar zoom nele no nível 4 poderia revelar:

[PaymentService (interface)]
  ├── ProcessPayment(order, method) -> PaymentResult
  └── RefundPayment(paymentID, amount) -> RefundResult

[StripePaymentService] ──implements──> [PaymentService]
[StripePaymentService] ──uses──> [StripeAdapter] : wraps the Stripe SDK
[StripePaymentService] ──uses──> [RetryPolicy] : exponential backoff, 3 attempts
[StripePaymentService] ──uses──> [PaymentRepository] : persists payment records

[StripeAdapter] ──maps──> [PaymentResult] : translates Stripe responses to domain types
[RetryPolicy] ──raises──> [PaymentFailedError] : after exhausting retries
[PaymentRepository] ──persists──> [Payment (entity)]

Repare no que esta visão responde e que o nível 3 não consegue:

  • Onde está a costura para testar? PaymentService é uma interface; os testes podem substituí-la por um fake sem tocar no Stripe.
  • Onde um segundo provedor se encaixaria? Um PaypalPaymentService implementando a mesma interface -- a estrutura torna o ponto de extensão óbvio.
  • O que acontece em caso de falha? A classe RetryPolicy detém o comportamento de backoff; PaymentFailedError é o caminho de escalação. Um auditor perguntando "o que acontece quando uma cobrança falha?" obtém uma resposta do diagrama.
  • O que toca o banco de dados? Apenas PaymentRepository. O fluxo de dados do portador do cartão é rastreável, o que importa enormemente em um component dentro do escopo PCI.

Este é um component em que o nível 4 se paga: ele é financeiramente sensível, o tratamento de falhas não é óbvio e múltiplas classes colaboram em um padrão deliberado. Compare-o com, digamos, um UserProfileHandler que lê e escreve um registro de perfil -- desenhá-lo em nível de classe não te diria nada que a árvore de arquivos não diga.

Erros comuns com o nível 4 do C4

Manter diagramas de classes à mão

A falha clássica. Um engenheiro motivado desenha lindos diagramas de classes para todo o código; seis meses depois eles descrevem um código que não existe mais e agora enganam ativamente. Se um diagrama de Code não é gerado a partir do código-fonte -- ou, no mínimo, regenerado em uma cadência -- trate-o como vencido no dia em que é desenhado.

Documentar getters, setters e boilerplate

Um diagrama de Code que lista todo acessador, sobrecarga de construtor e método utilitário tem o mesmo problema de um mapa em escala 1:1. Inclua os elementos que carregam intenção de design -- interfaces, colaborações-chave, os métodos que definem o contrato -- e omita a cerimônia. Visões geradas devem ser filtradas, não despejadas.

Usar o nível 4 onde o nível 3 basta

Se o seu "diagrama de code" mostra coisas como "o controller chama o service que chama o repository", você desenhou um diagrama de Component com caixas em forma de classe. Recolha-o de volta ao nível 3. Reserve o nível 4 para components cuja estrutura interna é a parte interessante.

Desenhar o container inteiro em nível de classe

Um diagrama de 200 classes abrangendo um serviço inteiro viola a hierarquia C4 e é ilegível de qualquer forma. Um diagrama de Code cobre um component. Se você não consegue dar a ele um escopo tão restrito, as fronteiras dos components no seu diagrama de nível 3 provavelmente precisam ser repensadas.

Tratar o nível 4 como obrigatório para uma documentação "completa"

Algumas equipes adotam o C4 com uma mentalidade de checklist: quatro níveis, então quatro conjuntos de diagramas. O resultado é esforço desperdiçado e ressentimento com a prática toda. O C4 é explícito quanto a o nível 4 ser opcional. Três níveis bem mantidos vencem quatro apodrecendo sempre.

FAQ

O nível 4 do C4 é só um diagrama de classes UML?

Na maior parte, sim -- e isso é por design. O modelo C4 não define sua própria notação para o nível de Code; ele recomenda reutilizar as existentes, e um diagrama de classes UML é a escolha mais comum (diagramas ER funcionam para components centrados em dados). O que o C4 adiciona é escopo e contexto: o diagrama de classes descreve exatamente um component, e esse component fica dentro de uma hierarquia navegável de diagramas de container e sistema. Um diagrama de classes UML isolado flutua solto; um diagrama de code C4 tem um endereço.

Devo criar um diagrama de code para todo component?

Não. A maioria dos components é simples o suficiente para que o código-fonte seja a melhor documentação. Reserve o nível 4 para components que são algoritmicamente complexos, sensíveis à segurança ou compliance, ou notórios obstáculos de onboarding. Se a documentação é gerada automaticamente, o custo de ter mais cobertura cai -- mas a atenção ainda é finita, então faça a curadoria do que você expõe.

Como mantenho um diagrama de code atualizado?

Não o mantendo à mão. Gere-o: a partir da sua IDE sob demanda, a partir de ferramentas de documentação no CI ou a partir de uma plataforma como a Archyl, que extrai classes, interfaces e funções do seu repositório durante a descoberta por IA e mantém o nível de código anexado ao seu modelo de components. Qualquer processo que dependa de um humano lembrar de atualizar um diagrama de classes após uma refatoração vai falhar.

Qual é a diferença entre um component e um elemento de code no C4?

Um component (nível 3) é um agrupamento lógico com uma única responsabilidade -- "a parte que trata de pagamentos" -- e pode se estender por várias classes e arquivos. Um elemento de code (nível 4) é um símbolo real no código-fonte: uma classe, interface ou função específica. Components são abstrações que você escolhe; elementos de code são fatos que o compilador impõe.

A conclusão final

O diagrama de code C4 é o nível que você deveria pular por padrão e implantar de forma deliberada. Os níveis 1-3 capturam conhecimento arquitetural que não existe em lugar algum; o nível 4 espelha o que o código já diz, então ele só conquista um lugar quando a estrutura em si é a parte difícil -- algoritmos complexos, components regulados, código legado denso -- e, idealmente, quando é gerado em vez de desenhado.

Se você de fato quer visões em nível de código sem o imposto de manutenção, conecte um repositório à Archyl e deixe a descoberta por IA extrair as classes, interfaces e funções para o seu modelo C4 automaticamente. Você obtém a profundidade quando precisa dela, e ninguém precisa redesenhar um diagrama de classes nunca mais.


Quer subir um nível? Leia o guia do diagrama de Component C4, revise com o guia completo do modelo C4 ou explore a visão geral do modelo C4. Pronto para experimentar? Comece com a Archyl gratuitamente.