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?
fonte
Respostas:
Isso é incrível. Desejo que mais desenvolvedores de software gastem tempo e esforço para fazer isso. Isto:
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?
fonte
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).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 ...) .
fonte
Eu não concordaria que esta é uma abordagem muito boa, principalmente devido a
Quando você refatorar seu projeto, mova os métodos, a documentação será interrompida.
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á.
fonte
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.
fonte
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;
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;
fonte
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.
fonte
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.
fonte
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
fonte
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.
fonte
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.
fonte