Generalisasi penggunaan variabel di dalam kode

11

Saya ingin tahu apakah ini merupakan praktik yang baik untuk menggeneralisasi variabel (gunakan variabel tunggal untuk menyimpan semua nilai).
Pertimbangkan contoh sederhana

 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 ;

dan

 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 ;

Dalam kasus pertama saya menggunakan 4 string masing-masing menyimpan data untuk melakukan tindakan yang disebutkan dalam sufiks mereka.
Dalam kasus kedua hanya 1 variabel untuk menyimpan semua jenis data.
Memiliki variabel yang berbeda memudahkan orang lain untuk membaca dan memahaminya dengan lebih baik. Tetapi memiliki terlalu banyak dari mereka membuatnya sulit untuk dikelola.

Juga apakah memiliki terlalu banyak variabel menghambat kinerja saya?

PS: tolong jangan jawab wrt kode contohnya itu hanya untuk menyampaikan maksud saya sebenarnya.

Shirish11
sumber
Tentu saja Anda menggunakan kembali variabel yang sama ... karena Anda telah mendefinisikannya dalam suatu fungsi. Untuk itulah fungsinya.
zzzzBov

Jawaban:

26

Harus bertanya pada diri sendiri pertanyaan ini adalah aroma yang cukup kuat bahwa Anda tidak mengikuti KERING (Jangan Ulangi Diri Sendiri). Misalkan Anda memiliki ini, dalam bahasa penjepit keriting hipotetis:

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 itu menjadi:

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

Perhatikan bagaimana kebutuhan untuk memutuskan apakah akan menggunakan variabel yang berbeda atau tidak, dan bagaimana Anda sekarang dapat mengubah logika untuk menjalankan kueri dan mencetak hasilnya di satu tempat, daripada harus menerapkan modifikasi yang sama tiga kali. (Misalnya, Anda mungkin memutuskan ingin memompa hasil kueri melalui sistem templat alih-alih mencetaknya langsung).

tammmer
sumber
2
Saya suka prinsip KERING :)
artjom
1
@tdammers itu baik untuk memiliki hanya 2 baris kode di dalam suatu fungsi? pertimbangkan jika saya memiliki fungsi ini doFoo () {print (runQuery ("Selct a, b, c dari XYZ"));}
Shirish11
1
Tidak, tumpukan panggilan tidak bertambah - setiap panggilan untuk runAndPrintmendorong satu bingkai tumpukan saat Anda memanggilnya, dan kemudian memunculkannya kembali ketika fungsi keluar. Jika Anda menyebutnya tiga kali, itu akan melakukan tiga pasang push / pop, tetapi tumpukan tidak pernah tumbuh lebih dari satu frame pada suatu waktu. Anda seharusnya benar-benar khawatir tentang kedalaman tumpukan panggilan dengan fungsi rekursif.
tdammers
3
Dan fungsi hanya dengan dua baris kode baik-baik saja: jika dua baris membuat unit logis, maka dua baris itu. Saya telah menulis banyak fungsi satu-liner, hanya untuk menjaga sedikit informasi terisolasi dan di satu tempat.
tdammers
1
@JamesAnderson: Ini adalah contoh yang agak dibuat-buat, tetapi berfungsi untuk menggambarkan suatu hal. Ini bukan tentang berapa banyak baris kode yang Anda miliki. Sudah berapa kali Anda menyatakan fakta yang sama. Itulah yang KERING tentang, serta prinsip Sumber Tunggal Kebenaran, Jangan Menyalin-Tempel aturan, dll.
tdammers
14

Biasanya, ini adalah praktik buruk .

Menggunakan kembali variabel adalah cara ini dapat membuat kode yang membingungkan untuk membaca sebuah pemahaman.

Mereka yang membaca kode tidak akan mengharapkan variabel untuk digunakan kembali sedemikian rupa dan tidak akan tahu mengapa nilai yang ditetapkan pada awal memiliki nilai yang berbeda di akhir fungsi.

Contoh yang Anda posting sangat sederhana dan tidak benar-benar menderita dari masalah ini, tetapi mereka tidak mewakili beberapa kode yang menggunakan kembali variabel (di mana ia diatur di awal, akan digunakan kembali di suatu tempat di tengah-tengah dari pandangan).

Contoh yang Anda berikan meminjamkan diri untuk enkapsulasi ke dalam fungsi, di mana Anda akan meneruskan kueri dan menjalankannya.

