Easier than before, we create Interfaces and contracts quickly and easily, with little or no attention to detail.
Increasingly I have the opinion that we are in a need to control and define our contracts to levels yet unseen.
As a base for this, comes the "Public is NOT Published" thought from Martin Fowler
And before you say combinations of ObsoleteAttribute, InternalsVisibleTo and public, private, internal modifiers etc - They do not all add up to the same thing!
But, "Publishing an Interface" must be thought of as being as complex as in any print media business, where the term is strong. If we are creating contracts, its a shame we have much less control on it than we thought.
And there are a few ways of thinking about what we need.
Do we need access modifiers of type published/unpublished or Attribute based?
Can it be role based, versioned, per client? (I wish to publish these two additional methods to the Administrators group)
Should it be Attributed/Annotated with tools or within the language itself.?
From an Artima interview Erich Gamma says "And in Eclipse we have the conventions for that difference. Actually we even have tool support. In Eclipse 3.1 we have added support for defining rules for which packages are published API. These access rules are defined on a project's class path. Once you have these access restrictions defined the Eclipse Java development tools report access to internal classes in the same way as any other compiler warnings. For example you get feedback as you type when you add a dependency to a type that isn't published."
Is it a good feature in Eclipese? Should we not have something as powerful in Visual Studio and languages?
So where will it go?
Well, I think its extremely important for our future contracts and interfaces to be malleable, and towards that end, Duck Typing , dynamic "versioned" proxies, and other technologies need to come into the frame.
I also believe that a split between Internal and External lines is needed within our code.
Example: Partial Methods is an internal tool, where as Partial Classes is an External tool. By internal, the Partial Method, can never be public, since its an internal feature of the class. The Partial Class can only be declared and partial'ed within the same .NET Assembly Module. This kind of feature (and many more to come) will aid Code Generation directly, making it a far more reliable and superior form of tool. We require these 'internal' helpers for code maintenance and as a "code file splitting technique", but we also need the External (traditionally Interfaces) to be revved up.
btw: Partial methods and classes is one of my favourite features. I like the way it now embodies a design pattern into the inner workings. (Template Method Design Pattern)
CodeGen meets Refactoring, meets new Interface Contract
Consider a tool in your IDE, where you select a class, and select 'Build Facade', which presents you with options and then ultimately creates an Adaptor/Facade for the selected model.
Can Rational do this?
However, importantly it will also set up the access modifiers for the selected classes which will allow us to present the Adaptor to a Client, without them seeing, being confused by, wanting access to additional non essential interfaces. In effect, we now have a new Assembly in Visual Studio, named, code generated talking to the bottom layers. The bottom layers would be marked as InternalsVisibleTo the new generated assembly. I can now supply the Adaptor/Facade to a client. I can then version that off, and create a new generated version of it. We can Select which members to Publish as a set and which to remain public
But thank MS for InternalsVisibleTo
By using the internal and public modifiers. together with InternalsVisibleTo Attribute on the Assembly, the client code, will be able to
Call the public member
Call internal member (if inheriting from the class)
Call the internal member (if InternalsVisibleTo) is added to the assembly attributes
So with the code above in one Assembly and the code below in another referenced assembly, the methods you see below are visible.
[code:c#]
//Client Code within a different Assembly.publicclass Class1 : ClassLibrary1.InterfaceA
{
public Class1()
{
//base contains nothing
ClassLibrary1.TypeX x = new ClassLibrary1.TypeX();
x.methodA();
x.methodB();
x.methodC(); //if InternalsVisibleTo
ClassLibrary1.TypeY y = new ClassLibrary1.TypeY();
y.methodA();
y.methodB();
y.methodC();//if InternalsVisibleTo
y.methodD();
y.methodE(); //if InternalsVisibleTo
}
#region InterfaceA Members
void ClassLibrary1.InterfaceA.methodA() { }
#endregion
}
publicclass Class2 : ClassLibrary1.TypeX
{
public Class2()
{
base.methodA();
base.methodB();
base.methodC(); //if InternalsVisibleTo
ClassLibrary1.TypeX x = new ClassLibrary1.TypeX();
x.methodA();
x.methodB();
x.methodC();//if InternalsVisibleTo
ClassLibrary1.TypeY y = new ClassLibrary1.TypeY();
y.methodA();
y.methodB();
y.methodC(); //if InternalsVisibleTo
y.methodD();
y.methodE(); //if InternalsVisibleTo
}
}
publicclass Class3 : ClassLibrary1.TypeY
{
public Class3()
{
base.methodA();
base.methodB();
base.methodD();
base.methodC(); //if InternalsVisibleTo
ClassLibrary1.TypeX x = new ClassLibrary1.TypeX();
x.methodA();
x.methodB();
x.methodC(); //if InternalsVisibleTo
ClassLibrary1.TypeY y = new ClassLibrary1.TypeY();
y.methodA();
y.methodB();
y.methodC(); //if InternalsVisibleTo
y.methodD();
y.methodE(); //if InternalsVisibleTo
}
}
[/code]
InternalsVisibleToAttribute needs to also be available to Classes and Members, as well as excluding a member from visibility to the outside. Also it should not be for internals only, but also for public, so therefore VisibleTo Attribute, and ExcludeTo Attribute