Code Comments
Filosofia e regras de comentários cross-language: WHY-not-WHAT por default; comentário só quando o motivo é não-óbvio; doc comments per-lang com formato canônico; TODO/FIXME/HACK com handle + ticket; commented-out code proibido; license header quando aplicável; module docstring quando obrigatório. Anti-patterns enumerados.
When this spec applies
Primary triggers
- Editar código fonte e considerar adicionar comentário
All triggers
- Escrever comentário em código fonte
- Code review verificando comentários
- Decidir se documenta uma função pública
- Refatorar bloco de comentários redundantes
Specification body
Spec — Code Comments
Facet Code do Koder Design.
Codifica formalmente a regra global do CLAUDE.md ("default to no comments") como spec auditável + estende com formato per-lang, doc styles, TODO conventions e anti-patterns.
Filosofia: WHY-not-WHAT
Default: não escrever comentário. Identificadores bem nomeados
(per code/naming.kmd) + funções curtas (per code/functions.kmd)
são a documentação primária do que o código faz.
Escrever comentário só quando:
- Esconde-se um WHY não-óbvio (constraint de negócio, invariante sutil, workaround por bug específico, comportamento que surpreende)
- O comportamento depende de algo fora do arquivo (spec externa, protocolo de terceiros, RFC, ticket de incidente)
- A escolha entre alternativas igualmente válidas precisa de justificativa pra evitar refactor inútil futuro
Não escrever comentário quando:
- Apenas repete o nome do identificador (
# increment counterem cima decounter += 1) - Descreve o WHAT que já é óbvio do código
- Referencia o "task atual"/"este fix"/"caller X" — isso pertence à PR description, não ao código (commit message + git blame preservam a referência sem rotação)
- Marca código removido (
# was: foo()) — git history tem isso
Exemplos
# ❌ Comenta o WHAT óbvio
# increment retry counter
retries += 1
# ✅ Comenta o WHY não-óbvio
# OAuth2 server occasionally returns 502 mid-handshake (vendor bug
# tracked in #4471); retry up to MAX_RETRIES with backoff before
# surfacing failure
retries += 1
# ❌ Referencia task atual (rotaciona)
# Added for the new login flow PR-#1234
def authenticate(token)
# ✅ Pertence ao PR/commit, não ao código
def authenticate(token)
Estilo léxico per-language
| Linguagem | Single-line | Multi-line | Doc comment |
|---|---|---|---|
| Koda | # |
(não tem; usar # consecutivos) |
#: em linhas consecutivas (3+) |
| Go | // |
(não tem; usar // consecutivos) |
// PascalName ... antes de export |
| Dart | // |
/* */ |
/// ou /** */ (dartdoc) |
| Python | # |
(não tem) | """...""" triple-quoted (PEP 257) |
| Rust | // |
/* */ |
/// ou //! (módulo) |
| JS/TS | // |
/* */ |
/** */ (JSDoc/TSDoc) |
| Shell | # |
(não tem) | n/a |
| SQL | -- |
/* */ |
n/a |
Princípio: usar o formato idiomático da linguagem; não forçar uniformidade total que viola o uso esperado pelo IDE/linter.
Doc comments
R1 — Quando obrigatório
- Toda função/método/classe pública (exportada do módulo)
- Toda constant pública não-trivial (não óbvia pelo nome)
- Todo módulo/package (docstring no topo)
R2 — Quando opcional
- Funções privadas curtas (≤10 linhas) com nome auto-explicativo
- Test functions (nome
test_ouit_should_é a doc)
R3 — Formato
Mínimo: 1 linha de resumo. Quando relevante: 1 linha em branco + detalhes (parâmetros, retorno, raises, exemplos).
def hash_password(password: str) -> str:
"""Hash a password with Argon2id."""
def hash_password(password: str, *, time_cost: int = 3) -> str:
"""Hash a password with Argon2id.
Time cost defaults to 3 (OWASP 2024 recommendation). Use higher
values for high-security contexts; benchmark target: ~50ms on
modern CPU.
Args:
password: Plaintext password (max 72 bytes effective).
time_cost: Argon2 t parameter; 3 ≤ t ≤ 10.
Returns:
PHC-format hash string (`$argon2id$v=19$...`).
Raises:
ValueError: If password is empty or time_cost out of range.
"""
R4 — Koda specific (#: triple-line)
Ver code/languages/koda-style.kmd § Doc comments. Resumo:
#: Compute SHA-256 hash of a string.
#:
#: Returns 64-char lowercase hex. Raises EncodingError on
#: invalid UTF-8.
def sha256(s)
...
end
TODO / FIXME / HACK / XXX / NOTE / WARN
R5 — Formato canônico
# TODO(@handle, ticket): description
# FIXME(@handle, ticket): description
# HACK(@handle, ticket): description — explanation of why
# XXX(@handle): something dangerous; needs careful review
# NOTE: something readers should know but isn't actionable
# WARN: behavior that surprises; non-obvious side effect
R6 — Quando usar cada um
| Marker | Significado |
|---|---|
TODO |
Trabalho planejado, não-urgente; tem ticket |
FIXME |
Bug conhecido; deve ter ticket |
HACK |
Workaround consciente; explicar o porquê + ticket de remoção |
XXX |
Algo perigoso/duvidoso que merece revisão |
NOTE |
Informação útil pro leitor, não-actionable |
WARN |
Comportamento surpreendente; alerta defensivo |
R7 — Regras
- TODO/FIXME/HACK devem ter
(@handle, ticket)— autor + ticket de tracking - Linter falha se TODO/FIXME sem ticket após 30 dias
- HACK exige explicação do porquê após
:(não pode ser só# HACK: fix later) XXXnão exige ticket mas exige revisão code-review- Markers em inglês (mesmo em comentário pt-BR raro — markers são vocabulário fechado universal)
R8 — Heisenbug workarounds
Caso especial: diagnóstico que "acidentalmente conserta" um bug pode ser shipado como workaround permanente, mas exige:
- Comentário explícito explicando que é workaround
- Ticket de follow-up pra root-cause investigation
- Marker
HACKouXXX
(Padrão registrado em memory feedback_heisenbug_workaround_pattern.)
Commented-out code
Proibido. Delete + git history. Linter falha se ≥5 linhas consecutivas comentadas com sintaxe que casa com a linguagem.
# ❌
def foo():
bar()
# baz()
# qux()
# frob()
return bar.result()
# ✅
def foo():
bar()
return bar.result()
# git blame mostra o que foi removido
Exceção rara: bloco de exemplo/template em README ou doc comment
(aceito porque o # está dentro de docstring/markdown).
Section headers
Quando arquivo tem ≥200 linhas e seções lógicas distintas, usar section headers:
# ============================================================
# Public API
# ============================================================
def authenticate(...): ...
def logout(...): ...
# ============================================================
# Internal helpers
# ============================================================
def _hash(...): ...
Não obrigatório; não adicionar em arquivos curtos onde o file outline do IDE já dá a estrutura.
License header
R9 — Política Koder
Default: não exigir license header em todo arquivo. Razões:
- LICENSE no root do repo é canônica
- Header em todo arquivo polui git diff e onboarding
- Tooling moderno (SBOM, REUSE) lê do
LICENSEdireto
Exceção: arquivos publicados como SDK público pra terceiros
(em engines/sdk/* quando publicado em registry público) — seguem
SPDX short-form:
// SPDX-License-Identifier: Apache-2.0
// Copyright (c) Koder. See LICENSE file in the project root.
Auditor verifica per-módulo via koder.toml [license_header]
opcional.
Module-level docstring
Obrigatório quando o módulo expõe API pública:
"""Identity service client for the Koder ID OIDC provider.
Provides authentication primitives compatible with the
specs/identity/login-resolution.kmd contract. Used by all Koder apps
via koder_kit.
"""
// Package identity provides the OIDC client for Koder ID.
//
// See specs/identity/login-resolution.kmd for the resolution contract.
package identity
Anti-patterns
AP-C1 — Comentário que repete o nome
# ❌
def get_user_by_id(user_id):
"""Get user by id."""
...
AP-C2 — Comentário desatualizado vs código
Se o comentário diverge do código, deletar o comentário (não "corrigir" — o código é a verdade).
AP-C3 — Banner "Created by X on Y"
# ❌
# Author: Joe Smith
# Created: 2024-01-15
# Last modified: 2024-12-20
Git tem essa informação. Linter falha.
AP-C4 — Long-form blog post em comentário
Se a explicação tem >20 linhas, mover pra:
- Doc adjacente (
<file>.mdoudocs/<topic>.kmd) - ADR/RFC se for decisão arquitetural
Comentário curto referencia o doc.
AP-C5 — Emoji em comentário sem motivo
Comentários técnicos não usam emoji por default. Exceção: marker
formal WARN pode ser // ⚠️ WARN: ... em algumas codebases —
manter consistência por projeto.
AP-C6 — Disclaimer/legal boilerplate inline
Pertence ao LICENSE ou NOTICE, não ao top de cada arquivo.
Audit deterministic
comments-audit.sh:
- TODO/FIXME/HACK sem
(@handle, ticket)→ warning (>30 dias = error) - ≥5 linhas consecutivas comentadas (commented-out code) → error
- Banner "Author/Created/Modified" → error
- Doc comment ausente em export pública → warning
- Module docstring ausente em módulo com API pública → warning
Severidade medium por enquanto (warning não-bloqueante); migrar
pra hard quando coverage estabilizar.
Cross-link
- Regra global "default to no comments" em CLAUDE.md (
policies/global) code/naming.kmd— nomes auto-explicativos reduzem necessidade de comentáriocode/functions.kmd— funções curtas reduzem necessidadecode/languages/koda-style.kmd— KodaDoc#:específicoreadmes/products.kmd— onde docs maiores vivem
References
rfcs/design-RFC-001-koder-design-system.kmdspecs/code/indentation.kmdspecs/code/naming.kmdspecs/code/languages/koda-style.kmdspecs/readmes/products.kmdpolicies/design-governance.kmd