Faz sentido algum refator terminar com um LOC mais alto? [fechadas]


25

Existem casos em que códigos mais detalhados (como em declarações mais lógicas) são mais limpos que códigos mais concisos?



18
Claro que sim. Mesmo ao eliminar a duplicação, o código para definir a nova função extraída ocupa espaço próprio. Escrever uma nova função pode levar quatro linhas e salvar apenas duas, e ainda assim vale a pena.
Kilian Foth

5
"código mais conciso"? Eu realmente odeio a crença equivocada de que uma contagem menor de linhas significa código "melhor". Não faz. De fato, geralmente é o oposto. Chega um ponto - e é alcançado muito rapidamente - onde colocar cada vez mais significado em cada vez menos espaço torna o código mais difícil de entender. De fato, há uma competição inteira - o Concurso Internacional de Código Ofuscado C - em que muitos vencedores confiam nesses limites da compreensão humana para escrever código impenetrável.
Andrew Henle 12/10

1
O título da sua pergunta e sua própria pergunta estão fazendo perguntas diferentes. Por exemplo, uma instrução if pode ser alterada para uma expressão ternária que é a mesma lógica, mas apenas 1 linha.
Captain Man

1
-1 *** código mais detalhado (como nas declarações mais lógicas) *** a verbosidade e o número de declarações lógicas são duas coisas não relacionadas. É uma má forma alterar as definições.
21818 Pieter B #:

Respostas:


70

Para responder a isso, vamos dar um exemplo do mundo real que aconteceu comigo. Em C # uma biblioteca que eu mantenho, eu tinha o seguinte código:

TResult IConsFuncMatcher<T, TResult>.Result() =>
    TryCons(_enumerator) is var simpleMatchData && !simpleMatchData.head.HasValue
        ? _emptyValue.supplied
            ? _emptyValue.value
            : throw new NoMatchException("No empty clause supplied");
        : _recursiveConsTests.Any() 
            ? CalculateRecursiveResult() 
            : CalculateSimpleResult(simpleMatchData);

Discutindo isso com colegas, o veredicto unânime foi que as expressões ternárias aninhadas, juntamente com o uso "inteligente" de is varresultaram em código conciso, mas difícil de ler.

Então eu refatorei para:

TResult IConsFuncMatcher<T, TResult>.Result()
{
    var simpleMatchData = TryCons(_enumerator);

    if (!simpleMatchData.head.HasValue)
    {
        return _emptyValue.supplied
            ? _emptyValue.value
            : throw new NoMatchException("No empty clause supplied");
    }

    return _recursiveConsTests.Any() 
        ? CalculateRecursiveResult() 
        : CalculateSimpleResult(simpleMatchData);
}

A versão original continha apenas uma expressão composta com um implícito return. A nova versão agora contém uma declaração explícita de variável, uma ifdeclaração e duas explícitas returns. Ele contém mais instruções e mais linhas de código. No entanto, todos que eu consultei consideraram mais fácil ler e raciocinar, que são aspectos-chave do "código limpo".

Portanto, a resposta para sua pergunta é um enfático "sim", mais detalhado pode ser mais limpo que o código conciso e, portanto, é uma refatoração válida.


34
Atualmente, o cérebro do desenvolvedor é um recurso mais escasso do que o disco, CPU, RAM ou largura de banda da rede. Essas outras coisas são importantes e, em certos aplicativos, podem ser seu fator limitador, mas na maioria dos casos, você deseja otimizar a capacidade de seus desenvolvedores de entender o código primeiro e depois essas outras coisas.
Anaximander 12/10

2
@anaximander, concordo absolutamente. Escreva o código para que outras pessoas leiam primeiro e depois o compilador. É por isso que acho útil que outras pessoas revisem meu código, mesmo que eu seja o único a desenvolvê-lo.
David Arno

4
Se eu estivesse analisando isso, sugeriria reverter a ordem das declarações de retorno e remover !a condição. Eu também sugeriria colocar o segundo retorno em um else. Mas mesmo assim, é uma grande melhoria.
Martin Bonner apoia Monica

2
@ Davididno Eu vejo essa lógica, e se if (!foo.HasValue)é um idioma no seu código, ainda mais fortemente. No entanto, ifnão é realmente uma saída cedo - é um "faça isso ou aquilo dependendo".
Martin Bonner apoia Monica

2
@fabric A comparação de valores booleanos é perigosa. Eu evito o máximo que posso.
Martin Bonner apoia Monica

30

1. Falta de correlação entre LOC e a qualidade do código.

O objetivo da refatoração é melhorar a qualidade de um pedaço de código.

