Saya sedang mengerjakan sebuah proyek di mana kami mencoba menerapkan desain berbasis domain dan REST untuk arsitektur berorientasi layanan. Kami tidak khawatir tentang kepatuhan REST 100%; mungkin akan lebih baik untuk mengatakan kami mencoba membangun HTTP API yang berorientasi pada sumber daya (~ Level 2 dari model maturitas REST Richardson). Namun demikian, kami mencoba untuk menjauh dari penggunaan permintaan HTTP gaya-RPC, yaitu kami mencoba untuk mengimplementasikan kata kerja HTTP kami menurut RFC2616 daripada menggunakan POST
melakukan IsPostalAddressValid(...)
, misalnya.
Namun, penekanan pada hal ini tampaknya mengorbankan upaya kami untuk menerapkan desain berbasis domain. Dengan hanya GET
, POST
, PUT
, DELETE
dan beberapa lainnya metode jarang digunakan, kita cenderung untuk membangun layanan cruddy, dan layanan cruddy cenderung memiliki model domain anemia.
POST
: Menerima data, memvalidasinya, membuangnya ke data. GET
: Ambil data, kembalikan. Tidak ada logika bisnis yang nyata di sana. Kami juga menggunakan pesan (peristiwa) antara layanan, dan menurut saya sebagian besar logika bisnis akhirnya dibangun di sekitar itu.
Apakah REST dan DDD tegang pada tingkat tertentu? (Atau apakah saya salah mengerti sesuatu di sini? Apakah kita mungkin melakukan sesuatu yang salah?) Apakah mungkin untuk membangun model domain yang kuat dalam arsitektur berorientasi layanan sambil menghindari panggilan HTTP gaya-RPC?
IsPostalAddressValid(...)
sesuai dengan "Menyediakan blok data, seperti hasil pengiriman formulir, ke proses penanganan data"?Jawaban:
Hukum pertama sistem distribusi Martin Fowler: "Jangan mendistribusikan benda Anda!" Antarmuka jarak jauh harus berbutir kasar dan antarmuka internal halus. Seringkali model domain kaya hanya berlaku dalam konteks terbatas .
REST API memisahkan dua konteks yang berbeda, keduanya memiliki model internal mereka sendiri. Konteks berkomunikasi melalui antarmuka kasar (REST API) menggunakan objek "anemia" (DTO).
Dalam kasus Anda, sepertinya Anda mencoba menyebarkan konteks melalui batas yang merupakan REST API. Ini dapat menyebabkan antarmuka jarak jauh halus atau model anemia. Tergantung pada proyek Anda itu mungkin atau mungkin tidak menjadi masalah.
sumber
POST sengaja dirancang untuk "sengaja dibuat-buat;" hasil dari POST adalah implementasi khusus. Apa yang mencegah Anda melakukan apa yang dilakukan Twitter dan perancang API lainnya, dan menentukan setiap metode POST di bagian non-CRUD dari API Anda sesuai dengan persyaratan spesifik Anda sendiri? POST adalah kata kerja catchall. Gunakan ketika tidak ada kata kerja lain yang cocok untuk operasi yang ingin Anda lakukan.
Dengan kata lain, pertanyaan Anda bisa sama-sama diajukan sebagai "Apakah objek 'pintar' mendorong desain gaya RPC?" Bahkan Martin Fowler (yang menciptakan istilah "Anemic Domain Model") mengakui bahwa telanjang DTO memang memiliki beberapa manfaat:
Mengenai Model Kematangan Richardson , Anda bisa mencapai level 3 tanpa pernah mengkhawatirkan tentang "Model Domain Anemik." Ingat, Anda tidak akan pernah mentransfer perilaku ke browser (kecuali jika Anda berencana menyuntikkan beberapa Javascript melalui model Anda).
REST sebagian besar tentang independensi mesin; mengimplementasikan model REST sejauh yang Anda inginkan titik akhir Anda mewakili sumber daya, dan bagi konsumen API Anda agar dapat dengan mudah mengakses dan mengelola sumber daya tersebut dengan cara standar. Jika itu tampaknya anemia, maka jadilah itu.
Lihat Juga
Saya Membutuhkan Lebih Banyak Kata Kerja
sumber
REST API hanyalah satu jenis lapisan presentasi. Itu tidak ada hubungannya dengan model domain.
Pertanyaan yang Anda posting berasal dari kebingungan Anda bahwa Anda perlu beradaptasi satu sama lain. Kamu tidak.
Anda memetakan model domain Anda ke REST API Anda dengan cara yang sama Anda memetakan model domain Anda ke RDBMS melalui ORM - harus ada lapisan pemetaan ini.
Domain ← ORM →
Domain RDBMS ← Pemetaan REST → REST API
sumber
IMHO Saya tidak berpikir mereka cenderung mendorong model domain anemia (ADM), tetapi mereka mengharuskan Anda untuk meluangkan waktu dan memikirkan semuanya.
Pertama-tama saya pikir karakteristik utama dari ADM adalah bahwa mereka memiliki sedikit atau tidak ada perilaku di dalamnya. Itu bukan untuk mengatakan bahwa sistem tidak memiliki perilaku, hanya saja biasanya dalam beberapa jenis kelas Layanan (lihat http://vimeo.com/43598193 ).
Dan tentu saja jika perilaku itu tidak ada dalam ADM, lalu apa fungsinya? Jawabannya tentu saja adalah data. Lalu bagaimana peta ini ke REST API? Mungkin data peta ke konten sumber daya, dan perilaku peta ke kata kerja HTTP.
Jadi Anda memiliki semua yang Anda butuhkan untuk membangun model domain yang kaya, Anda hanya harus dapat melihat bagaimana kata kerja HTTP memetakan ke operasi domain pada data, dan kemudian menempatkan operasi tersebut di kelas yang sama yang merangkum data Anda.
Saya pikir di mana orang cenderung mengalami masalah adalah bahwa mereka mengalami kesulitan melihat bagaimana kata kerja HTTP memetakan perilaku domain mereka ketika perilaku itu di luar CRUD sederhana, yaitu, ketika ada efek samping di bagian lain dari domain di luar sumber daya sedang dimodifikasi oleh permintaan HTTP. Salah satu cara untuk mengatasi masalah itu adalah dengan peristiwa domain ( http://www.udidahan.com/2009/06/14/domain-events-salvation/ ).
sumber
Ini artikel yang cukup berkaitan dengan subjek dan saya percaya menjawab pertanyaan Anda.
Konsep inti yang menurut saya menjawab pertanyaan Anda dengan sangat baik, dirangkum dalam paragraf berikut dari artikel yang disebutkan:
"Sangat penting untuk membedakan antara sumber daya dalam REST API dan entitas domain dalam desain berbasis domain. Desain berbasis domain berlaku untuk sisi implementasi hal-hal (termasuk implementasi API) sementara sumber daya dalam REST API mendorong desain dan kontrak API. Sumber daya API pemilihan tidak harus bergantung pada detail implementasi domain yang mendasarinya.
sumber
Beberapa implementasi yang cukup berhasil saya telah melihat / membangun menjawab pertanyaan dalam bagaimana mereka mencampur metafora kata benda + kata benda menggunakan metode 'ramah bisnis' kasar yang bertindak pada entitas.
Jadi, alih-alih
getName()
metode / layanan (terkutuk) , bukagetPerson()
, serahkan hal-hal seperti pengenal-jenis / ID, kembalikan seluruhPerson
entitas.Karena perilaku entitas Orang dalam konteks seperti itu tidak dapat disampaikan secara memadai (atau mungkin juga harus dalam konteks data-sentris seperti ini), sangat masuk akal untuk mendefinisikan model data (versus Obyek) untuk pasangan permintaan / tanggapan dari pelayanan.
Layanan dan kata kerja yang didefinisikan sendiri akan menambahkan beberapa perilaku yang diizinkan, kontrol, dan bahkan aturan transisi negara untuk entitas. Misalnya, akan ada logika khusus domain tentang apa yang terjadi dalam
transferPerson()
panggilan layanan tetapi antarmuka itu sendiri hanya akan menentukan input / output entitas / data tanpa mendefinisikan perilaku internal MEREKA.Saya tidak setuju dengan penulis yang akan mengatakan, misalnya, implementasi kata kerja transfer termasuk dalam kelas Person atau terkait dengan layanan Person-centric. Memang, metode transfer untuk a
Person
dan opsi-opsi daripadanya (dalam contoh sederhana ini) akan lebih baik didefinisikan oleh aCarrier
, di mana merekaPerson
mungkin tidak memiliki pengetahuan tentang bahkan metode transfer apa yang tersedia atau bagaimana transfer bahkan terjadi (siapa yang tahu bagaimana mesin jet bekerja bagaimanapun).Apakah ini membuat
Person
entitas anemia? Saya kira tidak.Dapat / harus ada logika tentang hal-hal spesifik Orang yang bersifat internal bagi Orang seperti keadaan kesehatan mereka, yang tidak boleh didefinisikan oleh kelas eksternal.
Namun, tergantung pada kasus penggunaan, sepenuhnya dapat diterima bahwa kelas entitas tidak memiliki perilaku penting / relevan dalam sistem tertentu, seperti layanan penugasan kursi di sistem transportasi. Sistem seperti itu mungkin mengimplementasikan layanan berbasis REST yang berhubungan dengan instance Orang dan pengidentifikasi terkait tetapi tidak pernah mendefinisikan / mengimplementasikan perilaku internal mereka.
sumber
Apakah masalah Anda bahwa Anda mencoba menjejalkan model Anda ke dalam set kata kerja dasar, menggunakan POST sebanyak mungkin?
Tidak perlu - saya tahu bahwa bagi kebanyakan orang REST berarti POST, GET, PUT dan DELETE, tetapi http rfc mengatakan:
Dan sistem seperti SMTP menggunakan gaya metode berbasis kata kerja yang sama tetapi dengan perangkat yang sama sekali berbeda.
Jadi, tidak ada alasan mengapa Anda harus menggunakan ini, Anda dapat menggunakan set kata kerja apa pun yang Anda suka (meskipun, Anda benar-benar akan menemukan bahwa Anda dapat melakukan semua yang Anda butuhkan di dasar 4 dengan sedikit pemikiran). Hal yang membuat REST berbeda dari mekanisme lainnya adalah cara stateless dan konsekuen menerapkan kata kerja ini. Anda tidak boleh mencoba menerapkan sistem penyampaian pesan di antara tingkatan karena pada dasarnya Anda tidak melakukan REST, maka Anda melakukan mekanisme penyampaian pesan, RPC atau pesan-antrian yang pasti akan menghilangkan manfaat REST (yaitu kesederhanaannya yang membuatnya bekerja dengan sangat baik melalui koneksi http).
Jika Anda menginginkan fitur lengkap, protokol pengiriman pesan yang rumit, kemudian bangun itu (jika Anda dapat melakukannya melalui web, ada alasan mengapa REST sangat populer), tetapi cobalah untuk tetap berpegang pada desain arsitektur REST.
sumber