Changes between Version 1 and Version 2 of Development/Code/CodingStyle
- Timestamp:
- Mar 21, 2010, 11:27:45 AM (16 years ago)
Legend:
- Unmodified
- Added
- Removed
- Modified
-
Development/Code/CodingStyle
v1 v2 10 10 11 11 There 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]]:12 them. [http://www.kroah.com/linux/talks/ols_2002_kernel_codingstyle_paper/codingstyle.ps In short]: 13 13 14 14 * I want to read your code. … … 19 19 === Further reading === 20 20 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-Hartman21 * [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 23 23 24 24 == The basics == … … 40 40 === Use meaningful names for globals, short names for locals === 41 41 42 <tt>i</tt>is a perfectly valid identifier for a loop variable. However, you42 `i` is a perfectly valid identifier for a loop variable. However, you 43 43 deserve nasty punishment if you use it as a function name. 44 44 45 On the opposite, <tt>this_is_a_temporary_counter</tt>is plain bad for45 On the opposite, `this_is_a_temporary_counter` is plain bad for 46 46 a loop variable. 47 47 48 48 So, some good examples: 49 49 {{{ 50 50 sub write_user_credentials 51 51 { 52 52 # ... 53 53 } 54 54 }}} 55 56 {{{ 55 57 for my $i (0..10) { 56 58 # ... 57 59 } 58 60 }}} 59 61 60 62 And very bad examples: 61 63 64 {{{ 62 65 sub wuc 63 66 { 64 67 # WTH??? 65 68 } 66 69 }}} 70 71 {{{ 67 72 for my $counter_from_0_to_10_included (0..10) { 68 73 # Excuse me??? 69 74 } 70 75 }}} 71 76 72 77 === Be modular === … … 79 84 80 85 Here 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. 90 94 91 95 === Don't use magic numbers === 92 96 93 The <tt>constant</tt>pragma will give you meaningful names for any97 The `constant` pragma will give you meaningful names for any 94 98 values other than 0 and 1 you need. They'll help you to understand why 95 99 you chose such values on the past. 96 100 97 101 Good example: 98 102 {{{ 99 103 use constant PI => 3.141592; 100 104 }}} 105 {{{ 101 106 my $circle_area = $radio * PI * PI; 102 107 }}} 103 108 And the bad example 104 109 {{{ 105 110 # Oops! I missed a decimal somewhere! 106 111 my $circle_area = $radio * 3.14159 * 3.141592; 112 }}} 107 113 108 114 === Comments === … … 123 129 124 130 Bad examples: 125 131 {{{ 126 132 ############################################################ 127 133 # … … 130 136 ############################################################ 131 137 $i++; 132 138 }}} 139 140 {{{ 133 141 sub do_something 134 142 { … … 143 151 ... 144 152 } 153 }}} 145 154 146 155 These are best done like this: 147 156 {{{ 148 157 $i++; 149 158 }}} 159 160 {{{ 150 161 # Performs task foo... 151 162 sub foo {...} … … 154 165 # Performs task baz, which is quite similar to bar 155 166 sub baz {...} 156 167 157 168 # Performs a set of tasks, returning blah blah with arguments 158 169 # $arg1: … … 165 176 baz (@args); 166 177 } 167 178 }}} 168 179 169 180 Finally, don't put any credits on your comments, excepting on file 170 181 headers. 171 182 172 === Don't use <tt>vars</tt>===183 === Don't use `vars` === 173 184 174 185 This 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-wide186 ago. Instead, use the `our` declaration for package-wide 176 187 variables: 177 188 178 189 Good: 179 190 {{{ 180 191 our @ISA = ...; 192 }}} 181 193 182 194 Bad: 183 195 {{{ 184 196 use vars qw (@ISA); 185 197 @ISA = ...; 198 }}} 186 199 187 200 === Curly bracket position === … … 190 203 line as the sentence they belong to and close them on a line for their 191 204 own, excepting when it's an else or a do-while block: 192 205 {{{ 193 206 if ($foo) { 194 207 ... 195 208 } 196 209 }}} 210 211 {{{ 197 212 while ($bar) { 198 213 ... 199 214 } 200 215 }}} 216 217 {{{ 201 218 if ($foo) { 202 219 ... … … 204 221 ... 205 222 } 206 223 }}} 224 225 {{{ 207 226 do { 208 227 ... 209 228 } while ($bar); 229 }}} 210 230 211 231 This way it is perfectly clear where each block starts, finishes and … … 215 235 function. They should be on a different line, and have nothing else on 216 236 the same line: 217 237 {{{ 218 238 sub foo 219 239 { 220 240 my @args = @_; 221 241 } 242 }}} 222 243 223 244 The reason for this is that decent editors (f.i, Emacs) are aware that … … 229 250 230 251 Use them a lot. When in doubt, use them. Especially: 231 232 252 * Always use parenthesis on function calls 233 253 * Always use them on function calls even when there are no arguments 234 235 254 The reason is that: 236 255 {{{ 237 256 foo(); 238 257 }}} 239 258 Is easier to understand than: 240 259 {{{ 241 260 foo; 261 }}} 242 262 243 263 === Prefer methods over plain functions === 244 264 245 265 Especially when writing components, you want to log unexpected 246 things. It's free to have a <tt>$self</tt>object, and let it log.266 things. It's free to have a `$self` object, and let it log. 247 267 248 268 Only use plain functions if you want them exported to some other … … 253 273 === Running commands === 254 274 255 Do not use backticks or <tt>system</tt>, nor use <tt>open</tt>for pipes. The256 <tt>CAF::Process</tt>module has all you need, and it won't spawn new275 Do 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 257 277 subshells, which is much safer. 258 278 259 Another advantage of the <tt>CAF::Process</tt>module is that your279 Another advantage of the `CAF::Process` module is that your 260 280 command line will be automatically logged at verbose level, which 261 281 saves you snippets like this: 262 282 {{{ 263 283 $self->debug (5, "Going to run ls -l"); 264 284 system ("ls", "-l"); 285 }}} 265 286 266 287 This will become inconsistent with different uses. Instead, do: 267 288 {{{ 268 289 # Or any reporter object. 269 290 my $proc = CAF::Proces->new (["ls", "-l"], log => $self); … … 271 292 # One-line version: 272 293 CAF::Process->new (["ls", "-l"], log => $self)->run(); 294 }} 273 295 274 296 The log option is any CAF::Logger object, for instance the component … … 280 302 an encrypted password to usermod. In this cases, you don't want your 281 303 command logged. Just don't pass any log argument to CAF::Process::new: 282 304 {{{ 283 305 my $proc = CAF::Process->new (["ls", "-l"]); 284 306 $proc->run(); 307 }}} 285 308 286 309 ==== Examples ==== … … 292 315 293 316 Create the contents to be piped: 294 317 {{{ 295 318 my $contents = "Hello, world"; 296 319 }}} 297 320 Create the command, specifying $contents as the input, and "execute" it: 298 321 {{{ 299 322 my $proc = CAF::Process->new (["cat", "-"], stdin => $contents); 300 323 $proc->execute(); 324 }}} 301 325 302 326 ===== Piping in and out ===== … … 304 328 Suppose we want a bi-directional pipe: we provide the command's stdin, 305 329 and need to get its output and error: 306 330 {{{ 307 331 my ($stdin, $stdout, $stderr) = ("Hello, world", undef, undef); 308 332 my $proc = CAF::Process->new (["cat", "-"], stdin => $stdin, … … 310 334 stderr => \$stderr); 311 335 $proc->execute(); 336 }}} 312 337 313 338 And we'll have the command's standard output and error on $stdout and … … 317 342 318 343 Create the command: 319 344 {{{ 320 345 my $proc = CAF::Process->new (["ls", "-lh"]); 321 346 }}} 322 347 And get the output: 323 348 {{{ 324 349 my $output = $proc->output(); 350 }}} 325 351 326 352 === File handling === … … 329 355 that you should be aware of. For instance, the following code is an 330 356 example of what shouldn't be done: 331 357 {{{ 332 358 open (FH, ">/tmp/foo"); 333 334 If /tmp/foo already exists and is a symbolic link to /etc/shadow, you 359 }}} 360 361 If `/tmp/foo` already exists and is a symbolic link to `/etc/shadow`, you 335 362 just lost all accounts on your system. 336 363 … … 339 366 Don't open files directly. Use the CAF::FileWriter module to do the 340 367 work for you: 341 368 {{{ 342 369 my $fh = CAF::FileWriter->open ("/my/file", log => $self); 343 370 print $fh "Hello, world!\n"; 344 371 $fh->close(); 372 }}} 345 373 346 374 This module will perform all security checks for you, and will log … … 349 377 350 378 You can specify the permissions you want at instantiation, too: 351 379 {{{ 352 380 my $fh = CAF::FileWriter->open ("/my/path", mode => 0400, log => $self ); 353 381 print $fh "Hello, world!\n"; 354 382 $fh->close(); 383 }}} 355 384 356 385 If you find any errors and have to discard your contents, just call 357 386 the cancel method, and the existing file will be preserved: 358 387 {{{ 359 388 my $fh = CAF::FileWriter->open ("/my/path", mode => 0400, log => $self); 360 389 print $fh "Hello, world!\n"; … … 363 392 } 364 393 $fh->close(); 394 }}} 365 395 366 396 Finally, if the contents you generate are the same as on the original … … 391 421 Sometimes you just want to add a couple of lines to an existing file, 392 422 without destroying its current contents. Or to remove them. The module 393 <tt>CAF::FileEditor</tt>is just for that. It is a subclass of394 <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` 395 425 method you'll get a reference to the file's contents so that you can 396 426 freely update them. … … 398 428 For instance, you only want to change the first "a" for a b on the 399 429 first line of a file: 400 430 {{{ 401 431 my $fh = CAF::FileEditor->open ("/foo/bar", 402 432 log => $self); … … 404 434 $$ref_to_contents =~ s{a}{b}; 405 435 $fh->close(); 436 }}} 406 437 407 438 If 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. 409 440 410 441 ==== Other tasks with files ==== 411 442 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.443 When 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. 415 446 416 447 == Input handling == … … 424 455 Also, when you print files that will be sourced by shell scripts, be 425 456 sure to print all values between single quotes. This is true for 426 almost every file you have under /etc/sysconfig.457 almost every file you have under `/etc/sysconfig`. 427 458 428 459 == Quality of messages == … … 430 461 === Don't annoy the user === 431 462 432 The main principle is not to annoy the user. Use <tt>info</tt>and433 <tt>ok</tt>methods only for '''very''' important messages. A small463 The main principle is not to annoy the user. Use `info` and 464 `ok` methods only for '''very''' important messages. A small 434 465 description of the tasks you are going to perform, if they are complex 435 466 enough. … … 438 469 439 470 Provide 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, 441 472 services you have to enable or disable... 442 473 … … 446 477 === Debugging output === 447 478 448 Don't print user-relevant messages with <tt>debug</tt>. This should be479 Don't print user-relevant messages with `debug`. This should be 449 480 used only for developer-relevant stuff, such as tracking temporary 450 481 contents or so. … … 452 483 We don't have any convention for debug levels, is it needed? 453 484 454 === Use <tt>error</tt>only for fatal errors ===455 456 Use the <tt>error</tt>method only if this error will make the entire485 === Use `error` only for fatal errors === 486 487 Use the `error` method only if this error will make the entire 457 488 component fail. If you can handle it, or the fail is not really 458 important for the component's results, use <tt>info</tt>instead. If489 important for the component's results, use `info` instead. If 459 490 failing to download a file is OK because you can work around it, or 460 491 you know you may have no rights to write on AFS, but that's OK, use an 461 <tt>info</tt>message.492 `info` message. 462 493 463 494 Otherwise, the component will be re-run with no need, and will keep … … 473 504 task we repeat over and over (f.i, do we need any especial code to do 474 505 DNS queries or download files from the Internet?). 475 476 [[User:Luisfmunoz|Luisfmunoz]] 00:19, 12 January 2009 (UTC)