Devemos eliminar variáveis ​​locais, se pudermos?

95

Por exemplo, para manter uma CPU ativada no Android, posso usar um código como este:

PowerManager powerManager = (PowerManager)getSystemService(POWER_SERVICE);
WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "abc");
wakeLock.acquire();

mas acho que as variáveis ​​locais powerManagere wakeLockpodem ser eliminadas:

((PowerManager)getSystemService(POWER_SERVICE))
    .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakelockTag")
    .acquire();

cena semelhante aparece na visualização de alerta do iOS, por exemplo:

UIAlertView *alert = [[UIAlertView alloc]
    initWithTitle:@"my title"
    message:@"my message"
    delegate:nil
    cancelButtonTitle:@"ok"
    otherButtonTitles:nil];
[alert show];

-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
    [alertView release];
}

para:

[[[UIAlertView alloc]
    initWithTitle:@"my title"
    message:@"my message"
    delegate:nil
    cancelButtonTitle:@"ok"
    otherButtonTitles:nil] show];

-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
    [alertView release];
}

É uma boa prática eliminar uma variável local se ela for usada apenas uma vez no escopo?

ggrr
fonte
95
Não necessariamente. Às vezes, torna o código mais claro para o uso de variáveis ​​únicas e, na maioria das linguagens de programação decentes, há muito pouco (se houver) custo em tempo de execução para essas variáveis ​​adicionais.
Robert Harvey
75
Também torna mais difícil percorrer o código com um depurador. E você também deve ter certeza (dependendo do idioma) que a primeira expressão não é um NULL ou um erro.
GrandmasterB
78
Não é não. De fato, é uma boa prática introduzir variáveis ​​locais para quebrar cadeias de chamadas de método. É provável que o código de máquina gerado seja idêntico e é quase garantido que o código fonte seja mais legível e, portanto, melhor.
precisa saber é o seguinte
48
Tente isso. Agora conecte o depurador e tente ver o estado do PowerManager ou WakeLock. Perceba seu erro. Eu pensava o mesmo ("o que há com todos esses locais?") Até ter que gastar a maior parte do tempo investigando o código.
Faerindel
42
Mesmo no seu exemplo, sua versão "eliminada" possui uma barra de rolagem e não se encaixa totalmente na minha tela, o que dificulta a leitura.
Erik

Respostas:

235

O código é lido com muito mais frequência do que está escrito; portanto, você deve ter pena da pobre alma que terá que ler o código daqui a seis meses (pode ser você) e se esforçar para obter o código mais claro e fácil de entender. Na minha opinião, a primeira forma, com variáveis ​​locais, é muito mais compreensível. Eu vejo três ações em três linhas, em vez de três ações em uma linha.

E se você pensa que está otimizando alguma coisa se livrando de variáveis ​​locais, não está. Um compilador moderno colocará powerManagerum registro 1 , independentemente de uma variável local ser usada ou não, para chamar o newWakeLockmétodo. O mesmo vale para wakeLock. Então você acaba com o mesmo código compilado em ambos os casos.

1 Se você tivesse muito código intermediário entre a declaração e o uso da variável local, ele pode ficar na pilha, mas é um detalhe menor.

Tony BenBrahim
fonte
2
Você não pode saber se há muito código, o otimizador pode incorporar algumas funções ... Caso contrário, concordou, buscar a legibilidade primeiro é o movimento certo.
Matthieu M.
2
Bem, acho que o oposto, se eu vejo variáveis ​​locais sendo inicializadas múltiplas vezes em cada função em que é usada, em vez de ser um atributo quando possível, procurarei por que, basicamente, lerei completamente as linhas e as compararei apenas para verifique se são iguais. Então eu vou perder tempo.
Walfrat
15
@Walfrat Variáveis ​​locais sendo inicializadas várias vezes? Ai. Ninguém sugeriu reutilizar os habitantes locais :)
Luaan
32
Os membros do @Walfrat geram efeitos colaterais e só devem ser usados ​​quando você deseja especificamente manter o estado entre as chamadas para membros públicos. Essa pergunta parece tratar do uso local para armazenamento temporário de cálculos intermediários.
Gusdor #
4
P: Devemos eliminar variáveis ​​locais, se pudermos? A: Não.
simon
94

