Come progettare un software estensibile (architettura plugin)?

Ho bisogno di alcune risorse che parlano di come progettare il tuo software per essere estensibile, cioè in modo che altre persone possano scrivere componenti aggiuntivi / plug-in che aggiungano funzionalità ad esso.

Che cosa mi consiglia? Qualche libro là fuori che discute l’argomento?
Preferirei qualcosa che sia breve e diretto; un po ‘di teoria e un mucchio di esempi concreti.

Non sto prendendo di mira una lingua specifica, voglio essere in grado di comprendere l’idea di base in modo da poterla implementare in qualsiasi lingua.

E per la stessa ragione, preferisco non farlo usando un framework che qualcun altro ha costruito (a meno che il framework non sia di altissimo livello, cioè non si nasconda troppo ), al momento voglio solo educarmi sul sobject e sperimentare vari modi per implementarlo. Inoltre, un framework di solito presuppone la conoscenza dell’utente sull’argomento.

AGGIORNARE

Non sto chiedendo di OOP o di permettere che le mie classi vengano ereditate. Sto parlando della progettazione di un’applicazione che verrà distribuita su un sistema, in modo che possa essere estesa da componenti aggiuntivi di terze parti dopo che è stata distribuita.

Ad esempio, Notepad ++ ha un’architettura plug-in in cui è ansible inserire un file .dll nella cartella plugins e aggiunge funzionalità all’applicazione che non era presente, come color-picking o inserimento di snippet o molte altre cose (una vasta gamma di funzionalità).

Se stiamo parlando di .NET, prova Scripting .NET applications con VBScript over su CodeProject. Un sacco di esempi concreti lì.

Di seguito sono riportati i siti che implementano varie tecniche di estensione delle applicazioni

  • ClearScript: rende V8, VBScript e JScript disponibili per le app .NET
  • CS-Script – Il motore di script C #
  • Architettura plugin usando C #
  • Opinio plugin architecture
  • Note sull’architettura plug-in di Eclipse
  • Framework di architettura plug-in per principianti
  • Architettura plugin Gecko
  • Architettura dei plugin di Fungimol

L’OSGI è un buon esempio pratico di un quadro tecnico che consente di fare ciò che si sta cercando .

La teoria è qui .

Il libro (gratis!) È lì .

L’estensibilità e la capacità di scrivere plug-in devono occuparsi del ciclo di vita del servizio

  • aggiungendo / rimuovendo servizio / plugin sul posto
  • gestire le dipendenze tra i servizi
  • gestione degli stati dei servizi (dichiarati, installati, avviati, fermati, …)

A cosa serve OSGI?

Una delle funzioni principali di un modulo è come una unità di distribuzione … qualcosa che possiamo build o scaricare e installare per estendere la funzionalità della nostra applicazione.

Troverai una buona introduzione qui , sulla nozione centrale di servizio (che è legata alla tua domanda, e che spiega alcuni problemi relativi ai servizi, componente chiave per l’estensibilità).

Estratto:

Perché i servizi sono così importanti se possono essere create così tante applicazioni senza di loro? Bene, i servizi sono il modo più conosciuto per separare i componenti software l’uno dall’altro.

Uno degli aspetti più importanti dei servizi è che riducono in modo significativo i problemi di caricamento della class perché funzionano con istanze di oggetti, non con nomi di class. Istanze create dal provider, non dal consumatore. La riduzione della complessità è abbastanza sorprendente

Non solo i servizi riducono al minimo la configurazione, ma riducono anche significativamente il numero di pacchetti condivisi.

Cerchi di raggiungere due obiettivi in ​​competizione:

  1. I componenti del tuo software devono esporre molto di loro stessi, in modo che possano essere riutilizzati
  2. I componenti del software devono esporre molto poco di se stessi, in modo che possano essere riutilizzati

