<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>John W Powell : InternalsVisibleTo</title><link>http://blogs.msdn.com/johnwpowell/archive/tags/InternalsVisibleTo/default.aspx</link><description>Tags: InternalsVisibleTo</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>Implementing the "Only Talk to Friends" pattern using the InternalsVisibleTo Attribute</title><link>http://blogs.msdn.com/johnwpowell/archive/2008/05/09/implementing-the-only-talk-to-friends-pattern-using-the-internalsvisibleto-attribute.aspx</link><pubDate>Fri, 09 May 2008 15:24:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8479744</guid><dc:creator>johnwpowell</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/johnwpowell/comments/8479744.aspx</comments><wfw:commentRss>http://blogs.msdn.com/johnwpowell/commentrss.aspx?PostID=8479744</wfw:commentRss><description>&lt;P mce_keep="true"&gt;Did your parents ever tell you "don't talk to strangers?"&amp;nbsp; They were trying to protect you, and even though you are all grown up now, that principle is still relevant--to the design of your software, that is.&amp;nbsp; The basic idea is that classes should limit their surface area and not expose that which reveals implementation details.&amp;nbsp; Let's go though an example to illustrate these concepts.&lt;/P&gt;
&lt;P mce_keep="true"&gt;In a traditional layered architecture you logically divide components by responsibility.&amp;nbsp; In this example, we will use a domain, business and data access logic layer each realized as a Visual Studio 2008 project.&amp;nbsp; In our contrived architecture, we want the business layer to be the "gatekeeper" for retrieving customer domain objects.&amp;nbsp; The business layer uses the data access logic layer to fetch a customer, so we &lt;EM&gt;might&lt;/EM&gt; expose the data access class as a property of the business class as demonstrated here:&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;A href="http://blogs.msdn.com/blogfiles/johnwpowell/WindowsLiveWriter/ImplementingTheOnlyTalktoFriendsPatternU_10C77/DontTalkToStrangersIteration1_4.png" mce_href="http://blogs.msdn.com/blogfiles/johnwpowell/WindowsLiveWriter/ImplementingTheOnlyTalktoFriendsPatternU_10C77/DontTalkToStrangersIteration1_4.png"&gt;&lt;IMG height=238 alt=DontTalkToStrangersIteration1 src="http://blogs.msdn.com/blogfiles/johnwpowell/WindowsLiveWriter/ImplementingTheOnlyTalktoFriendsPatternU_10C77/DontTalkToStrangersIteration1_thumb_1.png" width=648 border=0 mce_src="http://blogs.msdn.com/blogfiles/johnwpowell/WindowsLiveWriter/ImplementingTheOnlyTalktoFriendsPatternU_10C77/DontTalkToStrangersIteration1_thumb_1.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P mce_keep="true"&gt;Here's the code to use this design:&amp;nbsp; &lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;A href="http://blogs.msdn.com/blogfiles/johnwpowell/WindowsLiveWriter/ImplementingTheOnlyTalktoFriendsPatternU_10C77/DontTalkToStrangersCodeIteration1_4.png" mce_href="http://blogs.msdn.com/blogfiles/johnwpowell/WindowsLiveWriter/ImplementingTheOnlyTalktoFriendsPatternU_10C77/DontTalkToStrangersCodeIteration1_4.png"&gt;&lt;IMG height=44 alt=DontTalkToStrangersCodeIteration1 src="http://blogs.msdn.com/blogfiles/johnwpowell/WindowsLiveWriter/ImplementingTheOnlyTalktoFriendsPatternU_10C77/DontTalkToStrangersCodeIteration1_thumb_1.png" width=557 border=0 mce_src="http://blogs.msdn.com/blogfiles/johnwpowell/WindowsLiveWriter/ImplementingTheOnlyTalktoFriendsPatternU_10C77/DontTalkToStrangersCodeIteration1_thumb_1.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P mce_keep="true"&gt;So what's wrong with this approach?&amp;nbsp; We have violated a core principal of object oriented design by exposing implementation details.&amp;nbsp; Just like your parents protected you from strangers, classes should not expose their children or any other details about implementation.&amp;nbsp; You may have heard of this concept by another name such as:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;
&lt;DIV mce_keep="true"&gt;Don't Talk to Strangers&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV mce_keep="true"&gt;Principal of Least Knowledge&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV mce_keep="true"&gt;Demeter's Law&lt;/DIV&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P mce_keep="true"&gt;Consumers don't need to know how the CustomerBusiness fetches a Customer, it only needs to know that CustomerBusiness fetches a customer.&amp;nbsp; So, let's revise the design using a technique called &lt;STRONG&gt;interface promotion&lt;/STRONG&gt;.&amp;nbsp; This involves hiding a child object and promoting all or some of its interface to the parent.&amp;nbsp; The new design looks like this:&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;A href="http://blogs.msdn.com/blogfiles/johnwpowell/WindowsLiveWriter/ImplementingTheOnlyTalktoFriendsPatternU_10C77/DontTalkToStrangersIteration2_2.png" mce_href="http://blogs.msdn.com/blogfiles/johnwpowell/WindowsLiveWriter/ImplementingTheOnlyTalktoFriendsPatternU_10C77/DontTalkToStrangersIteration2_2.png"&gt;&lt;IMG height=233 alt=DontTalkToStrangersIteration2 src="http://blogs.msdn.com/blogfiles/johnwpowell/WindowsLiveWriter/ImplementingTheOnlyTalktoFriendsPatternU_10C77/DontTalkToStrangersIteration2_thumb.png" width=642 border=0 mce_src="http://blogs.msdn.com/blogfiles/johnwpowell/WindowsLiveWriter/ImplementingTheOnlyTalktoFriendsPatternU_10C77/DontTalkToStrangersIteration2_thumb.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P mce_keep="true"&gt;Here's the code to use the new design:&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;A href="http://blogs.msdn.com/blogfiles/johnwpowell/WindowsLiveWriter/ImplementingTheOnlyTalktoFriendsPatternU_10C77/DontTalkToStrangersCodeIteration2_2.png" mce_href="http://blogs.msdn.com/blogfiles/johnwpowell/WindowsLiveWriter/ImplementingTheOnlyTalktoFriendsPatternU_10C77/DontTalkToStrangersCodeIteration2_2.png"&gt;&lt;IMG height=38 alt=DontTalkToStrangersCodeIteration2 src="http://blogs.msdn.com/blogfiles/johnwpowell/WindowsLiveWriter/ImplementingTheOnlyTalktoFriendsPatternU_10C77/DontTalkToStrangersCodeIteration2_thumb.png" width=480 border=0 mce_src="http://blogs.msdn.com/blogfiles/johnwpowell/WindowsLiveWriter/ImplementingTheOnlyTalktoFriendsPatternU_10C77/DontTalkToStrangersCodeIteration2_thumb.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;H3&gt;Only Talk to Friends&lt;/H3&gt;
&lt;P mce_keep="true"&gt;The responsibility of the business layer is to act as a "gatekeeper" and control access to the underlying layers.&amp;nbsp; Although it might seem that we have accomplished our goal with this design, there is another issue that needs to be addressed.&amp;nbsp; Remember the layered architecture?&amp;nbsp; Business logic is in one project/assembly and data access logic is in another.&amp;nbsp; In order for CustomerBusiness to use CustomerData, the methods in CustomerData must be public.&amp;nbsp; The implication of this is &lt;STRONG&gt;a consumer can reference the data access layer and call it's public methods, bypassing any logic in the business layer&lt;/STRONG&gt;.&amp;nbsp; To solve this problem, I would like to introduce a technique that I call &lt;STRONG&gt;only talk to friends&lt;/STRONG&gt;.&lt;/P&gt;
&lt;P mce_keep="true"&gt;The intent of the only talk to friends pattern is provide a mechanism for an assembly to expose it's interface to specified friend assemblies.&amp;nbsp; In our example, the data access logic layer would only expose it's interface to the business layer.&amp;nbsp; In order to accomplish this, let's revisit the design and make the CustomerData class and its methods internal:&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;A href="http://blogs.msdn.com/blogfiles/johnwpowell/WindowsLiveWriter/ImplementingTheOnlyTalktoFriendsPatternU_10C77/CustomerData_2.png" mce_href="http://blogs.msdn.com/blogfiles/johnwpowell/WindowsLiveWriter/ImplementingTheOnlyTalktoFriendsPatternU_10C77/CustomerData_2.png"&gt;&lt;IMG height=131 alt=CustomerData src="http://blogs.msdn.com/blogfiles/johnwpowell/WindowsLiveWriter/ImplementingTheOnlyTalktoFriendsPatternU_10C77/CustomerData_thumb.png" width=425 border=0 mce_src="http://blogs.msdn.com/blogfiles/johnwpowell/WindowsLiveWriter/ImplementingTheOnlyTalktoFriendsPatternU_10C77/CustomerData_thumb.png"&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;Now for the magic. Add the InternalsVisibleTo attribute to the AssemblyInfo.cs file in the Data project thereby exposing anything internal in the data access logic layer to the business layer.&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;A href="http://blogs.msdn.com/blogfiles/johnwpowell/WindowsLiveWriter/ImplementingTheOnlyTalktoFriendsPatternU_10C77/image_2.png" mce_href="http://blogs.msdn.com/blogfiles/johnwpowell/WindowsLiveWriter/ImplementingTheOnlyTalktoFriendsPatternU_10C77/image_2.png"&gt;&lt;IMG height=33 alt=image src="http://blogs.msdn.com/blogfiles/johnwpowell/WindowsLiveWriter/ImplementingTheOnlyTalktoFriendsPatternU_10C77/image_thumb.png" width=354 border=0 mce_src="http://blogs.msdn.com/blogfiles/johnwpowell/WindowsLiveWriter/ImplementingTheOnlyTalktoFriendsPatternU_10C77/image_thumb.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P mce_keep="true"&gt;The InternalsVisibleTo attribute exposes anything internal in one assembly to the specified friend assembly.&amp;nbsp; It would be nice if we could be more granular than the entire assembly, but this approach will work well for most circumstances.&lt;/P&gt;
&lt;H3&gt;Sometimes It's OK to Talk to Strangers&lt;/H3&gt;
&lt;P mce_keep="true"&gt;There is one exception for breaking the "do not talk to strangers" principle, and that is unit testing.&amp;nbsp; When we write the unit test for CustomerBusiness, we only want to test CustomerBusiness, not CustomerData or the database.&amp;nbsp; In order to do this, we mock the CustomerData class.&amp;nbsp; For this work, CustomerBusiness will need to provide a mechanism that allows the unit test to replace the CustomerData instance in CustomerBusiness.&amp;nbsp; There are a few techniques for doing this such as dependency injection (and I do have an article planned on this subject), but one way is to allow CustomerData to be passed into the CustomerBusiness constructor as follows.&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;A href="http://blogs.msdn.com/blogfiles/johnwpowell/WindowsLiveWriter/ImplementingTheOnlyTalktoFriendsPatternU_10C77/image_6.png" mce_href="http://blogs.msdn.com/blogfiles/johnwpowell/WindowsLiveWriter/ImplementingTheOnlyTalktoFriendsPatternU_10C77/image_6.png"&gt;&lt;IMG height=329 alt=image src="http://blogs.msdn.com/blogfiles/johnwpowell/WindowsLiveWriter/ImplementingTheOnlyTalktoFriendsPatternU_10C77/image_thumb_2.png" width=475 border=0 mce_src="http://blogs.msdn.com/blogfiles/johnwpowell/WindowsLiveWriter/ImplementingTheOnlyTalktoFriendsPatternU_10C77/image_thumb_2.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P mce_keep="true"&gt;Note that &lt;STRONG&gt;the constructor that allows the data access object to be specified is internal&lt;/STRONG&gt;.&amp;nbsp; Once again, you use the InternalsVisibleTo attribute granting access only to the business layer unit tests.&lt;/P&gt;
&lt;H3&gt;Summary&lt;/H3&gt;
&lt;P mce_keep="true"&gt;I hope this article has reinforced the object-oriented principle "don't talk to strangers," and provided a modern spin, "only talk to friends," that you can add to your toolbox.&lt;/P&gt;
&lt;H3&gt;References&lt;/H3&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;A href="http://www.amazon.com/exec/obidos/tg/detail/-/0131489062/qid=1102729726/sr=8-1/ref=sr_8_xs_ap_i1_xgl14/102-5016397-2387360?v=glance&amp;amp;s=books&amp;amp;n=507846" target=_blank mce_href="http://www.amazon.com/exec/obidos/tg/detail/-/0131489062/qid=1102729726/sr=8-1/ref=sr_8_xs_ap_i1_xgl14/102-5016397-2387360?v=glance&amp;amp;s=books&amp;amp;n=507846"&gt;Applying UML and Patterns&lt;/A&gt; 
&lt;LI&gt;&lt;A href="http://www.cmcrossroads.com/bradapp/docs/demeter-intro.html" target=_blank mce_href="http://www.cmcrossroads.com/bradapp/docs/demeter-intro.html"&gt;Introducing Demeter and Its Laws&lt;/A&gt; 
&lt;LI&gt;&lt;A href="http://en.wikipedia.org/wiki/Law_of_Demeter" mce_href="http://en.wikipedia.org/wiki/Law_of_Demeter"&gt;Law of Demeter&lt;/A&gt; 
&lt;LI&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.internalsvisibletoattribute.aspx" target=_blank mce_href="http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.internalsvisibletoattribute.aspx"&gt;InternalsVisibleTo Attribute Class&lt;/A&gt;&lt;/LI&gt;&lt;/UL&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8479744" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/johnwpowell/archive/tags/InternalsVisibleTo/default.aspx">InternalsVisibleTo</category><category domain="http://blogs.msdn.com/johnwpowell/archive/tags/Design+Pattern/default.aspx">Design Pattern</category><category domain="http://blogs.msdn.com/johnwpowell/archive/tags/Don_2700_t+Talk+to+Strangers/default.aspx">Don't Talk to Strangers</category></item></channel></rss>