Qual é o equilíbrio certo entre consistência de código e melhoria de código?

52

Recentemente, tive uma discussão com um colega sobre o estilo do código. Ele estava argumentando que seu uso de APIs e os padrões gerais que você está usando devem ser o mais semelhante possível com o código circundante, se não com o codebase como um todo, assim como faria com a aparência de código (posicionamento de chave, capitalização etc) . Por exemplo, se eu estivesse adicionando um método a uma classe DAO em C #, tentaria usar LINQ quando necessário para ajudar a tornar meu código limpo e fácil de manter, mesmo se nenhum dos outros métodos dessa classe o estivesse usando. No entanto, meu colega argumentaria que eu não deveria usá-lo nesse caso porque seria contra o estilo existente dessa classe e, portanto, mais difícil de entender.

No começo eu achei a posição dele bastante extrema, mas depois de pensar por um tempo, estou começando a ver o que ele disse. Com o exemplo hipotético de LINQ, talvez essa classe não contenha isso porque meus colegas não estão familiarizados com o LINQ? Em caso afirmativo, meu código não seria mais sustentável para meus colegas desenvolvedores se eu não o usasse? Por outro lado, se eu realmente acredito que usar tal técnica resultaria em um código mais limpo, então eu não deveria usá-lo mesmo que difira drasticamente do código circundante?

Acho que o ponto crucial do argumento de meu colega é que, se todos nós implementarmos uma funcionalidade semelhante em uma base de código de maneiras diferentes, cada um de nós acha que nosso caminho é "melhor", então, no final, o código como um todo fica mais difícil de entender. No entanto, no momento, ainda acho que, se seguirmos cegamente demais o código existente, a qualidade irá apodrecer lentamente ao longo do tempo.

Então, até que ponto os padrões são parte do estilo de código e onde devemos estabelecer a linha entre permanecer consistente e fazer melhorias?

    
por Robert Johnson 15.03.2013 / 08:55
fonte

9 respostas

53

Para dar uma resposta mais geral:

Em um caso como este, você tem duas "melhores práticas" de programação que se opõem: a consistência do código é importante, mas também é escolher o melhor método possível para realizar sua tarefa. Não há uma resposta correta para esse dilema; isso depende de alguns fatores:

  • Qual é o benefício da maneira "correta"?

    • Às vezes, as melhores práticas novas e aprimoradas aumentarão drasticamente o desempenho, eliminarão bugs, serão muito mais fáceis de programar, etc. Nesse caso, eu me apoiaria bastante no uso do novo método. Por outro lado , a "maneira correta" pode ser um pouco mais que um açúcar sintático, ou um método idiomático concordado de fazer algo que não é realmente superior. Nesse caso, a consistência do código é provavelmente mais importante.
  • Qual o tamanho de um problema que a inconsistência criaria?

    • Como interconectado é o novo código com código legado? Seu novo código é parte de uma biblioteca? Cria um objeto que é passado para muitas partes do programa? Em casos como esses, a consistência é muito importante. Usar uma nova API, ou uma nova maneira de fazer as coisas em geral, pode criar resultados sutilmente diferentes, que quebram as suposições em outras partes do programa. Por outro lado , se você estiver escrevendo uma parte do código bastante isolada, a inconsistência será menos provável de ser um problema.
    • Qual é o tamanho e a maturidade da sua base de código? Quantos desenvolvedores precisam entender e trabalhar nisso? Padrões concordantes e consistentes são muito mais importantes para projetos maiores.
    • O código precisa ser executado em ambientes mais antigos que talvez não ofereçam suporte aos recursos mais recentes?

Com base no equilíbrio desses problemas, você precisa fazer a escolha certa sobre qual rota seguir. Pessoalmente, vejo pouco valor na consistência por causa da consistência, e preferiria usar os melhores e mais recentes métodos, a menos que haja um custo significativo para isso.