Spiegazione: Per incoraggiare il riutilizzo del codice, dovresti essere in grado di estendere le classi esistenti e chiamare i loro metodi. Questo non è ansible quando i metodi sono dichiarati “privati” e le classi sono “definitive” (e non possono essere estese). Quindi per raggiungere questo objective, tutto dovrebbe essere pubblico e accessibile. Nessun dato o metodo privato.

Quando pubblichi la seconda versione del tuo software, scoprirai che molte delle idee della versione 1 erano semplicemente sbagliate. È necessario modificare molte interfacce o il codice, i nomi dei metodi, eliminare i metodi, interrompere l’API. Se lo fai, molte persone si allontaneranno. Quindi, per essere in grado di evolvere il tuo software, i componenti non devono esporre nulla che non sia assolutamente necessario, al costo del riutilizzo del codice.

Esempio: volevo osservare la posizione del cursore (caret) in un SWT StyledText. Il caret non è pensato per essere esteso. Se lo fai, scoprirai che il codice contiene verifiche come “questa è la class nel pacchetto org.eclipse.swt” e molti metodi sono privati, finali e quant’altro. Ho dovuto copiare circa 28 classi di SWT nel mio progetto solo per implementare questa funzione perché tutto è bloccato.

SWT è un buon framework da usare e un inferno da estendere.

Ovviamente c’è il famoso principio Open Closed – http://en.wikipedia.org/wiki/Open/closed_principle

Implementa i principi SOLID nella tua applicazione.

