Coding Standard and Guidelines

From OpenPetra Wiki
Jump to navigation Jump to search

About the C# Coding Style Guide

This document may be read as a guide to writing robust and reliable C# programs.

Notes:

  1. Many of the rules in this document can be applied automatically to source code using the 'Uncrustify' tool that we use (make uncrustify)
    1. Those rules are marked with 'Enforced by Uncrustify.'
  2. Many of the rules in this document can be checked automatically with the 'StyleCop' tool that we use (make stylecop)!
    1. Those rules are marked with 'Checked by StyleCop.' TODO
  3. 'Uncrustify' and 'StyleCop' and how we use them with Petra are described in Coding Standards Tools: 'Uncrustify' and 'StyleCop'.

This 'C# Coding Style Guide' was inspired by the C# Coding Style Guide written by Mike Krüger. This is used by the SharpDevelop programmers who work on the SharpDevelop IDE.

File Organization

C# Sourcefiles

  • Keep your classes/files short: try hard not to exceed 3.000 lines of code and never go beyond 4.000 lines of code.
    • Exception to that:
      • Auto-generated code can ignore that rule if the generated file doesn't need to be looked at/touched by developers.
  • Divide your code up and make structures clearer.
  • Every class should go in a separate file.
    • Exceptions to that:
      • Helper classes for the main class in the same file are allowed, but they must be private classes!
      • Auto-generated code can ignore that rule if the generated file doesn't need to be looked at/touched by developers.
  • The file name should reflect the name of the class in the file (.cs as extension of course).
    • Exception to that:
      • The file name of a source file can have the last part of a Namespace in it if the Namespace is nested quite deeply and

the directory structure doesn't reflect that deep nesting anymore (see 'Directory Layout' below). Example: DataAggregates.PPartnerAddress.cs in Namespace 'Ict.Petra.Server.MPartner.DataAggregates' in directory 'U:\openpetraorg\csharp\ICT\Petra\Server\lib\MPartner'.


These conventions makes things much easier to read and find.

Directory Layout

  • Create a directory for every namespace. Example: for Namespace 'Ict.Petra.Server.App.Core' use 'U:\delphi.net\ICT\Petra\Server\app\' as the path (do not use the Namespace name with dots for directory names).
    • Exceptions to that:
      • Additional directories might be placed inbetween parts of the Namespace if that benefits the directory structure and an agreed rule when to do that is followed. Example: Namespace 'Ict.Petra.Server.MPartner.DataAggregates' resides in directory 'U:\delphi.net\ICT\Petra\Server\lib\MPartner'. Note the 'lib' directory, which is inserted.
      • If a Namespace is nested quite deeply, we can opt to have the directory structure not reflecting that deep nesting. In that case, the last part of a Namespace should then be part of the file name of a Class (see 'C# Sourcefiles' above).


See also 'Explanation of Directory Structure and Rules' for more detailed information!


These conventions make it easier to map namespaces to the directory layout.

Indentation

White Spaces

For code indentation, two standards exist in the world of programming: indendation with spaces and indendation with tabs. Some programmers prefer spaces, others prefer tabs.

Here, we define the space character as the standard indentation character. Specifically, we indent everything with four spaces - Enforced by Uncrustify. This applies for the indendation from column 1 to the indendation level of the current code and also to any further indendations from there.

By using spaces, not tabs, we can ensure that our code is indented identically for every developer and in every editor. If we used tabs, the indentation could vary.

Don't use tabs for indentation - use spaces! Enforced by Uncrustify.

Wrapping Lines

When an expression will not fit on a single line, break it up before it reaches more than 150 characters. Enforced by Uncrustify. You might want to break it up before that for readability.

Follow these general principles when breaking up a line:

  • Break after a comma.
  • Break after an operator.
  • Prefer higher-level breaks to lower-level breaks.
  • Indent the new line at the standard indentation level, or align the new line with the beginning of the expression at the same level on the previous line.

Example of breaking up method calls:

LongMethodCall(expr1, expr2,

     expr3, expr4, expr5);  // indented at the standard indentation level

or