Alguns comentários altamente votados afirmaram isso, mas nenhuma das respostas que vi fizeram, por isso vou adicioná-lo como resposta. Seu principal fator na decisão desse problema é:

Debuggability

Freqüentemente, os desenvolvedores gastam muito mais tempo e esforço na depuração do que escrevendo código.

Com variáveis ​​locais, você pode:

  • Ponto de interrupção na linha em que foi atribuído (com todas as outras decorações de ponto de interrupção, como ponto de interrupção condicional, etc ...)

  • Inspecione / observe / imprima / altere o valor da variável local

  • Problemas de captura que surgem devido a elencos.

  • Ter rastreamentos de pilha legíveis (a linha XYZ tem uma operação em vez de 10)

Sem variáveis ​​locais, todas as tarefas acima são muito mais difíceis, extremamente difíceis ou absolutamente impossíveis, dependendo do seu depurador.

Como tal, siga a máxima infame (escreva o código da maneira que você faria como se o próximo desenvolvedor a manter depois de si mesmo seja um lunático louco que sabe onde você mora) e erre no lado de uma depuração mais fácil , ou seja, use variáveis ​​locais .

DVK
fonte
20
Eu acrescentaria que os rastreamentos de pilha são muito menos úteis quando há muitas chamadas em uma única linha. Se você tiver uma exceção de ponteiro nulo na linha 50 e houver 10 chamadas nessa linha, não restringirá muito o visual. Em um aplicativo de produção, essa geralmente é a maior parte das informações obtidas de um relatório de defeitos.
precisa saber é o seguinte
3
Percorrer o código também é muito mais difícil. Se houver chamada () -> chamada () -> chamada () -> chamada (), é um trabalho difícil entrar na terceira chamada de método. Muito mais fácil se houver quatro variáveis ​​locais
gnasher729
3
@FrankPuffer - temos que lidar com o mundo real. Onde depuradores não fazem o que você propõe.
DVK
2
@DVK: Na verdade, existem mais depuradores do que pensei que permitem inspecionar ou observar qualquer expressão. O MS Visual Studio (desde a versão 2013) possui esse recurso para C ++ e C #. O Eclipse possui para Java. Em outro comentário, Faerindel mencionou o IE11 para JS.
precisa saber é o seguinte
4
@DVK: Sim, muitos depuradores do mundo real não fazem o que eu proponho. Mas isso não tem nada a ver com a primeira parte do meu comentário. Eu acho louco presumir que a pessoa que vai manter meu código irá interagir principalmente com ele por meio de um depurador. Depuradores são ótimos para certos propósitos, mas se eles obtiverem a ferramenta principal para analisar código, eu diria que algo está seriamente errado e tentarei corrigi-lo em vez de tornar o código mais debugável.
Frank Puffer
47

Somente se tornar o código mais fácil de entender. Nos seus exemplos, acho que fica mais difícil de ler.

Eliminar as variáveis ​​no código compilado é uma operação trivial para qualquer compilador respeitável. Você pode inspecionar a saída para verificar.

whatsisname
fonte
1
Isso tem tanto a ver com o estilo quanto com o uso de variáveis. A questão foi editada agora.
Jodrell
29

Sua pergunta "é uma boa prática eliminar uma variável local se for usada apenas uma vez no escopo?" está testando os critérios errados. O utilitário de uma variável local não depende do número de vezes que é usado, mas se torna o código mais claro. Rotular valores intermediários com nomes significativos pode melhorar a clareza em situações como a que você apresenta, pois divide o código em blocos menores e mais digeríveis.

Na minha opinião, o código não modificado que você apresentou é mais claro que o código modificado e, portanto, deve permanecer inalterado. De fato, eu consideraria extrair uma variável local do seu código modificado para melhorar a clareza.

Eu não esperaria nenhum impacto no desempenho das variáveis ​​locais e, mesmo que exista, é provável que seja pequeno demais para ser considerado, a menos que o código esteja em um loop muito restrito em uma parte crítica da velocidade do programa.

Jack Aidley
fonte
Eu acho que isso tem muito a ver com o estilo e o uso de espaço em branco como qualquer coisa. A pergunta foi editada.
precisa saber é o seguinte
15

Talvez.

Pessoalmente, hesitaria em eliminar as variáveis ​​locais se um typecast estiver envolvido. Acho sua versão compacta menos legível quando o número de colchetes começa a se aproximar de um limite mental que eu tenho. Ele até introduz um novo conjunto de colchetes que não era necessário na versão um pouco mais detalhada usando uma variável local.

