Mengapa ide yang buruk untuk berbagi antarmuka antara server dan klien?

12

Saya sedang membaca dokumentasi Spring Cloud Netflix ketika saya menemukan cara untuk berbagi antarmuka antara server HTTP dan kliennya. Mereka menggunakan contoh ini untuk layanan microser, meskipun tidak ada alasan mengapa itu tidak dapat meluas ke komunikasi HTTP umum:

// The shared interface, in a common library
public interface UserService {
    @RequestMapping(method = GET, value = "/users/{id}")
    User getUser(@PathVariable long id);
}

// The controller, on the server
@RestController
public class UserResource implements UserService {
}

// The same interface used for the client
@FeignClient("users")
public interface UserClient extends UserService {
}

Ini mendefinisikan antarmuka yang digunakan sebagai server (Pegas @RestControllermengubahnya menjadi server HTTP) dan klien (Feign @FeignClientmengaturnya untuk penggunaan klien HTTP). Implementasi server dan kelas klien dapat digunakan dalam proyek terpisah tetapi masih menggunakan antarmuka yang sama untuk memastikan bahwa jenisnya cocok.

Namun, di bawah contoh mereka menempatkan peringatan berikut:

Catatan: Pada umumnya tidak disarankan untuk berbagi antarmuka antara server dan klien. Ini memperkenalkan kopling ketat, dan juga sebenarnya tidak berfungsi dengan Spring MVC dalam bentuk saat ini (pemetaan parameter metode tidak diwariskan).

OK, jadi tidak terintegrasi dengan baik sekarang ... tetapi bagian itu muncul setelah peringatan terhadap kode berbagi dan memperkenalkan sambungan antara server dan klien, yang menurut mereka lebih penting. Mengapa menurut mereka itu ide yang buruk untuk berbagi antarmuka dengan cara ini?

Tanpa itu, Anda kehilangan kemampuan untuk menjamin bahwa server dan klien saling mengirim data yang mereka berdua bisa mengerti. Anda bisa menambahkan bidang ke satu tetapi tidak yang lain dan hanya menemukan ketidakcocokan sampai runtime. Menurut saya, ini bukan memperkenalkan kopling, tetapi hanya mengungkapkan kopling yang sudah ada. Apakah kebutuhan untuk membuat server benar-benar independen lebih besar daripada kebutuhan untuk memberi tahu mereka jenis data apa yang akan mereka terima?

Ben S
sumber
1
Kopling yang ada, dalam hal data / format yang ditangani oleh klien / server, ditentukan oleh protokol - sepotong dokumentasi yang dapat digunakan sebagai konvensi . Kopling yang diperkenalkan dengan berbagi antarmuka adalah kopling waktu kompilasi - pertimbangkan apa yang terjadi ketika antarmuka diubah (dengan cara yang tidak kompatibel ke belakang, misalnya), tetapi kode klien / server yang menggunakan antarmuka tersebut digunakan pada waktu yang berbeda. Bahwa penyebaran waktu kopling bisa lebih sulit untuk mengelola, terutama pada skala Netflix'.
Castaglia
1
Saya cukup yakin saya tidak beroperasi pada skala Netflix :) tetapi jika antarmuka diubah dengan cara yang tidak kompatibel ke belakang , maka bukankah ini hanya mengubah kesalahan dari ditemukan pada waktu kompilasi menjadi ditemukan saat runtime? Apakah mereka menganggap itu OK untuk membiarkan beberapa panggilan fungsi gagal sementara mereka perlahan-lahan meningkatkan semua server?
Ben S
1
Mungkin; tergantung pada kode klien. Pertimbangkan juga kasus lain: server ditingkatkan terlebih dahulu, dan klien sekarang harus berurusan dengan (tiba-tiba) panggilan gagal ...
Castaglia
1
Hanya ingin tahu, dengan berbagi antarmuka ini, apakah itu membatasi bahasa / tumpukan apa yang dapat Anda gunakan untuk membangun klien?
JeffO
Ya - ini adalah file Java sehingga Anda harus menggunakan Java. Anda mungkin dapat menggunakan bahasa JVM lain tapi saya belum mencobanya.
Ben S

Jawaban:

6

Alasan seperti yang dinyatakan dalam komentar adalah bahwa hal itu menghasilkan penggandengan erat platform klien Anda ke platform server Anda. Di sini, itu berarti klien Anda diharuskan untuk menggunakan bahasa / platform yang Anda gunakan di server untuk memahami kontrak yang diharapkan dari server Anda. Perhatikan bahwa ada perbedaan antara berbagi kode yang sama (artefak bahasa / platform tertentu) dan menyepakati kontrak tertentu.

Banyak proyek yang sebaliknya menggunakan dokumentasi untuk kontrak mereka. Contoh permintaan dan tanggapan dalam format netral (misalnya JSON) di atas protokol standar (misalnya REST). (Lihat Stripe API docs , misalnya). Karena tidak praktis untuk menulis kontrak berbasis kode untuk setiap platform klien yang mungkin Anda ingin gunakan atau izinkan. Yang lain lagi menggunakan alat manajemen API untuk mendefinisikan kontrak netral .

Contoh Anda menambahkan bidang adalah masalah yang terpisah - contoh mengapa penting untuk kontrak versi API. Biarkan klien menggunakan versi yang mereka dirancang. Versi API baru yang tidak kompatibel mundur ada di samping yang lama. Klien untuk versi yang lama terus bekerja sampai timnya memperbaruinya atau sampai Anda menghentikan versi yang lama (setelah periode penghentian / migrasi). Lihat Perubahan Paralel .

Mengikuti (saran implisit dalam) membantu klien dan server untuk berevolusi dengan cara dan langkah yang masuk akal untuk masing-masing. Jika Anda dapat secara wajar menjamin bahwa server dan klien Anda akan selalu berbagi bahasa / platform yang sama DAN berkembang pada kecepatan yang sama, maka menggunakan artefak kode khusus bahasa dan platform karena kontrak Anda mungkin akan baik-baik saja. Namun, ini mungkin bukan harapan yang masuk akal, terutama untuk proyek-proyek yang menargetkan Netflix OSS (sesuatu yang khusus ditujukan untuk skalabilitas dan kinerja cloud, dengan semua kerumitan yang diperlukan).

Kasey Speakman
sumber
2
Apakah klien benar-benar diharapkan untuk menggunakan antarmuka? Saya selalu melihat konstruksi seperti itu sebagai cara untuk membuat menulis klien lebih mudah. Bagaimanapun, Anda masih bisa menulis klien REST dalam bahasa yang berbeda.
Jimmy T.
1
Tepatnya, api akan tetap ada, dengan definisi rutenya, tidak ada yang mencegah pembuatan klien dalam bahasa lain, tetapi selama Anda menggunakan java dapat menggunakan antarmuka
Leonardo Villela