Bagaimana Cara Membuat Arsitektur Plug-In Fleksibel?

154

Tema berulang dalam karya pengembangan saya adalah penggunaan atau pembuatan arsitektur plug-in in-house. Saya telah melihatnya mendekati banyak cara - file konfigurasi (XML, .conf, dan sebagainya), kerangka kerja pewarisan, informasi basis data, perpustakaan, dan lainnya. Dalam pengalaman saya:

  • Basis data bukan tempat yang bagus untuk menyimpan informasi konfigurasi Anda, terutama yang digabungkan dengan data
  • Mencoba ini dengan hierarki warisan membutuhkan pengetahuan tentang plug-in yang akan dikodekan, artinya arsitektur plug-in tidak terlalu dinamis
  • File konfigurasi berfungsi dengan baik untuk memberikan informasi sederhana, tetapi tidak dapat menangani perilaku yang lebih kompleks
  • Perpustakaan tampaknya berfungsi dengan baik, tetapi dependensi satu arah harus dibuat dengan cermat.

Ketika saya berusaha untuk belajar dari berbagai arsitektur yang telah saya kerjakan, saya juga mencari saran untuk komunitas. Bagaimana Anda menerapkan arsitektur plug-in SOLID? Apa kegagalan terburuk Anda (atau kegagalan terburuk yang pernah Anda lihat)? Apa yang akan Anda lakukan jika Anda akan mengimplementasikan arsitektur plug-in baru? SDK atau proyek sumber terbuka apa yang telah Anda kerjakan memiliki contoh terbaik arsitektur yang bagus?

Beberapa contoh yang saya temukan sendiri:

Contoh-contoh ini tampaknya memainkan berbagai kekuatan bahasa. Apakah arsitektur plugin yang baik harus dikaitkan dengan bahasa? Apakah yang terbaik untuk menggunakan alat untuk membuat arsitektur plugin, atau melakukannya pada model berikut sendiri?

justkt
sumber
Bisakah Anda mengatakan mengapa arsitektur plugin menjadi tema umum? Masalah apa yang dipecahkan, atau tujuan yang ditujuinya? Banyak sistem / aplikasi yang dapat dikembangkan menggunakan plugin dari beberapa bentuk, tetapi bentuknya sangat bervariasi tergantung pada masalah yang dipecahkan.
mdma
@mdma - itu pertanyaan yang bagus. Saya akan mengatakan ada beberapa tujuan umum dalam sistem yang dapat diperluas. Mungkin tujuan yang umum, dan solusi terbaik bervariasi tergantung pada seberapa luas sistem perlu, bahasa apa sistem itu ditulis, dan sebagainya. Namun, saya melihat pola-pola seperti IOC diterapkan di banyak negara, dan saya telah diminta untuk melakukan plugin yang sama (untuk potongan demi potongan menanggapi permintaan fungsi yang sama) berulang kali. Saya pikir itu baik untuk mendapatkan ide umum praktik terbaik untuk berbagai jenis plugin.
justkt

Jawaban:

89

Ini bukan jawaban sebanyak sekelompok komentar / contoh yang berpotensi berguna.

  • Salah satu cara efektif untuk membuat aplikasi Anda bisa dikembangkan adalah dengan mengekspos internalnya sebagai bahasa scripting dan menulis semua hal tingkat atas dalam bahasa itu. Ini membuatnya cukup dimodifikasi dan praktis menjadi bukti masa depan (jika primitif Anda dipilih dan diimplementasikan dengan baik). Kisah sukses dari hal semacam ini adalah Emacs. Saya lebih suka ini daripada sistem plugin gaya eclipse karena jika saya ingin memperluas fungsionalitas, saya tidak perlu mempelajari API dan menulis / kompilasi plugin terpisah. Saya dapat menulis cuplikan 3 baris di buffer saat ini, mengevaluasinya, dan menggunakannya. Kurva belajar yang sangat halus dan hasil yang sangat menyenangkan.

  • Salah satu aplikasi yang saya tambahkan sedikit adalah Trac . Ini memiliki arsitektur komponen yang dalam situasi ini berarti bahwa tugas didelegasikan ke modul yang mengiklankan poin ekstensi. Anda kemudian dapat mengimplementasikan komponen lain yang sesuai dengan poin-poin ini dan mengubah alurnya. Ini sedikit seperti saran Kalkie di atas.

  • Satu lagi yang bagus adalah py.test . Ini mengikuti filosofi "API terbaik bukan API" dan hanya mengandalkan kait yang dipanggil di setiap level. Anda dapat mengganti kait ini dalam file / fungsi yang dinamai sesuai dengan konvensi dan mengubah perilaku. Anda dapat melihat daftar plugin di situs untuk melihat seberapa cepat / mudah mereka dapat diimplementasikan.

