Mengapa REST Api tidak mengikuti pola desain Fasad

9

Dalam membandingkan struktur REST [api] dengan model OO, saya melihat kesamaan ini:

Kedua:

  • Berorientasi data

    • REST = Sumberdaya
    • OO = Objek
  • Operasi surround di sekitar data

    • REST = mengelilingi VERBS (Dapatkan, Posting, ...) di sekitar sumber daya
    • OO = mempromosikan operasi di sekitar objek dengan enkapsulasi

Namun, praktik OO yang baik tidak selalu berlaku pada REST apis ketika mencoba menerapkan pola fasad misalnya: di REST, Anda tidak memiliki 1 pengontrol untuk menangani semua permintaan DAN Anda tidak menyembunyikan kompleksitas objek internal.

Hubungan objek sederhana antara 2 konsep

Analogi antara OO dan REST

Sebaliknya, REST mempromosikan penerbitan sumber daya dari semua hubungan dengan sumber daya dan lainnya di setidaknya dua bentuk:

  1. melalui hubungan hierarki sumber daya (Kontak id 43 terdiri dari alamat 453): /api/contacts/43/addresses/453

  2. melalui tautan dalam respons json REST:

>> GET /api/contacts/43
<< HTTP Response {
   id: 43, ...
   addresses: [{
      id: 453, ...
   }],
   links: [{
      favoriteAddress: {
          id: 453
      }
   }]
}

Kompleksitas dasar disembunyikan oleh objectA

Kembali ke OO, pola desain fasad menghormati a Low Couplingantara objectA dan ' objectB client ' dan High Cohesionuntuk objectA ini dan komposisi objek internalnya ( objectC , objectD ). Dengan ObjectA antarmuka, ini memungkinkan pengembang untuk dampak batas objectB dari ObjectA perubahan internal (dalam objectC dan objectD ), selama ObjectA api (operasi) masih dihormati.

Dalam REST, data (sumber daya), hubungan (tautan), dan perilaku (kata kerja) diledakkan dalam berbagai elemen dan tersedia untuk web.

Bermain dengan REST, saya selalu berdampak pada perubahan kode antara klien dan server saya: Karena saya memiliki High Couplingantara Backbone.jspermintaan saya dan Low Cohesionantara sumber daya.

Saya tidak pernah menemukan cara untuk membiarkan Backbone.js javascript applicationkesepakatan saya dengan penemuan " sumber daya dan fitur REST " dipromosikan oleh tautan REST. Saya mengerti bahwa WWW dimaksudkan untuk dilayani oleh multi server, dan bahwa elemen OO harus diledakkan untuk dilayani oleh banyak host di sana, tetapi untuk skenario sederhana seperti "menyimpan" halaman yang menunjukkan kontak dengan alamatnya, Saya berakhir dengan:

GET /api/contacts/43?embed=(addresses)
[save button pressed]
PUT /api/contacts/43
PUT /api/contacts/43/addresses/453

yang mengarahkan saya untuk memindahkan tanggung jawab transaksi aksi atom pada aplikasi browser (karena dua sumber dapat diatasi secara terpisah).

Dengan mengingat hal ini, jika saya tidak dapat menyederhanakan pengembangan saya (Pola desain fasad tidak berlaku), dan jika saya membawa lebih banyak kompleksitas kepada klien saya (menangani penyelamatan atom transaksional), di mana manfaatnya tenang?