Claro, há uma terceira opção: reescrever o código existente para que ele use os melhores métodos e é consistente. Há momentos em que isso é necessário, mas isso tem um custo alto.

    
por 15.03.2013 / 10:17
fonte
26

Permanecer consistente tem pouco valor na minha perspectiva; continuamente fazendo melhorias é uma obrigação.

A posição do seu colega realmente impede a inovação. O argumento de consistência coloca você em uma situação em que você pode usar, por exemplo, LINQ somente se você migrar o código all para usar o LINQ. E bem, não temos tempo para isso, não é?

Eu prefiro ter inconsistência onde algum código ainda está fazendo foreach sobre ArrayLists e outras partes usam LINQ em IEnumerable<T> , em vez de aderir à maneira mais antiga de fazer as coisas até o final dos tempos.

É responsabilidade de seus colegas permanecerem relevantes e aprenderem novas maneiras de fazer as coisas.

    
por 15.03.2013 / 09:59
fonte
8

A consistência da API é muito importante, tanto para APIs públicas quanto internas.

A consistência da formatação de código é importante e, idealmente, deve ser aplicada por uma ferramenta de formatação automática com as mesmas regras de formatação para todos. Torna a convivência com a base de código compartilhada controlada pela versão mais fácil.

As convenções de nomenclatura devem ser consistentes, também para coisas como variáveis locais, etc.

Ferramentas de análise estática devem ser usadas para reforçar certas convenções e boas práticas (mas não siga cegamente os padrões de qualquer ferramenta desse tipo, os padrões podem às vezes ser insanos), mas se algo exigir isso, não tenha medo para desabilitar alguma verificação (geralmente com uma diretiva dentro de um comentário) temporariamente, se você puder justificá-la.

O que acontece dentro de funções / métodos , além do que está listado acima, não precisa ser consistente de forma alguma, contanto que seja um bom código por conta própria . Bom, compreensível, bem código comentado é muito importante, mas depois disso, se as ferramentas de análise estática e de compiladores acharem que o código é consistente, isso é consistente o suficiente.

Sobre novos recursos como o LINQ (bem, isso não é exatamente novo), a única coisa que precisa ser considerada é: novas versões de linguagem / bibliotecas estarão em uso em qualquer lugar onde o código será usado? Em caso de dúvida, atenha-se a recursos conhecidos como compatíveis. Isso obviamente não impede que você faça uma atualização de versão em todo o sistema, para que você possa começar a usar as novas coisas legais.

E todos os desenvolvedores que trabalham com código devem se manter atualizados, portanto qualquer desenvolvedor .NET deve conhecer o LINQ e, se não o fizer, eles devem ser forçados a aprender, para seu próprio bem (nunca se sabe quando você estará procurando para um novo emprego neste negócio, por um motivo ou outro).

    
por 15.03.2013 / 09:20
fonte
5

A resposta para isso é simples.

A consistência é de suma importância.

mas vem com uma ressalva ...

Você e seu colega de trabalho provavelmente estão obcecados com o tipo errado de consistência

As implementações são descartáveis. Eles podem ser completamente revisados com vários graus de facilidade, dependendo da qualidade e abrangência do conjunto de testes. Preocupando-se com coisas como "Isso deve ser uma propriedade?", "O código não deve usar o LINQ em vez de uma construção de nível inferior?" é de valor duvidoso. Sua variação é difícil de vincular qualquer medida ao valor da consistência no nível de implementação. Uma pergunta muito melhor para perguntar nesse nível é "Esse código funciona como anunciado?". A consistência de implementação de DR é onde as "mentes pequenas" colocam seu Hobgoblin.

Por que a consistência não é tão importante aqui? Implementações geralmente têm um pequeno número de colaboradores. A maioria dos métodos é escrita e nunca mais tocada. Do código restante, o número de métodos que tem dois contribuidores quase certamente é a maioria. Esse padrão continua ad infinitum . Neste contexto, a consistência não é tão importante. Se o prazo de validade do código for muito pequeno ( alguns anos ), os ganhos da consistência agressiva provavelmente não são fatores.