O destaque da sintaxe fornecido pelo editor de código pode atenuar essas preocupações em certa medida.

Para meus olhos, este é o melhor compromisso:

PowerManager powerManager = (PowerManager)getSystemService(POWER_SERVICE);
powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "abc").acquire();

Mantendo assim uma variável local e abandonando a outra. Em C #, eu usaria a palavra-chave var na primeira linha, pois o typecast já fornece as informações de tipo.

9Rune5
fonte
13

Embora eu aceite a validade das respostas que favorecem as variáveis ​​locais, vou interpretar o advogado do diabo e apresentar uma visão contrária.

Pessoalmente, sou contra o uso de variáveis ​​locais exclusivamente para fins de documentação, embora esse próprio motivo indique que a prática tem valor: as variáveis ​​locais efetivamente pseudo-documentam o código.

No seu caso, o principal problema é o recuo e não a ausência de variáveis. Você pode (e deve) formatar o código da seguinte maneira:

((PowerManager)getSystemService(POWER_SERVICE))
        .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,"MyWakelockTag")
        .acquire();

Compare isso com a versão com variáveis ​​locais:

PowerManager powerManager=(PowerManager)getSystemService(POWER_SERVICE);
WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,"abc");
wakeLock.acquire();

Com as variáveis ​​locais: os nomes adicionam algumas informações ao leitor e os tipos são claramente especificados, mas as chamadas de método reais são menos visíveis e (na minha opinião) não são lidas com clareza.

Sem usar variáveis ​​locais: é mais conciso e as chamadas de método são mais visíveis, mas você pode solicitar mais informações sobre o que está sendo retornado. Alguns IDEs podem mostrar isso no entanto.

Mais três comentários:

  1. Na minha opinião, adicionar código que não tem uso funcional às vezes pode ser confuso, pois o leitor deve perceber que ele realmente não tem uso funcional e simplesmente existe para "documentação". Por exemplo, se esse método tivesse 100 linhas, não seria óbvio que as variáveis ​​locais (e, portanto, o resultado da chamada do método) não fossem necessárias em algum momento posterior, a menos que você leia o método inteiro.

  2. A adição de variáveis ​​locais significa que você deve especificar seus tipos, e isso introduz uma dependência no código que, de outra forma, não estaria lá. Se o tipo de retorno dos métodos mudasse trivialmente (por exemplo, ele foi renomeado), você teria que atualizar seu código, enquanto que, sem as variáveis ​​locais, não seria.

  3. A depuração poderia ser mais fácil com variáveis ​​locais se o depurador não mostrar valores retornados dos métodos. Mas a correção para isso é corrigir as deficiências nos depuradores, não alterar o código.

rghome
fonte
Em relação aos seus comentários adicionais: 1. Isso não deve ser um problema se você estiver seguindo a convenção de que variáveis ​​locais são declaradas o mais próximo possível de onde elas são usadas e você está mantendo seus métodos um comprimento razoável. 2. Não está em uma linguagem de programação com inferência de tipo. 3. Código bem escrito geralmente não precisa de um depurador.
Robert Harvey
2
Seu primeiro exemplo de código funciona apenas se você estiver criando objetos usando interfaces fluentes ou padrões de "construtor", que eu não usaria em todo lugar no meu código, mas apenas seletivamente.
Robert Harvey
1
Eu acho que a pergunta assume que as variáveis ​​locais são funcionalmente redundantes e, portanto, esse tipo de interface é necessário para o caso. Provavelmente, poderíamos conseguir remover os habitantes locais caso contrário, por várias contorções, mas eu tinha em mente que estávamos analisando o caso simples.
Rgome
1
Acho a sua variante ainda pior para facilitar a leitura. Eu posso ter sido exposto demais ao VB.net, mas o meu primeiro pensamento, ao ver seu exemplo, foi "Para onde foi a instrução WITH? Eu a apaguei acidentalmente?" Preciso olhar duas vezes o que está acontecendo e isso não é bom quando preciso revisitar o código muitos meses depois.
Tonny
1
@ Tonny para mim, é mais legível: os locais não acrescentam nada que não seja óbvio do contexto. Eu tenho minha cabeça de Java, então não há withdeclarações. Seriam convenções de formatação normais em Java.
Rgome
6

