Development Team/Coding Standards
m (→Separation) |
m (→Braces) |
||
Line 114: | Line 114: | ||
For example, place braces like this: | For example, place braces like this: | ||
- | < | + | <c> |
if (!(bp = malloc(sizeof (Buffer)))) { | if (!(bp = malloc(sizeof (Buffer)))) { | ||
perror("malloc"); | perror("malloc"); | ||
abort(); | abort(); | ||
} | } | ||
- | </ | + | </c> |
and NOT: | and NOT: | ||
- | < | + | <c> |
if (!(bp = malloc(sizeof (Buffer)))) | if (!(bp = malloc(sizeof (Buffer)))) | ||
{ | { | ||
perror("malloc"); | perror("malloc"); | ||
abort(); | abort(); | ||
- | }</ | + | }</c> |
== Variable naming == | == Variable naming == |
Revision as of 03:30, 4 December 2009
DareNET Development Wiki - Coding Standards
The following is a guide to explain the programming style used for ircd-darenet and services-darenet, and to advise future developers, creators or patches, or other maintainers in regards to desirable programming practices. Since these programs are based on the works of others (outside of the DareNET development team), it's reasonable to assume not all code will follow them. This, of course, will be rectified with time.
Comments
Comments can add immensely to the readability of a program, but used heavily or poorly placed they can render good code completely incomprehensible.
That being said, good places to put comments are:
- a broad overview at the beginning of a module
- data structure definitions
- global variable definition
- at the beginning of a function
- tricky steps within a function
You should also strive to doxify your comments, where suitable. Rambles, rants, and personal complaints do not provide any benefit to understanding code, please do not add them.
Multi Line
Multi line comments should follow the C-style comment, for example:
/**
* This is a multi line comment.
* - SecretAgent
*/
Single Line
Single line comments should also be in the C style, for example: <source lang="c" line start=1 > /**< This is a one-line comment. - SecretAgent */</source>
Please avoid using C++-style single line comments (e.g. // Something here
).
Additionally, the opening / of all comments should be indented to the same level as the code to which it applies, for example:
if (fubar()) { /* * Fouled up beyond all recognition. Print a nastygram * and attempt to clean up. If that doesn't work, * die horribly, and try to crash the system while * we're at it. */ ... }
Character Sets
The ASCII character set (plain text, 7-bit characters) should be used in all source code comments, text documents, and other contexts (note, this doesn't apply to services-darenet help files). Also, it is okay to use non-ASCII characters to represent proper names of contributors in change logs and credits; however, these are the only exceptions. In general, you can't mix encodings reliably.
Source/Header Files Organization
Use the following organization for source files:
- includes of system headers
- includes of local headers
- global variables
- functions
Within each section, order your functions in a 'bottom up' manner - defining functions before their use. The benefit of avoiding redundant (hence error prone) forward declarations outweighs the minor irritation of having to jump to the bottom of the file to find the main functions.
In header files, use the following organization:
- type and constant definitions
- external object declarations
- external function declarations
Avoid having nested includes, ever. If you've ever tried to track a bug through the SunOS /usr/include maze, you'll understand why. Consider using the makedepend tools to help maintain your source file dependencies in your Makefile.
File Naming Conventions
File names are made up of a base name, peiod and suffix. The first character of the name should be a letter and all characters (except the period) should be lower-case letters and numbers. Please try to keep the base name short. These rules apply to both program files and default files used and produced by the program. Browse the current repos for an idea of how things are currently done. Ask if you're unsure!
Suffix Conventions
- C source files should end in .c
- Python source files should end in .py
The following conventions are universally followed:
- Relocatable object files end in .o
- Include header files end in .h
- Yacc source files end in .y
- Lex source files end in .l
In addition, it is conventional to use "Makefile" (not "makefile") for the control file for make (for systems that support it) and "README" for a summary of the contents of the directory or directory tree.
Indentation
Tabs. Tabs. ONLY TABS.
Use a single tab for each level of indentation, for example:
int main() { if (condition) { code } }
Separation
Always put a space in between a keyword like if/while and the condition, for example:
if (foo == bar)
NOT
if(foo == bar)
Braces
We follow the K&R style of indentation. That means, opening braces should go on the same line as the control statement, while closing braces should go on a line of its own at the same indentation level as the control statement. However, functions should be braced distinctly from statements; an opening function brace is placed on the line following the declaration, at the same indentation level as the declaration.
For example, place braces like this:
if (!(bp = malloc(sizeof (Buffer)))) { perror("malloc"); abort(); }
and NOT:
if (!(bp = malloc(sizeof (Buffer)))) { perror("malloc"); abort(); }
Variable naming
Length is not a virtue in a name; clarity of expression is. A global variable rarely used may deserve a long name, maxphysaddr say. An array index used on every line of a loop needn't be named any more elaborately than i. Saying index or elementnumber is more to type (or calls upon your text editor) and obscures the details of the computation. When the variable names are huge, it's harder to see what's going on.
Struct names should be in camel case with a leading capital letter, for example, "MyBagOfBones". Variable names can be either in camel case with a leading capital letter or alternatively all lower case, so long as the same naming convention is adhered to throughout. Constants and enum values should always be completely in CAPITALS and underscores may be used.
Use of char pointers
Whenever you use char pointers (char*, char**) try to use const equivalents. This is much safer and avoids ugly and dangerous casts.
Macros
Macros should only be used to simplify a piece of code that has complicated or repeated expressions. We also advise that you #undef a macro when you're done with it. Over using them can, and will, slow a program down, not to mention make the compiled code become rather large. If you are writing a piece of code that is going to be available from multiple parts of the program, it should be a function, not a macro.
Functions
Functions should be short and sweet. If a function won't fit on a single screen, it's probably too long. Don't be afraid to break functions down into smaller helper functions. If they are static to the module an optimizing compiler can inline them again, if necessary. Helper functions can also be reused by other functions.
However, we do realize that it is sometimes hard to break things down. Since functions don't nest, variables have to be communicated through function arguments or global variables. Don't create huge interfaces to enable a decomposition that is just not meant to be.
Linefeeds
Unix linefeeds only please. We do not like to see our screens covered in ^M.
Additionally, the maximum line width is 80 characters. If you are writing a longer line, try to break it at a logical point and continue on the next line with the same indenting. Use of backslash is okay; however, multi-line literals might cause less confusion if they are defined before the function start.
Portability
Always make sure your code is portable to all supported operating systems. Don't write code that only works on Linux. Test your code on all platforms or ask for help from other developers who have the platforms you want to test on.
We currently test all major releases on Gentoo and FreeBSD. If you have another platform in mind, let us know. We may just be willing to add it to our list.
External Dependencies
You must not use any dependencies that are not available as standard on all supported operating systems beyond libc, and whatever else is currently needed to build the ircd/services. If you absolutely must do so, you will need approval from the Development Manager first.
Profiling and Performance
It is one thing to assume that code performs bad, it is another thing to prove that it actually is. A lot of experienced programmers talk about 'premature optimization', and here is what it means: if you have a piece of code called once on start up that takes 10 seconds instead of one second to run, and a piece of code that takes 0.05 seconds to run when it should take 0.01, and it is called once per second, the second piece of code is the priority.
In other words, make sure that what you think is slow, and a performance problem in ircd-*/services-* actually is.
more to come, possibly...