Haruskah kita menghilangkan variabel lokal jika kita bisa?

95

Misalnya, untuk mengaktifkan CPU di Android, saya dapat menggunakan kode seperti ini:

PowerManager powerManager = (PowerManager)getSystemService(POWER_SERVICE);
WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "abc");
wakeLock.acquire();

tapi saya pikir variabel lokal powerManagerdan wakeLockdapat dihilangkan:

((PowerManager)getSystemService(POWER_SERVICE))
    .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakelockTag")
    .acquire();

adegan serupa muncul di tampilan peringatan iOS, misalnya: dari

UIAlertView *alert = [[UIAlertView alloc]
    initWithTitle:@"my title"
    message:@"my message"
    delegate:nil
    cancelButtonTitle:@"ok"
    otherButtonTitles:nil];
[alert show];

-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
    [alertView release];
}

untuk:

[[[UIAlertView alloc]
    initWithTitle:@"my title"
    message:@"my message"
    delegate:nil
    cancelButtonTitle:@"ok"
    otherButtonTitles:nil] show];

-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
    [alertView release];
}

Apakah praktik yang baik untuk menghilangkan variabel lokal jika hanya digunakan satu kali dalam cakupan?

ggrr
sumber
95
Belum tentu. Kadang-kadang itu membuat kode lebih jelas untuk menggunakan variabel satu kali, dan dalam sebagian besar bahasa pemrograman yang layak, ada sangat sedikit (jika ada) biaya run-time untuk variabel tambahan tersebut.
Robert Harvey
75
Itu juga membuat melangkah melalui kode dengan debugger lebih sulit. Dan Anda juga harus yakin (tergantung pada bahasa) ekspresi pertama bukan NULL atau kesalahan.
GrandmasterB
78
Tidak. Bahkan, itu adalah praktik yang baik untuk memperkenalkan variabel lokal untuk memutus rantai panggilan metode. Kode mesin yang dihasilkan cenderung identik, dan kode sumbernya hampir dijamin lebih mudah dibaca, karenanya lebih baik.
Kilian Foth
48
Coba itu. Sekarang pasang debugger dan coba lihat status PowerManager atau WakeLock. Sadarilah kesalahan Anda. Saya dulu berpikiran sama ("ada apa dengan semua penduduk setempat ini?") Sampai saya harus menghabiskan sebagian besar waktu saya menyelidiki kode.
Faerindel
42
Bahkan dalam contoh Anda, versi "dihilangkan" Anda memiliki bilah gulir dan tidak muat di layar saya sepenuhnya, yang membuatnya jauh lebih sulit untuk dibaca.
Erik

Jawaban:

235

Kode dibaca jauh lebih sering daripada yang tertulis, jadi Anda harus kasihan pada jiwa miskin yang harus membaca kode enam bulan dari sekarang (mungkin Anda) dan berusaha untuk kode yang paling jelas dan termudah untuk dipahami. Menurut pendapat saya, bentuk pertama, dengan variabel lokal, jauh lebih mudah dipahami. Saya melihat tiga tindakan pada tiga baris, bukan tiga tindakan pada satu baris.

Dan jika Anda pikir Anda mengoptimalkan apa pun dengan menyingkirkan variabel lokal, Anda tidak. Kompiler modern akan memasukkan powerManagerregister 1 , apakah variabel lokal digunakan atau tidak, untuk memanggil newWakeLockmetode. Hal yang sama berlaku untuk wakeLock. Jadi Anda berakhir dengan kode terkompilasi yang sama dalam kedua kasus.

1 Jika Anda memiliki banyak kode intervensi antara deklarasi dan penggunaan variabel lokal, mungkin ada di stack, tetapi ini adalah detail kecil.

Tony BenBrahim
sumber
2
Anda tidak dapat mengetahui apakah ada banyak kode, pengoptimal mungkin menyejajarkan beberapa fungsi ... Jika tidak, setuju, berjuang terlebih dahulu agar mudah dibaca adalah langkah yang tepat.
Matthieu M.
2
Yah, saya pikir sebaliknya, jika saya melihat variabel lokal mendapatkan diinisialisasi beberapa kali pada setiap fungsi yang digunakan alih-alih menjadi atribut ketika itu bisa, saya akan mencari mengapa, pada dasarnya saya akan membaca dengan seksama garis dan membandingkannya hanya untuk pastikan mereka sama. Jadi saya akan membuang waktu.
Walfrat
15
@Walfrat Variabel lokal mendapatkan diinisialisasi beberapa kali? Aduh. Tidak ada yang menyarankan untuk menggunakan kembali penduduk setempat :)
Luaan
32
@Walfrat membiakkan efek samping dan seharusnya hanya digunakan ketika Anda secara khusus ingin mempertahankan status di antara panggilan ke anggota publik. Pertanyaan ini tampaknya berkaitan dengan penggunaan lokal untuk penyimpanan sementara dari perhitungan menengah.
Gusdor
4
T: Haruskah kita menghilangkan variabel lokal jika kita bisa? A: Tidak.
simon
94

