É melhor documentar funções no arquivo de cabeçalho ou no arquivo de origem?

86

Nas linguagens que distinguem entre um arquivo "fonte" e "cabeçalho" (principalmente C e C ++), é melhor documentar funções no arquivo de cabeçalho:

(roubado do CCAN )

/**
 * time_now - return the current time
 *
 * Example:
 *  printf("Now is %lu seconds since epoch\n", (long)time_now().tv_sec);
 */
struct timeval time_now(void);

ou no arquivo de origem?

(roubado do PostgreSQL)

/*
 * Convert a UTF-8 character to a Unicode code point.
 * This is a one-character version of pg_utf2wchar_with_len.
 *
 * No error checks here, c must point to a long-enough string.
 */
pg_wchar
utf8_to_unicode(const unsigned char *c)
{
...

Observe que algumas coisas são definidas apenas no cabeçalho, como estruturas, macros e static inlinefunções. Estou falando apenas de coisas que são declaradas em um arquivo de cabeçalho e definidas em um arquivo de origem.

Aqui estão alguns argumentos em que consigo pensar. Estou inclinado a documentar no arquivo de origem, então meus argumentos "Pro-header" podem ser um pouco fracos.

Cabeçalho profissional:

  • O usuário não precisa do código fonte para ver a documentação.
    • A fonte pode ser inconveniente ou até impossível de adquirir.
    • Isso mantém a interface e a implementação ainda mais separadas.

Pro-fonte:

  • Isso torna o cabeçalho muito mais curto, oferecendo ao leitor uma visão panorâmica do módulo como um todo.
  • Ele associa a documentação de uma função à sua implementação, facilitando ver que uma função faz o que diz que faz.

Ao responder, tenha cuidado com argumentos baseados no que as ferramentas e os "IDEs modernos" podem fazer. Exemplos:

  • Cabeçalho profissional: a dobragem de código pode ajudar a tornar os cabeçalhos comentados mais navegáveis ​​ocultando os comentários.
  • Pro-source: o recurso do cscopeFind this global definition leva você ao arquivo de origem (onde está a definição ) e não ao arquivo de cabeçalho (onde está a declaração ).

Não estou dizendo que não faça tais argumentos, mas lembre-se de que nem todo mundo se sente à vontade com as ferramentas que você usa.

Joey Adams
fonte
A mesma pergunta pode ser aplicada ao Pascal / Delphi, onde não temos arquivos de origem e cabeçalho, mas seções de interface e implementação.
Jan Doggen

Respostas:

96

Minha visão...

  • Documente como usar a função no arquivo de cabeçalho ou mais perto da declaração.

  • Documente como a função funciona (se não for óbvia no código) no arquivo de origem ou, mais precisamente, próximo à definição.

Para a coisa de passarinho no cabeçalho, você não precisa necessariamente da documentação que fecha - você pode documentar grupos de declarações de uma só vez.

De um modo geral, o chamador deve estar interessado em erros e exceções (apenas para que possam ser traduzidos à medida que se propagam pelas camadas de abstração); portanto, esses documentos devem ser documentados próximo às declarações relevantes.

Steve314
fonte
13
+1 - isto é, documenta a interface no cabeçalho. Os detalhes sangrentos do como e por que na fonte.
quickly_now
2
Para cabeçalhos de bibliotecas onde não há fonte disponível, talvez adicione condições pré e pós, etc ... para ajudar nos testes. Além disso, adicione O (n) desempenho, se fizer sentido, para que os usuários da biblioteca possam escolher sabiamente.
Patrick Hughes
Naturalmente, às vezes declaração e definição são a mesma coisa.
Deduplicator
@ Reduplicador - quando as mesmas regras ainda levam à coisa certa, mesmo no caso especial, por que repetir essas regras para todos os casos especiais? Certamente um desduplicador não deveria querer isso?
Steve314
1
@Duplicador - é claro que esse é um raciocínio massivamente exagerado por não seguir o seu conselho, mas estou cumprindo.
Steve314
34

Se você usar uma ferramenta como o Doxygen (observe no primeiro exemplo, que realmente se parece com um comentário do Doxygen porque começa com /**), isso realmente não importa - o Doxygen examinará seus arquivos de cabeçalho e de origem e encontrará todos os comentários para gerar a documentação.

No entanto, eu estaria mais inclinado a colocar os comentários da documentação nos cabeçalhos, onde estão as declarações. Seus clientes vão lidar com os cabeçalhos para interagir com seu software, os cabeçalhos são o que incluirão em seus próprios arquivos de origem e é aí que eles procurarão primeiro ver a aparência da sua API.

Se você observar a maioria das bibliotecas Linux, por exemplo, seu sistema de gerenciamento de pacotes Linux geralmente possui um pacote que contém apenas os binários da biblioteca (para usuários "normais" que possuem programas que precisam da biblioteca) e você tem um pacote "dev" que contém os cabeçalhos da biblioteca. O código fonte normalmente não é fornecido diretamente em um pacote. Seria realmente complicado se você tivesse que obter o código fonte de uma biblioteca em algum lugar para obter a documentação da API.

Jesper
fonte
2
+1 - desde que, mesmo que você use Doxygen, isso não significa que você nunca vai ler diretamente da fonte. Às vezes, as anotações de oxigênio são úteis como padrões padrão para as quais grep é útil, e é útil se a anotação encontrada estiver próxima ao código que ela descreve.
Steve314
1
@ Steve314, é claro, eu não disse que você nunca iria querer olhar o código fonte de alguma biblioteca - mas esse não seria o primeiro lugar em que você procuraria a aparência da API e como usá-la.
Jesper
Eu também defenderia manter tudo relacionado à API no cabeçalho (ou pelo menos no cabeçalho ou na fonte), pois isso evitaria incoerência potencial ao atualizar a documentação em um local e não no outro.
jopasserat
12

Resolvemos esse problema (há cerca de 25 anos) criando um monte de #defines (por exemplo, público, privado, etc., resolvidos para <nenhum>) que poderiam ser usados ​​no arquivo de origem e verificados por um script awk (horrores !) para gerar automaticamente os arquivos .h. Isso significa que todos os comentários residiram na fonte e foram copiados (quando apropriado) no arquivo .h gerado. Eu sei que é uma velha escola, mas simplificou bastante esse tipo de documentação embutida.

Peter Rowell
fonte
1
hmm eu sei que este estilo de coisa pode ser útil, mas do meu ponto de vista eu sempre achei que tipo de documentação a ser francamente chato ...
osirisgothra
1
Parafraseando Donald Rumsfeld (um homem de quem não gostei): "Você programa com as ferramentas que possui, não com as ferramentas que gostaria de ter". Todos os idiomas com os quais trabalhei nos últimos 40 anos tiveram pelo menos uma verruga importante (se não mais). Nossa solução a) funcionou, b) utilizou as ferramentas existentes na época, c) passamos nosso tempo obtendo códigos geradores de receita.
precisa
Embora eu provavelmente não opte por isso, é uma maneira interessante de lidar com comentários nos cabeçalhos. Os cabeçalhos gerados estariam no controle de versão? ou isso é algum processo de lançamento para tornar a fonte redistribuível? (mas não é usado pelos desenvolvedores)
ideasman42
Oh, eu vi o mesmo padrão recentemente em um projeto iniciado em ≥ 2000 e eles estavam tão orgulhosos de sua invenção inteligente ...
5gon12eder 12/15/15
3
No nosso caso, não mantivemos nenhum dos arquivos gerados sob controle de versão, pois eles eram fácil e diretamente (re) derivados de arquivos rastreados.
22416 Peter Fieldell
9

Supondo que este seja um código dentro de um projeto maior (onde os desenvolvedores costumam se mover entre a fonte e os cabeçalhos) , e fornecendo que isso não seja uma biblioteca / middleware, onde outras pessoas podem não ter acesso à fonte, descobri que isso funciona melhor...

  • Cabeçalhos:
    comentários concisos de 1 a 2 linhas, apenas se forem necessários.
    Às vezes, comentários acima de um grupo de funções relacionadas também são úteis.
  • Fonte:
    documentação na API diretamente acima da função (texto simples ou doxygen, se você preferir) .
  • Mantenha os detalhes da implementação, relevantes apenas para um desenvolvedor que modifique o código no corpo da função.

A principal razão para isso é manter os comentários próximos ao código, notei que os documentos nos cabeçalhos tendem a ficar fora de sincronia com as alterações no código com mais frequência (é claro que não deveriam, mas fizeram no nosso projeto em menos) . Os desenvolvedores também podem adicionar documentação na parte superior das funções quando fazem alguma alteração, mesmo se houver documentos de cabeçalho ... em outro lugar. Causando duplicatas ou informações úteis apenas em uma das strings de documentos.

Claro que você pode escolher uma convenção e garantir que todos os desenvolvedores sigam. Acabei de encontrar a convenção acima da forma mais natural e com menos problemas de manutenção.


Por fim, para projetos grandes - há uma tendência a não fazer pequenas correções em um cabeçalho quando você sabe que isso fará com que centenas ou milhares de arquivos sejam recompilados quando outros atualizam o controle de versão - diminuindo também os erros de divisão.

ideasman42
fonte
5

Na minha opinião (bastante limitada e tendenciosa), sou uma maneira de pensar em código pró-fonte. Quando eu faço bits e partes em C ++, geralmente edito o arquivo de cabeçalho uma vez e nunca mais volto a examiná-lo.

Quando coloco a documentação no arquivo de origem, sempre a vejo quando estou editando ou lendo códigos. Eu acho que é uma coisa de hábito.

Mas isso sou só eu ...

MattyD
fonte
1
Não funciona muito bem se tudo o que você tem é uma biblioteca compilada e o arquivo de cabeçalho. Nesse caso, mais informações no cabeçalho são boas, porque é a única documentação de interface que você possui.
quickly_now
você pode gerar documentação com doxygen - é necessário também a partir de arquivos .c. Assim, você pode distribuir documentação facilmente com bibliotecas compiladas. Mas o problema seria com o IDE, que pode analisar arquivos de cabeçalho e fornecer documentação ao usar a função ... Mas talvez ele possa resolver algum script de implantação que copia os comentários da função frm .c para .h ...
Vit Bernatik
5

Comentários não são documentação. A documentação para uma função geralmente pode ter 2K de texto, possivelmente com diagramas - consulte, por exemplo, a documentação para funções no SDK do Windows. Mesmo se o seu comentário ao documento permitir isso, você estará tornando o código que contém o comentário ilegível. Se você deseja produzir documentação, use um processador de texto.

Neil Butterworth
fonte
atualização, é muito mais fácil documentar hoje em dia (com coisas como o Qt creator por aí) documentar apenas a maneira doxygen (ou clone); por exemplo, no qtc, basta pressionar a tecla / algumas vezes antes do comentário e metade do trabalho é feito para você. Por causa disso, duvido que as pessoas desejem pular para um processador de texto apenas para documentar seu código. Eu costumava fazer isso, concedido em 2005, mas nunca faria isso agora. Mesmo usando um editor de html parece ser bastante arcaico agora.
Osirisgothra 23/04
@osirisgothra Doxygen- "documentação" pode ser fácil, e certamente produz muitos LOCs escritos rapidamente, mas o valor da "documentação" produzida permanece discutível na grande maioria dos casos. Os comentários sobre o oxigênio não são uma boa documentação (quase todos os detalhes cruciais estão ausentes em geral), nem são bons comentários (eles tendem a repetir o que já é óbvio na assinatura). Eu acho que a nbt está certa ao dizer que a documentação real não deve ser misturada ao código porque é prejudicial à legibilidade do código. Vai ficar fora de sincronia de qualquer maneira, não há bala de prata para isso.
cmaster
4

Se os participantes do seu código-fonte (digamos, uma pequena biblioteca) consistirem em "usuários" (colegas desenvolvedores que usarão a funcionalidade da sua biblioteca sem se envolver na implementação) e "desenvolvedores" (você e outros desenvolvedores que implementarão a biblioteca) , coloque as "informações dos usuários" no cabeçalho e a "nota de implementação" na fonte.

Com relação ao desejo de não alterar os arquivos de cabeçalho mais do que o absolutamente necessário - suponho que se sua biblioteca não estiver "em um fluxo louco de mudanças", que a "interface" e a "funcionalidade" não mudem muito, e nem os comentários do cabeçalho devem mudar com muita frequência. Por outro lado, os comentários do código-fonte deverão ser mantidos sincronizados ("atualizados") com o código-fonte.

rwong
fonte
0

O objetivo principal do uso do doxygen é que você gera documentação e a torna acessível em outro lugar. Agora toda essa documentação nos cabeçalhos é apenas lixo, o que torna mais difícil detectar rapidamente a declaração de função necessária e talvez suas sobrecargas. O comentário de um forro é o máximo que deve ir para lá, mas mesmo isso é uma má prática. Porque, se você alterar a documentação na fonte, recompila essa fonte e vincula novamente. Mas se você colocar documentos no cabeçalho, realmente não deseja alterar nada, porque isso acionará parte significativa da reconstrução do projeto.

Slava
fonte
1
este não parece oferecer nada substancial sobre os pontos feitos e explicado na anterior 7 respostas
mosquito
1
@gnat das 7 respostas anteriores, apenas uma é a favor do código contra os cabeçalhos. E esse está dando uma argumentação totalmente diferente.
Slava