Skip to end of metadata
Go to start of metadata

<p>This is not a hard and fast rule, but more of a guide to naming such that we can build more consistent API's in the various components in Zend Framework. By now, we've had a significant amount of time to work with namespaced and PHP 5.3 code, I think it's time to talk about some of our previous decisions to ensure they were indeed the right ones.</p>

<h3>Previous arguments</h3>

<p>Previous arguments that have been put forth have drawn inspiration far and wide from various programming language communities and various programming language code bases. Ultimately, I think this is a bad idea. When it comes to THIS decision, we should look directly at the communities and languages that are most like our own. Our own is object-oriented with an implementation that is single inheritance / multiple interfaces. What that means is our direct inspiration should be language communities like this, which is primarily C# and Java, but maybe Pascal and a few others.</p>

<p>On of the larger previous arguments has been that by adding "abstract" and "interface" to a class name is another form of Hungarian Notation. In all my research, I've seen very few texts say that apply the term Hungarian Notation to the naming of "types"; I've only seen this terminology applied to variables. Saying it's a form of Hungarian Notation seems incorrect to me, and thus should not be used as an argument.</p>

<p>Another argument is that with IDE's, the behavior of a type is known since the IDE will know if a name is a concrete class, abstract class or interface name. While I, being an IDE user, can understand this argument; it is both that the greater PHP community might not be a user of an IDE but also that type support and hinting in major IDEs is still not 100%. Thus, in my mind, this argument can be dismissed too.</p>

<p>Yet another argument is that the PEAR standards for 2.0 have been set and that we should follow these recommendations. While we've traditionally seen PEAR as the standards group (some say "gold standard"), it is clear they are embarking into PHP 5.3 at the same time as us and are identifying the same problems as us. At this point, their research is as old as ours and it would be an injustice to our group to simply default to the PEAR group for direction here. So again, in my mind, this argument too is not solid.</p>

<p>Finally, we have to admit that the SPL is not perfect and over time has been produced by many developers that have varying and differing opinions on what names should be used. The PHP Group does not go into the same depth as we should when it comes to namings (they have an altogether different set of goals and perspectives that rank naming and refactorings lower). One of the major reasons for a PHP frameworks existence is that frameworks are built by a smaller group of developers that share a common set of goals, perspectives and coding standards. For us and our success; consistency, cohesiveness and clarity of our API are what make ZF a more successful project moving forward.</p>

<h3>What are the Problems At Hand?</h3>

<ul>
<li>Name collisions</li>
<li>Too much creativity required on behalf of a developer (this is a bad thing)</li>
<li>Unclear API, hard to distinguish consumption vs. extension API (this is important!)</li>
<li>Lack of purpose and intent in type names</li>
</ul>

<p>First, we are seeing more <strong>name collisions</strong>, that is, places where we actually want to create a class now has an interface in it's place. Since we've banned the usage of the suffix "Interface", we've had to find new names for things that are interfaces (which, in ZF2 we will have more of since we've rightfully adopted the <a href="http://en.wikipedia.org/wiki/Solid_(object-oriented_design)">SOLID</a> & <a href="http://en.wikipedia.org/wiki/Design_by_contract">Design-by-contract</a> approaches.) Without the suffix of "interface", we now have to become <strong>more creative</strong> in naming when it comes to finding a home (in both name and filesystem location) for our interfaces. This is a bad thing. Too much creativity from too many people will create too many variances in the ZF2 API. As a consequence, we will diverge from consistency in the naming of classes - a bad thing. Instead of ZF2 becoming more a more cohesive API to interact with, it will remain the same or worse than ZF1 in the fact that it is ultimately looks and feels like code written build by lots of developers each with their own programming nuances.</p>

<p>Ultimately, we need our class names to immediately identify their <strong>purpose and intent through their name</strong>. What this will allow is for both new developers and seasoned ZF2 developers the ability to glance over a components classes and be able to distinguish between what is part of the <a href="http://ralphschindler.com/2011/01/18/php-component-and-library-api-design-overview"><strong>consumption API</strong> and what is part of the <strong>extension API</strong></a>.</p>

<h3>How Have Others Like Us Solved This Problem</h3>

