Ini adalah contoh yang sangat sederhana . Ini belum tentu merupakan pertanyaan khusus bahasa, dan saya meminta Anda mengabaikan banyak cara lain fungsi dapat ditulis, dan perubahan yang dapat dilakukan untuk itu. . Warna adalah jenis yang unik
string CanLeaveWithoutUmbrella()
{
if(sky.Color.Equals(Color.Blue))
{
return "Yes you can";
}
else
{
return "No you can't";
}
}
Banyak orang yang saya temui, ReSharper, dan orang ini (yang komentarnya mengingatkan saya bahwa saya sudah lama ingin menanyakan hal ini) akan merekomendasikan refactoring kode untuk menghapus else
blok meninggalkan ini:
(Saya tidak ingat apa yang dikatakan mayoritas, saya mungkin tidak menanyakan hal ini jika tidak)
string CanLeaveWithoutUmbrella()
{
if(sky.Color.Equals(Color.Blue))
{
return "Yes you can";
}
return "No you can't";
}
Pertanyaan: Apakah ada peningkatan kompleksitas yang dimasukkan dengan tidak menyertakan else
blok?
Saya mendapat kesan yang else
lebih langsung menyatakan maksud, dengan menyatakan fakta bahwa kode di kedua blok terkait langsung.
Selain itu saya menemukan bahwa saya dapat mencegah kesalahan halus dalam logika, terutama setelah modifikasi kode di kemudian hari.
Ambil variasi contoh sederhana saya ini (Mengabaikan fakta or
operator karena ini adalah contoh yang sengaja disederhanakan):
bool CanLeaveWithoutUmbrella()
{
if(sky.Color != Color.Blue)
{
return false;
}
return true;
}
Seseorang sekarang dapat menambahkan if
blok baru berdasarkan kondisi setelah contoh pertama tanpa segera mengenali dengan benar kondisi pertama menempatkan kendala pada kondisi mereka sendiri.
Jika ada else
blok, siapa pun yang menambahkan kondisi baru akan dipaksa untuk memindahkan isi else
blok (dan jika entah bagaimana mereka mengabaikannya heuristik akan menunjukkan kode tidak dapat dijangkau, yang tidak dalam kasus salah satu if
membatasi) .
Tentu saja ada cara lain contoh spesifik harus didefinisikan, yang semuanya mencegah situasi itu, tetapi itu hanya contoh.
Panjang contoh yang saya berikan dapat memiringkan aspek visual dari ini, jadi anggaplah bahwa ruang yang digunakan untuk kurung relatif tidak signifikan terhadap sisa metode.
Saya lupa menyebutkan kasus di mana saya setuju dengan penghilangan blok lain, dan ketika menggunakan if
blok untuk menerapkan kendala yang harus dipenuhi secara logis untuk semua kode berikut, seperti cek kosong (atau pengawal lainnya) .
sumber
else
klausa (sesuai selera saya, akan lebih mudah dibaca ketika meninggalkan tanda kurung yang tidak perlu. Tapi saya pikir contohnya tidak dipilih dengan baik, karena dalam kasus di atas saya akan menulisreturn sky.Color == Color.Blue
(tanpa if / else). Contoh dengan tipe pengembalian yang berbeda dari bool mungkin akan membuat ini lebih jelasJawaban:
Dalam pandangan saya, blok eksplisit lain lebih disukai. Ketika saya melihat ini:
Saya tahu bahwa saya berurusan dengan opsi yang saling eksklusif. Saya tidak perlu membaca apa yang ada di dalam blok if untuk mengetahui.
Ketika saya melihat ini:
Pada pandangan pertama, terlihat bahwa ia mengembalikan false terlepas dan memiliki efek samping opsional langit tidak biru.
Seperti yang saya lihat, struktur kode kedua tidak mencerminkan apa yang sebenarnya dilakukan oleh kode tersebut. Itu buruk. Sebaliknya, pilih opsi pertama yang mencerminkan struktur logis. Saya tidak ingin harus memeriksa kembali / istirahat / melanjutkan logika di setiap blok untuk mengetahui aliran logis.
Mengapa ada orang yang lebih suka yang lain adalah misteri bagiku, semoga seseorang akan mengambil posisi sebaliknya akan menerangi aku dengan jawaban mereka.
Saya akan mengatakan bahwa kondisi penjaga baik-baik saja jika Anda meninggalkan jalan bahagia. Telah terjadi kesalahan atau kegagalan yang mencegah eksekusi biasa dari melanjutkan. Ketika ini terjadi, Anda harus melempar pengecualian, mengembalikan kode kesalahan, atau apa pun yang sesuai untuk bahasa Anda.
Tak lama setelah versi asli dari jawaban ini, kode seperti ini ditemukan di proyek saya:
Dengan tidak memasukkan return ke dalam elses, fakta bahwa statement return tidak ada telah diabaikan. Kalau sudah dipekerjakan, kode itu bahkan tidak akan dikompilasi. (Tentu saja, kekhawatiran yang jauh lebih besar yang saya miliki adalah bahwa tes yang ditulis pada kode ini sangat buruk untuk tidak mendeteksi masalah ini.)
sumber
else
blok (itu bisa menyusahkan ketika saya terpaksa melakukannya hanya untuk tetap sejalan dengan konvensi untuk basis kode). Saya juga tertarik untuk melihat titik konter di sini.} // else
mana yang lain biasanya pergi sebagai kompromi antara keduanya.Alasan utama untuk menghapus
else
blok yang saya temukan adalah indentasi berlebih. Hubungan arus pendekelse
blok memungkinkan struktur kode yang lebih datar.Banyak
if
pernyataan pada dasarnya penjaga. Mereka mencegah dereferencing dari null pointer dan lainnya "jangan lakukan ini!" kesalahan. Dan mereka mengarah pada penghentian cepat fungsi saat ini. Sebagai contoh:Sekarang tampaknya
else
klausa akan sangat masuk akal di sini:Dan memang, jika hanya itu yang Anda lakukan, itu tidak lebih menjorok dari contoh di atas. Tapi, ini jarang semua yang Anda lakukan dengan struktur data multi-level nyata (suatu kondisi yang terjadi setiap saat ketika memproses format umum seperti JSON, HTML, dan XML). Jadi jika Anda ingin memodifikasi teks semua anak dari simpul HTML yang diberikan, ucapkan:
Para penjaga tidak meningkatkan indentasi kode. Dengan sebuah
else
klausa, semua pekerjaan aktual mulai bergerak ke kanan:Ini mulai memiliki gerakan ke kanan yang signifikan, dan ini adalah contoh yang cukup sepele, dengan hanya dua kondisi penjaga. Setiap penjaga tambahan menambahkan tingkat lekukan lain. Kode nyata yang saya tulis memproses XML atau mengonsumsi umpan JSON terperinci dapat dengan mudah menumpuk 3, 4, atau lebih banyak kondisi penjaga. Jika Anda selalu menggunakan
else
, Anda memiliki indentasi 4, 5, atau 6 level. Mungkin lebih. Dan itu pasti berkontribusi pada rasa kompleksitas kode, dan lebih banyak waktu yang dihabiskan untuk memahami apa yang sejalan dengan apa. Gaya keluar cepat, datar, dan cepat menghilangkan beberapa "struktur berlebih" itu, dan tampak lebih sederhana.Addendum Komentar jawaban ini membuat saya menyadari bahwa itu tidak mungkin jelas bahwa NULL / penanganan kosong tidak satu-satunya alasan untuk conditional penjaga. Tidak hampir! Sementara contoh sederhana ini berfokus pada NULL / penanganan kosong dan tidak mengandung alasan lain, mencari struktur dalam seperti XML dan AST untuk konten "relevan", misalnya, sering memiliki serangkaian tes khusus untuk menghilangkan node yang tidak relevan dan tidak menarik. kasus. Serangkaian tes "jika node ini tidak relevan, kembali" akan menyebabkan drift kanan yang sama dengan NULL / blank guard. Dan dalam praktiknya, tes relevansi berikutnya sering digabungkan dengan NULL / penjaga kosong untuk struktur data yang lebih dalam dicari - sebuah whammy ganda untuk pergeseran ke kanan.
sumber
else
blok berlebihan, ketika menggunakanif
blok untuk menerapkan kendala yang harus dipenuhi secara logis untuk semua kode berikut, seperti cek-nol (atau penjaga lainnya).then
klausa (seperti pernyataan penjaga berturut-turut), maka tidak ada nilai tertentu untuk menghindarielse
klausa tertentu . Memang, itu akan mengurangi kejelasan dan berpotensi berbahaya (dengan gagal hanya menyatakan struktur alternatif yang ada / seharusnya ada).Ketika saya melihat ini:
Saya melihat idiom yang umum . Pola umum , yang di kepala saya diterjemahkan menjadi:
Karena ini adalah ungkapan yang sangat umum dalam pemrograman, programmer yang terbiasa melihat kode semacam ini memiliki 'terjemahan' implisit di kepala mereka setiap kali mereka melihatnya, yang 'mengubahnya' menjadi makna yang tepat.
Saya tidak perlu yang eksplisit
else
, kepala saya 'meletakkannya di sana' untuk saya karena ia mengenali polanya secara keseluruhan . Saya mengerti arti dari keseluruhan pola umum, jadi saya tidak perlu detail kecil untuk memperjelasnya.Misalnya, baca teks berikut:
Apakah kamu membaca ini?
Jika demikian, Anda salah. Baca teks lagi. Apa yang sebenarnya ditulis adalah
Ada dua kata "the" dalam teks. Jadi mengapa Anda melewatkan salah satu dari keduanya?
Itu karena otak Anda melihat pola umum , dan segera menerjemahkannya ke maknanya yang diketahui. Itu tidak perlu membaca keseluruhan hal dengan detail untuk mengetahui artinya, karena sudah mengenali pola setelah melihatnya. Inilah sebabnya mengapa ia mengabaikan "si" tambahan .
Hal yang sama dengan idiom di atas. Programmer yang telah membaca banyak kode digunakan untuk melihat pola ini , dari
if(something) {return x;} return y;
. Mereka tidak perlu penjelasanelse
untuk memahami maknanya, karena otak mereka 'menempatkannya di sana untuk mereka'. Mereka mengenalinya sebagai pola dengan makna yang diketahui: "apa yang setelah kurung kurawal akan berjalan hanya sebagai implisitelse
dari yang sebelumnyaif
".Jadi menurut saya,
else
itu tidak perlu. Tapi gunakan saja apa yang tampaknya lebih mudah dibaca.sumber
Mereka menambahkan kekacauan visual dalam kode, jadi ya, mereka mungkin menambah kompleksitas.
Namun, kebalikannya juga benar, refactoring yang berlebihan untuk mengurangi panjang kode juga dapat menambah kompleksitas (tidak dalam kasus yang sederhana ini tentu saja).
Saya setuju dengan pernyataan bahwa
else
maksud menyatakan blok. Tetapi kesimpulan saya berbeda, karena Anda menambahkan kompleksitas dalam kode Anda untuk mencapai ini.Saya tidak setuju dengan pernyataan Anda bahwa itu memungkinkan Anda untuk mencegah kesalahan yang halus dalam logika.
Mari kita lihat contoh, sekarang seharusnya hanya mengembalikan true jika Langit adalah Biru dan ada Kelembaban tinggi, Kelembaban tidak tinggi atau jika Langit Merah. Tapi kemudian, Anda salah mengaitkan satu penyangga dan menempatkannya di salah
else
:Kami telah melihat semua kesalahan konyol dalam kode produksi ini dan bisa sangat sulit dideteksi.
Saya akan menyarankan yang berikut ini:
Saya menemukan ini lebih mudah dibaca, karena saya dapat melihat secara default
false
.Juga, gagasan memaksa untuk memindahkan isi blok untuk memasukkan klausa baru, rentan terhadap kesalahan. Ini entah bagaimana berkaitan dengan prinsip terbuka / tertutup (kode harus terbuka untuk ekstensi tetapi ditutup untuk modifikasi). Anda dipaksa untuk memodifikasi kode yang ada (mis. Koder mungkin memperkenalkan kesalahan dalam penyeimbangan kawat gigi).
Akhirnya, Anda mengarahkan orang untuk menjawab dengan cara yang telah Anda tentukan sebelumnya yang menurut Anda benar. Sebagai contoh, Anda memberikan contoh yang sangat sederhana tetapi setelah itu, Anda menyatakan bahwa orang tidak harus mempertimbangkannya. Namun, kesederhanaan contoh mempengaruhi keseluruhan pertanyaan:
Jika kasusnya sesederhana yang disajikan, maka jawaban saya adalah menghilangkan
if else
klausa sama sekali.return (sky.Color == Color.Blue);
Jika kasusnya sedikit lebih rumit, dengan berbagai klausa, saya akan menjawab:
bool CanLeaveWithoutUmbrella () {
}
Jika kasusnya rumit dan tidak semua klausa mengembalikan true (mungkin mereka mengembalikan dua kali lipat), dan saya ingin memperkenalkan beberapa perintah breakpoint atau loggin, saya akan mempertimbangkan sesuatu seperti:
}
Jika kita tidak berbicara tentang metode yang mengembalikan sesuatu, melainkan blok if-else yang menetapkan beberapa variabel atau memanggil metode, maka ya, saya akan menyertakan
else
klausa akhir .Oleh karena itu, kesederhanaan contoh juga merupakan faktor yang perlu dipertimbangkan.
sumber
Meskipun kasus if-else yang dideskripsikan memiliki kompleksitas yang lebih besar, dalam sebagian besar (tetapi tidak semua) situasi praktis tidak masalah banyak.
Bertahun-tahun yang lalu ketika saya mengerjakan perangkat lunak yang digunakan untuk industri penerbangan (harus melalui proses sertifikasi), pertanyaan Anda muncul. Ternyata ada biaya keuangan untuk pernyataan 'lain' itu karena menambah kompleksitas kode.
Inilah sebabnya.
Kehadiran 'orang lain' menciptakan kasus ke-3 implisit yang harus dievaluasi - bahwa tidak ada 'jika' maupun 'orang lain' diambil. Anda mungkin berpikir (seperti saya saat itu) WTF?
Penjelasannya seperti ini ...
Dari sudut pandang logis, hanya ada dua opsi - 'jika' dan 'lain'. Namun, yang kami sertifikasi adalah file objek yang dihasilkan oleh kompiler. Oleh karena itu, ketika ada 'yang lain', analisis harus dilakukan untuk mengkonfirmasi bahwa kode percabangan yang dihasilkan sudah benar dan bahwa jalur ke-3 yang misterius tidak muncul.
Bandingkan ini dengan kasus di mana hanya ada 'jika' dan tidak ada 'yang lain'. Dalam hal ini, hanya ada dua opsi - jalur 'jika' dan jalur 'non-jika'. Dua kasus untuk dievaluasi kurang kompleks dari tiga.
Semoga ini membantu.
sumber
Tujuan kode yang paling penting adalah agar dapat dimengerti sebagai komitmen (bukan kebalikan dari refactored yang mudah, yang bermanfaat tetapi kurang penting). Contoh Python yang sedikit lebih kompleks dapat digunakan untuk menggambarkan ini:
Ini cukup jelas - ini setara dengan
case
pencarian pernyataan atau kamus, versi tingkat yang lebih tinggi darireturn foo == bar
:Ini lebih jelas, karena meskipun jumlah token lebih tinggi (32 vs 24 untuk kode asli dengan dua pasangan kunci / nilai), semantik fungsi sekarang eksplisit: Ini hanya pencarian.
(Ini memiliki konsekuensi untuk refactoring - jika Anda ingin memiliki efek samping jika
key == NIK
, Anda memiliki tiga pilihan:if
/elif
/else
dan masukkan satu baris kekey == NIK
case.if
pernyataanvalue
untuk kasus khusus sebelum kembali.if
pernyataan di pemanggil.Sekarang kita melihat mengapa fungsi pencarian adalah penyederhanaan yang kuat: Ini membuat opsi ketiga jelas solusi paling sederhana, karena selain menghasilkan perbedaan yang lebih kecil dari opsi pertama, itu adalah satu-satunya yang memastikan bahwa
value
hanya melakukan satu hal. )Kembali ke kode OP, saya pikir ini dapat berfungsi sebagai panduan untuk kompleksitas
else
pernyataan: Kode denganelse
pernyataan eksplisit secara obyektif lebih kompleks, tetapi yang lebih penting adalah apakah itu membuat semantik kode menjadi jelas dan sederhana. Dan itu harus dijawab berdasarkan kasus per kasus, karena setiap bagian kode memiliki arti yang berbeda.sumber
case
atauswitch
pernyataan) kurang homogen. Beberapa opsi hanyalah pengembalian nilai langsung, tetapi kemudian satu atau dua kasing memerlukan pemrosesan ekstra. Dan ketika Anda menemukan strategi pencarian tidak sesuai, Anda perlu menulis ulang dalamif
elif
...else
sintaks yang sama sekali berbeda .Saya pikir itu tergantung pada
if
pernyataan apa yang Anda gunakan. Beberapaif
pernyataan dapat dilihat sebagai ekspresi, dan yang lainnya hanya dapat dilihat sebagai pernyataan aliran kontrol.Contoh Anda terlihat seperti ungkapan bagi saya. Dalam bahasa mirip-C, operator ternary
?:
sangat mirip denganif
pernyataan, tetapi merupakan ekspresi, dan bagian lainnya tidak dapat dihilangkan. Masuk akal bahwa cabang lain tidak dapat dihilangkan dalam ekspresi, karena ekspresi harus selalu memiliki nilai.Menggunakan operator ternary, contoh Anda akan terlihat seperti ini:
Karena ini adalah ekspresi boolean, itu benar-benar harus disederhanakan sampai selesai
Termasuk klausul eksplisit lain membuat maksud Anda lebih jelas. Penjaga bisa masuk akal dalam beberapa situasi, tetapi dalam memilih antara dua nilai yang mungkin, yang keduanya tidak luar biasa atau tidak biasa, mereka tidak membantu.
sumber
I ask that you ignore the many other ways the function can be written, and changes that can be made to it. (I know most people are itching to write return sky.Color == Color.Blue.)
Satu hal lain untuk dipikirkan dalam argumen ini adalah kebiasaan yang dipromosikan oleh setiap pendekatan.
jika / lain membingkai ulang sampel pengkodean dalam hal cabang. Seperti yang Anda katakan, terkadang kesaksian ini bagus. Sebenarnya ada dua jalur eksekusi yang mungkin dan kami ingin menyoroti itu.
Dalam kasus lain, hanya ada satu jalur eksekusi dan kemudian semua hal luar biasa yang harus dikhawatirkan oleh programmer. Seperti yang Anda sebutkan, klausa penjaga sangat bagus untuk ini.
Ada, tentu saja, 3 kasus atau lebih (n), di mana kami biasanya mendorong meninggalkan rantai if / else dan menggunakan pernyataan case / switch atau polimorfisme.
Prinsip panduan yang saya ingat di sini adalah bahwa metode atau fungsi seharusnya hanya memiliki satu tujuan. Kode apa pun dengan pernyataan if / else atau switch hanya untuk percabangan. Jadi harus pendek kepalang (4 baris) dan hanya mendelegasikan ke metode yang benar atau menghasilkan hasil yang jelas (seperti contoh Anda). Ketika kode Anda sesingkat itu, sulit untuk melewatkan beberapa pengembalian :) Seperti halnya "dianggap berbahaya", pernyataan percabangan apa pun dapat disalahgunakan, sehingga memasukkan beberapa pemikiran kritis ke dalam pernyataan lain biasanya sepadan. Seperti yang Anda sebutkan, hanya memiliki blok lain menyediakan tempat bagi kode untuk menggumpal. Anda dan tim Anda harus memutuskan bagaimana perasaan Anda tentang hal itu.
Apa yang benar-benar dikeluhkan oleh alat ini adalah kenyataan bahwa Anda memiliki return / break / throw di dalam blok if. Jadi sejauh menyangkut, Anda menulis klausa penjaga tetapi mengacaukannya. Anda dapat memilih untuk membuat alat ini bahagia atau Anda dapat "menghibur" sarannya tanpa menerimanya.
sumber
else
semantik, alat analisis kode biasanya mencari instruksi yang asing karena mereka sering menyoroti kesalahpahaman aliran kontrol. Theelse
setelahif
itu kembali terbuang bit.if(1 == 1)
sering memicu jenis peringatan yang sama.Saya pikir jawabannya tergantung. Sampel kode Anda (seperti yang Anda tunjukkan secara tidak langsung) hanyalah mengembalikan evaluasi suatu kondisi, dan paling baik disajikan seperti yang Anda ketahui, sebagai satu ekspresi.
Untuk menentukan apakah menambahkan kondisi lain mengklarifikasi atau mengaburkan kode, Anda perlu menentukan apa yang diwakili IF / ELSE. Apakah ini sebuah (seperti dalam contoh Anda) sebuah ekspresi? Jika demikian, ungkapan itu harus diekstraksi dan digunakan. Apakah ini kondisi penjaga? Jika demikian, maka ELSE tidak perlu dan menyesatkan, karena membuat kedua cabang tampak setara. Apakah ini contoh polimorfisme prosedural? Ekstrak itu. Apakah pengaturan prasyarat? Maka itu bisa sangat penting.
Sebelum Anda memutuskan untuk memasukkan atau menghilangkan ELSE, tentukan apa yang diwakilinya, yang akan memberi tahu Anda apakah itu harus ada atau tidak.
sumber
Jawabannya agak subyektif. Sebuah
else
blok dapat membantu pembacaan dengan mendirikan bahwa satu blok dari mengeksekusi kode secara eksklusif untuk blok lain kode, tanpa perlu membaca kedua blok. Ini bisa membantu jika, katakanlah, kedua blok relatif panjang. Ada beberapa kasus, meskipun di mana memilikiif
tanpaelse
dapat lebih mudah dibaca. Bandingkan kode berikut dengan sejumlahif/else
blok:dengan:
Blok kode kedua mengubah
if
pernyataan bersarang menjadi klausa penjaga. Ini mengurangi lekukan, dan membuat beberapa kondisi pengembalian lebih jelas ("jikaa != b
, maka kami kembali0
!")Telah ditunjukkan dalam komentar bahwa mungkin ada beberapa lubang dalam contoh saya, jadi saya akan menyempurnakannya sedikit lagi.
Kita bisa menulis blok kode pertama di sini seperti agar lebih mudah dibaca:
Kode ini setara dengan kedua blok di atas, tetapi menyajikan beberapa tantangan. The
else
klausul disini menghubungkan ini jika pernyataan bersama-sama. Dalam versi klausa penjaga di atas, klausa penjaga independen satu sama lain. Menambahkan yang baru berarti hanya menulis yang baruif
antara yang terakhirif
dan sisa dari logika. Di sini, itu juga bisa dilakukan, dengan hanya sedikit beban kognitif yang lebih sedikit. Perbedaannya adalah ketika beberapa logika tambahan perlu terjadi sebelum klausa penjaga baru itu. Ketika pernyataan independen, kita bisa melakukan:Dengan
if/else
rantai yang terhubung , ini tidak mudah dilakukan. Faktanya, jalur termudah untuk dilakukan adalah dengan memutus rantai agar lebih mirip versi klausa penjaga.Tapi sungguh, ini masuk akal. Menggunakan
if/else
lemah menyiratkan hubungan antara bagian-bagian. Kita bisa menduga itua != b
ada hubungannyac > d
dalamif/else
versi dirantai. Anggapan itu akan menyesatkan, seperti yang bisa kita lihat dari versi klausa penjaga bahwa mereka, pada kenyataannya, tidak berhubungan. Itu berarti bahwa kita dapat melakukan lebih banyak dengan klausa independen, seperti mengatur ulang mereka (mungkin untuk mengoptimalkan kinerja permintaan atau untuk meningkatkan aliran logis). Kita juga bisa mengabaikan mereka secara kognitif begitu kita melewati mereka. Dalam sebuahif/else
rantai, saya kurang yakin bahwa hubungan kesetaraan antaraa
danb
tidak akan muncul kembali nanti.Hubungan yang tersirat dengan
else
juga terlihat dalam kode contoh yang sangat bersarang, tetapi dengan cara yang berbeda. Theelse
pernyataan dipisahkan dari bersyarat mereka melekat, dan mereka yang terkait dalam terbalik Agar conditional (yang pertamaelse
melekat terakhirif
, terakhirelse
melekat pertamaif
). Ini menciptakan disonansi kognitif di mana kita harus menelusuri kembali kode, mencoba untuk meluruskan indentasi dalam otak kita. Ini seperti mencoba untuk mencocokkan sekelompok kurung. Bahkan menjadi lebih buruk jika lekukan salah. Kawat gigi opsional juga tidak membantu.Ini adalah konsesi yang bagus, tetapi benar-benar tidak membatalkan jawaban apa pun. Saya bisa mengatakan itu dalam contoh kode Anda:
interpretasi yang valid untuk menulis kode seperti ini adalah bahwa "kita hanya harus pergi dengan payung jika langit tidak biru." Di sini ada batasan bahwa langit harus biru agar kode berikut valid untuk dijalankan. Saya telah memenuhi definisi konsesi Anda.
Bagaimana jika saya mengatakan bahwa jika warna langit hitam, itu adalah malam yang cerah, jadi tidak perlu payung. (Ada cara yang lebih sederhana untuk menulis ini, tetapi ada cara yang lebih sederhana untuk menulis seluruh contoh.)
Seperti pada contoh yang lebih besar di atas, saya bisa menambahkan klausa baru tanpa banyak pemikiran yang diperlukan. Dalam sebuah
if/else
, saya tidak bisa begitu yakin saya tidak akan mengacaukan sesuatu, terutama jika logikanya lebih rumit.Saya juga akan menunjukkan bahwa contoh sederhana Anda juga tidak begitu sederhana. Tes untuk nilai non-biner tidak sama dengan kebalikan dari tes itu dengan hasil terbalik.
sumber
else
blok sangat penting untuk keterbacaan.Anda terlalu menyederhanakan contoh Anda. Salah satu alternatif mungkin lebih mudah dibaca, tergantung pada situasi yang lebih besar: khususnya, itu tergantung pada apakah salah satu dari dua cabang kondisi tersebut tidak normal . Biarkan saya menunjukkan kepada Anda: dalam kasus di mana salah satu cabang sama-sama mungkin, ...
... lebih mudah dibaca daripada ...
... karena pameran pertama struktur paralel dan yang kedua tidak. Tetapi, ketika sebagian besar fungsi dikhususkan untuk satu tugas dan Anda hanya perlu memeriksa beberapa prasyarat terlebih dahulu, ...
}
... lebih mudah dibaca daripada ...
... karena dengan sengaja tidak membuat struktur paralel memberikan petunjuk bagi pembaca masa depan bahwa mendapatkan input yang "benar-benar tipe dua" di sini adalah tidak normal . (Dalam kehidupan nyata,
ProcessInputDefinitelyOfTypeOne
tidak akan menjadi fungsi yang terpisah, jadi perbedaannya akan lebih mencolok.)sumber
if
-> Lakukan yang luar biasa dan tinggalkan« sebagai strategi pengembalian-awal . Pikirkan kode, yang standarnya mencakup lebih banyak pemeriksaan, akan lebih cepat menangani kasus luar biasa terlebih dahulu.when using an if block to apply a constraint that must be logically satisfied for all following code, such as a null-check (or any other guards)
. Secara logis, pekerjaan apaProcessInputOfTypeOne
pun tergantung pada fakta itu!InputIsReallyTypeTwo(input)
, jadi kita perlu menangkapnya di luar pemrosesan normal kita. BiasanyaProcessInputOfTypeTwo(input);
akan benar-benar menjadithrow ICan'tProccessThatException
yang akan membuat kesamaan lebih jelas.u+
" biasanya memperkenalkan token "unicode-range", tetapi jika karakter berikutnya bukan hex digit, maka orang perlu membuat cadangan dan memproses 'u' sebagai pengidentifikasi. Jadi loop pemindai utama mengirimkan untuk "memindai token jangkauan-unicode" agak tidak tepat, dan itu dimulai dengan "... jika kita berada dalam kasus khusus yang tidak biasa ini, buat cadangan, lalu panggil subroutine pemindaian dan pengidentifikasi sebagai gantinya."ProcessInputOfTypeOne
menggunakan pemeriksaan tidak tepat tapi cepat yang kadang-kadang menangkap tipe dua sebagai gantinya.Ya, ada peningkatan dalam kompleksitas karena klausa lain berlebihan . Oleh karena itu lebih baik meninggalkan kode agar tetap ramping dan berarti. Itu pada akor yang sama dengan menghilangkan
this
kualifikasi yang berlebihan (Java, C ++, C #) dan menghilangkan tanda kurung direturn
pernyataan, dan sebagainya.Seorang programmer yang baik berpikir "apa yang bisa saya tambahkan?" sementara programmer yang hebat berpikir "apa yang bisa saya hapus?".
sumber
else
blok, jika dijelaskan dalam satu-liner (yang tidak sering) sering dengan alasan semacam ini, jadi +1 untuk menyajikan argumen "default" yang saya lihat, tapi saya tidak merasa itu alasan yang cukup kuat.A good programmer things "what can I add?" while a great programmer things "what can I remove?".
tampaknya menjadi pepatah umum bahwa banyak orang melakukan overextend tanpa pertimbangan yang matang, dan saya pribadi menemukan ini sebagai salah satu contohnya.Saya perhatikan, mengubah pikiran saya pada kasus ini.
Ketika ditanya pertanyaan ini sekitar setahun yang lalu, saya akan menjawab sesuatu seperti:
»Seharusnya hanya ada satu
entry
dan satuexit
ke metode« Dan dengan mengingat hal ini, saya akan menyarankan untuk refactor kode ke:Dari sudut pandang komunikasi , jelas , apa yang harus dilakukan.
If
sesuatu terjadi, memanipulasi hasilnya dengan satu cara ,else
memanipulasi dengan cara lain .Tapi ini melibatkan yang tidak perlu
else
. Yangelse
mengekspresikan case default . Jadi pada langkah kedua, saya bisa refactorKemudian muncul pertanyaan: Mengapa menggunakan variabel sementara? Langkah refactorisasi selanjutnya mengarah ke:
Jadi ini jelas dalam apa fungsinya. Saya bahkan akan melangkah lebih jauh:
Atau untuk yang lemah hati :
Anda bisa membacanya seperti itu: »CanLeaveWithoutUmbrella mengembalikan bool . Jika tidak ada yang istimewa terjadi, ia mengembalikan false «Ini adalah bacaan pertama, dari atas ke bawah.
Dan kemudian Anda "mem-parsing" kondisinya »Jika kondisinya terpenuhi, ia mengembalikan true « Anda benar-benar dapat melewatkan kondisional dan telah memahami, apa fungsi ini dalam huruf default . Mata dan pikiran Anda hanya perlu membaca beberapa huruf di sisi kiri, tanpa membaca bagian di sebelah kanan.
Ya itu benar. Tetapi informasi itu berlebihan . Anda memiliki case default dan satu "exception" yang dicakup oleh
if
-statement.Ketika berhadapan dengan struktur yang lebih kompleks, saya akan memilih strategi lain, menghilangkan
if
atau itu saudara jelekswitch
.sumber
So this is clear in what it does...
dan mengembangkannya? (Kasus-kasus sebelumnya juga relevan dipertanyakan). Saya mengatakan ini karena pertanyaannya adalah pertanyaan yang kami periksa. Anda telah menyatakan kuda-kuda Anda, menghilangkan balok orang lain, dan sebenarnya kuda-kuda itu yang membutuhkan penjelasan lebih lanjut (dan orang yang membuat saya mengajukan pertanyaan ini). Dari pertanyaan:I ask that you ignore the many other ways the function can be written, and changes that can be made to it. (I know most people are itching to write return sky.Color == Color.Blue.)
Singkatnya, dalam hal ini, menyingkirkan
else
kata kunci adalah hal yang baik. Ini benar-benar berlebihan di sini, dan tergantung pada bagaimana Anda memformat kode Anda, itu akan menambahkan satu hingga tiga baris yang sama sekali tidak berguna untuk kode Anda. Pertimbangkan apa yang ada diif
blok:Oleh karena itu, jika
if
blok dimasukkan ke dalam, seluruh fungsi, secara definisi, tidak dieksekusi. Tetapi jika tidak dimasukkan ke dalam, karena tidak adaif
pernyataan lebih lanjut , seluruh fungsi dijalankan. Akan sangat berbeda jikareturn
pernyataan tidak ada dalamif
blok, dalam hal ini ada atau tidak adanyaelse
blok akan berdampak, tetapi di sini, itu tidak akan berdampak.Dalam pertanyaan Anda, setelah membalikkan
if
kondisi Anda dan menghilangkanelse
, Anda menyatakan yang berikut:Mereka perlu membaca kode sedikit lebih dekat. Kami menggunakan bahasa tingkat tinggi dan
else
pengaturan kode yang jelas untuk mengurangi masalah ini, tetapi menambahkan blok yang sepenuhnya berlebihan menambah "noise" dan "clutter" ke kode, dan kami tidak harus membalikkan atau membalikkanif
kondisi kami juga. Jika mereka tidak dapat membedakannya, maka mereka tidak tahu apa yang mereka lakukan. Jika mereka dapat membedakannya, maka mereka selalu dapat membalikkanif
kondisi aslinya sendiri.Pada dasarnya itulah yang terjadi di sini. Anda kembali dari
if
blok, sehinggaif
penilaian kondisifalse
merupakan kendala yang harus dipenuhi secara logis untuk semua kode berikut.Tidak, ini akan merupakan penurunan kompleksitas dalam kode Anda, dan bahkan mungkin merupakan penurunan dalam kode yang dikompilasi, tergantung pada apakah optimasi super sepele tertentu akan atau tidak akan terjadi.
sumber
Dalam contoh spesifik yang Anda berikan, ya.
Saya pikir ini tidak bisa lebih sederhana dari ini:
sumber
if
pernyataan. Sebenarnya saya secara eksplisit mencegah penyederhanaan lebih lanjut menggunakan kode persis yang Anda gunakan. Selain itu kompleksitas siklomatik tidak meningkat olehelse
blok.Saya selalu berusaha menulis kode saya sehingga tujuannya sejelas mungkin. Contoh Anda kurang konteks, jadi saya akan sedikit memodifikasinya:
Niat kami tampaknya agar kami bisa pergi tanpa payung saat Langit Biru. Namun, niat sederhana itu hilang dalam lautan kode. Ada beberapa cara yang bisa kita lakukan untuk membuatnya lebih mudah dipahami.
Pertama, ada pertanyaan Anda tentang
else
cabang. Saya juga tidak keberatan, tetapi cenderung mengabaikanelse
. Saya memahami argumen tentang menjadi eksplisit, tetapi pendapat saya adalah bahwaif
pernyataan harus membungkus cabang 'opsional', seperti yangreturn true
ada. Saya tidak akan menyebutreturn false
cabang 'opsional', karena bertindak sebagai default kami. Bagaimanapun, saya melihat ini sebagai masalah yang sangat kecil, dan jauh lebih penting daripada yang berikut:Masalah yang jauh lebih penting adalah bahwa cabang Anda melakukan terlalu banyak! Cabang, seperti segalanya, harus 'sesederhana mungkin, tetapi tidak lebih'. Dalam hal ini Anda telah menggunakan
if
pernyataan, yang bercabang di antara blok kode (koleksi pernyataan) ketika semua yang Anda butuhkan untuk bercabang di antaranya adalah ekspresi (nilai). Ini jelas karena a) blok kode Anda hanya berisi pernyataan tunggal dan b) mereka adalah pernyataan yang sama (return
). Kita dapat menggunakan operator ternary?:
untuk mempersempit cabang hanya ke bagian yang berbeda:Sekarang kita mencapai redundansi yang jelas bahwa hasil kita identik dengan
this.color == Color.Blue
. Saya tahu pertanyaan Anda meminta kami untuk mengabaikan ini, tetapi saya pikir sangat penting untuk menunjukkan bahwa ini adalah cara berpikir prosedural tingkat pertama: Anda meruntuhkan nilai input dan membangun beberapa nilai output. Tidak apa-apa, tetapi jika mungkin jauh lebih kuat untuk berpikir dalam hal hubungan atau transformasi antara input dan output. Dalam hal ini hubungannya jelas bahwa mereka sama, tetapi saya sering melihat kode prosedural yang berbelit-belit seperti ini, yang mengaburkan beberapa hubungan sederhana. Mari kita lanjutkan dan buat penyederhanaan ini:Hal berikutnya yang akan saya tunjukkan adalah bahwa API Anda mengandung double-negative: mungkin
CanLeaveWithoutUmbrella
sajafalse
. Ini, tentu saja, menyederhanakanNeedUmbrella
menjaditrue
, jadi mari kita lakukan itu:Sekarang kita dapat mulai berpikir tentang gaya pengkodean Anda. Sepertinya Anda menggunakan bahasa Berorientasi Objek, tetapi dengan menggunakan
if
pernyataan untuk bercabang di antara blok kode, Anda akhirnya menulis prosedural kode .Dalam kode Berorientasi Objek, semua blok kode adalah metode dan semua percabangan dilakukan melalui pengiriman dinamis , misalnya. menggunakan kelas atau prototipe. Dapat diperdebatkan apakah hal itu membuat segalanya lebih sederhana, tetapi seharusnya membuat kode Anda lebih konsisten dengan bagian bahasa lainnya:
Perhatikan bahwa menggunakan operator ternary untuk bercabang di antara ekspresi adalah hal biasa dalam pemrograman fungsional .
sumber
I ask that you ignore the many other ways the function can be written, and changes that can be made to it. (I know most people are itching to write return sky.Color == Color.Blue.)
. Sebenarnya Anda menggunakan baris kode yang tepat yang saya sebutkan. Selain itu, sementara bagian dari pertanyaan ini di luar topik, saya katakan Anda terlalu jauh dalam kesimpulan. Anda telah mengubah secara radikal apa kode itu.return false;
vselse { return false; }
sementara tidak peduli dengan polaritas cabang, pengiriman dinamis, ternaries, dll. Jika Anda menulis kode prosedural dalam bahasa OO, perubahan radikal diperlukan;)if/else
pernyataan, dan apa polaritas cabang.