Di mana memvalidasi aturan model domain yang bergantung pada konten basis data?

10

Saya sedang mengerjakan sistem yang memungkinkan Administrator untuk mendefinisikan Formulir yang berisi Bidang. Formulir yang ditentukan kemudian digunakan untuk memasukkan data ke sistem. Kadang-kadang Formulir diisi oleh manusia melalui GUI, kadang-kadang Formulir diisi berdasarkan nilai yang dilaporkan oleh sistem lain.

Untuk setiap Bidang, Administrator dapat menetapkan Aturan Validasi yang membatasi nilai yang diizinkan untuk Bidang tersebut. Aturan Validasi dapat berupa apa saja mulai dari "nilai yang dimasukkan di Bidang harus Benar atau Salah" hingga "nilai yang dimasukkan di Bidang harus ada di kolom A dari tabel B dalam database". Administrator dapat setiap saat mengubah Aturan Validasi untuk Bidang.

Dalam skenario ini, menurut Anda, tempat apa yang paling cocok untuk memvalidasi bahwa setiap Field diisi dengan benar? Saat ini saya memiliki dua pendekatan utama dalam pikiran:

Opsi # 1: Validasi dalam Model Domain

Setiap objek bidang akan berisi Aturan Validasi yang ditentukan oleh Administrator. Objek Field juga akan memiliki referensi ke IValidator. Ketika upaya dilakukan untuk mengatur nilai Field, Field akan meneruskan nilai yang diberikan dan Aturan Validasi ke IValidator. Jika nilai yang diberikan tidak valid, ValidationException akan dibuang dan ditangani dengan benar di GUI / antarmuka ke sistem lain.

Pro:

  • Perlindungan yang kuat terhadap Fields yang secara tidak sengaja diberi nilai yang melanggar Aturan Validasi

Cons:

  • Layer Akses Data harus dapat mem-bypass validasi dan membuat Fields yang melanggar Aturan Validasi saat ini. Meskipun Administrator mengubah Aturan Validasi untuk Bidang, kami masih harus dapat membangun objek Bidang berdasarkan data lama misalnya ketika membuat Formulir yang diisi tahun lalu. Ini berpotensi diselesaikan dengan menyimpan Aturan Validasi saat ini setiap kali kita menyimpan Field.

  • Dalam desain ini, model Field memiliki tautan tidak langsung ke Lapisan Akses Data / Repositori melalui IValidator. Injeksi Layanan / Repositori ke Model Domain tampaknya umumnya disukai .

Opsi # 2: Validasi dalam Layanan

Cobalah untuk memastikan bahwa semua upaya untuk menetapkan nilai Field lulus melalui Layanan yang memastikan Aturan Validasi berlaku. Jika Aturan Validasi dilanggar, lemparkan ValidationException.

Tentu saja, Lapisan Akses Data tidak akan menggunakan Layanan saat membuat objek Bidang yang sebelumnya telah ada dalam DB.

Pro:

  • Tidak melanggar "jangan menyuntikkan Layanan / Repositori ke dalam Model Domain Anda" - berpikir.

  • Tidak perlu mempertahankan Aturan Validasi saat ini saat bertahan di Lapangan. Layanan dapat dengan mudah mencari Aturan Validasi saat ini untuk Lapangan; saat melihat data riwayat, nilai Field tidak akan berubah.

Cons:

  • Tidak ada jaminan bahwa semua logika yang harus menggunakan Layanan untuk mengatur nilai Field benar-benar melakukannya. Saya melihat ini sebagai kelemahan utama; yang diperlukan hanyalah seseorang yang menulis "thisField.setValue (thatField.getValue ())" dan Aturan Validasi thisField mungkin dilanggar tanpa ada yang lebih bijak. Ini dapat berpotensi dimitigasi dengan memastikan bahwa nilai Field cocok dengan Aturan Validasi ketika Layer Akses Data akan tetap bertahan Field.

Saat ini saya lebih suka Opsi # 1 daripada Opsi # 2, terutama karena saya melihat ini sebagai logika bisnis dan merasa bahwa Opsi # 2 memiliki risiko lebih besar untuk memperkenalkan data buruk ke sistem. Opsi mana yang Anda sukai, atau adakah desain lain yang sesuai dengan skenario ini lebih baik daripada dua opsi yang dijelaskan?

Edit (Kompleksitas validasi)