Beberapa poin umum.

  • Cobalah untuk menjaga agar inti yang tidak dapat diperluas / tidak dapat diubah pengguna sekecil mungkin. Delegasikan semua yang Anda bisa ke lapisan yang lebih tinggi sehingga ekstensibilitas meningkat. Lebih sedikit barang untuk dikoreksi di inti maka dalam kasus pilihan yang buruk.
  • Terkait dengan poin di atas adalah bahwa Anda tidak boleh membuat terlalu banyak keputusan tentang arah proyek Anda di awal. Terapkan subset terkecil yang dibutuhkan dan kemudian mulai menulis plugin.
  • Jika Anda menyematkan bahasa scripting, pastikan itu bahasa yang lengkap di mana Anda dapat menulis program umum dan bukan bahasa mainan hanya untuk aplikasi Anda.
  • Kurangi boilerplate sebanyak yang Anda bisa. Jangan repot-repot dengan subkelas, API kompleks, pendaftaran plugin, dan hal-hal seperti itu. Cobalah untuk membuatnya tetap sederhana agar mudah dan tidak hanya mungkin untuk diperpanjang. Ini akan membuat API plugin Anda digunakan lebih banyak dan akan mendorong pengguna akhir untuk menulis plugin. Bukan hanya pengembang plugin. py.test melakukan ini dengan baik. Gerhana sejauh yang saya tahu, tidak .
Noufal Ibrahim
sumber
1
Saya akan memperluas titik bahasa scripting ke hal itu layak mempertimbangkan untuk menanamkan bahasa yang ada seperti python atau perl
Rudi
Rudi yang sebenarnya. Banyak bahasa sedang dibuat ini dirancang untuk disematkan. Tipu muslihat, dibuat hanya untuk menanamkan. Ini menghemat waktu jika Anda membuat skrip aplikasi Anda. Anda bisa memasukkan salah satu bahasa ini.
Noufal Ibrahim
24

Dalam pengalaman saya, saya benar-benar menemukan dua jenis arsitektur plug-in.

  1. Seseorang mengikuti Eclipse modelyang dimaksudkan untuk memungkinkan kebebasan dan terbuka.
  2. Yang lain biasanya membutuhkan plugin untuk mengikuti narrow APIkarena plugin akan mengisi fungsi tertentu.

Untuk menyatakan ini dengan cara yang berbeda, satu memungkinkan plugin untuk mengakses aplikasi Anda sementara yang lain memungkinkan aplikasi Anda untuk mengakses plugin .

Perbedaannya halus, dan kadang-kadang tidak ada gangguan ... Anda menginginkan keduanya untuk aplikasi Anda.

Saya tidak punya banyak pengalaman dengan Eclipse / Membuka model App to plugins Anda (artikel di posting Kalkie sangat bagus). Saya sudah membaca sedikit tentang cara gerhana melakukan sesuatu, tetapi tidak lebih dari itu.

Blog properti Yegge berbicara sedikit tentang bagaimana penggunaan pola properti memungkinkan plugin dan ekstensibilitas.

Sebagian besar pekerjaan yang saya lakukan telah menggunakan arsitektur plugin untuk memungkinkan aplikasi saya mengakses plugin, hal-hal seperti data waktu / tampilan / peta, dll.

Bertahun-tahun lalu saya akan membuat pabrik, pengelola plugin, dan file konfigurasi untuk mengelola semuanya dan biarkan saya menentukan plugin mana yang akan digunakan saat runtime.

  • Sekarang saya biasanya hanya DI frameworkmelakukan sebagian besar pekerjaan itu.

Saya masih harus menulis adaptor untuk menggunakan perpustakaan pihak ketiga, tetapi mereka biasanya tidak terlalu buruk.

menjaraz
sumber
@ Just ya, DI = injeksi ketergantungan.
derivasi
14

Salah satu arsitektur plug-in terbaik yang pernah saya lihat diimplementasikan di Eclipse. Alih-alih memiliki aplikasi dengan model plug-in, semuanya adalah plug-in. Aplikasi dasar itu sendiri adalah kerangka kerja plug-in.

http://www.eclipse.org/articles/Article-Plug-in-architecture/plugin_architecture.html

