Difference between revisions of "Programming Guidelines"

From Dreamwidth Notes
Jump to: navigation, search
(comments)
(prettify and organize!)
Line 7: Line 7:
 
'''These are guidelines, and not to be afraid of!'''  Please don't feel intimidated by the style of the code.  People will help you out if you have questions or aren't sure how to write something.
 
'''These are guidelines, and not to be afraid of!'''  Please don't feel intimidated by the style of the code.  People will help you out if you have questions or aren't sure how to write something.
  
* Spaces.  Yes, we use spaces.  There are four per level of indentation.  But use your judgement when you're lining things up.
+
== Whitespace ==
  
* Use postfix conditionals.  That means:
+
=== Spaces for indentation ===
  
    # This is incorrect:
+
Yes, we use spaces: four per level of indentation.  But use your judgment when lining things up.
    if ( $something ) {
+
        do_something();
+
    }
+
   
+
    # Try this instead:
+
    do_something() if $something;
+
   
+
    # Or even:
+
    do_something()
+
        if $something;
+
  
It is your discretion which of the forms you use.  Pick whatever seems appropriate to the code.  (I tend to prefer the latter personally unless the line is really short.)
+
=== Spaces around parenthesis and operators ===
  
* Proper usage of hashes is importantDo not quote literals unless needed.  That may not make sense, so here are some examples:
+
Perl has a well-deserved reputation for being line noiseLet's try to avoid that by putting spaces around parenthesis and operators:
  
    # This is bad
+
<source lang="perl"># This is right out:
    $HASH{'DATA'} = 5;
+
if ((($a||$b)&&(($c>1)||$d&5))+1)>3) { ... }
    $hashref->{'Something'} = $foo;
+
   
+
    # try these instead
+
    $HASH{DATA} = 5;
+
    $hashref->{Something} = $foo;
+
  
The only time that you need quotes is if the value you are quoting has non-word characters in it.  I.e., dashes, quotes, etc.
+
# This is much better:
 
+
if ( ( ( $a || $b ) && ( ( $c > 1 ) || ( $d & 5 ) ) + 1 ) > 3 ) { ... }</source>
* Spaces around parenthesis and operators.  Perl has a well-deserved reputation for being line noise.  Let's try to avoid that.
+
 
+
    # This is right out:
+
    if ((($a||$b)&&(($c>1)||$d&5))+1)>3) { ... }
+
   
+
    # This is much better:
+
    if ( ( ( $a || $b ) && ( ( $c > 1 ) || ( $d & 5 ) ) + 1 ) > 3 ) { ... }
+
  
 
Well.  It's better, but this line is terrible anyway.  If you end up with a line like this, I'd suggest rewriting it entirely.  Don't be too afraid of going onto multiple lines if it makes the operation more readable.
 
Well.  It's better, but this line is terrible anyway.  If you end up with a line like this, I'd suggest rewriting it entirely.  Don't be too afraid of going onto multiple lines if it makes the operation more readable.
  
The "space around parenthesis" rule also applies to method calls.  Here are some examples of when this comes into play:
+
The "spaces around parenthesis" rule also applies to method calls.  Here are some examples of when this comes into play:
  
    call_method( $arg, $arg2 );
+
<source lang="perl">call_method( $arg, $arg2 );
   
+
 
    do_something( 45 ) if $org || $neg;
+
do_something( 45 ) if $org || $neg;</source>
  
 
However, do NOT use spaces around operators used to index into arrays or hashes.  It gets confusing.
 
However, do NOT use spaces around operators used to index into arrays or hashes.  It gets confusing.
  
    # Wrong:
+
<source lang="perl"># Wrong:
    if ( $array[ 13 ] > $hash->{ $index } ) { ... }
+
if ( $array[ 13 ] > $hash->{ $index } ) { ... }
   
+
    # Right:
+
    if ( $array[13] > $hash->{$index} ) { ... }
+
  
* Don't use extraneous parenthesis. This happens mostly on method calls that don't need it and postfix conditionals.
+
# Right:
 +
if ( $array[13] > $hash->{$index} ) { ... }</source>
  
    # These are wrong:
+
=== No tabs or trailing whitespace ===
    my $r = DW::Request->get();
+
 
    do_something() if ( $r->method() eq 'POST' );
+
No tabs, ever.  No trailing whitespace.
   
+
 
    # Fixed:
+
These things happen.  I'll try to catch them before commit.  But don't commit tabs or trailing whitespace.  Convert all tabs to spaces and prune trailing whitespace.
    my $r = DW::Request->get;
+
 
    do_something() if $r->method eq 'POST';
+
=== Linebreak readably ===
 +
 
 +
It is NOT imperative to fit everything on one line, and in fact it's suggested that you try to keep line lengths down under 120 or so if you can.  Just keep it readable.
 +
 
 +
== Don't use extraneous parenthesis ==
 +
 
 +
Don't use extraneous parenthesis.  This happens mostly on method calls that don't need it and postfix conditionals.
 +
 
 +
<source lang="perl"># These are wrong:
 +
my $r = DW::Request->get();
 +
do_something() if ( $r->method() eq 'POST' );
 +
 
 +
# Fixed:
 +
my $r = DW::Request->get;
 +
do_something() if $r->method eq 'POST';</source>
  
 
Note that you need parenthesis after bareword function calls such as the do_something() above.  Otherwise Perl has no idea it's a method and not a constant or some other value.  But when you call it on a reference (using the -> operator) then it's assumed to be a method.
 
Note that you need parenthesis after bareword function calls such as the do_something() above.  Otherwise Perl has no idea it's a method and not a constant or some other value.  But when you call it on a reference (using the -> operator) then it's assumed to be a method.
  
* No tabs, ever.  No trailing whitespace.
+
== Logic ==
  
These things happen.  I'll try to catch them before commit.  But don't commit tabs or trailing whitespace.  Convert all tabs to spaces and prune trailing whitespace.
+
=== Postfix conditionals ===
  
* Use human logicThis is a big one that will really help people reading the code.  The human brain is good at some things, bad at others.
+
Use postfix conditionalsThat means:
  
     # if something is true is easy to understand:
+
<source lang="perl"># This is incorrect:
    if ( $whatever ) { ... }
+
if ( $something ) {
 +
     do_something();
 +
}
 +
 
 +
# Try this instead:
 +
do_something() if $something;
 +
 
 +
# Or even:
 +
do_something()
 +
    if $something;</source>
 +
 
 +
It is your discretion which of the forms you use.  Pick whatever seems appropriate to the code.  (I tend to prefer the latter personally unless the line is really short.)
 +
 
 +
=== Use human logic ===
 +
 
 +
This is a big one that will really help people reading the code.  The human brain is good at some things, bad at others.
 +
 
 +
<source lang="perl"># if something is true is easy to understand:
 +
if ( $whatever ) { ... }
 
      
 
      
    # unless something is true is also easy to understand:
+
# unless something is true is also easy to understand:
    unless ( $whatever ) { ... }
+
unless ( $whatever ) { ... }</source>
  
 
However, some things are NOT easy to understand, and should be rewritten.
 
However, some things are NOT easy to understand, and should be rewritten.
  
    # don't use this unless you REALLY need to
+
<source lang="perl"># don't use this unless you REALLY need to
    if ( ! $something ) { ... }
+
if ( ! $something ) { ... }
   
+
 
    # use this instead:
+
# use this instead:
    unless ( $something ) { ... }
+
unless ( $something ) { ... }</source>
  
 
In some cases, the variable in question lends itself to the negation syntax in the first example.  But that's a rare case.  Just think about it for a second and go with what flows.
 
In some cases, the variable in question lends itself to the negation syntax in the first example.  But that's a rare case.  Just think about it for a second and go with what flows.
  
    # never use this
+
<source lang="perl"># never use this
    unless ( ! $foobar ) { ... }
+
unless ( ! $foobar ) { ... }</source>
  
 
There is no situation in which "unless not $something" makes sense.  The brain just doesn't parse it.  It's a double negative, you might as well just use "if $something" and call it good!
 
There is no situation in which "unless not $something" makes sense.  The brain just doesn't parse it.  It's a double negative, you might as well just use "if $something" and call it good!
  
* Linebreak readably.  It is NOT imperative to fit everything on one line, and in fact it's suggested that you try to keep line lengths down under 120 or so if you can.  Just keep it readable.
+
== Data structures ==
  
* Effective English stripping is a requirement!
+
=== Proper use of hashes ===
  
While we might not translate DW.org into other languages, other people who are using the DW code should be given the functionality to do so on their own sites.  This means that you need to be conscious of how to effectively strip a page or file of the text in it.
+
Proper use of hashes is important.  Do not quote literals unless needed. That may not make sense, so here are some examples:
  
