O meu código deve ser DRY ou legível se não puder ser ambos?

14

Estou escrevendo código Ruby para um simples exercício de criptografia e frequentemente corro este dilema (o exercício é uma cifra de solitário se você precisar saber). É uma questão de saber se devo seguir minha lógica com variáveis descritivas e instruções de etapa única que tornam a função legível em vez de uma declaração concisa, até mesmo densa, que elimine a repetição e / ou minimize as oportunidades de erros.

Meu exemplo mais recente: Meu programa recebe comentários e, por causa das diretrizes de formato rígido, pode determinar facilmente se a entrada deve ser criptografada ou descriptografada. Para simplificar, uma vez que a chave de criptografia e a mensagem sejam convertidas / geradas para serem compatíveis, é uma questão de subtrair a chave da mensagem criptografada ou adicionar a chave a uma mensagem não criptografada, para obter a saída desejada (pense na chave como criptografia, mensagem + criptografia = código; código - criptografia = mensagem). A posição DRY me diz que devo converter minha mensagem criptografada de forma diferente da minha mensagem não criptografada, de modo que a função que usa a chave de criptografia e a aplica à mensagem nunca precise ser distinguida. Descobri que isso significa que preciso de algumas instruções if aninhadas na função, mas a lógica parece ser sólida. Este código, no entanto, não é facilmente legível. Isso exigiria alguns comentários para ficar claro.

Eu poderia, por outro lado, escrever duas funções diferentes que são chamadas com base em um sinalizador definido quando o aplicativo determina a criptografia ou descriptografia. Isso seria mais simples de ler, mas duplicaria a função de alto nível de aplicar a chave de criptografia a uma mensagem (fazendo com que ela fosse criptografada ou descriptografada).

Devo me concentrar em código legível ou código conciso? Ou perdi outra maneira de obter essa funcionalidade e satisfazer os dois princípios? É uma posição ao longo de uma escala na qual é preciso considerar o propósito do projeto e tomar as melhores decisões para servir a esse propósito?

Até agora, costumo enfatizar código DRY conciso sobre código legível.

    
por lutze 10.04.2013 / 03:47
fonte

7 respostas

19

DRY é uma diretriz, não uma religião. Aqueles que levam isso ao ponto de DRY acima de tudo, levaram isso longe demais.

Em primeiro lugar, o código utilizável é primordial. Se o código não é útil e utilizável, não é ... e não há nenhum ponto em escrevê-lo em primeiro lugar.

Em segundo lugar, algum dia alguém terá que manter seu código. Se o seu código não for passível de manutenção, eles irão quebrar seu design "bonito" denso, conciso e seco ao mesmo tempo em que amaldiçoará seu nome. Não faça isso. Eu fui essa pessoa e toda vez que eu vejo um certo nome na anotação de código, eu estremeço.

Fazer código denso que não tem "variáveis descritivas" e colar tudo em expressões ternárias aninhadas com lambdas sem qualquer documentação é inteligente. É bom saber que você pode fazer isso - mas não sabe. Um código inteligente é muito difícil de depurar. Evite escrever códigos inteligentes .

A maior parte do tempo gasto em software é gasto na manutenção do software - não é escrito na primeira vez. Escreva o código para que você (ou outra pessoa) possa corrigir rápida e facilmente os bugs e adicionar recursos conforme necessário, com o mínimo de alterações de quebra de design ideais.

    
por 10.04.2013 / 04:25
fonte
17

Não tenho certeza com base na pergunta que você entende DRY. O código DRY não é o mesmo que conciso. Muitas vezes é o contrário.

Aqui, não sei qual é o grande problema para este exemplo. Faça uma função para criptografar, uma função para descriptografar, ajudantes para funcionalidade comum (mix bytes), e um front-end simples para receber informações e determinar criptografar / descriptografar ... Não se repetindo.

Em geral, tanto a DRY quanto a legibilidade existem para ajudar a manter e estender o código. Nem todos os cenários são iguais, um grande hit de legibilidade para remover um pouco de repetição não é bom, e nem é um monte de duplicação para adicionar um pouco de legibilidade.

Se pressionado, prefiro legibilidade. O código duplicado ainda pode ser testado - código ilegível leva você a fazer (e testar) a coisa errada.

    
por 10.04.2013 / 04:24
fonte
12

Não estou familiarizado com seu caso específico, mas posso fornecer algumas diretrizes gerais.

O propósito da legibilidade e do DRY é manutenibilidade .

A manutenção é importante na maioria das situações em que você passará mais tempo mantendo código do que escrevendo. Isso é especialmente verdadeiro se você considerar que escrever código é um tipo especial de manutenção.

Infelizmente, DRY é muitas vezes mal compreendido. Isto é em parte porque parece tão simples, mas como muitas coisas simples, pode ser, bem ... complicado.

