Generalizar o uso de variáveis ​​dentro do código


11

Gostaria de saber se é uma boa prática generalizar variáveis ​​(use uma variável única para armazenar todos os valores).
Considere um exemplo simples

 Strings querycre,queryins,queryup,querydel; 
    querycre = 'Create table XYZ ...';
    execute querycre ;
    queryins = 'Insert into XYZ ...';
    execute queryins ;
    queryup  = 'Update  XYZ set ...';
    execute queryup;
    querydel = 'Delete from XYZ ...';
    execute querydel ;

e

 Strings query; 
    query= 'Create table XYZ ... ';
    execute query ;
    query= 'Insert into XYZ ...';
    execute query ;
    query= 'Update  XYZ set ...';
    execute query ;
    query= 'Delete from XYZ ...';
    execute query ;

No primeiro caso, eu uso 4 strings cada armazenando dados para executar as ações mencionadas em seus sufixos.
No segundo caso, apenas 1 variável para armazenar todos os tipos de dados.
Ter variáveis ​​diferentes facilita a leitura e a compreensão por outra pessoa. Mas ter muitos deles dificulta o gerenciamento.

Também ter muitas variáveis ​​dificulta meu desempenho?

PS: por favor, não responda o código errado, por exemplo, era apenas para transmitir o que eu realmente quero dizer.


Claro que você reutiliza a mesma variável ... porque você a definiu em uma função. É para isso que servem as funções.
precisa saber é o seguinte

Respostas:


26

Ter que se fazer essa pergunta é um cheiro muito forte que você não está seguindo DRY (não se repita). Suponha que você tenha isso, em uma linguagem hipotética de chaves:

function doFoo() {
    query = "SELECT a, b, c FROM foobar WHERE baz = 23";
    result = runQuery(query);
    print(result);

    query = "SELECT foo, bar FROM quux WHERE x IS NULL";
    result = runQuery(query);
    print(result);

    query = "SELECT a.foo, b.bar FROM quux a INNER JOIN quuux b ON b.quux_id = a.id ORDER BY date_added LIMIT 10";
    result = runQuery(query);
    print(result);
}

Refatorar isso para:

function runAndPrint(query) {
    result = runQuery(query);
    print(result);
}

function doFoo() {
    runAndPrint("SELECT a, b, c FROM foobar WHERE baz = 23");
    runAndPrint("SELECT foo, bar FROM quux WHERE x IS NULL");
    runAndPrint("SELECT a.foo, b.bar FROM quux a INNER JOIN quuux b ON b.quux_id = a.id ORDER BY date_added LIMIT 10");
}

Observe como a necessidade de decidir se deve ou não usar variáveis ​​diferentes desaparece e como agora você pode alterar a lógica para executar uma consulta e imprimir o resultado em um único local, em vez de ter que aplicar a mesma modificação três vezes. (Por exemplo, você pode decidir que deseja bombear o resultado da consulta através de um sistema de modelos em vez de imprimi-lo imediatamente).


2
I princípio DRY apenas amor :)
Artjom

1
@ tdammers é bom ter apenas 2 linhas de código dentro de uma função? considere se eu tenho essa função doFoo () {print (runQuery ("Selct a, b, c de XYZ")));}
Shirish11

1
Não, a pilha de chamadas não aumenta - cada chamada runAndPrintempurra um quadro de pilha quando você a chama e depois a retorna quando a função é encerrada. Se você chamá-lo três vezes, ele fará três pares push / pop, mas a pilha nunca aumenta em mais de um quadro por vez. Você só deve realmente se preocupar com a profundidade da pilha de chamadas com funções recursivas.
tdammers

3
E funções com apenas duas linhas de código são perfeitas: se duas linhas formam uma unidade lógica, então duas linhas são. Eu escrevi muitas funções de uma linha, apenas para manter algumas informações isoladas e em um só lugar.
tdammers

1
@ JamesAnderson: É um exemplo um tanto artificial, mas serve para ilustrar um ponto. Não se trata de quantas linhas de código você possui. É quantas vezes você declara o mesmo fato. Isso é o que DRY é sobre, bem como a única fonte de princípio Verdade, a Shalt de mil não copiar e colar regra, etc.
tdammers

14

Normalmente, essa é uma prática ruim .

Reutilizar uma variável é assim, pode tornar o código confuso para ler um entendimento.

