Re: C# Plugin system - same interface in two different assemblies...



WTH <wth@xxxxxxxxxx> wrote:
Yes - the source code for the interface is present twice.

But that's the whole point.

That's duplication, which it's good practice to avoid.

Ridiculous. How come you aren't arguing the very same point about having to
"add a reference to the appropriate assemblies to each and every project"?

Well, where possible they should refer to either a prebuilt version, or
the latest version built from source control, which other projects can
also reference. You still have a single point of truth, within the
confines of branches. You don't have each plugin project deciding what
its idea of the interface is.

That's duplication too. That is just as open to being forgotten or done
incorrectly, et cetera. You're creating straw man arguments. At least by
letting the developer define the interface you can accomplish things you
can't by forcing people to include them in assemblies as I've explained.

I believe your solution introduces extra complexity, complexity which
is worth avoiding.

Define it
where and when you need it, don't force people to have it defined all the
time like you would if they have to include an assembly to get one
interface
and that assembly contains 30 other interface definitions. The code is
still there. If you simply put one interface per assembly you're only
including in the developers code once but then they have to have all the
assemblies which they 'may' use...

No, they only have to reference the assemblies they *do* use.

So now you're discussing the 'many assemblies' option.

Um, yes, because that's the one you were writing about. When you start
by saying "If you simply put one interface per assembly" then that's
what I'll address. It's not like I've changed the topic.

Ok, so instead of a
3rd party developer simply opening up the SDK documentation and adding the
interface definitions they need directly to their already existing code
base, you think it's wiser to have them obtain all the assemblies they need,
place them somewhere, and then add references for each one to their project?

For each one they need, yes.

I can assure you that our developers here would prefer simply adding the
interface themselves.

Maybe that's just because that's what they're used to - it doesn't mean
it's a good preference.

Heck, unless each of the potentially many
assemblies was deployed on every single developer's box, you'd have to make
them available by network share (which has issues itself - not related to
assemblies but to code sharing.)

So sharing via cut and paste is okay, but sharing by copying files has
issues? Doesn't sound like a terribly productive environment.

There's all kinds of potentially messy
issues regarding versioning and code sharing amongst developers on a team as
well.

Which are avoided by each developer deciding to have their own
potentially different version of an interface? That sounds like it's
*introducing* messy issues rather than avoiding them.

If one developer hasn't gotten the very latest assembly being used by
a common utlity class, their code breaks.

If one developer hasn't gotten the very latest copy of the SDK
interface, their code would break, wouldn't it?

Now you can get around things
like this by enforcing a check-in process that is strict (and we do this
already), but the question isn't if it's possible to do this, the question
is why go through all this extra crap? There's no logical reason (that I've
come up with or heard) that explains why you can't marshal one interface
into another. It seems like it would be pretty easy to do, just make it an
attribute on your interface something like 'Can be marshalled'...

I just don't see the benefit, I really don't. It sounds like it's
encouraging what I still regard as bad practice.

<snip>

If you meant interface, that's a very strange way
to deploy and SDK. What if you're application/host requires licensing?
What if it has a complicated configuration? Serious deployment
dependencies?

Who said anything about configuring it or installing it? You don't need
to do either of those things just to *reference* it.

You don't need to instance the application, but you can't just drop the
application or application components of a real product wherever you want.

You can reference assemblies without installing them, if you want to
build against them but not actually run the code.

But hey, if you don't want to use that technique, don't. There are
numerous ways to go:

o All plugin interfaces in a single assembly
o Plugin interfaces in the same assemblies as their hosts
o One assembly per plugin interface
o A hybrid, e.g. 5 assemblies with 4 interfaces each for 20 plugin
interfaces - group appropriately.

You planning on writing/debugging/supporting another installer that involves
the host and/or sub-component necessary in order to reference? You going to
ensure that the new installer doesn't include dependencies? Updating an
interface now means someone must perform an installation/migration?

