Em alguns projetos de código aberto, reuni o seguinte estilo de codificação
void someFunction(bool forget);
void ourFunction() {
someFunction(false /* forget */);
}
Eu sempre tenho dúvidas sobre o que false
significa aqui. Isso significa "esquecer" ou "esquecer" se refere ao parâmetro correspondente (como no caso acima), e "false" significa negá-lo?
Qual estilo é usado com mais frequência e qual é a melhor maneira (ou algumas das melhores maneiras) de evitar a ambiguidade?
coding-style
comments
boolean
Johannes Schaub - litb
fonte
fonte
someFunction(forget: true);
true
parafalse
e não atualizarão o comentário. Se você não pode alterar a API, a melhor maneira de comentar isso ésomeFunction( false /* true=forget, false=remember */)
sortAscending
esortDescending
, ou similares). Agora, por dentro , os dois podem chamar o mesmo método privado, que pode ter esse tipo de parâmetro. Na verdade, se o idioma suportado, provavelmente o que eu passar em seria uma função lambda que continha a direcção da ordenação ...Respostas:
No código de exemplo que você postou, parece
forget
ser um argumento de flag. (Não posso ter certeza porque a função é puramente hipotética.)Os argumentos de sinalização são um cheiro de código. Eles indicam que uma função faz mais de uma coisa e uma boa função deve fazer apenas uma coisa.
Para evitar o argumento flag, divida a função em duas funções que explicam a diferença no nome da função.
Argumento de sinalização
Nenhum argumento de sinalização
edit: Idealmente, você não precisa manter uma função com o parâmetro flag. Existem casos ao longo das linhas do que Fowler chama de implementação emaranhada, em que a separação completa das funções cria código duplicado. No entanto, quanto maior a complexidade ciclomática da função parametrizada, mais forte é o argumento para se livrar dela.
Isso é apenas um palpite, mas um parâmetro chamado
forget
parece inveja do recurso. Por que um chamador diz a outro objeto para esquecer algo? Pode haver um problema maior de design.fonte
serveTraditionalIceCream
e seserveLowFatIceCream
parecem? Eu tenho um enum com 14 tipos de sorvete.Nas palavras dos leigos:
false
é um literal.false
someFunction
para não esquecersomeFunction
que o parâmetro esquecer éfalse
someFunction
para lembrarNa minha opinião, seria melhor se a função fosse assim:
o que você pode chamar
ou mantenha o nome antigo, mas altere sua função de wrapper para
EDITAR:
Como a @Vorac afirmou, sempre se esforce para usar palavras positivas. A dupla negação é confusa.
fonte
remember
, a menos que o nome da função tornasse o significadoremember
muito óbvio.rememberToCleanUp* or *persist
ou alguma coisa.O parâmetro pode ser bem nomeado; é difícil dizer sem saber o nome da função. Presumo que o comentário foi escrito pelo autor original da função, e foi um lembrete do que passar
false
emsomeFunction
meio, mas para qualquer um que vem junto depois, é um pouco obscuro à primeira vista.O uso de um nome de variável positivo (sugerido no Código Completo ) pode ser a alteração mais simples que facilitaria a leitura deste trecho, por exemplo,
então
ourFunction
se torna:No entanto, o uso de um enum torna a chamada de função ainda mais fácil de entender, à custa de algum código de suporte:
Se você não puder alterar a assinatura
someFunction
por qualquer motivo, o uso de uma variável temporária também facilita a leitura do código, como simplificar condicionais introduzindo uma variável por nenhum outro motivo, além de facilitar a análise do código por humanos .fonte
remember
como verdadeiro significa esquecer (no seu exemplo desomeFunction(true /* forget */);
)?enum
é de longe a melhor solução. Só porque um tipo pode ser representado como -bool
ou seja, são isomórficos - não significa que deva ser representado como tal. O mesmo argumento se aplica astring
e mesmoint
.Renomeie a variável para que um valor bool faça sentido.
Isso é um milhão de vezes melhor do que adicionar um comentário para explicar argumentos para uma função porque o nome é ambíguo.
fonte
Crie um booleano local com um nome mais descritivo e atribua o valor a ele. Dessa forma, o significado será mais claro.
Se você não pode renomear a variável, o comentário deve ser um pouco mais expressivo:
fonte
/* forget */
comentário deve abordar, que é que sem a declaração de função bem na sua frente, pode ser difícil lembrar o que está sendo definidofalse
. (É por isso que eu acho @ conselho de Esailija para adicionar uma enumeração é melhor, e por isso que eu amo línguas que permitem parâmetros nomeados.)Há um bom artigo que menciona essa situação exata, pois se refere às APIs de estilo Qt. Lá, ele se chama The Boolean Parameter Trap e vale a pena ler.
A essência disso é:
fonte
Este é um comentário bizarro.
Do ponto de vista do compilador,
someFunction(false /* forget */);
é realmentesomeFunction(false);
(o comentário é retirado). Portanto, tudo o que essa linha faz é chamarsomeFunction
com o primeiro (e único) argumento definido comofalse
./* forget */
é apenas o nome do parâmetro Provavelmente, não passa de um lembrete rápido (e sujo), que realmente não precisa estar lá. Basta usar um nome de parâmetro menos ambíguo e você não precisará do comentário.fonte
Um dos conselhos do código Clean é minimizar o número de comentários desnecessários 1 (porque eles tendem a apodrecer) e nomear funções e métodos corretamente.
Depois disso, eu apenas removeria o comentário. Afinal, IDEs modernos (como eclipse) abrem uma caixa com código quando você passa o mouse sobre a função. Ver o código deve limpar a ambiguidade.
1 Comentar algum código complexo está ok.
fonte
Para elaborar o óbvio, os comentários podem mentir. Portanto, é sempre melhor tornar seu código auto-documentado sem recorrer a comentários para explicar, porque alguma pessoa (talvez você) mudará
true
parafalse
e não atualizará o comentário.Se você não pode alterar a API, recorro a duas opções
fonte
Gosto da resposta sobre como tornar o comentário sempre verdadeiro , mas, apesar de bom, acho que ele perde o problema fundamental desse código - ele está sendo chamado com um literal.
Você deve evitar o uso de literais ao chamar métodos. Variáveis locais, parâmetros opcionais, parâmetros nomeados, enumerações - a melhor maneira de evitá-las dependerá do idioma e do que está disponível, mas tente evitá-las. Os literais têm valores, mas não têm significado.
fonte
Em C #, usei parâmetros nomeados para tornar isso mais claro
Ou
enum
:Ou sobrecargas:
Ou polimorfismo:
fonte
A nomeação deve sempre resolver a ambiguidade dos booleanos. Eu sempre nomeio booleano como 'isThis' ou 'shouldDoThat', por exemplo:
e assim por diante. Mas quando você está referenciando o código de outra pessoa, é melhor deixar um comentário ao passar valores.
fonte