paint-brush
Tabel sebagai API? Ilusi dan Realitasoleh@truewebber
Sejarah baru

Tabel sebagai API? Ilusi dan Realitas

oleh Aleksei Kish9m2025/03/05
Read on Terminal Reader

Terlalu panjang; Untuk membaca

Penulis berpendapat bahwa penggunaan tabel basis data bersama sebagai sarana komunikasi antarlayanan merupakan antipola. Meskipun tampaknya merupakan solusi cepat, hal itu menyebabkan masalah dalam pembuatan versi, kepemilikan yang tidak jelas, dan kesulitan dengan skalabilitas dan keamanan. Sebaliknya, artikel tersebut menganjurkan pendekatan "Contract First", di mana setiap layanan secara formal mendefinisikan antarmukanya dan mempertahankan kepemilikan atas datanya sendiri. Metode ini mendorong akuntabilitas yang lebih jelas, evolusi yang lebih lancar, dan integrasi yang lebih kuat di seluruh tim.
featured image - Tabel sebagai API? Ilusi dan Realitas
Aleksei Kish HackerNoon profile picture
0-item
1-item

Perkenalan

Apa yang dimaksud dengan “kontrak” dalam konteks interaksi layanan?

Dalam konteks modul layanan yang saling berinteraksi, muncul pertanyaan yang tak terelakkan: Dengan aturan apa komunikasi berlangsung? Dalam produk TI, "kontrak" merupakan pemahaman formal tentang data apa yang mengalir di antara sistem dan bagaimana data tersebut ditransmisikan. Hal ini mencakup format data (JSON, Protobuf, dll.), elemen struktural (bidang, tipe data), protokol komunikasi (REST, gRPC, antrean pesan), dan spesifikasi lainnya.


Kontrak memastikan keterbukaan (semua orang tahu apa yang diterima dan dikirim), prediktabilitas (kami dapat memperbarui kontrak dan memelihara versi), dan keandalan (sistem kami tidak akan gagal jika kami membuat perubahan yang dikelola dengan baik).

Mengapa orang cenderung memilih tabel dalam database sebagai “kontrak.”

Dalam praktiknya, meskipun semua orang berbicara tentang layanan mikro, “kontrak”, dan API, kita sering melihat orang menggunakan pendekatan: “Mengapa tidak membuat tabel bersama dalam database alih-alih membangun API?”


  • Kebiasaan historis atau organisasi: Ketika semuanya selalu disimpan dalam satu sistem DB dalam satu perusahaan, mengapa harus menciptakan kembali roda?


  • Mentalitas “perbaikan cepat”: Kami akan menulis, Anda akan membaca tanpa menyiapkan aturan otorisasi dan merancang spesifikasi API.


  • Argumen “big data”: Saat bekerja dengan puluhan atau bahkan ratusan gigabyte data, transfer langsung ke tabel bersama tampak lebih sederhana, lebih cepat, dan lebih ekonomis, tetapi dalam praktiknya, hal ini menimbulkan masalah skalabilitas dan kinerja serta masalah kepemilikan data.


Oleh karena itu, meskipun penggunaan tabel bersama untuk pertukaran data mungkin tampak efisien dan dioptimalkan untuk hasil yang cepat, hal itu menimbulkan berbagai tantangan teknis dan organisasi dalam jangka panjang. Namun, ketika tim memilih tabel bersama untuk pertukaran data, mereka mungkin menghadapi banyak masalah selama implementasi.

Mengapa “Tabel dalam Basis Data” Bukan Kontrak (dan Mengapa Itu Anti-Pola).

Kurangnya Antarmuka yang Jelas

Saat layanan berkomunikasi melalui REST/gRPC/GraphQL, layanan tersebut memiliki definisi formal: OpenAPI (Swagger), skema protobuf, atau skema GraphQL. Skema ini mendefinisikan secara terperinci sumber daya (titik akhir) mana yang tersedia, kolom mana yang diharapkan, jenisnya, dan format permintaan/respons. Saat 'tabel bersama' bertindak sebagai kontrak, tidak ada deskripsi formal: Tidak ada deskripsi formal kontrak; hanya skema tabel (DDL) yang tersedia dan itu pun tidak terdokumentasi dengan baik. Setiap modifikasi kecil pada struktur tabel (misalnya, menambahkan atau menghapus kolom, mengubah tipe data) dapat memengaruhi tim lain yang membaca atau menulis ke tabel ini.

