Salah satu bagian dari program saya mengambil data dari banyak tabel dan kolom dalam database saya untuk diproses. Beberapa kolom mungkin null
, tetapi dalam konteks pemrosesan saat ini yang merupakan kesalahan.
Ini seharusnya "secara teoritis" tidak terjadi, jadi jika itu mengarah ke data yang buruk atau bug dalam kode. Kesalahan memiliki keparahan berbeda, tergantung bidang mana yang null
; yaitu untuk beberapa bidang pemrosesan harus dihentikan dan seseorang memberi tahu, untuk yang lain pemrosesan harus diizinkan untuk melanjutkan dan hanya memberi tahu seseorang.
Apakah ada prinsip arsitektur atau desain yang baik untuk menangani null
entri yang jarang tetapi mungkin ?
Solusi harus dimungkinkan untuk diterapkan dengan Java tetapi saya tidak menggunakan tag karena saya pikir masalahnya agak agnostik bahasa.
Beberapa pemikiran yang saya miliki:
Menggunakan NOT NULL
Paling mudah adalah dengan menggunakan batasan NOT NULL dalam database.
Tetapi bagaimana jika memasukkan data asli lebih penting daripada langkah pemrosesan nanti? Jadi kalau-kalau insert akan dimasukkan null
ke dalam tabel (baik karena bug atau mungkin bahkan beberapa alasan yang valid), saya tidak ingin insert gagal. Katakanlah banyak bagian program bergantung pada data yang dimasukkan, tetapi tidak pada kolom khusus ini. Jadi saya lebih suka mengambil risiko kesalahan pada langkah pemrosesan saat ini daripada langkah memasukkan. Itu sebabnya saya tidak ingin menggunakan batasan NOT NULL.
Secara naif tergantung pada NullPointerException
Saya hanya bisa menggunakan data seolah-olah saya berharap untuk selalu ada di sana (dan itu harus benar-benar terjadi), dan menangkap NPE yang dihasilkan pada tingkat yang sesuai (misalnya sehingga pemrosesan entri saat ini berhenti tetapi tidak seluruh proses pemrosesan berlangsung ). Ini adalah prinsip "gagal puasa" dan saya sering lebih suka. Jika itu bug, setidaknya saya mendapatkan NPE yang dicatat.
Tetapi kemudian saya kehilangan kemampuan untuk membedakan berbagai jenis data yang hilang. Misalnya untuk beberapa data yang hilang saya bisa meninggalkannya, tetapi untuk yang lain pemrosesan harus dihentikan dan admin diberitahu.
Memeriksa null
sebelum setiap akses dan melemparkan pengecualian khusus
Pengecualian khusus akan membuat saya memutuskan tindakan yang benar berdasarkan pengecualian, jadi ini sepertinya cara yang harus dilakukan.
Tetapi bagaimana jika saya lupa memeriksanya di suatu tempat? Juga saya kemudian mengacaukan kode saya dengan cek nol yang tidak pernah atau jarang diharapkan (dan tentunya bukan bagian dari aliran logika bisnis).
Jika saya memilih jalan seperti ini, pola apa yang paling cocok untuk pendekatan ini?
Setiap pemikiran dan komentar tentang pendekatan saya disambut. Juga solusi apa pun yang lebih baik (pola, prinsip, arsitektur kode atau model saya yang lebih baik, dll.).
Edit:
Ada kendala lain, dalam hal itu saya menggunakan ORM untuk melakukan pemetaan dari DB ke objek kegigihan, sehingga melakukan pemeriksaan nol pada tingkat itu tidak akan berfungsi (karena objek yang sama digunakan di bagian di mana nol tidak membahayakan) . Saya menambahkan ini karena jawaban yang diberikan sejauh ini sama-sama menyebutkan opsi ini.
Jawaban:
Saya akan meletakkan cek nol dalam kode pemetaan Anda, tempat Anda membangun objek dari hasil yang ditetapkan. Itu menempatkan pemeriksaan di satu tempat, dan tidak akan memungkinkan kode Anda untuk setengah jalan memproses catatan sebelum memukul kesalahan. Bergantung pada bagaimana alur aplikasi Anda bekerja, Anda mungkin ingin melakukan pemetaan semua hasil sebagai langkah pra-pemrosesan alih-alih memetakan dan memproses setiap catatan satu per satu.
Jika Anda menggunakan ORM maka Anda harus melakukan semua pemeriksaan nol sebelum memproses setiap catatan. Saya akan merekomendasikan
recordIsValid(recordData)
metode -type, dengan begitu Anda dapat (lagi) menyimpan semua logika pemeriksaan-nol dan validasi lainnya di satu tempat. Saya pasti tidak akan mencampurkan cek nol dengan sisa logika pemrosesan Anda.sumber
Kedengarannya seperti memasukkan nol adalah kesalahan tetapi Anda takut untuk menegakkan kesalahan ini pada penyisipan karena Anda tidak ingin kehilangan data. Namun, jika suatu bidang tidak boleh nol tetapi, Anda kehilangan data . Oleh karena itu solusi terbaik adalah memastikan bahwa bidang nol tidak salah disimpan.
Untuk tujuan ini, tegakkan bahwa data tersebut benar dalam repositori permanen yang otoritatif untuk data tersebut, yaitu database. Lakukan dengan menambahkan kendala bukan nol. Maka kode Anda mungkin gagal tetapi kegagalan ini segera memberi tahu Anda tentang bug, memungkinkan Anda untuk memperbaiki masalah yang sudah menyebabkan Anda kehilangan data. Sekarang Anda dapat dengan mudah mengidentifikasi bug, menguji kode Anda dan mengujinya dua kali. Anda dapat memperbaiki bug yang menyebabkan hilangnya data dan dalam prosesnya, sangat menyederhanakan pemrosesan data di bagian hilir karena Anda tidak perlu khawatir tentang nol.
sumber
Sehubungan dengan kalimat ini dalam pertanyaan:
Saya selalu menghargai kutipan ini (milik artikel ini ):
Pada dasarnya: sepertinya Anda mendukung Hukum Postel , "jadilah konservatif dalam apa yang Anda kirim, jadilah liberal dalam apa yang Anda terima". Meskipun hebat dalam teori, dalam praktiknya "prinsip kekokohan" ini mengarah pada perangkat lunak yang tidak kuat , setidaknya dalam jangka panjang - dan kadang-kadang juga dalam jangka pendek. (Bandingkan kertas Eric Allman, The Robustness Principle Reconsidered , yang merupakan perawatan yang sangat teliti terhadap subjek, walaupun sebagian besar berfokus pada kasus penggunaan protokol jaringan.)
Jika Anda memiliki program yang salah memasukkan data ke dalam basis data Anda, program-program itu rusak dan perlu diperbaiki . Mengatasi masalah hanya akan membuatnya semakin buruk; ini adalah rekayasa perangkat lunak yang setara dengan memungkinkan seorang pecandu untuk melanjutkan kecanduan mereka.
Namun, secara pragmatis, kadang-kadang Anda memang perlu mengaktifkan perilaku "rusak" untuk melanjutkan, setidaknya untuk sementara, terutama sebagai bagian dari transisi yang mulus dari kondisi longgar, rusak ke kondisi ketat dan benar. Dalam hal ini, Anda ingin menemukan cara untuk memungkinkan penyisipan yang salah berhasil, tetapi masih memungkinkan penyimpanan data "kanonik" selalu dalam keadaan yang benar . Ada berbagai cara untuk melakukan ini:
Salah satu cara untuk menghindari semua masalah ini adalah dengan menyisipkan lapisan API yang Anda kontrol antara program yang menulis dan database aktual.
Kedengarannya seperti bagian dari masalah Anda adalah bahwa Anda bahkan tidak tahu semua tempat yang menghasilkan tulisan salah - atau ada terlalu banyak dari mereka untuk Anda perbarui. Itu adalah kondisi yang menakutkan, tetapi seharusnya tidak boleh dibiarkan muncul.
Segera setelah Anda mendapatkan lebih dari beberapa sistem yang diizinkan untuk mengubah data di toko data produksi kanonik Anda akan berada dalam masalah: tidak ada cara untuk secara terpusat mengelola apa pun tentang database itu. Lebih baik membiarkan proses sesedikit mungkin untuk mengeluarkan menulis, dan menggunakannya sebagai "penjaga gerbang" yang dapat memproses data sebelum memasukkan sebagaimana diperlukan. Mekanisme yang tepat untuk ini sangat tergantung pada arsitektur spesifik Anda.
sumber
" Apakah ada prinsip arsitektur atau desain yang bagus untuk menangani entri nol yang jarang tetapi mungkin? "
Jawaban sederhana - ya.
ETL
Lakukan beberapa pemrosesan di muka untuk memastikan data berkualitas cukup untuk masuk ke database. Apa pun yang ada di file drop harus dilaporkan kembali dan data bersih apa pun dapat dimuat ke dalam basis data.
Sebagai seseorang yang telah menjadi pemburu (dev) dan penjaga permainan (DBA), saya tahu dari pengalaman pahit bahwa pihak ke-3 tidak akan menyelesaikan masalah data mereka kecuali jika dipaksa. Terus-menerus membungkuk ke belakang dan memijat data melalui set preseden yang berbahaya.
Mart / Repositori
Dalam skenario ini, data mentah didorong ke dalam repositori DB dan kemudian versi yang disanitasi didorong ke DB mart yang kemudian diakses oleh aplikasi.
Nilai dasar
Jika Anda dapat menerapkan nilai default yang masuk akal ke kolom maka Anda harus melakukannya meskipun ini dapat melibatkan beberapa pekerjaan jika ini adalah database yang ada.
Gagal lebih awal
Sangat menggoda untuk hanya mengatasi masalah data di gateway ke aplikasi, laporan suite, antarmuka dll. Saya sangat menyarankan Anda untuk tidak hanya mengandalkan ini. Jika Anda menghubungkan beberapa widget lain ke DB, Anda berpotensi menghadapi masalah yang sama lagi. Mengatasi masalah kualitas data.
sumber
Kapan pun kasus penggunaan Anda memungkinkan untuk mengganti NULL dengan aman dengan nilai default yang baik, Anda dapat melakukan konversi dalam
SELECT
pernyataan Sql menggunakanISNULL
atauCOALESCE
. Jadi, bukannyaorang bisa menulis
Tentu saja, itu hanya akan berfungsi ketika ORM memungkinkan untuk memanipulasi pernyataan pilih secara langsung, atau menyediakan templat yang dapat diubah untuk generasi. Orang harus memastikan bahwa tidak ada kesalahan "nyata" yang ditutup-tutupi dengan cara ini, jadi terapkan hanya jika mengganti dengan nilai default persis seperti yang Anda inginkan jika NULL.
Jika Anda dapat mengubah database dan skema, dan sistem db Anda mendukung ini, Anda dapat mempertimbangkan untuk menambahkan klausa nilai default ke kolom tertentu, seperti yang disarankan oleh @RobbieDee. Namun, ini juga akan perlu untuk memodifikasi data yang ada di database untuk menghapus nilai NULL yang dimasukkan sebelumnya, dan itu akan menghapus kemampuan untuk membedakan antara data impor yang benar dan tidak lengkap sesudahnya.
Dari pengalaman saya sendiri, saya tahu bahwa menggunakan ISNULL dapat bekerja dengan sangat baik - di masa lalu saya harus memelihara aplikasi warisan di mana para pengembang asli lupa menambahkan batasan NOT NULL ke banyak kolom, dan kami tidak dapat dengan mudah menambahkan kendala itu nanti untuk beberapa alasan. Tetapi dalam 99% dari semua kasus, 0 sebagai default untuk kolom angka dan string kosong sebagai default untuk kolom teks sepenuhnya dapat diterima.
sumber
OP berasumsi bahwa pasangan akan mengatur bisnis dengan rincian teknis basis data.
Ini semua aturan bisnis. Aturan bisnis tidak peduli dengan nol per-se. Yang diketahui database itu bisa saja nol, 9999, "BOO!" ... Ini hanyalah nilai lain. Bahwa, dalam RDBMS, null memiliki sifat yang menarik dan penggunaan unik diperdebatkan.
Satu-satunya hal yang penting adalah apa arti "null-ness" untuk objek bisnis yang diberikan ...
Iya.
Melempar pengecualian pada pengambilan data tidak masuk akal.
Pertanyaannya adalah "haruskah saya menyimpan data 'buruk'"? Tergantung:
sumber
Ada banyak cara untuk menangani null, jadi kita akan beralih dari lapisan basis data ke lapisan aplikasi.
Lapisan basis data
Anda dapat melarang nulls ; meskipun di sini tidak praktis.
Anda dapat mengonfigurasi default berdasarkan per kolom:
insert
, jadi tidak mencakup penyisipan null eksplisitinsert
kolom ini keliruAnda dapat mengonfigurasi pemicu , sehingga saat penyisipan nilai yang hilang dihitung secara otomatis:
insert
Lapisan permintaan
Anda dapat melewati baris di mana ketidaknyamanan
null
hadir:Anda dapat memberikan nilai default dalam kueri:
Catatan: menginstruksikan setiap kueri belum tentu menjadi masalah jika Anda memiliki cara otomatis untuk menghasilkannya.
Lapisan aplikasi
Anda dapat memeriksa terlebih dahulu tabel terlarang
null
:Anda dapat mengganggu pemrosesan saat menemukan yang terlarang
null
:null
dan mana yang tidakAnda dapat melewati baris ketika menemukan yang terlarang
null
:null
dan mana yang tidakAnda dapat mengirim pemberitahuan ketika menemukan yang terlarang
null
, baik satu per satu atau secara batch, yang gratis untuk cara-cara lain yang disajikan di atas. Namun yang paling penting adalah "lalu apa?", Terutama, jika Anda berharap baris tersebut akan ditambal dan perlu diproses ulang, Anda mungkin perlu memastikan bahwa Anda memiliki beberapa cara untuk membedakan baris yang sudah diproses dari baris yang membutuhkan. sedang diproses ulang.Mengingat situasi Anda, saya akan menangani situasi di aplikasi dan menggabungkan:
Saya akan cenderung hanya melewatkan jika mungkin entah bagaimana menjamin sedikit kemajuan, terutama jika prosesnya bisa memakan waktu.
Jika Anda tidak perlu memproses ulang baris yang dilewati, maka cukup login saja sudah mencukupi dan email yang dikirim pada akhir proses dengan jumlah baris yang dilewati akan menjadi pemberitahuan yang tepat.
Kalau tidak, saya akan menggunakan tabel sisi untuk baris yang harus diperbaiki (dan diproses ulang). Tabel samping ini dapat berupa referensi sederhana (tanpa kunci asing) atau salinan lengkap: yang terakhir, bahkan jika lebih mahal, diperlukan jika Anda tidak punya waktu untuk mengatasi
null
sebelum harus membersihkan data utama.sumber
Nulls dapat ditangani dalam terjemahan atau pemetaan tipe basis data ke tipe bahasa. Misalnya dalam C #, berikut adalah metode umum yang menangani null untuk Anda untuk semua jenis:
Atau, jika Anda ingin melakukan tindakan ...
Dan kemudian dalam pemetaan, dalam hal ini ke objek tipe "Sampel", kami akan menangani null untuk salah satu kolom:
Akhirnya, semua kelas pemetaan dapat secara otomatis dihasilkan berdasarkan query SQL atau tabel yang terlibat dengan melihat tipe data SQL dan menerjemahkannya ke tipe data spesifik bahasa. Inilah yang dilakukan banyak ORM untuk Anda secara otomatis. Perhatikan bahwa beberapa tipe basis data mungkin tidak memiliki pemetaan langsung (Geo-spatial colunms, dll.) Dan mungkin perlu penanganan khusus.
sumber