DSPaul / COMPASS

TTRPG resource manager, bringing all your books, maps, etc. in one place.
https://www.compassapp.info
GNU General Public License v3.0
88 stars 9 forks source link

Plugin system #79

Open anthony-bernaert opened 1 month ago

anthony-bernaert commented 1 month ago

I am playing around with a few ideas of which I am not sure they would 100% fit in the application. A few apps I use provide a plugin system for this type of extensions. I think it can also be a good way to keep the core application 'tidy' by not having to implement feature requests from a minority of users. From my experience, .NET actually makes it relatively easy to implement such a plugin architecture.

Do you think it would be possible to make this? The amount of customization could be kept simple to start with. The use cases I was thinking of:

That would allow other developers (e.g. me) to add specific functionality. Plugins would be made open-source afterwards, of course.

DSPaul commented 1 month ago

I've definitely also thought about it and agree it would be a great addition. Especially because the barcode reader alone is responsible for over half of the install size so splitting that of into a separate plugin would be great. It would also allow the rpg integrations to become optional as some people just want to use it for general purpose files.

The reasons I haven't done it yet are the following:

Could you link some sources on how dotnet supports such an architecture as you mentioned?

anthony-bernaert commented 1 month ago

The only experience with plugins I had until now is nopCommerce. As far as I know, nopCommerce doesn't use any packages for plugins, and implements all plugin loading logic itself. I think their DI-based approach is really powerful and nice to develop for, but it's certainly not perfect. There is tight coupling between the core version and plugin version, and external plugins I've used therefore often provide a build per nopCommerce version. This works because you typically don't update your eCommerce framework as often as you would update a desktop app.

In general, I see lots of references to MEF when I look up on how to write a plugin architecture, yet it seems a bit outdated (see here). Instead, there are alternatives such as DotNetCorePlugins, described on this blog post, and this seems rather neat. It's a lightweight package that handles assembly and dependency loading.

As I found the plugin subject interesting, I did a few experiences within the COMPASS code (however, before reading about DotNetCorePlugins). You can find it on the plugin_poc branch of my fork. For assembly loading, it still uses the more naive Assembly.LoadFrom approach, but it works for now if you build everything as a whole (note my changes did break your Tests though). For integrating new WPF views in the 2 sample plugins, I've been inspired by this article and associated Github repo.

While making this, a few challenges appeared:

Referring back to the nopCommerce example: they make a distinction between core and framework features, and put them in separate C# projects/class libraries, ensuring proper decoupling. I don't know if you'll need a lot of architectural changes for moving to Avalonia, but it is maybe also a refactoring opportunity - even if you don't implement plugins in the end.

Lastly, for version differences, I found this post about using an adapter pattern.

Note I really don't want to push you in any direction - I understand that there are higher priorities. The subject draw my interest and I made the demo mainly for own learning purposes (both on plugins, but also more basic MVVM/WPF). I'm sharing it so you can possibly refer to it in the future and see how things can be done (or shouldn't be done :smile:).