Generalizza l'utilizzo delle variabili all'interno del codice

11

Vorrei sapere se è una buona pratica generalizzare le variabili (usa una variabile singola per memorizzare tutti i valori).
Considera un semplice esempio

 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 ;

Nel primo caso utilizzo 4 stringhe ciascuna memorizzando i dati per eseguire le azioni indicate nei loro suffissi.
Nel secondo caso solo 1 variabile per memorizzare tutti i tipi di dati.
Avere variabili diverse facilita la lettura e la comprensione di qualcun altro. Ma avere troppi di essi rende difficile la gestione.

Inoltre avere troppe variabili ostacolano le mie prestazioni?

P.S: per favore non rispondere w.r.t. il codice, ad esempio, era solo per trasmettere ciò che intendo veramente.

    
posta Shirish11 09.06.2012 - 12:32
fonte

7 risposte

26

Doverti questa domanda è un odore piuttosto strong che non stai seguendo DRY (Do not Repeat Yourself). Supponiamo di avere questo, in un ipotetico linguaggio a ricci:

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);
}

Refactor in:

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");
}

Si noti come la necessità di decidere se utilizzare o meno variabili diverse scompaia e come sia possibile modificare la logica per l'esecuzione di una query e stampare il risultato in un'unica posizione, piuttosto che dover applicare la stessa modifica tre volte. (Ad esempio, potresti decidere di pompare il risultato della query attraverso un sistema di template invece di stamparlo subito).

    
risposta data 09.06.2012 - 15:47
fonte
14

Normalmente, questa è una cattiva pratica.

Riutilizzare una variabile in questo modo può rendere il codice confuso per leggere una comprensione.

Chi legge il codice non si aspetta che una variabile venga riutilizzata in questo modo e non saprà perché un valore impostato all'inizio abbia un valore diverso alla fine della funzione.

