Added by Matthew Ratzloff, last edited by Matthew Ratzloff on Oct 31, 2008  (view change)

Labels

 
(None)

Zend Framework: Naming conventions for 2.0 - Matthew Ratzloff Component Proposal

Proposed Component Name Naming conventions for 2.0 - Matthew Ratzloff
Developer Notes http://framework.zend.com/wiki/display/ZFDEV/Naming conventions for 2.0 - Matthew Ratzloff
Proposers Matthew Ratzloff
Zend Liaison TBD
Revision 1.0 - May 25, 2008: Incomplete initial draft (wiki revision: 11)

Table of Contents

1. Overview

To do: Zend_Search, methods, Boolean accessors

Since the initial preview in March 2006, there hasn't really been much in the way of direction given on naming standards for classes in Zend Framework. This lack of consistency is what has yielded two nomenclatures for CLI components ("Zend_Console" vs. "Zend_Controller_Response_Cli"), differing terms for similar concepts ("Zend_Json_Decoder" vs. "Zend_Mime_Decode"), both nouns and verbs in equal measure ("Zend_Loader" but not "Zend_Translator"; alternately, "Zend_Translate" but not "Zend_Load"), and so on.

I first brought this issue up in February 2007 and concluded, "Consistency means predictability, which means being able to recall names without having to check the manual every time. It's why most people can't use PHP's date or string functions without looking at the documentation, for example." Beyond this there are also intangible benefits, such as presenting a more professional appearance. Because many skilled PHP developers contribute to this project, the Zend Framework community also has an opportunity to lead the general PHP community by example.

There was a lot of agreement from the community (and a couple Zenders) but no movement because the framework was preparing for 1.0. At the time I was told, "There is life after 0.9.0," and so as we prepare for 2.0, I think it's the perfect time to revisit this.

Note: Because this is a non-traditional proposal, the bulk of the proposal will be in the first three sections.

2. References

3. Component Requirements, Constraints, and Acceptance Criteria

Class Names

There are currently 1074 classes that comprise Zend Framework. With few exceptions, these all follow similar standards found in other languages and frameworks. For example, that Java Naming Conventions state,

Class names should be nouns, in mixed case with the first letter of each internal word capitalized. Try to keep your class names simple and descriptive. Use whole words-avoid acronyms and abbreviations (unless the abbreviation is much more widely used than the long form, such as URL or HTML).

The .NET Guidelines for Names state the following:

In general, type names should be noun phrases, where the noun is the entity represented by the type. For example, Button, Stack, and File each have names that identify the entity represented by the type. Choose names that identify the entity from the developer's perspective; names should reflect usage scenarios.

ActionScript Naming Conventions are similar:

Class names are usually nouns or qualified nouns. (...) Don't use nouns that also might be interpreted as verbs. For example, Running, or Gardening. Using these nouns might lead to confusion with methods, states, or other application activities.

Therefore, I propose the Zend Framework Coding Standard section B.3 be modified to include language similar to the following:

Class names must be nouns, noun phrases, or proper nouns (i.e., protocols, formats, algorithms, PHP extensions, or products), with two exceptions.

In cases of classes that represent implementation strategies, an unambiguous adjective is permitted. For example, Zend\Controller\Router\Rewrite is acceptable (it should be interpreted as "RewriteRouter"), but Zend\Loader\Plugin is not, as it is unclear whether the class represents a Zend::Loader plugin or a generic plugin loader. (In this case it is the latter; the class is actually named Zend\Loader\PluginLoader.)

Gerunds (verbs in noun form ending in "-ing") are permitted when a suitable noun cannot be found. The Zend\Measure\Cooking namespace is an example of this.

Verbs, adverbs, and prepositions are not permitted.

Abstract Classes and Interfaces

As Matthew Weier O'Phinney notes, there are issues with PHP 5.3's namespace implementation and the framework's pre-2.0 standard of interface names in the form of Zend_Example_Interface and quasi-standard of abstract class names in the form of Zend_Example_Abstract. As such, I propose the following:

Abstract classes and interfaces are special cases and therefore are treated as such. Abstract classes must be named in the form of Zend\Example\AbstractExample, while interfaces are named in the form of Zend\Example\ExampleInterface.

Abbreviations

