Desain API: pendekatan konkret vs abstrak - praktik terbaik?

25

Ketika membahas API antar sistem (pada tingkat bisnis) sering ada dua sudut pandang yang berbeda di tim kami: beberapa orang lebih suka pendekatan abstrak yang lebih umum - katakanlah generik , yang lain pendekatan "konkret" yang lurus ke depan.

Contoh: desain API "pencarian orang" sederhana. versi konkretnya adalah

 searchPerson(String name, boolean soundEx,
              String firstName, boolean soundEx,
              String dateOfBirth)

Orang-orang yang mendukung versi konkret mengatakan:

  • API mendokumentasikan diri sendiri
  • mudah dimengerti
  • mudah untuk memvalidasi (kompiler atau sebagai layanan web: validasi skema)
  • CIUMAN

Grup orang lain di tim kami akan mengatakan "Itu hanya daftar kriteria pencarian"

searchPerson(List<SearchCriteria> criteria)

dengan

SearchCritera {
  String parameter,
  String value,
  Map<String, String> options
}

dengan kemungkinan membuat "parameter" dari beberapa jenis enumerasi.

Para pendukung mengatakan:

  • tanpa mengubah (deklarasi) API, implementasinya dapat berubah, misalnya menambahkan lebih banyak kriteria atau lebih banyak opsi. Bahkan tanpa menyinkronkan perubahan seperti itu pada waktu penempatan.
  • dokumentasi diperlukan bahkan dengan varian konkret
  • validasi skema berlebihan, seringkali Anda harus memvalidasi lebih lanjut, skema tidak dapat menangani semua kasus
  • kami sudah memiliki API serupa dengan sistem lain - digunakan kembali

Argumen tandingannya adalah

  • banyak dokumentasi tentang parameter yang valid dan kombinasi parameter yang valid
  • lebih banyak upaya komunikasi karena lebih sulit dipahami untuk tim lain

Apakah ada praktik terbaik? Literatur?

erik
sumber
3
diulang "String first / name, boolean soundEx" adalah pelanggaran yang jelas kering dan menunjukkan bahwa desain ini gagal untuk mengatasi fakta bahwa nama tersebut diharapkan sesuai dengan soundEx. Dihadapkan dengan kesalahan desain sederhana seperti itu, rasanya sulit untuk melanjutkan dengan analisis yang lebih canggih
Agak
Kebalikan dari "beton" bukan "generik", ini "abstrak". Abstraksi sangat penting untuk perpustakaan atau API, dan diskusi ini gagal untuk mengajukan pertanyaan yang benar-benar mendasar, dan bukan berfokus pada apa yang sebenarnya merupakan pertanyaan gaya yang agak sepele. FWIW, argumen tandingan untuk opsi B terdengar seperti beban FUD, Anda tidak perlu memerlukan dokumentasi atau komunikasi tambahan jika desain API bahkan setengah bersih dan mengikuti prinsip SOLID.
Aaronaught
@ Terima kasih karena menunjukkan itu ("abstrak"). Ini mungkin masalah terjemahan, "generisch" dalam bahasa Jerman terdengar masih oke untuk saya. Apa "pertanyaan mendasar" bagi Anda?
erik
4
@Aaronaught: Pertanyaannya bukan tentang abstrak. Koreksi yang tepat adalah kebalikan dari "generik" adalah "spesifik", bukan "konkret".
Jan Hudec
Pilihan lain untuk ini bukan tentang generik versus abstrak, tetapi generik versus spesifik. Contoh "konkret" di atas sebenarnya spesifik untuk nama, nama depan dan dateOfBirth, contoh lain adalah generik untuk parameter apa pun. Tidak ada yang abstrak. Saya akan mengedit judul tetapi saya tidak ingin memulai perang edit :-)
matt freake

Jawaban:

18

Itu tergantung pada berapa banyak bidang yang Anda bicarakan, dan bagaimana mereka digunakan. Beton lebih disukai untuk kueri yang sangat terstruktur dengan hanya beberapa bidang, tetapi jika kueri cenderung menjadi bentuk yang sangat bebas, maka pendekatan konkret dengan cepat menjadi sulit dengan lebih dari tiga atau empat bidang.

Di sisi lain, sangat sulit untuk menjaga API generik murni. Jika Anda melakukan pencarian nama sederhana di banyak tempat, pada akhirnya seseorang akan bosan mengulangi lima baris kode yang sama, dan mereka akan membungkusnya dalam suatu fungsi. API seperti itu selalu berevolusi menjadi hibrida dari permintaan umum bersama dengan pembungkus beton untuk pertanyaan yang paling umum digunakan. Dan saya tidak melihat ada yang salah dengan itu. Ini memberi Anda yang terbaik dari kedua dunia.