Gli esempi che hai postato sono molto semplici e non soffrono di questo problema, ma non rappresentano un codice che riutilizza le variabili (dove è impostato all'inizio, viene riutilizzato da qualche parte nel mezzo - da vista).

Gli esempi che hai dato si prestano all'incapsulamento in funzioni, dove devi passare la query ed eseguirla.

    
risposta data 09.06.2012 - 12:56
fonte
7

Il codice auto-documentato è più facile da leggere e mantenere

Segui Principio di Least Atonishment e del precetto di codice-come-documentazione : usa una variabile per un obiettivo, per renderne l'uso facile da capire e il codice facile da leggere senza spiegazioni.

Il codice strutturato correttamente è più semplice (quindi più economico) per (ri) utilizzare

Inoltre, qui sembrerebbe che query sia sempre usato per preparare un'istruzione prima di eseguirla. Questo è probabilmente un segno che vuoi refactor parte di questo codice in uno (o più) Metodi helper per preparare ed eseguire la query (per conformarsi al principio ASCIUTTO ).

In questo modo, efficacemente:

  • usa solo una variabile nel tuo metodo di supporto per identificare la query del contesto corrente,
  • è necessario digitare meno codice ogni volta che si desidera rieseguire una query,
  • rende il tuo codice più leggibile per gli altri.

Esempi:

Considera questo, preso dal tuo esempio, in cui la versione refactored è ovviamente migliore. Ovviamente il tuo frammento di codice era solo un esempio per lo scopo di questa domanda, ma il concetto è ancora valido e in scala.

Il tuo esempio 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 ;

Il tuo esempio 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 ;

Esempio 3 (pseudo-codice refactored):

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 ...');

Il vantaggio viene mostrato con un normale riutilizzo.

Aneddoto personale

Inizialmente ero un programmatore C che lavorava con proprietà immobiliari limitate dello schermo, quindi riutilizzare le variabili aveva senso sia per il codice compilato (a quei tempi) che per consentire a più codici di essere letti contemporaneamente.

Tuttavia, dopo aver spostato i linguaggi di livello superiore e aggiornato la programmazione funzionale, ho preso l'abitudine di usare variabili immutabili e riferimenti immutabili laddove possibile per limitare gli effetti collaterali.

Cosa c'è dentro per me?

Se prendi l'abitudine di rendere immutabili tutti gli input della tua funzione e di restituire un nuovo risultato (come una vera funzione matematica), prendi l'abitudine di non duplicare i negozi.

Per estensione, questo porta a:

  • stai scrivendo brevi funzioni,
  • con obiettivi ben definiti,
  • che sono più facili da capire,
  • da riutilizzare,
  • per estendere (sia per l'ereditarietà OO che per il concatenamento funzionale),
  • e documento (come già auto-documentante).

Non sto dicendo che non ci sia alcun beneficio per lo stato mutabile qui, sto solo facendo notare come l'abitudine potrebbe crescere su di te e come influisce sulla leggibilità del codice.

    
risposta data 12.06.2012 - 09:21
fonte
2

In Design dei termini di codice

In generale, è giusto riutilizzare le variabili per memorizzare valori diversi - dopotutto, è per questo che vengono chiamate variabili, poiché il valore memorizzato in esse varia - purché il valore non sia solo dello stesso tipo ma significa anche la stessa cosa . Ad esempio, ovviamente, è possibile riutilizzare la variabile currentQuery qui:

for currentQuery in queries:
    execute query;

Naturalmente c'è un ciclo in modo da avere per riutilizzare una variabile, ma anche se non ci fosse un ciclo sarebbe andato tutto bene. Se il valore non significa la stessa cosa, usa una variabile separata.

In particolare, però, il codice che stai descrivendo non sembra molto buono - si ripete da solo . È molto meglio usare una chiamata di metodo loop o helper (o entrambi). Personalmente ho visto molto raramente il codice di produzione che assomiglia alla tua 1a o alla 2a versione, ma nei casi che ho, penso che la seconda versione (riutilizzo variabile) fosse più comune.

In termini di prestazioni

Dipende dalla lingua, dal compilatore e dai sistemi di runtime utilizzati, ma in generale non dovrebbe esserci alcuna differenza - in particolare compilatori per macchine di registro basate su stack (come il popolare x86 / x86-64) utilizzerà comunque qualsiasi memoria di stack libera o registrerà come possibile target di assegnamento, ignorando completamente se si desidera o meno la stessa variabile.

Ad esempio, gcc -O2 genera lo stesso binario esatto e l'unica differenza di prestazioni che conosco è la dimensione della tabella dei simboli durante la compilazione - completamente trascurabile a meno che non si ritorni indietro nel tempo agli anni '60.

Un compilatore Java genererà bytecode che ha bisogno di più spazio per la prima versione, ma il jitter della JVM lo rimuoverà comunque, quindi di nuovo, sospetto che non ci sarebbero praticamente impatti evidenti sulle prestazioni, anche se hai bisogno di codice altamente ottimizzato.

    
risposta data 12.06.2012 - 09:14
fonte
0

Penso che riutilizzare la variabile sia sempre la maggior parte del tempo.

Per me, ho semplicemente riutilizzato la variabile di query per la maggior parte del tempo. Eseguo quasi sempre la query subito dopo. Quando non eseguo subito la query, di solito uso un nome di variabile diverso.

    
risposta data 09.06.2012 - 16:31
fonte
-1

Può aumentare l'utilizzo dello stack se il compilatore è particolarmente stupido. Personalmente non penso che avere una variabile separata per ogni query possa aggiungere a qualsiasi tipo di leggibilità, è comunque necessario esaminare effettivamente la stringa della query per vedere cosa fa.

    
risposta data 09.06.2012 - 12:57
fonte
-2

Nell'esempio, andrei con il secondo esempio. È chiaro sia al lettore che agli ottimizzatori cosa stai facendo. Il primo esempio è un po 'più corretto, e con un codice un po' più complicato lo userei, ma lo faccio come:

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

(A questo punto, potrei prendere in considerazione la soluzione di tdammers .)

Il problema con il primo esempio è che querycre è in ambito per l'intero blocco, che potrebbe essere esteso. Questo può confondere qualcuno che legge il codice. Può anche confondere gli ottimizzatori, che potrebbero lasciare in una memoria non necessaria scrivere in modo che querycre sia disponibile in seguito, se necessario (che non è). Con tutte le parentesi, query è memorizzato solo in un registro, se questo.

Con frasi come "Crea tabella" ed "esegui" non mi sembra che in questo caso si noterà una scrittura di memoria in più, quindi mi farebbe solo un errore nel codice per confondere il lettore. Ma è utile essere consapevoli di questo se stai scrivendo codice in cui la velocità è importante.

    
risposta data 11.06.2012 - 19:05
fonte

Leggi altre domande sui tag