1. Principio della responsabilità unica: una class dovrebbe avere una sola responsabilità (vale a dire, solo un potenziale cambiamento nelle specifiche del software dovrebbe essere in grado di influenzare le specifiche della class

2. Principio aperto / chiuso : le entity framework software … dovrebbero essere aperte per l’estensione, ma chiuse per la modifica

3. Principio di sostituzione di Liskov: gli oggetti in un programma dovrebbero essere sostituibili con istanze dei loro sottotipi senza alterare la correttezza di quel programma

4. Principio di segregazione dell’interfaccia: molte interfacce specifiche per il cliente sono migliori di un’interfaccia generica

5. Principio di inversione delle dipendenze: si dovrebbe dipendere dalle astrazioni . Non dipendere dalle concrezioni

Domande StackOverflow:

Esempio di principio di responsabilità singola

Il principio aperto / chiuso è una buona idea?

Qual è il principio di sostituzione di Liskov?

Interfaccia Segregation Principle: programma su un’interfaccia

Qual è il principio di inversione delle dipendenze e perché è importante?

Beh, dipende dalla lingua.

  • In C / C ++ sono abbastanza sicuro che esista una funzione loadlibrary che consente di aprire una libreria in fase di runtime e invocare le sue funzioni esportate. Questo è in genere come è fatto in C / C ++.
  • In .NET, c’è Reflection, che offre offerte simili (ma più ampie) a loadlibrary. Ci sono anche intere librerie basate su Reflection come Managed Extension Framework, o Mono.Addins che fa già gran parte del lavoro pesante per te.
  • In Java, c’è anche Reflection. E c’è il JPF (Java Plugin Framework) che viene utilizzato in cose come Eclipse IIRC.

A seconda della lingua che utilizzi, potrei raccomandare alcuni tutorial / libri. Spero che questo sia stato utile.

L’articolo Scrivere applicazioni basate su plugin spiega chiaramente le responsabilità delle varie parti dell’architettura usando un esempio molto semplice; il codice sorgente è fornito (VB.Net). L’ho trovato molto utile per capire i concetti di base.

Checkout “CAB” – Framework di Building Application Building Blocks di Microsoft. Penso che abbiano anche una “versione web” di questo …

Ho appena iniziato a sviluppare un’applicazione client intelligente. Queste sono due opzioni che sto considerando.

Utilizzo dello spazio dei nomi System.AddIn di Microsoft. Sembra molto promettente, tuttavia potrebbe essere un po ‘complesso per la nostra soluzione finale.

O lo Smart Client – Blocco interfaccia utente composito di Microsoft

Recentemente, ho cercato di prendere i componenti sia del blocco di applicazioni dell’interfaccia utente composito che dello spazio dei nomi System.AddIn per creare il mio. Poiché il codice sorgente è disponibile per il CAB, è facile estenderlo. Penso che la nostra soluzione finale sarà una versione leggera del CAB, sicuramente utilizzando Unity Application Block

L’architettura dei plugin sta diventando molto popolare per la sua estensibilità e quindi la flessibilità.

Per c ++, il server httpd di Apache è in realtà basato su plugin, ma al suo posto viene utilizzato un concetto di modulo. La maggior parte delle funzionalità di Apache sono implementate come moduli, come cache, riscrittura, bilanciamento del carico e persino modello di threading. È un software molto modulare che abbia mai visto.

E per java, Eclipse è decisamente basato su plugin. Il nucleo di Eclipse è un sistema di moduli OSGI che gestisce i bundle, un altro concetto per i plugin. Bundle può fornire punti di estensione su cui possiamo build moduli con meno sforzi. La cosa più complessa in OSGI è la sua caratteristica dynamic, il che significa che i pacchetti possono essere installati o disinstallati in fase di runtime. Non c’è più la sindrome di stop-the-world!

Se lavori con .Net, la nostra ricerca ha prodotto due approcci: scripting e composizione.

Scripting

Estendi la funzionalità di ciò che le tue classi possono fare orchestrandole usando gli script. Ciò significa esporre ciò che è compilato nella tua lingua .Net preferita in un linguaggio dinamico.

Alcune opzioni che abbiamo trovato vale la pena esplorare:

  • IronPython
  • IronRuby
  • JavaScript: Jint , Jurassic e JavaScript .Net sono buoni punti di partenza.
  • Script.Net -> questo è stato il primo a richiamare la nostra attenzione.

Composizione

Se inizi un progetto con .Net 4 o successivo, devi dare un’occhiata al Managed Extensibility Framework (MEF). Ti consente di estendere la funzionalità delle tue app in modo plug-in.

Il Managed Extensibility Framework (MEF) è uno strato di composizione per .NET che migliora la flessibilità, la manutenibilità e la testabilità di applicazioni di grandi dimensioni. MEF può essere utilizzato per estensibilità di plug-in di terze parti, oppure può portare i benefici di un’architettura plug-in liberamente accoppiata alle normali applicazioni.

Anche l’Add-in Framework gestito è una buona lettura.

Dal momento che non ho abbastanza punti Rep per lasciare un commento, lo sto postando come risposta. SharpDevelop è un IDE per lo sviluppo di applicazioni in C # / VB.NET / Boo. Ha un’architettura piuttosto impressionante che si lascia estendere in diversi modi: dalle nuove voci di menu al supporto per lo sviluppo di lingue completamente nuove.

Usa un po ‘di configurazione XML per fungere da strato di colla tra un nucleo dell’IDE e l’implementazione del plugin. Gestisce l’individuazione, il caricamento e il controllo delle versioni dei plug-in fuori dalla scatola. La distribuzione di nuovi plug-in dipende semplicemente dalla copia nel nuovo file di configurazione xml e dagli assembly richiesti (DLL) e dal riavvio dell’applicazione. Potete leggere di più su questo nel libro “Dissecting a csharp application” dell’autore originale (s) – Christian Holm, Mike Krüger, Bernhard Spuida dell’applicazione da qui . Il libro sembra non essere disponibile su quel sito, ma ho trovato una copia che potrebbe ancora essere qui intorno

Inoltre ho trovato una domanda correlata qui

Piuttosto che reinventare la ruota, usa le strutture in mano. Eclipse e Netbeans supportano entrambe le estensioni basate su plugin. Devi lavorare in Java però.