Estilos de codificação ao usar várias bibliotecas diferentes

9

Estou trabalhando em algum código C ++ que usa várias bibliotecas, incluindo algumas bibliotecas C, todas com estilos de codificação diferentes. Será aberto quando chegar a um estágio utilizável. O que causaria a menor confusão para um colaborador de curto prazo que verifica o código para corrigir um bug ou adicionar um recurso?

  • Tenha um estilo de codificação consistente em todo o aplicativo, mesmo que ocasionalmente não corresponda ao estilo de codificação típico das bibliotecas usadas.
  • Quando uma biblioteca é muito usada em um determinado módulo, conforme o estilo de codificação típico dessa biblioteca (ou seja, o estilo de codificação usado no próprio código e documentação da biblioteca) nesse módulo.

Meu pensamento é que o último facilitará a contribuição de especialistas nessa biblioteca específica e facilitará a incorporação de código de tutorial / exemplo durante o desenvolvimento. No entanto, também torna o estilo de codificação inconsistente em todo o aplicativo. Quais são os prós e os contras de cada abordagem?

Karl Bielefeldt
fonte
4
Seria possível evitar esse problema agrupando todas as bibliotecas em suas próprias abstrações personalizadas? Seu próprio código e abstrações podem seguir um único estilo de codificação.
MetaFight
Muito do que estou fazendo é abstrair essas bibliotecas. A questão é qual estilo de codificação usar dentro da abstração.
Karl Bielefeldt
6
Ah Não sou especialista aqui, mas parece que seria melhor usar a convenção da própria biblioteca. Usar uma convenção incompatível soa como um pesadelo de manutenção. E desde que o estilo da biblioteca esteja contido na classe / módulo que a abstrai, presumo que esteja tudo bem. Mais uma vez, não sou profissional aqui, mas isso parece ser um bom equilíbrio que garante uma manutenção mais fácil em suas abstrações e também permite que você tenha seu próprio estilo no restante do aplicativo.
MetaFight
11
Às vezes, abstrações como essa podem ficar um pouco feias, faça o possível para mantê-la limpa, independentemente das convenções usadas, mas, acima de tudo, verifique se a API que você apresenta da abstração é de qualidade suficiente para que você não precise voltar atrás na intromissão da abstração e os consumidores poderão trabalhar com consistência com as abstrações facilmente, para garantir que o código deles não se torne uma bagunça como o que pode estar nas abstrações. Portanto, em resumo, não há uma boa resposta, mas desde que suas abstrações apresentem boas APIs, pelo menos você está impedindo que o problema se espalhe por elas.
Jimmy Hoffa
11
O que exatamente você quer dizer com "estilo de codificação" - coisas simples como usar_escores / camelCase / PascalCase e localização da chave, ou coisas mais complexas como classe / método / layout de função e estilo imperativo / funcional?
amigos estão dizendo sobre Izkata

Respostas:

10

Eu acho que depende do tamanho do projeto geral.

Em um extremo, digamos que você tenha um projeto de 1 Mloc. Para esse grande projeto, é improvável que um único indivíduo seja um "especialista" em todas as áreas envolvidas. Portanto, nesse caso, eu ficaria com os estilos de código existentes para cada componente principal. Os novos desenvolvedores escolherão uma área, aprenderão isso e é improvável que eles vejam muitos outros componentes que podem ter estilos de código diferentes.

Se o projeto for muito menor, onde é provável que as pessoas entendam toda a base de código, eu escolheria um estilo de código dominante e o manteria. Nesse caso, acho que a consistência em todo o projeto faz mais sentido, porque é provável que novos desenvolvedores trabalhem em todas as áreas do projeto.

Projetos de médio porte são talvez os mais difíceis de tomar essa decisão. Nesse caso, você deve ponderar os custos de cada abordagem e decidir qual você acha que será menos caro a longo prazo. O desafio é que os projetos de tamanho médio geralmente crescem apenas o suficiente para um refatoramento de estilo completo parecer proibitivamente caro. Você pode dar uma olhada na estrutura da árvore de códigos para ver se as coisas podem ser organizadas para agrupar estilos de código específicos.

