Public vs. Published
One of the thing that you see some people agonizing about is what they should be exposed to the outside world. On the one hand, people have heard all about encapsulation, and how it is going to save the world. On the other hand, we want to expose functionality to the outside world, be it for testing or for advance usages of your software.
Something that I wish that C# had is the published alias to the public keyword, that would have expressed intent in a much easier fashion than just public.
That said, I found a very useful approach to handling this myself. Separating interface and implementation. Let us look at an example:
public interface ICommand { void Init(string[] args); void Execute(); }
And an implementation of that:
public class MyCommand : ICommand { public string Key { get; set; } public long ByteCount { get; set; } public void Init(string [] args) { // parse args to key & byte count } }
Now, if I want to test that I am getting the right thing, I can, easily. At the same time, the published interface of this is ICommand, not whatever is public in MyCommand.
In situations where I have one to one mapping between interfaces and implementations (IUserRepository and UserRepository), this is even more pronounced.
Comments
I think it's exactly what 'internal' is for.
I always make things like UserRepository internal.
I use this all the time for my repository and service classes. It allows me to use property injection without publishing the public properties. I can still access those properties if I want to, but they aren't a part of the "published" interface to those classes.
congrats, you've discovered OOP! ;)
I've used the "Interface as published" thing before on my projects. I had class with a HUGE set of public methods being passed around, and I finally went around partitioning them into separate iterfaces, and rewriting the client code to accept only the narrowed interface.
This worked wonders.
I was able to componentize the kitchen-sink class and finally refactor the responsibilities into wherever they needed to go, rather than in the kitchen-sink.
It helps intellisense within the client code too, as I only see those methods which I "ought" be using, instead of everything the class has.
andrey,
Internal is a bad solution, it means that you are only exposing things to the current assembly.
Testing, advance scenarios needs that access as well
Ayende,
you can test internal members if you make test assembly a friend assembly (with InternalsVisibleToAttribute)
Petar, I am aware of that.
I strongly dislike this method
Adding InternalsVisibleTo a project's AssemblyInfo.cs will allow other explicitly defined assemblies access to internal members. This is really helpful for unit testing.
Example:
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("UnitTests, PublicKeyToken=123456789abcdef0")]
http://www.sturmnet.org/blog/archives/2005/05/10/internalsvisibleto-sn/
Why wouldn't you mark the set parts of the properties to private since the way they should be initialized is via the Init method?
Testing works extremely well with InternalsVisibleTo. Also it seems the right thing to do -- why do something as big as making everything public just for testing purposes?
I always try to write my code to be test ignorant (making code modular or using interfaces are common sense good design decisions, not test-forced ones). Doing something 'just for tests' feels as bad as doing something 'just for persistence' or 'just for specific IoC container'.
But if you have an advanced scenario when you need these classes to be public, probably it means they are 'published' as well.
You seem to be ignoring the part of testing not the only thing required.
And published is not the same as public. For published, I want to support this.
For public, it means that you can do things with it, but it is your responsability
Ed,
I really don't see how "other explicitly defined assemblies" could access internal members. It would defeat the whole purpose of friend assemblies.
Ayende,
could you say why you dislike this method ? Because I see it very much like Andrey.
The other way to test internal stuff could be to implement test classes inside the tested assembly itself and manage builds so that test classes are not included in release version. With partial classes maybe we could test private stuff to. Haven't tried this scenario myself..
Because testability is a secondary concern. I often need to be able to support additional functionality, and I found out that creating this distinction means that I can get pretty good results over a long period of time.
here is an example:
http://www.ayende.com/Blog/archive/2008/01/24/Interception-as-an-extensibility-mechanism.aspx
I do not see any be-public requirements here: http://www.ayende.com/Blog/archive/2008/01/24/Interception-as-an-extensibility-mechanism.aspx, what am I missing?
I do not see any be-public requirements here: http://www.ayende.com/Blog/archive/2008/01/24/Interception-as-an-extensibility-mechanism.aspx, what am I missing?
Out of interest, has anyone here ever seen a good use for InternalsVisibleTo other than testing? That's the only use I've had for it so far, and I'd be slightly worried at other uses, I suspect. If anyone's found one, I'd be interested to hear about it.
Jon, when working with NHibernate, I use InternalsVisibleTo to give Castle.DynamicProxy access to the internals of my domain model.This allows me to use the lazy loading that Castle.DynamicProxy provides while keeping stricter controls on the visibility of constructors.
The first textbook I ever came across on computer security discussed role-based security access to functions prior to applying it to things like file and object access. I agree that public/private/protected/internal are too gross in their scopes- very convenient for lots of cases, but not adequate. I for one would like to be able to unit-test "private" methods and classes as well. Of course, role-based or named-entity-based access authorization for code introduces a set of questions, but I'm quite confident that a broader set of cases could be handled with the answers that are easier to arrive at.
Noticed you have Execute on the interface but not on the class...
@Andrey
"Doing something 'just for tests' feels as bad as doing something 'just for persistence' or 'just for specific IoC container'."
I think a lot of the time this is true, changes put in for testing don't necessarily prove that useful. That is not an argument against TDDD though, just not sure always designing for testability is always a good approach.
@Jon Skeet
Good, maybe not but I've seen it used where you have a seperation between layers but actually there is a tight relationship. For example only an AccountService (in one project) should access a member on Account (in another project), in those cases you can make the member public and only use it from AccountService or just use InternalsVisibleTo in order to give the project containing AccountService access.
Comment preview