Há uma tensão de motivações aqui. A introdução de variáveis ​​temporárias pode facilitar a leitura do código. Mas eles também podem impedir e dificultar a visualização de outras refatorações possíveis, como o Método de Extração e Substituir Temp por Consulta . Esses últimos tipos de refatoração, quando apropriado, geralmente oferecem benefícios muito maiores do que a variável temp.

Sobre as motivações para essas refatorações, Fowler escreve :

"O problema com os temporários é que eles são temporários e locais. Como eles podem ser vistos apenas no contexto do método em que são usados, os temporários tendem a incentivar métodos mais longos, porque é a única maneira de atingir a temperatura. substituindo o temp por um método de consulta, qualquer método da classe pode obter as informações. Isso ajuda muito a criar um código mais limpo para a classe ".

Portanto, sim, use temporários se eles tornarem o código mais legível, principalmente se for uma norma local para você e sua equipe. Mas esteja ciente de que fazer isso às vezes pode dificultar a identificação de melhorias alternativas maiores. Se você pode desenvolver sua capacidade de sentir quando vale a pena ficar sem essas temperaturas e se sentir mais confortável ao fazê-lo, isso provavelmente é uma coisa boa.

FWIW Eu pessoalmente evitei ler o livro de Fowler "Refatoração" por dez anos, porque imaginei que não havia muito a dizer sobre tópicos relativamente simples. Eu estava completamente errado. Quando finalmente o li, ele mudou minhas práticas diárias de codificação, para melhor.

Jonathan Hartley
fonte
1
Ótima resposta. O melhor código que eu escrevi (e vi de outras pessoas) geralmente tinha muitos métodos pequenos (2, 3 linhas) que poderiam substituir essas variáveis ​​temporárias. Relacionado é este controvérsia que métodos privados cheiram mal ... Bem pensado e muitas vezes achei verdade.
Stijn de Witt
Os temps nesta pergunta já se referem a funções, portanto, essa resposta é irrelevante para a pergunta dos OP.
precisa saber é o seguinte
@ user949300 Não acho que seja irrelevante. Sim, as temperaturas no exemplo específico do OP são os valores de retorno de funções ou métodos. Mas o OP é muito claro que é apenas um cenário de exemplo. A questão real é a muito mais geral "devemos eliminar variáveis ​​temporárias quando podemos?"
Jonathan Hartley
1
OK, estou vendido, ** tentei ** alterar meu voto. Mas, muitas vezes, quando vou além do escopo limitado da questão do OP, sou enganado. SO pode ser inconstante ... :-). Er, não pode mudar o meu voto até que você editar, qualquer que seja ...
user949300
@ user949300 Santa vaca! Uma pessoa que muda de idéia ao considerar cuidadosamente os problemas! Você, senhor, é uma raridade, e eu tiro meu boné para você.
Jonathan Hartley
3

Bem, é uma boa idéia eliminar variáveis ​​locais se você puder tornar o código mais legível. Esse seu one-liner longo não é legível, mas segue um estilo OO bastante detalhado. Se você pudesse reduzi-lo a algo como

acquireWakeLock(POWER_SERVICE, PARTIAL, "abc");

então eu diria que provavelmente seria uma boa ideia. Talvez você possa introduzir métodos auxiliares para reduzi-lo a algo semelhante; se um código como esse aparecer várias vezes, pode valer a pena.

leftaroundabout
fonte
2

Vamos considerar a Lei de Demeter aqui. No artigo da Wikipedia sobre LoD, o seguinte é afirmado:

A Lei de Demeter para funções exige que um método m de um objeto O possa invocar apenas os métodos dos seguintes tipos de objetos: [2]

  1. O próprio
  2. parâmetros de m
  3. Quaisquer objetos criados / instanciados dentro de m
  4. Objetos de componentes diretos de O
  5. Uma variável global, acessível por O, no escopo de m

Uma das conseqüências de seguir esta lei é que você deve evitar chamar métodos de objetos retornados por outros métodos em uma cadeia longa pontilhada, como é mostrado no segundo exemplo acima:

((PowerManager)getSystemService(POWER_SERVICE)).newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,"MyWakelockTag").acquire();

É realmente difícil descobrir o que isso está fazendo. Para entendê-lo, você precisa entender o que cada procedimento faz e decifrar qual função está sendo chamada em qual objeto. O primeiro bloco de código

