Di manakah "lapisan logika bisnis" cocok dengan aplikasi MVC?

87

Pertama, sebelum ada yang berteriak menipu, saya kesulitan merangkumnya dalam judul yang sederhana. Judul lain mungkin adalah "Apa perbedaan antara model domain dan model MVC?" atau "Apa model itu?"

Secara konseptual, saya memahami Model sebagai data yang digunakan oleh views dan controller. Di luar itu, tampaknya ada banyak perbedaan pendapat tentang apa yang membentuk model tersebut. Apa itu model domain, versus model aplikasi, vs model tampilan, vs model layanan, dll ..

Misalnya, dalam pertanyaan baru-baru ini yang saya tanyakan tentang pola repositori, saya diberi tahu secara langsung bahwa repositori adalah bagian dari model. Namun, saya telah membaca pendapat lain bahwa model tersebut harus dipisahkan dari model ketekunan dan lapisan logika bisnis. Lagi pula, bukankah pola Repositori seharusnya memisahkan metode persistensi konkret dari model? Orang lain mengatakan ada perbedaan antara model Domain dan model MVC.

Mari kita ambil contoh sederhana. AccountController yang disertakan dengan proyek default MVC. Saya telah membaca beberapa pendapat bahwa kode Akun yang disertakan memiliki desain yang buruk, melanggar SRP, dll .. dll. Jika seseorang harus merancang model Keanggotaan yang "tepat" untuk aplikasi MVC, apakah itu?

Bagaimana Anda memisahkan layanan ASP.NET (penyedia Keanggotaan, penyedia peran, dll ..) dari model? Atau apakah Anda sama sekali?

Cara saya melihatnya, model harus "murni", mungkin dengan logika validasi .. tetapi harus terpisah dari aturan bisnis (selain validasi). Misalnya, Anda memiliki aturan bisnis yang mengatakan seseorang harus dikirimi email ketika akun baru dibuat. Menurut saya, itu tidak benar-benar sesuai dengan model. Jadi, di mana tempatnya?

Adakah yang peduli untuk menjelaskan masalah ini?

Erik Funkenbusch
sumber
1
Itulah mengapa Anda harus menanyakan empat pertanyaan terpisah.
John Farrell
3
Kata kuncinya adalah "hampir". Ini benar-benar pertanyaan yang sama, dengan mungkin subpertanyaan yang digunakan untuk menggambarkan pertanyaan utama.
Erik Funkenbusch
3
Model - Tampilan - Pengontrol. Apakah reposirory / BL View? Tidak. Apakah itu Pengendali? Tidak. Apa yang tersisa :)? Ini adalah MVC, bukan MSVC, bukan MRVC, bukan MBLVC. Hanya ada tiga lapisan. Jadi repositori adalah bagian dari model, BL adalah bagian dari model. Dan Anda dapat membuat pemisahan tambahan, tetapi itu dilakukan di dalam lapisan model.
LukLed
3
@LukeLed, @bslm - Tidak juga. MVC tidak mengatakan bahwa tidak boleh ada lapisan lain yang berinteraksi dengan pengontrol atau model.
John Farrell
3
@LukLed - Disagree - MVC hanyalah pola lapisan presentasi. Ini tidak berdampak pada bagaimana Anda menyusun lapisan Anda yang lain seperti BLL dan DAL.
Cory House

Jawaban:

69

Cara saya melakukannya - dan saya tidak mengatakan itu benar atau salah, adalah memiliki View saya dan kemudian model yang berlaku untuk pandangan saya. Model ini hanya memiliki apa yang relevan dengan pandangan saya - termasuk anotasi data dan aturan validasi. Pengontrol hanya menampung logika untuk membangun model. Saya memiliki lapisan layanan yang menampung semua logika bisnis. Pengontrol saya memanggil lapisan layanan saya. Di luar itu adalah lapisan repositori saya.

Objek domain saya ditempatkan secara terpisah (dalam proyek mereka sendiri, sebenarnya). Mereka memiliki anotasi data dan aturan validasi sendiri. Repositori saya memvalidasi objek di domain saya sebelum menyimpannya ke dalam database. Karena setiap objek di domain saya mewarisi dari kelas dasar yang memiliki validasi bawaan, repositori saya bersifat umum dan memvalidasi semuanya (dan mengharuskannya mewarisi dari kelas dasar).

Anda mungkin berpikir bahwa memiliki dua set model adalah duplikasi kode, dan itu sampai batas tertentu. Namun, ada beberapa contoh yang masuk akal ketika objek domain tidak sesuai untuk tampilan.

