Saya sering mendapatkan posisi dalam kode saya di mana saya menemukan diri saya memeriksa kondisi tertentu berulang-ulang.
Saya ingin memberi Anda contoh kecil: misalkan ada file teks yang berisi baris yang dimulai dengan "a", baris yang dimulai dengan "b" dan baris lainnya dan saya sebenarnya hanya ingin bekerja dengan dua jenis baris pertama. Kode saya akan terlihat seperti ini (menggunakan python, tetapi membacanya sebagai pseudocode):
# ...
clear_lines() # removes every other line than those starting with "a" or "b"
for line in lines:
if (line.startsWith("a")):
# do stuff
elif (line.startsWith("b")):
# magic
else:
# this else is redundant, I already made sure there is no else-case
# by using clear_lines()
# ...
Bisa dibayangkan saya tidak hanya memeriksa kondisi ini di sini, tetapi mungkin juga di fungsi lain dan seterusnya.
Apakah Anda menganggapnya sebagai noise atau menambah nilai pada kode saya?
coding-style
clean-code
marktani
sumber
sumber
assert()
di sana untuk membantu dengan pengujian, tetapi di luar itu mungkin berlebihan. Yang mengatakan, itu akan bervariasi tergantung pada situasinya.elif (line.startsWith("b"))
? Ngomong-ngomong, Anda dapat dengan aman menghapus tanda kurung di sekitar kondisi, mereka tidak idiomatik dengan Python.Jawaban:
Ini adalah praktik yang sangat umum dan cara mengatasinya adalah melalui filter tingkat tinggi .
Pada dasarnya, Anda meneruskan fungsi ke metode filter, bersama dengan daftar / urutan yang ingin Anda filter dan daftar / urutan yang dihasilkan hanya berisi elemen-elemen yang Anda inginkan.
Saya tidak terbiasa dengan sintaks python (walaupun, itu memang mengandung fungsi seperti yang terlihat pada tautan di atas), tetapi dalam c # / f # tampilannya seperti ini:
c #:
f # (mengasumsikan ienumerable, jika tidak List.filter akan digunakan):
Jadi, untuk menjadi jelas: jika Anda menggunakan kode / pola yang dicoba dan diuji, itu adalah gaya yang buruk. Itu, dan mengubah daftar dalam memori dengan cara Anda muncul melalui clear_lines () kehilangan Anda keamanan thread dan harapan paralelisme yang bisa Anda miliki.
sumber
(line for line in lines if line.startswith("a") or line.startswith("b"))
.clear_lines
sebenarnya adalah ide yang buruk. Dengan Python Anda mungkin akan menggunakan generator untuk menghindari memuat file lengkap dalam memori.lines
merupakan koleksi yang dihasilkan.skip
,take
,reduce
(aggregate
NET),map
(select
NET), dan masih ada lagi tapi itu awal yang benar-benar solid.Baru-baru ini saya harus mengimplementasikan programmer firmware menggunakan format S-record Motorola , sangat mirip dengan yang Anda gambarkan. Karena kami memiliki beberapa tekanan waktu, draft pertama saya mengabaikan redudansi dan membuat penyederhanaan berdasarkan subset yang sebenarnya saya perlukan untuk digunakan dalam aplikasi saya. Itu lulus ujian saya dengan mudah, tetapi gagal keras begitu orang lain mencobanya. Tidak ada petunjuk apa masalahnya. Semua berhasil tetapi gagal pada akhirnya.
Jadi saya tidak punya pilihan selain menerapkan semua cek yang berlebihan, untuk mempersempit di mana masalahnya. Setelah itu, saya butuh sekitar dua detik untuk menemukan masalah.
Mungkin butuh dua jam ekstra untuk melakukannya dengan cara yang benar, tetapi menghabiskan satu hari dari waktu orang lain juga dalam pemecahan masalah. Sangat jarang bahwa beberapa siklus prosesor bernilai satu hari pemecahan masalah yang sia-sia.
Yang sedang berkata, di mana membaca file yang bersangkutan, itu sering bermanfaat untuk merancang perangkat lunak Anda untuk bekerja dengan membacanya dan memprosesnya satu baris pada satu waktu, daripada membaca seluruh file ke dalam memori dan memprosesnya dalam memori. Dengan begitu masih bisa bekerja pada file yang sangat besar.
sumber
Anda dapat mengajukan pengecualian
else
jika ada. Dengan cara ini tidak mubazir. Pengecualian adalah hal-hal yang tidak seharusnya terjadi tetapi tetap diperiksa.sumber
"c"
, itu bisa menjadi kurang jelas.Dalam desain berdasarkan kontrak , satu tebakan setiap fungsi harus melakukan tugasnya seperti yang dijelaskan dalam dokumentasinya. Jadi, setiap fungsi memiliki daftar pra-kondisi, yaitu, kondisi pada input fungsi serta kondisi pasca, yaitu, kondisi output fungsi.
Fungsi harus menjamin kepada kliennya bahwa, jika input menghormati pra-kondisi, maka output akan seperti yang dijelaskan oleh pasca-kondisi. Jika setidaknya satu dari pra-kondisi tidak dihormati, fungsi dapat melakukan apa yang diinginkannya (macet, kembalikan hasil apa pun, ...). Oleh karena itu pra dan pasca-kondisi adalah deskripsi fungsi semantik.
Berkat kontrak, suatu fungsi yakin kliennya menggunakannya dengan benar dan klien yakin fungsi itu melakukan tugasnya dengan benar.
Beberapa bahasa menangani kontrak secara asli atau melalui kerangka kerja khusus. Bagi yang lain, yang terbaik adalah memeriksa pra dan pasca kondisi berkat pernyataan, seperti yang dikatakan @Lattyware. Tetapi saya tidak akan menyebut pemrograman defensif itu, karena dalam pikiran saya konsep ini lebih fokus pada perlindungan terhadap input pengguna (manusia).
Jika Anda mengeksploitasi kontrak, Anda dapat menghindari kondisi yang diperiksa secara berlebihan karena fungsi yang dipanggil berfungsi dengan baik dan Anda tidak memerlukan pemeriksaan ganda, atau fungsi yang dipanggil tidak berfungsi dan fungsi panggilan dapat berperilaku seperti yang diinginkan.
Bagian yang lebih sulit adalah menentukan fungsi mana yang bertanggung jawab atas apa, dan mendokumentasikan peran-peran ini secara ketat.
sumber
Anda sebenarnya tidak memerlukan clear_lines () di awal. Jika garisnya bukan "a" atau "b", maka kondisional tidak akan terpicu. Jika Anda ingin menghilangkan garis-garis itu maka buat yang lain menjadi clear_line (). Saat berdiri Anda sedang melakukan dua melewati dokumen Anda. Jika Anda melewatkan clear_lines () di awal dan melakukannya sebagai bagian dari loop foreach maka Anda memotong waktu pemrosesan Anda menjadi dua.
Ini bukan hanya gaya buruk, ini juga buruk komputasi.
sumber
"a"
/"b"
. Tidak mengatakan itu mungkin ( nama yang jelas menyiratkan mereka sedang dibuang), hanya saja ada kemungkinan itu diperlukan. Jika rangkaian garis itu berulang kali diulang di masa depan, bisa juga bermanfaat untuk menghapusnya sebelumnya untuk menghindari banyak iterasi yang tidak berguna.Jika Anda benar-benar ingin melakukan apa pun jika Anda menemukan string yang tidak valid (output debug misalnya) maka saya akan mengatakan itu baik-baik saja. Beberapa baris tambahan dan beberapa bulan ke depan ketika berhenti bekerja karena alasan yang tidak diketahui Anda dapat melihat output untuk mencari tahu mengapa.
Namun, jika aman untuk mengabaikannya saja, atau Anda tahu pasti Anda tidak akan pernah mendapatkan string yang tidak valid maka tidak perlu untuk cabang tambahan.
Secara pribadi saya selalu untuk memasukkan setidaknya jejak output untuk kondisi yang tidak terduga - itu membuat hidup lebih mudah ketika Anda memiliki bug dengan output terlampir memberi tahu Anda apa yang salah.
sumber
Saya benci
if...then...else
konstruksi. Saya akan menghindari seluruh masalah:sumber