Masalah Versi dan Evolusi

Pembuatan versi API merupakan praktik yang normal: Kita mungkin memiliki v1, v2, dan seterusnya, dan kita dapat mempertahankan kompatibilitas mundur lalu secara bertahap memindahkan klien ke versi yang lebih baru. Untuk tabel basis data, kita hanya memiliki operasi DDL (misalnya, ALTER TABLE ), yang terkait erat dengan mesin DB tertentu dan memerlukan penanganan migrasi yang cermat.


Tidak ada sistem terpusat yang dapat mengirimkan peringatan kepada konsumen tentang perubahan skema yang mengharuskan mereka memperbarui kueri mereka. Akibatnya, transaksi "di bawah meja" dapat terjadi: Seseorang dapat memposting di obrolan, "Besok, kami akan mengubah kolom X menjadi Y", tetapi tidak ada jaminan semua orang akan siap tepat waktu.

Tidak Ada Kepemilikan Yang Jelas

Bila ada API yang didefinisikan dengan jelas, jelas siapa pemiliknya: layanan yang berfungsi sebagai penerbit API. Bila beberapa tim menggunakan tabel basis data yang sama, ada kebingungan tentang siapa yang berhak menentukan struktur dan kolom mana yang harus disimpan serta cara menafsirkannya. Akibatnya, tabel tersebut dapat menjadi "milik siapa pun", dan setiap perubahan menjadi pertanyaan: "Kita perlu memeriksa dengan tim lain itu untuk memastikan apakah mereka menggunakan kolom lama!"

Masalah Keamanan dan Kontrol Akses

Sulit untuk melacak siapa yang dapat membaca dan menulis ke tabel jika banyak tim memiliki akses ke DB. Ada kemungkinan layanan yang tidak sah dapat mengakses data meskipun data tersebut tidak ditujukan untuk mereka. Lebih mudah untuk mengelola masalah tersebut dengan API: Anda dapat mengontrol hak akses (siapa yang dapat memanggil metode mana), menggunakan autentikasi dan otorisasi, dan memantau siapa yang memanggil apa. Dengan tabel, semuanya jauh lebih rumit.

Ketergantungan pada Struktur Internal

Segala modifikasi internal pada data (menata ulang indeks, mempartisi tabel, mengubah DB) menjadi masalah global. Jika tabel berfungsi sebagai antarmuka publik, pemilik tidak dapat membuat perubahan internal tanpa membahayakan semua pembaca dan penulis eksternal.

Titik Nyeri dan Masalah Umum dalam Praktik

Mengkoordinasikan Perubahan

Ini adalah aspek yang paling menyakitkan: Bagaimana seseorang memberi tahu tim lain bahwa skema akan berubah keesokan harinya?

  • Skenario yang berhasil untuk memperbarui versi tabel: Pemilik membuat tabel baru dengan skema yang diperbarui secara paralel dengan yang lama. Versi lama tetap dapat diakses oleh konsumen saat ini dan pemilik mengirimi mereka pesan yang mengatakan, “Struktur baru tersedia; periksa dokumentasi dan tenggat waktu. Harap migrasikan selagi kedua versi tersedia.”


  • Namun, dalam skenario OLAP atau dengan volume data yang besar, mengelola dua tabel paralel bukanlah tugas yang mudah. Anda juga harus menentukan cara memindahkan data dari skema lama ke skema baru. Hal ini terkadang memerlukan waktu henti yang direncanakan atau infrastruktur yang sangat canggih. Proses ini tentu saja menimbulkan risiko dan pekerjaan tambahan.

Masalah Integritas Data

Bila beberapa tim menggunakan tabel bersama untuk memilih dan memperbarui data penting, hal itu dapat dengan mudah menjadi "medan perang". Hasilnya adalah logika bisnis tersebar di berbagai layanan, dan tidak ada kontrol terpusat atas integritas data. Menjadi sangat sulit untuk mengetahui mengapa bidang tertentu disimpan dengan cara tertentu, siapa yang dapat memperbaruinya, dan apa yang terjadi jika dibiarkan kosong.

Tantangan Debugging dan Pemantauan

Misalnya, misalkan tabel rusak: Katakanlah, ada data yang salah atau seseorang telah mengunci beberapa baris penting. Mengidentifikasi sumber masalah sering kali memerlukan pertanyaan kepada setiap tim yang memiliki akses DB untuk menentukan kueri apa yang menyebabkan masalah tersebut. Sering kali tidak jelas: Ini berarti kueri satu tim mungkin telah mengunci basis data, sementara kueri tim lain menghasilkan kesalahan yang dapat diamati.

