Estou escrevendo o código Ruby para um exercício de criptografia simples e frequentemente encontro esse dilema (o exercício é uma cifra de paciência, se você precisar saber). É uma questão de saber se eu devo preencher minha lógica com variáveis descritivas e instruções de etapa única que tornam a função legível em vez de instruções concisas e até densas que eliminam a repetição e / ou minimizam as oportunidades de erros.
Meu exemplo mais recente: Meu programa recebe entrada e, devido às rígidas diretrizes de formato, pode determinar facilmente se a entrada deve ser criptografada ou descriptografada. Para simplificar, uma vez que a chave e a mensagem de criptografia são 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 diz para mim que devo converter minha mensagem criptografada de forma diferente da mensagem não criptografada para que a função que recebe a chave de criptografia e a aplica à mensagem nunca precise distinguir. Descobri que isso significa que preciso de algumas instruções if aninhadas na função, mas a lógica parece sólida. Este código, no entanto, não é facilmente legível.
Por outro lado, eu poderia escrever duas funções diferentes 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 inclinar para código legível ou código conciso? Ou eu perdi outra maneira de obter essa funcionalidade e satisfazer os dois princípios? É uma posição em uma escala em que é preciso considerar o objetivo do projeto e tomar as melhores decisões para servir a esse objetivo?
Até agora, costumo enfatizar o código DRY conciso sobre o código legível.
fonte
Respostas:
DRY é uma diretriz, não uma religião. Aqueles que o levam ao ponto de DRY acima de tudo, o levaram longe demais.
Em primeiro lugar, o código utilizável é fundamental. Se o código não é útil e utilizável, não é ... e não faz sentido escrevê-lo em primeiro lugar.
Segundo, algum dia alguém precisará manter seu código. Se o seu código não puder ser mantido, eles quebrarão seu design "bonito" denso, conciso e SECO enquanto amaldiçoam seu nome. Não faça isso. Eu sou essa pessoa e toda vez que vejo um determinado nome na anotação do código, estremeço.
Criar um código denso que não possua "variáveis descritivas" e colocar tudo em expressões ternárias aninhadas com lambdas sem nenhuma documentação é inteligente. É bom saber que você pode fazê-lo - mas não o faz. Código inteligente é muito difícil de depurar. Evite escrever código inteligente .
A maior parte do tempo gasto em software é gasta em manutenção do software - não sendo gravada na primeira vez. Escreva o código para que você (ou qualquer outra pessoa) possa rápida e facilmente corrigir bugs e adicionar recursos conforme necessário, com o mínimo de alterações ideais no design.
fonte
Não tenho certeza com base na pergunta que você entende DRY. Código DRY não é o mesmo que conciso. Muitas vezes é o contrário.
Aqui, não tenho certeza de qual é o grande problema desse exemplo. Crie uma função para criptografar, uma função para descriptografar, ajudantes para funcionalidades comuns (misturar bytes) e um front end simples para receber entradas e determinar a criptografia / descriptografia ... Não se repita.
Em geral, porém, existem DRY e legibilidade para ajudar a manter e estender o código. Nem todos os cenários são iguais, uma grande legibilidade para remover um pouco de repetição não é boa, e nem um monte de duplicação para adicionar um pouco de legibilidade.
Se pressionado, eu preferiria a legibilidade. O código duplicado ainda pode ser testado - o código ilegível leva você a fazer (e testar) a coisa errada.
fonte
Não estou familiarizado com o seu caso específico, mas posso fornecer algumas diretrizes gerais.
O objetivo da legibilidade e do DRY é a manutenção .
A manutenção é importante na maioria das situações, você gastará mais tempo mantendo o 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 incompreendido. Isso ocorre em parte porque parece muito simples, mas, como muitas coisas simples, pode ser, bem ... complicado.
A intenção do DRY é que cada unidade de funcionalidade exista em apenas um local. Se o princípio for seguido, o mantenedor do código encarregado de alterar ou verificar essa funcionalidade pode lidar com o código de uma só vez. Se o DRY não for seguido, há um risco muito real de que algumas cópias da funcionalidade não sejam mantidas adequadamente.
A violação mais flagrante do DRY é a codificação de copiar e colar, na qual blocos inteiros de código são repetidos verbatum na base de código. Isso é surpreendentemente comum na minha experiência, e de nenhuma maneira isso contribui para a legibilidade. Portanto, refatorar o código para introduzir um método comum invariavelmente aumenta a conformidade e a legibilidade do DRY.
A segunda violação mais flagrante é "copiar e colar e alterá-lo um pouco". Novamente, refatorar para introduzir um método comum com parâmetros ou dividir uma função em etapas e abstrair os pontos comuns quase sempre aumentam a legibilidade.
Existem as violações mais sutis, nas quais a funcionalidade é duplicada, mas o código é diferente. Isso nem sempre é fácil de detectar, mas quando você o vê e refatora para extrair o código comum em um único método / classe / função, o código fica usualmente mais legível do que era antes.
Finalmente, há os casos de repetição de design. Por exemplo, você pode ter usado o padrão de estado várias vezes em sua base de código e está pensando em refatorar para eliminar essa repetição. Nesse caso, continue com cuidado. Você pode estar reduzindo a legibilidade introduzindo mais níveis de abstração. Ao mesmo tempo, você não está realmente lidando com a duplicação da funcionalidade, mas com a duplicação da 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 chamadas de julgamento, tento considerar a quantidade de tempo que as pessoas gastam mantendo o código. Se o código é a funcionalidade principal do negócio, 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 apresentar um pouco mais de abstração para reduzir a repetição. Por outro lado, um script raramente usado e mantido com pouca frequê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.
Também considero o nível de experiência de outros membros da minha equipe. Evito abstrações "sofisticadas" com desenvolvedores inexperientes, mas aproveito os padrões de design reconhecidos pela indústria com grupos mais maduros.
Em conjunto, a resposta para sua pergunta é fazer o que torna seu código mais sustentável. O que isso significa no seu cenário depende de você decidir.
fonte
Se suas funções se tornarem mais complicadas e mais longas (portanto, menos legíveis) quando você tentar torná-las SECAS, estará 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.
Tornar o 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 peças adicionais que não são usadas em outros lugares. 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.
Fazer isso consequentemente leva principalmente a diferentes níveis de abstração no 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 principal aqui é dar bons nomes às funções menores, introduzir tipos de dados e abstrações bem nomeados, que podem ser facilmente compreendidos por uma segunda pessoa. Dessa forma, "SECO" e "legibilidade" só devem muito, muito raramente, entrar em conflito.
fonte
Embora não saiba exatamente o que está causando o problema aqui, minha experiência é que, quando você acha DRY e a legibilidade conflitantes, é hora de refatorar algo.
fonte
Eu escolheria legível (= mantenível) em vez de SECO em qualquer dia da semana. Na realidade, os dois geralmente se alinham, alguém que entende o conceito de DRY geralmente produzia (principalmente) código legível.
fonte
Muito, muito, muito, muito poucas vezes na minha carreira, encontrei um caso legítimo que lesse a legibilidade contra a DRY. Torne-o legível primeiro. Nomeie bem as coisas. Copie e cole, se necessário.
Agora, dê um passo atrás e observe 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 extraído em sua própria classe.
A repetição de código deve ser o último recurso. Legível E SECO primeiro, na falta disso, se você limitar o escopo do código repetido.
fonte