LOC é uma métrica muito básica que, às vezes, se correlaciona com a qualidade de um pedaço de código: por exemplo, é provável que um método com alguns milhares de LOC tenha problemas de qualidade. Deve-se notar, no entanto, que LOC não é a única métrica e, em muitos casos, carece de correlação com a qualidade. Por exemplo, um método 4 LOC não é necessariamente mais legível ou mais sustentável que um método 6 LOC.

2. Algumas técnicas de refatoração consistem na adição de LOCs.

Se você fizer uma lista de técnicas de refatoração , poderá identificar facilmente as que consistem na adição intencional de LOCs. Exemplos:

Ambas são técnicas de refatoração muito úteis, e seu efeito no LOC é completamente irrelevante quando se pensa em usá-las ou não.

Evite usar LOC.

LOC é uma métrica perigosa. É muito fácil de medir e muito difícil de interpretar corretamente.

Até você se familiarizar com as técnicas de medição da qualidade do código, considere evitar medir o LOC em primeiro lugar. Na maioria das vezes, você não obtém nada de relevante e, em alguns casos, isso o leva a diminuir a qualidade do seu código.


Você reformulado sua resposta e melhorou a qualidade adicionando mais LOT (linhas de texto): p
grinch

12

Se você deseja ver o resultado final de apenas minimizar a contagem de bytes ou LoC do seu código-fonte, consulte os envios para o site Stack Exchange Code Golf .

Se seu código-fonte for reduzido dessa maneira, em breve você terá uma bagunça insustentável. Mesmo que você seja a pessoa que escreveu esse código e o entenda completamente na época, qual será sua eficiência quando voltar a usá-lo daqui a seis meses? Também não há evidências de que esse código mínimo seja executado mais rapidamente.

O código deve ser escrito de tal maneira que qualquer membro da sua equipe possa analisá-lo e entender o que está fazendo imediatamente.


Talvez redundante, mas apenas para explicar; se você refatorar golfed código para facilitar a leitura você sempre acabar com mais LoC
jollyjoker

1

Sim, a refatoração pode definitivamente resultar em mais linhas de código.

O caso mais comum da IMO é quando você pega um código que não é genérico e o torna mais genérico / flexível . Gerar código facilmente faz com que as linhas de código aumentem significativamente (às vezes por um fator de dois ou mais).

Se você espera que o código recém-genérico seja usado por outras pessoas (em vez de apenas como um componente interno de software) como uma biblioteca, normalmente você acaba adicionando códigos mais unidos e marcação de documentação no código que aumentará as linhas de código novamente.

Por exemplo, aqui está um cenário muito comum que acontece para todo desenvolvedor de software:

  • seu produto precisa de um novo recurso urgente de alta prioridade ou correção de bugs ou aprimoramento em duas semanas (ou qualquer período de tempo considerado urgente para o tamanho do seu projeto / empresa / etc)
  • você trabalha duro e entrega o XYZ no prazo e ele funciona. Parabéns! Bom trabalho!
  • Enquanto você desenvolvia o XYZ, o design / implementação de código existente não era realmente compatível com o XYZ, mas você conseguiu colocar o XYZ na base de código
  • o problema é que o calço é feio e tem um cheiro horrível de código porque você fez algumas coisas complicadas / inteligentes / feias / de más práticas, mas meio que funcionam
  • quando você encontrar tempo mais tarde, refatorar o código, o que pode alterar muitas classes ou adicionar uma nova camada de classes, e sua nova solução será "executada corretamente" e não terá mais o mau cheiro do código ... "caminho certo" agora ocupa muito mais linhas de código.

Alguns exemplos concretos que me vêm à cabeça:

  • para uma interface de linha de comandos você pode ter 5000 linhas de código if / else-if ou usar retornos de chamada ... cada retorno de chamada seria muito menor e mais fácil de ler / testar / verificar / depurar / etc, mas se você contar linhas de codifique as feias 5000 linhas do código if / else-if provavelmente seriam menores
  • para um trecho de código de processamento que suporta N métodos de processamento , você pode novamente usar instruções if / else com a aparência mais feia ...
    • ou você pode mudar para retornos de chamada que seriam mais agradáveis ​​/ melhores, mas retornam mais linhas de código (embora ainda compile o tempo)
    • ou você pode abstrair ainda mais e criar plugins que podem ser alterados em tempo de execução. plug-ins são bons porque você não precisa recompilar o produto principal para cada novo plug-in ou modificação em um plug-in existente. e você pode publicar a API para que outras pessoas possam estender o produto. Mas, novamente, uma abordagem de plug-in usa mais linhas de código.
  • para uma GUI, você cria um ótimo novo widget
    • você ou um colega de trabalho observa que o novo widget seria ótimo para XYZ e ABC, mas agora o widget está totalmente integrado apenas para trabalhar com XYZ
    • você refatora o widget para trabalhar para ambos, mas agora o total de linhas de código aumenta
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.