利用者:Nazg-gul/WritingGoodCode

提供: wiki
< 利用者:Nazg-gul
2018年6月29日 (金) 05:45時点におけるYamyam (トーク | 投稿記録)による版 (1版 をインポートしました)
(差分) ← 古い版 | 最新版 (差分) | 新しい版 → (差分)
移動先: 案内検索

Writing Good Code

There are only two important rules:

  • When making changes, conform to the style and conventions of the surrounding code.
  • Strive for clarity, even if that means occasionally breaking the guidelines. Use your head and ask for advice if your common sense seems to disagree with the conventions.

Formatting

  • Don't ever reformat, re-indent, change whitespace, or make any other such changes to working code. If you're adding just a few lines or fixing a bug in existing code, stick to the style of the surrounding code. In very rare circumstances, and with consensus of the group, reformatting is sometimes helpful to improve code readability, but it should be done as a separate formatting-only checkin.

Indentation

  • In C/C++ sources use TABs for indenation. Spaces are only allowed to keep wrapped part of line aligned with first part of line.
  • In python sources use SPACEs and never use TABs.
  • The whole idea behind indentation is to clearly define where a block of control starts and ends. Always indent when needed - that is, after if, do, while statements, function declarations, and so on.
  • When defining an argument list over multiple lines, the lines preferrable be indented with spaces such that the argument lines up under the opening brace of the argument list. For example:
/* Don't: */
void function_foo(arg1, arg2, ..., argN,
    argN+1, ..., argM,
    argM+1, argM+2);
void function_foo(arg1,
                  arg2,
                  arg3);
/* Do: */
void function_foo(arg1, arg2, ..., argN,
                  argN+1, ..., argM,
                  argM+1, argM+2);
/* --- snip --- *//* --- 120 chars long --- */
  • It is also OK to use two tab as indentation for wrapped lines in cases if editor doesn't support alignment automatically or in cases when function name and data types used in arguments are long:
/* Don't: */
/*   --- Line is longer than 120 characters  ---*/
static struct ReallyLongStructName *very_long_function_name_we_infact_have_a_handful_of_these(const struct ReallyLongStructName *some_arg,
                                                                                              void (*some_callback_with_many_args)(bContext *C, wmWindowManager *, int *arg1, int *arg2));
/* Do: */
static struct ReallyLongStructName *very_long_function_name_we_infact_have_a_handful_of_these(
        const struct ReallyLongStructName *some_arg,
        void (*some_callback_with_many_args)(bContext *C, wmWindowManager *, int *arg1, int *arg2));
  • When splitting if statement it's preferrable to split it on disjunction operation and keeping wrapped conditions:
if ((size = VectorObject_Check(value)     ? ((VectorObject *)value)->size : 0) ||
    (size = EulerObject_Check(value)      ? 3 : 0) ||
    (size = QuaternionObject_Check(value) ? 4 : 0) ||
    (size = ColorObject_Check(value)      ? 3 : 0))
{ /* in this case wrapped opening brace is reading easier */
	/* code - snip */
}

Arguments

Arguments to code constructs and functions shouldn't have a space between the construct or function name and the open parenthesis. The same goes for functions that take no arguments:

/* Don't: */
funct_foo (arg1, arg2);
funct_bar ();
/* Do: */
funct_foo(arg1, arg2);
funct_bar();

