Warning – Best Practices

According to the wikipedia definition, best practice is

…a technique, method, process, activity, incentive or reward that is believed to be more effective at delivering a particular outcome than any other technique, method, process, etc.

The word “believed”, in my opinion, plays an important role. What one believes in, is not necessarily shared by another person. And not only with faith, but with technologies as well. What one technology / platform / methodology will describe as good practice, another one can claim if not the opposite, then at least disagree on the stated.

The motivation for this though was withdrawn from the project I am working on quickly, which is entirely written in Java. Despite my opinions on Java as a language, there’s something fundamental embedded in  Java, that does not exist in C# – one class per file. It bothered me, so I decided to spike the history of the feature.

Now you can debate for hours if this right or wrong. I think this is a false best practice. From Object Oriented perspective, there’s nothing wrong with more than one class (or “type”) within a single file. Let me demonstrate a few examples.

Example 1 – Design by Contract

The system is coded with a Container (Dependency Injection), and Contracts are what we care about, not implementers. In some cases it makes sense to see packaging done the following way:

   1: public interface IContract
<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060">   2:</span> {</pre>

<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060">   3:</span>   <span style="color: #008000">//...</span></pre>

<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060">   4:</span> }</pre>

<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060">   5:</span>&#160; </pre>

<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060">   6:</span> <span style="color: #0000ff">internal</span> <span style="color: #0000ff">class</span> DefaultContractImplementation : IContract</pre>

<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060">   7:</span> {</pre>

<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060">   8:</span>   <span style="color: #008000">//...</span></pre>

<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060">   9:</span> }</pre>

I intentionally highlighted “packaging”, because in my opinion it’s all about packaging and some sort of convenience.

Example 2 – BDD Specifications

If you are familiar with Behaviour-Driven Development, you know that there can be multiple specifications for a single SUT (system under test). The most common and efficient way to achieve it, is to break it into separate classes, extending some sort of base spec for a particular SUT.

   1: public abstract class DomainService_Specs : ContextSpecification<IDomainService>
<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060">   2:</span> {</pre>

<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060">   3:</span>     <span style="color: #0000ff">protected</span> IDomainService system_udner_test;</pre>

<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060">   4:</span>     <span style="color: #008000">// ...</span></pre>

<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060">   5:</span> }</pre>

<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060">   6:</span>&#160; </pre>

<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060">   7:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">class</span> When_DomainService_is_asked_to_to_deliver_a_message_and_exception_is_thrown : DomainService_Specs</pre>

 

   9:     [Observation]
<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060">  10:</span>     <span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span> Should_recover_and_log_exception()</pre>

<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060">  11:</span>     {}</pre>

<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060">  12:</span>&#160; </pre>

<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060">  13:</span>     [Observation]</pre>

<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060">  14:</span>     <span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span> Should_do_something_else()</pre>

<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060">  15:</span>     {}</pre>

<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060">  16:</span> }</pre>

<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060">  17:</span>&#160; </pre>

<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060">  18:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">class</span> When_DomainService_is_asked_to_to_find_a_message_by_sender : DomainService_Specs</pre>

<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060">  19:</span> {</pre>

<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060">  20:</span>     [Observation]</pre>

<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060">  21:</span>     <span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span> Should_do_this()</pre>

<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060">  22:</span>     {}</pre>

<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060">  23:</span>&#160; </pre>

<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060">  24:</span>     [Observation]</pre>

<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060">  25:</span>     <span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span> Should_do_that()</pre>

<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060">  26:</span>     {}</pre>

<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060">  27:</span> }</pre>

We could potentially break the specs into multiple files, but is it worth it?

The Reason

Before making a blind assumption that a best practice is always good thing to apply, always look for the reason(s) it came to existence. Googling why Java had this best practice was an interesting finding (The Java Language Specification):