If you update the interface, that means code changes however you're
referencing the code. With appropriate versioning, using assembly
referencing is more robust than just deciding that an interface may be
suitable to be marshalled. If the appropriate versions aren't present,
there'll be a clear type load error, rather than things going wrong in
a possibly mysterious and hard to diagnose way.

Listen, I can understand your reticence to find fault with something you've
obviously accepted as 'the way'

Try reading the same paragraph back to yourself. I've used both ways in
the past, and found duplicating source code a far inferior solution to
referring to built binaries.

but let me describe a real software suite
that has real complexity and real issues that you seem to be ignoring.

I believe you're ignoring the complexity and issues which are involved
in *your* way of doing them. Either this is because you've learned to
work your way round them, or they happen not to have bitten you - but
that doesn't mean they aren't there.

Imagine a security product that has a thick display client. The product has
a middleware layer. The product has a centralized storage back end. The
product has sensors and devices (logical software constructs that represent
real sensors and devices.) The product has a large number of potential 3rd
party integration points. There's a team of 12 people working on it broken
up into 3 primary groups - Client, Engine, Sensors. There are teams of
developers in several places inside and outside the US that write code to
these integration points (some of which are TCP/IP based, some HTTP based,
some are plugins.) This product is released approximately every 6 months
for a minor revision and every 18 months for a major revision. There are
many large corporations, military installations, and research groups using
this product. The client consists of ~13 projects that aggregate into a
small set of applications. The middleware consists of ~47 projects that
aggregate into sets of services and aggregatable components. The
centralized storage system has ~3 projects that represent major components
plus a primary project. The sensors system has ~27 in house projects for
components, 5 of which represent services or major components. The client
system has 3 integration points which support plugins. The middleware has
dozens of integration points that are plugins, tied to services and the
occasion host application, there are probably only 3 different interfaces
used across the middle ware components but the middleware can be deployed in
many different fashions depending upon what parts of the product you pay
for. The backend and sensors have 2 and 1 plugin integration points
respectively. The system is designed so that each aspect,
client/middleware/sensors (but not storage) can migrate independently.

And you want each plugin to have its own possibly changed and possibly
out of date copy of its plugin's interface? That sounds like madness to
me.

Now, given a rough scope of this 'product suite', can you understand how I
find it vastly simpler and less complex that if a developer wants to write a
plugin for our system they simply define the interface rather than the
rather complicated scenario of managing all the possible scenarios for
deploying components, hosts, assemblies, organizing the assemblies,
versioning them, et cetera...

No, I don't understand that - because there's more room for the
developers to get things out of sync, or foul them up themselves.

If you want to get as close to a single interface in a single source
file, just use a single interface for a single assembly. Yes, you get
quite a few small assemblies - but there's no significant harm in that,
and you get the benefit of knowing exactly which version of the plugin
interface you're using. If it's compiled into the plugin itself, it
gets a lot more complicated in my view.

You mean multiple definitions of the interface? Do you not realize that
this happens no matter what method you choose? Are you worried about
typos
or something? lol.
When somebody re-uses a class that someone else wrote, do you consider
that
code duplication and you don't "buy it"?

No, I don't consider that code duplication.

I'm sure you don't but it is the same thing.

Sounds like we'll have to agree to differ.

The source code only lives
in one place

You're making assumptions about how it would be used. In a software company
people tend to check out source from a repository and they have a local
copy. It is archived in one place, but it's duplicated across the network.
If you find that to be splitting hairs, I remind you that the way I would
like to do interfaces is exactly the same. You just seem to consider 'that'
code duplication.

That's more than splitting hairs, it's coming up with a straw man
scenario. There's still a single point of truth - the source control
system. (Or rather, there's a single point of truth per branch.) As far
as each developer is concerned, the working copies of other developers
don't exist until the code is checked in. That's very different from
each project having a checked in copy of code coming from elsewhere.

Your experience which is limited in C#, by your own admission.

My experience certainly covers everything that we've been talking about,
lol.

Sounds to me like you're just so used to one way of working that you've
been blindsided to its downsides, and you're reluctant to change.

You seem to have latched onto this as your only reasoning as to why C#
cannot discern that two interfaces are identical.

Nope - it's just *one* good reason. It's a good enough one for me.
Various other reasons are also available, but I only need the one.

How many people work on the same product where you are? You sound like you
don't have to worry about too much complexity (that's not a slam, that's a
"I wish that were me" :))