Beberapa komentar yang sangat tersirat menyatakan hal ini, tetapi tidak ada jawaban yang saya lihat, jadi saya akan menambahkannya sebagai jawaban. Faktor utama Anda dalam memutuskan masalah ini adalah:

Debuggability

Seringkali, pengembang menghabiskan lebih banyak waktu dan upaya debugging daripada menulis kode.

Dengan variabel lokal, Anda dapat:

  • Breakpoint pada baris tempat ditugaskan (dengan semua dekorasi breakpoint lainnya, seperti breakpointing bersyarat, dll ...)

  • Periksa / saksikan / cetak / ubah-nilai-variabel lokal

  • Menangkap masalah yang muncul karena gips.

  • Memiliki jejak tumpukan yang dapat dibaca (jalur XYZ memiliki satu operasi alih-alih 10)

Tanpa variabel lokal, semua tugas di atas mungkin jauh lebih sulit, sangat sulit, atau benar-benar mustahil, tergantung pada debugger Anda.

Dengan demikian, ikuti pepatah terkenal (tulis kode dengan cara yang Anda inginkan seolah-olah pengembang berikutnya untuk mempertahankannya setelah Anda sendiri adalah orang gila gila yang tahu di mana Anda tinggal), dan berbuat salah di sisi debuggability yang lebih mudah , artinya gunakan variabel lokal .

DVK
sumber
20
Saya ingin menambahkan bahwa stacktraces jauh lebih tidak berguna ketika ada banyak panggilan pada satu baris. Jika Anda memiliki pengecualian penunjuk nol pada saluran 50 dan ada 10 panggilan pada saluran itu tidak mempersempit banyak hal. Dalam aplikasi produksi, ini akan sering menjadi sebagian besar informasi yang Anda dapatkan dari laporan cacat.
JimmyJames
3
Melangkah melalui kode juga jauh lebih sulit. Jika ada panggilan () -> panggilan () -> panggilan () -> panggilan (), sulit untuk masuk ke metode panggilan ketiga. Jauh lebih mudah jika ada empat variabel lokal
gnasher729
3
@ Frankpuffer - kita harus berurusan dengan dunia nyata. Di mana debuggers tidak melakukan apa yang Anda usulkan.
DVK
2
@DVK: Sebenarnya ada lebih banyak debugger daripada yang saya pikir memungkinkan Anda memeriksa atau menonton ekspresi apa pun. MS Visual Studio (sejak versi 2013) memiliki fitur ini untuk C ++ dan C #. Eclipse memilikinya untuk Java. Dalam komentar lain, Faerindel menyebut IE11 untuk JS.
Frank Puffer
4
@DVK: Ya, banyak penipu dunia nyata tidak melakukan apa yang saya usulkan. Tetapi itu tidak ada hubungannya dengan bagian pertama dari komentar saya. Saya merasa gila untuk berasumsi bahwa orang yang akan mempertahankan kode saya terutama akan berinteraksi dengannya melalui debugger. Debuggers hebat untuk tujuan tertentu tetapi jika mereka mendapatkan alat utama untuk menganalisis kode, saya akan mengatakan bahwa ada sesuatu yang salah dan saya akan mencoba memperbaikinya alih-alih membuat kode tersebut lebih dapat debuggable.
Frank Puffer
47

Hanya jika itu membuat kode lebih mudah dimengerti. Dalam contoh Anda, saya pikir itu membuatnya lebih sulit untuk dibaca.

Menghilangkan variabel dalam kode yang dikompilasi adalah operasi sepele untuk setiap kompiler yang terhormat. Anda dapat memeriksa sendiri output untuk memverifikasi.

Apa namanya
sumber
1
Itu ada hubungannya dengan styling seperti penggunaan variabel. Pertanyaannya sekarang telah diedit.
Jodrell
29

Pertanyaan Anda "apakah ini praktik yang baik untuk menghilangkan variabel lokal jika hanya digunakan satu kali dalam cakupan?" sedang menguji kriteria yang salah. Utilitas variabel lokal tidak tergantung pada berapa kali digunakan tetapi apakah itu membuat kode lebih jelas. Memberi label nilai menengah dengan nama yang bermakna dapat meningkatkan kejelasan dalam situasi seperti yang Anda hadirkan karena memecah kode menjadi potongan yang lebih kecil dan lebih mudah dicerna.

