Atribuição booleana de práticas recomendadas [fechada]

10

Me deparei com o seguinte condicional em um programa que substituí de outro desenvolvedor:

if (obj.Performance <= LOW_PERFORMANCE)
{
    obj.NeedsChange = true;
}
else
{
    obj.NeedsChange = false;
}

Eu acredito que esse código é redundante e feio, então mudei para o que eu pensava ser uma atribuição booleana simples com base em uma comparação:

obj.NeedsChange = obj.Performance <= LOW_PERFORMANCE;

Ao ver isso, alguém revisando meu código comentou que, embora minha alteração esteja funcionalmente correta, ela pode confundir alguém que está olhando para ela. Ele acredita que o uso de um operador ternário torna essa atribuição mais clara, enquanto eu não gosto da adição de código mais redundante:

obj.NeedsChange = (obj.Performance <= LOW_PERFORMANCE) ? true : false;

Seu raciocínio é que fazer algo da maneira mais concisa não vale a pena, se faz com que outro desenvolvedor pare e decifre exatamente o que você fez.

A verdadeira questão aqui é qual desses três métodos de atribuir um valor ao booleano obj.NeedsChangeé o mais claro e o mais sustentável?

Zach Posten
fonte
25
A terceira forma é ridícula; está apenas declarando o que já deveria ser óbvio na segunda forma.
Robert Harvey
6
Isso depende inteiramente da preferência pessoal. Podemos fingir o contrário, mas como todos são funcionalmente equivalentes, tudo se resume ao estilo . Claro, há uma diferença na legibilidade, mas meu "legível e transparente" pode ser a sua "obtuso e opaco"
MetaFight
3
@scriptin 5-8 linhas v 1 linha é mais do que preferência, o liner 5-8 geralmente é mais claro e melhor para ele. Neste exemplo simples, prefiro a linha 1, mas, em geral, já vi muitos 10 revestimentos que foram ofuscados em revestimentos 1 para maior conforto. Dado isso, eu nunca reclamaria da variante 1, pode não ser bonita, mas faz o trabalho de maneira tão clara e óbvia.
Gbjbaanb
4
As opções 1 e 3 dizem-me "O autor realmente não entende a lógica booleana".
17 de 26
2
A variante 1 pode ser útil se você precisar definir frequentemente um ponto de interrupção que depende do valor.
Ian

Respostas:

39

Prefiro 2, mas posso fazer um pequeno ajuste:

obj.NeedsChange = ( obj.Performance <= LOW_PERFORMANCE );

Para mim, os parênteses facilitam a análise da linha e deixam claro que você está atribuindo o resultado de uma comparação e não executando uma tarefa dupla. Não sei ao certo por que motivo (já que não posso pensar em um idioma em que os parênteses realmente impediriam uma tarefa dupla), mas se você deve satisfazer seu revisor, talvez seja um compromisso aceitável.

Jacob Raihle
fonte
4
esta é a resposta correta - embora o código da pergunta esteja correto, adicionar colchetes diz ao leitor que não é uma tarefa. Se você estava olhando rapidamente através do código, os colchetes fornecem essas informações extras instantâneas que o impedem de olhar mais de perto para ver se o código deveria ser assim e não era um bug acidental. Por exemplo, imagine que a linha fosse a = b == c, você quis dizer atribuir um bool ou designou c a ambos be b.
Gbjbaanb
Parênteses impediriam uma atribuição dupla em Python. Mesmo nos idiomas em que eles não impedem a atribuição dupla, os parênteses definitivamente ajudam a indicar que você está lidando com dois tipos de operações.
User2357112 suporta Monica
23

A variante 1 é facilmente compreendida, mas essa é sua única vantagem. Suponho automaticamente que quem escreve assim realmente não entende o que são os booleanos e estará escrevendo código infantil similar em muitos outros aspectos.

A variante 2 é o que eu sempre escreveria e esperaria ler. Eu acho que qualquer um que esteja confuso com esse idioma não deve ser um escritor profissional de software.

A variante 3 combina as desvantagens de 1 e 2. 'disse nuff.

Kilian Foth
fonte
Bem, a variante 1 ações a sua vantagem com a variante 2 ...
Deduplicator
1
+1 para código infantil. Estive analisando esse código há anos, só faltava a palavra certa para identificá-lo.
Lilienthal
1
Minha primeira suposição com código como a variante 1 é que as duas ramificações em um ponto no passado eram mais complicadas e alguém não estava prestando atenção ao refatorar. Se, porém, que é como era quando escrito em primeiro lugar, então eu concordo com "Não booleans compreensão"
Izkata
13