Isso não quer dizer que você deva ficar louco em suas implementações. Pelo contrário, é para dizer que um design simples, limpo e agradável terá ordens de grandeza mais valiosas para seu mantenedor futuro hipotético do que o método de consistência de placa de caldeira bobo por método. Isso nos leva ao ponto real ...

As APIs não são descartáveis.

Isso é tudo nível de código de APIs, serviços da Web, SDKs etc. Esses devem, devem, ser consistentes. Os ganhos de produtividade dessa variedade de consistência são enormes por vários motivos:

Testes de integração:

Se você mantiver sua API consistente, poderá criar conjuntos de testes de integração. Estes permitem que os desenvolvedores troquem livremente os detalhes da implementação e obtenham uma validação imediata. Quer trocar sua porcaria co-works para LINQ? Os testes de integração são executados? Também fornece validação quando se prepara para ir para a produção. Como os computadores são rápidos, um único laptop pode executar o trabalho de milhares de testadores que executam tarefas comuns. É o mesmo que aumentar consideravelmente o número de funcionários da sua organização.

Produtividade

Quando as APIs são consistentes, você pode adivinhar como usar uma API apenas seguindo o que aprendeu sobre outras partes da API. Isso ocorre porque a API oferece uma aparência "natural e consistente". Isso significa que seu cliente gasta menos tempo analisando a documentação. A integração é mais fácil e barata. Menos perguntas são feitas para as pessoas que desenvolveram a API. Consistência faz de todos um vencedor

Por que a consistência é importante nesse cenário? Porque as APIs têm o problema exatamente oposto das implementações. O número de pessoas que os utilizam é normalmente muito maior do que o número de pessoas que contribuem para suas implementações. Pequenos ganhos de pouca consistência são multiplicados e os custos de manutenção dessa consistência são amortizados.

Conclusão

A consistência é cara. Por sua vez, reduz a produtividade. Isso restringe os desenvolvedores e dificulta a vida deles. Ele coloca limitações nas maneiras como eles podem resolver um problema, às vezes, forçando-os a resolvê-lo de uma maneira não ideal. Isto é frequentemente por razões que eles não entendem, são mal concebidos, ou não estão a par (contratos, políticas organizacionais ou interorganizacionais maiores).

Raymond Hettinger fez alguns pontos excelentes em sua palestra sobre Pycon 2015 sobre o uso do guia de estilo PEP8 para equipes de programadores python. Ele mostrou que a obsessão pela consistência estilística em um pedaço de código fazia com que os revisores de código perdessem falhas sérias na lógica e no design. Sua hipótese pode ser resumida como encontrar inconsistências estilísticas é fácil; determinar a qualidade real de um pedaço de código é difícil

O ponto aqui é crítico. Identifique onde a consistência é importante e proteja-a agressivamente. Onde não é importante, não perca seu tempo. Se você não puder fornecer uma maneira objetiva de medir o valor da consistência (nos casos acima, "efetivo de funcionários", custo como uma função da produtividade) e você não pode demonstrar que os retornos são substanciais, então provavelmente você está fazendo um desserviço para sua organização.

    
por 02.05.2015 / 16:03
fonte
4

Unfamiliar with LINQ? If so, wouldn't my code be more maintainable for my fellow developers if I didn't use it?

A linguagem C # ainda está evoluindo. Se as pessoas não aprendessem as alterações do C # 1, elas estariam perdendo:

  • Genéricos
  • Parciais
  • Métodos anônimos
  • Iteradores
  • Tipos anuláveis
  • Propriedades automáticas
  • Tipos anônimos
  • Métodos de extensão
  • Ling
  • Lambdas
  • Métodos assíncronos