Karl Bielefeldt
sumber
7

Merancang API yang baik adalah seni. API yang baik dihargai bahkan setelah waktu berlalu. Menurut pendapat saya, seharusnya tidak ada bias umum pada garis abstrak-konkret. Beberapa parameter bisa sekonkret hari dalam seminggu, beberapa perlu dirancang untuk diperpanjang (dan itu cukup bodoh untuk membuatnya konkret, misalnya, bagian dari nama fungsi), namun yang lain mungkin lebih jauh dan untuk memiliki keanggunan API yang satu perlu menyediakan panggilan balik atau bahkan bahasa khusus domain akan membantu memerangi kompleksitas.

Jarang terjadi hal-hal baru di bawah Bulan. Lihatlah seni sebelumnya, terutama standar dan format yang ditetapkan (misalnya, banyak hal dapat dimodelkan setelah feed, deskripsi acara diuraikan dalam ical / vcal). Jadikan API Anda mudah tambahan, di mana entitas yang sering dan berada di mana-mana konkret dan ekstensi yang dibayangkan adalah kamus. Ada juga beberapa pola mapan untuk menghadapi situasi tertentu. Misalnya, menangani permintaan HTTP (dan yang serupa) dapat dimodelkan dalam API dengan objek Permintaan dan Respons.

Sebelum merancang API, bertukar pikiran tentang berbagai aspek, termasuk yang tidak akan disertakan, tetapi Anda harus sadar. Contohnya adalah bahasa, arah penulisan, pengodean, lokal, informasi zona waktu dan sejenisnya. Perhatikan tempat-tempat di mana kelipatan dapat muncul: gunakan daftar, bukan nilai tunggal untuk mereka. Misalnya, jika Anda menginginkan API untuk sistem videochat, API Anda akan jauh lebih bermanfaat, jika Anda mengasumsikan N peserta, bukan hanya dua (walaupun spesifikasi Anda saat ini demikian).

Kadang-kadang, menjadi abstrak membantu mengurangi kompleksitas secara drastis: bahkan jika Anda merancang kalkulator untuk menambahkan hanya 3 + 4, 2 + 2, dan 7 + 6, mungkin jauh lebih mudah untuk mengimplementasikan X + Y (dengan batasan yang secara teknis layak pada X dan Y, dan sertakan ADD (X, Y) ke API Anda alih-alih ADD_3_4 (), ADD_2_2 (), ...

Singkatnya, memilih satu cara atau lain hanyalah detail teknis. Dokumentasi Anda harus menggambarkan kasus penggunaan yang sering terjadi secara konkret.

Apa pun yang Anda lakukan di sisi struktur data, berikan bidang untuk versi API.

Untuk meringkas, API harus meminimalkan kompleksitas ketika berhadapan dengan perangkat lunak Anda. Untuk menghargai API, tingkat kompleksitas yang terekspos harus memadai. Memutuskan bentuk API sangat bergantung pada stabilitas domain masalah. Dengan demikian, harus ada beberapa estimasi pada arah mana perangkat lunak dan API itu akan tumbuh, karena informasi ini dapat mempengaruhi persamaan untuk kompleksitas. Juga, desing API ada untuk dipahami orang. Jika ada tradisi bagus di bidang teknologi perangkat lunak tempat Anda berada, cobalah untuk tidak menyimpang banyak darinya, karena itu akan membantu pemahaman. Mempertimbangkan untuk siapa Anda menulis. Pengguna yang lebih maju akan menghargai sifat umum dan fleksibilitas, sementara mereka yang kurang berpengalaman mungkin lebih nyaman dengan konkret. Namun, perhatikan sebagian besar pengguna API di sana,

Di sisi literatur saya dapat merekomendasikan "Kode Indah" Programmer Terkemuka Jelaskan Bagaimana Mereka Berpikir Oleh Andy Oram, Greg Wilson, karena saya pikir kecantikan adalah tentang merasakan optimalitas tersembunyi (dan kesesuaian untuk beberapa tujuan).

Roman Susi
sumber
1

Preferensi pribadi saya bersifat abstrak, namun kebijakan perusahaan saya mengunci saya agar menjadi konkret. Itulah akhir dari perdebatan untuk saya :)

