Make everything public. Mark Two

You are looking at revision 3 of this page, which may be out of date. View the latest version.  

So a while back I wrote a post Make everything public which proposed making your entire API public.

Just to recap it proposed that instead of using permission modifiers (internal and private) we make everything public and instead use [EditorBrowsable(EditorBrowsableState.Advanced)] to hide members.

For the purposes of this discussion the two approaches will be referred to as the modifier approach and the attribute approach.

The Score Board

First off I would like to go through the various trade-offs of the two approaches as it stood when i wrote the initial post.

Performance

Using the attribute approach there is no need to use reflection when accessing hidden members. This results in a significant performance improvement over the modifier approach.

Outcome: Win for the attribute approach

Code Usability and Readability

With the attribute approach people can use strong typing and intellisense when writing their code. This is much less painful than the modifier approach which results in ugly reflection code.

Outcome: Win for the attribute approach

Visibility and Surface Area

The attribute approach hides things unless the user enables advance features in their editor. The modifier approach hides things unless you use reflection. Both approaches effectively hide types and members from the consumer of the API. So the visibility of things and the surface area of you API does not change.

Outcome: Draw

Encapsulation

While encapsulation is an important tenant of Object Orient programming is it not truly enforced in .net. With the modifier approach it can be bypassed with reflection. With the attribute approach it can be bypassed by turning on advanced features of the editor.

At best encapsulation in .net is an angry old man yelling "keep off my lawn".

Outcome: Draw

Don't use this part of my API

Many people avoid making things public so that is is easier to make changes in the future. The theory is that the smaller the surface area the smaller the agreed API contract is. So when you make breaking changes you only need to be careful about the public part of you API.

In reality people will use reflection to bypass that contract anyway.

So with the modifier approach you take the stance of "please don't use anything that is marked internal or private". With the attribute approach you take the stance "please don't use anything marked with [EditorBrowsable(EditorBrowsableState.Advanced)]". Not really much of a difference.

Outcome: Draw

Proper visibility within your project

Note: this point is referring to the code base of the API

Since the attribute approach makes no distinction between internal and private you can not property express all scenarios that you can with modifier approach.

Outcome: Win for modifier approach

Amount of code

The attribute approach requires the use of [EditorBrowsable(EditorBrowsableState.Advanced)]. This is clearly much more verbose than modifier approach which uses internal and private.

Outcome: Win for modifier approach

Outcome

If you sum up the points it is two each. However the last two points were always blocking issues for me when pitching this idea to people. To really convince people of a differnet idea you have to make the transition as smooth as possible. So I hade to make the last two points at least Draws. This way there would be no drawbacks of using the attribute approach.

Enter IL Weaving

I turned to IL Weaving in an attempt to solve the last two points and created the Publicize project. It is and addin to Fody which modifies an assembly just after it has been compiles.

Publicize performs the following actions

  • Find all types and members that are internal or private.
  • Convert these things to public.
  • Add [EditorBrowsable(EditorBrowsableState.Advanced)] to each of them.

So how does it solve that last two issues.

Proper visibility within your project

You can now use the internal and private modifies as you would normally. So all you rules about encapsulation and OO design will be followed in your code base.

Outcome: Draw

Amount of code

Since you don't need to write [EditorBrowsable(EditorBrowsableState.Advanced)] anywhere your code is no more verbose.

Outcome: Draw

In Summary

Hopefully some people got to this point without exclaiming "this guy is crazy" and closing the browser.

I think it is a pity that .net and c# were not initially designed with this type of approach. If it was build in to the language there could be a custom keyword similar to unsafe. Then everything inside it would bypass permission modifiers without the performance hit of reflection. Perhaps re-use the public keyword.

public
{
   //all code placed in hear will bypass permission modifiers
}

It is also a pity that people cling to the illusion that permission modifiers are respected.

I hope that the approach I have outlined above make people consider that there may be better approach the controlling the visibility of an API. The consumers of your API will love you for not forcing them to use reflection.

Posted by: Simon Cropp
Last revised: 08 Feb, 2013 11:11 PM History
You are looking at revision 3 of this page, which may be out of date. View the latest version.

Comments

No comments yet. Be the first!

No new comments are allowed on this post.