A qualquer momento, o código é mais complicado do que precisa ser acionado, "o que isso está fazendo?" cheiro no leitor.

Por exemplo, o primeiro exemplo me faz pensar: "havia outra funcionalidade na instrução if / else em algum momento que foi removida?"

O exemplo (2) é simples, claro e faz exatamente o que é necessário. Eu li e entendi imediatamente o que o código faz.

O fluff extra em (3) me faria pensar por que o autor a escreveu dessa maneira em vez de (2). Não deve haver uma razão, mas neste caso não parece ser, por isso não é útil e mais difícil de ler porque a sintaxe sugere algo presente que não está lá. Tentar aprender o que está presente (quando nada está) torna o código mais difícil de ler.

enderland
fonte
2

É fácil ver que as variantes 2 e 1 estão relacionadas por meio de uma série de refatorações óbvias e simples:

if (obj.Performance <= LOW_PERFORMANCE)
{
    obj.NeedsChange = true;
}
else
{
    obj.NeedsChange = false;
}

Aqui, temos duplicação de código desnecessária, podemos fatorar a atribuição:

obj.NeedsChange = if (obj.Performance <= LOW_PERFORMANCE)
{
    true
}
else
{
    false
}

ou escrito de forma mais concisa:

obj.NeedsChange = if (obj.Performance <= LOW_PERFORMANCE) true else false

Agora, deve ficar imediatamente óbvio que isso atribuirá true se a condição for verdadeira e false se a condição for falsa; IOW simplesmente atribuirá o valor da condição, ou seja, é equivalente a

obj.NeedsChange = obj.Performance <= LOW_PERFORMANCE

As variantes 1 e 3 são códigos novatos típicos escritos por alguém que não entende qual é o valor de retorno de uma comparação.

Jörg W Mittag
fonte
Eu adicionaria sua parte if (...) ... false como um comentário antes do bom, então você obtém a varredura simples através da clareza do código e do melhor código.
Davem
2

Embora sua programação deva ficar explícita em vez de implícita "como se o cara que acaba mantendo seu código fosse um psicopata violento que sabe onde você mora", você pode assumir algumas coisas básicas nas quais seu psicopata sucessor será competente.

Uma delas é a sintaxe do idioma que ele está usando.

obj.NeedsChange = obj.Performance <= LOW_PERFORMANCE;

é muito claro para quem conhece a sintaxe C / C ++ / C # / Java / Javascript.

Também é muito mais legível do que 8 linhas.

if (obj.Performance <= LOW_PERFORMANCE)
{
    obj.NeedsChange = true;
}
else
{
    obj.NeedsChange = false;
}

e menos propenso a erros

if (obj.Performance <= LOW_PERFORMANCE)
{
    obj.NeedsChange = true;
}
else
{
    obj.Needschange = false;
}

E é melhor do que adicionar caracteres desnecessários, como se você tivesse esquecido a sintaxe do idioma:

obj.NeedsChange = obj.Performance <= LOW_PERFORMANCE ? true : false;

obj.NeedsChange = (obj.Performance <= LOW_PERFORMANCE);

Acho que há muita coisa errada na sintaxe do tipo C de muitas linguagens: ordem inconsistente de operações, associatividade inconsistente esquerda / direita, uso sobrecarregado de símbolos, chaves / duplicação de indentação, operadores ternários, notação de infixo, etc.

Mas a solução não é inventar sua própria versão proprietária. Dessa maneira, está a loucura, pois todos criam seus próprios.


Geralmente o # 1 coisa que faz Mundo Real TM código ilegível é a quantidade do mesmo.

Entre um programa não-patológico de 200 linhas e um programa trivialmente idêntico de 1.600, o mais curto quase sempre será mais fácil de analisar e entender. Gostaria de receber sua mudança a qualquer dia.

Paul Draper
fonte
1

A maioria dos desenvolvedores será capaz de entender a segunda forma rapidamente. Na minha opinião, a simplificação como na 1ª forma é simplesmente desnecessária.

Você pode melhorar a legibilidade adicionando espaços e chaves, como:

obj.NeedsChange =    obj.Performance <= LOW_PERFORMANCE;

ou

obj.NeedsChange = ( obj.Performance <= LOW_PERFORMANCE );

como mencionado por Jacob Raihle.

Uday Shankar
fonte