PowerManager powerManager=(PowerManager)getSystemService(POWER_SERVICE);
WakeLock wakeLock=powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,"abc");
wakeLock.acquire();

mostra claramente o que você está tentando fazer - você está obtendo um objeto do PowerManager, obtendo um objeto WakeLock do PowerManager e adquirindo o wakeLock. A regra acima segue a regra nº 3 do LoD - você está instanciando esses objetos no seu código e, portanto, pode usá-los para fazer o que você precisa.

Talvez outra maneira de pensar é lembrar que, ao criar um software, você deve escrever com clareza, não com brevidade. 90% de todo o desenvolvimento de software é manutenção. Nunca escreva um código que você não gostaria de manter.

Boa sorte.

Bob Jarvis
fonte
3
Eu estaria interessado em saber como a sintaxe fluida se encaixa nessa resposta. Com a formatação correta, a sintaxe fluida é altamente legível.
precisa saber é o seguinte
12
Não é isso que significa "Lei de Deméter". A Lei de Deméter não é um exercício de contagem de pontos; significa essencialmente "apenas fale com seus amigos imediatos".
Robert Harvey
5
O acesso aos mesmos métodos e membros por meio de uma variável intermediária ainda é uma violação tão grave da lei de Demeter. Você acabou de obscurecer, não corrigiu.
Jonathan Hartley
2
Em termos da "Lei de Deméter", ambas as versões são igualmente "ruins".
Hulk
@Gusdor concordou, mais um comentário sobre o estilo no exemplo da pergunta. A questão foi editada agora.
Jodrell
2

Uma coisa a notar é que o código é lido com freqüência, em diferentes "profundidades". Este código:

PowerManager powerManager = (PowerManager)getSystemService(POWER_SERVICE);
WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "abc");
wakeLock.acquire();

é fácil "roçar". São 3 afirmações. Primeiro, criamos um PowerManager. Então criamos um WakeLock. Então nós acquireo wakeLock. Eu posso ver isso com muita facilidade apenas olhando para o início de cada linha; atribuições de variáveis ​​simples são realmente fáceis de reconhecer parcialmente como "Digite varName = ..." e apenas deslize mentalmente sobre o "...". Da mesma forma, a última afirmação obviamente não é a forma da tarefa, mas envolve apenas dois nomes; portanto, a "essência principal" é imediatamente aparente. Muitas vezes, isso é tudo que eu precisaria saber se estivesse apenas tentando responder "o que esse código faz?" em um nível alto.

Se eu estou perseguindo um bug sutil que acho que está aqui, então obviamente precisarei revisar isso com muito mais detalhes e, na verdade, lembrarei dos "..." s. Mas a estrutura de declaração separada ainda me ajuda a fazer uma declaração de cada vez (especialmente útil se eu precisar aprofundar a implementação das coisas que são chamadas em cada declaração; quando eu voltar, eu entendi completamente "uma unidade" e pode passar para a próxima declaração).

((PowerManager)getSystemService(POWER_SERVICE))
    .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakelockTag")
    .acquire();

Agora é tudo uma afirmação. A estrutura de nível superior não é tão fácil de ler rapidamente; na versão original do OP, sem quebras de linha e recuo para comunicar visualmente qualquer estrutura, eu teria que contar parênteses para decodificá-la em uma sequência de três etapas. Se algumas das expressões de várias partes estiverem aninhadas uma à outra, em vez de organizadas como uma cadeia de chamadas de método, ainda assim poderá parecer semelhante a isso, por isso tenho que ter cuidado ao confiar nisso sem contar parênteses. E se eu confio no recuo e apenas deslizo para a última coisa como o ponto presumido de tudo isso, o que .acquire()me diz por si só?

Às vezes, porém, isso pode ser o que você deseja. Se eu aplicar sua transformação no meio do caminho e escrever:

WakeLock wakeLock =
     ((PowerManeger)getSystemService(POWER_SERVICE))
    .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakeLockTage");
wakeLock.acquire();

