Haruskah saya menggunakan kembali variabel?

59

Haruskah saya menggunakan kembali variabel?

Saya tahu bahwa banyak praktik terbaik mengatakan Anda tidak boleh melakukannya, namun, nanti, ketika pengembang yang berbeda sedang men-debug kode dan memiliki 3 variabel yang mirip dan satu-satunya perbedaan adalah bahwa mereka dibuat di tempat yang berbeda dalam kode, ia mungkin bingung. Pengujian unit adalah contoh yang bagus untuk ini.

Namun, saya tidak tahu bahwa praktek-praktek terbaik yang sebagian besar waktu menentangnya. Misalnya mereka mengatakan tidak untuk "mengganti" parameter metode.

Praktik terbaik bahkan menentang pembatalan variabel sebelumnya (di Jawa ada Sonar yang memberikan peringatan ketika Anda menetapkan nullke variabel, bahwa Anda tidak perlu melakukannya untuk memanggil pengumpul sampah sejak Java 6. Anda tidak selalu dapat mengontrol peringatan mana yang dimatikan; sebagian besar waktu default diaktifkan.)

IAdapter
sumber
11
Sejak Java 6? Anda tidak perlu menetapkan nol ke variabel di versi Java apa pun. Ketika sebuah variabel keluar dari ruang lingkup, itu melepaskan referensi ke objeknya.
Kevin Panko
35
menggunakan kembali variabel adalah salah satu hal pertama yang digunakan code-obfuscators
Lelouch Lamperouge
7
Konflik penggunaan ulang variabel dengan memilih pengidentifikasi yang layak untuk variabel Anda. Dalam bahasa modern sebenarnya tidak ada manfaat untuk menggunakan kembali variabel yang lebih besar daripada manfaat memiliki pengidentifikasi yang baik.
Joren
4
Perhatikan juga bahwa tidak semua reuse adalah reuse. Programmer FORTRAN lama, bahkan yang telah berpindah ke bahasa lain, secara rutin menggunakan I, J, K, L, M, N (atau i, j, k, l, m, n) untuk semua loop-DO kami (for- loop) penghitung. Kita terbiasa melihat hal-hal seperti SUM = SUM + A (I, K) * B (K, J), atau jumlah + = a [i] [k] * b [k] [j] ;.
John R. Strohm
1
Menggunakan kembali variabel dapat dibenarkan ketika memprogram mikrokontroler dengan sumber daya yang sangat terbatas (beberapa kBytes RAM).
m .lin

Jawaban:

130

Masalah Anda muncul hanya ketika metode Anda panjang dan melakukan banyak tugas secara berurutan. Ini membuat kode lebih sulit untuk dipahami (dan dengan demikian mempertahankan) per se. Menggunakan kembali variabel menambahkan di atas ini elemen risiko tambahan, membuat kode lebih sulit untuk diikuti dan lebih rentan kesalahan.

Praktik terbaik IMO adalah menggunakan metode yang cukup pendek yang hanya melakukan satu hal, menghilangkan seluruh masalah.

Péter Török
sumber
bagaimana dengan unit-testing? misalnya saya perlu menguji jika setelah menjalankan metode untuk kedua kalinya masih berfungsi seperti yang diharapkan.
IAdapter
20
@IAdapter, kode uji unit adalah masalah yang berbeda, di mana standar mungkin lebih santai daripada kode produksi. Namun, membuatnya mudah dibaca dan mudah dipelihara adalah prioritas tinggi. Anda dapat (dan harus) mengekstrak metode dari unit test Anda juga, untuk membuatnya pendek dan mudah dibaca (dan untuk menghilangkan kebutuhan untuk menggunakan kembali variabel).
Péter Török
3
@IAdapter, untuk skenario yang Anda jelaskan saya tidak akan menggunakan kembali variabel. Hal yang tepat akan menjadi sesuatu seperti result1 = foo(); result2 = foo(); Assert.AreEqual(result1, result2);saya tidak melihat banyak tempat di mana Anda perlu menggunakan kembali variabel dalam kasus ini.
JSB ձոգչ
1
@IAdapter untuk (int i = 0; i <2; i ++) {result = foo (); assertEquals (expectedResult, result);}
Bill K
2
+1 - ini adalah bau kode yang bagus untuk kapan membuat metode yang lebih kecil.
49