Abbreviations are acceptable, so long as they are universally understood and unambiguous, and the unabbreviated word is sufficiently long. Examples include "db", "config", and "info". "Auth" is acceptable so long a disambiguation note is included in the documentation. Examples of out-of-conformance words include "str".

I'd like some community input here. Which abbreviations are unacceptable? What are some examples of common abbreviations that aren't acceptable?

Our Lexicon

A consistent set of names for common concepts is important for the framework to feel like a cohesive whole. To that end, we have standardized on certain words: Alphabetic not Alpha or Text, Alphanumeric not Alnum or TextNum, Directory not Dir, Integer not Int, and Utilities not Util or Utils.

These specific word choices are of course debatable and community input is welcome. Naturally, this is also related to the above section.

Specific class name change recommendations

These are specific name change recommendations.

Old class name New class name Notes
Zend_Acl_Assert Zend\Acl\Assertion  
Zend_Filter_Alnum Zend\Filter\Alphanumeric 1
Zend_Filter_Alpha Zend\Filter\Alphabetic 1
Zend_Filter_Dir Zend\Filter\Directory 1
Zend_Filter_Int Zend\Filter\Integer 1
Zend_Controller_Action Zend\Controller\AbstractAction  
Zend_Controller_Response_Cli Zend\Controller\Response\Console  
Zend_Db_Statement_Oracle* Zend\Db\Statement\Oci*  
Zend_Db_Table_Rowset Zend\Db\Table\RowSet 2
Zend_Gdata_App_Util Zend\Gdata\App\Utilities 1
Zend_Gdata_Calendar_Extension_Timezone Zend\Gdata\Calendar\Extension\TimeZone 2
Zend_Gdata_Exif_Extension_FStop Zend\Gdata\Exif\Extension\Fstop 2
Zend_Log_Filter_Suppress Zend\Log\Filter???  
Zend_Mime_Decode Zend\Mime\Decoder  
Zend_Service_Amazon* Zend\Service\Amazon\Associates* 4
Zend_Service_StrikeIron_USAddressVerification Zend\Service\StrikeIron\UsAddressVerification 2
Zend_Service_Technorati_Utils Zend\Service\Technorati\Utilities 1
Zend_Translate Zend\Translator  
Zend_Validate* Zend\Validator*  
Zend_Validate_Alnum Zend\Validator\Alphanumeric 1
Zend_Validate_Alpha Zend\Validator\Alphabetic 1
Zend_Validate_Ccnum Zend\Validator\CreditCard 3
Zend_Validate_Int Zend\Validator\Integer 1
Zend_Validate_Ip Zend\Validator\IpAddress 3

1 Subject to community input about abbreviations and/or lexicon
2 Does not follow existing naming standard
3 For reasons of clarity
4 This must be namespaced to allow for EC2, S3, etc.

4. Dependencies on Other Framework Components

5. Theory of Operation

6. Milestones / Tasks

7. Class Index

8. Use Cases

9. Class Skeletons

I like it, use as few abbreviations as possible, in favor of unambiguous names.

I am also in favor of this... This would break BC but in a good way I think.

Also, wouldn't be a better name Zend_Logger for Zend_Log?

Both Logger and Log are nouns, and both make sense. I see no reason to rename in this example.

This is a definite must-have for ZF 2.0 in my opinion.

I agree totally with you.
Every respectable framework needs order and a consistent name convention.

Would it also be an idea to use the new PHP Namespaces feature? It'll probably break compatibility with earlier PHP versions (< 5.3), but it'll get rid of classnames like Zend_Controller_Blah_Blah. Instead, you define your Blah class to belong to the Controller namespace, and the Controller in the Zend namespace.

Using the Action class, for example, would change from class SomeController extends Zend_Controller_Action to

<?php
use Zend::Controller;
class SomeController extends Action

Would, from my point of view, be a lot neater - no need to 'fake' namespaces by prefixing classnames with Zend_Something anymore. But that's perhaps not directly related to naming conventions. That, and it breaks pre-PHP 5.3 compatibility.

This proposal will take into account PHP 5.3. The current naming convention is at odds with namespaces in PHP 5.3, so that will have to be addressed. For example, one can't have Zend_Example_Interface or Zend_Example_Abstract because if you say new Interface() or new Abstract() an exception will be thrown. It's possible that the developers of PHP will fix this before the final release, but I doubt it. We may ultimately have to go the route of Zend_Example_ExampleInterface or Zend_Example_IExample.