Kasus validasi yang muncul untuk saat ini relatif sederhana; nilai Field harus berupa numerik, tanggal, tanggal dengan waktu, atau menjadi nilai yang ada di kolom database. Namun, saya menduga kompleksitas meningkat secara bertahap dari waktu ke waktu. Misalnya, solusi validasi perlu dibangun dengan mempertimbangkan internasionalisasi - hal-hal seperti Tanggal dapat dimasukkan dalam sintaksis khusus-lokal.

Saya telah memutuskan untuk melanjutkan dengan Opsi # 1 untuk saat ini, berusaha berhati-hati untuk tidak memberikan terlalu banyak tanggung jawab pada Model Domain. Mereka yang menghadapi situasi serupa mungkin juga ingin memeriksa pertanyaan terkait Validasi dan otorisasi dalam arsitektur berlapis dan validasi input data - Di mana? Berapa banyak? .

Lauri Harpf
sumber
Membuat model berfungsi dengan baik dengan semua validasinya. Tetapi ketika Anda ingin mengedit atau melihat formulir, validasinya juga masuk. Ini melempar pengecualian untuk bidang yang kosong atau memiliki nilai tidak valid - mungkin berubah di db atau diambil dari Excel. Solusi yang diharapkan adalah mengizinkan formulir ditampilkan pada pembaruan sehingga Admin dapat memperbaiki bidang tersebut.
tunmise fasipe

Jawaban:

4

Seberapa rumit validasinya? Seringkali validasi memerlukan kombinasi bidang dan atau aturan bisnis yang bergantung pada bidang untuk dievaluasi secara akurat.

Semakin kompleks validasi, semakin sulit dan kurang berkinerja opsi # 2 adalah.

Tentu saja tingkat data dapat meminta layanan validasi pada waktu yang lama. Ini dapat membantu situasi aneh di mana data dalam keadaan tidak valid karena perubahan aturan.

Item lain yang layak dikomentari adalah kemampuan untuk perubahan aturan validasi tanpa semacam siklus qa. Tapi itu topik untuk utas berbeda.

Dengan informasi di atas, opsi 1 tampaknya paling fleksibel dengan asumsi Anda mempertahankan disiplin, memisahkan validasi, dan kegigihan.

deschaefer
sumber
0

Mungkin Anda kehilangan lapisan. Tanpa mengetahui detail aplikasi Anda (syarat, arsitektur, dll) saya akan melakukan sesuatu seperti Klien (siapa pun itu) -> Layanan Aplikasi -> Model Domain

Lapisan layanan aplikasi diizinkan untuk berinteraksi dengan repositori dan model domain yang berisi logika bisnis. Jadi Anda dapat memiliki sesuatu seperti:

FieldUpdateService >> updateField(fieldId, newValue)
  List<FieldRule> rules = this.rulesRepository.findRulesFor(fieldId)
  Field field = this.fieldRepository.find(fieldId)
  try 
    field.updateValue(rules,newValue)
    fieldRepository.save(field)
  catch 
    // manage error

Jika Anda memiliki hubungan antara Field dan FieldRules-nya dan menggunakan ORM seperti Hibernate di Java, Anda hanya akan melakukan:

FieldUpdateService >> updateField(fieldId, newValue)
  Field field = this.fieldRepository.find(fieldId)
  try 
    field.updateValue(newValue)
    fieldRepository.save(field)
  catch 
    // manage error

Field >> updateValue(newValue)
  for rule in rules
     if !rule.isValid(newValue)
        throw ValueNotAllowedException
  this.value = newvalue

Karena permintaan ORM dan instantiates grafik objek yang Anda minta.

Mengenai keraguan Anda tentang fakta bahwa seseorang dapat melakukannya

thisField.setValue (thatField.getValue ()) "dan Aturan Validasi thisField mungkin dilanggar tanpa ada yang lebih bijak

Seseorang juga dapat menulis: FieldRule alwaysReturnTrueRule = new FieldRule {isValid (newValue) {return true; }} field.updateValue ("uncheckedValue", alwaysReturnTrueRule) Ini adalah contoh yang tidak jelas tetapi apa yang ingin saya katakan adalah tidak ada yang melindungi Anda dari penggunaan kode yang buruk. Mungkin dokumentasi dan komunikasi yang baik berhadap-hadapan. Saya pikir tidak ada yang melindungi Anda dari penggunaan kode yang buruk.

gabrielgiussi
sumber