Penggunaan kembali variabel dalam suatu metode adalah tanda kuat bahwa Anda harus memperbaiki / membaginya.

Jadi jawaban saya adalah bahwa Anda tidak boleh menggunakannya kembali, karena jika Anda melakukannya maka akan jauh lebih sulit untuk memperbaikinya nanti.

Thanos Papathanasiou
sumber
19

Tergantung.

Beberapa variabel mungkin dibuat dengan tujuan untuk menyimpan jenis data tertentu, yang dapat berubah selama eksekusi suatu fungsi. Kode pengembalian muncul di sini, misalnya:

void my_function() {
    HRESULT errorcode;
    errorcode = ::SomeWindowsApiFunction();
    if (FAILED(errorcode)) { /* handle error */ }
    errorcode = ::AnotherWindowsApiFunction();
    if (FAILED(errorcode)) { /* handle error */ }
}

Nama variabel membuatnya sangat jelas apa variabel ini dimaksudkan untuk disimpan. Saya pikir penggunaan kata-kata lain seperti ini adalah mungkin, di mana variabel secara konseptual adalah sebuah wadah yang secara logis digunakan oleh contoh berbeda dari hal-hal yang sangat mirip selama berlangsungnya suatu fungsi.

Namun, secara umum, ini harus dilakukan hanya dalam keadaan di mana sangat jelas bagi pembaca kode yang mungkin. Dalam kasus apa pun, kecuali mungkin optimasi ekstrim tanpa memperhatikan keterbacaan kode, variabel harus digunakan kembali hanya karena jenisnya cocok.

Semua ini pada dasarnya mengikuti dari praktik yang baik dalam penamaan variabel. Nama harus berbicara sendiri. Jika sulit untuk menempatkan tujuan yang tepat untuk semua penggunaan kembali dalam nama pendek, yang terbaik adalah hanya menggunakan variabel yang berbeda.

Felix Dombek
sumber
15

Alasan terbesar saya tidak menggunakan kembali variabel (terutama dalam unit test) adalah karena ia memperkenalkan jalur kode yang tidak perlu, yang sulit untuk diuji dan di-debug. Tes unit yang baik harus independen dari tes lain dan ketika Anda menggunakan kembali variabel level kelas (misalnya) dalam fixture tes unit Anda harus memastikan untuk menyatakan keadaan mereka sebelum setiap tes. Tes unit yang baik juga mengisolasi cacat sehingga dalam teori setiap kasus uji (metode) hanya boleh menyatakan 1 perilaku untuk sistem yang diuji. Jika metode pengujian Anda ditulis seperti ini, jarang ada kebutuhan atau manfaat untuk menggunakan kembali variabel tingkat metode. Terakhir, dalam bahasa yang mendukung penutupan dan pemrosesan asinkron, sangat sulit untuk berpikir tentang apa yang sedang terjadi jika Anda menggunakan kembali variabel di seluruh metode.

sbrenton
sumber
jadi saya harus menulis metode pengujian seperti -testSomething dan menegaskan untuk pemanggilan metode tunggal -testSomethingTwoInvocations dan menyatakan untuk pemanggilan kedua saja?
IAdapter
2
Iya. Ini membantu Anda menentukan apakah iterasi pertama atau kedua yang gagal. mspec dapat membantu untuk ini, pohon warisannya akan sangat berguna.
Bryan Boettcher
Jika Anda menggunakan "variabel" ketika Anda bermaksud "variabel kelas" atau "variabel instan" maka Anda perlu mengekspresikan diri Anda dengan lebih jelas.
gnasher729
13