Dalam pandangan saya, kode yang tidak dimodifikasi yang Anda berikan lebih jelas daripada kode Anda yang dimodifikasi dan karenanya tidak akan berubah. Bahkan, saya akan mempertimbangkan mengeluarkan variabel lokal dari kode Anda yang dimodifikasi untuk meningkatkan kejelasan.

Saya tidak akan mengharapkan dampak kinerja dari variabel lokal, dan bahkan jika ada satu kemungkinan terlalu kecil untuk dipertimbangkan kecuali jika kode berada dalam lingkaran yang sangat ketat di bagian penting kecepatan program.

Jack Aidley
sumber
Saya pikir itu ada hubungannya dengan gaya dan penggunaan ruang putih sebagai apa pun. Pertanyaannya telah diedit.
Jodrell
15

Mungkin.

Secara pribadi saya akan ragu menghilangkan variabel lokal jika ada typecast yang terlibat. Saya menemukan versi ringkas Anda kurang dapat dibaca karena jumlah tanda kurung mulai mendekati batas mental yang saya miliki. Bahkan memperkenalkan seperangkat tanda kurung baru yang tidak diperlukan dalam versi yang sedikit lebih verbose menggunakan variabel lokal.

Penyorotan sintaksis yang disediakan oleh editor kode dapat mengurangi kekhawatiran semacam itu sampai batas tertentu.

Bagi saya, ini adalah kompromi yang lebih baik:

PowerManager powerManager = (PowerManager)getSystemService(POWER_SERVICE);
powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "abc").acquire();

Dengan demikian menjaga satu variabel lokal dan membuang variabel lainnya. Di C # saya akan menggunakan kata kunci var di baris pertama karena typecast sudah menyediakan informasi jenis.

9Rune5
sumber
13

Meskipun saya menerima validitas jawaban yang mendukung variabel lokal, saya akan berperan sebagai advokat iblis dan menyajikan pandangan pelawan.

Saya pribadi agak menentang menggunakan variabel lokal murni untuk jumlah yang untuk tujuan dokumentasi, meskipun alasan itu sendiri menunjukkan bahwa praktik itu memiliki nilai: variabel lokal secara efektif pseudo-mendokumentasikan kode.

Dalam kasus Anda, masalah utama adalah lekukan dan bukan tidak adanya variabel. Anda dapat (dan harus) memformat kode sebagai berikut:

((PowerManager)getSystemService(POWER_SERVICE))
        .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,"MyWakelockTag")
        .acquire();

Bandingkan dengan versi dengan variabel lokal:

PowerManager powerManager=(PowerManager)getSystemService(POWER_SERVICE);
WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,"abc");
wakeLock.acquire();

Dengan variabel lokal: nama menambahkan beberapa informasi ke pembaca dan jenisnya ditentukan dengan jelas, tetapi panggilan metode aktual kurang terlihat dan (menurut saya) tidak dibaca dengan jelas.

Tanpa menggunakan variabel lokal: ini lebih ringkas dan pemanggilan metode lebih terlihat, tetapi Anda mungkin meminta informasi lebih lanjut tentang apa yang dikembalikan. Namun beberapa IDE dapat menunjukkan ini kepada Anda.

Tiga komentar lebih lanjut:

  1. Menurut pendapat saya, menambahkan kode yang tidak memiliki penggunaan fungsional kadang-kadang dapat membingungkan karena pembaca harus menyadari bahwa itu memang tidak memiliki penggunaan fungsional dan hanya ada untuk "dokumentasi". Misalnya, jika metode ini panjangnya 100 baris, tidak akan jelas bahwa variabel lokal (dan karenanya hasil dari pemanggilan metode) tidak diperlukan di beberapa titik kemudian kecuali Anda membaca keseluruhan metode.

  2. Menambahkan variabel lokal berarti bahwa Anda harus menentukan jenisnya, dan ini menimbulkan ketergantungan pada kode yang jika tidak maka tidak akan ada. Jika tipe pengembalian metode berubah sepele (misalnya, namanya diubah) Anda harus memperbarui kode Anda, sedangkan tanpa variabel lokal Anda tidak akan.

  3. Debugging bisa lebih mudah dengan variabel lokal jika debugger Anda tidak menunjukkan nilai yang dikembalikan dari metode. Tetapi perbaikan untuk itu adalah untuk memperbaiki kekurangan pada debugger, bukan mengubah kode.