A intenção do DRY é que cada unidade de funcionalidade existe em um único lugar. Se o princípio for seguido, o mantenedor de código encarregado de alterar ou verificar se a funcionalidade pode lidar com o código uma vez. Se DRY não for seguido, existe um perigo muito real de que alguma cópia da funcionalidade não seja mantida adequadamente.

A violação mais flagrante de DRY é a codificação de copiar e colar, onde blocos inteiros de código são repetidos verbatum na base de código. Isso é surpreendentemente comum na minha experiência, e isso não aumenta a legibilidade. Portanto, refatorar o código para introduzir um método comum aumenta invariavelmente a conformidade e a legibilidade do DRY.

A segunda violação mais flagrante é "copiar e colar e alterá-lo um pouco". Novamente, refatorar a introdução de um método comum com parâmetros, ou dividir uma função em etapas e abstrair as semelhanças quase sempre aumenta a legibilidade.

Depois, há as violações mais sutis, nas quais a funcionalidade é duplicada, mas o código é diferente. Isso sempre não é fácil de detectar, mas quando você o vê e refatora para puxar o código comum em um único método / classe / função, o código é usualmente mais legível do que era antes.

Finalmente, há os casos de repetição do design. Por exemplo, você pode ter usado o padrão de estado várias vezes em sua base de código e está considerando a refatoração para eliminar essa repetição. Nesse caso, prossiga com cautela. Você pode estar reduzindo a legibilidade, introduzindo mais níveis de abstração. Ao mesmo tempo, você não está realmente lidando com duplicação de funcionalidade, mas com duplicação de abstração. Às vezes vale a pena ... mas muitas vezes não é. Seu princípio orientador será perguntar "qual destes é mais sustentável".

Sempre que faço essas avaliações, tento considerar a quantidade de tempo que as pessoas gastarão para manter o código. Se o código é a principal funcionalidade do negócio, ele provavelmente precisará de mais manutenção. Nesses casos, pretendo tornar o código sustentável para pessoas familiarizadas com a base de código e as abstrações envolvidas. Eu ficaria mais feliz em introduzir um pouco mais de abstração para reduzir a repetição. Em contraste, um script que raramente é usado e mantido com pouca freqüência pode ser menos fácil de entender para os mantenedores se envolver muita abstração. Nesse caso, eu iria errar do lado da repetição.

Eu também considero o nível de experiência de outros membros da minha equipe. Evito abstrações "extravagantes" com desenvolvedores inexperientes, mas aproveito padrões de design reconhecidos pela indústria com grupos mais maduros.

Na concusão, a resposta à sua pergunta é fazer o que for mais fácil de manter. O que isso significa no seu cenário depende de você decidir.

    
por 10.04.2013 / 08:52
fonte
7

Se suas funções se tornarem mais complicadas e mais longas (assim menos legíveis) quando você tentar torná-las DRY, então você está fazendo errado. Você está tentando colocar muita funcionalidade em uma função porque acha que essa é a única maneira de evitar repetir os mesmos trechos de código em uma segunda função.

Fazer código DRY quase sempre significa refatorar a funcionalidade comum para funções menores. Cada uma dessas funções deve ser mais simples (e, portanto, mais legível) do que a original. Para manter tudo na função original no mesmo nível de abstração, isso também pode significar refatorar partes adicionais que não são usadas em outro lugar. Sua função original então se torna uma "função de alto nível", chamando as menores, e fica menor e mais simples também.

Isso, consequentemente, leva principalmente a diferentes níveis de abstrações em seu código - e algumas pessoas acreditam que esse tipo de código é menos legível. Para minha experiência, isso é uma falácia. O ponto-chave aqui é dar bons nomes às funções menores, introduzir tipos de dados bem-nomeados e abstrações que podem ser facilmente compreendidas por uma segunda pessoa. Dessa forma, "SECA" e "legibilidade" só muito raramente entrariam em conflito.

    
por 10.04.2013 / 08:53
fonte
2

Embora não esteja certo de exatamente o que está causando o problema, minha experiência é que quando você encontra DRY e legibilidade conflitante, diz que é hora de refazer algo.

    
por 10.04.2013 / 05:33
fonte
0

Eu escolheria legível (= sustentável) em vez de DRY em qualquer dia da semana. Na realidade, ambos geralmente se alinham, alguém que obtém o conceito de DRY geralmente produzia (principalmente) código legível.

    
por 10.04.2013 / 04:23
fonte
0
Muito muito, muito, muito, muito poucas vezes em minha carreira eu encontrei um caso legítimo que pitts de legibilidade contra DRY. Torne legível primeiro. Nomeie as coisas bem. Copie e cole, se necessário.

Agora recue e olhe para a totalidade que você criou, como um artista dando um passo atrás para ver a pintura deles. Agora você pode identificar corretamente a repetição.

O código repetido deve ser refatorado em seu próprio método ou retirado para sua própria classe.

O código de repetição deve ser o último recurso. Legível e seco primeiro, falhando que legível se você limitar o escopo de código repetido.

    
por 10.03.2017 / 00:10
fonte