Agora isso se comunica com um toque rápido "obtenha um WakeLock, então acquireele". Ainda mais simples que a primeira versão. É imediatamente óbvio que o que é adquirido é um WakeLock. Se a obtenção de um PowerManageré apenas um sub-detalhe que é bastante insignificante ao ponto deste código, mas wakeLocké importante, pode realmente ajudar a enterrar o PowerManagermaterial, de modo que é natural examiná-lo se você estiver apenas tentando obter rapidamente um idéia do que esse código faz. E, sem nomeá-lo, comunica que é usado apenas uma vez, e às vezes é o que é importante (se o restante do escopo for muito longo, eu teria que ler tudo isso para saber se é usado novamente; embora o uso de sub-escopos explícitos possa ser outra maneira de resolver isso, se o seu idioma os suportar).

O que traz à tona que tudo depende do contexto e do que você deseja se comunicar. Como na escrita em prosa em linguagem natural, sempre existem muitas maneiras de escrever um determinado trecho de código que é basicamente equivalente em termos de conteúdo de informações. Como na escrita em prosa em linguagem natural, como você escolhe entre eles geralmente não deve aplicar regras mecanicistas como "eliminar qualquer variável local que ocorra apenas uma vez". Pelo contrário, comovocê optar por escrever o seu código enfatizará certas coisas e enfatizará outras. Você deve se esforçar para fazer essas escolhas conscientemente (incluindo a opção de escrever código menos legível por razões técnicas às vezes), com base no que você realmente deseja enfatizar. Pense especialmente no que servirá aos leitores que precisam apenas "entender o essencial" do seu código (em vários níveis), pois isso acontecerá com muito mais frequência do que uma leitura muito próxima de expressão por expressão.

Ben
fonte
Para mim, mesmo não tendo conhecimento da API, é muito óbvio o que o código faz, mesmo sem as variáveis. getSystemService(POWER_SERVICE)recebe o gerente de energia. .newWakeLockrecebe um bloqueio de vigília. .acquireadquire. OK, não conheço todos os tipos, mas posso descobrir isso no IDE, se necessário.
Rgome
Pode ser óbvio para você o que o código deve fazer , mas você não tem idéia do que ele realmente faz. Se estou procurando um bug, tudo o que sei é que algum código em algum lugar não faz o que deveria fazer, e tenho que descobrir qual código.
precisa saber é o seguinte
@ gnasher729 Sim. Caçar bugs foi um exemplo que eu dei quando você precisaria ler cuidadosamente todos os detalhes. E uma das coisas que realmente ajuda a encontrar o código que não está fazendo o que deveria fazer é poder ver facilmente qual era a intenção do autor original.
Ben
quando volto, entendi completamente "uma unidade" e posso passar para a próxima afirmação. Na verdade não. De fato, as variáveis ​​locais impedem esse entendimento completo. Porque eles ainda estão demorando ... ocupando espaço mental ... o que lhes acontecerá nas próximas 20 declarações ... drumroll ... Sem os locais, você teria certeza de que os objetos se foram e é impossível fazer qualquer coisa com eles nas próximas linhas. Não há necessidade de lembrar sobre eles. Gosto o returnmais rápido possível dos métodos, pelo mesmo motivo.
Stijn de Witt
2

É até um antipadrão com seu próprio nome: Train Wreck . Vários motivos para evitar a substituição já foram mencionados:

  • Difícil de ler
  • Mais difícil de depurar (para observar variáveis ​​e detectar locais de exceções)
  • Violação da Lei de Demeter (LoD)

Considere se esse método sabe muito de outros objetos. O encadeamento de métodos é uma alternativa que pode ajudá-lo a reduzir o acoplamento.

Lembre-se também de que as referências a objetos são realmente baratas.

Borjab
fonte
O código revisado não está fazendo o encadeamento de métodos? EDIT ler o artigo vinculado, então eu vejo a diferença agora. Muito bom artigo obrigado!
Stijn de Witt
Obrigado por analisá-lo. De qualquer forma, o encadeamento de métodos pode funcionar em alguns casos, enquanto deixar a variável pode ser a decisão apropriada. É sempre bom saber por que as pessoas discordam da sua resposta.
Borjab
Eu acho que o oposto de "Train Wreck" é "Local Line". É aquele trem entre duas grandes cidades que para em cada vila do país, no meio do caminho, para o caso de alguém querer entrar ou sair, mesmo que na maioria dos dias ninguém o faça.
rghome 14/05
1

A pergunta declarada é "Devemos eliminar variáveis ​​locais, se pudermos"?

Não, você não deve eliminar apenas porque pode.