When packages are stored in a file system (�7.2.1), the host system may choose to enforce the restriction that it is a compile-time error if a type is not found in a file under a name composed of the type name plus an extension (such as .java or .jav) if either of the following is true:

* The type is referred to by code in other compilation units of the package in which the type is declared.

* The type is declared public (and therefore is potentially accessible from code in other packages).

This restriction implies that there must be at most one such type per compilation unit. This restriction makes it easy for a compiler for the Java programming language or an implementation of the Java virtual machine to find a named class within a package; for example, the source code for a public type wet.sprocket.Toad would be found in a file Toad.java in the directory wet/sprocket, and the corresponding object code would be found in the file Toad.class in the same directory.

It is obvious from the extract that the main reason behind the “best practice” was a technical optimization, and not OO principle implementation (like someone might raise up, Separation of Concerns, for example).

Conclusion

Java / C# (.NET) is a bit of a holly war. If you drop who borrowed what and when, you find that there’s an attempt to make a better development environment, and each attempt is packaged with the best practices considered to be “the best” at a time of product development. When product is outdated, or lagging behind, some will try to justify false best practices as best practices of even today. Be practical, search for the reasons, and make your decisions. Make sure you get the best out of the best practice, and not limited by it.

 

PS: Oh, and you can always convert to C# – proven to be more fun :)

