diff options
Diffstat (limited to 'libcrystfel/doc/coding.md')
-rw-r--r-- | libcrystfel/doc/coding.md | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/libcrystfel/doc/coding.md b/libcrystfel/doc/coding.md new file mode 100644 index 00000000..ffabc3bf --- /dev/null +++ b/libcrystfel/doc/coding.md @@ -0,0 +1,156 @@ +\page coding CrystFEL coding standards + +### Licensing + +CrystFEL is distributed under the terms of the GNU General Public License +version 3 or higher. Contributions are very welcome provided they also use this +license. If your code is not already licensed compatibly, or if the license if +not clear, we will ask you to re-license it. + +Whenever you edit a source file, don't forget to update the copyright dates at +the top. Add your name and email address if they're not there already. Be sure +to add your name to the 'AUTHORS' file in the top level folder, as well. + +### Scope + +The remainder of these rules apply to C code in libcrystfel and the core +CrystFEL programs. There are currently no specific guidelines for Python, +Perl, shell script, CMake files or other parts of the codebase. + +### Indentation + +*Indentation* is done with *tabs* and *alignment* is done with spaces. +For example: + + int function(int a, int b) + { + int p; /* <--- Tab character used to indent code inside function */ + char *str; + + do_something(a, "A long string which takes up a lot of space", + str, &p); /* <--- spaces used to align with bracket */ + } + +**Rationale:** Using tab characters makes it easy to align code correctly, +because you can't slip out of alignment by one character. It also makes the +code look neat whatever width you configure your editor to display tabs as. + +### Wrap width + +Code should fit into 80 columns (counting tab characters as 8 columns) wherever +possible, with exceptions only in cases where not doing so would cause line +breaks at ugly positions, such as straight after an *opening* bracket. The +absolute maximum allowable line length is 120 columns, with no exceptions +whatsoever. + +**Rationale:** Aside from ensuring it's always possible to display two parts of +the code side-by-side with a reasonable font size, this is not really about how +the code looks. Rather, it is to discourage excessive levels of nesting and +encourage smaller, more easily understood functions. I don't think I've yet +seen any examples of code where the intelligibility could not be improved while +simultaneously reducing the number of levels of indentation, except where very +long variable or function names had been used. Hence the next point: + +### Variable and function names + +Shorter variable and function names, with explanatory comments, are preferred +over long variable names: + + double wavelength_in_angstrom_units; /* <--- not preferred */ + +Preferred: + + /* The wavelength in Angstrom units */ + double wl; + +"Snake case" is preferred over "camel case": + + int model_option; /* <--- Preferred */ + int modelOption; /* <--- Discouraged */ + +### Nested loops + +When performing a two or three dimensional iteration which could be considered +as one larger iteration, for example over image coordinates or Miller indices, +it is acceptable to indent as follows: + + for ( h=-10; h<+10; h++ ) { + for ( k=-10; k<+10; k++ ) { + for ( l=-10; l<+10; l++ ) { + + /* Do stuff */ + + } + } + } + +In this case, there must be no lines at all, not even blank ones, between each +of the "for" statements and also between each of the final closing braces. + +***Rationale:*** Large multi-dimensional loops are common in scientific code, +with more than three levels not at all uncommon. Any reasonable limit on code +width would be overshot by indenting each level separately. + +### Bracket positions + +Brackets and so on should go like this: + + /* Multiple line comments have stars + * down one side */ + void somefunction(int someparam) + { + /* Single line comments use this style (not //) */ + if ( a < b ) { /* <--- Opening brace on same line as 'if' */ + do_something(a); + } else { /* <--- 'else's are 'cuddled' */ + do_other_something(a); + } + + if ( some && very && long && condition && that && spans + && two && lines ) + { /* <--- Opening brace on a line by itself acceptable in this case */ + do_something_completely_different(someparam); + } + } + + /* Comments use proper capitalisation to make things look neat */ + +'struct' blocks can have the braces like functions or 'if' statements. Usually +the former looks nicer if the struct is large. + +Parentheses should have spaces after them in 'if' statements, but not in +function calls. Function arguments should have spaces after the comma. There +should be no space between the function name and the opening bracket. That +means: + + if ( something ) { + do_something(a, b, c); + } + +instead of: + + if (something) { + do_something (a,b,c); + } + +### Cleverness + +Transparent, easily understood solutions are preferred over faster ones, except +where you can demonstrate that the code is performance-critical and the benefit +is significant. Even in that case, copious comments should be provided. + +Use of undefined behaviour, even if "it always works", is absolutely forbidden. + +### Git/VCS usage + +This style of commit message is preferred: + +> Strip out libfrosticle references and add new function model + +This style of commit message is discouraged: + +> Stripped out libfrosticle references, and added new function model + +**Rationale:** this encourages you to think in terms of small, self-contained +changes to the code, rather than successive versions with many different changes +combined together. It also matches the conventions used by most other projects. |