Oded
sumber
bagaimana dengan kinerja sistem yang terpengaruh olehnya?
Shirish11
@ Shirish11 - Mungkin. Tergantung pada kompiler, bahasa, lingkungan dan variabel lainnya.
Oded
Biasanya, kompiler pandai mengoptimalkan ini. Namun, itu selalu tergantung pada kompiler / plateform / case / konfigurasi tertentu.
deadalnix
7

Kode yang Didokumentasi Sendiri Lebih Mudah Dibaca dan Dipertahankan

Ikuti Principle of Least Atonishment dan aturan kode-sebagai-dokumentasi : gunakan satu variabel untuk satu tujuan, agar keduanya mudah dipahami dan kode mudah dibaca tanpa penjelasan.

Kode yang Terstruktur dengan Benar Lebih Mudah (sehingga Lebih Murah) untuk Penggunaan Kembali

Juga, di sini akan muncul yang queryselalu digunakan untuk menyiapkan pernyataan sebelum menjalankannya. Itu mungkin pertanda bahwa Anda ingin merombak sebagian kode ini menjadi satu (atau lebih) metode pembantu untuk mempersiapkan dan menjalankan kueri (untuk mematuhi prinsip KERING ).

Dengan cara ini, Anda akan secara efektif:

  • gunakan hanya satu variabel dalam metode pembantu Anda untuk mengidentifikasi kueri konteks saat ini,
  • perlu mengetikkan lebih sedikit kode setiap kali Anda ingin menjalankan kembali kueri,
  • membuat kode Anda lebih mudah dibaca oleh orang lain.

Contoh:

Pertimbangkan ini, diambil dari contoh Anda, di mana versi refactored jelas lebih baik. Tentu saja cuplikan Anda hanyalah contoh untuk tujuan pertanyaan ini, tetapi konsepnya tetap berlaku dan berskala.

Contoh Anda 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 ;

Contoh Anda 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 ;

Contoh 3 (Kode pseudo-ulang):

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

Manfaatnya ditunjukkan dengan penggunaan kembali yang teratur.

Anekdot Pribadi

Saya awalnya mulai sebagai seorang programmer C yang bekerja dengan real-estate layar terbatas, jadi menggunakan kembali variabel masuk akal baik untuk kode yang dikompilasi (saat itu) dan untuk memungkinkan lebih banyak kode dapat dibaca sekaligus.

Namun, setelah pindah ke bahasa tingkat yang lebih tinggi dan memoles pemrograman fungsional, saya membiasakan diri menggunakan variabel yang tidak dapat diubah dan referensi yang tidak dapat diubah di mana pun dimungkinkan untuk membatasi efek samping.

Apa untungnya bagi saya?

Jika Anda terbiasa memiliki semua input fungsi Anda tidak berubah dan untuk mengembalikan hasil baru (seperti fungsi matematika sejati), Anda terbiasa tidak menduplikasi toko.

Dengan ekstensi, ini mengarah ke:

  • Anda menulis fungsi pendek,
  • dengan tujuan yang jelas,
  • yang lebih mudah dimengerti,
  • untuk digunakan kembali,
  • untuk memperpanjang (apakah dengan pewarisan OO atau dengan perangkaian fungsional),
  • dan mendokumentasikan (sebagaimana telah mendokumentasikan diri).

Saya tidak mengatakan tidak ada manfaatnya untuk mengubah keadaan di sini, saya hanya menunjukkan bagaimana kebiasaan itu dapat tumbuh pada Anda dan bagaimana hal itu berdampak pada keterbacaan kode.

haylem
sumber
2

Dalam Ketentuan Desain Kode

Secara umum, boleh saja menggunakan kembali variabel untuk menyimpan nilai yang berbeda - setelah semua, itu sebabnya mereka disebut variabel, karena nilai yang disimpan di dalamnya bervariasi - selama nilainya tidak hanya dari jenis yang sama tetapi juga berarti hal yang sama . Sebagai contoh tentu saja tidak masalah untuk menggunakan kembali currentQueryvariabel di sini:

for currentQuery in queries:
    execute query;

Tentu saja ada loop sehingga Anda harus menggunakan kembali variabel, tetapi bahkan jika tidak ada loop itu akan baik-baik saja. Jika nilainya tidak berarti hal yang sama, gunakan variabel yang terpisah.

Namun, secara khusus, kode yang Anda gambarkan tidak terlihat sangat bagus - kode itu berulang sendiri . Jauh lebih baik menggunakan perulangan atau metode bantuan helper (atau keduanya). Secara pribadi saya sangat jarang melihat kode produksi yang terlihat seperti versi 1 atau 2 Anda, tetapi dalam kasus yang saya miliki, saya pikir versi 2 (penggunaan kembali variabel) lebih umum.

