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:
- Escopo: um component. Um diagrama de Code nunca abrange um container inteiro, muito menos um sistema. Ele abre exatamente um component -- o
OrderRepository, oPaymentService-- e mostra o que há dentro. - 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. (Nossos exemplos de modelo C4 levam sistemas reais até o nível 3; este desce um nível a mais.) 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
PaypalPaymentServiceimplementando a mesma interface -- a estrutura torna o ponto de extensão óbvio. - O que acontece em caso de falha? A classe
RetryPolicydeté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.