Considering the relatively small size of the company, there's more
complexity than I'd like - managing several brances with various
dependent projects. Not the sort of scale you mention above, but enough
to know that it would be worse if we had independent copies of bits of
code floating around.

I'd hate to think of how
you share code with others, presumably you just send them an assembly and
if
there's a problem with it, they have to ask you to fix it and ship them a
new assembly.

I suspect that most people who use my open source library only want or
need the DLL. Those who want to change the source can do so - but I'd
expect they'd usually still build to a DLL and reference that.
Assemblies are the units of code reference in .NET - not source code.

I would suggest that it is the way for relatively small projects. There are
other aspects of C# and VS 2005 (haven't tried 2008 yet) that indicate a
small team focus (i.e. adding a file to your project copies it by default
instead of linking it...)

That's not a small team focus - that's a focus of "code should only
live in a single project".

For some file types, it's appropriate to share - keys for signing
assemblies spring to mind. For actual code, I'd rather make sure I only
have a single copy anywhere *and* that it's only built into a single
project.

Hopefully you're sitting around with nothing to do when this
happens. Here we can't do that. If there's a bug in an SDK client
helper
class, the sdk developer can modify it because he has the file, not the
assembly. He doesn't have to wait for a new version of the SDK to come
out
in 6 months to a year.

No, but he then has to patch it every time there's a new release of the
SDK. Meanwhile, he may have introduced other bugs. The whole thing's a
versioning nightmare.

Patch what? He can simply grab the updated class or interface. It's not
all globbed together in an assembly.

The developer has made a local modification to his copy of the file.
When a new release comes out, he has to see whether that local
modification is still appropriate, and merge it in with the new
version.

I don't expect to convince you, to be honest.

I do appreciate the discussion though :). I hear .NET 3.5 will make changes
to the way in which plugin systems can work.

Well, it has a plugin infrastructure - but I very, very seriously doubt
that it will change this aspect of it. Good job too, IMO.

--
Jon Skeet - <skeet@xxxxxxxxx>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
World class .NET training in the UK: http://iterativetraining.co.uk
.



Relevant Pages

  • Re: How to use interfaces properly...
    ... > MyInterfaceTest). ... > property on the reference to "false". ... > interface have to have its own copy of the dll that contains the ... > references that will work during development, but will also let the plugin ...
    (microsoft.public.dotnet.framework)
  • C# Plugin system - same interface in two different assemblies...
    ... I am now aware that in C# if you reference the same interface from the same file in two different projects the types are actually incompatible. ... I found this out because I have written a generic plugin system for my current and future C# needs. ... When you compile and build both projects (we haven't even defined an interface which inherits from IPlugin yet, lol) and run the host.exe application, the host creates an instance of the plugin manager and tells it to load the dll produced by the MyPlugin project. ... This means that the runtime considers the interface IPlugin, which is of course defined in both assemblies so that each assembly can use it, to be different in each assembly. ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: Thanks... but...
    ... What you need to do is create an interface that the main form will ... You should have a constrained set of functionality that the form implements ... I already created an abstract PlugIn class which is the base class for ... I have a reference to my main form in the PlugIn class. ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: Plugin Architecture Problem
    ... You can define the interface in a single assembly but you need to manage how ... they are housed in different assemblies. ... > I'm trying to implement a Plugin architecture where I have a single UI ... > CreatePluginInstance - when I cast to the plugin interface type. ...
    (microsoft.public.dotnet.framework)
  • Re: C# Plugin system - same interface in two different assemblies...
    ... A developer using a skeleton plugin ... a user typing out the interface ... If you simply put one interface per assembly you're only including in the developers code once but then they have to have all the assemblies which they 'may' use... ...
    (microsoft.public.dotnet.languages.csharp)

Loading