LongMethodCall(expr1, expr2,

                expr3, expr4, expr5);  // aligned with the beginning of the expression on the previous line

The first is preferred because it results in uniformly formatted code, but if indenting with the second method makes for better reading in a specific case then use the second method.


Examples of breaking an arithmetic expression:

PREFER:

var = a * b / (c - g + f) + 

    4 * z;

BAD STYLE – AVOID:

var = a * b / (c - g + 

    f) + 4 * z;

The first is preferred, since the break occurs outside the paranthesized expression (higher level rule).


Comments

All comments must be written in English.

Block Comments

Block comments for the purpose of describing Classes, Methods, etc. should be avoided. Instead, use of the /// comments to give C# standard descriptions is recommended (see 'Documentation Comments' below).

If you wish to use block comments inside Methods, Classes, etc. you should use the following style:

/* The following Algorithm does bla bla bla

 * and is adapted from the well-known blah blah Algorithm.

 * An example of this Algorithm can be found on http://www.blahalgorithms.org

 */

...as this will set off the block visually from code for the (human) reader.

Block comments may be useful in rare cases, refer to the TechNote 'The fine Art of Commenting' for an example.

As a general rule of thumb, the length of a comment should not overly exceed the length of the code it explains as this is an indication of too complicated (and potentially buggy) code.

For commenting out sections of code, use the 'Single Line Comments' (despite their name) to distinguish better between code that has comments attached and code that is commented out.

Single Line Comments

Developers should use the // (two forward slahes) comment style to "comment out" code (SharpDevelop has a shotcut key for it, Alt+/). It may be used for commenting out sections of code too.

Note on using StyleCop: because we will use StyleCop, you should rather use //// (four forward slashes) instead of // when commenting out single lines of code. This helps the tool to not confuse it with a single line comment (which is not commented out code). (Refers to StyleCop Rule SA1512: SingleLineCommentsMustNotBeFollowedByBlankLine.)


Single line code comments must be indented to the indent level when they are used for code documentation. Commented out code should be commented out so that the // (two slashes) start in column 1. This is to enhance the visibility of commented out code.

Documentation Comments

In the .NET framework, Microsoft has introduced a documentation generation system based on XML comments. These comments are formally single line C# comments containing XML tags. They follow this pattern for single line comments:

/// <summary>

/// This class...

/// </summary>

Multiline XML comments follow this pattern:

/// <exception cref=”BogusException”>

/// This exception gets thrown as soon as a

/// Bogus flag gets set.

/// </exception>

All lines must be preceded by /// (three slashes) to be accepted as XML comment lines.

Tags fall into two categories:

  • Documentation items
  • Formatting/Referencing

The first category contains tags like <summary>, <param> or <exception>. These tags represent the elements of a program's API which must be documented for the program to be useful to other programmers. They usually have attributes such as name or cref (as demonstrated in the multi line example above) and are checked by the compiler, so they should be valid.

The latter category governs the layout of the documentation, using tags such as <code>, <list> or <para>.

For a fuller explanation of XML comments see 'CSharp In-Code Documentation with MS XML Tags'. For information on how to produce API-style documentation for C# Projects whose .cs files contain XML Comment Tags, see 'How to produce CSharp API Documentation'.

For information on commenting best practice and further issues related to commenting, see the TechNote 'The fine Art of Commenting'.

End Comments

By 'End Comments' we mean adding a single-line comment after the closing curly brace "}" of a code block to explain what section of code the closing curly braces ends.

We decided this is unnecessary if this information is obvious. In other words, use 'End Comments' only when the meaning of the closing curly brace "}" of a code block is not immediately obvious due to either a very long block, or in the case of many nested blocks.

Declarations

Number of Declarations per Line

Only one declaration per line is allowed. This greatly enhances readabiliy and it encourages commenting.

GOOD STYLE:

int Level;   // indentation level
int Size;    // size of table

Do not put more than one variable or variables of different types on the same line when declaring them.

BAD STYLE - AVOID:

int Var1, Var2;   // What is 'Var1'? What does 'Var2' stand for?

Declarations should be followed by an empty line so that they are visually set apart from the rest of the source code. Enforced by Uncrustify.

