Değişken kullanımını kod içinde genelleştirme


11

Değişkenleri genelleştirmenin iyi bir uygulama olup olmadığını bilmek istiyorum (tüm değerleri saklamak için tek değişken kullanın).
Basit bir örnek düşünün

 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 ;

ve

 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 ;

İlk durumda, eklerinde belirtilen eylemleri gerçekleştirmek için her bir veri depolayan 4 dize kullanıyorum.
İkinci durumda her türlü veri depolamak için sadece 1 değişken.
Farklı değişkenlere sahip olmak, başkasının daha iyi okumasını ve anlamasını kolaylaştırır. Ancak bunların çoğuna sahip olmak yönetmeyi zorlaştırıyor.

Ayrıca çok fazla değişken olması performansımı engelliyor mu?

PS: lütfen kodu wrt cevap etmeyin, örneğin sadece gerçekten ne demek istediğimi iletmek oldu.


Tabii ki aynı değişkeni tekrar kullanıyorsunuz ... çünkü onu bir fonksiyonda tanımladınız. Fonksiyonlar bunun içindir.
zzzzBov

Yanıtlar:


26

Kendinize bu soruyu sormak zorunda olduğunuz, KURU (Kendinizi Tekrarlama) izlemediğiniz oldukça güçlü bir koku. Varsayalım ki, varsayımsal bir kıvırcık ayraç dilinde:

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 bunu içine:

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

Farklı değişkenlerin kullanılıp kullanılmayacağına karar verme ihtiyacının ortadan kalktığına ve şimdi aynı değişikliği üç kez uygulamak yerine bir sorguyu çalıştırmak ve sonucu yazdırmak için mantığı nasıl değiştirebileceğinize dikkat edin. (Örneğin, sorgu sonucunu hemen yazdırmak yerine bir şablon sistemi üzerinden pompalamak istediğinize karar verebilirsiniz).


2
Ben sadece KURU prensibi seviyorum :)
artjom

1
@tdammers bir fonksiyon içinde sadece 2 satır kod olması iyi mi? Bu fonksiyona sahip olup olmadığımı düşünün doFoo () {print (runQuery ("XYZ'den Selct a, b, c"));}
Shirish11

1
Hayır, çağrı yığını artmaz - her çağrı, çağrı yaptığınızda runAndPrintbir yığın çerçeveyi iter ve işlevden çıkıldığında geriye doğru açılır. Üç kez çağırırsanız, üç itme / pop çifti gerçekleştirir, ancak yığın bir kerede birden fazla kare kadar büyümez. Yalnızca yinelenen işlevlerle çağrı yığını derinliği konusunda endişelenmelisiniz.
tdammers

3
Ve sadece iki satır kodlu fonksiyonlar gayet iyi: eğer iki satır mantıksal bir birim yaparsa, o zaman iki satır olur. Sadece biraz bilgi izole ve tek bir yerde tutmak için bir sürü tek katmanlı fonksiyon yazdım.
tdammers

1
@JamesAnderson: Bu biraz çelişkili bir örnek, ama bir noktayı açıklamaya hizmet ediyor. Kaç kod satırınız olduğu ile ilgili değil. Aynı gerçeği kaç kez ifade edersiniz.
DRY'nin

14

Normalde, bu kötü bir uygulamadır.

Bu şekilde bir değişkeni yeniden kullanmak, anlamak için kafa karıştırıcı bir kod oluşturabilir.

Kodu okuyanlar, bir değişkenin bu şekilde yeniden kullanılmasını beklemez ve başlangıçta ayarlanan bir değerin işlevin sonunda neden farklı bir değere sahip olduğunu bilmezler.

Gönderdiğiniz örnekler çok basittir ve bu sorundan gerçekten muzdarip değildir, ancak değişkenleri yeniden kullanan bazı kodları temsil etmezler (başlangıçta ayarlandığı yerde, ortada olmayan bir yerde yeniden kullanılır).

Verdiğiniz örnekler, sorguya geçip onu yürüteceğiniz işlevlere kapsülleme yapmayı sağlar.


sistem performansından ne etkileniyor?
Shirish11

@ Shirish11 - Olabilir. Derleyiciye, dile, çevreye ve diğer değişkenlere bağlıdır.
Oded