rghome
sumber
Mengenai komentar Anda lebih lanjut: 1. Ini seharusnya tidak menjadi masalah jika Anda mengikuti konvensi bahwa variabel lokal dinyatakan semirip mungkin dengan tempat mereka digunakan dan Anda menjaga metode Anda cukup lama. 2. Tidak dalam bahasa pemrograman dengan inferensi tipe. 3. Kode yang ditulis dengan baik seringkali tidak memerlukan debugger sama sekali.
Robert Harvey
2
Contoh kode pertama Anda hanya berfungsi jika Anda membuat objek menggunakan antarmuka fasih atau "builder," pola yang tidak akan saya gunakan di mana pun dalam kode saya, tetapi hanya selektif.
Robert Harvey
1
Saya pikir pertanyaannya mengasumsikan bahwa variabel lokal secara fungsional berlebihan dan oleh karena itu jenis antarmuka diperlukan untuk kasus ini. Kami mungkin bisa mencapai pemindahan penduduk lokal jika tidak melalui berbagai contortions, tetapi saya berpikir kami sedang melihat kasus sederhana.
rghome
1
Saya menemukan varian Anda lebih buruk untuk dibaca. Saya mungkin terlalu sering terpapar ke VB.net, tetapi yang pertama saya lihat ketika melihat sampel Anda adalah "Kemana perginya pernyataan WITH? Apakah saya tidak sengaja menghapusnya?" Saya perlu melihat dua kali apa yang sedang terjadi dan itu tidak baik ketika saya perlu meninjau kembali kode beberapa bulan kemudian.
Tonny
1
@Tonny bagi saya, ini lebih mudah dibaca: penduduk setempat tidak menambahkan apa pun yang tidak jelas dari konteksnya. Saya memiliki kepala Java saya, jadi tidak ada withpernyataan. Ini akan menjadi konvensi pemformatan normal di Jawa.
rghome
6

Ada ketegangan motivasi di sini. Pengenalan variabel sementara dapat membuat kode lebih mudah dibaca. Tetapi mereka juga dapat mencegah, dan membuatnya lebih sulit untuk melihat, refactoring lain yang mungkin, seperti Metode Ekstrak , dan Ganti Temp dengan Permintaan . Jenis refactoring yang terakhir ini, bila sesuai, seringkali memberikan manfaat yang jauh lebih besar daripada variabel temp.

Pada motivasi untuk refactoring terakhir ini, Fowler menulis :

"Masalah dengan temps adalah temps dan temporer. Karena mereka hanya dapat dilihat dalam konteks metode yang digunakan, temps cenderung mendorong metode yang lebih lama, karena itulah satu-satunya cara Anda dapat mencapai temp. mengganti temp dengan metode kueri, metode apa pun di kelas dapat memperoleh informasi. Itu sangat membantu dalam menghasilkan kode pembersih untuk kelas. "

Jadi, ya, gunakan temps jika mereka membuat kode lebih mudah dibaca, terutama jika itu adalah norma lokal untuk Anda dan tim Anda. Tetapi sangat berhati-hati bahwa melakukan hal itu kadang-kadang dapat membuat Anda lebih sulit menemukan peningkatan alternatif yang lebih besar. Jika Anda dapat mengembangkan kemampuan Anda untuk merasakan ketika pergi tanpa manfaat seperti itu, dan menjadi lebih nyaman ketika melakukannya, maka itu mungkin hal yang baik.

FWIW Saya pribadi menghindari membaca buku Fowler "Refactoring" selama sepuluh tahun karena saya membayangkan tidak banyak yang bisa dikatakan tentang topik-topik yang relatif langsung itu. Saya benar-benar salah. Ketika saya akhirnya membacanya, itu mengubah praktik pengkodean harian saya, jauh lebih baik.