The above example also demonstrates the drawbacks of non-obvious variable names.

Be clear when naming variables. Using self-explanatory variable names such as IndentLevel eradicates the need for making explanatory comments.

Initialization

Try to initialize local variables as soon as they are declared.

For example:

string Name = myObject.Name;
int Val = time.Hours;

Initialisations should be followed by an empty line so that they are visually set apart from the rest of the source code. Enforced by Uncrustify if the initialisations are part of declarations.

Note: when initializing a Dialog/Modal Form (by using .ShowDialog instead of .Show), use the following construct to be sure the Form is released from memory when it is closed:

using (TOpenFileDialog openFileDialog = new TOpenFileDialog()) 
{
   openFileDialog.ShowDialog();
    ...
}   // .NET will release openFileDialog automatically, so we can't forget about it!

Background: forms shown with .ShowDialog are not released from memory, but kept in memory so the caller can call methods after the Form is closed to retrieve parameters. Therefore, you can forget to release the form from memory later.

Class, Interface and Namespace Declarations

For C# classes, interfaces and namespaces, the following formatting rules should be followed:

  • Braces
    • The opening brace "{" appears in the next line after the declaration statement.
    • The closing brace "}" starts a line by itself indented to match its corresponding opening brace.
    • The opening brace "{" and the closing brace "}" should be on the same indentation level as the code block construct that owns it.
  • Spacing
    • A single space character should be placed on each side of the colon that follows the class name.
    • If there is a list of types/interfaces that the class inherits from, the items should be separated by a comma followed by a space character.
  • Code block separation
    • An empty line should preceed and succeed each class, interface or namespace block.
      • Exceptions:
        • if a class, interface or namespace block begins immediately after another class, interface or namespace block has been started with an opening brace "{": then no empty line should be inserted.
        • if a class, interface or namespace block ends and another enclosing code block also ends immediately after the closing brace "}": then no empty line should be inserted.

For example:

namespace MyNamespace
{                                                     // no empty line
    class TMySample : TMyClass, IMyInterface
    {
        void DoSomething()
        {
        
        }
        
        void DoAnotherThing()
        {
        
        }
    }
                                                       // empty line goes here
    class TMyOtherSample : TMySample, IMyOtherInterface
    {
        void DoSomething()
        {
        
        }
        
        void DoAnotherThing()
        {
        
        }
    }                                                  // no empty line
}

For another brace placement example look at section 'Code Examples - Brace placement example'.

Enforced by Uncrustify: all rules

Method Declarations

For method declarations the following formatting rules should be followed:

  • Braces
    • Class braces placement rules should be applied.
  • Spacing
    • No space should be put between a method name and the opening parenthesis "(" that starts its parameter list.
  • Code block separation
    • An empty line should preceed and succeed the statement block (the same applies to other statements that appear as blocks of code).

For example:

                                                       // empty line goes here
public MySample(int AMyInt)
{
    this.FMyInt = AMyInt;
}
                                                       // empty line goes here
void Inc()
{
    ++FMyInt;
}
                                                       // empty line goes here

Enforced by Uncrustify: all rules

Property, Indexer and Event Declarations