+1

No arguments here +1

Is there any reason why it's called Zend_Gdata, when all other similar components are grouped under Zend_Service?

Would it not make sense to rename it Zend_Service_Gdata or even Zend_Service_Google to make room for other APIs from Google?

The development of a PHP GData API was part of a deal between Zend and Google, and as part of the deal Google allowed Zend to include the component in Zend Framework (it must also be available separately--see http://framework.zend.com/download/webservices). While Zend_Service_Google (for example) would make more sense in the context of the framework, the name must stay as it is.

Same story for Zend_InfoCard.

Actually, that's an oversimplification. Google abbreviates its own "Google Data API" to "GData". In this case, GData is an appropriate component name. It, and Zend_InfoCard, have top-level namespaces not just because they were developed by partners, but because they provide rich functionality that falls outside the scope of other top-level components. Zend_GData, while a web service, provides much more functionality than most other web services for which we have APIs, and because of its scope does not follow the same design guidelines of other Zend_Service components; Zend_InfoCard relates to identity, authentication, and resource management (falling under multiple top-level components).

Additionally, I'd like to caution against the idea that a nested, hierarchical structure is best for the framework. While it makes sense in some areas, many other areas it does not. One particular pain point of a nested hierarchy is in the documentation: how does a user find the appropriate component, browsing through the manual? For instance, many feel pagination is something that works on data sets, and thus should be under Zend_Data_Paginator – but if all that is in the TOC is "Zend_Data", and you're looking for pagination, how do you find it? In such a case, a flattened hierarchy with at most 2 - 3 levels of depth would aid tremendously.

There are arguments for both styles of organization. I think we need to be careful of renaming for the sake of renaming, and be cognizant of the many requirements of ZF users.

I can see both sides with GData, but I wouldn't change it anyway. By the way, did you realize that you were using my own argument from a few months ago against me? Maybe it was intentional, in which case I laughed.

Agreed about restraining the desire to "rename for the sake of renaming". On the other hand, this will be the single largest renaming effort the framework will ever undergo, so it's important to get it right.

+1

When would this be happening? Is there an estimate date for the release of version 2.0?

No, but it will almost certainly be a little while after the release of PHP 5.3.

I'm thinking it will be 6 - 12 months after 5.3.0. This will give enough time for a bugfix release on the PHP 5.3 branch, and some time for distributions to begin adopting it. Additionally, we'll need time to perform our changes; utilization of namespaces will not be a trivial undertaking, and we also want to identify other areas where new language functionality may help simplify our implementations.

I'm not sure I agree with the "AbstractSomething" and "SomethingInterface" naming convention at this point, even though I'm the one who originally put the idea (or a similar one) forward.

Why? Two reasons: it smacks of Hungarian Notation, and because it's better to use plain language.

As an example, which makes more sense from a language perspective: Zend_Foobar_Adapter, or Zend_Foobar_AdapterInterface? Sure, the latter clearly denotes that it's an interface, but now consider actual usage:

The latter in this case clearly notes an IS-A type of relation, as well as gives a better semantic: $foo IS-A adapter. It's not an interface, it's an adapter.

A similar argument may be made for abstract classes: what particular base functionality is provided? Which of the following makes more sense from a natural language perspective:

In the latter, it's clear that the new class is inheriting some base functionality; in the former, it's less clear what the AbstractRequest provides.

If we're going to get all gung-ho about naming, let's use meaningful names, not type-driven names.

I'm not sure I agree with the "AbstractSomething" and "SomethingInterface" naming convention at this point, even though I'm the one who originally put the idea (or a similar one) forward.

Why? Two reasons: it smacks of Hungarian Notation, and because it's better to use plain language.

I can see how it would seem similar to Hungarian notation, but it's really not that bad. Seems something like "IAdapter" would fit that criticism better. Hungarian notation relies on a shared shorthand, which the full word "Interface" is not.

I go back to first principles in these cases, and one of mine (and, I think, Zend Framework's) is "explicit is always better than implicit". Saying $foo instanceof AdapterInterface is more explicit than $foo instanceof Adapter. For me, explicitly specifying "abstract" communicates more clearly than "base". Base doesn't imply abstract to me.

For that matter, if we're talking about meaningful names, using Zend::Controller::Router::Route::Routable instead of Zend::Controller::Router::Route::Interface could be interpreted as more meaningful. I still like having the word "interface" in the class name in some way, however.

Of course, this proposal is to get people talking, so hopefully we get more feedback.

I think that generic names fit in most cases.
Adapter for example... we use Adapter almost over the whole framework.
Having the classes additionally named Interface and Abstract is in this case irrelevant in my opinion. A Translate_Adapter is always an adapter.

Anyhow the decission itself will be made there is one other point.
WHEN we name it AdapterInterface we should also name it AdapterAbstract or visa versa all types in front and then the class... InterfaceAdapter... AbstractAdapter...

I see no reason, except english grammar, why to have the type in two different places depending on the type. InterfaceAdapter would simply read as InterfaceForAdapter.

I'm with Matthew! Explicity rules (for me).

You could state that you can differentiate naming a class and naming an interface (e.g. interfaces get the pre- or suffix Interface) since those are different language constructs but that doesn't apply to abstract classes of course...

Which Matthew are you with? there are two of us, on opposite sides of the issue.

Sorry Matthew, the other Matthew.

Actually, using Abstract or Interface in the name is Hungarian Notation. HN is simply the practice of naming a variable such that the name "indicates its type or intended use" (see the Wikipedia entry). Typically it starts with a three letter annotation, but it's not restricted to this style. The point, though, is that using the names "Abstract" and "Interface" in the names is not particularly helpful – doing so merely hints to the underlying language level implementation. API documentation, user documentation, and the class/interface declarations themselves are the appropriate places to give those details.

Saying "instanceof AdapterInterface" explicitly says... what? That it implements an interface? That's implicit in the "instanceof" operator, which will only evaluate true if the class implements or extends the right side item. It doesn't matter if the right side item is an interface, an abstract class, or another defined class; what matters is simply that the left side item somehow adheres to the contract (API) it defines.

My "Base" example is definitely a poor one. Here's a better one:

In the above case, we know that we're extending the action controller. Does it matter that it's an abstract class? No. What matters is that we are aware that we're extending something, and that the name states what it is we're extending (an action controller). A class does not need to be abstract to be extended.

Here's another one:

In the above examples, the first indicates that we're defining a controller plugin. In the second, we indicate we're extending a plugin that defines all hooks. These are good, clear, explicit names. Again, how would adding the words "Interface" or "Abstract" make these any clearer? What if at a later date we decided to make AllHooks concrete (maybe it could provide some functionality on its own for managing plugins)? Usage would be the same, but with the rules proposed, we'd need to rename the class!

PHP will tell you if you try to instantiate an abstract class or interface, and will barf up tons of messages as it merrily shuts itself down. Good API documentation and end-user documentation can help alleviate the need for the user to find this information out "the hard way". There's really no need for the implementation information to be present in the class/interface names themselves.

Finally, one of the goals of namespacing is to help shorten names. Including the class types in the names is completely counterintuitive in this regard. Let's stick with sensible names.

In practice, I've never promoted an abstract class to be concrete. I've made interfaces abstracts, and vice versa, but that would necessitate a change in usage anyway.

Let's come from the other side. Say you have an abstract class, Zend::Example. Now you realize that it would be really handy to have a concrete class in its place (for example, for static configuration methods). You'd have to rename the existing class. Now any userland code that extends Zend::Example must likewise change to point to the abstract class.

By explicitly calling it Zend::Example::AbstractExample, you are free to create a concrete class Zend::Example without impacting anything. Examples of this exist in the framework today: Captcha, Measure, Request, and Server, for example.

Let's take another situation. How do you port the following?

In this case, Zend_View already exists.

$foo instanceof Adapter may be self-explanatory, but the real issue is if you are looking at the directory tree, can you instantly pick out if there is an abstract class or an interface?

I absolutely agree with your point of view! With one exception. Class names Plugin or Adapter may be confusing if there is a lot of classes with the same name in different namespaces. Especially when they are (frequently) used in one peace of user code. Namespaces should aviod name collisions. But not only in parse/compile level, but in developer-mind-level too.

This is particular problem of classes *Exception.