Esta é apenas uma pequena seleção de recursos comuns encontrados no artigo da Wikipedia. O ponto que estou fazendo é que, se os desenvolvedores não aprenderem, a base de código permanecerá no vácuo. Espera-se que seus desenvolvedores melhorem continuamente e que a base de código evolua, apoiada por um conjunto de testes completo. Você se lembra como foi ruim com o .NET 1 implementar manualmente as propriedades.

Linq facilita a vida. Use-o onde puder. Você pode motivar os membros da sua equipe.

So, to what extent are patterns part of code style, and where should we draw the line between staying consistent and making improvements?

As melhorias são graduais. Para mim, não faz sentido manter o código antigo, que é menos legível e potencialmente menos sustentável. Os membros da sua equipe devem pelo menos ser capazes de descobrir o que está acontecendo, mesmo que não possam escrevê-lo.

    
por 15.03.2013 / 09:18
fonte
3

Você deve ser consistente, mas não necessariamente com o código antigo. Ou seja, sua equipe deve concordar com a maneira correta de fazer algo e usar dessa maneira sempre que um novo código for escrito ou alterações substanciais forem feitas.

Dessa forma, você obtém a maior parte dos benefícios da consistência (em particular, não importa quem escreve o código), mas ainda pode melhorar se a equipe perceber um benefício claro ao fazer as coisas de outra maneira.

Em um mundo ideal, nós reescreveríamos todo o código antigo para se adequar ao novo caminho correto. Embora isso não seja economicamente viável, ele deve fazer sentido técnico (ou o novo caminho não é o melhor), e seu plano de longo prazo deve ser o de atualizá-lo. Se isso não valer a pena, não se incomode com o novo caminho. Em outras palavras, deve haver uma clara vantagem para a nova maneira de considerar declarar a correta.

    
por 15.03.2013 / 14:10
fonte
1

Acho importante seguir um código style em um projeto, por exemplo. convenções de nomenclatura, recuos etc.

Eu não concordo que você deva se limitar a usar novas construções de linguagem ou padrões de design simplesmente porque seus colegas não os entendem, ou eles não foram usados no projeto antes.

É claro que essas coisas devem ter boas razões para usá-las, por exemplo. desempenho ou brevidade, se apropriado.

    
por 15.03.2013 / 11:20
fonte
0

Eu seria extremamente cuidadoso seguindo cegamente os padrões atuais de design. Naturalmente, quando não há desvantagem apreciável, deve-se sempre tentar seguir padrões semelhantes em toda a base de código.

No entanto, é muito fácil entrar em circunstâncias em que a maioria dos desenvolvedores acha que é uma "melhor prática" seguir os padrões ruins existentes, levando a situações em que bons desenvolvedores estão escrevendo códigos ruins e inatingíveis.

Por outro lado, a consistência é importante. Ao lidar com enormes bases de código, é extremamente útil tentar seguir padrões similares, de forma que, mesmo que os desenvolvedores não tenham lido cada centímetro da base de código, eles sabem o que esperar.

Portanto, acredito que é melhor estabelecer e atualizar as diretrizes sobre quais padrões os desenvolvedores devem seguir se puderem. Desta forma, qualquer novo código é consistente com outro novo código.

    
por 15.03.2013 / 19:16
fonte
-1

Temos reuniões técnicas regulares e informais que qualquer um de nós pode realizar. Se encontrarmos uma nova técnica, apresentamos na reunião. Você geralmente tem uma boa noção de como a ideia é aceita e compreendida pelos seus colegas. Isso ajuda você a decidir se é sensato incluí-lo em seu código, ajuda os outros a decifrá-lo se você o fizer e também estabelece a pessoa 'vá para' se outros precisarem de ajuda com esse estilo. Se ninguém reinventasse a roda, nós ainda estaríamos arrastando coisas nos logs.

    
por 15.03.2013 / 17:26
fonte