Alain
sumber
1
Biarkan saya mengerti. Anda mengatakan bahwa Anda harus memperbarui Kontak dengan alamat tertaut (komposisi) tertaut menggunakan dua panggilan REST, satu untuk Kontak dan satu lagi untuk Alamatnya. Anda memiliki Facade untuk menangani pembaruan kontak. Apa masalah dengan membuat PUT /api/contacts/43kaskade pembaruan ke objek batin? Saya memiliki banyak API yang dirancang seperti ini (URL master membaca / membuat / memperbarui "keseluruhan" dan sub-url memperbarui bagian-bagiannya). Pastikan Anda tidak memperbarui alamat ketika tidak ada perubahan yang diperlukan (untuk alasan kinerja).
Anthony Accioly
@AnthonyAccioly, Anda mengerti dengan benar. Saya mencoba mengklarifikasi pertanyaan saya dengan menambahkan beberapa gambar. Saran Anda baik dan itu juga kesimpulan saya datang dengan: mengendalikan permintaan saya secara manual dan menggunakan objek tertanam untuk mengirim hanya satu permintaan untuk menjaga atom pembaruan saya. Namun: Mengapa segala sesuatu di REST mendorong saya menjauh dari kualitas OO atau penegakan (enkapsulasi, ...) dengan meratakan model saya (menyiratkan banyak pengendali). Menggunakan solusi Anda memberikan 1 pembaruan atom. Tidak menggunakan solusi Anda membawa tanggung jawab baru pengembang dan tidak ada aturan pada api untuk mencegahnya melakukannya.
Alain
Hanya sebuah catatan: "hubungan hierarki sumber daya" yang Anda sebutkan adalah masalah bagaimana seseorang dapat memutuskan untuk menyandikan informasi hubungan dalam pengidentifikasi (dalam hal ini, URL). Saya tidak yakin eksposisi informasi ini adalah sesuatu yang merupakan bagian dari REST atau sesuatu yang dipromosikannya, hanya keputusan yang diambilnya sendiri ketika membuat URL suatu sistem. Jika Anda percaya sebaliknya, apakah Anda memiliki referensi tentang Roy Fielding yang membahas masalah ini sebagai bagian dari REST?
Thiago Silva

Jawaban:

7

Saya pikir objek hanya dibangun dengan benar di sekitar perilaku yang koheren dan bukan di sekitar data. Saya akan memprovokasi dan mengatakan bahwa data hampir tidak relevan di dunia berorientasi objek. Bahkan, itu mungkin dan kadang-kadang umum untuk memiliki objek yang tidak pernah mengembalikan data, misalnya "log sink", atau objek yang tidak pernah mengembalikan data yang dilewatkan, misalnya jika mereka menghitung properti statistik.

Mari kita tidak membingungkan PODS , (yang sedikit lebih dari struktur), dan objek nyata yang memiliki perilaku (seperti Contactskelas pada contoh Anda) 1 .

PODS pada dasarnya adalah kenyamanan yang digunakan untuk berbicara dengan repositori dan objek bisnis. Mereka memungkinkan kode untuk diketik aman. Tidak lebih, tidak kurang. Objek bisnis, di sisi lain, memberikan perilaku konkret , seperti memvalidasi data Anda, atau menyimpannya, atau menggunakannya untuk melakukan perhitungan.

Jadi, perilaku adalah apa yang kami gunakan untuk mengukur "kohesi" 2 , dan cukup mudah untuk melihat bahwa dalam contoh objek Anda ada beberapa kohesi, meskipun Anda hanya menunjukkan metode untuk memanipulasi kontak tingkat atas dan tidak ada metode untuk memanipulasi alamat.

Mengenai REST, Anda dapat melihat layanan REST sebagai repositori data. Perbedaan besar dengan desain berorientasi objek adalah bahwa ada (hampir) hanya satu pilihan desain: Anda memiliki empat metode dasar (misalnya, jika Anda menghitung HEAD, misalnya) dan tentu saja Anda memiliki banyak kelonggaran dengan URI sehingga Anda dapat melakukan dengan baik hal-hal seperti melewati banyak id dan mendapatkan struktur yang lebih besar kembali. Jangan bingung data yang mereka lewati dengan operasi yang mereka lakukan. Kohesi dan kopling adalah tentang kode dan bukan data .

Jelas, layanan REST memiliki kohesi yang tinggi (setiap cara untuk berinteraksi dengan sumber daya ada di tempat yang sama) dan kopling rendah (setiap repositori sumber daya tidak memerlukan pengetahuan tentang yang lain).