<ul>
<li>.NET (C#) & Pascal community has traditionally (dominantly) prefixed classes with "I" for interface</li>
<li>The Java Community has traditionally (dominantly) suffixed classes with "Interface"</li>
</ul>

<p>The PHP OO type system is not really so different from .NET/C# and Java. That said, perhaps we should have a hard look at these communities. After all, these happen to be two of the <a href="http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html">most popular programming languages on earth</a>. Their audience tends to be more enterprise centric, but is that one of our core audiences too?</p>

<h3>Visual Demonstrations</h3>

<p>The following imagery will help to explain my position as it relates to the API, its clarity & cohesiveness, and ultimately, the first impressions it gives off.</p>

<p>This is an example of an early, but mostly complete Zend Framework 2.0 component. It currently follows the existing naming conventions we've setup over the past year.<br />
<ac:image ac:border="true"><ri:attachment ri:filename="naming1.jpg" /></ac:image></p>
<hr />
<p>One of the first questions a new developer (to this component) might ask is "How do I use this component, where do I start". This component answers this question very well...<br />
<ac:image ac:border="true"><ri:attachment ri:filename="naming1-entrypoint.jpg" /></ac:image></p>
<hr />
<p>Beyond identifying the initial use case or "entry point" for this new API, a question might be either of the following: "What other classes can I interact with immediately", "How do I extend this code base for my use case"...<br />
<ac:image ac:border="true"><ri:attachment ri:filename="naming1-where-extension-points.jpg" /></ac:image></p>
<hr />
<p>Without examining all the files, what might we assume about the intent and purpose of each class..<br />
(blue is correct assumptions, red is incorrect assumptions),<br />
<ac:image ac:border="true"><ri:attachment ri:filename="naming1-assumptions-of-purpose.jpg" /></ac:image><br />
(Yes, these are my assumptions, perhaps yours would be closers to the purpose/intent of the class. But, my point ultimately is that there is less a chance that two developers can make the same assumption about the same classes purpose/intent)</p>
<hr />
<p>In this screenshot, in order to identify all the interfaces, we've had to explore each file. This screenshot is in an IDE, but without an IDE, the process is still the same. The developer will have to explore each and every class to get the "full picture"...<br />
<ac:image ac:border="true"><ri:attachment ri:filename="naming2.jpg" /></ac:image></p>
<hr />
<p>Now that we've opened or examined all the files, we can identify what's what:<br />
<ac:image ac:border="true"><ri:attachment ri:filename="naming2-identify-by-expansion.jpg" /></ac:image></p>
<hr />
<p>Here is an alternative naming scheme. Yes, the namings of interfaces are far less creative than previously, and yes, they add a little bit of length (Interface vs. Manager - 2 characters), but the length problem has already been solved with the PHP namespace implementation. More importantly though this boring conventions does reduce the need for creative names. And that is ultimately a good thing because creative leads to divergence and variance whereas convention leads to consistency and cohesiveness...<br />
<ac:image ac:border="true"><ri:attachment ri:filename="naming-alt-highlight-types.jpg" /></ac:image></p>

<h3>Code Review Consideration</h3>

<p>When looking at code others have produced, having an 'Interface' suffix allows the reviewer to be able to distinguish if the code under review is coupling classed based on a particular contract (interface) or a specific implementation (concrete implementation / abstract implementation).</p>

<p>For example:</p>

<ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
public function someMethod(Bar $bar) { // is Bar a class, abstract or interface?
// ...

if ($baz instanceof Baz) {} // is Baz a class, abstract or interface?

// ...
}
]]></ac:plain-text-body></ac:macro>

<p>as oppose to:</p>

<ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
public function someMethod(BarInterface $bar) { // this class just wants an object that satisfies a particular interface
// ...
if ($boo instanceof BooInterface) {} // definitely an interface
if ($bam instanceof AbstractBam) {} // definiately expecting something that has a based abstract impl. of AbstractBam
if ($bax instanceof Bax) {} // definitely a concrete implementation
}

]]></ac:plain-text-body></ac:macro>

<p>The latter code (above) makes it easy for anyone consuming the above code to see what kind of type expectations there are without having to have full knowledge of all the types in a particular namespace. This gives a consumer a better understanding of where possible extension points more immediately than having to fully understand all the code in the codebase.</p>

<h3>Conclusion & Proposal</h3>

