Como tornar mais fácil entender uma grande base de código


104

Suponha que eu esteja desenvolvendo um projeto relativamente grande. Eu já documentei todas as minhas classes e funções com o Doxygen, no entanto, tive uma ideia de colocar "notas do programador" em cada arquivo de código-fonte.

A idéia por trás disso é explicar em termos leigos como uma classe específica funciona (e não apenas o porquê, como a maioria dos comentários). Em outras palavras, dar aos colegas programadores uma visão diferente de como uma classe funciona.

Por exemplo:

/*
 * PROGRAMMER'S NOTES:
 *
 * As stated in the documentation, the GamepadManager class 
 * reads joystick joystick input using SDL and 'parses' SDL events to
 * Qt signals.
 *
 * Most of the code here is about goofing around the joystick mappings.
 * We want to avoid having different joystick behaviours between
 * operating systems to have a more integrated user experience, since
 * we don't want team members to have a bad surprise while
 * driving their robots with different laptops.
 *
 * Unfortunately, we cannot use SDL's GamepadAPI because the robots
 * are interested in getting the button/axes numbers, not the "A" or
 * "X" button.
 *
 * To get around this issue, we created a INI file for the most common 
 * controllers that maps each joystick button/axis to the "standard" 
 * buttons and axes used by most teams. 
 *
 * We choose to use INI files because we can safely use QSettings
 * to read its values and we don't have to worry about having to use
 * third-party tools to read other formats.
 */

Essa seria uma boa maneira de facilitar um grande projeto para novos programadores / colaboradores entenderem como ele funciona? Além de manter um estilo de codificação consistente e uma organização de diretórios 'padrão', existem 'padrões' ou recomendações para esses casos?


32
De jeito nenhum. Se o seu código estiver ilegível, a documentação não ajudará.
Telastyn

35
@jeffo - o problema é que reservar um tempo para fazer isso pode acontecer uma vez. O tempo para manter o código legível acontece com o tempo. Eu já estive em lugares com esse tipo de documentação, feito quando o projeto era jovem ou quando Joe, o perfeccionista, ainda estava na equipe. Em seguida, foi abandonado e os comentários persistiram, não sendo mais precisos.
Telastyn

25
Em um nível mais alto, pelo menos, uma descrição em prosa fora do código do que um projeto faz, como funciona e quais compensações foram feitas na arquitetura são inestimáveis. Esse tipo de documento é uma leitura obrigatória para um recém-chegado antes que ele faça um tour de código. Há muita besteira da minha metodologia é radical demais para os docs na rede e, embora seja verdade que um documento inicial do arco e um documento em evolução do arco não se alinham, é necessária uma descrição da prosa para que qualquer um compreenda rapidamente uma base de código grande e não trivial. Aqui está um exemplo (ruim): zxq9.com/erlmud/html/001-002_architecture.html
zxq9