Você deve seguir as diretrizes de codificação em sua loja.

Na maioria das vezes, as variáveis ​​locais facilitam a leitura e a depuração do código.

Eu gosto do que você fez PowerManager powerManager. Para mim, uma letra minúscula da classe significa que é apenas uma vez.

Quando você não deveria, é se a variável vai se apegar a recursos caros. Muitos idiomas têm sintaxe para uma variável local que precisa ser limpa / liberada. Em C # está usando.

using(SQLconnection conn = new SQLconnnection())
{
    using(SQLcommand cmd = SQLconnnection.CreateCommand())
    {
    }
}
paparazzo
fonte
Isso não está realmente relacionado às variáveis ​​locais, mas à limpeza de recursos ... Eu não sou versado em C #, mas ficaria surpreso se using(new SQLConnection()) { /* ... */ }não fosse legal também (se seria útil é uma questão diferente :).
Stijn de Witt
1

Um aspecto importante não foi mencionado nas outras respostas: Sempre que você adiciona uma variável, você introduz um estado mutável. Isso geralmente é uma coisa ruim porque torna seu código mais complexo e, portanto, mais difícil de entender e testar. Obviamente, quanto menor o escopo da variável, menor o problema.

O que você deseja não é realmente uma variável cujo valor possa ser modificado, mas uma constante temporária. Portanto, considere expressar isso em seu código, se seu idioma permitir. Em Java você pode usar finale em C ++ você pode usar const. Na maioria das linguagens funcionais, esse é o comportamento padrão.

É verdade que as variáveis ​​locais são o tipo menos prejudicial de estado mutável. As variáveis ​​de membro podem causar muito mais problemas e as variáveis ​​estáticas são ainda piores. Ainda assim, acho importante expressar com a maior precisão possível em seu código o que ele deve fazer. E há uma enorme diferença entre uma variável que pode ser modificada posteriormente e um mero nome para um resultado intermediário. Portanto, se seu idioma permitir que você expresse essa diferença, faça-o.

Frank Puffer
fonte
2
Não neguei sua resposta, mas acho que isso está relacionado ao fato de que variáveis ​​locais geralmente não são consideradas 'estado' em idiomas imperativos, a menos que você esteja falando de algum tipo de método de longa duração. Concordo com o uso de final / const como uma prática recomendada, mas é pouco provável que a introdução de uma variável para simplesmente interromper uma chamada em cadeia leve a problemas causados ​​por um estado mutável. De fato, o uso de variáveis ​​locais ajuda a lidar com o estado mutável. Se um método pode retornar valores diferentes em momentos diferentes, você pode acabar com alguns bugs realmente interessantes.
JimmyJames
@ JimmyJames: Adicionamos algumas explicações à minha resposta. Mas há uma parte do seu comentário que eu não entendi: "o uso de variáveis ​​locais ajuda a lidar com o estado mutável". Você poderia explicar isso?
Frank soprador
1
Por exemplo, digamos que eu precise verificar um valor e, se tiver mais de 10 anos, dispare um alerta. Suponha que este valor vem do método getFoo(). Se eu evitar uma declaração local, terminarei com if(getFoo() > 10) alert(getFoo());Mas getFoo () pode retornar valores diferentes nas duas chamadas diferentes. Eu poderia enviar um alerta com um valor menor ou igual a 10, o que é confuso na melhor das hipóteses e voltará para mim como um defeito. Esse tipo de coisa se torna mais importante com a simultaneidade. A atribuição local é atômica.
JimmyJames
Muito bom ponto. Talvez o motivo pelo qual eu não goste desses locais .... Você fará algo com essa PowerManagerinstância depois de chamar esse método? Deixe-me verificar o resto do método .... mmm ok não. E isso WakeLockque você tem ... o que você está fazendo com isso (digitalizando o restante do método mais uma vez) ... mmm novamente nada ... ok, então por que eles estão lá? Ah, sim, deveria ser mais legível ... mas sem eles, tenho certeza que você não os usa mais, para que não precise ler o restante do método.
Stijn de Witt
Em uma conversa recente, o palestrante argumentou que a melhor maneira de mostrar que uma variável é final é escrever métodos curtos, onde é óbvio que a variável não muda . Se finalfor necessário em uma variável local em um método, seu método é muito longo.
precisa saber é o seguinte