De qualquer forma, a decisão final deve ser da equipe em que você está montando este pacote.


Alguns dos valores extremos que podem mudar meu raciocínio de cima:

  • Se um ou mais módulos têm um estilo atroz, não faz sentido manter isso por perto, mesmo em um projeto maior. Sim, o estilo é subjetivo, mas se você e seus colegas participantes do projeto realmente não gostam da maneira como determinadas áreas fluem, então refaça o estilo antigo e ofereça um melhor.

  • Se todos os estilos estiverem razoavelmente próximos um do outro, pode ser igualmente fácil declarar "aqui está o novo caminho" e usá-lo para todos os novos códigos e refatorações significativas. Isso pode tornar as revisões um pouco trabalhosas, mas, na minha experiência, a maioria das pessoas é capaz de se adaptar a essa abordagem. Ele também fornece um sinal revelador onde está o código antigo.

  • Às vezes, o estilo é alterado com base nas novas funcionalidades adicionadas ao idioma. O C ++ pegou vários recursos ao longo dos anos. Pode fazer sentido refatorar, conforme necessário, o estilo antigo para um estilo mais recente que aproveite esses recursos.

  • Algumas bibliotecas podem ter uma abordagem ou estilo particularmente idiomático. Nesse caso, eu continuaria com esse estilo para essa biblioteca, mesmo que ela possa entrar em conflito com o restante do projeto. A intenção aqui é aumentar as chances de alguém que trabalhar frobnosticatorsem outros projetos também trabalhar no seu projeto.


Alguns dos comentários mencionaram estilos imperativos e orientados a objetos como sendo uma consideração.

Módulos que são "pesados" em um estilo específico provavelmente devem permanecer assim se o módulo for de tamanho médio ou maior. Trabalhei com os três principais estilos (imperativo, objetivo e funcional) e refatorei os estilos imperativos pesados ​​em um estilo OO. Com uma quantidade média ou maior de código, a refatoração pode ser (excepcionalmente) difícil. Minha experiência foi confusa porque eu não tinha nenhum suporte de ferramentas para ajudar na refatoração.

Eu imagino que exista uma alta correlação entre os módulos fortemente imperativos e os módulos sendo idiomáticos para nichos de desenvolvimento específicos, que remontam ao último ponto que levantei com discrepâncias. Portanto, qualquer módulo que você encontrasse para essa funcionalidade terá essa aparência e você deseja que os especialistas desse domínio também possam trabalhar com facilidade em seu projeto. Mas se houver opções e sua equipe não gostar do estilo desse módulo, investigarei as opções.

Da mesma forma, trabalhei com um módulo com estilo OO pesado em que os princípios OO foram levados longe demais e usados ​​incorretamente. Como exemplo, as interfaces estavam sendo usadas como um substituto para a herança múltipla. E como você poderia esperar, foi uma implementação grosseira. Consegui fazer um progresso razoável na refatoração desse módulo, mas finalmente abandonei essa abordagem, pois encontrei pacotes melhores para usar.


fonte
Essa é uma boa maneira de dizer. Projetos similares são de cerca de 300 KLOC.
Karl Bielefeldt
3

Parece que há várias camadas a serem consideradas, pelo menos:

  1. As bibliotecas existentes e quaisquer modificações nelas.
  2. Novo código de teste de unidade para essas bibliotecas.
  3. A camada de abstração.
  4. A API apresentada pela camada de abstração.
  5. Exemplo e código de teste usando a camada de abstração.

Eu vou assumir que não faz sentido refatorar todo o código para um estilo comum logo de cara - se você não tivesse feito a pergunta.

