develooper Front page | perl.perl6.stdlib | Postings from August 2001

RE: Perl 6 modules plan

Thread Previous | Thread Next
From:
Bill Odom
Date:
August 28, 2001 02:13
Subject:
RE: Perl 6 modules plan
Message ID:
000701c12f84$de499f80$d0fb0a0a@wnodom00
Kirrily 'Skud' Robert [mailto:skud@infotrope.net] said:
>
> My main purpose with perlmodstyle was to give us a starting
> point for a Perl 6 style guide, in time for the Great Rewrite
> that's likely to happen with most of CPAN.
>

I have some raw material that may be useful (and I do mean raw).

Off and on for the last few months, I've been compiling notes on "Perl 
for Enterprise Development."  Topics range from style, formatting,
and naming conventions, all the way to team structure, culture, and
software engineering principles from a Perl perspective.

I originally planned to do a couple of things with this material:

  - Create a developers' guide to be used within my own organization,
    to help ensure the success of Perl-related projects.

  - Educate the powers-that-be in the company I work for that Perl
    is a reasonable choice for the development of maintainable,
    scalable, reliable, [insert desirable trait here] systems,
    despite what they may have heard otherwise.

However, in light of the recent style and SDK discussions here and on 
P5P, I thought it might prove useful to the community at large.

Most of this stuff isn't new, of course.  I was happy to see that 
there's a lot of overlap between my random scribblings and 
perlmodstyle, for example. Stylistic issues owe a lot to the perlstyle 
manpage, the Camel book, and TomC's "Perl Style" talk.  Much of it
comes from staring at my own Perl code and trying to figure out what's
good and what's not.  The team dynamics / culture / pragmatism aspects
are the result of spending a lot of my life developing software,
and knowing what I like and what I don't like about the experience.

Some things to remember:

  - This is a list of ideas, not a finished guide.  The items are 
    discussion points, memory-joggers, and questions to myself, and
    they shift gleefully among first, second, and third-person
    viewpoints (whee, what fun).

  - It's not done.  The categories are ad hoc, items are in only
    the vaguest order, and many areas are missing or woefully
    under-represented.

  - It's written from a Perl 5 perspective, not Perl 6.

  - It's about large projects with multiple programmers or teams
    of programmers.  I'm not advocating the "one true way" to do
    anything.  TMTOWTDI and all that.

  - It wasn't originally meant for public consumption.  If something
    doesn't make sense, ask me what I meant.  I might even remember
    the answer.

So if you're still interested after all the caveats, here it is.
Tear it apart.

 :)


--Bill



===============================
Perl for Enterprise Development
===============================


----------
PHILOSOPHY
----------

Main idea: Many people consider Perl the ultimate tool for individual 
programmer productivity and creativity. Despite its detractors, Perl 
has proven fantastically well-suited for this role -- but often at the 
expense of another role that it is also qualified to fill.  Perl is an 
excellent language for large-scale system development, and, properly 
used, extremely adept at bestowing the same creative, productive boon 
to enterprise projects that it has done so successfully for 
individuals.

Pick your battles. Choosing to develop large systems in Perl *will* be 
controversial, no matter how often it's been successful in the past, 
so be sure to position the language choice appropriately. The 
reputation of the Perl language and community is muddy enough already 
without a failed multi-million-dollar project around our collective 
neck.

Respect the developers. Often, methodologies (either consciously or 
otherwise) paint the actual builders of a system -- the programmers -- 
as uncouth rabble that must be tolerated because they -- tsk, tsk -- 
are so gauche, so blue-collar, that they (horrors) write code and 
(gasp) make the system *work*.  *Don't do this* and don't allow it to be 
done in your organization.

Allow Perl to work for you. The goal of this guide is not to turn Perl 
into Java or Python or C++, but to show how Perl can be used as an 
effective tool for team development and large system creation, and 
*still be Perl*.

While it's certainly possible to write Perl that looks like Java, 
you're probably using Perl because it affords a different approach and 
a different philosophy to solving problems. Don't consign that 
philosophy to the scrap heap just because the problem is bigger.

Be aware of the unique advantages that Perl brings. Many of the 
strictures of other methodologies exist because it is so *hard* to do 
anything with other languages. Taking a rigid, methodical approach is 
the only way to ensure, or at least encourage, timely, reliable 
results.  Perl is different. In the time it might take to perfect one 
particular version of a C++ program, the Perl programmer can try ten 
different approaches, select the best one, and move on.  This is the 
form of TMTOWTDI that we don't often celebrate -- that it can be used 
as a means to finding the *best* way to do it.

