Документация
HTML CSS PHP PERL другое

Section 3.1.  Identifiers

 
Previous
Table of Contents
Next

3.1. Identifiers

Use grammatical templates when forming identifiers.

The single most important practice when creating names is to devise a set of grammar rules to which all names must conform. A grammar rule specifies one or more templates (e.g., Noun :: Adjective :: Adjective) that describe how to form the entity on the left of the arrow (e.g., namespace). Placeholders in templates, such as Noun and Adjective, are replaced by the corresponding parts of speech: nouns like "Disk" and adjectives like "Audio". For a Perlish introduction to the concepts of grammars, see the tutorial.html file that accompanies the Parse::RecDescent CPAN module.

Develop a set of "name templates" for your packages' subroutines and variables, learn them by heart, and use them consistently. This practice will ensure that you always generate names that have a standard internal structure.

A suitable grammar rule for naming packages and classes is:


    
namespace
Section 3.1.  Identifiers
Noun
::
Adjective
::
Adjective
|
Noun
::
Adjective
|
Noun

This rule might produce package names such as:


    package Disk;
    package Disk::Audio;
    package Disk::DVD;
    package Disk::DVD::Rewritable;

In this scheme, specialized versions of an existing namespace are named by adding adjectives to the name of the more general namespace. Hence you would expect that Disk::DVD::Rewritable represents a class derived from Disk::DVD, which in turn inherits from the general Disk class. Placing the adjectives last (in defiance of the usual English convention[*]) ensures that the most prominent feature of any class or package name is the hierarchy in which the class belongs.

[*] The approach advocated here is much more like the Linnaean system of biological taxonomy: a "genus" name followed by one or more increasingly specific modifiers. Such schemes make it easy to detect that the common Camelus dromedarius and the less-common Camelus bactrianus are two species of the same genus, that the endangered Camelus bactrianus ferus is a particular subspecies of Camelus bactrianus, and that all three creatures are wholly unrelated to the elusive Nessiteras rhombopteryx.

It's important to remember, however, that Perl won't automatically enforce the hierarchical relationships indicated by this naming scheme. You still have to specify those relationships explicitly:


    package Disk;

    package Disk::DVD;
    use base qw( Disk );

    package Disk::DVD::Rewritable;
    use base qw( Disk::DVD );

The naming scheme is purely to help human readers of the code identify and remember the relationships you specify.

Variables should be named according to the data they will store, and as specifically as possible. Variables that are used in more than one block should always have a two-part (or longer) name. Reserve single-word names for variables of very limited scope and, even then, consider whether a longer name would be clearer. The recommended grammar rule is very simple. A variable is named with a noun, preceded by zero or more adjectives:


    
variable
Section 3.1.  Identifiers
[adjective
_
]* noun

The choice of nouns and adjectives is critical. The nouns in particular should indicate what the variable does in terms of the problem domain, not in terms of the implementation. For example:


    my $next_client;             
# not: $next_elem
my $prev_appointment;
# not: $prev_elem
my $estimated_nett_worth;
# not: $value
my $next_node;
# not: $node
my $root_node;
# not: $root
my $final_total;
# not: $sum
my $cumulative_total;
# not: $partial_sum

The use of adjectives to make an identifier more specific is strongly encouraged. The more specific a name, the easier it is to detect mistakes such as:

    my $total = 0;
    my $count = 0;

    while (my $next = get_next_score_for($curr_player)) {
         $total++;
         $count += $next;
    }

That algorithmic error would be much easier to pick out if the variables had more explicit names:


    my $total_score = 0;
    my $games_count = 0;

    while (my $next_score = get_next_score_for($curr_player)) {
         $total_score++;
         $games_count += $next_score;
    }

Incrementing a "total score" is dubious; adding a "score" to a "count" is almost certainly wrong.

Furthermore, the use of qualifiers on variable names can help reinforce the reader's understanding. For example, if a cumulative total is to be printed on each iteration, it would be better to name the variable like so:


    my $running_total = 0;
    my $games_count   = 0;

    while (my $next_score = get_next_score_for($curr_player)) {
        $running_total += $next_score;
        $games_count++;
        print "After $games_count: $running_total\n";
    }

This style leaves the maintainer of the code in no doubt that you really did intend to track cumulative intermediate scores, rather than just the final total. That would be especially obvious if you had accidentally mistyped:


    my $running_total = 0;
    my $games_count   = 0;

    while (my $next_score = get_next_score_for($curr_player)) {
        $running_total += $next_score;
        $games_count++;
    }
    print "After $games_count: $running_total \n";

Note that the rules for creating variables ($adjective_noun) are the opposite of those for naming classes and packages (Noun::Adjective). This is deliberate, and designed to help readers distinguish between the two types of names. The more conventional grammatical structure (adjective before the noun) is used for the more frequently used type of name (i.e., for variables), which improves the overall readability of the code. At the same time, namespace names stand out better because of their unusual reversed syntax.

There is one extra grammatical variation that applies only to hashes and arrays that are used as look-up tables:


    
lookup_variable
Section 3.1.  Identifiers
[adjective
_
]* noun  preposition

Adding a preposition to the end of the name makes hash and array accesses much more readable:


    my %title_of;
    my %ISB N_for;
    my @sales_from;

    
# and later...
while (my $month = prompt -menu => $MONTH_NAMES) { for my $book ( @catalog ) { print "$ISB N_for{$book} $title_of{$book}: $sales_from[$month]\n"; } }

For subroutines and methods, a suitable grammatical rule for forming names is:


    
routine
Section 3.1.  Identifiers
imperative_verb[
_
adjective]?
_
noun
_
preposition
|
imperative_verb [
_
adjective]?
_
noun
_
participle
|
imperative_verb [
_
adjective]?
_
noun

This rule results in subroutine names such as:


    sub get_record;                        
# imperative_verb noun
sub get_record_for;
# imperative_verb noun preposition
sub eat_cookie;
# imperative_verb noun
sub eat_previous_cookie;
# imperative_verb adjective noun
sub build_profile;
# imperative_verb noun
sub build_execution_profile;
# imperative_verb adjective noun
sub build_execution_profile_using;
# imperative_verb adjective noun participle

These naming rulesparticularly the two that put participles or prepositions at the ends of namescreate identifiers that read far more naturally, often eliminating the need for any additional comments:


    @config_options = get_record_for($next_client);

    for my $option (@config_options) {
        build_execution_profile_using($next_client, $option);
    }

    Previous
    Table of Contents
    Next
    © 2000- NIV