Genellikle, derleyici bunu optimize etmekte iyidir. Bununla birlikte, her zaman derleyiciye / plaka formuna / özel kasaya / yapılandırmaya bağlıdır.
deadalnix

7

Kendinden Belgelenmiş Kod Okunması ve Bakımı Daha Kolay

En Az Kefaret İlkesi'ni ve belgeleme kodu kodunu izleyin : hem kullanımını kolay anlaşılır kılmak hem de açıklama yapmadan kodun okunmasını kolaylaştırmak için bir hedef için bir değişken kullanın.

Doğru Şekilde Yapılandırılmış Kod (Yeniden) Kullanımından Daha Kolay (Böylece Daha Ucuz)

Ayrıca, burada queryher zaman bir ifadeyi yürütmeden önce bir deyim hazırlamak için kullanılır. Muhtemelen bu kodun bir kısmını sorguyu hazırlamak ve yürütmek ( DRY ilkesine uymak için) için bir (veya daha fazla) yardımcı yöntemde yeniden düzenlemek istediğiniz bir işarettir .

Bu şekilde, etkili bir şekilde şunları yapacaksınız:

  • geçerli bağlamın sorgusunu tanımlamak için yardımcı yönteminizde yalnızca bir değişken kullanın,
  • her sorguyu yeniden yürütmek istediğinizde daha az kod yazmanız gerekir,
  • kodunuzu diğerleri için daha okunabilir hale getirin.

Örnekler:

Örneğin, yeniden düzenlenmiş sürümün daha iyi olduğu örneklerden alınmıştır. Elbette snippet'iniz bu sorunun amacına sadece bir örnekti, ancak kavram hala geçerli ve ölçeklidir.

Örnek 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 ;

Örnek 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 ;

Örnek 3 (Yeniden düzenlenmiş sözde kod):

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

Fayda düzenli kullanım ile ortaya çıkar.

Kişisel Anekdot

Başlangıçta sınırlı ekran gayrimenkul ile çalışan bir C programcısı olarak başladım, bu yüzden değişkenleri yeniden kullanmak hem derlenmiş kod (o zamanlar) hem de daha fazla kodun aynı anda okunabilmesini sağlamak için mantıklıydı.

Ancak, daha sonra üst düzey dillere geçtikten ve işlevsel programlamayı geliştirdikten sonra, yan etkileri sınırlamak için mümkün olduğunda değişmez değişkenler ve değişmez referanslar kullanma alışkanlığını aldım.

Bunun içinde benim için ne var?

Tüm işlev girdilerinizin değişmez olmasını ve yeni bir sonuç döndürmeyi (gerçek bir matematiksel işlevde olduğu gibi) alıyorsanız, mağazaları kopyalamama alışkanlığına girersiniz.

Uzantı olarak, bu aşağıdakilere yol açar:

  • kısa fonksiyonlar yazıyorsunuz,
  • iyi tanımlanmış hedefleri olan,
  • anlaşılması daha kolay,
  • yeniden kullanmak,
  • genişletmek (ister OO mirası ister fonksiyonel zincirleme yoluyla),
  • ve belge (zaten kendi kendine belgelendiği gibi).

Burada değişebilir duruma bir faydası olduğunu söylemiyorum, sadece alışkanlığın senin üzerinde nasıl büyüyebileceğini ve kod okunabilirliğini nasıl etkilediğini gösteriyorum.


2

Kod Tasarımı Açısından

Genel olarak, değişkenleri farklı değerleri saklamak için yeniden kullanmak iyidir - sonuçta, bu nedenle değişken olarak adlandırılırlar, çünkü değer yalnızca aynı türden değil aynı zamanda aynı şey anlamına geldiği sürece, içinde depolanan değer değişir . Örneğin, currentQuerydeğişkeni burada tekrar kullanmak sorun değil:

for currentQuery in queries:
    execute query;

Doğal olarak bir döngü vardır, bu yüzden bir değişkeni yeniden kullanmanız gerekir , ancak bir döngü olmasa bile iyi olurdu. Değeri yoksa değil aynı anlama ayrı bir değişken kullanın.

Özellikle, açıkladığınız kod çok iyi görünmüyor - kendini tekrarlıyor . Bir döngü veya yardımcı yöntem çağrıları (veya her ikisini) kullanmak çok daha iyidir. Şahsen çok nadiren 1. ya da 2. versiyonunuza benzeyen üretim kodunu gördüm, ancak sahip olduğum durumlarda, 2. versiyonun (değişken yeniden kullanım) daha yaygın olduğunu düşünüyorum.