Perl programmers are rightly suspicious of this sort of guide.  Too 
often, it's an attempt to relegate programmers to diagram-reading, 
spec-following drones -- just another set of interchangeable parts.  
This guide will *not* be like that, and should work to gently but 
firmly correct that line of thinking.

Yes, there's more than one way to do it -- but not all ways are 
equally good.  This guide is about selecting the ways that are best 
for building software *of a particular type at a particular level*.  
Attempting to promulgate the "One True Way" of Perl is silly and 
pointless, so don't try.

Discuss the "big ideas" in software development, but from a Perl point 
of view. Patterns, refactoring, XP, RUP, other methodologies, etc.  Be 
up-front about how the premises and underlying themes of these ideas 
both agree *and conflict* with the Perl philosophy.  One of Perl's 
greatest strengths is its pragmatism; if something is stupid, it's 
stupid no matter how much hype it has going for it.

Flout the conventional wisdom where it's appropriate.  Example: Strong 
typing, at least in its Pascal/Ada tradition, is a failure.  Other 
sacred cows are ripe for skewering, too.  Perl is not a traditional 
language -- don't force it to act like one.

Explain why the discussion should center on the language at all. 
Aren't we supposed to design systems in a language-independent 
fashion? Use Larry's Turing-complete example, as well as the respect 
for programmers argument. How easy is it to find BCPL programmers 
these days?

To OO or not to OO? Discuss Perl's pragmatic approach to 
Object-Oriented Programming, and how this philosophy should and should 
not be applied to large system development.

Train the teams. Perl is a powerful, rich, baroque language. Make sure 
the builders know how to use their tools, to ensure the 
highest-quality work, and to make sure there's no need to "dumb down" 
the level of development so that untrained team members can keep up 
with the rest of the class.

Reviews, reviews, reviews -- code should never be written or 
incorporated in isolation. The richness of Perl makes this even more 
important -- it's too easy to scatter land mines throughout a system 
without additional sets of eyes to catch them early.

>From Larry's essay in _Open Sources_:

   I began by talking about the virtues of a programmer: laziness, 
   impatience, and hubris. These are virtues of passion. They are also 
   virtues of an individual. They are not, however, virtues of 
   community.

   The virtues of community sound like their opposites: diligence, 
   patience, and humility.

   They're not really opposites, because you can do them all at the 
   same time. It's another matter of perspective. These are the 
   virtues that have brought us this far. These are the virtues that 
   will carry our community into the future, if we do not abandon 
   them.

If you must deliver an all-or-nothing edict, include the rationale. 
People deserve to know why certain practices are forbidden and others 
mandated, and they're also more likely to abide by them.  It's also 
useful to know the reason for a rule, so when the reason is no longer 
applicable, the rule can be discarded.

QUESTION: Who's the target audience for this guide?  Is there more 
than one?  Many of these suggestions are aimed at developers, but much 
of the background information is most appropriate for team leaders and 
technical managers (and PHBs?).

QUESTION: Can teams be smaller by using Perl? Individuals are 
certainly more productive in Perl; does that translate to the team as 
well? I think so, although this needs further thought and 
stats/studies to back it up.

Include a reasoned, level-headed explanation of why Perl is a good 
idea for large system development.



------
DESIGN
------

Don't reinvent the wheel. Perl is provided with many standard (and de 
facto standard) modules and module bundles. Use them. You'll spend 
less time building what's already been built, and you're more likely 
to find developers familiar with standard modules than with those you 
rolled at home. Do you think it will be easier to get assistance with 
CGI.pm or with your custom web-page generation script? CGI.pm is just 
the beginning, of course -- there's DBI, LWP, XML, HTML, Getopts, 
Win32, etc., etc.

When you need a better wheel, start with one that already exists. 
Subclass an existing OOP module, or wrap a non-OOP module. As a last 
resort, patch an existing module (and submit the patches back to the 
author/maintainer). Be careful of version and namespace issues.

TMTOWTDI is a tricky concept to apply to module design.  In general, 
it's best to do one thing and do it well.  In this spirit, use a small 
set of primitives (PoP 105), and resist the urge to provide many 
different ways to accomplish the same task.  The best modules have 
lean, focused interfaces.

