Un tema recurrente en mi trabajo de desarrollo ha sido el uso o la creación de una arquitectura de plug-in interna. Lo he visto acercarse de muchas maneras: archivos de configuración (XML, .conf, etc.), marcos de herencia, información de bases de datos, bibliotecas y otros. En mi experiencia:
- Una base de datos no es un gran lugar para almacenar su información de configuración, especialmente combinada con datos
- Intentar esto con una jerarquía de herencia requiere conocimiento sobre los complementos a codificar, lo que significa que la arquitectura de complementos no es tan dinámica
- Los archivos de configuración funcionan bien para proporcionar información simple, pero no pueden manejar comportamientos más complejos
- Las bibliotecas parecen funcionar bien, pero las dependencias unidireccionales deben crearse cuidadosamente.
Mientras busco aprender de las diversas arquitecturas con las que he trabajado, también estoy buscando sugerencias en la comunidad. ¿Cómo ha implementado una arquitectura de complemento SOLID? ¿Cuál fue tu peor fracaso (o el peor fracaso que has visto)? ¿Qué haría si implementara una nueva arquitectura de plug-in? ¿Qué SDK o proyecto de código abierto con el que has trabajado tiene el mejor ejemplo de una buena arquitectura?
Algunos ejemplos que he encontrado por mi cuenta:
- Módulo de Perl :: Enchufable y COI para inyección de dependencia en Perl
- Los diversos frameworks Spring (Java, .NET, Python) para la inyección de dependencias.
- Una pregunta SO con una lista para Java (incluidas las interfaces de proveedor de servicios )
- Una pregunta SO para C ++ que apunta a un artículo del Dr. Dobbs
- Una pregunta SO con respecto a una idea de complemento específica para ASP.NET MVC
Estos ejemplos parecen jugar con varias fortalezas del lenguaje. ¿Una buena arquitectura de complementos está necesariamente vinculada al lenguaje? ¿Es mejor usar herramientas para crear una arquitectura de plugin, o hacerlo en los siguientes modelos?
Respuestas:
Esta no es una respuesta tanto como un montón de comentarios / ejemplos potencialmente útiles.
Una forma efectiva de hacer que su aplicación sea extensible es exponer sus elementos internos como un lenguaje de script y escribir todas las cosas de nivel superior en ese idioma. Esto lo hace bastante modificable y prácticamente a prueba de futuro (si sus primitivas están bien elegidas e implementadas). Una historia de éxito de este tipo de cosas es Emacs. Prefiero esto al sistema de complementos de estilo eclipse porque si quiero ampliar la funcionalidad, no tengo que aprender la API y escribir / compilar un complemento por separado. Puedo escribir un fragmento de 3 líneas en el búfer actual, evaluarlo y usarlo. Curva de aprendizaje muy suave y resultados muy agradables.
Una aplicación que he extendido un poco es Trac . Tiene una arquitectura de componentes que, en esta situación, significa que las tareas se delegan en módulos que anuncian puntos de extensión. Luego puede implementar otros componentes que encajarían en estos puntos y cambiar el flujo. Es un poco como la sugerencia de Kalkie anterior.
Otro que es bueno es py.test . Sigue la filosofía de "la mejor API no es API" y se basa únicamente en ganchos que se llaman en todos los niveles. Puede anular estos enlaces en archivos / funciones nombrados de acuerdo con una convención y alterar el comportamiento. Puede ver la lista de complementos en el sitio para ver qué tan rápido / fácil pueden implementarse.
Algunos puntos generales.
fuente
En mi experiencia, he encontrado que realmente hay dos tipos de arquitecturas de complemento.
Eclipse model
que está destinado a permitir la libertad y es abierto.narrow API
porque el complemento completará una función específica.Para decir esto de una manera diferente, uno permite que los complementos accedan a su aplicación, mientras que el otro permite que su aplicación acceda a los complementos .
La distinción es sutil y, a veces, no hay discreción ... desea ambos para su aplicación.
No tengo mucha experiencia con Eclipse / Abrir tu aplicación al modelo de complementos (el artículo en la publicación de Kalkie es genial). He leído un poco sobre la forma en que eclipse hace las cosas, pero nada más que eso.
El blog de propiedades de Yegge habla un poco sobre cómo el uso del patrón de propiedades permite complementos y extensibilidad.
La mayor parte del trabajo que he realizado ha utilizado una arquitectura de complementos para permitir que mi aplicación acceda a complementos, cosas como tiempo / visualización / datos de mapas, etc.
Hace años, creé fábricas, administradores de complementos y archivos de configuración para administrar todo y me permitieron determinar qué complemento usar en tiempo de ejecución.
DI framework
hacer la mayor parte de ese trabajo.Todavía tengo que escribir adaptadores para usar bibliotecas de terceros, pero generalmente no son tan malos.
fuente
Una de las mejores arquitecturas de complementos que he visto se implementa en Eclipse. En lugar de tener una aplicación con un modelo de complemento, todo es un complemento. La aplicación base en sí es el marco del complemento.
http://www.eclipse.org/articles/Article-Plug-in-architecture/plugin_architecture.html
fuente
Describiré una técnica bastante simple que he usado en el pasado. Este enfoque utiliza la reflexión de C # para ayudar en el proceso de carga del complemento. Esta técnica se puede modificar para que sea aplicable a C ++, pero pierde la conveniencia de poder usar la reflexión.
Se
IPlugin
utiliza una interfaz para identificar clases que implementan complementos. Se agregan métodos a la interfaz para permitir que la aplicación se comunique con el complemento. Por ejemplo, elInit
método que utilizará la aplicación para indicar al complemento que se inicialice.Para buscar complementos, la aplicación escanea una carpeta de complementos en busca de ensamblados .Net. Cada conjunto está cargado. La reflexión se utiliza para buscar clases que implementan
IPlugin
. Se crea una instancia de cada clase de complemento.(Alternativamente, un archivo Xml puede enumerar los ensamblados y las clases para cargar. Esto podría ayudar al rendimiento, pero nunca encontré un problema con el rendimiento).
Se
Init
llama al método para cada objeto de complemento. Se le pasa una referencia a un objeto que implementa la interfaz de la aplicación:IApplication
(o algo más llamado específico para su aplicación, por ejemplo, ITextEditorApplication).IApplication
contiene métodos que permiten que el complemento se comunique con la aplicación. Por ejemplo, si está escribiendo un editor de texto, esta interfaz tendría unaOpenDocuments
propiedad que permite que los complementos enumeren la colección de documentos abiertos actualmente.Este sistema de complemento se puede extender a los lenguajes de secuencias de comandos, por ejemplo, Lua, creando una clase de complemento derivada, por ejemplo,
LuaPlugin
que reenvía lasIPlugin
funciones y la interfaz de la aplicación a un script de Lua.Esta técnica le permite implementar de forma iterativa sus
IPlugin
,IApplication
y otras interfaces específicas de la aplicación durante el desarrollo. Cuando la aplicación está completa y bien refactorizada, puede documentar sus interfaces expuestas y debe tener un buen sistema para que los usuarios puedan escribir sus propios complementos.fuente
Usualmente uso MEF. El Marco de Extensibilidad Administrada (o MEF para abreviar) simplifica la creación de aplicaciones extensibles. MEF ofrece capacidades de descubrimiento y composición que puede aprovechar para cargar extensiones de aplicaciones.
Si estás interesado lee más ...
fuente
Una vez trabajé en un proyecto que tenía que ser tan flexible en la forma en que cada cliente podía configurar el sistema, ¡el único buen diseño que encontramos fue enviar al cliente un compilador de C #!
Si la especificación está llena de palabras como:
Haga muchas preguntas sobre cómo brindará soporte al sistema (y cómo se cobrará el soporte, ya que cada cliente considerará que su caso es el caso normal y no debería necesitar ningún complemento), como en mi experiencia
fuente
En mi experiencia, las dos mejores formas de crear una arquitectura de plugin flexible son los lenguajes de scripting y las bibliotecas. Estos dos conceptos son, en mi opinión, ortogonales; los dos se pueden mezclar en cualquier proporción, más bien como la programación funcional y orientada a objetos, pero encuentran sus mayores fortalezas cuando se equilibran. Una biblioteca es típicamente responsable de cumplir una interfaz específica con funcionalidad dinámica, mientras que los scripts tienden a enfatizar la funcionalidad con una interfaz dinámica.
He encontrado que una arquitectura basada en scripts que manejan bibliotecas parece funcionar mejor. El lenguaje de secuencias de comandos permite la manipulación de alto nivel de las bibliotecas de nivel inferior, y las bibliotecas se liberan de cualquier interfaz específica, dejando toda la interacción a nivel de aplicación en las manos más flexibles del sistema de secuencias de comandos.
Para que esto funcione, el sistema de secuencias de comandos debe tener una API bastante robusta, con enlaces a los datos, la lógica y la GUI de la aplicación, así como la funcionalidad básica de importar y ejecutar código desde bibliotecas. Además, generalmente se requiere que los scripts sean seguros en el sentido de que la aplicación puede recuperarse con gracia de un script mal escrito. El uso de un sistema de secuencias de comandos como una capa de indirección significa que la aplicación puede separarse más fácilmente en caso de Something Bad ™.
El medio de empaquetar complementos depende en gran medida de las preferencias personales, pero nunca puede equivocarse con un archivo comprimido con una interfaz simple, por ejemplo,
PluginName.ext
en el directorio raíz.fuente
Creo que primero debe responder la pregunta: "¿Qué componentes se espera que sean complementos?" Desea mantener este número al mínimo absoluto o el número de combinaciones que debe probar explota. Intente separar su producto principal (que no debería tener demasiada flexibilidad) de la funcionalidad del complemento.
Descubrí que el director de IOC (Inversión de control) (leer springframework) funciona bien para proporcionar una base flexible, a la que puede agregar especialización para simplificar el desarrollo de complementos.
fuente
El patrón de complemento es un patrón de software para extender el comportamiento de una clase con una interfaz limpia. A menudo, el comportamiento de las clases se extiende por la herencia de clases, donde la clase derivada sobrescribe algunos de los métodos virtuales de la clase. Un problema con esta solución es que entra en conflicto con el ocultamiento de la implementación. También conduce a situaciones donde la clase derivada se convierte en un lugar de reunión de extensiones de comportamiento no relacionadas. Además, las secuencias de comandos se utilizan para implementar este patrón como se mencionó anteriormente "Hacer elementos internos como un lenguaje de secuencias de comandos y escribir todas las cosas de nivel superior en ese idioma. Esto lo hace bastante modificable y prácticamente a prueba de futuro". Las bibliotecas utilizan bibliotecas de gestión de scripts. El lenguaje de secuencias de comandos permite la manipulación de alto nivel de las bibliotecas de nivel inferior. (También como se mencionó anteriormente)
fuente