<p>Just as the prefix "Abstract" helps us identify incomplete implementations, "Interface" helps us distinguish useable classes from contracts (ie: interfaces). This proposal is not to change anything as it releates to the prefix "Abstract", which has been accepted and is in use. This proposal suggests two things only:</p>

<ul>
<li>Suffix contracts with "Interface". Contracts will <em>generally</em> consist of more than a single method, but not always.</li>
<li>Suffix object capabilities with 'able' or some other kind of representation of capability. While it's not a hard and fast rule, capability interfaces should generally be single method interfaces.</li>
</ul>

<h3>References</h3>

<ul>
<li><a href="http://zend-framework-community.634137.n4.nabble.com/Proposal-to-update-Abstract-Interface-Naming-Conventions-tt1755544.html#none">Super Old Discussion "Proposal-to-update-Abstract-Interface-Naming-Conventions"</a></li>
<li><a href="http://zend-framework-community.634137.n4.nabble.com/Poll-Interfaces-Abstract-class-naming-conventions-tt1755142.html#none">Old Discussion "Poll-Interfaces-Abstract-class-naming-conventions"</a></li>
<li><a href="http://framework.zend.com/wiki/display/ZFPROP/Naming+conventions+for+2.0+-+Matthew+Ratzloff">Old Proposal By Matthew Ratzloff</a></li>
<li><a href="http://en.wikipedia.org/wiki/Solid_(object-oriented_design)">SOLID principle</a> & <a href="http://en.wikipedia.org/wiki/Design_by_contract">Design-by-contract</a></li>
<li><a href="http://ralphschindler.com/2011/01/18/php-component-and-library-api-design-overview">Ralph's Article on API Design</a></li>
</ul>