Avoid making design choices based on arcane internals knowledge 
(usually for performance or memory optimization).  This stuff changes, 
and the choices you make today based on your nifty knowledge of how 
hashes are implemented may change in the next revision.  If you do 
give in to temptation, however, and do this, document such choices so 
future generations will know why your code is no longer working.

Adhere to the ideas of n-tier design.  Rigorously separate 
presentation, business logic, data, etc.

Where possible, use existing terms for processes, objects, entities, 
etc.; don't invent new ones if reasonable terms already exist.  
Program in the language that makes sense to your customer/audience.

Discuss available frameworks (and similar environments).

Choose your modules carefully.  They can save lots of time and money 
right up until they kill your project.  Use resources that you can 
trust.  Establish that trust through research and thorough testing.



-------
CULTURE
-------

Be familiar with the common (and not so common) Perl idioms -- even if 
your team doesn't use them all.  They'll show up in a lot of code, and 
understanding them is a big part of being a successful Perl 
programmer.

Don't write Perl for programmers that disdain Perl -- Perl's idioms 
and peculiar strengths are the *reason* to use Perl, not something to 
be ashamed of.  Trying to "un-Perl" Perl code removes much of its 
power, and leaves it in a diluted, unpalatable state.  It helps no 
one, and certainly doesn't impress them.

Don't just program in Perl.  Perl is such an adaptable, flexible tool 
that skills and strengths learned in one language or environment can 
often translate quite effectively to Perl.  (It also helps you 
appreciate how nice programming in Perl can be.)

Don't do something just because you can.

Emphasize hubris.

Isolate weirdness (code weirdness, that is).

Practice (and encourage) good behavior even when it can't be enforced. 
(PoP 106).

Find a way to allow programmers to satisfy the urge to write 
incredibly cryptic code -- without actually allowing such code to get 
into the production system.  Some naive ideas:

  - Internal golf and obfuscation contests (part of training, perhaps)

  - Code dissection

  - Code that includes the terse code in docs above the lucid code

  - Mandate that "creative" code has to be reusable, and it has to
    be isolated in a module. Perhaps these excessively creative bits 
    of code should be treated like libraries of binary code. :)

  These may be pretty silly ideas, but the central theme is this -- a
  big part of the reason that Perl programmers program in Perl is 
  because it's fun, and part of that fun is in the incredible semantic 
  density of Perl. Take that away, and you might as well be 
  programming in VB.



----------------------
STANDARDS & GUIDELINES
----------------------

Establish company/organization standards for coding and documentation, 
including the rationale behind the standards.  Use it as a yardstick 
for walkthroughs and code reviews.  Such a guide should be tailored to 
the organization, and often to a particular project.  Update it often.

Establish documentation standards, both for structure and content. 
Code is not complete and does not pass review until documentation is 
complete. Document as you go.

Use the natural program structure to assist documentation.  Don't 
synthesize constructs when the existing code can be used as a 
commenting framework (and this has the added benefit of encouraging 
the parameter/variable/logic grouping).  Personally, I despise huge 
block comment headers that include the subroutine name, the 
parameters, the return code, etc.  Don't do this -- it's extra work, 
and it practically encourages the header and the code to get out of 
sync. Instead, place the description after the sub line.  Same for 
parameters -- provide a comment after the [my $param = shift; ] 
statement, instead of repeating the parameter names in the header.  As 
for value vs. reference parameters -- practically all your parameters 
should be value parameters, with the exception of references.  Call 
out the exceptions to the rule, instead of always specifying (in) 
everywhere.

  So what should be in a subroutine header?
    - Description
    - Return values
    - Exceptions
    - Change history (?)

  And should it be POD or straight comments?

Recommend program structure, common coding style of CPAN authors, etc. 
This is a tough one, as many of the most popular CPAN modules aren't 
the best examples of maintainable code.

Recommend module structure.  Consider recent experience with the need 
for BEGIN blocks and the intermingling of pragmas and regular [use] 
statements.

Recommend multi-file/multi-directory application structure.  Include 
detailed strategies for local library directories (@INC).

Recommend local namespace strategy. Consider the wisdom of 
app-specific namespaces (and the problems that can cause for 
reusability). Describe the standard Local:: namespace.  Discuss the 
use of per-project and per-organization namespaces.

