Jadi setelah membaca "Menerapkan Desain Berbasis Domain oleh Vaughn Vernon" Saya telah memutuskan untuk memperbaiki kode saya untuk kegunaan yang lebih baik dengan mengisolasi apa yang saya yakini sebagai konsep domain inti ke dalam modul terpisah.
Setiap modul berisi set sendiri lapisan arsitektur yang berbeda yang mencakup Domain, Infrastruktur, dan lapisan Aplikasi / Presentasi (sesuai rekomendasi Vaughn, saya telah memutuskan untuk lebih jauh memisahkan tanggung jawab lapisan Aplikasi dari rute, pengontrol MVC + templat yang ada di Lapisan Presentasi).
Saya telah memutuskan untuk menempatkan masing-masing lapisan ini dalam paket mereka sendiri; dan setiap paket mereferensikan layer di bawahnya sebagai dependensi. yaitu: Lapisan Presentasi tergantung pada Lapisan Aplikasi, Aplikasi tergantung pada Infrastruktur, dll. Karena Repositori adalah bagian dari Domain, setiap Antarmuka Repositori ada di dalam lapisan / paket Domain dengan implementasi menjadi tanggung jawab lapisan / paket Infrastruktur (Doktrin , dll).
Saya berharap bahwa dengan merestrukturisasi kode saya dengan cara ini saya akan dapat menukar lapisan Aplikasi dan menggunakan kembali Domain saya di beberapa Aplikasi Web.
Kode akhirnya terlihat seperti mulai terbentuk lagi namun yang masih membingungkan saya adalah perbedaan antara Aplikasi, Infrastruktur, dan Layanan Domain ini.
Salah satu contoh umum Layanan Domain adalah sesuatu yang akan Anda gunakan untuk kata sandi hash. Ini masuk akal bagi saya dari perspektif SRP karena entitas Pengguna seharusnya tidak mementingkan dirinya sendiri dengan banyak algoritma hashing yang berbeda yang dapat digunakan untuk menyimpan kredensial pengguna.
Maka dengan itu dalam pikiran saya memperlakukan layanan Domain baru ini dengan cara yang sama seperti Repositori saya; dengan mendefinisikan antarmuka di Domain dan membiarkan implementasinya hingga ke lapisan Infrastruktur. Namun, sekarang saya bertanya-tanya tentang apa yang harus dilakukan dengan Layanan Aplikasi.
Seperti sekarang, setiap Entitas memiliki Layanan Aplikasi sendiri, yaitu Entitas Pengguna memiliki Layanan Pengguna dalam Lapisan Aplikasi. UserService dalam hal ini bertanggung jawab untuk mem-parsing tipe data primitif dan menangani kasus penggunaan umum "UserService :: CreateUser (nama string, email string, dll): Pengguna.
Yang membuat saya khawatir adalah kenyataan bahwa saya perlu mengimplementasikan kembali logika ini di beberapa aplikasi jika saya memutuskan untuk menukar layer Aplikasi. Jadi saya kira ini mengarahkan saya ke beberapa pertanyaan saya berikutnya:
Apakah Layanan Domain hanyalah Antarmuka yang ada untuk memberikan lapisan abstraksi antara Lapisan Infrastruktur dan Model Anda? yaitu: Repositori + Layanan Hashing, dll.
Saya sebutkan memiliki Layanan Aplikasi yang terlihat seperti ini:
Akses / Aplikasi / Layanan / UserService :: CreateUser (nama string, email string, dll): Pengguna
Tanda tangan metode menerima argumen tipe data primitif dan mengembalikan Entitas Pengguna baru (bukan DTO!).
Apakah ini termasuk dalam lapisan Infrastruktur sebagai implementasi dari beberapa antarmuka yang didefinisikan dalam lapisan Domain atau apakah Lapisan Aplikasi sebenarnya lebih sesuai karena argumen tipe data primitif, dll ?
contoh:
Access/Domain/Services/UserServiceInterface
dan
Access/Infrastructure/Services/UserService implements UserServiceInterface
Bagaimana seharusnya modul terpisah menangani hubungan searah. Haruskah lapisan aplikasi modul A modul referensi B (seperti yang dilakukannya sekarang) atau implementasi infrastruktur (melalui antarmuka terpisah)?
Apakah Layanan Lapisan Aplikasi memerlukan Antarmuka Terpisah? Jika jawabannya ya maka di mana mereka seharusnya berada?
sumber
Jawaban:
Tanggung jawab layanan domain mencakup beberapa hal. Yang paling jelas adalah logika perumahan yang tidak cocok dengan satu entitas. Misalnya, Anda mungkin perlu mengesahkan pengembalian dana untuk pembelian tertentu, tetapi untuk menyelesaikan operasi Anda memerlukan data dari
Purchase
entitas,Customer
entitas,CustomerMembership
entitas.Layanan domain juga menyediakan operasi yang diperlukan oleh domain untuk menyelesaikan fungsinya seperti
PasswordEncryptionService
, tetapi implementasi layanan ini akan berada di lapisan infrastruktur karena sebagian besar akan menjadi solusi teknis.Layanan infrastruktur adalah layanan yang jadi operasi infrastruktur seperti membuka koneksi jaringan, menyalin file dari sistem file, berbicara dengan layanan web eksternal atau berbicara dengan basis data.
Layanan aplikasi adalah implementasi use case dalam aplikasi yang Anda bangun. Jika Anda membatalkan reservasi penerbangan, Anda akan:
Lapisan aplikasi adalah klien dari domain. Domain tidak tahu kasus penggunaan Anda. Itu hanya memperlihatkan fungsi melalui agregat dan layanan domainnya. Namun lapisan aplikasi mencerminkan apa yang ingin Anda capai dengan mengatur lapisan domain dan infrastruktur.
PHP mungkin bukan tempat terbaik untuk mulai belajar tentang DDD karena banyak kerangka kerja PHP di luar sana (Laravel, Symfony, Zend, dll) cenderung mempromosikan RAD. Mereka lebih fokus pada CRUD dan menerjemahkan formulir ke entitas. CRUD! = DDD
Lapisan presentasi Anda harus bertanggung jawab untuk membaca input formulir dari objek permintaan dan menjalankan layanan aplikasi yang benar. Layanan aplikasi akan membuat pengguna dan memanggil repositori Pengguna untuk menyimpan pengguna baru. Anda dapat secara opsional mengembalikan DTO pengguna kembali ke lapisan presentasi.
Modul kata dalam istilah DDD memiliki arti yang berbeda dari yang Anda gambarkan. Modul harus memuat konsep terkait. Misalnya, modul pesanan di lapisan domain dapat menampung agregat pesanan, entitas OrderItem, OrderRepositoryInterface, dan MaxOrderValidationService.
Modul Order di lapisan aplikasi dapat menampung OrderApplicationServie, CreateOrderCommand dan OrderDto.
Jika Anda berbicara tentang lapisan maka setiap lapisan sebaiknya tergantung pada antarmuka lapisan lain bila memungkinkan. Lapisan presentasi harus bergantung pada antarmuka lapisan aplikasi. Lapisan aplikasi harus merujuk antarmuka dari repositori atau layanan domain.
Saya pribadi tidak membuat antarmuka untuk entitas dan objek nilai karena saya percaya antarmuka harus terkait dengan perilaku, tapi YMMV :)
Itu tergantung :) untuk aplikasi kompleks saya membangun antarmuka karena kita menerapkan unit yang ketat, pengujian integrasi dan penerimaan. Kopling longgar adalah kunci di sini dan antarmuka berada di lapisan yang sama (lapisan aplikasi).
Untuk aplikasi sederhana saya membangun terhadap layanan aplikasi secara langsung.
sumber
Hmm jawaban singkat untuk pertanyaan panjang, tapi saya melihat polanya sebagai berikut
Aturan 1: Objek Domain harus memiliki Root Agregat tunggal
Aturan 2: Agregat Root seharusnya tidak terlalu besar, Pisahkan semuanya menjadi Konteks Terbatas
Masalah: Agregat Root segera menjadi terlalu besar dan tidak ada cara yang jelas untuk menggambar garis antara berbagai Model Domain di dalamnya
Solusi: Layanan Domain. Buat antarmuka yang Anda dapat menyuntikkan ke Model Domain yang memungkinkan mereka untuk melakukan hal-hal di luar Konteks Domain atau Agregat Root mereka.
Jadi saya pikir saya akan mengatakan bahwa contoh Anda hanya Layanan / Repositori dll, IDatabaseRepositoryForStoringUsers atau IGenericHashingCode
Layanan Domain memungkinkan komunikasi antara Konteks Terbatas. yaitu
Di mana Pengguna dan Akun berada di Root Agregat terpisah / Konteks Terbatas.
Jika Pengguna dan Akun berada di Root Agregat yang sama, Anda tentu harus dapat melakukan:
Saya tidak sepenuhnya jelas dari pertanyaan Anda bagaimana Anda mengintegrasikan hal-hal Aplikasi / Infrastruktur nTier dan hal-hal Modul. Obvs Anda tidak benar-benar ingin referensi silang antara Konteks Terikat, sehingga Anda akan menempatkan Antarmuka Layanan Domain Anda di Modul mereka sendiri yang tidak merujuk pada Konteks Terikat lainnya. membatasi Anda untuk mengekspos tipe nilai dasar, atau perhapse hanya DTO
sumber