Patrick
sumber
Tentu saja contoh yang bagus, tetapi apakah ini lebih besar dan lebih kompleks daripada yang dibutuhkan banyak aplikasi?
justkt
Ya bisa jadi, peningkatan fleksibilitas disertai dengan biaya. Tapi saya pikir ini menunjukkan sudut pandang yang berbeda. Mengapa menu aplikasi Anda tidak bisa menjadi plug-in atau tampilan utama?
Patrick
6
Pendekatan yang sama (semuanya adalah plugin) digunakan dalam versi baru kerangka kerja Symfony. Mereka disebut bundel tetapi prinsipnya sama. Arsitekturnya cukup sederhana, mungkin Anda harus melihatnya: symfony-reloaded.org/quick-tour-part-4
Marijn Huizendveld
@Marjin Huizendveld - Anda harus menambahkan ini sebagai jawaban yang terpisah sehingga saya dapat meningkatkan jawaban Tampak seperti kerangka kerja yang menarik!
justkt
11

Saya akan menjelaskan teknik yang cukup sederhana yang saya gunakan di masa lalu. Pendekatan ini menggunakan refleksi C # untuk membantu dalam proses pemuatan plugin. Teknik ini dapat dimodifikasi sehingga berlaku untuk C ++ tetapi Anda kehilangan kenyamanan karena dapat menggunakan refleksi.

Sebuah IPluginantarmuka digunakan untuk mengidentifikasi kelas yang mengimplementasikan plugin. Metode ditambahkan ke antarmuka untuk memungkinkan aplikasi berkomunikasi dengan plugin. Misalnya Initmetode yang akan digunakan aplikasi untuk menginstruksikan plugin untuk menginisialisasi.

Untuk menemukan plugin, aplikasi memindai folder plugin untuk .Net assemblies. Setiap unit dimuat. Refleksi digunakan untuk memindai kelas yang mengimplementasikan IPlugin. Sebuah instance dari setiap kelas plugin dibuat.

(Atau, file Xml dapat mendaftar majelis dan kelas untuk memuat. Ini mungkin membantu kinerja tetapi saya tidak pernah menemukan masalah dengan kinerja).

The Initmetode ini disebut untuk setiap objek Plugin. Itu diberikan referensi ke objek yang mengimplementasikan antarmuka aplikasi: IApplication(atau sesuatu yang bernama khusus untuk aplikasi Anda, misalnya ITextEditorApplication).

IApplicationberisi metode yang memungkinkan plugin untuk berkomunikasi dengan aplikasi. Misalnya jika Anda menulis editor teks antarmuka ini akan memiliki OpenDocumentsproperti yang memungkinkan plugin untuk menyebutkan koleksi dokumen yang sedang terbuka.

Sistem plugin ini dapat diperluas ke bahasa scripting, misalnya Lua, dengan membuat kelas plugin turunan, misalnya LuaPluginyang meneruskan IPluginfungsi dan antarmuka aplikasi ke skrip Lua.

Teknik ini memungkinkan Anda untuk secara iteratif mengimplementasikan antarmuka Anda IPlugin, IApplicationdan aplikasi khusus lainnya selama pengembangan. Ketika aplikasi selesai dan refactored dengan baik, Anda dapat mendokumentasikan antarmuka Anda yang terbuka dan Anda harus memiliki sistem yang bagus di mana pengguna dapat menulis plugin mereka sendiri.

Ashley Davis
sumber
7

Biasanya saya menggunakan MEF. Kerangka Kerja Diperpanjang yang Dikelola (atau disingkat MEF) menyederhanakan pembuatan aplikasi yang dapat dikembangkan. MEF menawarkan kemampuan penemuan dan komposisi yang dapat Anda manfaatkan untuk memuat ekstensi aplikasi.

Jika Anda tertarik baca lebih lanjut ...

BALKANGraph
sumber
Terima kasih, terlihat menarik. Seberapa mudahnya menerapkan prinsipal yang serupa di seluruh bahasa lain?
justkt
Sebenarnya MEF hanya untuk .NET framework Saya tidak tahu apa-apa tentang framework lainnya
BALKANGraph
7

Saya pernah bekerja pada sebuah proyek yang harus sangat fleksibel dalam cara setiap pelanggan dapat mengatur sistem, yang satu-satunya desain bagus yang kami temukan adalah untuk mengirimkan kompiler C # kepada pelanggan!

Jika spec diisi dengan kata-kata seperti:

  • Fleksibel
  • Plug-In
  • Dapat disesuaikan