Kegagalan satu simpul akan menjatuhkan semua orang.

Basis data bersama merupakan satu titik kegagalan. Jika basis data tersebut mati, maka banyak layanan akan ikut mati bersamanya. Jika basis data mengalami masalah kinerja karena permintaan yang besar dari satu layanan, semua layanan akan mengalami masalah. Dalam model dengan API dan kepemilikan data yang jelas, setiap tim menguasai ketersediaan dan kinerja layanan mereka, sehingga kegagalan pada satu komponen tidak akan menyebar ke komponen lainnya.

Menyediakan replika baca-saja yang terpisah tidak menyelesaikan masalah.

Kompromi yang umum adalah: “Kami akan memberi Anda replika baca-saja sehingga Anda dapat melakukan kueri tanpa memengaruhi basis data utama kami.” Awalnya, hal itu mungkin mengatasi beberapa masalah beban, tetapi:

  • Masalah versi masih ada. Masalah utamanya adalah, ketika struktur tabel utama berubah, struktur replika juga ikut berubah, hanya saja dengan sedikit penundaan.


  • Kelambatan replikasi dapat menyebabkan status data tidak dapat diprediksi, terutama pada kumpulan data besar.


  • Kepemilikannya masih belum jelas: Siapa yang menentukan format, struktur, dan aturan penggunaan? Replika masih merupakan "bagian" dari basis data milik orang lain.

Cara Mendesain Interaksi Layanan dengan Tepat (Kontrak Terlebih Dahulu)

Definisi kontrak yang eksplisit.

Praktik desain modern (misalnya, “API First” atau “Contract First”) dimulai dengan definisi antarmuka formal. Skema OpenAPI/Swagger, protobuf, atau GraphQL digunakan. Dengan cara ini, baik orang maupun mesin mengetahui titik akhir mana yang tersedia, kolom mana yang wajib diisi, dan tipe data apa yang digunakan.

Layanan sebagai Pemilik Data

Dalam arsitektur layanan mikro (atau bahkan modular), asumsinya adalah bahwa setiap layanan memiliki datanya sendiri secara keseluruhan. Layanan tersebut mendefinisikan struktur, penyimpanan, dan logika bisnis serta menyediakan API untuk semua akses eksternal ke API tersebut. Tidak seorang pun dapat menyentuh basis data 'milik orang lain': hanya titik akhir atau peristiwa resmi. Hal ini memudahkan setiap kali ada perubahan yang dipertanyakan dan selalu jelas siapa yang harus disalahkan.

Contoh Implementasi

  • REST/HTTP: Layanan menerbitkan titik akhir seperti GET /items , POST /items , dll., dan klien membuat permintaan dengan skema data yang terdefinisi dengan baik (DTO).


  • gRPC/protokol biner: Dalam gRPC/protobuf, layanan dan pesan didefinisikan secara formal dalam file .proto, dan perubahan cukup dilakukan pada file .proto tempat metode, permintaan, dan respons didefinisikan.


  • Berbasis peristiwa: Layanan yang memiliki data menerbitkan peristiwa ke broker seperti Kafka atau RabbitMQ, dan pelanggan menggunakannya. Kontrak di sini adalah format peristiwa. Perubahan struktural dilakukan melalui topik atau pesan yang memiliki versi.

Kontrol Versi

Apa pun modelnya, penerapan kontrol versi pada antarmuka adalah mungkin dan penting. Misalnya:

  • Dalam REST, kita memiliki /api/v1/… dan /api/v2/.


  • Dengan gRPC/protobuf, terdapat mekanisme yang kuat untuk kompatibilitas mundur/maju—bidang, pesan, dan metode baru dapat ditambahkan tanpa merusak klien lama sementara klien lain ditandai sebagai usang.


  • Dalam arsitektur berbasis peristiwa, Anda dapat menerbitkan format peristiwa lama dan baru secara paralel hingga semua konsumen bermigrasi.

Tanggung Jawab Terdistribusi

Prinsip dasarnya adalah bahwa tim yang memiliki data berhak memutuskan cara menyimpan dan mengelolanya, tetapi mereka tidak boleh memberikan akses tulis langsung ke layanan lain. Layanan lain harus melalui API, bukan mengedit data asing. Hal ini menghasilkan distribusi tanggung jawab yang lebih jelas: Jika layanan A rusak, maka layanan A bertanggung jawab untuk memperbaikinya, bukan layanan di sekitarnya.

