Let's meditate for a while...
Latest Update: Monks, I created a follow-up thread to this one: 20 tips to avoid pitfalls while Programming Perl
Update: Monks, thank you very much for your responses. Every one of you contributed valuable thoughts. Even if I didn't reply to your post, I have read it and I'm considering what you said. I have decided to rethink my strategy and I will let you know when I am ready with something new. You may still contribute if you like, I will keep following this thread. Thanks again!
Untouched original post here:
For my work, I am trying to compile a list of the 20 most important Perl Best Practices. I don't want to have too many, because I don't want to scare people, but I want to have enough to improve the quality of the code developed by less experienced co-workers (or some careless ones). So far, I came up with 13, so I am missing 7 to complete my list. If you wish to contribute to the list, I would really appreciate it! Plus, I hope it could benefit people who read this thread.
I have read Perl Best Practices from Damian Conway (O'Reilly), I think it is a great book but I really want to limit myself to 20 best practices. Certainly, there are practices more important than others. In my opinion, there is three goals to following a set of best practices while developing Perl code:
- Robustness
- Efficiency
- Maintainability
Here is my list:
1) Place a semicolon after every statement.
Yes, the last statement inside a block can be written without a semicolon. Put one anyway. Even if there is only one statement in the block.
2) Never place two statements on the same line.
Yes, it works. But don't do it.
3) Always start your elsif or else block on a new line.
Don't put elsif or else on the same line as the closing bracket of the previous if or elsif block.
4) Always use a label on loops when using next, last and redo.
This way, if you later add another embedded loop around your next, last or redo statement, your code will not break, it will still act on the outer loop, not the new inner loop. Also, it helps readability.
5) Use lowercase characters and underscore to separate words in an identifier.
Don't use CamelCase. This is true for variables and subroutines.
6) Use CamelCase or uppercase for package names.
CamelCase is preferable over uppercase, unless it is an acronym. Never use all lowercase. Never use underscore.
7) Use uppercase characters and underscore to separate words in a constant.
Don't use CamelCase. Never use lowercase.
8) In classes, prefix subroutines with an underscore to identify an "internal use only" method.
In Perl it is not possible to create a private function like in Java or C++. Still, you should identify your methods accordingly.
9) Never use $_ or the invisible equivalent.
Always define your own variable in a foreach loop. Never use print or /regex/ with the invisible $_.
10) Never use @_ in subroutines.
Always copy it's content to your own array or list of scalar variables.
11) Always use if blocks, never postfix if statements as a one-liner.
There is an exception to this rule: when using flow of control commands.
12) Use postfix if statements when using flow of control commands.
Flow of control commands are : next, last, redo, return, goto, die, croak and throw.
13) Use unless and until as little as possible.
Unless and until could be very confusing. It is preferable to use if and while with a negative statement. Use unless and until only with positive statements so you don't create a double negative logic, which would be twice as confusing! Never follow an unless block with an else block.
Monks, what do you think? This thread is opened to debate, if you don't like what I have put in the list, please let me know, and most importantly, explain why.
Thank you!
Take my advice. I don't use it anyway.
Re: 20 most important Perl Best Practices
by moritz (Cardinal) on Aug 22, 2012 at 20:30 UTC
|
3) Always start your elsif or else block on a new line.
That seems to be a pure stylistic choice, cuddled else don't decrease robustness, efficiency or maintainability -- they just make some diffs a tiny bit larger.
9) Never use $_ or the invisible equivalent.
Always define your own variable in a foreach loop. Never use print or /regex/ with the invisible $_.
That's just stupid. If the scope for $_ is small, there's no reason to avoid it. Even more, if you don't want to use $_, you are doomed not to use map, grep and friends from List::Util. Which can make code much more maintainable.
Compare
my @filtered = grep /someregex/, @original;
with
my @filtered;
for $str (@original) {
if ($str ~~ /someregex/) {
push @filtered, $str;
}
}
I for one find the first one much more readable and maintainable, because it has less boilerplate code.
Unless and until could be very confusing.
They could be, if you used them in a stupid way. Like with a negated condition. But so could be the if and while equivalents. I agree about unless and else blocks though.
What I don't like about your list is that it forces people to write very unperlish code, and (implicitly) forbidding map and grep seems like you are afraid of their power. Maybe that's because you haven't understood them yet?
Anyway, here are my top 3:
1) Don't do stupid things
It's usually pretty obvious if code will be hard to maintain later on. Convoluted call graphs, 50-char regexes without whitespaces and excessive use of magic literals all indicate that you don't want to end up maintaining the code. So don't do that. But you don't need a rule for everything if you apply your common sense.
Which brings me to my second point:
2) Think about what you write
That one is pretty obvious, no?
3) Be consistent
In many ways it doesn't matter much how exactly your programming style looks like, as long as it's consistent. If you don't code alone, make sure to agree on some style with your peers.
| [reply] [d/l] [select] |
|
| [reply] |
|
| [reply] |
Re: 20 most important Perl Best Practices
by eyepopslikeamosquito (Archbishop) on Aug 22, 2012 at 22:12 UTC
|
I have some experience in this area, starting from
the time I wrote On Coding Standards and Code Reviews.
I think a top twenty list is a good idea because many
folks are turned off by very long lists.
However, the top twenty list should focus on things
that matter -- not trivia or dogma.
Unfortunately, your list seems to focus on things
I would describe as "trivia". Indeed, most of your
list could be covered by a single point: "Agree upon a coherent layout style and automate it".
Here's my attempt at a top twenty list:
- Correctness, simplicity and clarity come first.
- Avoid unnecessary cleverness. If you must rely on cleverness, encapsulate and comment it.
- Avoid duplication (DRY).
- Coupling and Cohesion. Systems should be designed as a set of cohesive modules as loosely coupled as is reasonably feasible.
- Data hiding. Minimize the exposure of implementation details.
- Minimize the scope of variables, pragmas, etc..
- Establish a rational error handling policy and follow it strictly.
- Interfaces matter. Once an interface becomes widely used, changing it becomes practically impossible (just about anything else can be fixed in a later release). Design the module's interface first.
- Design interfaces that are: consistent; easy to use correctly; hard to use incorrectly; easy to read, maintain and extend; clearly documented; appropriate to your audience. Be sufficient, not complete; it is easier to add a new feature than to remove a mis-feature.
- Write components that are testable in isolation.
- The result of every file operation or API call or external command should be checked, and unexpected results handled.
- Use descriptive, explanatory, consistent and regular names.
- Avoid magic numbers.
- Don't optimize prematurely. Benchmark before you optimize. Comment why you are optimizing.
- Agree upon a coherent layout style and automate it.
- Adopt a policy of zero tolerance for warnings and errors. Tools such as Perl::Tidy and Perl::Critic can help here.
- Commenting: prefer to make the code obvious; don't belabor the obvious; comments describe what and why not how.
- Separate user vs maintainer documentation.
- Use a revision control system and single-step automated build/test.
- "Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live" (Damian Conway)
Rather than the standards police enforcing a standard
on a team, I think it is better to set up a wiki page
and encourage all team members to add to it during
a code review, or at any time, when they find
something that could improve the coding standard.
That is, create a vibe of inclusiveness with everyone
trying to improve the quality of the shared codebase,
not individuals fighting the standards police.
And with a focus on real world things that matter,
not trivia or dogma.
The coding standard should be a living document.
| [reply] |
|
| [reply] |
Re: 20 most important Perl Best Practices
by ww (Archbishop) on Aug 22, 2012 at 19:51 UTC
|
No downvote; you're entitled to your opinions and local practices, but the only items I can endorse are 1, 2 and possibly 8 ... and even those have exceptions.
As for the rest of the list? Contentious, at best. Some shops will work well with your kind of internal policy; others would turn into hell-holes were they to adopt this kind of rigid (and, in many cases, IMO, ill-advised) rules.
- 3: Some of us regard nested } else { statements as easily readable. Though trivial, for me, the required, subsequent additional scrolling in't worth the supposed gain.
- 4: Perhaps a good idea if your shop is mostly full of minimum-wage noobs. The kind of breakage you're trying to avoid isn't generally a problem with skilled programmers given time to work carefully (...yeah, yeah, yeah -- but I'd love to live :) in a more nearly perfect world.)
- 5, 6 & 7: Again, arguably reasonable as a standardization technique; the specifics, however, are not universally acceptable.
- 9 & 10: Aw, c'mon. Are your minimum-wage hacks also unable to read code accurately?
- 11 & 12: Bunkum, IMO, but at least present them as the single point they actually constitute.
- 13: Well.... maybe. The headline statement is valuable; the narrative wanders off into disputable territory.
Now, how about some items that should be included:
- use strict; use warnings; (oops, two statements on one line...) UNLESS you are very sure of a good (coding) justification for omitting them!
- Generally, prefer use warnings over -w because of its limited scope (of course, if incompetents are writing the modules or somesuch, ignore this rule).
- Indent and break logical sections with an extra newline (yes, I know this is at least to some extent inconsistent with the observation about your 3. "Consistency," a wise man observed, "is the hobgoblin of little minds.") Use white space to make your code easy to follow.
- (Add some of of many possible guides on commenting.) My own choice would be to tell the programmers to use inline comments only for non-routine syntax or unusual construct (and I would provide some format guidlines: same line? minimum white space between code a # comment..., etc). Advise that the concepts behind most routine comments are better included in documentation, whether plain POD or something more elaborate.
- Documentation. The programmer(s) should know better than anyone else the high points and the lows; the capabilities and perhaps the shortcuts available to the end user. Don't simply hand that off to tech writers who may or may not have the skills and experience to fully explain your code.
PS: Don't mix as many fonts and styles as I've done here :(
| [reply] [d/l] [select] |
|
First, thank you for your constructive input. It is really appreciated.
Now, to give you a little perspective, the firm I work for does not hire minimum
waged developpers, and it's not about trying to manage newbies. In fact, it is so
hard to find experienced Perl developpers that the firm hire C++ or Java
developpers and train them to Perl. I'm not even kidding. I am not saying
everyone being hired is forced to work in Perl, but the group I work with mostly
do Perl development, some other groups also use Perl, C++ and/or Java. In my
group, we support old applications but we also build new ones, in Perl.
On our systems, not only we have access to all the (approved by the firm) CPAN modules but we have access to all the versions of these modules, build for all version of Perl from 5.8, 5.10, 5.14, in 32 and 64-bits.
So, the best practices I am trying to compile is of course to improve the
readability of the code, because it is certain that multiple programmers will
work on it, but most importantly, it is a tool for less experienced developpers to avoid pitfalls that could lead to hours of debugging weird issues. Note that we have dozens of different projects, all object oriented, some uses Moose and MooseX syntax, and several projects share dependencies with each others. It is serious stuff we are doing.
With that said, I will add some explainations on the selection of the best practices you are debating.
3: You are right, it is as easily readable but at some point we need to choose one or the other. I hate to see two different styles in the same file. I like the way I mentionned because it adds a natural empty line, and it answers your recommandation: Use white space to make your code easy to follow.
4: This one I added last to my list. I am not sure about it.
5, 6, 7: This is mostly for consistency, since we have multiple developpers working on the same projects. It is debatable, I agree.
9, 10: These are not about readability. In our experience it may lead to very weird problems. We use a lot of callback functions and we often use classes that extend other classes. This one doesn't come from me but it was already in place before I started working here.
11, 12: This is for readability. You are right, I will merge them.
13: OK I will try to re-state the narrative. Got this one from Perl Best Practices.
For the rest, of course we use strict and warnings. It is so obvious to me that I forgot to add it! Indent, break, empty lines, white spaces, etc. I think this is obvious for any language. I may add it as a best practice. Commenting and Documentation too!
Thank you again! Very appreciated!
Take my advice. I don't use it anyway.
| [reply] |
|
+ +
However, despite the fact that your response appears well thought out -- in fact, excellent, comprehensive and clear -- I'm not strongly enough persuaded to adopt your package.
Your objective appears to boil down to 'maintain consistency, across multi-programmer work, across files, and across interdependent packages' (a point on which I'm wholly in agreement) but that's a best practice in itself; most of the details you enumerate are just details and could vary widely from establishment to establishment while still useful as elements informing a local "best practice."
Speaking of details, the advice I received somewhere, long ago and in a faraway place -- most likely -- that one should use use single quotes rather than double when assigning values, etc, might fit well with your scheme. If nothing else, it tends, for me, anyway, to pay attention to interpolation issues.
| [reply] |
Re: 20 most important Perl Best Practices
by GrandFather (Saint) on Aug 22, 2012 at 21:21 UTC
|
Many of your "best practices", as pointed out by others, are simply style guides. Hack out a Perl::Tidy configuration the team is happy with and most of that stuff is taken care of. Oh, you might still want to impose local constraints on identifier construction and stuff of that nature, but those really are not Best Practice items.
You may also find Perl::Critic is a helpful tool.
BTW: I find statement modifiers read very nicely. They break the flow much less than the same statement broken into two parts by forcing half of it into a block. A single succinct entity is easier to comprehend than the same code broken into two disparate parts.
True laziness is hard work
| [reply] |
Re: 20 most important Perl Best Practices
by Riales (Hermit) on Aug 22, 2012 at 20:01 UTC
|
These are not so much best practices as they are style guidelines. You should probably introduce them as such. | [reply] |
|
| [reply] |
Re: 20 most important Perl Best Practices
by aaron_baugher (Curate) on Aug 22, 2012 at 22:40 UTC
|
1) Place a semicolon after every statement.
Agreed; if I come back to add another statement later, I don't want to have to look and see whether the formerly-last statement has a semicolon yet. Same reason applies when always following the last item in a list with a comma. (The inability to use that trailing comma is reason #853 why I hate PHP.)
2) Never place two statements on the same line.
Eh. In most cases, yes; but when I have two or more small statements that go together as a set, it's clearer to me if I put them together on one line. For instance, if setting a set of 3D coordinates:
$x=3; $y=4; $z = 5;
# or maybe better
($x, $y, $z) = (3, 4, 5);
Of course, the second one is a single statement with three effects. But can you really say it's okay and the first one is bad? To me, either one makes it very clear that the items are a set, and the statements are short enough that it saves space without getting overly dense.
3) Always start your elsif or else block on a new line.
Get thee behind me. I hate, hate, hate curly brackets on their own line, unless at the end of a complete block ( and that's only because I don't know where else to put it). I have no idea why I'd want to use up 8 lines on this ode to whitespace:
if(match)
{
do_this();
}
else
{
do_that();
}
when I can do this:
if(match){
do_this();
} else {
do_that();
}
I have more trouble seeing the flow in the first example than the second, and it takes up more space in my terminal. I know, this is one of those personal style things, so I'm not going to try to convert anyone else to the One True K&R Way. But please don't tell me the first example is better. It's not.
4) Always use a label on loops when using next, last and redo.
This way, if you later add another embedded loop around your next, last or redo statement, your code will not break, it will still act on the outer loop, not the new inner loop. Also, it helps readability.
Bah. In the extremely unlikely event that I discover that a loop needs an inner loop I hadn't thought of (I've wrapped an existing loop inside a new one before, but I don't think I've ever needed to go the other way around), I'll notice these statements while I'm re-indenting. If my
loop is so long that a next unless $something; can hide from me, it probably needs to be redone anyway. And really, thanks to Perl's map, grep, and hash lookups, nested loops are rare enough (in my work, anyway) that I'm not going to add some extra typing to all my loops because it might end up coming in handy for the one-in-a-thousand of them that are nested.
CamelCase is preferable over uppercase, unless it is an acronym. Never use all lowercase. Never use underscore.
Preferable for whom? I don't like any of them, honestly, so I tend to keep my variables to single words and acronyms as much as possible. I prefer the clarity of the underscore look, but hate typing shifted characters when I don't have to. CamelCase is ugly and gives me Java flashbacks. Stringing lowercasewordstogether isn't very legible, but least offensive to me. Sometimes I wish I could use a hyphen in variable names, as in Emacs.
9) Never use $_ or the invisible equivalent.
Bah again. Yes, I know $_ can bite you in certain circumstances. But consider the following:
while(<DATA>){
chomp;
next unless /\w/;
s/foo/bar/g;
say;
}
while(my $line = <DATA>){
chomp $line;
next unless $line =~ /\w/;
$line =~ s/foo/bar/g;
say $line;
}
Please don't tell me that the second one is better. It's more cluttered, so harder to read, and the extra variable introduces five more opportunities for typos -- seven if you count the need to include the =~ operator explicitly now. Avoiding $_ at all times because you fear stumbling across one of those odd circumstances where it's a problem (without recognizing it) is like wearing a steel helmet whenever you go outside because you're afraid of meteorites. $_ is
one of Perl's best features. Use it without fear; just know how.
11) Always use if blocks, never postfix if statements as a one-liner.
There is an exception to this rule: when using flow of control commands.
So I shouldn't say:
calculate_time($date) if defined $date;
? I'd probably reword that to say something like, "Don't use
postfix modifiers after complex or multiple statements." I wouldn't do
the following, because I'm not sure how the precedence would work or
if they'd even compile:
do_this(), do_that if $match;
do_this($_) for @items if $match;
13) Use unless and until as little as possible.
I don't see why. One of the beauties of Perl (intentional, I think)
is the ability to write things similarly to the way you'd say them in
your native language. If the process I'm thinking in my head is, "Do this unless
the Found flag is set," then I don't see why this isn't the best way
to code that:
do_this() unless $found;
# surely you're not suggesting this is better, are you?
do_this if not $found;
All the other guidelines seem fine to me.
Aaron B.
Available for small or large Perl jobs; see my home node.
| [reply] [d/l] [select] |
|
| [reply] |
|
| [reply] |
|
Heh, I originally wrote "English," but then I changed it to be less Anglo-centric. :-) But now that you mention it, I suppose spoken languages with different word order might not translate as well into idiomatic Perl.
Aaron B.
Available for small or large Perl jobs; see my home node.
| [reply] |
Re: 20 most important Perl Best Practices
by runrig (Abbot) on Aug 22, 2012 at 20:54 UTC
|
13) Use unless and until as little as possible.
I wouldn't say that. I would say "Don't use unless with elsif/else blocks". That's just ridiculous.
And don't use it in combination with and/or logic because it requires yet another mental step of negation at the end.
| [reply] |
Re: 20 most important Perl Best Practices
by tinita (Parson) on Sep 05, 2012 at 08:16 UTC
|
since I was busy at YAPC::EU when this was written and afterwards an offtopic part of this thread got my attention first, I just wanted to add what I usually say when talking about Perl Best Practices:
The goal of PBP is not to be a list of rules. Then it could have been much shorter. Its goal is making you think about how you program and try to be consistent. The "rules" can vary from person to person or from company to company, although I agree that I often wish more people would use the suggested practices in the book, especially the ones I use ;-) | [reply] |
|
especially the ones I use ;-)
Oh absolutely!
With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
RIP Neil Armstrong
| [reply] |
Re: 20 most important Perl Best Practices
by pvaldes (Chaplain) on Aug 23, 2012 at 10:25 UTC
|
This is a false problem. Some of this advices are only cosmetic. People are different and always will be, you can't expect that the next guy that will read your code have the same brain structure or habits that you
I tend to think in terms of structures, so I personally hate the "stammer code" extending over seven pages
while (blah)
{... cri cri
if (/this/)
{... cri cri
do thiiiis
}.... cri cri
elseee ....
{.... cri cri
do thaaaat
}
}... violins
An excess of hesitation really makes me feel very nervous. As long as all options fit in a line, this is much better for me
While(blah){
if(/match/){ do_this() }
else { do_that() }
# no, I don't like the "} else" way, you lose the symmetry
}
(blank line here)
If you have a legacy code that you need to maintain, and you like, i.e, to see a carriage return between "if(blah)" and "{" don't suffer seing this disgusting (for you) structure all the time... make a copy of the code, lock the original in a safe place under seven keys and USE PERL regexes to "reorder the furniture of this room" in the copy as you like. What is the big fuss?
s/"I really hate this stupid way of writing code in a single line"/"That's \n much \n better now"/
If you add a sentence to a block and forget the ";" the program will emit a warning with the number of the exact offending line. Solution: read the warnings...
I you can use five characters to build your functional code structure don't use six (unless the omited character makes the code unreadable), but if you can use six characters to document your code don't use five. | [reply] [d/l] [select] |
Re: 20 most important Perl Best Practices
by tobyink (Canon) on Aug 24, 2012 at 15:56 UTC
|
"In Perl it is not possible to create a private function like in Java or C++."
It's not especially difficult...
sub my_function {
croak "my_function is private" unless caller(0) eq __PACKAGE__;
# body of function goes here
}
MooseX::Privacy makes creating private and protected methods really easy (if you're already using Moose).
perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'
| [reply] [d/l] |
|
| [reply] |
Re: 20 most important Perl Best Practices
by Ovid (Cardinal) on Aug 29, 2012 at 11:13 UTC
|
Have an upvote. I do feel this is more of a style guide than "best practices", but it's nice to see people thinking of these things.
Perl::Critic has been mentioned a couple of times. I have a reasonable introduction to it in Chapter 18 of my book (I'm not sure how long O'Reilly and Wrox will keep that online, but it's free for now). You'll learn enough to use Perl::Critic for catching code issues and how to configure it for your personal tastes.
| [reply] |
|
| [reply] |
Re: 20 most important Perl Best Practices
by Aristotle (Chancellor) on Aug 29, 2012 at 10:22 UTC
|
| [reply] |
Re: 20 most important Perl Best Practices
by erix (Prior) on Aug 30, 2012 at 18:03 UTC
|
| [reply] |
Re: 20 most important Perl Best Practices
by sundialsvc4 (Abbot) on Aug 22, 2012 at 22:08 UTC
|
Whether I completely agree with them or not ... is not the point. They are well-reasoned, and they are well-said, and they will surely produce a good crop of other well-reasoned well-said responses. For this alone, “thanks for sharing.”
Sometimes, the best-all-around “best practice” is simply to have one. To have a really-clear idea of what such a practice is, and the determination to stick to it consistently throughout a project. Indeed, IMHO, the word “consistently” just might be the very most important one of all ...
| |
Re: 20 most important Perl Best Practices
by Danny (Chaplain) on May 10, 2024 at 18:03 UTC
|
9) Never use $_ or the invisible equivalent.
Sacrilege!
| [reply] |
Re: 20 most important Perl Best Practices
by BrowserUk (Patriarch) on Aug 22, 2012 at 18:32 UTC
|
| [reply] |
|
| [reply] |
|
Your list is nothing more than yet-another-arbitrary-and-capricious-ruleset that uses thin justifictions to imbibe your personal preferences with theocratic status. Yet another list that doesn't correspond with anyone elses arbitrary list. Another set of arbitrary rules that will confuse newbies and frustrate the experienced coming from other places where different arbitrary lists were in force.
There is only one definitive list -- it's called Perl.
You are second guessing the heralded and qualified language designer to come up with some subset of the defined language on the basis of what qualification?
Even where you agree with the language designer in one place -- lower-case and underscores -- you later contradict him -- and yourself -- with "only CamelCase". This is both capricious, and more damning, inconsistent.
Your rules appear to be aimed to favour restricting and emphasising the linguistic elements of the language, rather than the structure of the algorithm, which is the completely wrong thing to be doing. The language's syntax is already very constrained and well documented. Whether those completely new to programming, or those migrating in from other languages, learning Perl syntax is just a matter of exposure.
What all programmers should be doing when writing their code, is trying to capture the essence of the variable part of their programs -- the algorithms -- in as clear and concise manner as possible. And perl's full syntactic richness is expressly designed to allow that to be done.
By placing arbitrary restrictions on that syntactic richness, you do not make it easier to read the code, because the inevitable affect is to force the programmer to use more verbose code to capture the essence of the important part of the source code -- the algorithms.
With many of your proposed restrictions, you are effectively converting a 4GL to a 3GL with all the loss in productivity that implies.
See also Re: What is code readability? and follow-on discussion for specific counter example to some of your justifictions.
With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
| [reply] |
|
|
|
|
|
|
|
| A reply falls below the community's threshold of quality. You may see it by logging in. |
|
|