For properties, indexers and events, the following formatting rules should be followed:

  • Braces
    • Class braces placement rules should be applied. Enforced by Uncrustify: all rules, except for 'opening curly bracket must be on a new line' (Uncrustify can't enforce that for EventHandlers).
  • Spacing
    • For properties where both 'get' and 'set' blocks are present, an empty line should be placed between the 'get' block and the 'set' block.
    • For event handlers where both 'add' and 'remove' blocks are present, an empty line should be placed between the 'add' block and the 'remove' block.
    • For indexers, use no space between 'this' and '['. Enforced by Uncrustify.
  • Code block separation
    • An empty line should preceed and succeed the statement block (the same applies to other statements that appear as blocks of code).
  • No one-liners
    • Always use braces "{" and "}" on their own code lines even if there is only one statement in the getter/setter or adder/remover!

For example:

                                                       // empty line goes here
public int Amount 
{
    get 
    {
        ...
    }
                                                       // empty line goes here    
    set 
    {
        ... 

    }
}
                                                       // empty line goes here
public EventHandler MyCustomEventHandler
{
    add 
    {
        ...
    }
                                                       // empty line goes here
    remove 
    {
        ...
    }
}
                                                       // empty line goes here
public this[string index]
{
    get;
                                                       // empty line goes here    
    set;
}
                                                       // empty line goes here

Simple Statements

Each code line should contain only one statement.

Return Statements

A return statement should not use outermost parentheses. Enforced by Uncrustify.

GOOD STYLE :

return (n * (n + 1)) / 2;

BAD STYLE - AVOID:

return ((n * (n + 1)) / 2);


Statements With Multiple Conditions

In a situation where more than one condition is specified (eg. in if, for or do-while-statments), please follow these guidelines:

  • Place each condition on a separate line.
  • Place the && and || that connects the conditions on the same line as the next condition. (See example.)
  • If you have a very complicated condition statement, try to align the different conditions. The goal is to make the condition more readable in the end, so you may use your discretion here as well.

Example:

if (((condition1)
     && (condition2)
     || (condition3
         && condition4))
    (&& !condition5))
{
   ...
}

If, if-else, if else-if else Statements

if, if-else and if else-if else statements should follow the following formatting rules:

  • Braces
    • Class braces placement rules should be applied.
  • Spacing
    • A space character should be put between "if" and the opening parenthesis "(".
    • No space character should be put between the opening bracket "(" and the ensuing code statement(s), or between the code statement(s) and the closing bracket ")".
  • Code block separation
    • An empty line should preceed and succeed the statement block (the same applies to other statements that appear as blocks of code).
  • No one-liners
    • Always use braces "{" and "}" on their own code lines even if there is only one statement in the condition!

For example:

                        // empty line goes here
if (condition)
{
    DoSomething();
    ...
}
                        // empty line goes here
if (condition) 
{
    DoSomething();
    ...
} 
else 
{
    DoSomethingOther();
    ...
}
                        // empty line goes here
if (condition)
{
    DoSomething();
    ...
} 
else if (condition)
{
    DoSomethingOther();
    ...
} 
else 
{
    DoSomethingOtherAgain();
    ...
}
                        // empty line goes here

Enforced by Uncrustify: all rules

For / Foreach Statements

For and foreach statements should follow the following formatting rules:

  • Braces
    • Class braces placement rules should be applied.
  • Spacing
    • A space character should be put between "for"/"foreach" and the opening parenthesis "(".
    • No space character should be put between the opening bracket "(" and the ensuing code statement(s), or between the code statement(s) and the closing bracket ")".
    • for only
      • Space characters should be put after the semicolon ";" which separates the initialisation, condition and execution code parts (contained inside the brackets).
      • Inter-term spacing rules should be applied (see 'Inter-term spacing' below).
  • Code block separation
    • An empty line should preceed and succeed the statement block (the same applies to other statements that appear as blocks of code).
  • No one-liners
    • Always use braces "{" and "}" on their own code lines even if there is only one statement in the loop!


For example:

                                                       // empty line goes here
for (int Counter = 0; Counter < 5; ++Counter) 
{
    ...
}
                                                       // empty line goes here
foreach (int MyIterator in IntList) 
{
    ...
}
                                                       // empty line goes here

Enforced by Uncrustify: all rules

While/Do-While Statements

while/do statements should follow the following formatting rules:

  • Braces
    • Class braces placement rules should be applied.
  • Spacing
    • A space character should be put between "while" and the opening parenthesis "(".
    • No space character should be put between the opening bracket "(" and the condition, or between the condition and the closing bracket ")".
  • Code block separation
    • An empty line should preceed and succeed the statement block (the same applies to other statements that appear as blocks of code).
  • No one-liners
    • Always use braces "{" and "}" on their own code lines even if there is only one statement in the loop!

For example:

                                                       // empty line goes here
while (condition)
{
    ...
}
                                                       // empty line goes here

An empty while should have the following form:

while (condition)
{
    ;
}

A do-while statement should have the following form:

                                                       // empty line goes here
do 
{
    ...
} while (condition);
                                                       // empty line goes here

Enforced by Uncrustify: all rules

Switch Statements

A switch statement should follow the following formatting rules:

  • Braces
    • Class braces placement rules should be applied.
  • Spacing
    • A space character should be put between "switch" and the opening parenthesis "(".
    • No space character should be put between the opening bracket "(" and the condition, or between the condition and the closing bracket ")".
  • Code block separation
    • An empty line should preceed and succeed the statement block (the same applies to other statements that appear as blocks of code).
    • An empty line should succeed each 'break;' statement.
      • Exception: no empty line after the 'break;' statement in the 'default' block.
  • Other line breaks:
    • the case x: condition and its ensuing statement(s), as well as the default: line and its statement(s), should be separated by a line break.

For example:

                                                       // empty line goes here
switch (condition)
{
    case A:                                            // line break here
        ...
        break;
                                                       // empty line goes here
    case B:                                            // line break here
        ...
        break;
                                                       // empty line goes here
    default:                                           // line break here
        ...
        break;                                         // NO empty line to follow!
}
                                                       // empty line goes here

Enforced by Uncrustify: all rules

Try-Catch Statements

try-catch statements should follow these formatting rules:

  • Braces
    • Class braces placement rules should be applied.
  • Code block separation
    • An empty line should preceed and succeed the statement block (the same applies to other statements that appear as blocks of code).
  • No one-liners
    • Always use braces "{" and "}" on their own code lines even if there is only one statement in the respective try/except/finally section!

For example:

                                                       // empty line goes here
try 
{
    ...
} 
catch (Exception) 
{
    ...
}
                                                       // empty line goes here

or

                                                       // empty line goes here
try 
{
    ...
} 
catch (ApplicationException ae) 
{
    ...
}
catch (Exception e) 
{
    ...
} 
finally 
{
    ...
}
                                                       // empty line goes here

Enforced by Uncrustify - all rules, except for:

  • 'Code block separation' (Uncrustify can't enforce that);
  • 'Opening curly bracket must be on new line' for the 'finally' statement (Uncrustify's rule to enforce that doesn't work).

White Space

Blank Lines

Blank lines improve readability by setting off blocks of code which are in themselves logically related.

Two blank lines should always be used between:

  • Logical sections of a source file.
  • Class and interface definitions (try one class/interface per file to prevent this case).

One blank line should always be used between:

  • Methods. Enforced by Uncrustify
  • Properties.
  • Code blocks (if statements, for/foreach loops and while loops, switch blocks and try/catch blocks). Enforced by Uncrustify
  • Local variables in a method and the first statement in the method. Enforced by Uncrustify (although not always reliable)
  • Logical sections inside a method to improve readability.

Blank lines should be indented to the correct indent level instead of leaving them blank or, even worse, using another indentation level. This makes the insertion of new statements in these lines much easier.

Inter-term spacing

There should be a single space after a comma or a semicolon.

For example:

TestMethod(a, b, c);                              // don't use : TestMethod(a,b,c)

Single spaces surround operators (except unary operators like increment (++) or logical not (!)).

For example:

a = b;                                            // don't use a=b;

for (int Counter = 0; Counter < 10; ++Counter)    // don't use 'for (int i=0; i<10; ++i)'   
                                                   // or 'for(int i=0;i<10;++i)'

Enforced by Uncrustify: all rules.


Naming Conventions

All names of all code elements must be written in English.

Capitalization Styles

Pascal Casing

This convention capitalises the first character of each word (as in TestCounter).

Camel Casing

This convention capitalises the first character of each word except the first word (as in testCounter).

All-Uppercase

All-uppercase capitalises all characters of a word. Use all-uppercase only for constant identifiers. (For non-constant identifiers that are commonly used in all-uppercase (eg. URL, PI) use Pascal Casing instead.)

Naming Guidelines

Naming according to the guidelines for 'Hungarian Notation' is considered bad practice.

Hungarian Notation is a defined set of prefixes and postfixes which are applied to names to reflect the type of the variable. This style of naming was widely used in early Windows programming, but is now obsolete or at least should be considered deprecated. Using Hungarian Notation is not allowed if you follow this guide.

Remember: a good variable name describes the semantic not the type.

An exception to this rule is GUI code. All fields and variable names that contain GUI elements like Button should be prefixed with their respective GUI control prefix.

For example:

System.Windows.Forms.Button btnCancel;
System.Windows.Forms.TextBox txtName;

Namespace Naming Guidelines

  • Namespace names should be nouns or noun phrases.
  • Use Pascal Casing.
  • Name prefix: none.

Class Naming Guidelines

  • Class names should be nouns or noun phrases.
  • Use Pascal Casing.
  • Name prefix: 'T' (stands for Type).
    • Classes that are derived from System.Windows.Form should use the prefix TFrm instead.

For example:

public class TConnection
{
    ...
}


public class TFrmAboutPetra
{
    ...
}

Interface Naming Guidelines

  • Name interfaces with nouns or noun phrases or adjectives describing behaviour.
  • Use Pascal Casing.
  • Name prefix: 'I' (stands for Interface).

For example:

public interface IComponent
{
    ...
}

Exception Naming Guidelines

  • Name Exceptions with nouns or noun phrases.
  • Use Pascal Casing.
  • Name prefix: 'E' (stands for Exception).
  • Name suffix: 'Exception'. (The suffix is a recommended convention of Microsoft and considered good style by many C# programmers.)

For example:

public class EDBConnectionNotEstablishedException : EOPDBException
{
    ...
}

Enum Naming Guidelines

  • Name
    • Use singular names for enum types. Pascal Casing.
    • Use singular names for enum values. camelCasing.
  • Prefixes
    • Enum type name: 'T'. It is to be followed by a capital letter (first character of the enum name). Enum types should also include the word Enum as a suffix to the name.
    • Enum values: concatenate the letters of each word that make up the enum type name and prefix those in lower case to the enum value.


For example:

public enum TModuleSwitchEnum
{
    msNone, msPartner, msPersonnel, msFinance
}


public enum TUIConnectorTypeEnum
{ 
    uictPartnerKey, uictLocationKey, uictNewPartner
}

Event Names

Event Handlers:

  • Name event handlers with the EventHandler suffix.
  • Name event handlers that have a timeline concept of pre and post using the present and past tense (eg. ...ChangingEventHandler and ...ChangedEventHandler).
  • For generic event handlers use two parameters named sender and e.
  • Use Pascal Casing.
  • Prefix: 'T' followed with a capital letter (first character of the event handler).

Event Arguments:

  • Name event argument classes with the EventArgs suffix.
  • Consider naming events using a verb.
  • Use Pascal Casing.
  • Prefix: 'T' followed with a capital letter (first character of the event argument class).

Property Names

  • Name properties using nouns or noun phrases.
  • Consider naming a property with the same name as it’s Type.
  • Avoid having two property names that are singular and plural in one Class in order to disambiguate them (also if they are of different Types).
    • This good practice helps in preventing the programmer who reads the code from accidentally mixing up those two properties.
    • Example: Rather than declaring two string properties 'FamilyName' and 'FamilyNames', which are different by only one letter, declare a string property 'FamilyName' and 'SeveralFamilyNames', which are more different.
  • Use Pascal Casing.
  • Prefix: none!

Method Names

  • Name methods with verbs or verb phrases.
  • Use Pascal Casing.
  • Prefix: none!

Argument Names

'Arguments' are parameters that are passed to a method. They are used much like private variables of a method.

  • Use accurate and descriptive names that are sufficient to determine the argument's meaning and it’s type.
  • Use Pascal Casing.
  • Prefix: 'A' (stands for Argument) followed by a capital letter (first character of the argument name).

Field Names

'Fields' are private variables of a class.

  • Use accurate and descriptive names that are sufficient to determine the field's meaning and it’s type.
  • Avoid having two field names that are singular and plural in one Class in order to disambiguate them (also if they are of different Types).
    • This good practice helps in preventing the programmer who reads the code from accidentally mixing up those two fields.
    • Example: Rather than declaring two string fields 'FFamilyName' and 'FFamilyNames', which are different by only one letter, declare a string field 'FFamilyName' and 'FSeveralFamilyNames', which are more different.
  • Use Pascal Casing.
  • Prefix: 'F' (stands for Field) followed by a capital letter (first character of the field name).

Variable Names

'Variables' are private variables of a method.

  • Use accurate and descriptive names that should be sufficient to determine the variable's meaning and it’s type.
  • Boolean variables: use prefixes like 'Is...', 'Has...' or 'Can...'. and names that imply true or false. For example: 'FileFound', 'Done', 'Success' or with their prefixes: 'IsFileFound', 'IsDone', 'IsSuccess'; don't try 'IsName' that doesn't make sense at all.
  • Loop counters: use Counter as the standard name for these kinds of variables as they are used in loops to serve as counters, indexes, or the like. Whenever you have a nested loop that also uses a counter, add numbers to the end to indicate the level of the counter.
  • Temporary variables: should be called Tmp. Many times you need to use a variables with no specific meaning - just a quick place-holder or something that will have but a moment of usage. Whenever you need more than one temporary variable in a particular context, you should consider using self-explanatory names for these variables instead.
  • Avoid having two variable names that are singular and plural in one Method in order to disambiguate them (also if they are of different Types). It is also a good practice do this if one method calls another method and the one handles singular and the other one plural instances of something.
    • These good practices help in preventing the programmer who reads the code from accidentally mixing up those two variables.
    • Example: Rather than declaring two string variables 'FamilyName' and 'FamilyNames', which are different by only one letter, declare a string variable 'FamilyName' and 'SeveralFamilyNames', which are more different.
  • Use Pascal Casing.
  • Prefix: none!

Constant Names

  • Name constant fields with nouns, noun phrases or abbreviations for nouns. If they consist of more than one word, separate the words with underscore characters (_).
  • Use ALL-UPPERCASE
  • Prefix: none!

For example:

public class TMath
{
    public const string LONG_CONST_NAME = ...
    public const double PI = 3.14...
    public double Pi = 3.14...                         // this is a variable and not a constant, 
                                                       // so don't use PI
}

Naming and Capitalisation Summary

Type

Prefix

Case

Notes

Namespaces

none

Pascal Casing

Classes / Structs

T

Pascal Casing

Special prefix: TFrm if derived from System.Windows.Form.

Interfaces I

Pascal Casing

Exception Classes

E

Pascal Casing

Suffix: Exception.

Enum Types

T

Pascal Casing

Suffix: Enum

Enum Values

see Notes

Camel Casing

Prefix: Concatenate the letters of each word that make up the enum type name and prefix those in lower case to the enum value.

Event Handlers / Event Arguments

T

Pascal Casing

Suffix for Event Handlers: EventHandler. Suffix for Event Arguments: EventArgs.

Properties

none

Pascal Casing

Methods

none

Pascal Casing

Arguments

A

Pascal Casing

Fields

F

Pascal Casing

Local variables

none

Pascal Casing

Global Variables

G

Pascal Casing

Constants

none

All-Uppercase

Programming Practices

Visibility

Generally

Give a class, interface, event handler, method, field always the least possible visibility. This means that you should consider giving it private visibility, and only if that is not enough increase the visibility - but only as much as is needed.

Fields

Do not make fields public - always make them private. Create properties for fields instead. You may use public static fields (or consts) as an exception to this rule, but be very careful with it.

Having appropriate visibility ensures proper use of classes by every programmer and is kind of 'self-documenting' in the way that it tells how the class can be used.

No 'Magic' Numbers

Do not use 'magic' numbers, i.e. place constant numerical values directly into the source code. Replacing these lateron in case of changes (say, your application can now handle 3540 users instead of the 427 users hardcoded into your code in 50 lines scattered troughout your 25000 lines of code) is error-prone and unproductive. Instead declare a const which contains the number:

public class TMyMath
{
    public const double PI = 3.14159265358979323846264338 // As a double, will only store to 15 significant digits
}

SQL Queries

All SQL keywords should be in capital letters.

The main query command keyword (e.g. SELECT, UPDATE, INSERT, etc.) should be on the indentation base, and the rest of the text belonging to that query should be indented.

Indentation for SQL queries should be four spaces (like for the rest of the source code).

If the list of columns or tables become to long, it should be split over more than one line. If this is done, the lists should be aligned.

Every keyword that signifies a new 'section' of the query should be on a new line, with everything belonging to that section indented. (See example.)

The keywords AND and OR should also be on a new line, and indented. It is also recommended to try and align the conditions. To do this, simply add a few spaces after the AND and OR keywords until the condition is aligned to the one in the previous line.


Cumulative examples:

  SELECT a_column_1_i, a_column_2_l,
         a_column_3_i, a_column_4_n
    FROM  a_table
    WHERE a_column_1_i > 5
      AND a_column_2_l = TRUE
      OR  a_column_4_n = 10
    ORDER BY a_column_3_i;

  SELECT surname, forenames
    FROM  employee
    WHERE depno =
          (SELECT depno
            FROM  employee
            WHERE empno = 16)
      AND empno != 16

  DELETE FROM a_whatever
    WHERE mmm
      AND mmm
      OR  mmm

  UPDATE a_whatever
    SET (mm1 = 'khasg kvjshdfbv jszhdvb kszjhvb ksjvhb asj,f abv,jfhv badfj',
         mm2 = (SELECT id
                  FROM  something
                  WHERE something else)
         mm3, mm4)
    WHERE mmm
      AND mmm;


Table aliases can be named by using the first letter of every word in the table name (excluding unnecessary things like prefixes). If the same table is used twice in the query with two aliases, simply add a number at the end of the alias name to distinguish them, or name them in such a way as to separate them logically.

Never use SELECT * for a query in Petra! This can cause a lot of data transfer! By not using it you can prevent errors, and also make life much easier for things like Typed DataSets.

Use Discretion!

These standards were set up to help us as programmers to better maintain the code. Please try to comply to these standards.

We realise that there are times when the standards would actually have a negative effect, or maybe where the standards are not entirely clear. In these situations, please use your discretion to come up with a suitable alternative, and discuss it with the rest of the team before you use it.


Code Examples

Brace placement example

namespace ShowMeTheBracket
{
    public enum TTheTestEnum
    {
        ttOne, ttTwo
    }

	
    public class TTestMeClass
    {
        TTheTestEnum FTestVar;

		
        public TTheTestEnum Test 
        {
            get 
            {
                return FTestVar;
            }
            
            set 
            {
                FTestVar = value;
            }
        }

		
        void DoSomething()
        {
            if (FTestVar == TTestEnum.ttOne) 
            {
                //...stuff gets done
            } 
            else 
            {
                //...other stuff gets done
            }
        }
    }
}

Variable naming example

Instead of:

for (int i = 1; i < num; ++i) 
{
    meetsCriteria[i] = true; 
}


for (int i = 2; i < num / 2; ++i) 
{
    int j = i + i;
	

    while (j <= num) 
    {
        meetsCriteria[j] = false;
        j += i;
    }
}


for (int i = 0; i < num; ++i) 
{
    if (meetsCriteria[i]) 
    {
        Console.WriteLine(i + " meets criteria");
    }
}


...do name variables appropriately:

for (int Counter1 = 1; Counter1 < num; ++Counter1) 
{
    isPrime[Counter1] = true; 
}


for (int Counter2 = 2; Counter2 < num / 2; ++Counter2) 
{
    int factorableNumber = Counter2 + Counter2;

	
    while (factorableNumber <= num) 
    {
        isPrime[factorableNumber] = false;
        factorableNumber += Counter2;
    }
}


for (int Counter3 = 0; Counter3 < num; ++Counter3) 
{
    if (isPrime[Counter3]) 
    {
        Console.WriteLine(Counter3 + " is prime.");
    }
}

Note: indexer variables should generally be called Counter1, Counter2, etc. But in cases like this where it isn't quickly obvious what is going on with those loops, it may make sense to reconsider this rule: for instance, Counter1 and Counter3 could be renamed to PrimeCandidate, and Counter2 to Factor to make the code more 'self-documenting'.