davidfowl / WebApplicationPlugins

A sample plugin model for ASP.NET Core applications
119 stars 13 forks source link

Concerns about plugin systems #1

Open InDieTasten opened 2 years ago

InDieTasten commented 2 years ago

Hi David!

I've experimented with plugin systems since the introduction of the AssemblyLoadContext in dotnet 3: https://github.com/InDieTasten/DevTease.Plugins

I'd like to share my findings with this approach:

I've also seen numerous Java applications with plugin systems that were difficult to deal with, even though dynamic code loading is basically a first-class citizen on that platform.

I don't want to forbid this approach. Feel free to experiment. I just wanted to inform you of my takeaways before this gets endorsed/promoted without giving it enough thoughts. IMO, it introduces more evil than it does good.

Kind regards!

PeterKneale commented 2 years ago

@InDieTasten In regards to one of your points..

working with multiple plugins that require different versions of the same dependency is almost impossible and creates arbitrary coupling between otherwise independent plugins

Is it possible that this has been addressed? - The related documentation appears to describe using multiple assembly load contexts to address this issue. when-do-you-need-multiple-assemblyloadcontext-instances

davidfowl commented 2 years ago

working with multiple plugins that require different versions of the same dependency is almost impossible and creates arbitrary coupling between otherwise independent plugins

I see this as opt-into this set of problems when you decide on a plugin based architecture like this. There are various reasons people implement plugin systems from actually providing dynamic behavior to development ease (modular monolith). This sample is just showing a very basic sample and doesn't try to expose/solve fundamental issues with version conflicts between dynamically loaded components.

There are a few things you can do to mitigate some of the problem you might encounter while building these systems. If all components are known at development time and this separation is for development ease, then it's easy to add references to each of the plugins to resolve conflicts. The normal build time tooling will do it's thing and it'll work like a regular .NET application.

If plugins are truly dynamic then it's much more complex. There's nothing built in to handle this so you need:

Debugging gets a whole lot more messy or sometimes impossible

Not sure what you mean by this, can you elaborate?

Management of assemblies/build artifacts needs to be streamlined, because there are no standards on how to package these plugins

Right, this is part of the magic nuget package that targets the plugin host. Plugins are unique to the plugin host and how it wants the app to package/load them. How do you deploy a plugin to the deployment target? It's sorta like using nuget at runtime to install a plugin for this host. Something that definitely isn't supported out of the box (and won't be).

Thanks for the great feedback, this is a sample that people can run and play with and tweak if they want, nothing more.

InDieTasten commented 2 years ago

@PeterKneale

Is it possible that this has been addressed? - The related documentation appears to describe using multiple assembly load contexts to address this issue. when-do-you-need-multiple-assemblyloadcontext-instances

That might work, but logically implies that there cannot be any interaction between those two contexts. Looking at the Java eco-system, there are oftentimes plugins extending on funtionality of other plugins. That is it's own use-case sure, but you get to this point really quickly, more quickly than one might expect. Davids reply covers this already:

If plugins are truly dynamic then it's much more complex. There's nothing built in to handle this so you need: [...]

@davidfowl

Debugging gets a whole lot more messy or sometimes impossible

Not sure what you mean by this, can you elaborate?

I've had a fair share of problems getting the debugger attached properly with working code-mapping to plugin assemblies when they reload, or when they update during the runtime. Maybe not a top concern, maybe it's been improved upon since I've last tested this, or maybe it's been incompetence on my behalf all along. I'm no expert when it comes to Assembly loading and things that take place there and how the debugger does code-mapping. But it definitely wasn't trivial.

Thanks for the great feedback, this is a sample that people can run and play with and tweak if they want, nothing more.

Glad this came across as genuine feedback rather than hate. I'm all for experimentation!

I was only worried about the potential damage when others get inspired to do this, as I still believe that there is only a very narrow set of problems that would benefit from this approach + having to make bunch of conscious decisions on how not to end up with a mess at the end.

davidfowl commented 2 years ago

I was only worried about the potential damage when others get inspired to do this, as I still believe that there is only a very narrow set of problems that would benefit from this approach + having to make bunch of conscious decisions on how not to end up with a mess at the end.

There are more damaging things on the internet to worry about 😉

InDieTasten commented 2 years ago

@davidfowl Do not dare to distract! 😄

We can close this if you want, or keep it open for more visibility. It's your repo. I merely wanted to inform you of my concerns.

Or maybe the limitations/caveats outlined in the discussion could be added to the readme?

davidfowl commented 2 years ago

@InDieTasten you might have nerd snipped me into adding more code to show some of those scenarios.

InDieTasten commented 2 years ago

@davidfowl Ooops! Once pushed I'm intrigued to take a look