Jonathan Hartley
sumber
1
Jawaban yang bagus Kode terbaik yang saya tulis (dan telah dilihat dari orang lain) sering memiliki banyak metode kecil (2, 3 baris) yang dapat menggantikan variabel temp tersebut. Terkait adalah ini mengambil kontroversial bahwa metode pribadi bau .... Dipikirkan dengan baik dan saya sering menemukan itu benar.
Stijn de Witt
Temps dalam pertanyaan ini sudah merujuk ke fungsi, jadi jawaban ini tidak relevan dengan pertanyaan OPs.
user949300
@ user949300 Saya tidak berpikir itu tidak relevan. Ya, temps dalam contoh spesifik OP adalah nilai pengembalian dari fungsi atau metode. Tetapi OP sangat jelas itu hanyalah sebuah contoh skenario. Pertanyaan yang sebenarnya adalah pertanyaan yang jauh lebih umum "haruskah kita menghilangkan variabel sementara ketika kita bisa?"
Jonathan Hartley
1
OK, saya sudah terjual, ** mencoba ** mengubah suara saya. Tetapi seringkali ketika saya melampaui ruang lingkup terbatas dari pertanyaan OP, saya menjadi kotor. JADI bisa berubah-ubah ... :-). Eh, tidak dapat mengubah suara saya sampai Anda mengedit, apa pun ...
user949300
@ user949300 Sapi suci! Seseorang yang berubah pikiran setelah mempertimbangkan masalah dengan seksama! Anda, tuan, jarang, dan saya melepas topiku untuk Anda.
Jonathan Hartley
3

Sebaiknya hilangkan variabel lokal jika Anda bisa membuat kode lebih mudah dibaca. Satu kalimat panjang Anda tidak dapat dibaca, tetapi kemudian mengikuti gaya OO yang sangat jelas. Jika Anda bisa menguranginya menjadi seperti

acquireWakeLock(POWER_SERVICE, PARTIAL, "abc");

maka saya akan mengatakan itu mungkin ide yang bagus. Mungkin Anda bisa memperkenalkan metode pembantu untuk merebusnya menjadi sesuatu yang serupa; jika kode seperti ini muncul beberapa kali maka mungkin bermanfaat.

leftaroundabout
sumber
2

Mari pertimbangkan Hukum Demeter di sini. Dalam artikel Wikipedia tentang LoD berikut ini dinyatakan:

Hukum Demeter untuk fungsi mensyaratkan bahwa metode m suatu objek O hanya dapat memanggil metode dari jenis objek berikut ini: [2]

  1. O sendiri
  2. parameter m
  3. Benda apa pun yang dibuat / dipakai dalam m
  4. Objek komponen langsung O
  5. Variabel global, dapat diakses oleh O, dalam lingkup m

Salah satu konsekuensi dari mengikuti Undang-undang ini adalah Anda harus menghindari metode memanggil objek yang dikembalikan oleh metode lain dalam string bertitik-panjang, seperti yang ditunjukkan pada contoh kedua di atas:

((PowerManager)getSystemService(POWER_SERVICE)).newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,"MyWakelockTag").acquire();

Sangat sulit untuk mengetahui apa yang dilakukannya. Untuk memahaminya, Anda harus memahami apa yang dilakukan masing-masing prosedur, dan kemudian menguraikan fungsi yang dipanggil pada objek mana. Blok kode pertama

PowerManager powerManager=(PowerManager)getSystemService(POWER_SERVICE);
WakeLock wakeLock=powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,"abc");
wakeLock.acquire();

jelas menunjukkan apa yang Anda coba lakukan - Anda mendapatkan objek PowerManager, mendapatkan objek WakeLock dari PowerManager, lalu mendapatkan wakeLock. Aturan di atas mengikuti aturan # 3 dari LoD - Anda membuat instance objek-objek ini dalam kode Anda, dan dengan demikian dapat menggunakannya untuk menyelesaikan apa yang Anda butuhkan.

Mungkin cara lain untuk dipikirkan adalah dengan mengingat bahwa ketika membuat perangkat lunak Anda harus menulis untuk kejelasan, bukan untuk singkatnya. 90% dari semua pengembangan perangkat lunak adalah pemeliharaan. Jangan pernah menulis kode yang tidak akan Anda sukai.

Semoga berhasil.

Bob Jarvis
sumber
3
Saya akan tertarik pada bagaimana sintaksis fluida cocok dengan jawaban ini. Dengan pemformatan yang benar, sintaks fluid sangat mudah dibaca.
Gusdor
12
Bukan itu yang dimaksud dengan "Hukum Demeter". Hukum Demeter bukanlah latihan penghitungan titik; itu pada dasarnya berarti "hanya berbicara dengan teman dekat Anda."
Robert Harvey
5
Mengakses metode dan anggota yang sama melalui variabel perantara masih merupakan pelanggaran berat terhadap hukum Demeter. Anda baru saja mengaburkannya, bukan memperbaikinya.
Jonathan Hartley
2
Dalam hal "Hukum Demeter", kedua versi sama-sama "buruk".
Hulk
@ Goddor setuju, ini lebih banyak komentar pada styling dalam contoh pertanyaan. Pertanyaannya sekarang telah diedit.
Jodrell
2

Satu hal yang perlu diperhatikan adalah bahwa kode sering dibaca, untuk "kedalaman" yang berbeda. Kode ini:

