Topik Permasalahan dan Kapan Ini Berlaku
Sebuah public Orders REST API telah digunakan oleh 600 integrasi pihak ketiga dan beberapa aplikasi seluler yang tidak dapat dipaksa untuk memperbarui sistem mereka. GET /v1/orders yang ada saat ini mengembalikan setiap pesanan dalam satu respons. Setiap pesanan berisi string customer_name, dan status saat ini hanya mengembalikan pending atau paid. Rilis berikutnya harus mengekspos data pelanggan sebagai objek terstruktur, memaginasi daftar pesanan, dan memperkenalkan status refunded.
600 integrasi, field saat ini, dan nilai status adalah asumsi wawancara. Batasan pengikatnya adalah bahwa penyedia layanan (provider) tidak dapat mengontrol kapan setiap konsumen (consumer) melakukan pembaruan. Keberhasilan mencakup v2 yang berfungsi, perilaku v1 yang tetap berjalan di bawah kontrak awal, migrasi yang dapat diobservasi, tanggal penghentian (deprecation) yang dapat ditemukan, dan pemulihan dari rilis yang gagal tanpa mengubah arti yang dijanjikan dari suatu versi.
Ini adalah pertanyaan backend karena menguji kontrak API, representasi sisi server, rekayasa rilis, dan tata kelola kompatibilitas. Pertanyaan ini tidak memerlukan desain untuk seluruh sistem pemesanan atau rencana database-sharding. Tuliskan kontrak yang ada sebelum mengklasifikasikan setiap perubahan. Hanya mengatakan "letakkan v2 di URL" tidak membuktikan bahwa klien lama tetap aman.
{
"orders": [
{
"id": "ord_1",
"customer_name": "Ada Lovelace",
"status": "paid"
}
]
}Hal yang Dinilai oleh Pewawancara
Sinyal pertama adalah apakah kandidat membedakan tiga jenis kompatibilitas. Kompatibilitas source menanyakan apakah kode klien lama masih dapat dikompilasi setelah membuat ulang atau memperbarui SDK-nya. Kompatibilitas wire menanyakan apakah serializer lama dapat mengurai (parse) pesan baru. Kompatibilitas semantik menanyakan apakah panggilan yang sama masih berperilaku seperti yang diharapkan oleh konsumen secara wajar. Tipe field yang tidak berubah tidak dengan sendirinya menjaga semantik. Mengubah "kembalikan setiap pesanan" menjadi "kembalikan 100 pesanan pertama" secara diam-diam masih menghasilkan JSON yang valid, tetapi klien lama akan kehilangan data.
Sinyal kedua adalah pertimbangan berbasis kontrak. Tabel universal yang dihafal tidak dapat mewakili perilaku parsing setiap klien di dunia nyata. Field permintaan (request) opsional baru yang jika diabaikan tetap mempertahankan perilaku lama biasanya dapat tetap berada di v1. Menghapus, mengganti nama, atau mengubah tipe field akan merusak v1. Field respons tambahan adalah penambahan yang aman hanya jika kontrak mengizinkan field yang tidak dikenal dan SDK sebenarnya mengabaikannya. Menambahkan nilai enum respons membutuhkan pemeriksaan ekstra: kontrak open-enum dapat memungkinkan ekspansi, sementara closed enum, SDK bertipe kuat yang dibuat secara otomatis, atau switch lengkap (exhaustive switch) tanpa cabang default dapat mengalami kegagalan.
Sinyal ketiga adalah alur kerja nyata yang menghubungkan versi, implementasi, dan siklus hidup (lifecycle). Jawaban yang kuat mempertahankan lapisan presentasi v1, menggunakan logika domain bersama untuk menghasilkan respons v1 dan v2 yang terpisah, menjalankan uji diff-kontrak dan uji SDK lama sebelum rilis, mengukur adopsi, kesalahan, dan latensi berdasarkan konsumen setelahnya, dan akhirnya menghentikan versi lama dengan sinyal deprecation terstandarisasi, panduan migrasi, dan batasan penonaktifan (shutdown gates) yang eksplisit. Pengidentifikasi versi adalah pilihan perutean (routing); hal itu tidak melakukan tugas-tugas tersebut secara otomatis.
Pertanyaan untuk Diklarifikasi Sebelum Menjawab
- Apakah konsumen dapat dikontrol? Tiga layanan di dalam satu perusahaan yang dapat mengoordinasikan peluncuran atomik dapat menggunakan expand–migrate–contract tanpa v2 jangka panjang. Pihak ketiga dan klien seluler lama memerlukan batas versi yang stabil dan siklus hidup publik.
- Apakah kontrak saat ini mewajibkan klien untuk mengabaikan field dan nilai enum yang tidak dikenal? Hal ini menentukan apakah field respons atau nilai enum yang ditambahkan dapat tetap berada di v1. JSON yang valid saja tidak cukup; periksa kontrak OpenAPI, tipe SDK, dan perilaku konsumen yang sebenarnya.
- Seberapa besar daftar tersebut, dan risiko keandalan apa yang ditimbulkannya? Jika mengembalikan semua pesanan masih memenuhi SLO, paginasi dapat diterapkan hanya di v2. Jika respons tak terbatas sudah mengancam ketersediaan sistem, pembatasan laju permintaan (rate limits) dan jalur komunikasi darurat mungkin diperlukan, tetapi pemotongan data secara diam-diam tetap bukan perubahan yang kompatibel.
- Apakah API sudah memublikasikan mekanisme pemilihan versi? Lanjutkan menggunakan
/v1dan/v2jika versi jalur (path version) sudah ada, atau pertahankan header tanggal yang ada jika pembuatan versi berbasis header. Mengubah mekanisme selama migrasi akan menciptakan perubahan lain pada sisi klien. - Dapatkah penyedia mengidentifikasi setiap konsumen dan menghubungi pemiliknya? ID aplikasi yang stabil, versi SDK, dan kontak pemilik memungkinkan pelacakan migrasi yang presisi. Lalu lintas anonim membutuhkan batasan penghentian yang lebih konservatif.
- Periode dukungan hukum, kontraktual, atau bisnis apa yang dijanjikan? Tanggal penonaktifan berasal dari kebijakan yang dipublikasikan, kewajiban pelanggan, risiko, dan adopsi aktual. Periode dukungan platform lain bukanlah aturan universal.
Kerangka Respons 30 Detik
"Pertama-tama saya akan membekukan kontrak tertulis v1 dan perilaku yang dapat diamati, kemudian mengklasifikasikan setiap usulan perubahan ke dalam kompatibilitas source, wire, dan semantik. Field opsional baru dengan perilaku default yang tidak berubah dapat masuk ke v1. Mengganti string dengan objek, mengganti nama field, dan mengubah daftar semua hasil menjadi paginasi memerlukan v2. Nilai enum respons baru bergantung pada kebijakan open-enum dan perilaku SDK lama. Saya akan berbagi logika domain Orders dan hanya mempertahankan adaptor representasi v1 dan v2. Sebelum rilis, saya akan menjalankan diff OpenAPI, pengujian SDK lama, pemutaran ulang request yang direkam (replay), dan pengujian kontrak ujung-ke-ujung (end-to-end), lalu mengizinkan konsumen yang dikenal untuk memilih menggunakan (opt-in) v2. Saya akan memantau adopsi dan kesalahan per konsumen, memublikasikan tanggal migrasi, deprecation, dan penonaktifan, serta menghentikan v1 hanya setelah batasan migrasi dan kewajibannya terpenuhi. Pada setiap titik kegagalan, saya dapat me-rollback rute atau adaptor v2 sementara v1 tetap tidak berubah."
Pembahasan Mendalam Langkah-demi-Langkah
Mulailah dengan membangun baseline kompatibilitas. Simpan dokumen OpenAPI saat ini, SDK yang telah dirilis, contoh request dan respons yang representatif, kode kesalahan, pengurutan, nilai default, dan perilaku daftar data. Ambil juga sampel perilaku yang tidak terdokumentasi tetapi terlihat, karena konsumen mungkin bergantung pada format field, penanganan nilai null, pengurutan, atau mendapatkan seluruh kumpulan hasil dalam satu respons. Catat ID konsumen, versi, volume request, dan pemilik pada saat yang sama. Nantinya, ini memisahkan antara data yang 'tidak digunakan' dan yang 'digunakan oleh seseorang yang tidak dapat diidentifikasi oleh penyedia.'
Kemudian klasifikasikan setiap usulan perubahan:
| Usulan perubahan | Penilaian v1 | Penanganan |
|---|---|---|
| Menambahkan field request opsional yang jika diabaikan tetap mempertahankan perilaku lama | Biasanya kompatibel | Tambahkan ke v1 dan uji request lama |
| Menambahkan field respons opsional | Kompatibel secara bersyarat | Verifikasi kebijakan field tak dikenal dan SDK lama terlebih dahulu |
Mengganti customer_name dengan objek customer | Tidak kompatibel | Pertahankan string di v1; kembalikan objek di v2 |
| Menghapus atau mengganti nama field yang ada | Tidak kompatibel | Tambahkan nama baru dalam versi baru; jangan hapus dari v1 |
| Mengubah daftar semua hasil menjadi paginasi secara default | Tidak kompatibel secara semantik | Tentukan semantik kursor dan halaman di v2 |
Menambahkan refunded ke enum respons | Bergantung pada kontrak enum | Periksa aturan open-enum, kode yang dibuat otomatis, dan exhaustive switches |
| Mengoreksi ejaan tidak terdokumentasi yang tidak memengaruhi dependensi wajar | Masih membutuhkan bukti | Buktikan dengan pengujian konsumen dan replay traffic |
Paginasi adalah kasus yang mudah diremehkan. Panduan kompatibilitas Google menyoroti risiko penambahan nilai default page_size yang terbatas pada API yang sebelumnya mengembalikan setiap item: klien lama dapat salah berasumsi bahwa respons pertama sudah lengkap. Tentukan aturan items, next_page_token, pengurutan, dan ketidakvalidan token di v2. Selama periode dukungan, v1 mempertahankan semantik aslinya sementara kuota, pemantauan ukuran respons, dan komunikasi migrasi mengendalikan risiko operasional.
Selanjutnya, buat batasan versi. Topik masalah sudah menggunakan penerapan versi melalui path, jadi tambahkan /v2/orders. Jangan menebak versi dari User-Agent pada path yang sama, dan jangan secara diam-diam merutekan v1 ke representasi dengan semantik baru. Buat versi hanya untuk representasi eksternal. Urai setiap request ke dalam command domain yang sama, bagikan logika kueri pesanan dan otorisasi, lalu gunakan V1OrderPresenter atau V2OrderPresenter untuk menghasilkan format yang sesuai. Perbaikan keamanan dan aturan bisnis tetap dapat menjangkau kedua versi tanpa menduplikasi layanan.
Contoh respons v2 adalah:
{
"orders": [
{
"id": "ord_1",
"customer": {
"display_name": "Ada Lovelace"
},
"status": "paid"
}
],
"next_page_token": "eyJvcmRlcl9pZCI6Im9yZF8xIn0"
}Gunakan empat batasan rilis (release gates). Pertama, bandingkan definisi OpenAPI lama dan baru lalu tolak penghapusan field v1, perubahan tingkat keharusan (requiredness), perubahan tipe, dan aturan validasi baru yang tidak disengaja. Kedua, kompilasi dan jalankan kasus kontrak tetap dengan SDK v1 publik terakhir, termasuk field tak dikenal, null, respons error, dan enum. Ketiga, putar ulang request representatif yang telah disanitasi dan bandingkan kode status, field penting, serta pengurutan antara implementasi v1 lama dan baru. Keempat, biarkan sebagian kecil konsumen yang dikenal memilih untuk mencoba v2 di lingkungan sandbox atau canary dan amati fungsionalitas, 4xx, 5xx, latensi, dan ukuran respons. Schema diff dapat menemukan perubahan struktural; ini tidak dapat menggantikan asersi semantik tentang pengurutan, nilai default, atau kelengkapan halaman.
Migrasi dimulai secara opt-in. Publikasikan dokumentasi v2, SDK, tabel migrasi field-demi-field, dan lingkungan sandbox yang mendukung kedua versi. Tunjukkan kepada setiap konsumen yang dikenal tentang volume panggilan v1 mereka, endpoint yang gagal, dan target tanggal. Migrasikan contoh penyedia dan SDK resmi terlebih dahulu agar celah dalam panduan terlihat sejak dini. Tinjau adopsi berdasarkan konsumen dan periksa total request secara terpisah: integrasi rekonsiliasi akhir bulan bervolume rendah bisa lebih penting daripada banyak pemeriksaan kesehatan (health check). Lacak konsumen aktif unik per versi, volume request, 4xx, 5xx, latensi p95, penyelesaian paginasi, kegagalan parsing SDK lama, dan akun berisiko tinggi yang telah dihubungi tetapi belum bermigrasi.
Pisahkan tiga momen siklus hidup: memublikasikan kebijakan migrasi, menghentikan API secara formal (deprecation), dan menghentikan layanannya agar tidak merespons lagi. RFC 9745 mendefinisikan header respons Deprecation untuk tanggal deprecation dan relasi tautan deprecation untuk informasi pendukung. Tambahkan Sunset hanya jika penyedia merencanakan resource tersebut untuk berhenti merespons. Penghentian itu sendiri tidak boleh mengubah perilaku resource. Tanggal-tanggal ini adalah contoh untuk wawancara; tanggal sebenarnya harus mengikuti kebijakan yang dipublikasikan:
Deprecation: @1803859200
Sunset: Wed, 01 Sep 2027 00:00:00 GMT
Link: <https://api.example.com/migrations/orders-v2>; rel="deprecation"; type="text/html"Sebelum menonaktifkan v1, pastikan semua hal berikut terpenuhi: kewajiban dukungan terpenuhi; konsumen kritis yang dikenal telah bermigrasi atau menerima pengecualian yang disetujui; lalu lintas yang tersisa dapat dijelaskan; panduan migrasi dan saluran dukungan berfungsi; kriteria error v2, latensi, dan hasil bisnis terpenuhi; serta gladi bersih penonaktifan dapat dibatalkan (reversible). Jika pelanggan bernilai tinggi masih terhambat, perpanjang dukungan, sediakan gateway kompatibilitas terbatas, atau ikuti kontrak. Jangan abaikan pelanggan tersebut hanya untuk menampilkan tingkat adopsi 100%.
Tentukan skenario rollback sebelum rilis. Rute v2 dan adaptor presentasi dapat dinonaktifkan secara independen, penulisan domain tetap kompatibel ke belakang (backward-compatible), dan v1 mempertahankan artefak terverifikasi terakhirnya. Jika field v2 membutuhkan penyimpanan baru, perluas dan isi data lama (backfill) penyimpanan tersebut sebelum v2 membacanya; jangan menghapus data yang dibutuhkan oleh v1 dalam rilis v2. Me-rollback v2 berarti memulihkan implementasinya. Mengubah arti dari "v2" untuk menyembunyikan insiden justru akan melanggar kontrak lagi.
Contoh Jawaban Berkualitas Tinggi
"Saya akan memisahkan perubahan kontrak dari siklus hidup rilis. Klien-klien ini tidak dapat dipaksa untuk memperbarui sistem, jadi saya perlu mempertahankan parsing JSON, eksekusi SDK lama, dan hasil lengkap dengan makna yang sama untuk request yang sama.
Mengubah customer_name dari string menjadi objek mengubah tipenya, dan mengubah namanya adalah operasi hapus-dan-tambah, jadi keduanya termasuk dalam v2. Memaginasi GET /orders secara default akan menyebabkan klien lama kehilangan hasil, yang merupakan pemutusan semantik dan juga termasuk dalam v2. Saya tidak akan berasumsi bahwa menambahkan refunded itu aman. Jika enum respons didokumentasikan sebagai open dan SDK lama mempertahankan nilai yang tidak dikenal, v1 dapat diperluas. Jika kode yang dibuat otomatis menggunakan closed enum atau konsumen melakukan switch lengkap padanya, saya akan mempertahankan nilai baru di v2 atau terlebih dahulu membuat dan menguji jalur penanganan nilai tak dikenal yang aman.
Saya akan mempertahankan respons dan semantik all-results dari /v1/orders, lalu membuat /v2/orders dengan objek customer terstruktur, kursor, dan aturan halaman. Kedua versi berbagi logika kueri, otorisasi, dan status pesanan; hanya penguraian request dan presentasi respons yang berbeda. Sebelum penggabungan (merge), saya akan membandingkan definisi OpenAPI, menjalankan pengujian kontrak melalui SDK v1 terakhir, dan memutar ulang request yang telah disanitasi untuk memeriksa kode status, pengurutan, nilai default, dan kelengkapan data. SDK internal dan sebagian kecil integrasi yang dikenal akan mencoba v2 terlebih dahulu. Jika terjadi regresi, rute v2 dapat dinonaktifkan sementara v1 berlanjut tanpa perubahan.
Selama migrasi, saya akan mengukur konsumen aktif berdasarkan ID aplikasi, menggunakan total lalu lintas sebagai sinyal pendukung, dan melacak adopsi versi, kegagalan parsing, 4xx, 5xx, latensi, penyelesaian paginasi, dan akun-akun kritis. Panduan mencakup pemetaan field, loop paginasi, fallback enum, dan lingkungan pengujian. Deprecation formal dapat ditemukan melalui header respons dan tautan migrasi; penghentian total memiliki tanggal deklarasi terpisah. Saya menonaktifkan v1 hanya setelah kewajiban dukungan, konsumen kritis, sisa lalu lintas, dan SLO v2 semuanya memenuhi syarat, serta setelah gladi bersih yang dapat dibatalkan. Hal itu menjadikan pengidentifikasi versi, implementasi yang kompatibel, bukti migrasi, dan penghentian sebagai satu rencana yang dapat diuji."
Kesalahan Umum
- Hanya menjawab "letakkan
/v2di URL" → Ini tidak mengidentifikasi siapa yang terdampak maupun batasan migrasi dan penonaktifan → Tetapkan baseline v1, lalu klasifikasikan setiap perubahan ke dalam kompatibilitas source, wire, dan semantik. - Mengasumsikan setiap penambahan respons bersifat kompatibel → Deserializer ketat, closed enum, dan exhaustive switch masih bisa gagal → Periksa kontrak publik dan SDK yang dibuat otomatis, lalu jalankan pengujian versi lama yang sebenarnya.
- Secara otomatis mengalihkan (redirect) v1 ke v2 → Satu pengidentifikasi versi mulai mewakili dua semantik, sehingga klien tidak dapat memilih atau melakukan rollback → Pertahankan representasi v1 yang stabil dan wajibkan pemilihan v2 secara eksplisit.
- Menyalin seluruh layanan untuk v1 dan v2 → Perbaikan keamanan dan aturan bisnis menjadi tidak konsisten sementara biaya pemeliharaan dua versi meningkat → Bagikan logika domain dan isolasi hanya bagian penguraian dan presentasi yang benar-benar berbeda.
- Mematikan v1 begitu tanggal yang diumumkan tiba → Panggilan anonim jangka panjang, rekonsiliasi berfrekuensi rendah, dan pelanggan kritis mungkin masih bergantung padanya → Verifikasi adopsi berdasarkan konsumen, kewajiban, dan sisa lalu lintas, lalu latih proses pemulihan.
- Hanya memantau tingkat 2xx di sisi server → Klien dapat menerima respons tetapi gagal menguraikannya, melewatkan halaman, atau salah menafsirkan status baru → Tambahkan hasil SDK lama, penyelesaian paginasi, hasil ujung-ke-ujung, dan sinyal dukungan.
Pertanyaan Lanjutan dan Tanggapan
Pertanyaan Lanjutan 1: Apakah tiga konsumen internal yang dimiliki oleh perusahaan yang sama memerlukan v2?
Belum tentu. Jika setiap pemanggil dapat diidentifikasi, rilis dapat dikoordinasikan, dan rollback dapat dilakukan dengan cepat, gunakan expand–migrate–contract: tambahkan field atau endpoint yang kompatibel, rilis konsumen yang dapat membaca kedua format, alihkan produsen, lalu hapus kontrak lama setelah penggunaan terukur mencapai nol. Pengujian kontrak dan bukti deployment berversi tetap penting, tetapi konsumen yang dapat dikontrol tidak memerlukan v2 publik permanen. Satu pekerjaan offline yang tidak terkoordinasi, klien lama, atau mitra eksternal akan membatalkan asumsi tersebut.
Pertanyaan Lanjutan 2: Haruskah webhook event mengikuti versi API akun saat ini?
Jangan menginterpretasikan ulang event historis dengan versi "saat ini" selama pemutaran ulang (replay). Tetapkan versi API event saat endpoint dibuat, catat bersama event tersebut, dan pertahankan format asli untuk percobaan ulang dan replay. Lakukan pembaruan dengan membuat atau beralih ke endpoint versi baru dan memvalidasi konsumen. Dokumentasi publik Stripe juga mengaitkan format event webhook dengan versi API pada saat pembuatan endpoint. Mengirimkan event lama dan baru secara bersamaan menciptakan efek samping duplikat dan hanya aman sebagai migrasi singkat ketika konsumen melakukan deduplikasi berdasarkan ID event yang stabil.
Pertanyaan Lanjutan 3: Apakah nilai enum respons baru merupakan breaking change?
Hal ini bergantung pada kontrak yang dipublikasikan. GitHub mencantumkan penambahan nilai enum sebagai aditif, sementara panduan kompatibilitas Google juga memperingatkan bahwa kode lama mungkin tidak menangani nilai enum respons baru dengan baik. Nyatakan perbedaan tersebut secara eksplisit. Jika kontrak mendefinisikan set terbuka (open set), SDK mengekspos representasi tak dikenal, dan konsumen diwajibkan untuk menoleransinya, perubahan tersebut bisa kompatibel. Jika tipenya tertutup atau ekosistem berisi exhaustive switch, perlakukan itu sebagai risiko perubahan yang merusak: perbaiki SDK dan kontrak terlebih dahulu atau tempatkan nilai tersebut dalam versi baru. Skema sisi server saja tidak dapat menentukan hal ini.
Pertanyaan Lanjutan 4: Daftar v1 yang tidak terbatas mengalami timeout. Bagaimana jika migrasi tidak dapat selesai tepat waktu?
Pertama, pulihkan layanan dengan kontrol yang diizinkan oleh kontrak yang ada: kuota, caching, optimasi kueri, dan backpressure, sambil secara langsung memindahkan konsumen bervolume tinggi ke v2. Jika pembatasan respons darurat tidak dapat dihindari, nyatakan bahwa hal itu dapat merusak v1, gunakan proses insiden dan persetujuan perubahan, umumkan cakupan yang terpengaruh, sediakan ekspor massal atau saluran kompatibilitas sementara, dan pantau risiko hilangnya data. Mengembalikan 100 catatan pertama secara diam-diam dengan respons 200 mengubah insiden ketersediaan menjadi kesalahan data yang sulit dideteksi; itu bukan perbaikan yang kompatibel.
Pertanyaan Lanjutan 5: Tanggal penonaktifan tiba, tetapi 0,2% lalu lintas masih menggunakan v1. Apa selanjutnya?
Urai persentase tersebut ke dalam konsumen dan tujuan bisnis: pemeriksaan (probe), konfigurasi yang salah, tugas akhir bulan, atau pelanggan yang terikat kontrak. Hapus lalu lintas yang dapat diidentifikasi yang tidak memiliki ketergantungan bisnis. Konsumen kritis memerlukan pembaruan, pengecualian, atau eskalasi dukungan. Tangani lalu lintas anonim di bawah kebijakan yang dipublikasikan dan model risiko. Catat panggilan yang tersisa, bukti pemberitahuan, kewajiban dukungan, rencana pemulihan, dan pemilik keputusan. Persentase saja tidak membuktikan bahwa penonaktifan aman atau bahwa versi tersebut harus dipertahankan selamanya.