Contoh Interaksi Layanan

Dalam Satu Tim

Sekilas, jika semuanya ada dalam satu tim, mengapa harus mempersulit dengan API? Kenyataannya, bahkan jika Anda memiliki satu produk yang dibagi menjadi beberapa modul, tabel bersama dapat menimbulkan masalah yang sama.


  • Lebih baik membuat "fasad" atau "layanan mikro" yang memiliki tabel `pesanan`, misalnya, dan kemudian modul lain (seperti analitik) memanggil fasad/layanan ini.


  • Hal ini menjaga prinsip kontrak tetap eksplisit dan menyederhanakan proses debugging.


Misalnya, layanan Pesanan adalah pemilik tabel pesanan, dan layanan Penagihan tidak mengakses tabel tersebut secara langsung – layanan ini membuat panggilan ke titik akhir layanan Pesanan untuk mendapatkan detail pesanan atau menandai pesanan sebagai sudah dibayar.

Antara Dua Tim

Pada tingkat yang lebih tinggi, ketika dua atau lebih tim bertanggung jawab atas area yang berbeda, prinsip-prinsipnya tetap sama. Misalnya:

  • Tim A bertanggung jawab atas layanan katalog produk yang berisi informasi tentang setiap item (harga, ketersediaan, atribut).


  • Tim B mengurus layanan keranjang belanja.


Jika Tim B secara langsung menanyakan tabel “Katalog” milik Tim A, setiap perubahan skema internal di A (misalnya, menambahkan kolom, mengubah struktur) dapat memengaruhi Tim B.


Pendekatan yang tepat adalah menggunakan API: Tim A menyediakan titik akhir seperti GET /catalog/items , GET /catalog/items/{id} , dll., dan Tim B menggunakan metode tersebut. Jika A mampu mendukung versi lama dan baru, mereka dapat merilis /v2, yang memberi waktu bagi B untuk bermigrasi.

Aspek Organisasi dan Manfaat

Komunikasi Transparan

Dengan kontrak formal, semua perubahan terlihat: di Swagger/OpenAPI, file .proto, atau dokumentasi acara. Setiap pembaruan dapat didiskusikan sebelumnya, diuji dengan benar, dan dijadwalkan, dengan strategi kompatibilitas mundur sesuai kebutuhan.

Pengembangan Lebih Cepat

Perubahan dalam satu layanan berdampak lebih kecil pada layanan lainnya. Tim tidak perlu khawatir akan "merusak" orang lain jika mereka mengelola bidang atau titik akhir baru dan lama dengan baik, sehingga memastikan transisi yang lancar.

Manajemen Akses dan Keamanan

Gateway API, autentikasi, dan otorisasi (JWT, OAuth) merupakan standar untuk layanan, tetapi hampir mustahil dengan tabel bersama. Lebih mudah untuk menyempurnakan akses (siapa yang dapat memanggil metode mana), menyimpan log, melacak statistik penggunaan, dan memberlakukan kuota. Hal ini membuat sistem lebih aman dan lebih dapat diprediksi.

Kesimpulan

Tabel bersama dalam basis data merupakan detail implementasi, bukan kesepakatan antara layanan, sehingga tidak dianggap sebagai kontrak. Banyaknya masalah (versi yang rumit, perubahan yang kacau, kepemilikan yang tidak jelas, risiko keamanan, dan kinerja) membuat pendekatan ini tidak dapat dipertahankan dalam jangka panjang.


Pendekatan yang tepat adalah Contract First yang berarti mendefinisikan interaksi melalui desain formal dan mengikuti prinsip bahwa setiap layanan tetap menjadi pemilik datanya. Hal ini tidak hanya membantu mengurangi utang teknis tetapi juga meningkatkan transparansi, mempercepat pengembangan produk, dan memungkinkan perubahan yang aman tanpa harus terlibat dalam pemadaman kebakaran atas skema basis data.


Ini merupakan masalah teknis (bagaimana merancang dan mengintegrasikan) dan masalah organisasi (bagaimana tim berkomunikasi dan mengelola perubahan). Jika Anda ingin produk Anda berkembang tanpa harus berhadapan dengan keadaan darurat yang tak berkesudahan terkait skema basis data, maka Anda harus mulai berpikir dalam hal kontrak daripada akses basis data langsung.