Tendo em cada um por sua vez:

  1. Para a base de código existente, é provável que você queira seguir esse estilo.
  2. O novo código de teste de unidade para o código existente fica em uma área cinza, principalmente dependendo de quanto ele está integrado ao código mais antigo. Mas, provavelmente, eu tentaria fazê-lo no 'estilo preferido'.
  3. O novo código na camada de abstração. Ao garantir que essa seja realmente uma camada de código separada, não deve haver dificuldade em usar um estilo preferido, mesmo que o código esteja fazendo muita interface com um estilo ou estilos herdados. A maioria dos códigos precisa interagir com outros estilos, e nunca achei isso um problema.
  4. Obviamente, a própria API precisa de mais reflexão e atende às necessidades máximas de usabilidade.
  5. Qualquer exemplo ou código de teste também deve poder ser escrito no estilo preferido. Dependendo da completude da abstração (ou seja, se está ocultando completamente as camadas inferiores), isso pode ser fácil ou difícil. Obviamente, garantir que o futuro código do cliente seja legível será um dos seus principais objetivos.

Algumas coisas que eu encontrei pessoalmente é que, com uma grande base de código herdada:

  • Definir um estilo preferido e impor alterações de código não resulta magicamente na migração de todo o código antigo para o novo estilo.

  • A maioria dos engenheiros costuma gostar de codificar (mais ou menos) o estilo existente em uma determinada biblioteca. Exigir de outra forma resulta em muita aplicação.

  • A exigência de um estilo preferido em uma biblioteca herdada tende a resultar em muita inconsistência de estilo nessa biblioteca. Portanto, para os padrões que são puramente relacionados à apresentação, em oposição à robustez do código, também é difícil ver muitos benefícios em exigi-los.

Como uma questão final (um pouco fora do tópico, mas acho relevante), a verdade é que alguns engenheiros lutam para seguir qualquer padrão de estilo que não seja o que eles conhecem melhor. Eu recomendo fortemente envolver a equipe em decisões de estilo e garantir que haja uma adesão. Depois disso, você estará em uma posição muito melhor para aplicar um padrão em código misto.

Keith
fonte
0

Concordo com o @MetaFight aqui caso você esteja desenvolvendo um projeto de tamanho grande com muitos módulos de terceiros.

Permite mapear seu problema com um problema real de palavras: " Suponha que você tenha um estilo de vida tranquilo em sua casa. Você gosta do seu lugar para ficar quieto, nunca fala mais alto e nunca gosta de qualquer membro da sua família. Mas você interage com muitos pessoas diferentes fora todos os dias para trazer algo para sua casa.Não necessariamente elas também falam em voz baixa, nesse caso, você se molda adequadamente ao lidar com essas pessoas.Portanto, a interface ou o invólucro para essas pessoas é altamente flexível apenas por uma questão de seu trabalho a ser feito. "Exemplo idiota ... lol

Mas meu objetivo é criar um invólucro para essas bibliotecas, de acordo com seu padrão de codificação, de forma que você as utilize através desses invólucros, mantendo seu estilo de codificação original.

+1 para o MetaFight.

theinsaneone
fonte
Exatamente a solução certa. Eu uso wrappers para amarrar o código que outras pessoas escrevem para meus projetos também. Defina uma interface antecipadamente e, quando a implementarem, você poderá envolvê-la e testá-la na caixa preta.
Kieveli
11
Por que isso está diminuindo? Eu acho que este é claramente a melhor solução :)
MetaFight
0

Isso causaria claramente a menor quantidade de confusão para usar um único estilo de codificação em todo o projeto. O objetivo de usar um estilo de codificação em primeiro lugar é tornar o código mais fácil de ler e modificar.

Quanto ao estilo de código usado internamente em uma biblioteca, não acho relevante. Se a biblioteca é muito imperativa, escrever um wrapper OO é bom, mas isso não exige que você use o mesmo estilo de código dos exemplos ou internos da biblioteca.

Gustav Bertram
fonte