Contoh kasusnya adalah ketika bekerja dengan kartu kredit - saya harus meminta cvv saat memproses pembayaran, tetapi saya tidak dapat menyimpan cvv (denda $ 50.000 untuk melakukannya). Tetapi, saya juga ingin Anda dapat mengedit kartu kredit Anda - perubahan alamat, nama, atau tanggal kedaluwarsa. Tetapi Anda tidak akan memberi saya nomor atau cvv saat mengeditnya, dan saya pasti tidak akan mencantumkan nomor kartu kredit Anda dalam teks biasa di halaman. Domain saya memiliki nilai-nilai yang diperlukan untuk menyimpan kartu kredit baru karena Anda memberikannya kepada saya, tetapi model edit saya bahkan tidak menyertakan nomor kartu atau cvv.

Manfaat lain dari begitu banyak lapisan adalah jika dirancang dengan benar, Anda dapat menggunakan peta struktur atau wadah IoC lainnya dan menukar bagian-bagian tanpa memengaruhi aplikasi Anda secara merugikan.

Menurut pendapat saya, kode pengontrol seharusnya hanya kode yang ditargetkan pada tampilan. Tunjukkan ini, sembunyikan itu, dll. Lapisan layanan harus menampung logika bisnis untuk aplikasi Anda. Saya suka memiliki semuanya di satu tempat sehingga mudah untuk mengubah atau menyesuaikan aturan bisnis. Lapisan repositori harus relatif bodoh - tanpa logika bisnis dan hanya membuat kueri data Anda dan mengembalikan objek domain Anda. Dengan memisahkan model tampilan dari model domain, Anda memiliki lebih banyak fleksibilitas dalam hal aturan validasi kustom. Ini juga berarti Anda tidak perlu membuang setiap bagian data ke dalam tampilan Anda di bidang tersembunyi dan mendorongnya bolak-balik antara klien dan server (atau membuatnya kembali di backend).

