There is a very simple thing to do to rationalize a code base: making
sure that every methods, fields and types have an optimal visibility. For
example, if a method is declared internal but is not used outside its declaring
type, it should be declared private. For such method the private visibility is
its optimal one. Rationalizing a code base with optimal visibility help
protecting from potential flaw. For example having optimal visibility can avoid
improper coupling with a class that should have been declared internal as soon as it
was developed.
Since the early days of NDepend, the tool was able to tell which code elements
do not have optimal visibility. We now moved this feature into Code Query Language
v1.5 with the following CQL conditions:
CouldBeInternal, CoulBeInternalProtected, CouldBeProtected, CouldBePrivate and ShouldBePublic.
The default set of CQL constraints comes with a new
Optimal Encapsulation group that contains constraints such as…
SELECT METHODS WHERE CouldBePrivate
…and that you can adapt to suit the needs of your own
code base…
SELECT METHODS OUT OF NAMESPACES “MyNamespace1″, “MyNamespace2″ WHERE CouldBePrivate AND !NameLike “MyMethodsThatIDontWantToBePrivate”…
Of course, if your code base is a framework, there are
chances that the query…
SELECT METHODS WHERE CouldBeInternal
…returns a lot of public methods that are not used by
your code base, but that should remain public anyway because some external client code
relies on it. In this case, just discard this query.
What about the condition ShouldBePublic? This condition matches types,
methods and fields that are declared as internal but that are used by code
declared in other assemblies thanks to the attribute System.Compilers.Services.InternalsVisibleToAttribute. In general, having code
elements that are considered as ShouldBePublic is not a problem because it is
made on purpose. However, it can be interesting to list them.
The condition CoulBeInternal can also apply to namespaces although .NET
languages (C#, VB.NET etc) don’t allow visibility modifier on namespaces. A
namespace is considered as CoulBeInternal if it contains only types that are
used internally and if at least one of its types is declared as public.
SELECT NAMESPACES WHERE CouldBeInternal
While developing the
optimal visibility feature, we notice an interesting thing. When you declare an
internal class without an explicit constructor, the default constructor automatically provided by the C#
compiler is public. NDepend will tell you to declare explicitly an internal
constructor but beware here: having a default internal constructor can sometime lead to serialization
issues.