Recommend versioning strategy. Consider/discuss proper use of [require 
X.NNN] and [use SomeModule X.NN] statements.  Discuss naming 
strategies for multiple generations of a module, including backward 
compatibility, addition of new interfaces, etc.

Limit line length to something reasonable. Break expressions into 
meaningful chunks, using the included suggestions as a guide.

Be careful how quickly you allow your project to depend upon newer 
features of the language. An example would be pseudo-hashes -- they 
were a bad idea and now they're gone.

On the other end of the spectrum, don't use deprecated features. 
They're gone for a reason, and are unlikely to be maintained in Perl 6 
and beyond.

Avoid indirect object syntax. Explain why.

Avoid multiple inheritance. Explain why, and discuss exceptions.

Use objects for file and directory handles. Normally, these modules 
would be a memory and performance hit, but in the context of a much 
larger system, the impact is greatly outweighed by their usefulness.  
Reference MJD's article on uses for local, esp. on filehandles.

Avoid typeglobs and symbol-table manipulation.  When necessary, treat 
them the way Perl treats overloading -- as a very special thing, to be 
done only when absolutely required, and then to be isolated and 
wrapped in a protective coating.  There are probably other techniques 
where this is a suitable attitude as well.

Don't depend on precedence.  Use parens to be explicit.

Discuss effective use of context.  Be explicit with scalar().

Be sparing with pre/post increment/decrement embedded in 
expressions. 

"Omit redundant punctuation as long as clarity doesn't suffer." 
Provide examples of clarity vs. lack of clarity.  Usually, putting 
parentheses around function calls is a good example.  It keeps you out 
of trouble with the parser, which is sometimes too smart for your own 
good.  The right answer, as with most issues, is "do it when it makes 
the code better."

Don't [goto] anything, except in the *very* special cases where it's 
appropriate.  Explain those cases.

Show restraint with AUTOLOAD. It's a good way to handle get/set 
methods, but should probably be avoided elsewhere.

Discuss get/set/is methods vs. field access, and the use of lvalue 
subs to get the best of both worlds.

Discuss loop and subroutine exits -- one place or multiple places?  I 
favor the Ada "comb" over Wirth's structure.  Show examples of 
successful combinations of both, with a single unavoidable exit 
location, but with [last] statements to get you there.  Consider 
incorporating Larry's outdented [last] as part of the standard 
formatting.

Suggest sectional markers for program header, pragmas, constants, 
subroutines, and main program.

Provide statement formatting examples.  Be comprehensive.  Provide 
templates for breaking long expressions and statements across multiple 
lines.  This is especially important for statements that may include a 
block of code (like grep or map).

QUESTION: Should the main program have a "main" subroutine?  I don't 
do this (currently), but is there a maintenance advantage to it?  It 
might be useful for lexical variable isolation if nothing else.  What 
are some other good reasons to have it?

QUESTION: Should subroutines come before or after the main program? I 
like them before, but I was raised on Pascal.  Also, you don't need 
the [use subs] pragma.  Others find having the main logic of a program 
or module at the top of the file is better, since it emphasizes the 
main idea.  However, there's a nearly mandatory chunk of code that 
will be at the beginning of any non-trivial program or module, and you 
have to get past that anyway.  Also, POD comes after the __END__, and 
there's usually a comment to that effect.

Provide guidelines for building a module, including POD.

Provide guidelines for building a class.

Provide guidelines for building a subroutine.

Explain why prototypes should be avoided, except when they shouldn't.

Provide naming conventions for packages, modules, subroutines, 
lexicals, global/package variables, constants, filehandles, 
dirhandles, heredoc tags, block/loop labels, methods (including 
get/set routines).  (See next few paragraphs for example discussion).

Provide rules for use of similar names among scalar/array/hash 
namespaces. Don't forbid it -- sometimes it makes a lot of sense, and 
can make the code much more readable.

Thoughts on sub/method naming conventions:
  - sort => by_name
  - boolean => is_dirty
  - conversion => to_lower
  - inplace conversion (like chop or chomp) => ???

Don't prefix sub/method names with the package/class/object name; the 
package or object name provides the appropriate semantic cue.

Discuss grammatical and parts-of-speech guidelines for for naming of 
modules, classes, methods, subs, etc.