<% if (!String.IsNullOrEmpty(Model.SomeObject.SomeProperty) && 
    Model.SomeObject.SomeInt == 3 && ...) { %>

Meskipun semuanya tampak tersebar dan berlapis-lapis, itu memiliki tujuan untuk dirancang dengan cara ini. Apakah itu sempurna? tidak juga. Tetapi saya lebih memilihnya daripada beberapa desain sebelumnya yang memanggil repositori dari pengontrol dan memiliki logika bisnis yang dicampur dalam pengontrol, repositori, dan model.

Josh
sumber
Hampir seperti cermin dari apa yang saya miliki di aplikasi MVC perusahaan kami. Arsitektur N-Tier. Aplikasi MVC hanya berinteraksi dengan objek dan layanan bisnis di area N-Tier.
Ed DeGagne
Hampir sama di sini. Proyek terpisah untuk definisi, model, model tampilan, DAL, dll. Satu-satunya perbedaan adalah bahwa DAL saya menyertakan logika untuk meratakan data untuk web guna mengoptimalkan distribusi data kompleks untuk laporan atau tampilan pelanggan khusus. Saya sekarang menghindar dari menyimpan hal-hal di cache aplikasi untuk tabel pencarian, dll, dengan Web farms dan Azure cloud sedang dimainkan.
Robert Achmann
1
@ Astaga, akan sangat membantu jika Anda dapat menunjukkan cuplikan layar dari proyek sampel Anda?
Shaiju T
@Josh bagaimana jika proyek Anda tidak memiliki database. Ini berinteraksi dengan referensi layanan. Semua kelas dan metode domain berasal dari referensi ini. Apakah skenario ini cocok untuk struktur berlapis?
pengguna6395764
17

Saya terlalu sering bertanya-tanya bagaimana tepatnya elemen MVC cocok dengan struktur aplikasi web tradisional, di mana Anda memiliki tampilan (halaman), pengontrol, layanan, dan objek data (model). Seperti yang Anda katakan, ada banyak versi tentang itu.

Saya yakin kebingungan muncul karena arsitektur yang telah diterima secara luas dan dinyatakan di atas, yang menggunakan "model domain anemia" (dugaan) -anti pola. Saya tidak akan membahas banyak detail tentang "anti-pola" model data anemia (Anda dapat melihat upaya saya untuk menjelaskan berbagai hal di sini (berbasis Java, tetapi relevan untuk bahasa apa pun)). Namun singkatnya, itu berarti bahwa model kami hanya menyimpan data, dan logika bisnis ditempatkan di layanan / manajer.

Tapi mari kita asumsikan kita memiliki arsitektur yang didorong domain , dan objek domain kita seperti yang diharapkan - memiliki logika status dan bisnis. Dan dalam perspektif yang digerakkan oleh domain ini terjadi:

  • tampilan adalah UI
  • pengontrol mengumpulkan input UI, memanggil metode pada model, dan mengirim kembali respons ke UI
  • modelnya adalah komponen bisnis kita - menyimpan data, tetapi juga memiliki logika bisnis.

Saya rasa itu menjawab pertanyaan utama Anda. Segalanya menjadi rumit ketika kita menambahkan beberapa lapisan lagi, seperti lapisan repositori. Seringkali disarankan bahwa itu harus dipanggil oleh logika bisnis yang ditempatkan dalam model (dan karenanya setiap objek domain memiliki referensi ke repositori). Dalam artikel saya yang saya tautkan, saya berpendapat bahwa ini bukan praktik terbaik. Dan sebenarnya, memiliki lapisan layanan bukanlah hal yang buruk. Omong-omong, desain domain-driven tidak mengecualikan lapisan layanan, tetapi seharusnya 'tipis', dan hanya mengoordinasikan objek domain (jadi tidak ada logika bisnis di sana).

Untuk paradigma model data anemia, yang diadopsi secara luas (untuk kebaikan atau keburukan), modelnya adalah lapisan layanan dan objek data Anda.

Bozho
sumber
Poin yang bagus! Satu komentar: ada kekacauan yang sama dengan Layanan. Setidaknya layanan dapat berupa layanan Aplikasi dan layanan Domain. Layanan aplikasi hanyalah pembungkus tipis, yang mengumpulkan informasi dari Repositori, dll. Layanan domain menyediakan logika bisnis, yaitu menggunakan kombinasi model domain atau hanya hal-hal yang tidak selalu sesuai dengan model domain.
Artru
bagaimana jika proyek Anda tidak memiliki database. Ini berinteraksi dengan referensi layanan. Semua kelas dan metode domain berasal dari referensi ini. Apakah skenario ini cocok untuk struktur berlapis?
pengguna6395764
3

Menurutku,

Model -

Seharusnya tidak mengandung logika bisnis, itu harus dapat dicolokkan (skenario seperti WCF). Ini digunakan untuk mengikat untuk melihat jadi, itu harus memiliki properti.

Logika bisnis -

Ini harus ditempatkan di "Domain Services Layer", itu adalah lapisan yang terpisah sama sekali. Juga, akan menambahkan satu lapisan lagi di sini "Layanan Aplikasi".

Layanan Aplikasi berbicara ke lapisan Layanan Domain untuk menerapkan logika bisnis dan kemudian mengembalikan Model.

Jadi, Pengontrol akan meminta Layanan Aplikasi untuk Model dan alirannya akan seperti,

    Controller->Application Services(using domain services)->Model
py2020
sumber
2

Pola MVC dan kerangka kerja Asp.net tidak membedakan model yang seharusnya.

Contoh MS sendiri termasuk kelas ketekunan dalam model. Pertanyaan Anda tentang keanggotaan dalam model. Ini tergantung. Apakah kelas dalam model Anda dimiliki oleh sesuatu? Apakah ada hubungan antara siapa yang log in dan data apa yang ditampilkan? Apakah ada pemfilteran bagian data dari sistem perizinan yang dapat diedit? Apakah orang yang terakhir memperbarui atau mengedit bagian objek dari domain Anda karena orang lain perlu melihatnya atau sesuatu untuk dukungan backend?

Contoh email juga tergantung. Apakah Anda akrab dengan eventing domain atau eventing secara khusus? Apakah Anda memiliki layanan terpisah untuk mengirim email? Apakah tindakan mengirimkan email merupakan bagian dari domain Anda atau ini merupakan masalah tingkat aplikasi di luar cakupan sistem Anda? Apakah UI perlu mengetahui apakah email berhasil dikirim atau tidak? Apakah email yang gagal terkirim perlu dicoba ulang? Apakah konten email yang dikirim perlu disimpan untuk dukungan atau persyaratan layanan pelanggan?

Jenis pertanyaan ini terlalu luas dan subjektif, tetapi saya menjawabnya sehingga Anda dan semua orang yang memilih Anda dapat memahami hal ini.

Persyaratan / garis waktu / sumber daya Anda semuanya masuk ke dalam arsitektur sistem Anda. Bahkan model pendapatan bisa berpengaruh. Anda juga harus mempertimbangkan pola yang Anda bidik. DDD jauh berbeda dari aplikasi persistensi-as-model dan semua slop di antaranya juga berlaku untuk aplikasi tertentu. Apakah Anda memotret untuk menguji aplikasi? Semua ini berpengaruh.

John Farrell
sumber