Anda telah melakukan pro dan kontra daftar pekerjaan yang bagus untuk kedua pendekatan, dan jika Anda terus menggali Anda akan menemukan banyak argumen yang mendukung kedua belah pihak. Selama arsitektur API Anda dikembangkan dengan benar - artinya Anda telah memikirkan bagaimana itu akan digunakan hari ini dan bagaimana ia dapat berevolusi dan tumbuh di masa depan - maka Anda harus baik-baik saja.

Inilah dua bookmark yang saya miliki dengan sudut pandang yang berlawanan:

Mendukung Kelas Abstrak

Mendukung Interfaces

Tanyakan kepada diri Anda sendiri: "Apakah API memenuhi persyaratan bisnis saya? Apakah saya memiliki kriteria keberhasilan yang terdefinisi dengan baik? Bisakah ini ditingkatkan?". Itu tampak seperti praktik terbaik yang benar-benar sederhana untuk diikuti, tetapi sejujurnya itu jauh lebih penting daripada konkret vs generik.

gws2
sumber
1

Saya tidak akan mengatakan bahwa API abstrak tentu lebih sulit untuk divalidasi. Jika parameter kriteria cukup sederhana dan memiliki sedikit ketergantungan antara satu sama lain, itu tidak membuat banyak perbedaan apakah Anda melewatkan parameter secara terpisah atau dalam array. Anda masih perlu memvalidasi semuanya. Tapi itu tergantung pada desain parameter kriteria dan objek itu sendiri.

Jika API cukup kompleks, memiliki metode konkret bukanlah suatu pilihan. Pada titik tertentu Anda mungkin akan berakhir dengan salah satu metode dengan banyak parameter atau terlalu banyak metode sederhana yang tidak akan mencakup semua kasus penggunaan yang diperlukan. Sejauh pengalaman pribadi saya dalam merancang API yang digunakan, lebih baik memiliki metode yang lebih umum pada tingkat API dan menerapkan pembungkus yang diperlukan khusus pada tingkat aplikasi.

Pavels
sumber
1

Argumen perubahan harus diberhentikan dengan YAGNI. Pada dasarnya, kecuali jika Anda benar-benar memiliki setidaknya 3 kasus penggunaan berbeda yang menggunakan API generik berbeda, kemungkinan Anda mendesainnya cukup rendah sehingga tidak harus berubah ketika kasus penggunaan berikutnya muncul (dan ketika Anda memiliki penggunaan- kasus, Anda jelas membutuhkan antarmuka generik, titik). Jadi jangan berusaha dan bersiap untuk perubahan.

Perubahan tidak perlu disinkronkan untuk penerapan dalam kedua kasus. Saat Anda menggeneralisasi antarmuka nanti, Anda selalu dapat menyediakan antarmuka yang lebih spesifik untuk kompatibilitas mundur. Namun dalam praktiknya penyebaran apa pun akan memiliki begitu banyak perubahan sehingga Anda akan menyinkronkannya sehingga Anda tidak perlu menguji kondisi perantara. Saya tidak akan melihat itu sebagai argumen juga.

Adapun dokumentasi, salah satu solusi mungkin mudah digunakan dan jelas. Tapi itu merupakan argumen penting. Terapkan antarmuka sehingga akan mudah digunakan dalam kasus Anda yang sebenarnya. Kadang-kadang spesifik mungkin lebih baik dan kadang-kadang generik mungkin.

Jan Hudec
sumber
1

Saya lebih menyukai pendekatan antarmuka abstrak. Untuk mengajukan pertanyaan ke layanan (pencarian) semacam itu adalah masalah umum dan kemungkinan akan terjadi lagi. Selain itu, Anda mungkin akan menemukan lebih banyak kandidat layanan yang cocok untuk menggunakan kembali antarmuka yang lebih umum. Untuk dapat menyediakan antarmuka umum yang koheren untuk layanan tersebut, saya tidak akan menyebutkan parameter kueri yang saat ini diidentifikasi dalam definisi antarmuka.

Seperti yang telah ditunjukkan sebelumnya - Saya suka kesempatan untuk mengubah atau memperluas implementasi tanpa memodifikasi antarmuka. Menambahkan kriteria pencarian lain tidak harus tercermin dalam definisi layanan.

Meskipun tidak ada pertanyaan untuk mendesain antarmuka yang terdefinisi dengan baik, ringkas dan ekspresif Anda harus selalu memberikan beberapa dokumentasi tambahan. Menambahkan ruang lingkup definisi untuk kriteria pencarian yang valid bukanlah beban seperti itu.

