Nuclex C# Coding Guidelines
It's short, it's simple, it's obvious! ;)
These are the official coding guidelines used by Nuclex Development Labs. The goal of this document is not to define a rigid, bureaucratic set of rules that are tedious to comply with, but to complement the programmer in creating aesthetical and understandable code. All rules try to be intuitive and are based on solid reasoning.
In general, we try not to stray from the mainstream in any major point, so as to not alienate us from the code of other programmers or the rules by which the .NET Framework itself has been developed.
1. File Structure
Establishing a common order of elements in each source file greatly helps programmers to navigate unknown code. In this context, we believe that someone looking at the code should first see the actual methods he can call from the outside and only get to see the class' bowels (namely, private methods and fields) at the very end of the file.
1.1 Order class elements by their visibility
When you look at a class someone else has written, the first thing you
want to see are the constructor and the public methods it exposes,
not the implementation details. Thus, we order elements by their visibility,
first comes public, then internal, then
protected and finally private. Upon that,
we place additional type definitions (nested classes, delegates, events)
at the top of a class. Next comes the constructor(s) and destructor or
Dispose() method, if any. Then follow any methods and
properties with the fields at the very bottom of the class.
// 1. Nested classes, delegates and events
// 2. Constructors (of any visibility) and destructor / Dispose() method
// 3. Public methods and properties (visible globally)
// 4. Protected methods and properties (visible in inheritance tree)
// 5. Internal methods and properties (visible in same assembly)
// 6. Protected Internal methods and properties (visible in inheritance-tree of same assembly)
// 7. Private methods and properties (visible in class only)
// 8. Public fields
// 9. Protected fields
// 10. Internal fields
// 11. Protected Internal fields
// 12. Private fields
}
1.2 Keep source files below 500 lines
No source file is allowed to become longer than 500 lines. In fact, you should try
to stay way below that number. If you feel the need to write classes taking more
than 500 lines, either the design of your class is too complex, your class tries to
take on multiple roles or you are simply writing very inefficient code. There is always
the option to factor out concepts and strategies into separate, reusable classes.
This applies even more to Form classes that become too large by the mere amount
of controls they need to manage, which not only is problematic for the developers,
but also repels the end-user with overly complex dialogs.
2. Naming and Casing
There is nothing more important than using well chosen, descriptive variable names, or, in other words, hitting the nail on the head with a term. Always try to find a simple term that gives the reader a clear idea of what that variable or method does. If you really can't find a fitting term (or combination thereof), just standardize the closest matching term for this specific use throughout the project and document that!
2.1 Do not use abbreviations
Even well-known abbreviations make identifiers harder to read and in combination produce
ugly chunks of letters. Your code becomes more aesthetical and it helps to keep your
variable names simple if you force yourself to avoid abbreviations at all costs. There are
very few exceptions (like, Xml) and you certainly shouldn't add more to those :)
2.2 Write all your names in proper english
Any variable, method or class name you choose should follow the conventions of the
english language. Do not twist words around (eg. not FileOpen/FileClose
but OpenFile/CloseFile instead) and use the correct plural forms
(eg. not Childs, but Children instead). Do not use prefixes for your
identifiers (a prime example of prefixes would be hungarian notation). The only exception
to this rule is that interface names are prefixed with an I, for the sake of keeping
in compliance with the .NET Framework conventions.
2.3 Use NormalCase for public and camelCase for private elements
In order to not produce schizophrenic code when interacting with the .NET Framework,
all public elements follow the same naming rules that the .NET Framework uses.
Thus, anything that can be seen from the outside of a class, including internal and
protected members, is written in NormalCase. Private things such as private methods and
local variables are written in camelCase. Place uppercase letters only after
complete english words, not for each syllable (eg. not DisConnect
but simply Disconnect; not ReMove but Remove).
3. Braces
We handle all the different kinds of braces with the same rule (C# actually has 4 kinds of braces: curly braces, brackets, rounded braces and wedges). That means if the argument list of a method becomes too long, break it the same way as you break the code inside a multi-line if statement. One rule for everything.
3.1 Put opening braces at the end of the line
We like our opening braces at the end of declarations and control flow keywords. The
indentation already shows very well where a block begins and where it ends. There have
even been successful languages (Python being the most prominent example) that rely
solely on indentation to determine the length of blocks. Free standing curly braces would
act as semi-empty lines whereas we believe that empty lines should instead be at the
programmer's disposal to seperate logical sections in code.
3.2 Always use curly braces for cases in a switch statement
This is mainly for consistency reasons, since historically, the switch
and case statements don't blend in with the rest of the language
very well. Using curly braces for each case in a switch
statement makes the indentation more logical and prevents variables declared in one
case from becoming visible in the scope of other cases.
4. Indentation and Line Breaks
Indentation in general is a matter of personal preference and regularly subject to discussion. Using a consistent scheme throughout an entire project goes a long way in helping developers quickly grasp the workings of the code without being irritated by small discrepancies from the style their brain is currently trained to read.
4.1 Indent any nested block by 2 spaces
Indentation is done with spaces, not tabs. This keeps code looking identical in
web browsers and editors with different tab widths. While of course the nesting level
should not go too deep, 2 spaces provide good visual distinguishment without
scattering the code all over the horizontal width of an editor for developers
using larger fonts or a lower screen resolution.
4.2 Limit your lines to 100 columns at most
This is not just a suggestion, it's an actual rule. Creating long
lines will prevent the developer from seeing what's going on and
require him to scroll the text window or enable line wrapping, both
of which are awkward for anyone trying to get a quick grasp of the
code. It will also make it harder to post code snippets on the web
or to print them. So do not cross the 100 column boundary, ever.
4.3 Try to break long lines at the brace level
When you decide to break a long line, try to do so after an
opening brace (or a comma sign if no brace is available). As outlined
in section 3, the opening brace is left at the end of the line,
while everything that was inbetween the braces goes into the next
line(s), indented by 2 spaces. Example:
Do not:
int argument3) {
// ...
}
Instead, do:
int argument1, int argument2, int argument3
) {
// ...
}
5. Special Regulations
Some additional regulations not fitting into any of the topics laid out above:
5.1 Only write accessors where necessary
Do not commit to encapsulatiomania! There's no sense in writing useless
accessors that simply wrap fields without reason. Wrapping value type
fields makes it harder to work with such a field because you can no
longer modify them directly, you will have to copy them to a temporary
variable, modify them and assign them back. Also take into account the
performance aspect: while properties are prime candidates for inlining,
you cannot count on it. A virtual property will never be inlined. The
same goes for properties contained in other assemblies, like that
Vector class in your Math assembly,
for example ;)
5.2 Keep your code together
Try not to create too many assemblies (eg. don't create a separate assembly
for each namespace). It might feel nice and clean to have lots of assemblies
with different logical responsibilities, but the inter-assembly dependencies quickly
become a real pain to manage and it leaves a negative impression when someone
has to identify all the different assemblies required to use a given class by
working his way through the dependency tree one step at a time. This is very much
a matter of experience and taste, so please consult other developers when you're
unsure on whether you should create a new assembly or extend the responsibilities
of an existing assembly.