Dari segi Kinerja

Itu tergantung pada bahasa, kompiler dan sistem runtime yang digunakan, tetapi secara umum seharusnya tidak ada perbedaan - khususnya kompiler untuk mesin register berbasis stack (seperti x86 / x86-64 populer) tetap akan hanya gunakan memori tumpukan gratis apa pun atau daftarkan mereka sebagai target tugas, sepenuhnya mengabaikan apakah Anda menginginkan variabel yang sama atau tidak.

Sebagai contoh, gcc -O2menghasilkan biner yang sama persis, dan satu-satunya perbedaan kinerja yang saya tahu adalah ukuran tabel simbol selama kompilasi - benar-benar diabaikan kecuali Anda kembali ke masa 60-an.

Kompiler Java akan menghasilkan bytecode yang membutuhkan lebih banyak penyimpanan untuk versi 1, tetapi jitter JVM akan menghapusnya, jadi sekali lagi, saya kira praktis tidak akan ada dampak kinerja yang nyata bahkan jika Anda memerlukan kode yang sangat dioptimalkan.

ek
sumber
0

Saya pikir menggunakan kembali variabel baik-baik saja sebagian besar waktu.

Bagi saya, saya cukup sering menggunakan kembali variabel kueri. Saya hampir selalu menjalankan query setelahnya. Ketika saya tidak segera menjalankan query, saya biasanya menggunakan nama variabel yang berbeda.

Echo mengatakan Reinstate Monica
sumber
-1

Itu dapat meningkatkan penggunaan tumpukan jika kompiler Anda sangat bodoh. Secara pribadi saya tidak berpikir memiliki variabel terpisah untuk setiap kueri menambah keterbacaan apa pun, Anda masih perlu benar-benar melihat string kueri untuk melihat apa yang dilakukannya.

James
sumber
Saya baru saja memberikan contoh sederhana sehingga memudahkan pembaca untuk memahami apa yang saya cari. Kode saya jauh lebih kompleks dari ini.
Shirish11
-2

Dalam contoh, saya akan menggunakan contoh kedua. Cukup jelas bagi pembaca dan pengoptimal apa yang Anda lakukan. Contoh pertama sedikit lebih tepat, dan dengan kode yang sedikit lebih rumit saya akan menggunakannya, tetapi lakukan seperti:

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

(Pada titik ini, saya mungkin mempertimbangkan solusi tdammers .)

Masalah dengan contoh pertama adalah bahwa querycreada di ruang lingkup untuk seluruh blok, yang mungkin luas. Ini dapat membingungkan seseorang yang membaca kode. Ini juga dapat membingungkan pengoptimal, yang mungkin meninggalkan penulisan memori yang tidak perlu sehingga querycretersedia nanti jika diperlukan (yang bukan). Dengan semua kawat gigi, queryhanya disimpan dalam register, jika itu.

Dengan frasa seperti "Buat tabel" dan "eksekusi" itu tidak terlihat bagi saya seperti menulis memori tambahan akan diperhatikan di sini, jadi saya hanya akan menyalahkan kode untuk membingungkan pembaca. Tetapi berguna untuk mengetahui hal ini jika Anda menulis kode di mana kecepatan itu penting.

RalphChapin
sumber
Saya tidak setuju. Jika Anda lebih suka contoh kedua untuk kejelasan, itu harus di refactored untuk panggilan berturut-turut ke metode pembantu. itu woud menyampaikan lebih banyak makna, dan membutuhkan lebih sedikit kode.
haylem
@haylem: Dalam kasus sederhana yang nyata, seperti ini, Anda menambahkan metode pembantu, yang harus dicari dan dibaca oleh seseorang yang membaca kode. (Dan seseorang mungkin mengalami masalah dengan metode pembantu dan harus mencari tahu semua tempat asalnya.) Kurang jelas, tentang jumlah kode yang sama. Dalam kasus yang lebih rumit, saya akan menggunakan solusi saya, kemudian dengan tdammer . Saya menjawab pertanyaan ini sebagian besar untuk menunjukkan masalah (kurang jelas, tetapi menarik) masalah variabel yang digunakan kurang baik bagi manusia dan pengoptimal.
RalphChapin
@haylem: Anda dan tdammer keduanya memberikan solusi yang benar. Saya hanya berpikir itu bisa berlebihan dalam beberapa kasus.
RalphChapin