PowerManager powerManager = (PowerManager)getSystemService(POWER_SERVICE);
WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "abc");
wakeLock.acquire();

mudah untuk "skim". Ada 3 pernyataan. Pertama kami datang dengan PowerManager. Lalu kami datang dengan WakeLock. Lalu kami acquireyang wakeLock. Saya bisa melihatnya dengan sangat mudah hanya dengan melihat awal setiap baris; tugas variabel sederhana benar-benar mudah dikenali sebagian sebagai "Ketik varName = ..." dan hanya skim mental atas "...". Demikian pula pernyataan terakhir jelas bukan bentuk penugasan, tetapi hanya melibatkan dua nama, sehingga "inti utama" segera terlihat. Seringkali hanya itu yang perlu saya ketahui jika saya hanya mencoba menjawab "apa yang dilakukan kode ini?" pada level agak tinggi.

Jika saya mengejar bug halus yang saya pikir ada di sini, maka jelas saya harus membahas ini lebih detail, dan akan benar-benar mengingat "...". Tetapi struktur pernyataan yang terpisah masih membantu saya melakukan pernyataan itu satu per satu (khususnya berguna jika saya perlu terjun lebih dalam ke dalam implementasi hal-hal yang dipanggil dalam setiap pernyataan; ketika saya kembali, saya sepenuhnya memahami "satu unit" dan kemudian dapat beralih ke pernyataan berikutnya).

((PowerManager)getSystemService(POWER_SERVICE))
    .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakelockTag")
    .acquire();

Sekarang semuanya satu pernyataan. Struktur tingkat atas tidak mudah dibaca skim; dalam versi asli OP, tanpa linebreak dan indentasi untuk secara visual mengkomunikasikan struktur apa pun, saya harus menghitung tanda kurung untuk menerjemahkannya ke dalam urutan 3 langkah. Jika beberapa ekspresi multi-bagian bersarang di dalam satu sama lain alih-alih diatur sebagai rangkaian panggilan metode, maka itu masih bisa terlihat mirip dengan ini, jadi saya harus berhati-hati mempercayai itu tanpa menghitung tanda kurung. Dan jika saya benar-benar memercayai indentasi dan hanya melihat ke depan ke hal terakhir sebagai titik yang diduga dari semua ini, apa yang .acquire()saya katakan sendiri?

Namun terkadang, itu bisa menjadi apa yang Anda inginkan. Jika saya menerapkan transformasi Anda setengah jalan dan menulis:

WakeLock wakeLock =
     ((PowerManeger)getSystemService(POWER_SERVICE))
    .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakeLockTage");
wakeLock.acquire();

Sekarang ini berkomunikasi dengan skim cepat "dapatkan WakeLock, lalu acquireitu". Bahkan lebih sederhana dari versi pertama. Segera jelas bahwa hal yang diperoleh adalah a WakeLock. Jika memperoleh PowerManagerhanya sub-detail yang cukup signifikan untuk poin kode ini, tetapi yang wakeLockpenting, maka itu sebenarnya bisa membantu untuk mengubur PowerManagerbarang - barang jadi wajar saja untuk melewatinya jika Anda hanya mencoba dengan cepat mendapatkan ide tentang apa kode ini. Dan tidak penamaan itu berkomunikasi bahwa itu adalah hanya digunakan sekali, dan kadang-kadang itu yang penting (jika sisa cakupannya sangat panjang, saya harus membaca semua itu untuk mengetahui apakah itu pernah digunakan lagi; meskipun menggunakan sub-lingkup eksplisit dapat menjadi cara lain untuk mengatasinya, jika bahasa Anda mendukungnya).

Yang memunculkan bahwa semuanya tergantung pada konteks dan apa yang ingin Anda komunikasikan. Seperti halnya menulis prosa dalam bahasa alami, selalu ada banyak cara untuk menulis sepotong kode tertentu yang pada dasarnya setara dalam hal konten informasi. Seperti halnya menulis prosa dalam bahasa alami, bagaimana Anda memilih di antara mereka umumnya tidak boleh menerapkan aturan mekanistik seperti "menghilangkan variabel lokal yang hanya terjadi sekali". Lebih tepatnya bagaimanaAnda memilih untuk menuliskan kode Anda akan menekankan hal-hal tertentu dan tidak menekankan yang lain. Anda harus berusaha keras untuk membuat pilihan-pilihan itu secara sadar (termasuk pilihan untuk menulis kode yang kurang mudah dibaca karena alasan teknis pada waktu tertentu), berdasarkan apa yang sebenarnya ingin Anda tekankan. Terutama pikirkan tentang apa yang akan melayani pembaca yang hanya perlu "mendapatkan intisari" dari kode Anda (di berbagai tingkatan), karena itu akan terjadi jauh lebih sering daripada pembacaan ekspresi-per-ekspresi yang sangat dekat.

