March 25th, 2008
There are several annoying design flaws I often stumble into in .NET APIs.
I haven’t seen Design Guidelines on this matter, so I think I’ll point to 3 of these myself.
The Generic Sin
Do provide a non-generic overloads to generic utility methods.
Ayende already wrote about it, so it does not make sense to repeat the reasons.
Fortunately, this is a very rare issue.
Violating framework: Castle.MicroKernel (DefaultKernel.ResolveServices<T>).
The Sin of Shallow Digging
Do support non-public members when performing type/member discovery.
Do not ever use Assembly.GetExportedTypes unless this logic can easily be overriden.
For example, I like to make my Domain Service interfaces public, but keep implementations internal.
This means that if I use InternalsVisibleTo, I can unit-test implementations, but the clients must use interfaces.
But if I try to define a common generic test base class, and use it like XTest : TestBase<X>, then if X is internal XTest should also be.
Now neither MbUnit or TestDriven.Net see my test, regardless of TestFixture attribute.
So if you use attributes to discover members automatically, the only reason to discard a member should be the absense of an attribute.
Access modifiers should not be considered, if the member does have an attribute.
Violating frameworks: MbUnit, Castle.Facilities.BatchRegistration.
The Sin of Tivoization
For each public interface you create, think how user can inject his own implementation.
(If this interface is directly consumed by API public methods, you can skip this step).
For example, let’s look at an interface MbUnit.Core.IFixtureFactory.
It is public, which seems good enough for people who hate internals.
But it is not possible to provide your implementation without wrapping the whole test-running engine.
It’s a pity. The framework I am developing right now would really benefit from it.
Violating frameworks: MbUnit.