QUESTION: Are there variable prefixes that *do* make sense?  Since 
array entries and scalars are so easily confused, for example, should 
all arrays begin with 'arr' (or 'a') ? Al hashes with 'hash'  How 
about suffixes instead?  'ref' for references (perhaps as a suffix)?

  DISCUSSION:
  I intensely dislike Hungarian notation, and there are some very good 
  arguments against it (which I should probably find and read again). 
  However, I'd be lying to say it doesn't serve a useful purpose, and 
  it does get easier to read after a lot of exposure.  Perl already 
  has some built-in prefixes, however, and adding textual prefixes to 
  the batch may make things worse instead of better.

  Hungarian is probably most popular in VC++ and VB, due to the need 
  to know when to cast in C++, and a way of differentiating among all 
  the controls and objects in VB.  Perl doesn't need these types of 
  things so often.

  While I don't recommend going Hungarian, a set of reasonable 
  prefixes and suffixes is worthwhile if used selectively.  They're 
  especially useful when your code contains a mix of objects and names 
  associated with those objects.  For example, if you're dealing with 
  users, then what does $user refer to?  Is it the user's ID, or an 
  object containing properties for this user (one of which is probably 
  the ID)?  A set of suffixes and prefixes can avoid this confusion.  
  This also extends to problem-specific suffixes, which you probably 
  already use quite naturally.  An example might be "dn" for 
  "Distinguished Name" in an LDAP application.

  It's more natural to use a combination of funny characters, case 
  differences, and plurality to distinguish among different variable 
  semantics.  (provide real examples; these are just a stub)

      Use plural nouns for arrays:
      
          @widgets

      Use singular nouns for non-ref scalars:
      
          $widget
          $the_widget
          $widget_width  # this will probably bomb

      Use 'is_' prefix for boolean scalars:
      
          $is_dirty = 1;

      (similar rules for hash keys)

      Use '_of' suffix for hashes where appropriate:
      
          $color_of{$widget} eq 'green'

      How to handle references?  '_ref' suffix seems popular, but it's 
      verbose.  In pseudo-Hungarian, 'rWidget' is common. Maybe 'r_' 
      prefix?  What's most readable in actual code?

      Similar questions for objects.  (If you have to affix it with a 
      marker, then it may not be much of an object?)

  Expand on this citation from perlstyle:

      You may find it helpful to use letter case to indicate the scope 
      or nature of a variable. For example: 

         $ALL_CAPS_HERE   constants only (beware clashes with
                          Perl vars!)
         $Some_Caps_Here  package-wide global/static
         $no_caps_here    function scope my() or local() variables

      Function and method names seem to work best as all lowercase. 
      E.g., $obj->as_string().

      You can use a leading underscore to indicate that a variable or 
      function should not be used outside the package that defined it.

  A couple of notes:

    - Notice the warning about clashes with Perl vars, which may be
      a good argument for a more modern constant naming convention.
      It has certainly happened to me, with $RS.

    - The leading underscore convention is a nice idea, but it seems
      weak for the level of maintainability I'm trying to achieve
      here.

  Discuss exceptions to the established naming convention; Win32 code 
  is a good example.  While $names_like_this are great in a Perl-only 
  world, they can be tough to deal with in a Windows project, where 
  $NamesLikeThis are the rule.  In general, it may make the most sense 
  to adapt to the world you find yourself living in. Perl is a good 
  citizen, able to play well with others -- and sometimes that means 
  it has to adapt to the environment it's playing in.

  Avoid variable names that differ in case only.  *Possible* 
  exceptions include names that are all upper (CGI) vs. all lower 
  ($cgi).

  It would be easy (and wrong) to declare a blanket prohibition 
  against giving different types of variables (scalar, hash, etc.) the 
  same name.  However, it often makes a lot of sense, and makes the 
  code very easy to understand (and practically self-documenting).

  Similar variable names should live in the same semantic space.  For 
  example, $widget and @widgets make sense -- but be careful not to 
  create such mental associations where they're not appropriate.

Avoid action at a distance and adhere to the "Principle of Least 
Astonishment."  This does *NOT* mean a blanket prohibition against 
Perl idioms.

Choose the appropriate loop for the task.  Don't force one to be 
another.  Also, some types of loops are best avoided altogether.  The 
do {} and do {} until are both suspect. Be clear about when to use 
them.

The "postfix conditionals" are "postfix iterators" are *easy* to 
overuse.  Don't.  Consider limiting to statements with "atomic 
impact," like debug statements.