5 Comments

  • Sean, where does it say : "It is obvious from the extract that the main reason behind the “best practice” was a technical optimization" ?

    The chunk of specification you posted, only listed --one-- of the benefits of having class separated by filename. It does --not-- explicitly say that that was the only reason Java was designed like that.

    That's the problem of getting religiously attached to a programing language, operating system, or cell phone. You'll end up backwards rationalizing your choice/purchase, you'll get tunnel vision, bend the facts, stretch the truth, and ignore better products (at your loss).

    Oh, and Sean .. please keep telling yourself that your Nokia N85 is a better/ more advanced / more revolutionary cell phone that an iPhone ;-) Same goes for Windows and OSX.

  • @Person,

    If you know it's only --one-- reason out of --many--, why haven't you write those?

    When I saw your comment, I was really tempted to block it for a few reasons:

    1. Anonymously cowered comment from a person that does attack without bringing any facts to the table.

    2. Claims of things I have never said (Nokia better than iPhone in all of its aspects, Windows better than OSX) - I know that you tried to spread some salt, but dude, do that without making up things.

    Apparently, you are religiously attached to way more things and way more times than me - look at you:

    1. You are the one who's paying the Mac tax, not me.

    2. You are the one who explicitly agreed that .NET provides you way more than Java.

    3. You are the one who is restricted by iPhone licensing model (yes, with an amazingly good touch screen, but still restricted). And BTW, you are obviously not even bothering to check things yourself, since N85 is not what I have ;) who's tunnel visioned?...


    Anyways, Vic (ops, I said the name), don't be such an angry and scinic person. That only will push people away.


  • >> If you know it's only --one-- reason out of many why haven't you written those?
    Why haven't you answered my first question? I.e. about your blatant hearsay, and taking things out of context?
    Thats the main issue at hand, that you can't assume, that just because there it one reason for something listed, that it's the "obvious and main reason". Other reasons include, like you mentioned, Separation of Concerns.
    >> Cowering being anonymous comments?

    Come on, did I really not make it obvious enough would wrote the post ?

    >> Claims of things I have never said (Nokia better than iPhone in all of its aspects, Windows better than OSX)

    Your constant spam emails about random anti-apple links, and the Mac tax, seem to indicate otherwise. Seriously though, you can stop sending them. I could send you recent news articles of how bad Microsoft and Nokia are doing now adays, and how well Apple is doing, but I don't.

    -----

    >>You are the one who's paying the Mac tax, not me.

    Wow, Sean great fact .. clearly you're not biased, and not emotionally attached.

    >>You are the one who explicitly agreed that .NET provides you way more than Java.

    Again, hearsay and speculation ... I --never-- said that. I did however say that Java offers extra features, not available with .Net, i.e. cross platform compatibility. (and btw Mono, for .Net doesn't count).

    >>You are the one who is restricted by iPhone licensing model
    Wow, Sean even more great facts, ranting about some form of restrictions. Are you refereeing to iPhones App Store ? Fact: None of Apples competitors even come cross to what Apple is offering with the AppStore. Not even close.
    >>And BTW, you are obviously not even bothering to check things yourself, since N85 is not what I have

    My mistake, I meant the N95



    Now, lets see ...

    I've pretty much only owned Nokia phones for all of my life, including Nokia smartphones ( Nokia N73 ) , I've only recently switched to the iPhone recently. (I was after all willing to try it out, due to the positive reviews, and not being --attached-- to Nokias branding). And after using the iPhone extensively, I can say without a doubt in my mind that its a far superior product to anything I've used. I'm sure you'll argue otherwise, but the market speaks for itself.

    Fact: Apple is gaining marketshare, Nokia is lossing it, and Nokia is reporting record quarterly losses.

    I've used windows all of my life, and only recently switched to OSX. Again, I was willing to experiment and take the plunge, after reading positive reviews. (Although, to be fair there was a time where like many people in the Computer Science industry, I refused to touch anything Mac, and I insisted all Mac products suck, without first trying them out. Eventually I grew up. Don't worry Sean, one day you will to). After buying a Mac, I realized that OSX and Apple computers is far superior to anything Microsoft and Dell can offer. And paying a couple of hundred dollars extra for a better product is definitely worth it. Just like buying cars. Sean, you could have bought a cheaper used American car recently, but instead you bought a Mazda. Why did you pay the "Japanese" car-tax? Perhaps because you know it'll last longer, and provide better value?

    Fact: Apple is gaining marketshare, Microsoft and Dell are loosing it, and reporting record quarterly losses. Look around you Me, Dave, and JP have all upgraded to Mac's.

    I've used Java extensively in the past, and now I only use c#. When I started using c#, I didn't insist the product sucks because namespaces don't match filenames, lack of cross platform support, no integrated SVN client (the only alternative being VisualSVN, that even though it's non a free product, it feels beta, and constantly screws ups my checkins, when I move directories, or rename). ALso the Fact that MSDN is absolutely atrocious and useless compared to Sun Javadoc.

    So I've used Nokia Phones, IPhones, Windows, OSX, C#, and Java all quite extensively. Have you?

    Between me and you, who do you think has a better view of these debates?

    Do you think your views might be a bit biased because you've never had a recent Mac, an iPhone, or really used Java?

  • >>Anyways, Vic (ops, I said the name), don't be such an angry and scinic person. That only will push people away. '

    Anyways, Sean, don't play with fire if you don't want to get burned. If you're going to spam my email with pointless articles (i.e. that the nokia 5800 is a better version of the iPhone), complain daily how useless Java is because you can't do your fancy TDD the way you want to, force your stance of C# being so superior down our throats, and write hearsay / speculative posts that you deem as facts, then don't be surprised if I post counter arguments, and point out your flaws. If you can't handle a healthy argument then don't instigate it.

  • @Victor,
    You know what, sorry dude, I somewhat regret that I woke up a beast in you. On the other hand, I am actually happy it went this way. Now I see your true face, and what you think of me. Bottom line, tomorrow we are going back to the same work place. Just with slight difference - I am what I always was, and you, well, not the image you've projected. I can read between the lines very well. And you've said enough.

    I guess you forgot one simple thing while passionately commenting: Word like a bird, once let out never catch it back.

    ---
    A few things to clarify:
    - I do not buy a half of the things you've stated (blame my tunneled vision)
    - Do not talk on behalf of others - you are not they and I doubt if you know the real motivations
    - Comments are closed - anything you want to tell me, you can tell me in PERSONAL (if you are capable of that).

Comments have been disabled for this content.