0x0me
sumber
1

Ringkasan terbaik yang pernah saya lihat adalah skala Rusty, sekarang disebut manifesto Desain API Rusty . Saya hanya bisa sangat merekomendasikan yang itu. Demi kelengkapan, saya mengutip ringkasan skala dari tautan pertama (lebih baik di atas, lebih buruk di bawah):

API yang bagus

  • Tidak mungkin salah.
  • Compiler / linker tidak akan membiarkan Anda melakukan kesalahan.
  • Kompiler akan memperingatkan jika Anda salah.
  • Penggunaan yang jelas adalah (mungkin) yang benar.
  • Nama memberi tahu Anda cara menggunakannya.
  • Lakukan dengan benar atau akan selalu rusak saat runtime.
  • Ikuti konvensi umum dan Anda akan memperbaikinya.
  • Baca dokumentasi dan Anda akan memperbaikinya.
  • Baca implementasinya dan Anda akan melakukannya dengan benar.
  • Baca utas milis yang benar dan Anda akan melakukannya dengan benar.

API buruk

  • Baca utas milis dan Anda akan salah.
  • Baca implementasinya dan Anda akan salah.
  • Baca dokumentasinya dan Anda akan salah.
  • Ikuti konvensi umum dan Anda akan salah.
  • Lakukan dengan benar dan kadang-kadang akan rusak saat runtime.
  • Namanya memberitahu Anda bagaimana tidak menggunakannya.
  • Penggunaan yang jelas salah.
  • Kompiler akan memperingatkan jika Anda melakukannya dengan benar.
  • Compiler / linker tidak akan membiarkan Anda melakukannya dengan benar.
  • Tidak mungkin untuk menjadi benar.

Kedua halaman detail di sini dan di sini hadir dengan diskusi mendalam tentang setiap poin. Ini benar-benar harus dibaca untuk desainer API. Terima kasih Rusty, jika Anda pernah membaca ini.

JensG
sumber
0

Dalam kata-kata awam:

  • Pendekatan abstrak memiliki keunggulan memungkinkan untuk membangun metode konkret di sekitarnya.
  • Cara sebaliknya tidak benar
Tulains Córdova
sumber
UDP memiliki keunggulan memungkinkan Anda membangun aliran andal Anda sendiri. Jadi mengapa hampir semua orang menggunakan TCP?
svick
Ada juga pertimbangan sebagian besar kasus penggunaan. Beberapa kasus mungkin sangat dibutuhkan, sehingga layak untuk membuat kasus-kasus tersebut istimewa.
Roman Susi
0

Jika Anda sedikit memperluas SearchCriteriaide, itu dapat memberi Anda fleksibilitas seperti membuat AND, ORdll kriteria. Jika Anda memerlukan fungsionalitas seperti itu, ini akan menjadi pendekatan yang lebih baik.

Kalau tidak, desain untuk kegunaan. Jadikan API mudah bagi orang yang menggunakannya. Jika Anda memiliki beberapa fungsi dasar yang sering dibutuhkan (seperti mencari seseorang dengan namanya), berikan secara langsung. Jika pengguna tingkat lanjut memerlukan pencarian lanjutan, mereka masih dapat menggunakan SearchCriteria.

Uooo
sumber
0

Apa kode di belakang API lakukan? Jika itu sesuatu yang fleksibel maka API fleksibel itu bagus. Jika kode di balik API sangat spesifik maka menempatkan wajah yang fleksibel di atasnya hanya berarti pengguna API akan frustrasi dan kesal pada semua hal yang berpura-pura API mungkin tetapi sebenarnya tidak dapat dicapai.

Untuk contoh pencarian orang Anda, apakah ketiga bidang ini wajib diisi? Jika demikian maka daftar kriteria buruk karena memungkinkan banyak penggunaan yang tidak berfungsi. Jika tidak maka mengharuskan pengguna untuk menentukan input yang tidak diperlukan adalah buruk. Seberapa besar kemungkinan pencarian berdasarkan alamat akan ditambahkan dalam V2? Antarmuka yang fleksibel membuatnya lebih mudah untuk ditambahkan daripada yang tidak fleksibel.

Tidak setiap sistem perlu menjadi sangat fleksibel, mencoba untuk membuat semuanya jadi Arsitektur Astronauting. Busur yang fleksibel menembakkan panah. Pedang yang fleksibel bermanfaat seperti ayam karet.

stonemetal
sumber