Put important things first.  This applies to statements, but may also 
make sense for subs and modules.

Be wary of boolean operators used to control program flow.  It's 
probably best to limit such use to [ some_statement or die ] style 
constructs. Another exception to the rule may switch-style statements.

Use spaces instead of tabs.  If you absolutely must use tabs, use 
standard tabs.  But just make life easier on all of us and use spaces.

Minimize "synthetic code" (see articles by MJD).

Discuss exporting names into the calling namespace. Never, but with 
lots of :tags to make it easy? Also discuss from the angle of the 
importer, i.e., how much to import?

Pick a style of switch statement.  Simpler is probably better.  Don't 
be ashamed of the if .. elsif .. else if it's appropriate.

Don't refer to a package by static name within the package itself.  
Discuss alternatives, including __PACKAGE__ , caller(), etc.  
Generalize to rules regarding module names and position independence.

Discuss appropriate use of $_.  Again, don't just forbid it; use what 
makes the code easier to maintain and to understand.
  - Best used in short code segments.
  - Can't depend on $_ having a very long lifetime.
  - If you use it, localize it.
  - Discuss places where it's mandatory.

Discuss the wisdom of initializing variables at the point of 
declaration, vs. providing initial values as part of program logic. 
(Of course, if variables are always defined as close as possible to 
their point of use, then this issue may just go away.)

  PRO:
  - Provides a clue as to the expected type of value that this
    variable will hold, at least for scalars.
  - Avoids spurious "use of uninitialized value" warnings.

  CON:
  - Masks *real* uninitialized value warnings.
  - Perl already provides useful initial values for you,
    so why do it again?
  - Clutters the code
  
  Should initial values only be 0 or empty string for scalars, and 
  empty list for arrays and hashes?  Initializing to other values 
  mixes logic and declarations, which is generally a bad idea.

Use by-name interfaces to functions where they are available.  
Examples include time and stat, among others.

Provide guidelines on dealing with the subtleties of true/false, 
defined/undef, "", 0, etc.  Be sure to consider context issues, esp. 
around return statements.

Avoid using the older &subname style of subroutine calls.  For the 
situations where it's necessary (to bypass prototype checking, for 
example, or to automatically pass @_ ), document the heck out of it.  
Even better, figure out why you need to do it and eliminate the cause 
of the trouble.

Use the /x option for complex regexes.  Comment liberally.

Build complex regexes a piece at a time, for easier maintenance and 
understanding.

Declare variables one line and one variable at a time, for ease of 
maintenance and documentation.

  Do this:

      my $var1;  # documentation on $var1
      my $var2;  # documentation on $var2

  Instead of this:

      my ($var1, $var2);

  (This is likely to be a flashpoint, and I doubt it's worth the 
  effort to argue with people over it.)

Select an object reference notation and stick with it.  $self, $this, 
$me, whatever... just be consistent.  $self seems to be the most 
popular, but this is also a topic ripe for holy war.

Discuss bracing styles, and be prepared for a backlash.

Discuss advantages and disadvantages of the English module.  I don't, 
but the advent of Perl 6 may change that.

Of course, use the strict and warnings pragmas.  Discuss use 
diagnostics, especially in a debugging context.

Discuss the applicability of taint mode.  It's not just for web apps.

Know when to use local, and only use it then.

Always local'ize punctuation variables before changing them.

Prefer our to use vars, except in cases where backwards compatibility 
is an issue.

Use constants.  Discuss the pros and cons of different constant 
creation techniques.  Discuss constant naming techniques (ALL_CAPS vs. 
prefix vs. etc.).

Avoid direct use of subroutine parameters via @_, even for reading.

Avoid changing parameter values.  Return lists / hashes instead of 
modifying incoming variables.  Less chance of blowing up when passed 
constant values, too.

Name parameters using

    my $param = shift || "default value";

  instead of this:

    my ($p1, $p2, $p3) = @_;

  The first allows for cleaner documentation and easier maintenance,
  esp. w/ default values.

Use named sub arguments for complex argument lists.  Show techniques 
for doing so.  Prefer list vs. anonymous hash except in rare cases 
where a subroutine accepts both types of lists.

When it can't be avoided, group access of external data (such as 
global variables, file-scoped lexicals, or program configuration 
values) into a single location near the beginning of a routine. 
Consider these values to be like special parameters.  Of course, if 
access to such external data can be avoided, avoid it.