Namun fakta dasarnya tetap, REST pada dasarnya adalah pola repositori tunggal untuk data Anda. Ini memiliki konsekuensi, karena ini adalah paradigma yang dibangun di atas aksesibilitas yang mudah melalui media yang lambat, di mana ada biaya tinggi untuk "chattiness": klien biasanya ingin melakukan sesedikit mungkin operasi, tetapi pada saat yang sama hanya menerima data yang mereka butuhkan . Ini menentukan seberapa dalam suatu pohon data yang akan Anda kirim kembali.

Dalam desain berorientasi objek (benar), aplikasi non-sepele akan melakukan operasi yang jauh lebih kompleks, misalnya melalui komposisi. Anda dapat memiliki metode untuk melakukan operasi yang lebih khusus dengan data - yang harus demikian, karena sementara REST adalah protokol API, OOD digunakan untuk membangun seluruh aplikasi yang menghadap pengguna! Inilah sebabnya mengapa mengukur kohesi dan penggandengan merupakan hal mendasar dalam OOD, tetapi hampir tidak signifikan dalam REST.

Seharusnya sudah jelas sekarang bahwa menganalisis desain data dengan konsep OO bukanlah cara yang dapat diandalkan untuk mengukurnya: itu seperti membandingkan apel dan jeruk!

Faktanya, ternyata manfaat dari RESTful adalah (kebanyakan) yang diuraikan di atas: ini adalah pola yang baik untuk API sederhana melalui media yang lambat. Sangat mudah disimpan, dan dapat diakses. Ini memiliki kontrol berbutir halus atas obrolan, dll.

Saya harap ini menjawab pertanyaan Anda (cukup beragam) :-)


1 Masalah ini adalah bagian dari serangkaian masalah yang lebih besar yang dikenal sebagai Object-Relational impedance mismatch . Pendukung ORM umumnya di kamp yang mengeksplorasi kesamaan antara analisis data dan analisis perilaku, tetapi ORM telah jatuh di bawah kritik akhir-akhir ini karena mereka tampaknya tidak benar-benar menyelesaikan ketidakcocokan impedansi dan dianggap abstraksi bocor .

2 http://en.wikipedia.org/wiki/Cohesion_(computer_science)

Sklivvz
sumber
Anda benar, saya mengalami kesulitan untuk meledakkan pertanyaan saya dalam banyak aspek, untuk menentukan titik tertentu, karena pertanyaan tersebut membahas kesimpulan "salah" berdasarkan akumulasi dari aspek-aspek ini. Saya akan mencoba sekarang untuk menjawab poin Anda dalam banyak komentar.
Alain
[teks 1] Saya menggunakan kata "data" untuk abstrak dari dunia OO dan REST. Kata mana yang akan Anda gunakan untuk mengabstraksi properti dalam OO dan struktur data dalam REST?
Alain
@Alain "data" baik-baik saja, tapi poin saya bukan untuk membingungkan PODS dan objek bisnis. Ketika kita berbicara tentang OOD, kita biasanya berbicara tentang yang kedua. Yang pertama adalah kenyamanan, dan bisa dengan mudah dipikirkan kamus atau struct atau tuple.
Sklivvz
Ya, saya setuju, saya menggunakan Backbone.js di mana menyimpan model menggunakan struktur json sederhana. Di sinilah teks mencerminkan pengalaman pengkodean saya yang sebenarnya.
Alain
[teks 3] Ini baru bagi saya. Saya pikir kohesi diukur dengan sejumlah metode waktu menggunakan hubungan tertentu ... Saya lebih suka cara Anda melihatnya.
Alain
1

Dengan mengingat hal ini, jika saya tidak dapat menyederhanakan pengembangan saya (Pola desain fasad tidak berlaku), dan jika saya membawa lebih banyak kompleksitas kepada klien saya (menangani penyelamatan atom transaksional), di mana manfaatnya tenang?

Jawaban untuk "di mana manfaatnya tenang?" dianalisis secara menyeluruh dan dijelaskan di sini: http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm

Keraguan dalam pertanyaan ini adalah bahwa ini bukan tentang karakteristik REST dan bagaimana mengatasinya, tetapi dengan asumsi desain URL yang Anda temukan untuk sistem contoh Anda ada hubungannya dengan menjadi TETAP. Bagaimanapun, REST menyatakan bahwa ada hal-hal yang disebut sumber daya dan pengidentifikasi harus disediakan untuk hal-hal yang perlu direferensikan, tetapi itu tidak menentukan bahwa, katakanlah, entitas dalam model ER Anda harus memiliki korespondensi 1-1 dengan URL yang Anda buat (baik bahwa URL harus menyandikan kardinalitas hubungan ER dalam model).

Dalam hal kontak dan alamat, Anda bisa mendefinisikan sumber daya yang bersama-sama mewakili informasi ini sebagai satu unit, meskipun Anda mungkin ingin mengekstrak dan menyimpan informasi ini dalam, katakanlah, tabel DB relasional yang berbeda, setiap kali mereka PUT atau POSTed .

Thiago Silva
sumber
1

Itu karena fasad adalah 'kludge'; Anda harus melihat 'api abstraksi' dan 'api chaining'. Api adalah kombinasi dari dua set fungsi: I / O dan manajemen sumber daya. Secara lokal, I / O baik-baik saja tetapi dalam arsitektur terdistribusi (yaitu proxy, gerbang api, antrian pesan, dll) I / O dibagi dan dengan demikian data dan fungsionalitas menjadi duplikat dan terjerat. Ini mengarah pada masalah lintas sektoral arsitektur. Ini mengganggu SEMUA apis yang ada.

Satu-satunya cara untuk menyelesaikan ini adalah dengan abstrak fungsi I / O untuk API ke penangan pra / pasca (seperti handlerIntercepter di Spring / Grails atau filter dalam Rails) sehingga fungsionalitas dapat digunakan sebagai monad dan dibagikan di berbagai instance dan eksternal perkakas. Data untuk permintaan / respons juga perlu dieksternalisasi dalam suatu objek sehingga dapat dibagikan dan dimuat kembali juga.

http://www.slideshare.net/bobdobbes/api-abstraction-api-chaining

Orubel
sumber
0

Jika Anda memahami layanan REST Anda, atau secara umum segala jenis API, sama seperti antarmuka tambahan yang terpapar ke klien sehingga mereka dapat memprogram pengontrol Anda melalui itu, tiba-tiba menjadi mudah. Layanan ini tidak lebih dari lapisan tambahan di atas logika biz Anda.

Dengan kata lain, Anda tidak perlu membagi logika biz antara beberapa pengontrol, seperti yang Anda lakukan pada gambar di atas, dan yang lebih penting, Anda tidak boleh. Struktur data yang digunakan untuk menukar data tidak perlu cocok dengan struktur data yang Anda gunakan secara internal, mereka bisa sangat berbeda.

Ini adalah seni, dan diterima secara luas, bahwa itu adalah ide yang buruk untuk memasukkan logika biz ke dalam kode UI. Tetapi setiap UI hanyalah semacam antarmuka (I di UI) untuk mengontrol logika biz di belakang. Akibatnya, tampak jelas bahwa ini juga merupakan ide yang buruk untuk memasukkan logika biz ke dalam lapisan layanan REST, atau lapisan API lainnya apa pun.

Secara konseptual, tidak ada banyak perbedaan antara UI dan API layanan.

JensG
sumber
Saya setuju pada gagasan lapisan, tetapi apa yang Anda maksud dengan "program controller Anda melaluinya"?
Alain
1
Saya ingin menekankan fakta, bahwa controller itu sendiri adalah layanan nyata. Antarmuka yang melilit semuanya hanyalah sarana untuk mencapai sesuatu. Setiap antarmuka ada untuk memudahkan akses ke fungsionalitas yang dibungkus, dengan satu atau lain cara. GUI melakukan ini untuk pengguna manusia, API layanan digunakan oleh klien. Kedua audiens target ingin mencapai sesuatu dengan hal-hal yang dibungkus di belakang antarmuka. Saya setuju bahwa "program" mungkin bukan kata-kata terbaik untuk itu, tetapi "kontrol pengendali" juga terdengar canggung ;-)
JensG