'''TODO: Create a page for how to localize a page.'''
+
<source lang="perl"># This is bad
 +
$HASH{'DATA'} = 5;
 +
$hashref->{'Something'} = $foo;
  
* Header on source files, please use this on all original files created for Dreamwidth.  Existing/originaly LJ code should get a header eventually, when we figure out an appropriate one.
+
# try these instead
 +
$HASH{DATA} = 5;
 +
$hashref->{Something} = $foo;</source>
  
#!/usr/bin/perl
+
The only time that you need quotes is if the value you are quoting has non-word characters in itI.e., dashes, quotes, etc.
#
+
# DW::User::Edges
+
#
+
# This module defines relationships between accounts.  It allows for finding
+
# edges, defining edges, removing edges, and other tasks related to the edges
+
# that can exist between accounts.  Methods are added to the LJ::User/DW::User
+
# classes as appropriate.
+
  #
+
# Authors:
+
#      Mark Smith <mark@dreamwidth.org>
+
#
+
# Copyright (c) 2009 by Dreamwidth Studios, LLC.
+
#
+
# This program is free software; you may redistribute it and/or modify it under
+
# the same terms as Perl itself.  For a copy of the license, please reference
+
# 'perldoc perlartistic' or 'perldoc perlgpl'.
+
#
+
  
Copyright is maintained by the Dreamwidth Studios, LLC. organization, as all committers/contributors should have signed a contributor's agreement to properly pass over copyright.  But authors should be noted for credit purposes.
+
=== Preferred variable usage of $LJ::HOME ===
  
 
LJ::HOME/cgi-bin is preferred over $ENV{LJHOME}/cgi-bin -- use LJ::HOME instead, and if you see the old form, feel free to change it.
 
LJ::HOME/cgi-bin is preferred over $ENV{LJHOME}/cgi-bin -- use LJ::HOME instead, and if you see the old form, feel free to change it.
  
Rule of thumb: if you are writing a new file, you can add yourself to the authors.  If you are editing an existing file, you should only add yourself to the authors list if you are making significant changes (>10% or 100 lines, whichever is less).  (Fixing typos does not qualify one to be a called out author of a file, sorry!)
+
== Commenting ==
  
