Jadi saya sudah pemrograman selama beberapa tahun sekarang dan baru-baru ini sudah mulai menggunakan ReSharper lebih banyak. Satu hal yang selalu disarankan ReSharper kepada saya adalah "membalikkan 'jika' pernyataan untuk mengurangi bersarang".
Katakanlah saya memiliki kode ini:
foreach (someObject in someObjectList)
{
if(someObject != null)
{
someOtherObject = someObject.SomeProperty;
}
}
Dan ReSharper akan menyarankan agar saya melakukan ini:
foreach (someObject in someObjectList)
{
if(someObject == null) continue;
someOtherObject = someObject.SomeProperty;
}
Tampaknya ReSharper akan SELALU menyarankan agar saya membalikkan IF, tidak peduli berapa banyak sarang yang terjadi. Masalah ini adalah saya agak suka bersarang di setidaknya beberapa situasi. Bagi saya sepertinya lebih mudah untuk membaca dan mencari tahu apa yang sedang terjadi di tempat-tempat tertentu. Ini tidak selalu terjadi, tapi kadang-kadang saya merasa lebih nyaman bersarang.
Pertanyaan saya adalah: selain preferensi pribadi atau keterbacaan, apakah ada alasan untuk mengurangi bersarang? Apakah ada perbedaan kinerja atau hal lain yang mungkin tidak saya sadari?
sumber
Jawaban:
Tergantung. Dalam contoh Anda memiliki pernyataan non-terbalik
if
bukan masalah, karena tubuhif
sangat pendek. Namun Anda biasanya ingin membalikkan pernyataan ketika tubuh tumbuh.Kita hanya manusia dan menyimpan banyak hal sekaligus di kepala kita adalah hal yang sulit.
Ketika tubuh pernyataan besar, membalikkan pernyataan tidak hanya mengurangi bersarang tetapi juga memberitahu pengembang mereka bisa melupakan segala sesuatu di atas pernyataan itu dan hanya fokus pada sisanya. Anda sangat mungkin menggunakan pernyataan terbalik untuk menyingkirkan nilai yang salah sesegera mungkin. Setelah Anda tahu bahwa mereka keluar dari permainan, satu-satunya hal yang tersisa adalah nilai-nilai yang sebenarnya dapat diproses.
sumber
break
,continue
dan banyakreturn
yang tidak terstruktur.break
/continue
/return
memiliki keunggulan nyata atas satuelse
blok. Dengan keluar awal, ada 2 blok : blok keluar dan tinggal di sana; denganelse
ada 3 blok : jika, yang lain, dan apa pun yang datang setelah (yang digunakan apa pun yang diambil cabang). Saya lebih suka memiliki blok yang lebih sedikit.Jangan menghindari negatif. Manusia menghisap seperti mengurai mereka bahkan ketika CPU mencintai mereka.
Namun, hargailah idiom. Kita manusia adalah makhluk kebiasaan, jadi kita lebih suka jalur yang dipakai dengan baik ke jalur langsung yang penuh dengan gulma.
foo != null
sayangnya, telah menjadi idiom. Saya hampir tidak melihat bagian yang terpisah lagi. Saya melihat itu dan hanya berpikir, "oh, aman untuk disingkirkan darifoo
sekarang".Jika Anda ingin membatalkannya (oh, suatu hari, silakan), Anda memerlukan case yang sangat kuat. Anda membutuhkan sesuatu yang akan membuat mata saya dengan mudah lepas darinya dan memahaminya dalam sekejap.
Namun, apa yang Anda berikan kepada kami adalah ini:
Yang secara struktural bahkan tidak sama!
Itu tidak melakukan apa yang diharapkan oleh otak malas saya. Saya pikir saya bisa terus menambahkan kode independen tetapi saya tidak bisa. Ini membuat saya berpikir tentang hal-hal yang tidak ingin saya pikirkan sekarang. Anda mematahkan idiom saya tetapi tidak memberi saya yang lebih baik. Semua karena Anda ingin melindungi saya dari satu hal negatif yang telah membakar diri kecil yang jahat itu ke dalam jiwa saya.
Maaf, mungkin ReSharper benar untuk menyarankan ini 90% dari waktu tetapi dalam cek nol saya pikir Anda telah menemukan kasus sudut di mana itu sebaiknya diabaikan. Alat tidak pandai mengajarkan Anda apa kode yang dapat dibaca. Tanya manusia. Lakukan peer review. Tapi jangan membabi buta mengikuti alat.
sumber
if (foo != null){ foo.something() }
saya dapat terus menambahkan kode tanpa peduli apakahfoo
itu nol. Ini tidak. Sekalipun saya tidak perlu melakukan itu sekarang, saya tidak merasa termotivasi untuk mengacaukan masa depan dengan mengatakan, "Yah, mereka bisa memperbaiki itu jika mereka membutuhkannya". Feh. Perangkat lunak hanya lunak jika mudah diubah.Argumen lama tentang apakah istirahat lebih buruk dari bersarang.
Orang-orang tampaknya menerima pengembalian awal untuk pemeriksaan parameter, tetapi itu disukai sebagian besar metode.
Secara pribadi saya menghindari melanjutkan, istirahat, kebagian dll bahkan jika itu berarti lebih bersarang. Tetapi dalam kebanyakan kasus Anda dapat menghindari keduanya.
Jelas bersarang memang membuat hal-hal sulit untuk diikuti ketika Anda memiliki banyak lapisan
Yang terburuk adalah ketika Anda memiliki keduanya
sumber
foreach (subObject in someObjectList.where(i=>i != null))
Tidak tahu mengapa saya tidak pernah memikirkan hal seperti itu.Masalah dengan
continue
adalah bahwa jika Anda menambahkan lebih banyak baris ke kode logika menjadi rumit dan cenderung mengandung bug. misalnyaApakah Anda ingin memanggil
doSomeOtherFunction()
untuk semua someObject, atau hanya jika non-null? Dengan kode asli Anda memiliki opsi dan lebih jelas. Dengan yangcontinue
satu mungkin lupa "oh, ya, di sana kita melewatkan nol" dan Anda bahkan tidak memiliki pilihan untuk memanggilnya untuk semua beberapa proyek, kecuali Anda menempatkan panggilan itu pada awal metode yang mungkin tidak mungkin atau tidak benar karena alasan lain.Ya, banyak bersarang jelek dan mungkin membingungkan, tetapi dalam hal ini saya akan menggunakan gaya tradisional.
Pertanyaan bonus: Mengapa ada nol dalam daftar itu untuk memulai? Mungkin lebih baik untuk tidak pernah menambahkan nol di tempat pertama, dalam hal ini logika pemrosesan jauh lebih sederhana.
sumber
return
sebab mereka membentuk "istirahat bersih", tetapi IMObreak
dancontinue
menyebabkan kebingungan dan, dalam kebanyakan kasus, sebaiknya dihindari.Idenya adalah kembalinya awal. Awal
return
dalam satu lingkaran menjadi awalcontinue
.Banyak jawaban bagus untuk pertanyaan ini: Haruskah saya kembali dari suatu fungsi lebih awal atau menggunakan pernyataan if?
Perhatikan bahwa sementara pertanyaan ditutup berdasarkan opini, 430+ suara mendukung pengembalian awal, ~ 50 suara "tergantung", dan 8 menentang pengembalian awal. Jadi ada konsensus yang sangat kuat (baik itu, atau saya buruk dalam menghitung, yang masuk akal).
Secara pribadi, jika tubuh loop akan menjadi subjek awal terus dan cukup lama untuk itu menjadi masalah (3-4 baris), saya cenderung untuk mengekstrak tubuh loop ke dalam fungsi di mana saya menggunakan pengembalian awal, bukan awal melanjutkan.
sumber
Teknik ini berguna untuk mensertifikasi pra-kondisi ketika sebagian besar metode Anda terjadi ketika kondisi tersebut terpenuhi.
Kami sering membalikkan
ifs
pekerjaan saya dan menggunakan hantu lain. Dulu cukup sering bahwa ketika meninjau PR saya bisa menunjukkan bagaimana rekan saya dapat menghilangkan tiga tingkat bersarang! Itu terjadi lebih jarang karena kita melakukan ifs.Berikut adalah contoh mainan dari sesuatu yang dapat diluncurkan
Kode seperti ini, di mana ada SATU kasus menarik (di mana sisanya hanya mengembalikan atau blok pernyataan kecil) adalah umum. Sepele untuk menulis ulang di atas sebagai
Di sini, kode signifikan kami, 10 baris yang tidak termasuk, bukan indentasi tiga fungsi. Jika Anda memiliki gaya pertama, Anda tergoda untuk mengubah blok panjang menjadi metode atau mentolerir indentasi. Di sinilah penghematan masuk. Di satu tempat ini adalah penghematan sepele tetapi di banyak metode di banyak kelas, Anda menghemat kebutuhan untuk menghasilkan fungsi tambahan untuk membuat kode lebih bersih dan Anda tidak memiliki banyak tingkat multi yang mengerikan lekukan .
Menanggapi contoh kode OP, saya setuju bahwa itu adalah keruntuhan berlebihan. Terutama karena di 1TB, gaya yang saya gunakan, inversi menyebabkan kode bertambah besar.
sumber
Saran Resharpers seringkali bermanfaat tetapi harus selalu dievaluasi secara kritis. Ia mencari beberapa pola kode yang telah ditentukan sebelumnya dan menyarankan transformasi, tetapi tidak dapat memperhitungkan semua faktor yang membuat kode lebih atau kurang dapat dibaca oleh manusia.
Semua hal lain dianggap sama, lebih sedikit bersarang lebih disukai, itulah sebabnya ReSharper akan menyarankan transformasi yang mengurangi bersarang. Tetapi semua hal lain tidak sama: Dalam hal ini transformasi membutuhkan pengenalan a
continue
, yang berarti kode yang dihasilkan sebenarnya lebih sulit untuk diikuti.Dalam beberapa kasus, bertukar tingkat bersarang dengan yang memang
continue
bisa menjadi perbaikan, tetapi ini tergantung pada semantik kode yang dimaksud, yang berada di luar pemahaman aturan mekanik ReSharpers.Dalam kasus Anda, saran ReSharper akan membuat kode lebih buruk. Jadi abaikan saja. Atau lebih baik: Jangan gunakan transformasi yang disarankan, tetapi berikan sedikit pemikiran tentang bagaimana kode dapat ditingkatkan. Perhatikan bahwa Anda mungkin menugaskan variabel yang sama beberapa kali, tetapi hanya penugasan terakhir yang berpengaruh, karena yang sebelumnya hanya akan ditimpa. Ini memang terlihat seperti bug. Saran ReSharpers tidak memperbaiki bug, tetapi itu membuatnya sedikit lebih jelas bahwa beberapa logika yang meragukan sedang terjadi.
sumber
Saya pikir poin yang lebih besar di sini adalah bahwa tujuan dari loop menentukan cara terbaik untuk mengatur aliran dalam loop. Jika Anda memfilter beberapa elemen sebelum Anda mengulang sisanya, maka
continue
keluar lebih awal masuk akal. Namun, jika Anda melakukan berbagai jenis pemrosesan dalam satu lingkaran, mungkin lebih masuk akal untuk membuatnyaif
sangat jelas, seperti:Perhatikan bahwa di Java Streaming atau idiom fungsional lainnya, Anda dapat memisahkan pemfilteran dari pengulangan, dengan menggunakan:
Kebetulan, ini adalah salah satu hal yang saya sukai dari Perl terbalik jika (
unless
) diterapkan pada pernyataan tunggal, yang memungkinkan jenis kode berikut, yang menurut saya sangat mudah dibaca:sumber