Labels:
None
Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.
  1. Jan 09, 2012

    <p>Two things:</p>

    <ul>
    <li>Why are you only entertaining the "Interface" suffix, and not the "I" prefix? Both are valid, and I've seen the "I" prefix in more languages than I've see an "Interface" suffix (Python and C# both use it); shouldn't this also be an option?</li>
    <li>Your last point, "suffix object capabilities with 'able'" comes out of the blue, with little or no discussion. What is the purpose behind this? and wouldn't this create confusion as well – due to having multiple ways of naming interfaces?</li>
    </ul>

    <p>Based on your arguments, I'd argue <em>all</em> interfaces be named using the same notation (suffix or prefix, based on consensus).</p>

    1. Jan 10, 2012

      <p>C# uses I, but python doesn't really have native interfaces in the same sense that C#, Java, & PHP do - so it's hard to consider what python does (as such they have no runtime type checking based on a class/interface type, they do more duck-typing responds to / has_attr style type checking).</p>

      <p>At current, it appears the larger PHP community is using the "Interface" suffix, and by that, I mean Doctrine, Symfony2, and a handful of solo projects on github for php5.3 that don't have a ton of legacy code, specifically. At this point, using the "I" prefix, I feel would be "bucking the trend", and for very little value other than to be different. Of course, this statement is highly argumentative and speculative - I have no numbers to back that up.</p>

      <p>As for the "able" suffix, that is to address the naming of another <em>popular</em> use of interfaces outside of "as a contract" - which is that of being a <a href="http://en.wikipedia.org/wiki/Marker_interface_pattern">marker interface</a>. These include usages/ideas such as Serializable, Countable, Dispatchable; things of the kind of nature where they only have a single method as part of the interface. So, in essence, we're not talking about "multiple ways", we're only talking about 2: each with a well understood purpose.</p>

      <p>As you point out though, I'd love to bring this to consensus as as you know, I feel there is a bit of chaotic-ness in our current zf2 codebase that has emerged as its grown. I'll revise my argument above to further explain the idea of the marker interface, and I'd also suggest that find the consensus as a wiki poll, with public votes (same way we do our IRC meeting agenda).</p>

  2. Jan 25, 2012

    <p>I would just like to add my vote for adding an "interface" suffix (and other likewise suffixes) to interfaces as I was personally recently confused when looking at ZF2's code recently, it is difficult to differentiate what is an interface and what is not. </p>

    <p>As for what suffix to use, I've always been a fan of using longer English words to determine the type of a variable (and a class or interface in our situation) instead of the cryptic Hungarian Notation, so I'd vote for using "Interface" instead of "I", but it's very subjective and I'd be happy with either as long as we get a suffix! <ac:emoticon ac:name="smile" /></p>

    <p>Thanks for the good works guys.</p>

  3. Jan 26, 2012

    <p>The prime example given in this RFC relates to a complex component, considering how limited the OO-model is in PHP 5. I'd argue that this particular component could be refactored to introduce more self-explanatory names. Taking other, existing components into account: After working with zf2 for some time now, consuming and extending, I've got used to no-suffix interfaces. I got to the point that I think it's more elegant in many instances. I also hate how the word "creativity" is twisted to almost mean something bad to have.</p>

    <p>For example:</p>
    <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
    if($widget instanceof Widget){
    // do something
    }
    ]]></ac:plain-text-body></ac:macro>

    <p>I fail to see a confusion here. There are exactly two possibilities here:</p>
    <ol>
    <li><strong>Widget</strong> is an interface (hint)</li>
    <li><strong>Widget</strong> is a functional class</li>
    </ol>

    <p>This distinction does not matter for further consumption, because interfaces cannot be instantiated. When using an ide, writing "MyWidget extends Widget" will result in an error, if Widget is an interface. </p>

    <p>Because in current paradigm we do have <strong>Abstract</strong> prefixes for abstract components, there is no confusion in the "extension" department either. For example (component with interface+abstract):</p>

    <ul>
    <li>Zend/Validator
    <ul>
    <li>AbstractValidator.php – abstract (boiler-plate) class</li>
    <li>Date.php – concrete implementation</li>
    <li>Hostname.php – another one</li>
    <li>Validator.php – an interface, because there is an abstract above and we follow a simple rule</li>
    <li>ValidatorBroker.php – utility class, because it is suffixed with "Broker"</li>
    <li>ValidatorLoader.php – same as above</li>
    </ul>
    </li>
    </ul>

    <p>Another example (simple component):</p>

    <ul>
    <li>Zend/tag
    <ul>
    <li>Cloud.php – some concrete class</li>
    <li>Item.php – concrete class, because there is no AbstractItem anywhere in this namespace</li>
    <li>ItemList.php – probably utility because of "List" prefix</li>
    <li>Taggable.php – clearly an interface, because it has "able" suffix</li>
    </ul>
    </li>
    </ul>

    <p>At the same time I do see problems in some components that I believe should be fixed in the scope of that particular components. </p>

    <p>For example (a naming nightmare):</p>

    <ul>
    <li>Zend/Mail
    <ul>
    <li>AbstractProtocol.php – abstract class, obvious</li>
    <li>AbstractTransport.php – same</li>
    <li>Mail.php – hmm... I assume a class, because there is no AbstractMail anywhere</li>
    <li>MailPart.php – a class that lives inside Mail ?</li>
    <li>MailMessage.php – now I'm confused - is it a class that extends Mail ?</li>
    <li>Message.php – an interface?</li>
    </ul>
    </li>
    </ul>

    <p>The above are my assumptions before peeking inside those files. Of course they are all wrong, but I think introducing Interface suffix here and there will NOT fix this particular problem! </p>

    <p>Here is how Mail would like after refactor proposed by Ralph:</p>

    <ul>
    <li>Zend/Mail
    <ul>
    <li>AbstractProtocol.php</li>
    <li>AbstractTransport.php</li>
    <li>Mail.php</li>
    <li>MailPartInterface.php</li>
    <li>MailMessageInterface.php</li>
    <li>Message.php</li>
    </ul>
    </li>
    </ul>

    <p>A tiny bit better, but I am still confused :\</p>

  4. Jan 27, 2012

    <p>I very much like the idea of char-prefixing abstracts and interfaces. It's already been discussed before and it was declined, IMO. It is not much work to add it, it doesn't break anything, but it helps visual orientation - many IDEs have code-insight now, so that you can see on hover what it is. But there are a lot of cases when you just CAT a class or open it in simple notepad/viewer where there is no code-insight. </p>

    <p>Another plus is less writing than SomeClassInterface. Great mix of scan-speed readability, class name length (yay, we have namespaces, let's make the classnames longer <ac:emoticon ac:name="laugh" />) and formal naming logic. </p>

  5. Jan 27, 2012

    <p>Honestly I hate using programming language constructs to name my classes. The main reason is that I try to think outside of the programming language when designing, so I prefer to use domain language as much as possible. This may require 'creativity' but I think the focus should be on naming in regards to the problem space, rather than the implementation details.</p>

    <p>Is there really a use case for someone using a class without looking at it in any way? Whether you're in an IDE or not, you don't blindly extend a class without knowing what methods are available to it. The real time that class names become important are on actually using them, rather than implementing them, in which case having a domain-centric name instead of a programming construct-centric name is going to be more useful initially and down the road.</p>
    <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[if ($cat instanceof Mammal)

    Unknown macro: {..}

    ]]></ac:plain-text-body></ac:macro>
    <p>is far more readable than</p>
    <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[if ($cat instanceof MammalInterface)

    ]]></ac:plain-text-body></ac:macro>
    <p>and at that point in the code, do I really care if Mammal is a class or an interface?</p>

    <p>I think that goes along with RAD as well. I may not initially develop my feature with an interface, but if I want to later go back and refactor Mammal to an interface, the intention of my original code does not change.</p>

    <p>oh, and I'm absolutely against using 'I' if we go down that route. I is far too easily ignored as noise, or worse, misread. My company's current coding standard is to avoid all abbreviations, and while I was initially skeptical about this policy it has proven over and over again to me to make clearer, domain-readable code that requires very little parsing to understand what the intention of the code is.</p>

    1. Feb 01, 2012

      <p>Seth + Artur,</p>

      <p>I'll give you a for example from a two perspectives. First, lets say I am a developer consuming ZF, someone who has just downloaded the code base and started using it. How do they know that $m = new Mammal; is not legal? Especially since in most cases, we supply both the primary contract as well as a base implementation? In that case, its the difference between having a RequestInterface and a Request base object.</p>

      <p>As a consumer, its hard to look at a freshly downloaded codebase and ascertain anything from the file structure as you would expect.</p>

      <p>Now, from a development standpoint. If I am doing a code review of another developers code, lets say in a github pull request. Just by looking at the code, how can I ensure that you've coded to the contract instead of an implementation? ($cat instanceof MammalInterface) ensures this. Otherwise, I'd have to hunt down the use statement, then cross-reference that from the file in which the Mammal type was defined within.</p>

      <p>Mammal is a bad example of b/c you don't necessarily have an instance of a Mammal, you have an instance of a Cat which implements Mammal. This is often not the kind of relationship we have in the ZF codebase, there are typically interfaces, and them base implementations which often would carry the same name.</p>

      1. Feb 01, 2012

        <p>Granted, the example was a poor one, but to your questions: I still think it an uncommon use case to use an object/class without using 1) documentation examples or 2) api documentation (i.e., class/method signatures)</p>

        <p>If someone coming into the code base does a new Mammal; they will get an obvious fatal error and take a closer look at the implementation. (Either digging through code, which granted is not optimal, reading the example more closely, or studying the API documentation, which they should have done in the first place)</p>

        <p>I would really love to have my cake and eat it too, i.e., Interfaces with domain-meaningful names and classes with domain meaningful names, that do not overlap. </p>

        1. Feb 02, 2012

          <p>You have your interface - DbAdapter. You want to create your own implementation - named My\DbAdapter. Now when you use it in your code - the only way to say whether you use interface or concrete implementation is to corss-reference the use-statement (or use classname with namespace. </p>

          1. Feb 02, 2012

            <p>In this example, I think it's much more important to specify what kind of implementation is your Class such as My\MysqlDbAdapter or My\FileDbAdapter !<br />
            I totally agree with Set and Artur.</p>

  6. Feb 01, 2012

    <p>Thank you Ralph, this was bugging me as well while I was looking at the ZF2 codebase.</p>

  7. Oct 16, 2012

    <p>+1 for Seth Thornberry's domain language point. Just a side note, I don't like that we are calling it "creativity" when in fact what we are doing is accurately describing an object/object's intent. The name should become clear when the intent of the object is clearly defined--this happens through refactoring. My point being, if you need to add a suffix, your intent is not clear.</p>

    <p>We don't add a suffix to concrete classes, so why should we add them to abstracts and interfaces?</p>