Ben
sumber
Bagi saya, meskipun saya tidak memiliki pengetahuan tentang API, sangat jelas apa yang dilakukan kode, bahkan tanpa variabel. getSystemService(POWER_SERVICE)mendapatkan manajer kekuatan. .newWakeLockmendapat kunci bangun. .acquirememperolehnya. OK, saya tidak tahu semua tipe, tetapi saya dapat menemukannya di IDE jika saya perlu.
rghome
Mungkin sudah jelas bagi Anda apa yang seharusnya dilakukan oleh kode , tetapi Anda tidak tahu apa yang sebenarnya dilakukannya. Jika saya mencari bug, yang saya tahu adalah beberapa kode di suatu tempat tidak melakukan apa yang seharusnya dilakukan, dan saya harus menemukan kode mana.
gnasher729
@ gnasher729 Ya. Bug-hunt adalah contoh yang saya berikan ketika Anda perlu membaca semua detail dengan cermat. Dan salah satu hal yang sangat membantu menemukan kode yang tidak melakukan apa yang seharusnya dilakukan adalah untuk dapat dengan mudah melihat apa maksud penulis asli.
Ben
ketika saya kembali, saya sepenuhnya memahami "satu unit" dan kemudian dapat beralih ke pernyataan berikutnya. Sebenarnya tidak. Bahkan variabel lokal mencegah pemahaman penuh itu. Karena mereka masih berlama-lama ... mengambil ruang mental ... apa yang akan terjadi pada mereka dalam 20 pernyataan berikutnya ... drumroll ... Tanpa penduduk setempat Anda akan yakin bahwa benda-benda itu hilang dan tidak mungkin melakukan apa pun dengan mereka di baris berikutnya. Tidak perlu mengingatnya. Saya suka returnsecepat mungkin dari metode, untuk alasan yang sama.
Stijn de Witt
2

Ini bahkan merupakan antipattern dengan namanya sendiri: Train Wreck . Beberapa alasan untuk menghindari penggantian telah dinyatakan:

  • Sulit dibaca
  • Lebih sulit di-debug (keduanya untuk menonton variabel dan mendeteksi lokasi pengecualian)
  • Pelanggaran Hukum Demeter (LoD)

Pertimbangkan apakah metode ini tahu terlalu banyak dari objek lain. Metode chaining adalah alternatif yang bisa membantu Anda mengurangi kopling.

Juga ingat bahwa referensi ke objek sangat murah.

Borjab
sumber
Ehm bukankah kode yang direvisi melakukan metode chaining? EDIT membaca artikel yang terhubung sehingga saya melihat perbedaannya sekarang. Artikel yang cukup bagus terima kasih!
Stijn de Witt
Terima kasih telah mengulasnya. Bagaimanapun, metode chainning dapat bekerja pada beberapa kasus sementara meninggalkan variabel mungkin merupakan keputusan yang tepat. Itu selalu baik untuk mengetahui mengapa orang tidak setuju dengan jawaban Anda.
Borjab
Saya kira kebalikan dari "Train Wreck" adalah "Local Line". Itu adalah kereta antara dua kota besar yang berhenti di setiap desa di antara kalau-kalau ada seseorang yang ingin naik atau turun, meskipun sebagian besar hari tidak ada yang melakukannya.
rghome
1

Pertanyaan yang dinyatakan adalah "Haruskah kita menghilangkan variabel lokal jika kita bisa"?

Tidak, Anda tidak harus menghilangkan hanya karena Anda bisa.

Anda harus mengikuti pedoman pengkodean di toko Anda.

Sebagian besar variabel lokal membuat kode lebih mudah dibaca dan di-debug.

Saya suka dengan apa yang Anda lakukan PowerManager powerManager. Bagi saya huruf kecil dari kelas berarti hanya digunakan satu kali.

Ketika Anda seharusnya tidak, apakah variabel akan memegang sumber daya mahal. Banyak bahasa memiliki sintaks untuk variabel lokal yang perlu dibersihkan / dirilis. Dalam C # itu menggunakan.