Define guidelines for use of [ # end block ] markers.  They're a 
little silly when the whole statement is five lines long -- you can 
see the whole thing on the screen at once, and there's no doubt where 
it starts or stops.  For a nested statement twenty lines long, 
however, an ending statement marker is a good idea.

Discuss: Define all the variables for a routine at once, or define 
variables as close to the scope that uses them as possible?  In any 
case, declare all variables for a program or a scope at the beginning 
of the block.

The ready availability of hashes and lists sometimes keeps us from 
using other more advanced data structures, even when they're the right 
answer.  Know your options, and use a more exotic structure when you 
need it.

Explain when to use exception handling vs. return-value tests.

Discuss the appropriate use of exceptions (i.e., eval/die/$@).  The 
conservative approach is that exceptions are only for exceptional 
conditions, and are not part of the normal logic flow of a program.  
However... exceptions can often clean up the "happy path" of a 
routine, and can make it more understandable.  This topic deserves a 
lot more discussion (and research).

Build and use a real error/exception handler.  Discuss the appropriate 
scoping of such a handler, and the alternatives available (i.e., 
Graham Barr's Error module) for more advanced handling.  Look at Matt 
Sergeant's presentation on this subject, too.

Avoid doing anything in a BEGIN block that can change the external 
environment.

On whether or not to always use double quotes:

  Performance isn't the issue -- understanding is. During compilation, 
  Perl will resolve double-quoted strings to determine whether or not 
  interpolation is required, so using double quotes doesn't decrease 
  performance (ignoring the infinitesimal difference in compilation 
  time).

  But that's not the point. Double quotes *mean* something -- to the 
  reader of the code, they say "there's stuff in here that's 
  interpolated."  If that's not true, then the maintainer either 
  spends time looking for variables where there aren't any, or misses 
  them when they *are* there because you've accidentally taught him 
  that double-quoting doesn't necessarily mean anything in your code.

  So use double quotes when you need interpolation, and use single 
  quotes otherwise -- not for some nanosecond improvement in 
  performance, but for a real improvement in understandability.

Don't wait until you need to use a routine twice to make a subroutine 
or a method for it. Instead, build subs in order to capture ideas and 
discrete tasks; this allows for more concise expressions of 
higher-level routines.  Consider using "my subs" if the routines 
absolutely *must* be private.

(BTW, this may be a good way to allow for "extra creativity" -- give 
it a descriptive name and hide it in a subroutine.)



------------
TESTING & QA
------------

(This is a huge topic that's undergoing a lot of positive change in 
the Perl world.  Research it heavily before getting too far out on a 
limb.)



----------
DEPLOYMENT
----------

Discuss deployment techniques to ensure the integrity of your 
application, and avoid "DLL-Hell."
Examples include:
  - Local installation of all modules with your application
  - Private Perl installation
  - Version checking of all modules used (at a single point
    during app startup?)

Discuss app servers and their equivalents.



--------------------
TOOLS & ENVIRONMENTS
--------------------

Developers should, whenever possible, select their own tools.  It's 
downright stupid to demand that a developer switch tools just because 
of some misguided policy.  Interoperability is a valid concern, of 
course, but don't get carried away.

Select tools that can be automated in Perl.

Use source code management software, and make sure that using it is so 
transparent that no one has to think about it.

Use automated tools for testing and validation, such as perltidy and 
the B:: modules.




-------------------
MISCELLANEOUS NOTES
-------------------

Good sources to cite/consult, along with the O'Reilly Canon and 
Damian's OOPP:
  Kirrily Robert's "In Defense of Coding Standards"
  MJD's articles, esp. on strong typing, "Sins of Perl," synthetic 
  code
  _Effective Perl Programming_
  _The Practice of Programming_
  _The Elements of Programming Style_
  (lots and lots of others)

Include a recommended reading list, perhaps per topic (like Damian's 
OO book does).

QUESTION: What aspects of successful Open Source development also 
apply here?

Include sections on _Reliability_, _Scalability_, _Security_, 
_Performance_, and _Portability_.

There are techniques and tools that are not as widely known as they 
should be, and should be given some attention.  Memoize is a good 
example.

Scott Meyers' "Prefer X to Y" style of recommendation may be 
appropriate.  It worked well for _Effective Perl_, too.

Contact other people who've done this before, and include their 
experiences and lessons learned.



Thread Previous | Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About