Anda harus menggunakan variabel yang berbeda. Jika Anda khawatir rekan kerja Anda akan bingung, beri mereka nama yang jelas-jelas menutupi peran mereka.
Menggunakan kembali variabel kemungkinan merupakan sumber kebingungan di masa depan; lebih baik untuk menjernihkannya sekarang.
Dalam beberapa kasus, nama variabel yang sama dapat digunakan kembali; misalnya idalam lingkaran penghitungan sederhana. Dalam kasus ini, tentu saja Anda harus memastikan bahwa variabel berada dalam ruang lingkup mereka sendiri.

EDIT: Penggunaan kembali variabel kadang-kadang merupakan tanda bahwa Prinsip Tanggung Jawab Tunggal dilanggar. Periksa untuk melihat apakah variabel yang digunakan kembali digunakan dalam peran yang sama. Jika ya, itu mungkin tidak dapat digunakan kembali sama sekali (meskipun mungkin masih lebih disukai untuk memiliki dua variabel yang berbeda, untuk membatasi ruang lingkup variabel tersebut). Jika digunakan dalam peran yang berbeda, Anda memiliki pelanggaran SRP di tangan Anda.

SL Barth - Pasang kembali Monica
sumber
4

Ada satu situasi di mana Anda mungkin ingin menggunakan kembali variabel terlepas dari saran hebat yang diberikan oleh jawaban lain: ketika kompiler Anda membutuhkan uluran tangan.

Dalam beberapa kasus, kompiler Anda mungkin tidak cukup pintar untuk menyadari bahwa variabel register-dialokasikan tertentu tidak lagi digunakan oleh bagian selanjutnya dari kode. Oleh karena itu tidak akan menggunakan kembali register bebas secara teoritis untuk variabel berikutnya, dan kode yang dihasilkan mungkin kurang optimal.

Perhatikan bahwa saya tidak mengetahui adanya kompiler arus utama yang gagal menangkap situasi ini dengan benar, jadi jangan pernah, pernah melakukan ini kecuali Anda tahu pasti bahwa kompiler Anda menghasilkan kode sub-optimal. Jika Anda mengkompilasi untuk sistem embedded khusus dengan kompiler khusus, Anda mungkin akan mengalami masalah ini.

Joris Timmermans
sumber
17
-1 kecuali Anda dapat menunjuk ke situasi dunia nyata di mana ini benar-benar terjadi, dan di mana menggunakan kembali variabel membuat perbedaan yang cukup besar. Ini adalah solusi teoretis untuk masalah teoretis, dan bukan solusi yang sangat bagus. Dimana kompiler memutuskan untuk meletakkan variabel adalah perhatian kompiler; jika kompiler Anda menghasilkan kode yang buruk, dan jika itu benar-benar membuat perbedaan, maka perbaiki atau ganti kompiler.
Caleb
3
@ Caleb - Anda tidak selalu memiliki akses ke kode sumber kompilator untuk platform yang sedang Anda kembangkan, terutama untuk platform embedded yang dipatenkan. Saya juga TIDAK mengatakan dalam jawaban saya bahwa saya tidak tahu adanya kompiler arus utama saat ini (atau penerjemah / VMs sebenarnya) yang tidak melakukan analisis liveness ini dengan benar dalam semua kasus yang telah saya lihat. Namun, saya telah bekerja pada sistem embedded berpemilik dengan kompiler khusus yang sangat sederhana (10 tahun yang lalu atau lebih). Sistem ini memiliki kemampuan yang sangat terbatas, demikian juga kompilernya, sehingga situasi ini benar-benar terjadi di sana.
Joris Timmermans
2
+1 Saya benar-benar menggunakan kembali proyek sebelumnya (kode media yang sangat optimal ditulis dalam ANSI C). Sejauh yang saya ingat perbedaannya mudah terlihat dalam perakitan dan diukur dalam tolok ukur. Tidak pernah dilakukan dan berharap bahwa tidak akan pernah harus menggunakan kembali seperti itu di Jawa.
nyamuk
@ Caleb memperbaiki atau mengganti kompiler mungkin bukan opsi karena sejumlah alasan, dan Anda hanya harus puas dengan apa yang Anda miliki.
@ ThorbjørnRavnAndersen Apakah mungkin bahwa seseorang mungkin dipaksa untuk menggunakan kompiler yang buruk, dan lebih jauh lagi bahwa kinerja mungkin sangat penting sehingga Anda perlu menebak kompiler kedua dan memanipulasi kode Anda untuk menggunakan kembali register? Iya. Apakah itu mungkin ? Tidak. MadKeithV setuju bahwa dia tidak dapat memberikan contoh dunia nyata. Apakah ini praktik terbaik ? Apakah itu gaya yang baik ? Apakah ini merupakan indikator kualitas kode ? Tentu saja tidak. Apakah ini jawaban yang berguna untuk pertanyaan yang ditulis? Karena menghormati MadKeithV, tapi saya rasa tidak.
Caleb
2