* Comments: Please comment your new code as extensively as possible so that someone coming along behind you can follow what you're doing. If you're working with old code, and you find yourself having to puzzle through what various functions are doing, comment it up to indicate what you figure out. We want everything to be as understandable as possible for anyone who comes along after you. You don't need to comment every line, but anything of moderate complexity should have a line or two indicating what it does and why.
+
Please comment your new code as extensively as possible so that someone coming along behind you can follow what you're doing. If you're working with old code, and you find yourself having to puzzle through what various functions are doing, comment it up to indicate what you figure out. We want everything to be as understandable as possible for anyone who comes along after you. You don't need to comment every line, but anything of moderate complexity should have a line or two indicating what it does and why.
  
 
Code comments should be kept professional -- no profanity, no offensive or exclusionary language (in particular, the LJ code has a tendency to use the word "ghetto" to indicate that something isn't as good as it should be, and we should absolutely avoid that and change it whenever we encounter it), no self-deprecating humor ("this is totally stupid of me but ..."), etc.
 
Code comments should be kept professional -- no profanity, no offensive or exclusionary language (in particular, the LJ code has a tendency to use the word "ghetto" to indicate that something isn't as good as it should be, and we should absolutely avoid that and change it whenever we encounter it), no self-deprecating humor ("this is totally stupid of me but ..."), etc.
Line 141: Line 136:
 
If you need to indicate that something will need attention again later, we've standardized on "FIXME" as our "fix me or add to me later" indicator. Always indicate why you're flagging something FIXME:
 
If you need to indicate that something will need attention again later, we've standardized on "FIXME" as our "fix me or add to me later" indicator. Always indicate why you're flagging something FIXME:
  
    # FIXME: Works as-is, but needs foo, bar, and baz later.
+
<source lang="perl"># FIXME: Works as-is, but needs foo, bar, and baz later.</source>
  
    # FIXME: Totally broken. Needs foo, bar, and baz to work again.
+
<source lang="perl"># FIXME: Totally broken. Needs foo, bar, and baz to work again.</source>
  
 +
== English stripping ==
 +
 +
Effective English stripping is a requirement!  While we might not translate DW.org into other languages, other people who are using the DW code should be given the functionality to do so on their own sites.  This means that you need to be conscious of how to effectively strip a page or file of the text in it.
 +
 +
'''TODO: Create a page for how to localize a page.'''
 +
 +
== Source file headers and credit ==
 +
 +
Header on source files, please use this on all original files created for Dreamwidth.  Existing/originaly LJ code should get a header eventually, when we figure out an appropriate one.
 +
 +
<source lang="perl">#!/usr/bin/perl
 +
#
 +
# DW::User::Edges
 +
#
 +
# This module defines relationships between accounts.  It allows for finding
 +
# edges, defining edges, removing edges, and other tasks related to the edges
 +
# that can exist between accounts.  Methods are added to the LJ::User/DW::User
 +
# classes as appropriate.
 +
#
 +
# Authors:
 +
#      Mark Smith <mark@dreamwidth.org>
 +
#
 +
# Copyright (c) 2009 by Dreamwidth Studios, LLC.
 +
#
 +
# This program is free software; you may redistribute it and/or modify it under
 +
# the same terms as Perl itself.  For a copy of the license, please reference
 +
# 'perldoc perlartistic' or 'perldoc perlgpl'.
 +
#</source>
 +
 +
Copyright is maintained by the Dreamwidth Studios, LLC. organization, as all committers/contributors should have signed a contributor's agreement to properly pass over copyright.  But authors should be noted for credit purposes.
 +
 +
Rule of thumb: if you are writing a new file, you can add yourself to the authors.  If you are editing an existing file, you should only add yourself to the authors list if you are making significant changes (>10% or 100 lines, whichever is less).  (Fixing typos does not qualify one to be a called out author of a file, sorry!)
  
 
[[Category: Development]]
 
[[Category: Development]]

Revision as of 05:37, 25 February 2009

Initial starting point: LJ Programming Guidelines.

Now, let's talk a bit about how Dreamwidth code should be written. Note that this is the stylistic guideline to follow to make sure the code looks uniform. If you submit a patch that doesn't follow these guidelines, then it will likely get declined with a note to review this documentation. Realistically, we want everybody to be able to dive into the code and understand what is going on without having to try to interpret a dozen different coding styles.

Note that these are not hard and fast rules. A lot of the time you will be fixing up code somewhere that is broken, and you will want to follow the style of the code you are working in. If you're editing really old pages like talkread.bml then you should attempt to code legibly, but follow the style in use on the page. (Mixing styles within a file can be problematic.)

These are guidelines, and not to be afraid of! Please don't feel intimidated by the style of the code. People will help you out if you have questions or aren't sure how to write something.

Whitespace

Spaces for indentation

Yes, we use spaces: four per level of indentation. But use your judgment when lining things up.

Spaces around parenthesis and operators

Perl has a well-deserved reputation for being line noise. Let's try to avoid that by putting spaces around parenthesis and operators:

# This is right out:
if ((($a||$b)&&(($c>1)||$d&5))+1)>3) { ... }
 
# This is much better:
if ( ( ( $a || $b ) && ( ( $c > 1 ) || ( $d & 5 ) ) + 1 ) > 3 ) { ... }

Well. It's better, but this line is terrible anyway. If you end up with a line like this, I'd suggest rewriting it entirely. Don't be too afraid of going onto multiple lines if it makes the operation more readable.

The "spaces around parenthesis" rule also applies to method calls. Here are some examples of when this comes into play:

call_method( $arg, $arg2 );
 
do_something( 45 ) if $org || $neg;

However, do NOT use spaces around operators used to index into arrays or hashes. It gets confusing.

# Wrong:
if ( $array[ 13 ] > $hash->{ $index } ) { ... }
 
# Right:
if ( $array[13] > $hash->{$index} ) { ... }

No tabs or trailing whitespace

No tabs, ever. No trailing whitespace.

These things happen. I'll try to catch them before commit. But don't commit tabs or trailing whitespace. Convert all tabs to spaces and prune trailing whitespace.

Linebreak readably

It is NOT imperative to fit everything on one line, and in fact it's suggested that you try to keep line lengths down under 120 or so if you can. Just keep it readable.

Don't use extraneous parenthesis

Don't use extraneous parenthesis. This happens mostly on method calls that don't need it and postfix conditionals.

# These are wrong:
my $r = DW::Request->get();
do_something() if ( $r->method() eq 'POST' );
 
# Fixed:
my $r = DW::Request->get;
do_something() if $r->method eq 'POST';

Note that you need parenthesis after bareword function calls such as the do_something() above. Otherwise Perl has no idea it's a method and not a constant or some other value. But when you call it on a reference (using the -> operator) then it's assumed to be a method.

Logic

Postfix conditionals

Use postfix conditionals. That means:

# This is incorrect:
if ( $something ) {
    do_something();
}
 
# Try this instead:
do_something() if $something;
 
# Or even:
do_something()
    if $something;

It is your discretion which of the forms you use. Pick whatever seems appropriate to the code. (I tend to prefer the latter personally unless the line is really short.)

Use human logic

This is a big one that will really help people reading the code. The human brain is good at some things, bad at others.

# if something is true is easy to understand:
if ( $whatever ) { ... }
 
# unless something is true is also easy to understand:
unless ( $whatever ) { ... }

However, some things are NOT easy to understand, and should be rewritten.

# don't use this unless you REALLY need to
if ( ! $something ) { ... }
 
# use this instead:
unless ( $something ) { ... }

In some cases, the variable in question lends itself to the negation syntax in the first example. But that's a rare case. Just think about it for a second and go with what flows.

# never use this
unless ( ! $foobar ) { ... }

There is no situation in which "unless not $something" makes sense. The brain just doesn't parse it. It's a double negative, you might as well just use "if $something" and call it good!

Data structures

Proper use of hashes

Proper use of hashes is important. Do not quote literals unless needed. That may not make sense, so here are some examples:

# This is bad
$HASH{'DATA'} = 5;
$hashref->{'Something'} = $foo;
 
# try these instead
$HASH{DATA} = 5;
$hashref->{Something} = $foo;

The only time that you need quotes is if the value you are quoting has non-word characters in it. I.e., dashes, quotes, etc.

Preferred variable usage of $LJ::HOME

LJ::HOME/cgi-bin is preferred over $ENV{LJHOME}/cgi-bin -- use LJ::HOME instead, and if you see the old form, feel free to change it.

Commenting

Please comment your new code as extensively as possible so that someone coming along behind you can follow what you're doing. If you're working with old code, and you find yourself having to puzzle through what various functions are doing, comment it up to indicate what you figure out. We want everything to be as understandable as possible for anyone who comes along after you. You don't need to comment every line, but anything of moderate complexity should have a line or two indicating what it does and why.

Code comments should be kept professional -- no profanity, no offensive or exclusionary language (in particular, the LJ code has a tendency to use the word "ghetto" to indicate that something isn't as good as it should be, and we should absolutely avoid that and change it whenever we encounter it), no self-deprecating humor ("this is totally stupid of me but ..."), etc.

If you need to indicate that something will need attention again later, we've standardized on "FIXME" as our "fix me or add to me later" indicator. Always indicate why you're flagging something FIXME:

# FIXME: Works as-is, but needs foo, bar, and baz later.
# FIXME: Totally broken. Needs foo, bar, and baz to work again.

English stripping

Effective English stripping is a requirement! While we might not translate DW.org into other languages, other people who are using the DW code should be given the functionality to do so on their own sites. This means that you need to be conscious of how to effectively strip a page or file of the text in it.

TODO: Create a page for how to localize a page.

Source file headers and credit

Header on source files, please use this on all original files created for Dreamwidth. Existing/originaly LJ code should get a header eventually, when we figure out an appropriate one.

#!/usr/bin/perl
#
# DW::User::Edges
#
# This module defines relationships between accounts.  It allows for finding
# edges, defining edges, removing edges, and other tasks related to the edges
# that can exist between accounts.  Methods are added to the LJ::User/DW::User
# classes as appropriate.
#
# Authors:
#      Mark Smith <mark@dreamwidth.org>
#
# Copyright (c) 2009 by Dreamwidth Studios, LLC.
#
# This program is free software; you may redistribute it and/or modify it under
# the same terms as Perl itself.  For a copy of the license, please reference
# 'perldoc perlartistic' or 'perldoc perlgpl'.
#

Copyright is maintained by the Dreamwidth Studios, LLC. organization, as all committers/contributors should have signed a contributor's agreement to properly pass over copyright. But authors should be noted for credit purposes.

Rule of thumb: if you are writing a new file, you can add yourself to the authors. If you are editing an existing file, you should only add yourself to the authors list if you are making significant changes (>10% or 100 lines, whichever is less). (Fixing typos does not qualify one to be a called out author of a file, sorry!)