Misalkan kita memiliki metode foo(String bar)
yang hanya beroperasi pada string yang memenuhi kriteria tertentu; misalnya, harus huruf kecil, tidak boleh kosong atau hanya memiliki spasi putih, dan harus cocok dengan polanya [a-z0-9-_./@]+
. Dokumentasi untuk metode ini menyatakan kriteria ini.
Haruskah metode tersebut menolak setiap dan semua penyimpangan dari kriteria ini, atau haruskah metode ini lebih memaafkan tentang beberapa kriteria? Misalnya, jika metode awal adalah
public void foo(String bar) {
if (bar == null) {
throw new IllegalArgumentException("bar must not be null");
}
if (!bar.matches(BAR_PATTERN_STRING)) {
throw new IllegalArgumentException("bar must match pattern: " + BAR_PATTERN_STRING);
}
this.bar = bar;
}
Dan metode memaafkan kedua adalah
public void foo(String bar) {
if (bar == null) {
throw new IllegalArgumentException("bar must not be null");
}
if (!bar.matches(BAR_PATTERN_STRING)) {
bar = bar.toLowerCase().trim().replaceAll(" ", "_");
if (!bar.matches(BAR_PATTERN_STRING) {
throw new IllegalArgumentException("bar must match pattern: " + BAR_PATTERN_STRING);
}
}
this.bar = bar;
}
Haruskah dokumentasi diubah untuk menyatakan bahwa itu akan diubah dan diatur ke nilai yang ditransformasikan jika memungkinkan, atau haruskah metode ini dibuat sesederhana mungkin dan menolak setiap dan semua penyimpangan? Dalam hal ini, bar
dapat diatur oleh pengguna aplikasi.
Kasus penggunaan utama untuk ini adalah pengguna yang mengakses objek dari repositori oleh pengenal string tertentu. Setiap objek dalam repositori harus memiliki string unik untuk mengidentifikasinya. Repositori ini dapat menyimpan objek dengan berbagai cara (sql server, json, xml, binary, dll) dan jadi saya mencoba mengidentifikasi penyebut umum terendah yang cocok dengan kebanyakan konvensi penamaan.
sumber
foo
fungsi ketat yang ketat dalam argumen apa yang diterimanya, dan memiliki fungsi pembantu kedua yang dapat mencoba untuk "membersihkan" argumen yang akan digunakanfoo
. Dengan cara ini, masing-masing metode memiliki lebih sedikit untuk dilakukan sendiri, dan mereka dapat dikelola dan diintegrasikan dengan lebih bersih. Jika menuruni rute itu, mungkin juga akan membantu untuk menjauh dari desain pengecualian-berat; Anda dapat menggunakan sesuatu sepertiOptional
sebagai gantinya, dan kemudian memiliki fungsi yang mengkonsumsifoo
pengecualian melempar jika perlu.Jawaban:
Metode Anda harus melakukan apa yang dikatakannya.
Ini mencegah bug, baik dari penggunaan maupun dari pengelola yang mengubah perilaku nanti. Ini menghemat waktu karena pengelola tidak perlu menghabiskan banyak waktu untuk mencari tahu apa yang sedang terjadi.
Yang mengatakan, jika logika yang didefinisikan tidak ramah pengguna, mungkin harus ditingkatkan.
sumber
foo
danfooForUncleanString
metode di mana yang terakhir melakukan koreksi sebelum meneruskannya ke yang sebelumnya.)Ada beberapa poin:
Ingat bahwa ada pernyataan debug untuk mendiagnosis kesalahan logika dalam mode debug, yang sebagian besar mengurangi masalah kinerja.
Jika Anda menerapkan antarmuka pengguna, pesan kesalahan yang ramah (termasuk saran dan bantuan lainnya) adalah bagian dari desain yang baik.
Tetapi ingat bahwa API adalah untuk pemrogram, bukan pengguna akhir.
Eksperimen kehidupan nyata dalam menjadi kabur dan permisif dengan input adalah HTML.
Yang mengakibatkan semua orang melakukannya sedikit berbeda, dan spek, sekarang didokumentasikan, menjadi buku besar yang penuh dengan kasus-kasus khusus.
Lihat hukum Postel (" Jadilah konservatif dalam apa yang Anda lakukan, menjadi liberal dalam apa yang Anda terima dari orang lain. ") Dan kritik yang menyentuh itu ( Atau yang jauh lebih baik MichaelT membuat saya sadar ).
sumber
Perilaku metode harus jelas, intuitif, dapat diprediksi, dan sederhana. Secara umum, kita harus sangat ragu untuk melakukan pemrosesan ekstra pada input pemanggil. Dugaan seperti itu tentang apa yang dimaksudkan si penelepon selalu memiliki banyak kasus tepi yang menghasilkan perilaku yang tidak diinginkan. Pertimbangkan operasi sesederhana bergabung dengan jalur file. Banyak (atau bahkan mungkin sebagian besar) fungsi file path yang bergabung akan secara diam-diam membuang semua path sebelumnya jika salah satu path yang bergabung tampaknya telah di-root! Misalnya,
/abc/xyz
bergabung dengan/evil
akan menghasilkan adil/evil
. Ini hampir tidak pernah saya maksudkan ketika saya bergabung dengan jalur file, tetapi karena tidak ada antarmuka yang tidak berperilaku seperti ini, saya terpaksa memiliki bug atau menulis kode tambahan yang mencakup kasus-kasus ini.Yang mengatakan, ada kesempatan langka ketika masuk akal untuk metode untuk menjadi "pemaaf," tetapi itu harus selalu berada dalam kekuatan penelepon untuk memutuskan kapan dan apakah langkah-langkah pemrosesan ini berlaku untuk situasi mereka. Jadi, ketika Anda telah mengidentifikasi langkah preprocessing umum yang ingin Anda terapkan pada argumen dalam berbagai situasi, Anda harus mengekspos antarmuka untuk:
Yang terakhir adalah opsional; Anda hanya harus menyediakannya jika banyak panggilan akan menggunakannya.
Mengekspos fungsi mentah memberi pemanggil kemampuan untuk menggunakannya tanpa langkah preprocessing ketika mereka perlu. Mengekspos langkah preprosesor dengan sendirinya memungkinkan pemanggil untuk menggunakannya untuk situasi di mana mereka bahkan tidak memanggil fungsi atau ketika mereka ingin preprocess beberapa input sebelum memanggil fungsi (seperti ketika mereka ingin meneruskannya ke fungsi lain terlebih dahulu). Menyediakan kombinasi memungkinkan penelepon untuk memanggil keduanya tanpa kerumitan, yang berguna terutama jika sebagian besar penelepon akan menggunakannya dengan cara ini.
sumber
Seperti yang dikatakan orang lain, membuat string yang cocok "memaafkan" berarti memperkenalkan kompleksitas tambahan. Itu berarti lebih banyak pekerjaan dalam mengimplementasikan pencocokan. Anda sekarang memiliki lebih banyak kasus uji, misalnya. Anda harus melakukan pekerjaan tambahan untuk memastikan tidak ada nama yang sederajat secara semantik di namespace. Lebih banyak kompleksitas juga berarti ada lebih banyak kesalahan di masa depan. Mekanisme yang lebih sederhana, seperti sepeda, membutuhkan perawatan yang lebih sedikit daripada yang lebih kompleks, seperti mobil.
Jadi apakah pencocokan string yang ringan sepadan dengan semua biaya tambahan itu? Itu tergantung pada use case, seperti yang telah dicatat orang lain. Jika string adalah semacam input eksternal yang tidak dapat Anda kendalikan, dan ada keuntungan pasti untuk pencocokan ringan, mungkin layak dilakukan. Mungkin input berasal dari pengguna akhir yang mungkin tidak terlalu berhati-hati tentang karakter ruang dan huruf besar, dan Anda memiliki insentif yang kuat untuk membuat produk Anda lebih mudah digunakan.
Di sisi lain, jika input berasal dari, katakanlah, file properti yang dikumpulkan oleh orang-orang teknis, yang harus memahami itu
"Fred Mertz" != "FredMertz"
, saya akan lebih cenderung untuk membuat pencocokan lebih ketat dan menghemat biaya pengembangan.Saya pikir dalam hal apapun ada nilai dalam memangkas dan mengabaikan ruang terkemuka dan tertinggal, meskipun - saya telah melihat terlalu banyak waktu terbuang untuk men-debug masalah-masalah semacam itu.
sumber
Anda menyebutkan beberapa konteks dari mana pertanyaan ini datang.
Mengingat bahwa, saya akan memiliki metode melakukan hanya satu hal, itu menegaskan persyaratan pada string, biarkan dijalankan berdasarkan itu - saya tidak akan mencoba untuk mengubahnya di sini. Tetap sederhana dan tetap jelas; mendokumentasikannya , dan berusaha untuk menjaga dokumentasi dan kode tetap sinkron satu sama lain.
Jika Anda ingin mengubah data yang berasal dari basis data pengguna dengan cara yang lebih memaafkan, masukkan fungsi itu ke dalam metode transformasi yang terpisah dan dokumentasikan fungsi yang diikatnya .
Pada titik tertentu persyaratan fungsi perlu diukur, didokumentasikan dengan jelas dan eksekusi harus dilanjutkan. "Pengampunan", pada poinnya, sedikit bisu, ini adalah keputusan desain dan saya berpendapat untuk fungsi yang tidak mengubah argumennya. Memiliki fungsi bermutasi input menyembunyikan beberapa validasi yang akan diperlukan klien. Memiliki fungsi yang melakukan mutasi membantu klien menyelesaikannya dengan benar.
The penekanan besar di sini adalah kejelasan dan dokumen apa kode tidak .
sumber
sumber