Ajukan banyak pertanyaan tentang bagaimana Anda akan mendukung sistem (dan bagaimana dukungan akan dikenakan biaya, karena setiap pelanggan akan berpikir kasus mereka adalah kasus normal dan seharusnya tidak memerlukan plug-in.), Seperti dalam pengalaman saya

Dukungan pelanggan (atau orang-orang pendukung sumber) menulis Plug-Ins jauh lebih sulit daripada Arsitektur

Ian Ringrose
sumber
5

Dalam pengalaman saya, dua cara terbaik untuk membuat arsitektur plugin yang fleksibel adalah bahasa scripting dan perpustakaan. Kedua konsep ini dalam ingatan saya ortogonal; keduanya dapat dicampur dalam proporsi apa pun, lebih suka pemrograman fungsional dan berorientasi objek, tetapi menemukan kekuatan terbesar mereka ketika seimbang. Pustaka biasanya bertanggung jawab untuk memenuhi antarmuka tertentu dengan fungsionalitas dinamis, sedangkan skrip cenderung menekankan fungsionalitas dengan antarmuka dinamis.

Saya telah menemukan bahwa arsitektur yang didasarkan pada skrip yang mengelola perpustakaan tampaknya berfungsi paling baik. Bahasa scripting memungkinkan manipulasi tingkat tinggi dari perpustakaan tingkat rendah, dan perpustakaan dengan demikian dibebaskan dari antarmuka tertentu, meninggalkan semua interaksi tingkat aplikasi di tangan yang lebih fleksibel dari sistem scripting.

Agar ini berfungsi, sistem skrip harus memiliki API yang cukup kuat, dengan kaitan ke data aplikasi, logika, dan GUI, serta fungsi dasar mengimpor dan mengeksekusi kode dari perpustakaan. Lebih lanjut, skrip biasanya diperlukan untuk aman dalam arti bahwa aplikasi dapat dengan anggun pulih dari skrip yang ditulis dengan buruk. Menggunakan sistem scripting sebagai lapisan tipuan berarti bahwa aplikasi dapat lebih mudah melepaskan diri dalam kasus Sesuatu Buruk ™.

Sarana pengemasan plugin sebagian besar tergantung pada preferensi pribadi, tetapi Anda tidak pernah bisa salah dengan arsip terkompresi dengan antarmuka yang sederhana, katakanlah PluginName.extdi direktori root.

Jon Purdy
sumber
3

Saya pikir Anda harus terlebih dahulu menjawab pertanyaan: "Komponen apa yang diharapkan menjadi plugin?" Anda ingin menyimpan angka ini ke minimum absolut atau jumlah kombinasi yang harus Anda uji meledak. Cobalah untuk memisahkan produk inti Anda (yang seharusnya tidak memiliki terlalu banyak fleksibilitas) dari fungsionalitas plugin.

Saya telah menemukan bahwa kepala IOC (Inversion of Control) (baca springframework) bekerja dengan baik untuk memberikan basis yang fleksibel, yang dapat Anda tambahkan spesialisasi untuk membuat pengembangan plugin lebih sederhana.

  • Anda dapat memindai wadah untuk mekanisme "antarmuka sebagai iklan jenis plugin".
  • Anda dapat menggunakan wadah untuk menyuntikkan dependensi umum yang mungkin diperlukan plugin (yaitu ResourceLoaderAware atau MessageSourceAware).
Justin
sumber
1

Pola Plug-in adalah pola perangkat lunak untuk memperluas perilaku kelas dengan antarmuka yang bersih. Seringkali perilaku kelas diperluas dengan pewarisan kelas, di mana kelas turunan menimpa beberapa metode virtual kelas. Masalah dengan solusi ini adalah bahwa itu bertentangan dengan implementasi persembunyian. Ini juga mengarah pada situasi di mana kelas turunan menjadi tempat berkumpulnya ekstensi perilaku yang tidak terkait. Juga, scripting digunakan untuk menerapkan pola ini seperti yang disebutkan di atas "Jadikan internal sebagai bahasa scripting dan tulis semua hal tingkat atas dalam bahasa itu. Ini membuatnya cukup dapat dimodifikasi dan praktis menjadi bukti di masa depan". Perpustakaan menggunakan perpustakaan yang mengelola skrip. Bahasa scripting memungkinkan manipulasi tingkat tinggi dari perpustakaan tingkat bawah. (Juga seperti yang disebutkan di atas)

PresB4Me
sumber