API Versi

9

Misalkan Anda memiliki proyek besar yang didukung oleh basis API. Proyek ini juga mengirimkan API publik yang dapat digunakan pengguna (ish).

Terkadang Anda perlu membuat perubahan pada basis API yang mendukung proyek Anda. Misalnya, Anda perlu menambahkan fitur yang memerlukan perubahan API, metode baru, atau membutuhkan perubahan salah satu objek, atau format salah satu objek tersebut, diteruskan ke atau dari API.

Dengan asumsi bahwa Anda juga menggunakan objek-objek ini di API publik Anda, objek-objek publik juga akan berubah setiap kali Anda melakukan ini, yang tidak diinginkan karena klien Anda dapat mengandalkan objek API yang tetap identik agar kode parsingnya berfungsi. (klien C + + WSDL batuk ...)

Jadi salah satu solusi potensial adalah dengan versi API. Tetapi ketika kita mengatakan "versi" API, sepertinya ini juga harus berarti versi objek API serta memberikan panggilan metode duplikat untuk setiap tanda tangan metode yang diubah. Jadi saya kemudian akan memiliki objek CLR tua polos untuk setiap versi api saya, yang lagi-lagi tampaknya tidak diinginkan. Dan bahkan jika saya melakukan ini, saya pasti tidak akan membangun setiap objek dari awal karena akan berakhir dengan sejumlah besar kode duplikat. Alih-alih, API kemungkinan akan memperpanjang objek pribadi yang kami gunakan untuk API dasar kami, tetapi kemudian kami mengalami masalah yang sama karena properti yang ditambahkan juga akan tersedia di API publik ketika seharusnya tidak demikian.

Jadi, apakah kewarasan yang biasanya diterapkan pada situasi ini? Saya tahu banyak layanan publik seperti Git untuk Windows mengelola API versi, tetapi saya mengalami kesulitan membayangkan arsitektur yang mendukung ini tanpa banyak kode duplikat yang mencakup berbagai metode versi dan objek input / output.

Saya menyadari bahwa proses seperti upaya versi semantik untuk menempatkan kewarasan ketika API publik rusak harus terjadi. Masalahnya lebih karena sepertinya banyak atau sebagian besar perubahan memerlukan pemutusan API publik jika objek tidak lebih terpisah, tapi saya tidak melihat cara yang baik untuk melakukannya tanpa kode duplikat.

Kasus
sumber
1
I don't see a good way to do that without duplicating code- API baru Anda selalu dapat memanggil metode di API lama Anda, atau sebaliknya.
Robert Harvey
2
AutoMapper untuk menyelamatkan, sayangnya ya- Anda memerlukan versi berbeda dari setiap kontrak, jangan lupa semua objek yang dirujuk oleh kontrak Anda adalah bagian dari kontrak itu. Hasilnya adalah implementasi Anda yang sebenarnya harus memiliki versi model tunggal itu sendiri, dan Anda perlu mengubah versi tunggal ke berbagai versi kontrak. AutoMapper dapat membantu Anda di sini serta membuat model internal lebih pintar daripada model kontrak. Dengan tidak adanya AutoMapper, saya telah menggunakan metode ekstensi untuk membuat terjemahan sederhana antara model internal dan model kontrak.
Jimmy Hoffa
Apakah ada platform / konteks khusus untuk ini? (yaitu DLL, API REST, dll)
GrandmasterB
.NET, dengan MVC dan Webforms ui, kelas dll. Kami memiliki API istirahat dan sabun.
Kasus

Jawaban:

6

Saat mempertahankan API yang digunakan oleh pihak ketiga, tidak dapat dihindari bahwa Anda perlu melakukan perubahan. Tingkat kerumitan akan tergantung pada jenis perubahan yang terjadi. Ini adalah skenario utama yang muncul:

  1. Fungsi Baru Ditambahkan ke API yang Ada
  2. Fungsi Lama Dihentikan Dari API
  3. Fungsi Yang Ada Dalam Mengubah API Dalam Beberapa Cara

Fungsi Baru Menambahkan Ke API Yang Ada

Ini adalah skenario paling mudah untuk didukung. Menambahkan metode baru ke API seharusnya tidak memerlukan perubahan apa pun pada klien yang ada. Ini aman untuk digunakan untuk klien yang membutuhkan fungsionalitas baru karena tidak ada pembaruan untuk klien yang ada.

Fungsi Lama Dihentikan Dari API

Dalam skenario ini, Anda harus berkomunikasi dengan konsumen API Anda yang sudah ada bahwa fungsinya tidak akan didukung dalam jangka panjang. Sampai Anda menjatuhkan dukungan untuk fungsionalitas lama (atau sampai semua klien meningkatkan ke fungsionalitas baru), Anda harus menjaga fungsionalitas API lama dan baru pada saat yang sama. Jika perpustakaan yang disediakan sebagian besar bahasa memiliki cara untuk menandai metode lama sebagai usang / usang. Jika ini adalah layanan pihak ketiga dari jenis tertentu, biasanya yang terbaik adalah memiliki titik akhir yang berbeda untuk fungsi lama / baru.