Quem lê o código não espera que uma variável seja reutilizada dessa maneira e não saberá por que um valor definido no início tem um valor diferente no final da função.

Os exemplos que você postou são muito simples e realmente não sofrem com esse problema, mas não são representativos de algum código que reutiliza variáveis ​​(onde é definido no início, é reutilizado em algum lugar no meio - fora da vista).

Os exemplos que você deu se prestam ao encapsulamento em funções, onde você passaria a consulta e a executaria.


o desempenho do sistema é afetado por ele?
usar o seguinte código

@ Shirish11 - Pode. Depende do compilador, idioma, ambiente e outras variáveis.
Oded

Geralmente, o compilador é bom em otimizar isso. No entanto, sempre depende do compilador / placa / caso específico / configuração.
deadalnix

7

O código auto-documentado é mais fácil de ler e manter

Siga o Princípio da menor expiação e o preceito do código como documentação : use uma variável para um objetivo, para facilitar o entendimento e o código de leitura, sem explicações.

O código corretamente estruturado é mais fácil (portanto mais barato) para (re) usar

Além disso, aqui parece que querysempre é usado para preparar uma instrução antes de executá-la. Provavelmente, isso é um sinal de que você deseja refatorar parte desse código em um (ou mais) métodos auxiliares para preparar e executar a consulta (em conformidade com o princípio DRY ).

Dessa forma, você efetivamente:

  • use apenas uma variável no seu método auxiliar para identificar a consulta do contexto atual,
  • você precisa digitar menos código sempre que quiser executar novamente uma consulta,
  • torne seu código mais legível para outras pessoas.

Exemplos:

Considere isso, tirado do seu exemplo, onde a versão refatorada é obviamente melhor. É claro que seu snippet foi apenas um exemplo para o objetivo desta pergunta, mas o conceito ainda é verdadeiro e é escalável.

Seu exemplo 1:

Strings querycre,queryins,queryup,querydel; 
    querycre = 'Create table XYZ ...';
    execute querycre ;
    queryins = 'Insert into XYZ ...';
    execute queryins ;
    queryup  = 'Update  XYZ set ...';
    execute queryup;
    querydel = 'Delete from XYZ ...';
    execute querydel ;

Seu exemplo 2:

 Strings query; 
    query= 'Create table XYZ ...';
    execute query ;
    query= 'Insert into XYZ ...';
    execute query ;
    query= 'Update  XYZ set ...';
    execute query ;
    query= 'Delete from XYZ ...';
    execute query ;

Exemplo 3 (pseudocódigo refatorado):

def executeQuery(query, parameters...)
    statement = prepareStatement(query, parameters);
    execute statement;
end

// call point:
executeQuery('Create table XYZ ... ');
executeQuery('Insert into XYZ ...');
executeQuery('Update  XYZ set ...');
executeQuery('Delete from XYZ ...');

O benefício é mostrado com a reutilização regular.

Anedota pessoal

Inicialmente, comecei como programador C trabalhando com propriedades limitadas de tela, portanto, reutilizar variáveis ​​fazia sentido tanto para o código compilado (na época) quanto para permitir que mais código fosse legível ao mesmo tempo.

No entanto, depois de passar para linguagens de nível superior e aprimorar a programação funcional, adquiri o hábito de usar variáveis ​​imutáveis ​​e referências imutáveis ​​sempre que possível para limitar os efeitos colaterais.

O quê tem pra mim?

Se você adota o hábito de imutar todas as entradas de sua função e retornar um novo resultado (como seria uma verdadeira função matemática), adquire o hábito de não duplicar as lojas.

Por extensão, isso leva a:

  • você está escrevendo funções curtas,
  • com objetivos bem definidos,
  • que são mais fáceis de entender,
  • reutilizar,
  • estender (seja por herança de OO ou por encadeamento funcional),
  • e documento (como já se auto-documenta).

Não estou dizendo que não há benefício para o estado mutável aqui, apenas estou apontando como o hábito pode crescer em você e como isso afeta a legibilidade do código.


2

Em termos de design de código

Em geral, é bom reutilizar variáveis ​​para armazenar valores diferentes - afinal, é por isso que elas são chamadas de variáveis, porque o valor armazenado nelas varia - desde que o valor não seja apenas do mesmo tipo, mas também signifique a mesma coisa . Por exemplo, é claro que não há problema em reutilizar a currentQueryvariável aqui:

for currentQuery in queries:
    execute query;

Naturalmente, há um loop, então você precisa reutilizar uma variável, mas mesmo se não houvesse um loop, tudo estaria bem. Se o valor não significa a mesma coisa, use uma variável separada.

Especificamente, porém, o código que você está descrevendo não parece muito bom - ele se repete . É muito melhor usar chamadas de método auxiliar ou de loop (ou ambas). Pessoalmente, eu raramente vi código de produção que se parecesse com a sua 1ª ou 2ª versão, mas nos casos que tenho, acho que a 2ª versão (reutilização de variável) era mais comum.

Em termos de desempenho

Depende do idioma, do (s) compilador (es) e do (s) sistema (s) de tempo de execução usados, mas em geral não deve haver nenhuma diferença - em particular os compiladores para máquinas de registro baseadas em pilha (como o popular x86 / x86-64) irão apenas use qualquer memória de pilha livre ou registre como possível o destino da atribuição, ignorando completamente se você deseja a mesma variável ou não.

Por exemplo, gcc -O2gera exatamente o mesmo binário, e a única diferença de desempenho que conheço é o tamanho da tabela de símbolos durante a compilação - completamente desprezível, a menos que você volte no tempo para os anos 60.

Um compilador Java irá gerar bytecode que precisa de mais armazenamento para a 1ª versão, mas a instabilidade da JVM o removerá de qualquer maneira, então, novamente, suspeito que não haveria praticamente nenhum impacto perceptível no desempenho, mesmo se você precisar de código altamente otimizado.


0

Eu acho que reutilizar a variável é bom na maioria das vezes.

Para mim, simplesmente reutilizo a variável de consulta na maioria das vezes. Eu quase sempre executo a consulta logo depois. Quando não executo a consulta imediatamente, geralmente uso um nome de variável diferente.


-1

Pode aumentar o uso da pilha se o seu compilador for particularmente burro. Pessoalmente, eu não acho que ter uma variável separada para cada consulta acrescente qualquer legibilidade, você ainda precisa realmente olhar a string de consulta para ver o que ela faz.


Acabei de fornecer um exemplo simples, para que seja mais fácil para os leitores entenderem o que eu procuro. Meu código é muito mais complexo que isso.
precisa saber é o seguinte

-2

No exemplo, eu iria com o segundo exemplo. É bastante claro para o leitor e para os otimizadores o que você está fazendo. O primeiro exemplo é um pouco mais adequado e, com um código um pouco mais complicado, eu o usaria, mas faça o seguinte:

{
    String query = 'Create table XYZ ...';
    execute query;
}
{
    String query = 'Insert table XYZ ...';
    execute query;
}
And so on...

(Nesse ponto, posso considerar a solução de tdammers .)

O problema com o primeiro exemplo é que querycreestá no escopo de todo o bloco, que pode ser extenso. Isso pode confundir alguém lendo o código. Também pode confundir os otimizadores, que podem deixar uma gravação desnecessária na memória, para que querycreestejam disponíveis mais tarde, se necessário (o que não é). Com todas as chaves, queryé armazenado apenas em um registro, se houver.

Com frases como "Criar tabela" e "executar", não me parece que uma gravação extra na memória seja notada aqui, então eu culparia apenas o código por confundir o leitor. Mas é útil para estar ciente deste código se você estiver escrevendo onde a velocidade não importa.


Discordo. Se você preferir o segundo exemplo, para maior clareza, ele deve ser refatorado para chamadas sucessivas a um método auxiliar. transmitiria mais significado e exigiria menos código.
haylem

@haylem: Em um caso muito simples, como este, você está adicionando um método auxiliar, que alguém que lê o código precisa procurar. (E alguém pode ter problemas com o método auxiliar e ter que descobrir todos os locais de onde é chamado.) Menos clareza, sobre a mesma quantidade de código. Em um caso mais complicado, eu iria com a minha solução, depois com a do ddammer . Respondi a essa pergunta principalmente para apontar os problemas (reconhecidamente obscuros, mas interessantes) que as variáveis ​​subutilizadas representam tanto para os seres humanos quanto para os otimizadores.
RalphChapin

@haylem: você e o Tdammer fornecem a solução correta. Eu apenas acho que pode ser um exagero em alguns casos.
RalphChapin
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.