Saya akan mengatakan TIDAK.

Pikirkan skenario ini: program Anda macet dan Anda perlu mencari tahu apa yang terjadi dengan memeriksa dump inti ... dapatkah Anda melihat perbedaannya? ;-)

fortran
sumber
Jika dump inti Anda berasal dari build yang dioptimalkan, mungkin saja variabel tersebut berbagi memori. Jadi itu mungkin kurang membantu.
Winston Ewert
tentu saja, build yang dioptimalkan tidak terlalu berguna untuk debugging! tetapi bagaimanapun Anda masih memiliki opsi untuk menggunakan debug build ... Dan ketika Anda memiliki debugger terpasang, Anda tidak perlu pergi langkah demi langkah dari awal fungsi untuk melihat bagaimana variabel berubah, karena mereka jangan! :-D
fortran
2

Tidak, Anda tidak meningkatkan kode yang sedang dijalankan mesin (... kode perakitan). Biarkan menggunakan kembali memori apa pun yang digunakan kompiler untuk variabel ke kompiler. Cukup sering itu akan menjadi register, dan menggunakan kembali tidak memberi Anda apa pun. Fokus untuk membuat kode lebih mudah dibaca.

Rawbert
sumber
0

Tergantung. Dalam bahasa dinamis, di mana tipe berada pada nilai daripada variabel maka jika saya memiliki argumen yang cukup terkenal untuk fungsi yang, misalnya, adalah string. Saya perubahan dalam algoritma berarti bahwa itu selalu digunakan setelah ditafsirkan sebagai integer, kemudian, sebagai konsep pertama saya mungkin melakukan yang setara dengan

scrote = int (scrote)

Tapi saya akhirnya akan melihat untuk mengubah jenis yang dikirim ke fungsi dan perhatikan perubahan dalam tipe parameter.

Paddy3118
sumber
1
Menempatkan baris seperti "scrote = int (scrote)" di tengah kumpulan kode yang panjang adalah cara yang bagus untuk membuat gila para programmer pemeliharaan.
jhocking
Masalahnya lebih cenderung pada "batch kode yang panjang" yang Anda sebutkan.
Paddy3118
Seperti catatan jawaban yang diterima, menggunakan kembali variabel hanya benar-benar masalah dengan kumpulan kode yang panjang. Pada dasarnya, dalam situasi apa pun di mana Anda akan menulis sesuatu seperti "scrote = int (scrote)" Saya lebih suka untuk meletakkan int (scrote) dalam variabel baru, atau lebih baik lagi meneruskan int (scrote) ke fungsi baru.
jhocking
0

Pertama, lihat lingkungan pengembangan Anda. Jika Anda memiliki masalah debugging karena Anda memiliki lima variabel dalam cakupan yang berbeda dengan nama yang identik, dan debugger tidak menunjukkan kepada Anda mana dari variabel-variabel ini yang Anda butuhkan, maka jangan gunakan lima variabel dengan nama yang sama. Ada dua cara untuk mencapai ini: Gunakan satu variabel, atau gunakan lima nama yang berbeda.