Fungsi Yang Ada Dalam Mengubah API Dalam Beberapa Cara

Skenario ini akan tergantung pada jenis perubahan. Jika parameter input tidak lagi perlu digunakan maka Anda dapat memperbarui layanan / pustaka untuk mengabaikan data tambahan sekarang. Di perpustakaan itu akan memiliki metode kelebihan beban memanggil metode baru secara internal yang membutuhkan lebih sedikit parameter. Di layanan yang dihosting Anda memiliki titik akhir mengabaikan data tambahan dan dapat melayani kedua jenis klien dan menjalankan logika yang sama.

Jika fungsi yang ada perlu menambahkan elemen yang diperlukan baru maka Anda harus memiliki dua titik akhir / metode untuk layanan / perpustakaan Anda. Hingga klien memperbarui, Anda perlu mendukung kedua versi.

Pikiran Lainnya

Rather, the API is likely to extend the private objects we are using for our base API, but then we run into the same problem because added properties would also be available in the public API when they are not supposed to be.

Jangan memaparkan objek pribadi internal melalui perpustakaan / layanan Anda. Buat jenis Anda sendiri dan petakan implementasi internal. Ini akan memungkinkan Anda melakukan perubahan internal dan meminimalkan jumlah pembaruan yang perlu dilakukan klien eksternal.

The problem is more that it seems like many or most changes require breaking the public API if the objects aren't more separated, but I don't see a good way to do that without duplicating code.

API apakah itu layanan atau pustaka harus stabil pada titik integrasi dengan klien. Semakin banyak waktu yang Anda ambil untuk mengidentifikasi apa input dan output seharusnya dan menyimpannya sebagai entitas yang terpisah akan menghemat banyak sakit kepala di jalan. Jadikan kontrak API entitas terpisah dan petakan ke kelas yang menyediakan karya nyata. Waktu yang dihemat saat implementasi internal berubah harus lebih dari yang mengimbangi waktu ekstra yang diperlukan untuk mendefinisikan antarmuka ekstra.

Jangan melihat langkah ini sebagai "kode duplikat". Meskipun serupa, mereka adalah entitas terpisah yang layak untuk dibuat. Meskipun perubahan API eksternal hampir selalu membutuhkan perubahan terkait dengan implementasi internal, perubahan implementasi internal tidak selalu mengubah API eksternal.

Contoh

Misalkan Anda menyediakan solusi pemrosesan pembayaran. Anda menggunakan PaymentProviderA untuk melakukan transaksi kartu kredit. Kemudian, Anda mendapatkan nilai yang lebih baik melalui pemroses pembayaran PaymentProviderB. Jika API Anda mengekspos bidang Kartu Kredit / Alamat Bill dari jenis Anda alih-alih representasi PaymentProviderA maka perubahan API adalah 0 karena antarmuka tetap sama (semoga saja, jika PaymentProviderB membutuhkan data yang tidak diperlukan oleh PaymentProviderA maka Anda harus memilih salah satu dari keduanya) mendukung keduanya atau mempertahankan tingkat yang lebih buruk dengan PaymentProviderA).

Phil Patterson
sumber
Terima kasih atas jawaban yang sangat terperinci ini. Apakah Anda tahu contoh proyek sumber terbuka yang bisa saya teliti untuk mempelajari bagaimana proyek yang ada telah melakukan ini? Saya ingin melihat beberapa contoh nyata bagaimana mereka mengatur kode yang memungkinkan mereka melakukan ini tanpa hanya menyalin berbagai kode konstruksi POCO mereka ke berbagai objek versi, karena jika Anda memanggil metode bersama, Anda harus membaginya metode bersama untuk dapat mengedit objek itu untuk objek versi.
Kasus
1
Saya tidak mengetahui adanya contoh bagus dari atas kepala saya. Jika saya punya waktu akhir pekan ini saya dapat membuat aplikasi uji untuk melempar pada GitHub untuk menunjukkan bagaimana beberapa hal ini dapat diterapkan.
Phil Patterson
1
Bagian yang sulit adalah bahwa dari level tinggi ada begitu banyak cara berbeda untuk mencoba meminimalkan hubungan antara klien dan server. WCF memiliki antarmuka yang disebut IExtensibleDataObject yang memungkinkan Anda untuk melewatkan data yang tidak ada dalam kontrak dari klien dan mengirimkannya melalui kabel ke server. Google menciptakan Protobuf untuk komunikasi antar sistem (ada implementasi open source untuk .NET, Java, dll). Selain itu ada banyak sistem berbasis pesan yang juga dapat berfungsi (dengan asumsi bahwa proses Anda dapat dilakukan secara tidak sinkron).
Phil Patterson
Mungkin bukan ide buruk untuk menunjukkan contoh spesifik duplikasi kode yang Anda coba hapus (sebagai pertanyaan stack overflow baru) dan lihat solusi apa yang muncul dari komunitas. Sulit untuk menjawab pertanyaan secara umum; jadi skenario tertentu mungkin lebih baik.
Phil Patterson