Performans Açısından

Kullanılan dile, derleyicilere ve çalışma zamanı sistemlerine bağlıdır, ancak genel olarak herhangi bir fark olmamalıdır - özellikle yığın tabanlı kayıt makineleri için derleyiciler (popüler x86 / x86-64 gibi) zaten aynı değişken isteseniz de istemeseniz de tamamen yok sayarak atama hedefi olarak istedikleri boş yığın belleğini veya kaydını kullanın.

Örneğin, gcc -O2aynı ikili dosyayı oluşturur ve bildiğim tek performans farkı derleme sırasında sembol tablosunun boyutudur - 60'lara zamanında geri dönmedikçe tamamen ihmal edilebilir.

Bir Java derleyicisi, 1. sürüm için daha fazla depolama alanına ihtiyaç duyan bayt kodu üretecektir, ancak JVM'nin jitter'i yine de kaldıracaktır, bu yüzden yine, yüksek düzeyde optimize edilmiş koda ihtiyacınız olsa bile neredeyse hiçbir belirgin performans etkisi olmayacağından şüpheleniyorum.


0

Değişkenin tekrar kullanılması çoğu zaman iyi olur.

Benim için, sadece sorgu değişkeni çoğu zaman yeniden. Hemen hemen her zaman sorguyu yürütmek. Sorguyu hemen yürütmediğimde, genellikle farklı bir değişken adı kullanırım.


-1

Derleyiciniz özellikle aptalsa yığın kullanımını artırabilir. Şahsen ben her sorgu için ayrı bir değişken olması herhangi bir okunabilirlik ekler sanmıyorum, hala aslında ne yaptığını görmek için sorgu dizesine bakmak gerekir.


Basit bir örnek verdim, böylece okuyucuların aradığım şeyi anlaması daha kolay. Kodum bundan çok daha karmaşık.
Shirish11

-2

Örnekte, ikinci örnekle devam ederdim. Ne yaptığınızı hem bir okuyucuya hem de optimize edicilere açıktır. İlk örnek biraz daha uygun ve biraz daha karmaşık bir kodla onu kullanardım, ama şöyle yapın:

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

(Bu noktada, tdammers'ın çözümünü düşünebilirim .)

İlk örnekle ilgili sorun querycre, tüm blok için kapsamlıdır, bu da kapsamlı olabilir. Bu, birinin kodu okumasını şaşırtabilir. Ayrıca, gereksiz bellek yazmada bırakabilecek optimize edicileri de karıştırabilir, bu nedenle querycregerekirse daha sonra kullanılabilir (ki bu değildir). Tüm parantezlerle query, eğer sadece bir kayıtta saklanır.

"Tablo oluştur" ve "yürüt" gibi ifadeler ile bana burada fazladan bir bellek yazma fark edilecektir gibi görünmüyor, bu yüzden sadece okuyucu kafa karıştırıcı için kodu hata olur. Ama hız bu yazıyorsanız kod farkında olmak kullanışlı yapar olsun.


Katılmıyorum. Açıklık için ikinci örneği tercih edecekseniz, bir yardımcı yönteme yapılan art arda çağrılara yeniden bakılmalıdır. daha fazla anlam ifade eder ve daha az kod gerektirir.
haylem

@haylem: Gerçekten basit bir durumda, bunun gibi, kodu okuyan birisinin gitmesi ve bulması gereken bir yardımcı yöntem ekliyorsunuz. (Ve biri yardımcı yöntemle ilgili sorun yaşayabilir ve çağrıldığı tüm yerleri bulmak zorunda kalabilir.) Daha az netlik, aynı miktarda kod. Daha karmaşık bir durumda, çözümümle , sonra tdammer'larla giderdim . Bu soruyu çoğunlukla, hem insanlara hem de optimize edicilere yaratılan (kuşkusuz belirsiz, ancak ilginç) problemlerin altını çizmek için cevapladım.
RalphChapin

@haylem: Siz ve tdammer doğru çözümü veriyorsunuz. Sadece bazı durumlarda aşırıya kaçabileceğini düşünüyorum.
RalphChapin
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.