Changes between Version 1 and Version 2 of Development/Code/CodingStyle


Ignore:
Timestamp:
Mar 21, 2010, 11:27:45 AM (16 years ago)
Author:
loomis
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • Development/Code/CodingStyle

    v1 v2  
    1010
    1111There are lots of documents motivating this, feel free to review
    12 them. [[http://www.kroah.com/linux/talks/ols_2002_kernel_codingstyle_paper/codingstyle.ps In short]]:
     12them. [http://www.kroah.com/linux/talks/ols_2002_kernel_codingstyle_paper/codingstyle.ps In short]:
    1313
    1414* I want to read your code.
     
    1919=== Further reading ===
    2020
    21 * [[http://perldoc.perl.org/perlstyle.html Perl coding style guide]]
    22 * [[http://www.kroah.com/linux/talks/ols_2002_kernel_codingstyle_paper/codingstyle.ps Documentation/CodingStyle and beyond]], by Greg Kroah-Hartman
     21* [http://perldoc.perl.org/perlstyle.html Perl coding style guide]
     22* [http://www.kroah.com/linux/talks/ols_2002_kernel_codingstyle_paper/codingstyle.ps Documentation/CodingStyle and beyond], by Greg Kroah-Hartman
    2323
    2424== The basics ==
     
    4040=== Use meaningful names for globals, short names for locals ===
    4141
    42 <tt>i</tt> is a perfectly valid identifier for a loop variable. However, you
     42`i` is a perfectly valid identifier for a loop variable. However, you
    4343deserve nasty punishment if you use it as a function name.
    4444
    45 On the opposite, <tt>this_is_a_temporary_counter</tt> is plain bad for
     45On the opposite, `this_is_a_temporary_counter` is plain bad for
    4646a loop variable.
    4747
    4848So, some good examples:
    49 
     49{{{
    5050 sub write_user_credentials
    5151 {
    5252     # ...
    5353 }
    54  
     54}}}
     55
     56{{{
    5557 for my $i (0..10) {
    5658     # ...
    5759 }
    58  
     60 }}}
    5961
    6062And very bad examples:
    6163
     64{{{
    6265 sub wuc
    6366 {
    6467     # WTH???
    6568 }
    66  
     69}}}
     70
     71{{{
    6772 for my $counter_from_0_to_10_included (0..10) {
    6873     # Excuse me???
    6974 }
    70  
     75 }}}
    7176
    7277=== Be modular ===
     
    7984
    8085Here are the classic metrics for modularity:
    81 
    82 * No lines longer than 80 columns.
    83 ** Split or rearrange longer strings
    84 ** Split longer statements
    85 * If you have more than 3 levels of indentation, split your block
    86 * If your function goes beyond the screen, split it
    87 ** And don't try to reduce the font. ;)
    88 * If you have more than 7 local variables, split your function.
    89 ** Sometimes it's OK to have 10, but if you have 15 your code is a problem.
     86 * No lines longer than 80 columns.
     87   * Split or rearrange longer strings
     88   * Split longer statements
     89 * If you have more than 3 levels of indentation, split your block
     90 * If your function goes beyond the screen, split it
     91   * And don't try to reduce the font. ;)
     92 * If you have more than 7 local variables, split your function.
     93   * Sometimes it's OK to have 10, but if you have 15 your code is a problem.
    9094
    9195=== Don't use magic numbers  ===
    9296
    93 The <tt>constant</tt> pragma will give you meaningful names for any
     97The `constant` pragma will give you meaningful names for any
    9498values other than 0 and 1 you need. They'll help you to understand why
    9599you chose such values on the past.
    96100
    97101Good example:
    98 
     102{{{
    99103 use constant PI => 3.141592;
    100  
     104}}}
     105{{{
    101106 my $circle_area = $radio * PI * PI;
    102 
     107}}}
    103108And the bad example
    104 
     109{{{
    105110 # Oops! I missed a decimal somewhere!
    106111 my $circle_area = $radio * 3.14159 * 3.141592;
     112}}}
    107113
    108114=== Comments ===
     
    123129
    124130Bad examples:
    125 
     131{{{
    126132 ############################################################
    127133 #
     
    130136 ############################################################
    131137 $i++;
    132  
     138}}}
     139
     140{{{
    133141 sub do_something
    134142 {
     
    143151    ...
    144152 }
     153}}}
    145154
    146155These are best done like this:
    147 
     156{{{
    148157 $i++;
    149  
     158}}}
     159
     160{{{
    150161 # Performs task foo...
    151162 sub foo {...}
     
    154165 # Performs task baz, which is quite similar to bar
    155166 sub baz {...}
    156  
     167
    157168 # Performs a set of tasks, returning blah blah with arguments
    158169 # $arg1:
     
    165176     baz (@args);
    166177 }
    167 
     178}}}
    168179
    169180Finally, don't put any credits on your comments, excepting on file
    170181headers.
    171182
    172 === Don't use <tt>vars</tt> ===
     183=== Don't use `vars` ===
    173184
    174185This pragma has been deprecated since Perl 5.6, and that's a long time
    175 ago. Instead, use the <tt>our</tt> declaration for package-wide
     186ago. Instead, use the `our` declaration for package-wide
    176187variables:
    177188
    178189Good:
    179 
     190{{{
    180191 our @ISA = ...;
     192}}}
    181193
    182194Bad:
    183 
     195{{{
    184196 use vars qw (@ISA);
    185197 @ISA = ...;
     198}}}
    186199
    187200=== Curly bracket position ===
     
    190203line as the sentence they belong to and close them on a line for their
    191204own, excepting when it's an else or a do-while block:
    192 
     205{{{
    193206 if ($foo) {
    194207     ...
    195208 }
    196  
     209}}}
     210
     211{{{
    197212 while ($bar) {
    198213     ...
    199214 }
    200  
     215}}}
     216
     217{{{
    201218 if ($foo) {
    202219     ...
     
    204221     ...
    205222 }
    206  
     223}}}
     224
     225{{{
    207226 do {
    208227     ...
    209228 } while ($bar);   
     229}}}
    210230
    211231This way it is perfectly clear where each block starts, finishes and
     
    215235function. They should be on a different line, and have nothing else on
    216236the same line:
    217 
     237{{{
    218238 sub foo
    219239 {
    220240     my @args = @_;
    221241 }
     242}}}
    222243
    223244The reason for this is that decent editors (f.i, Emacs) are aware that
     
    229250
    230251Use them a lot. When in doubt, use them. Especially:
    231 
    232252* Always use parenthesis on function calls
    233253* Always use them on function calls even when there are no arguments
    234 
    235254The reason is that:
    236 
     255{{{
    237256 foo();
    238 
     257}}}
    239258Is easier to understand than:
    240 
     259{{{
    241260 foo;
     261}}}
    242262
    243263=== Prefer methods over plain functions ===
    244264
    245265Especially when writing components, you want to log unexpected
    246 things. It's free to have a <tt>$self</tt> object, and let it log.
     266things. It's free to have a `$self` object, and let it log.
    247267
    248268Only use plain functions if you want them exported to some other
     
    253273=== Running commands ===
    254274
    255 Do not use backticks or <tt>system</tt>, nor use <tt>open</tt> for pipes. The
    256 <tt>CAF::Process</tt> module has all you need, and it won't spawn new
     275Do not use backticks or `system`, nor use `open` for pipes. The
     276`CAF::Process` module has all you need, and it won't spawn new
    257277subshells, which is much safer.
    258278
    259 Another advantage of the <tt>CAF::Process</tt> module is that your
     279Another advantage of the `CAF::Process` module is that your
    260280command line will be automatically logged at verbose level, which
    261281saves you snippets like this:
    262 
     282{{{
    263283 $self->debug (5, "Going to run ls -l");
    264284 system ("ls", "-l");
     285}}}
    265286
    266287This will become inconsistent with different uses. Instead, do:
    267 
     288{{{
    268289 # Or any reporter object.
    269290 my $proc = CAF::Proces->new (["ls", "-l"], log => $self);
     
    271292 # One-line version:
    272293 CAF::Process->new (["ls", "-l"], log => $self)->run();
     294}}
    273295
    274296The log option is any CAF::Logger object, for instance the component
     
    280302an encrypted password to usermod. In this cases, you don't want your
    281303command logged. Just don't pass any log argument to CAF::Process::new:
    282 
     304{{{
    283305 my $proc = CAF::Process->new (["ls", "-l"]);
    284306 $proc->run();
     307}}}
    285308
    286309==== Examples ====
     
    292315
    293316Create the contents to be piped:
    294 
     317{{{
    295318 my $contents = "Hello, world";
    296 
     319}}}
    297320Create the command, specifying $contents as the input, and "execute" it:
    298 
     321{{{
    299322my $proc = CAF::Process->new (["cat", "-"], stdin => $contents);
    300323$proc->execute();
     324}}}
    301325
    302326===== Piping in and out =====
     
    304328Suppose we want a bi-directional pipe: we provide the command's stdin,
    305329and need to get its output and error:
    306 
     330{{{
    307331 my ($stdin, $stdout, $stderr) = ("Hello, world", undef, undef);
    308332 my $proc = CAF::Process->new (["cat", "-"], stdin => $stdin,
     
    310334                                stderr => \$stderr);
    311335 $proc->execute();
     336}}}
    312337
    313338And we'll have the command's standard output and error on $stdout and
     
    317342
    318343Create the command:
    319 
     344{{{
    320345 my $proc = CAF::Process->new (["ls", "-lh"]);
    321 
     346}}}
    322347And get the output:
    323 
     348{{{
    324349 my $output = $proc->output();
     350}}}
    325351
    326352=== File handling ===
     
    329355that you should be aware of. For instance, the following code is an
    330356example of what shouldn't be done:
    331 
     357{{{
    332358 open (FH, ">/tmp/foo");
    333 
    334 If /tmp/foo already exists and is a symbolic link to /etc/shadow, you
     359}}}
     360
     361If `/tmp/foo` already exists and is a symbolic link to `/etc/shadow`, you
    335362just lost all accounts on your system.
    336363
     
    339366Don't open files directly. Use the CAF::FileWriter module to do the
    340367work for you:
    341 
     368{{{
    342369 my $fh = CAF::FileWriter->open ("/my/file", log => $self);
    343370 print $fh "Hello, world!\n";
    344371 $fh->close();
     372}}}
    345373
    346374This module will perform all security checks for you, and will log
     
    349377
    350378You can specify the permissions you want at instantiation, too:
    351 
     379{{{
    352380 my $fh = CAF::FileWriter->open ("/my/path", mode => 0400, log => $self );
    353381 print $fh "Hello, world!\n";
    354382 $fh->close();
     383}}}
    355384
    356385If you find any errors and have to discard your contents, just call
    357386the cancel method, and the existing file will be preserved:
    358 
     387{{{
    359388 my $fh = CAF::FileWriter->open ("/my/path", mode => 0400, log => $self);
    360389 print $fh "Hello, world!\n";
     
    363392 }
    364393 $fh->close();
     394}}}
    365395
    366396Finally, if the contents you generate are the same as on the original
     
    391421Sometimes you just want to add a couple of lines to an existing file,
    392422without destroying its current contents. Or to remove them. The module
    393 <tt>CAF::FileEditor</tt> is just for that. It is a subclass of
    394 <tt>CAF::FileWriter</tt>, and when you call the <tt>string_ref</tt>
     423`CAF::FileEditor` is just for that. It is a subclass of
     424`CAF::FileWriter`, and when you call the `string_ref`
    395425method you'll get a reference to the file's contents so that you can
    396426freely update them.
     
    398428For instance, you only want to change the first "a" for a b on the
    399429first line of a file:
    400 
     430{{{
    401431 my $fh = CAF::FileEditor->open ("/foo/bar",
    402432                                 log => $self);
     
    404434 $$ref_to_contents =~ s{a}{b};
    405435 $fh->close();
     436}}}
    406437
    407438If you want to add text at the beginning of the file, the
    408 <tt>head_print</tt> method is what you are looking for.
     439`head_print` method is what you are looking for.
    409440
    410441==== Other tasks with files ====
    411442
    412 When in doubt, use <tt>LC::</tt> modules and functions, over standard ones. For instance, use <tt>LC::File::copy</tt>, <tt>LC::File::move</tt> instead of <tt>File::Copy</tt> and friends.
    413 
    414 <tt>LC::</tt> functions perform more security checks and are less prone to symlink attacks.
     443When in doubt, use `LC::` modules and functions, over standard ones. For instance, use `LC::File::copy`, `LC::File::move` instead of `File::Copy` and friends.
     444
     445`LC::` functions perform more security checks and are less prone to symlink attacks.
    415446
    416447== Input handling ==
     
    424455Also, when you print files that will be sourced by shell scripts, be
    425456sure to print all values between single quotes. This is true for
    426 almost every file you have under /etc/sysconfig.
     457almost every file you have under `/etc/sysconfig`.
    427458
    428459== Quality of messages ==
     
    430461=== Don't annoy the user ===
    431462
    432 The main principle is not to annoy the user. Use <tt>info</tt> and
    433 <tt>ok</tt> methods only for '''very''' important messages. A small
     463The main principle is not to annoy the user. Use `info` and
     464`ok` methods only for '''very''' important messages. A small
    434465description of the tasks you are going to perform, if they are complex
    435466enough.
     
    438469
    439470Provide a detailed trace of any task you perform with
    440 <tt>verbose</tt> messages. Trace DNS queries, URLs being retrieved,
     471`verbose` messages. Trace DNS queries, URLs being retrieved,
    441472services you have to enable or disable...
    442473
     
    446477=== Debugging output ===
    447478
    448 Don't print user-relevant messages with <tt>debug</tt>. This should be
     479Don't print user-relevant messages with `debug`. This should be
    449480used only for developer-relevant stuff, such as tracking temporary
    450481contents or so.
     
    452483We don't have any convention for debug levels, is it needed?
    453484
    454 === Use <tt>error</tt> only for fatal errors ===
    455 
    456 Use the <tt>error</tt> method only if this error will make the entire
     485=== Use `error` only for fatal errors ===
     486
     487Use the `error` method only if this error will make the entire
    457488component fail. If you can handle it, or the fail is not really
    458 important for the component's results, use <tt>info</tt> instead. If
     489important for the component's results, use `info` instead. If
    459490failing to download a file is OK because you can work around it, or
    460491you know you may have no rights to write on AFS, but that's OK, use an
    461 <tt>info</tt> message.
     492`info` message.
    462493
    463494Otherwise, the component will be re-run with no need, and will keep
     
    473504task we repeat over and over (f.i, do we need any especial code to do
    474505DNS queries or download files from the Internet?).
    475 
    476 [[User:Luisfmunoz|Luisfmunoz]] 00:19, 12 January 2009 (UTC)