]>
2006-19-05 YaST2 Developer Pages: Coding Rules Any fool can write code that a computer can understand. Good programmers write code that humans can understand. Martin Fowler in: Refactoring, improving the design of existing code Having multiple developers working on the same source code creates a need for a basic set of coding rules to adhere to. A proper code layout makes it a lot easier for others to read, understand, enhance, debug, and clean-up code. Having a coding style is quite common. Two of the more prominent examples are The Linux kernel coding style /usr/src/linux/Documentation/CodingStyle and the GNU coding standard http://www.gnu.org/prep/standards/. Preamble This document describes how to layout code written in YCP: how to name your variables and functions, how to place braces, and how to indent blocks. Most programmers have a personal style of writing code. The rules presented here might not match your personal preferences, but will help everyone work on the code as a team. Helping out and fixing bugs is easier with a common coding style. The following set of rules tries to be complete, but probably isn't. Feel free to write the maintainer, &document-maintainer;, about mistakes and omissions. These rules should apply to C, C++, and YCP code alike, even though the examples use YCP. As much as possible, additionally apply them to Perl code. The File Header Every file must begin with a proper header. This header should be started within the first 10 lines of the file, so it is visible when loading the file in an editor. The file header must include: The filename The file purpose summary (in one line) The author's name and e-mail address A few lines describing the contents Do /** * File: * io.ycp * * Module: * Security configuration * * Summary: * Input and output functions. * * Authors: * Michal Svec <msvec@suse.cz> * * $**Id$ * * There are in this file all functions needed for * the input and output of security settings. */ Don't { // a small example with no version and no hint // about the author. return 42; } Indendation Among developers, indentation of code is one of the most heated points of discussion. There are several 'good' ways to use whitespace when writing source code and all are 'right' in some respect. The only bad indentation is no indentation at all. To make code easy to read, a common way of using whitespaces is needed across a team of developers: Indent by 4 spaces Tabs, if used, are 8 spaces wide, replacing two levels of indentation Always indent Only a few lines of a file are allowed to be not indented. These are the initial comment lines of the file header and the opening and closing braces around the code. Do /** ... initial header */ { // opening brace at start of code // my first variable, 4 spaces indentation integer first_int_variable = 42; if (first_int_variable > 42) { // 8 spaces (== 1 tab character) indentation doSomething (); } else { somethingDifferent(); } // final return return first_int_variable; } // closing brace Don't /* ... initial header */ { // opening brace at start of code // my first variable, bad indentation integer first_int_variable=42; if(first_int_variable>42) doSomething (); else somethingDifferent(); return first_int_variable;} Whitespace Whitespaces (spaces, tabs, and new line characters) are allowed anywhere in the code. Proper use of whitespace does make code a lot easier to read and more pleasing to the eye. Spaces are mandatory at the following places: Before an open parenthesis At function calls At if and while expressions After a comma At parameter lists in function calls At list and map elements Before and after a binary operator (= is a binary operator) New lines are mandatory at the following places: After every statement. As a rule of thumb, a semicolon must be followed by a newline. Before and after every opening brace. Before and after every closing brace. After the initial variable declarations before the first statement. To separate functional groups. A functional group is this sense is a set of variable declarations before a group of computational statements. Another example is grouping in preprocessing, computing, and postprocessing often used in larger modules. Use whitespaces at other places you find appropriate to maintain readability. Do if (bool_flag) ... while (stay_in_loop) ... callFunction ( value1, value2 ); list a_list = [ 1, 2, 3, 4 ]; map a_map = $[ 1:`first, 2:`second ]; boolean test_flag = true; if (test_flag) { integer one = 1; boolean two_flag = false; callFunction (one, two_flag); } Don't if(bool_flag) ... while(stay_in_loop) ... callFunction(value1,value2); list a_list=[1,2,3,4]; map a_map=$[1:`first,2:`second]; boolean test_flag=true; if (test_flag){ integer one=1;boolean two_flag=false; callFunction(one,two_flag);} Some explanation to the above "Don't" example: There is no blank before the "(" in the if, while, and callFunction lines. There is no new line to properly separate the group of variable declarations from the computational statements. There are two variable declarations in the if () block. Without whitespace, this is not easily visible. Naming of Variables This rule should be easy if you keep in mind that other developers want to read and understand your code. The general rule is to use meaningful variable names. When reading the name of a variable, it should be immediately clear What kind of value variable represents How the variable is used Its scope The length of a variable is unrestricted. Use this fact. To make a clear distinction between variable names and function names, use _ in variables and uppercase and lowercase in function names. Do boolean is_sparc = (architecture == "sparc"); list <map> probed_modems = (list <map>) SCR::Read ( .probe.modem ); integer list_index = 0; map a_modem = $[]; while (list_index < size (probed_modems)) { a_modem = probed_modems[list_index]:$[]; doSomething (a_modem, is_sparc); list_index = list_index + 1; } Don't boolean n = (architecture == "sparc"); list <map> dev = (list <map>) SCR::Read(.probe.modem); integer i = 0; map m = $[]; while (i<size(dev)) { m = dev[i]:$[]; func (m, n); i=i+1; } Naming of Functions Like variables, function names should speak for themselves. The above arguments for naming variables apply also to functions. Instead of _, use mixed uppercase and lowercase. It is also helpful to distinguish between global and local functions. Local functions should start with a lowercase letter, while global functions should start with an uppercase letter. Do // this is a local function writeStringToFile (a_string, file_name); // this is a global function global_settings = ReadGlobalSettings (); Don't f1 (a_string, file_name); gs = rgs(); Blocks and Braces There are more ways to place braces around a block than there are computer languages that use { and }. For YaST2, only two rules about braces are important: The opening and closing brace are on the same indentation level The opening brace increases the indentation level by one (which equals 4 spaces) Do // start of file // first brace doesn't have any indentation { // 4 spaces indentation integer initial_index = 0; while (initial_index < 10) { // incremented indentation level initial_index = initial_index + 1; } return initial_index; } Don't {integer initial_index = 0; while (initial_index < 10){ initial_index = initial_index + 1;} return initial_index;} if-then-else, while, etc. Always use a block for if and else cases and while statements. Do if (value) { aStatement (); } else { anotherStatement (); } while (stay_in_loop) { doLoopStatement (); ... } Don't if (value) aStatement ();else anotherStatement (); while (stay_in_loop) doLoopStatement (); Comments Comment every function with a structured comment. The comments are used to generate documentation. The syntax is similar to ydoc (kdoc). Do /** * Update the SCR from the map of all security settings * * @param map settings a map of all security settings * @return boolean success */ boolean SecurityWrite (map settings) { ... } Other Habits This is a small list of other things to consider when writing code Superfluous whitespace in the source. For vi users, adding syntax on let c_space_errors=1 should help. In Emacs, set the variable show-trailing-whitespace (also see whitespace.el). Replace blanks with tabs. Because a tab character equals 8 spaces, numerous spaces should be replaced by tabs.