using(SQLconnection conn = new SQLconnnection())
{
    using(SQLcommand cmd = SQLconnnection.CreateCommand())
    {
    }
}
paparazzo
sumber
Ini tidak benar-benar terkait dengan variabel lokal tetapi untuk pembersihan sumber daya ... Saya tidak berpengalaman dalam C # tapi saya akan terkejut jika using(new SQLConnection()) { /* ... */ }tidak legal juga (apakah itu akan berguna adalah masalah yang berbeda :).
Stijn de Witt
1

Satu aspek penting belum disebutkan dalam jawaban lain: Setiap kali Anda menambahkan variabel, Anda memperkenalkan keadaan bisa berubah. Ini biasanya merupakan hal yang buruk karena membuat kode Anda lebih kompleks dan karenanya lebih sulit untuk dipahami dan diuji. Tentu saja, semakin kecil cakupan variabel, semakin kecil masalahnya.

Yang Anda inginkan sebenarnya bukan variabel yang nilainya dapat dimodifikasi tetapi konstanta sementara. Karena itu pertimbangkan untuk mengungkapkan ini dalam kode Anda jika bahasa Anda memungkinkan. Di Jawa Anda bisa menggunakan finaldan di C ++ Anda bisa menggunakan const. Dalam sebagian besar bahasa fungsional, ini adalah perilaku default.

Memang benar bahwa variabel lokal adalah jenis negara yang paling tidak berbahaya yang bisa berubah. Variabel anggota dapat menyebabkan lebih banyak masalah dan variabel statis bahkan lebih buruk. Masih saya merasa penting untuk mengekspresikan seakurat mungkin dalam kode Anda apa yang seharusnya dilakukan. Dan ada perbedaan besar antara variabel yang dapat dimodifikasi kemudian dan hanya nama untuk hasil antara. Jadi, jika bahasa Anda memungkinkan Anda mengekspresikan perbedaan ini, lakukan saja.

Frank Puffer
sumber
2
Saya tidak mengecilkan jawaban Anda, tetapi saya akan menebak bahwa itu terkait dengan fakta bahwa variabel lokal umumnya tidak dianggap 'negara' dalam bahasa imperatif kecuali Anda berbicara tentang semacam metode jangka panjang. Saya setuju pada penggunaan final / const sebagai praktik terbaik tapi itu sangat tidak mungkin bahwa memperkenalkan variabel untuk hanya memutus panggilan dirantai akan menyebabkan masalah yang disebabkan oleh keadaan bisa berubah. Bahkan, penggunaan variabel lokal membantu menangani keadaan yang bisa berubah. Jika suatu metode dapat mengembalikan nilai yang berbeda pada waktu yang berbeda, Anda dapat berakhir dengan beberapa bug yang sangat menarik.
JimmyJames
@ JimmyJames: Telah menambahkan beberapa penjelasan pada jawaban saya. Tetapi ada satu bagian dari komentar Anda yang saya tidak mengerti: "penggunaan variabel lokal membantu untuk berurusan dengan keadaan yang bisa berubah". Bisakah Anda menjelaskan ini?
Frank Puffer
1
Misalnya, katakan saya harus memeriksa nilai dan jika lebih dari 10 aktifkan peringatan. Misalkan nilai ini berasal dari metode getFoo(). Jika saya menghindari deklarasi lokal, saya akan berakhir dengan if(getFoo() > 10) alert(getFoo());Tapi getFoo () mungkin mengembalikan nilai yang berbeda pada dua panggilan yang berbeda. Saya dapat mengirimkan lansiran dengan nilai kurang dari atau sama dengan 10 yang paling membingungkan dan akan kembali kepada saya sebagai cacat. Hal semacam ini menjadi lebih penting dengan konkurensi. Tugas lokal adalah atomik.
JimmyJames
Poin yang sangat bagus. Mungkin yang alasan saya tidak suka penduduk setempat ini .... Apakah Anda akan melakukan sesuatu dengan itu PowerManagermisalnya setelah memanggil metode ini? Biarkan saya memeriksa sisa metode .... mmm ok tidak. Dan WakeLockhal ini Anda dapatkan ... apa yang Anda lakukan dengan itu (memindai sisa metode lagi) ... mmm lagi tidak ada ... ok jadi mengapa mereka ada di sana? Oh ya seharusnya lebih mudah dibaca ... tapi tanpa mereka saya yakin Anda tidak menggunakannya lagi jadi saya tidak perlu membaca sisa metode.
Stijn de Witt
Pada pembicaraan baru-baru ini, pembicara berpendapat bahwa cara terbaik untuk menunjukkan bahwa suatu variabel adalah final adalah dengan menulis metode singkat di mana jelas bahwa variabel tidak berubah . Jika finaldiperlukan pada variabel lokal dalam suatu metode, metode Anda terlalu panjang.
user949300