Placing braces

  • When defining a function, an opening brace must be at the next after relevant line. In other cases (i.e. for, while, if statements) opening brace should be on the same line as statement.
  • Note that the closing brace is empty on a line of its own, except in the cases where it is followed by a continuation of the same statement, ie a "while" in a do-statement. "Else" in an if-statement is placing on the next line of closed truth brench and opening brace is placing on the same line as "else" (if it's needed).

Operators and statements

  • Spaces should be used around assign operators (=, +=, /= and so), one space on each side of it:
/* Don't: */
foo= bar;
/* Do: */
foo = bar;
  • Space should be used between statement and brace:
/* Don't: */
for(ob = bmain->object.first; ob; ob = ob->id.next) {}
for( ob = bmain->object.first; ob; ob = ob->id.next ) {}
/* Do: */
for (ob = bmain->object.first; ob; ob = ob->id.next) {}
  • Body of switch statement should be indented, so case keyword has next indentation level relative to switch, body of case statement has got next indentation level relative to case:
/* Don't: */
switch(wmn->category) {
case NC_SPACE:
		ED_region_tag_redraw(ar);
		break;
default:
		break;
}
/* Do: */
switch (wmn->category) {
	case NC_SPACE:
			ED_region_tag_redraw(ar);
			break;
	default:
			break;
}

Header files

  • It is preferrable to keep header files inclused in alphabetical order.

Variable declarations

  • Variables should only be declared in beginning of blocks.
  • Declare complex variables (like structures, pointer to structures) first, scalar variables goes next:
/* Don't: */
int width, height;
float co[2];
MovieClip *clip;
MovieTrackingTrack *track;
/* Do: */
MovieClip *clip;
MovieTrackingTrack *track;
int width, height;
float co[2];
  • In case of structure variable depends on scalar variable, it's OK to declare scalar before structure.

Breaking long lines

  • Lines should not be longer than 120 characters (columns) long.
  • Statements longer than 120 columns will be broken into sensible chunks. Descendants are always substantially shorter than the parent and are placed substantially to the right. The same applies to function headers with a long argument list. Long strings are as well broken into shorter strings.

Generally the only exceptions are for comments with example commands or URLs - to make cut and paste easier.

The other exception is for those rare cases where letting a line be longer (and wrapping on an 120-character window) is actually a better and clearer alternative than trying to split it into two lines. Sometimes this happens, but it's extremely rare.

DO NOT alter somebody else's code to re-wrap lines (or change whitespace) just because you found something that violates the rules. Let the group/author/leader know, and resist the temptation to change it yourself.

Naming

  • Use descriptive names for global variables and functions.
  • Public function names should include module identiier, object and property they're operating and operation itself. Very familiar with RNA callbacks names: BLI_object_foo_get(...) / BLI_object_foo_set(...):
/* Don't: */
ListBase *curve_editnurbs(Curve *cu);
/* Do: */
ListBase *BLI_curve_editnurbs_get(Curve *cu);
  • Local variables should be short and to the point.

Punctuation, spelling and grammar

Pay attention to punctuation, spelling, and grammar; it is easier to read well-written comments than badly written ones.

Trailing whitespace

  • Try to avoid trailing whitespace. It's not issue if line contains only space characters placed for indentation (some editors are automatically placing them and not removing afterwards), but space characters at the end are annoying.

Commenting and documentation

  • Comments should explain what the code is doing, not how. The how should be more or less obvious from the way the code is written.
  • C code should use C-style comments only:
/* this is a C comment */
// This is a C++ comment, not a C comment
  • When using multiline comments, markers (star character, '*') should be used in the beginning of every line of comment:
/* special case: ima always local immediately. Clone image should only
 * have one user anyway. */

NOT

/* special case: ima always local immediately. Clone image should only
   have one user anyway. */
  • XXX marker should be used only in comments, describing usage of not very obvious solution caused by some design limitations which better be resolved after rethinking of design.

Functions

  • Functions should generally have a single exit (return) point.
  • Functions should be short and sweet, and do just one thing. They should fit on one or two screenfuls of text, and do one thing and do that well.
  • For complex functions, break the code up into helper functions, or inline code if performance-critical.
  • Try to keep the number of local variables in a function around 7 (plus or minus two or three). If more variables are needed, think about splitting the code into multiple functions.

Macros, Enums, Inline functions and RTL

  • Names of macros defining constants and labels in enums should be capitalized.
  • Macro names should be capitalised.
  • Enums used in DNA files should have explict values assigned.

Settings for the editors

Show whitespaces in the editors

Emacs
(setq-default show-trailing-whitespace t)
Vim
highlight WhitespaceEOL ctermbg=red guibg=red
match WhitespaceEOL /\s\+$/
Eclipse
Window -> Preferences -> General -> Editors -> Text Editors
[x] Show whitespace characters
GEdit
In Preferences, Plugin tab, enable White Space one (and set it to your liking).
QtCreator
In Preferences, Text Editor, Display, Visualize whitespace.