11
@ Telastyn: Isso não tem nada a ver com o código ser legível ou não (e eu espero que seja). Documentar a lógica do projeto é absolutamente importante.
Lightness Races in Orbit (

7
@Telastyn: Sim, talvez. Pessoalmente, eu o escreveria em um documento independente. Mas os blocos de comentários na parte superior dos arquivos de origem não são tão ruins.
Lightness Races em órbita em

Respostas:


139

Isso é incrível. Desejo que mais desenvolvedores de software gastem tempo e esforço para fazer isso. Isto:

  • Declara em inglês simples o que a classe faz (ou seja, é responsabilidade),
  • Fornece informações suplementares úteis sobre o código sem repetir literalmente o que o código já diz,
  • Descreve algumas das decisões de design e por que foram tomadas, e
  • Destaca algumas das dicas que podem acontecer com a próxima pessoa que está lendo seu código.

Infelizmente, muitos programadores entram no campo de "se o código for escrito corretamente, ele não deverá ser documentado". Não é verdade. Existem muitos relacionamentos implícitos entre classes de código, métodos, módulos e outros artefatos que não são óbvios apenas pela leitura do próprio código.

Um codificador experiente pode criar com cuidado um design com arquitetura clara e de fácil compreensão que seja óbvia sem documentação. Mas quantos programas como esse você realmente viu?


15
E por que o "Mês do Homem Mítico" se torna uma profecia auto-realizável, ninguém dedicou um tempo para escrever tudo isso para o novo desenvolvedor, quando estava fresco em sua mente e o projeto não ficou para trás.
JeffO 01/08/2015

3
Eu concordo com todos os argumentos que você faz aqui. Não gosto do termo que o OP usou em seu post how a class works. Isso muda com o tempo e a manutenção. Embora minha equipe não coloque isso acima na fonte. Mantemos um wiki com decisões e copiamos a discussão do canal de folga sobre as decisões brutas de design em um documento (fornecemos um link do resumo e da conclusão da decisão para as notas brutas, para que não tenhamos que re-misturar as decisões antigas). Tudo feito ordenadamente no github (portanto, está tudo em um só lugar).
Martin York

1
Meu único problema é aplicar isso globalmente. Essa classe é complexa o suficiente, com algumas dicas disponíveis, claramente é realmente útil (embora você ainda acabe lidando com a podridão de comentários). Quando uma aula é mais óbvia, o comentário pode ser um pouco supérfluo.
deworde

1
"Um codificador experiente pode criar cuidadosamente um design com uma arquitetura clara e de fácil compreensão que é óbvia sem documentação. Mas quantos programas como esse você realmente viu"? Embora isso seja verdade, a qualidade da documentação nunca é melhor do que a qualidade da o código. O código bem arquitetado tende a ter uma boa documentação, embora sem sentido. Mal código arquitetado tem comentários como "incremento x por 1"
deworde

3
Concordo plenamente com esta resposta e, se encontrasse algo como o exemplo do OP no código, ficaria muito feliz. Apenas uma adição: considere adicionar uma data ao seu comentário, apenas para dar uma dica aos leitores quanto ao frescor da descrição e atualizá-la sempre que atualizar o texto.
Svalorzen

36

A chave para trabalhar com uma grande base de código é não ter que ler toda a base de código para fazer uma alteração. Para permitir que um programador encontre rapidamente o código que está procurando, ele deve ser organizado e a organização aparente. Ou seja, cada unidade lógica no código, do executável, da biblioteca, do namespace até a classe individual deve ter uma responsabilidade claramente aparente. Portanto, eu não apenas documentaria os arquivos de origem, mas também os diretórios em que residem.

As anotações do programador também fornecem informações detalhadas sobre as decisões de design. Embora possa ser uma informação valiosa, eu a separaria da declaração de responsabilidade (para permitir que o leitor escolha se deseja ler sobre a responsabilidade da classe ou sua lógica de design) e a mova o mais próximo possível da fonte que descreve possível, para maximizar a chance de a documentação ser atualizada quando o código é (a documentação é útil apenas se pudermos confiar em sua precisão - a documentação desatualizada pode ser pior do que nenhuma!).

Dito isto, a documentação deve permanecer SECA, ou seja, não repetir as informações que poderiam ter sido expressas em código ou que já foram descritas em outros lugares (frases como "como a documentação declara" são um sinal de aviso). Em particular, futuros mantenedores serão apenas proficientes na linguagem de programação do projeto, assim como em inglês; parafrasear a implementação nos comentários (que eu vejo muitas vezes quando as pessoas se orgulham de sua documentação) não tem benefício e provavelmente diverge da implementação, principalmente se a documentação não estiver próxima do código que descreve.

Finalmente, a estrutura da documentação deve ser padronizada em todo o projeto para que todos possam encontrá-la (é uma bagunça real de documentos de Peter no rastreador de erros, Sue no wiki, Alan no leia-me e John no código-fonte ...) .


Sua primeira frase é exatamente como eu vejo isso. As grandes bases de código devem ser compostas como um número de componentes menores, nos quais um novo programador pode alterar de maneira confiável um sem colocar em risco nenhum dos outros.
9134 Jon Chesterfield

1
mova-o para o mais próximo possível da fonte que descreve, para maximizar a chance de a documentação ser atualizada quando o código for . Esta é uma experiência valiosa.
precisa saber é o seguinte

DRY como uma diretriz para a documentação é um ponto muito bom! Isso ajusta automaticamente o foco e proíbe os comentários desagradáveis ​​de "// incremento de x em 1".
Hans-Peter Störr

13

Eu não concordaria que esta é uma abordagem muito boa, principalmente devido a

  1. Quando você refatorar seu projeto, mova os métodos, a documentação será interrompida.

  2. Se a documentação não for atualizada corretamente, isso resultará em mais confusão do que em ajudar a entender o código.

Se você tiver testes de unidade para cada método / testes de integração para cada módulo, seria uma documentação própria mais sustentável e mais fácil de entender em comparação com os comentários do código.

Sim, ter uma estrutura de diretórios adequada definitivamente ajudará.


+1 para testes, sendo a melhor maneira de entender uma base de código. Testes de unidade, testes de integração e testes de aceitação contam a história de como o aplicativo deve funcionar e como deve ser usado.
BZink

7

Pessoalmente, sou fã de um documento de design de alto nível - de preferência escrito antes de qualquer código - que fornece uma visão geral do design e uma lista de classes e recursos. Um design de cima para baixo simplifica bastante as coisas - o seu pode ser "motor de jogo -> hardware -> controladores -> joystick"; assim, um novo programador disse "consertar o botão 'a' no 'xyz controller" saberia pelo menos por onde começar a procurar.

Muitas linguagens modernas tendem a dividir o código em centenas de arquivos minúsculos, portanto, encontrar o arquivo correto pode ser um desafio, mesmo em um projeto moderado.


16
20 anos atrás, todo o meu código estava em um arquivo enorme. Agora está em milhares de pequenos arquivos e arquivos de teste. Há uma boa razão para isso e reflete 20 anos de desenvolvimento de software (o ecossistema geral, não o meu conhecimento). Waaay muito tempo para um comentário.
quer

4
ah, o velho método em cascata de escrever uma Verdade única, abrangente e imutável, antes mesmo da codificação começar, e torna impossível se desviar na implementação da referida Verdade.
Jwenting 02/08/2015

2
@jwenting: Você não precisa levar isso tão longe. Mas ainda é bom ter uma ideia do que você está construindo.
Robert Harvey

1
Certamente, sem a ressalva de como quebrar isso adequadamente e onde quebrar as regras, você terá muito rapidamente um documento desatualizado ou uma pedra de moinho. "Eu preciso adicionar uma nova aula; ao Documanto, o Behemoth que consome tempo!"
deworde

2
@ Deworde: Eu li isso como "com preguiça de manter a documentação".
Robert Harvey

6

Se a base de código for grande - tento fornecer um documento de design que mapeie os principais elementos de seu design e implementação . A intenção aqui não é detalhar nenhuma das classes usadas, mas fornecer uma chave para o código e o pensamento que foi inserido no design. Ele fornece um contexto abrangente para o sistema, seus componentes e sua aplicação.

Os itens a serem incluídos no documento de design são;

  • Arquitetura de aplicativos
  • Estrutura de código lógico
  • Fluxos de dados
  • Padrões-chave usados ​​e a motivação por trás de seu uso
  • Estrutura de código fonte
  • Como construí-lo (isso oferece informações sobre dependências implícitas e estrutura de origem do código físico)

A seguir, a documentação para as classes e funções / métodos deve ser preenchida conforme apropriado . Em particular a API pública; deve ficar claro o que todos são os seguintes em cada caso;

  • Condições prévias
  • Efeitos
  • Invariantes
  • Condições de exceção (lançamentos)

+1 Melhor do que descrever cada classe, pois isso ficará desatualizado mais rapidamente do que um design geral.
Lode

4

A regra mais importante que encontrei para facilitar o entendimento de uma base de código pelos novos desenvolvedores é que o acordo perfeito é caro.

Se os novos desenvolvedores precisam entender perfeitamente o sistema em que estão trabalhando, isso impede todas as oportunidades de aprendizado no trabalho. Acho que as anotações do programador são um excelente começo, mas eu iria além. Tente escrever um código que, se abordado de novo, permitiria que um desenvolvedor descobrisse o que está fazendo em tempo real, em vez de exigir que aprendessem antes de fazê-lo. Pequenas coisas como afirmações para casos que você conhece nunca podem ocorrer, junto com comentários explicando por que a afirmação é válida, percorre um longo caminho. O mesmo acontece com a escrita de códigos que falham normalmente, em vez de segfaulting, se você fizer algo errado.


Minha regra é que os comentários sejam sobre POR QUE , não COMO . O código descreve como.
user11393

3

Eu já vi grandes classes com documentação e, depois de ler a documentação, não tenho idéia do que essa classe deve ser boa e por que alguém a usaria! E, ao mesmo tempo, eu precisava de algumas funcionalidades e tinha certeza absoluta de que deveria haver uma classe para lidar com isso, e não conseguia encontrá-lo em nenhum lugar - porque não havia documentação que me levasse do que eu precisava para a classe Fazendo.

Portanto, a primeira coisa que eu gostaria na documentação é apenas algumas frases do que uma classe faz e por que eu gostaria de usá-la. Os comentários na pergunta original estão indo muito bem nesse sentido. Depois de ler esses comentários, se eu tivesse um joystick que não funciona bem porque não consigo interpretar os valores que ele fornece, saberia qual código verificar.


0

Semelhante ao que o @meriton disse, divida o código em componentes separados. Melhor ainda, divida a base de código em pacotes separados (JARs, gemas, ovos, o que for) para deixar ainda mais claro como os componentes são separados. Se houver um erro, o desenvolvedor só precisa encontrar o pacote em que está o erro e (espero) apenas corrigi-lo lá. Sem mencionar, é mais fácil fazer testes de unidade e você pode aproveitar o gerenciamento de dependências.

Outra solução: diminua a base de código. Quanto menos código houver, mais fácil será entender. Refatorar o código não utilizado ou duplicado. Use técnicas de programação declarativa . Isso exige esforço, é claro, e muitas vezes não é possível nem prático. Mas é um objetivo digno. Como Jeff Atwood escreveu: O melhor código não é nenhum código


-1

Para sistemas complexos, pode valer a pena não apenas documentar cada arquivo, mas suas interações e hierarquia, e como o programa estrutura e por quê.

Por exemplo, um mecanismo de jogo geralmente é bastante complexo e é difícil decidir o que chama o que chama depois de cem camadas de abstração. Pode valer a pena criar um arquivo como "Architecture.txt" para explicar como e por que o código está estruturado dessa maneira e por que existe essa camada de abstração sem sentido ali.


-7

Isso pode ser em parte porque é difícil para um único programador escrevê-lo, pois cada indivíduo entende apenas sua parte do projeto.

Às vezes, você pode obter essas informações nas anotações do gerente de projetos, mas isso é tudo que você obtém, pois elas raramente reescrevem as anotações nesse formato.


7
Se você olhar no github, encontrará muitos projetos com esse tipo de nota em um arquivo README.md. Tornou-se parte da cultura do git em geral e os projetos javascript em particular para a maioria das pessoas não usarão uma biblioteca que não possua esse tipo de documentação de alto nível. Portanto, não é verdade que "nenhum programador escreveria", pois você só precisa olhar para algo como jQuery ou socket.io e encontrar programadores que escrevem essas coisas. Também se tornou uma cultura que arquivos README que não são precisos geram relatórios de erros.
slebetman

1
Isso não parece responder à pergunta, que estava procurando por razões pelas quais o estilo de documentação proposto funcionaria ou não, e também para os padrões de documentação.
user52889

5
Se você tem uma equipe de programadores trabalhando em um produto, e cada programador entende apenas o código específico em que trabalhou, sua equipe não apenas é incrivelmente disfuncional com um fator de barramento absurdo, mas também questiona a qualidade do código. Como alguém integra o código em um produto sem entender o restante do código no mesmo sistema ??!?
Lightness Races in Orbit (
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.