Debugger Anda juga mungkin menyulitkan untuk men-debug suatu fungsi dengan banyak variabel. Jika fungsi dengan 20 variabel lebih sulit untuk di-debug daripada satu dengan 16 variabel, maka Anda dapat mempertimbangkan untuk mengganti 5 variabel dengan satu. ("Mungkin mempertimbangkan" tidak sama dengan "harus selalu").

Tidak masalah menggunakan satu variabel di banyak tempat selama variabel tersebut selalu memiliki tujuan yang sama. Misalnya, jika sepuluh panggilan fungsi mengembalikan kode kesalahan, yang ditangani segera untuk setiap panggilan, gunakan satu variabel dan bukan 10. Tapi jangan gunakan variabel yang sama untuk hal-hal yang sama sekali berbeda. Seperti menggunakan "nama" untuk nama pelanggan, dan 10 baris kemudian menggunakan variabel yang sama untuk nama perusahaan, itu buruk dan akan membuat Anda mendapat masalah. Lebih buruk lagi, menggunakan "customerName" untuk nama pelanggan, dan 10 baris kemudian menggunakan variabel "customerName" yang sama untuk nama perusahaan.

Yang penting, tidak ada yang merupakan aturan besi. Semuanya memiliki kelebihan dan kekurangan. Jika "praktik terbaik" menyarankan satu hal, dan Anda memiliki alasan untuk mengatakan bahwa itu adalah ide yang buruk dalam situasi spesifik Anda, maka jangan lakukan itu.

gnasher729
sumber
0

Pertama, lihat lingkungan pengembangan Anda. Jika Anda memiliki masalah debugging karena Anda memiliki lima variabel dalam cakupan yang berbeda dengan nama yang identik, dan debugger tidak menunjukkan kepada Anda mana dari variabel-variabel ini yang Anda butuhkan, maka jangan gunakan lima variabel dengan nama yang sama. Ada dua cara untuk mencapai ini: Gunakan satu variabel, atau gunakan lima nama yang berbeda.

Debugger Anda juga mungkin menyulitkan untuk men-debug suatu fungsi dengan banyak variabel. Jika fungsi dengan 20 variabel lebih sulit untuk di-debug daripada satu dengan 16 variabel, maka Anda dapat mempertimbangkan untuk mengganti 5 variabel dengan satu. ("Mungkin mempertimbangkan" tidak sama dengan "harus selalu").

Tidak masalah menggunakan satu variabel di banyak tempat selama variabel tersebut selalu memiliki tujuan yang sama. Misalnya, jika sepuluh panggilan fungsi mengembalikan kode kesalahan, yang ditangani segera untuk setiap panggilan, gunakan satu variabel dan bukan 10. Ada satu masalah dengan ini: Biasanya, kompiler akan memberi tahu Anda ketika Anda menggunakan variabel yang tidak diinisialisasi. Tapi di sini, jika Anda membaca kode kesalahan setelah panggilan 6, tetapi variabel belum benar-benar berubah setelah panggilan 5, Anda akan mendapatkan data yang tidak berguna tanpa peringatan kompiler Anda. Karena variabel telah diinisialisasi, dengan data yang sekarang tidak berguna.

Yang penting, tidak ada yang merupakan aturan besi. Semuanya memiliki kelebihan dan kekurangan. Jika "praktik terbaik" menyarankan satu hal, dan Anda memiliki alasan untuk mengatakan bahwa itu adalah ide yang buruk dalam situasi spesifik Anda, maka jangan lakukan itu.

gnasher729
sumber
-2

Gunakan variabel global saat Anda perlu mempertahankan konstanta status atau store. Dengan menggunakan kembali variabel, Anda hanya menggunakan kembali nama yang menunjuk ke lokasi di memori. Nama deskriptif pada inisialisasi hanya dapat memenangkan kejelasan Anda (Dengan asumsi Java dan tidak ada OCD primitif).

Kecuali Anda ke dalam kebingungan kode dengan tangan atau menjengkelkan pengembang lain.

JunoA
sumber