Apakah RESTful APIs cenderung mendorong model domain anemia?

34

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 POSTmelakukan IsPostalAddressValid(...), misalnya.

Namun, penekanan pada hal ini tampaknya mengorbankan upaya kami untuk menerapkan desain berbasis domain. Dengan hanya GET, POST, PUT, DELETEdan 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?

Kazark
sumber
1
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?
Robert Harvey
@RobertHarvey Kami telah menafsirkan POST sebagai buat. Melihat standar lagi, mungkin itu terlalu sederhana. Misalnya, apakah menurut Anda POST yang harus dilakukan IsPostalAddressValid(...)sesuai dengan "Menyediakan blok data, seperti hasil pengiriman formulir, ke proses penanganan data"?
Kazark
Itu karena tidak ada kata kerja CREATE (dan tidak ada kata kerja UPDATE, dalam hal ini). Saya berpendapat bahwa kata kerja tersebut hilang dari standar (untuk alasan apa pun), itulah sebabnya Anda harus memilih POST untuk "segala sesuatu yang lain." "Proses penanganan data" Anda, dalam hal ini, adalah proses yang memeriksa alamat pos, dan mengembalikan nilai yang sesuai dengan hasil analisis tersebut.
Robert Harvey
1
@RobertHarvey: Saya percaya bahwa POST dan PUT / PATCH hanyalah kata kerja CREATE dan UPDATE yang Anda inginkan. Hanya diberi nama berbeda sehingga kata kerjanya masih masuk akal bahkan dalam desain yang tidak tenang.
Lie Ryan
@ LieRyan: Saya akan memberi Anda itu. Saya hanya berpikir bahwa CRUD menyiratkan model data anemia berdasarkan definisi. Anda dapat menjalankan beberapa perilaku jika, katakanlah, Anda berada di MVC, tetapi tentu saja tidak di seluruh sistem yang heterogen. Untuk yang lainnya kecuali CRUD, Anda perlu POST.
Robert Harvey

Jawaban:

38

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.

simoraman
sumber
1
Fowler memiliki banyak pemikiran bagus tetapi jangan lupa bencana apa yang menjadi spesifikasi EJB dan implementasinya. Hanya setelah itu mereka menemukan bahwa panggilan metode tingkat rendah untuk setiap operasi kecil seperti getName () adalah mimpi buruk jaringan / beban. Antarmuka kasar menjadi cara untuk pergi dan dengan itu konsep bahwa seluruh entitas-grafik / pesan dikirim dan diterima dalam konteks kata kerja + kata benda.
Darrell Teague
9

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:

Menempatkan perilaku ke objek domain tidak boleh bertentangan dengan pendekatan solid menggunakan layering untuk memisahkan logika domain dari hal-hal seperti ketekunan dan tanggung jawab presentasi. Logika yang harus ada dalam objek domain adalah logika domain - validasi, perhitungan, aturan bisnis - apa pun yang Anda suka menyebutnya.

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

Robert Harvey
sumber
Saya pikir itu pasti membahas sisi pertanyaan RFC2616. Bagaimana dengan fakta bahwa kita berusaha untuk berorientasi pada sumber daya, yaitu setidaknya berusaha mencapai Level 2 dalam model kematangan Richardson untuk REST?
Kazark
1
Saya membaca melalui martinfowler.com/articles/richardsonMaturityModel.html . Anda dapat 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).
Robert Harvey
4

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

Elnur Abdurrakhimov
sumber
3

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/ ).

RibaldEddie
sumber
3

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.

Majix
sumber
1

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) , buka getPerson(), serahkan hal-hal seperti pengenal-jenis / ID, kembalikan seluruh Personentitas.

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 Persondan opsi-opsi daripadanya (dalam contoh sederhana ini) akan lebih baik didefinisikan oleh a Carrier, di mana mereka Personmungkin 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 Personentitas 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.

Darrell Teague
sumber
Poin bagus --- ini benar-benar membawa perspektif baru yang belum dijawab oleh jawaban lain.
Kazark
0

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:

Serangkaian metode umum untuk HTTP / 1.1 didefinisikan di bawah ini. Meskipun set ini dapat diperluas, metode tambahan tidak dapat diasumsikan untuk berbagi semantik yang sama untuk klien dan server yang diperluas secara terpisah.

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.

gbjbaanb
sumber