TeamF::CGTMain Page | About | Help | FAQ | Special pages | Log in

Category: Documentation

Implementation Practices and Standards

From TeamF::CGT

Revision: 3229

Contents

Abstract


This document requires or recommends certain practices and standards for developing the Corporate Governace Toolkit (CGT) software system using Visual C# 2.0, ASP.NET 2.0 and related technologies.

Introduction


Objective

The objective of this practices and standards document is:

The document, however, does not aim to constrain on every aspect of coding habits. Instead, only those of higher importance are documented.

Scope

This document mainly focuses on the C# Language. It also mentions related .NET technologies that are deemed necessary or useful to the project. Although the C# language is implemented alongside the .NET Framework, this document does not address usage of .NET Framework class libraries. However, common patterns and problems related to C#'s usage of the .NET Framework are addressed in a limited fashion.

Audience

This document is supposed to be used by:

However, since each team member is required to be involved in at least implementation or testing, the audience of the document is the whole team.

Terminology and Definitions

Term Definition Examples
Access Modifier

A class-member-declaration can have any one of the five possible kinds of declared accessibility: public, protected internal, protected, internal, or private. Except for the protected internal combination, it is a compile-time error to specify more than one access modifier. Although default access modifiers vary, classes and most other members use the default of private. Notable exceptions are interfaces and enums which both default to public.

Identifier

A developer defined token used to uniquely name a declared object or object instance.

Magic Number Any numeric literal used within an expression (or to initialize a variable) that does not have an obvious or well-known meaning. This usually excludes the integers 0 or 1 and any other numeric equivalent precision that evaluates as zero.
Hungarian Notation

A variable name starts with one or more lower-case letters which are mnemonics for the type or purpose of that variable, followed by whatever the name the programmer has chosen; this last part is sometimes distinguished as the given name. The first character of the given name is capitalized to separate it from the type indicators.

lblSampleLabel
txtTextField
Camel Case A word with the first letter lowercase, and the first letter of each subsequent word-part capitalized.
loopCounter
Pascal Case A word with the first letter capitalized, and the first letter of each subsequent word-part capitalized.
LoopCounter

References

  1. C# Language Specification 1.2
  2. C# Language Specification 2.0, March 2005 Draft
  3. Design Guidelines for Class Library Developers
  4. Coding Standard: C# - Philips Medical Systems - Software / SPI
  5. C# Coding Standards for .NET

Development Guidelines


Development Methodology

The implementation team employs a pair-programming-by-request strategy, i.e., pair programming in its strict sense is neither encouraged nor discouraged. Instead, the choice of whether or not pair programming is conducted by a sub-team of developers who are dedicated to a particular build task is left to the developers themselves. One or more of the developers can pair up voluntarily or request to the manager to be paired up.

The decision of whether pair programming should be adopted needs to take the following into consideration:

Nevertheless, working in pairs is strongly encouraged, especially in the following two situations:

Even though pair programming is not enforced nor encouraged, we recognise the benefits of having two developers working closely together towards a particular goal, especially when there is a general lack of expertise in a particular field. As a result, implementation task allocation will be based on the interest and skill survey that each developer has filled in early on. The management team will try to match up those with plenty of experience with those who are really interested in the field, so that hopefully there will be a lot of learning and pushing going on in the sub-team.

Code Inspection

Code inspection, just like coding itself, is to be done on a rotational basis. Team members currently free from any implementation or testing duties are candidates for conducting a code inspection.

Code inspection should happen on a weekly basis, or as soon as a build is finished, or when a milestone has been reached.

Code inspection should mainly focus on coding styles and legibility of code and comments, although the inspector is also welcome to point out any likely logical errors that have not been detected by unit test cases.

The inspection report should be mainly checklist based. At the end of the inspection, the inspector is expected to produce a checklist report and also needs to make sure all his findings are conveyed to the responsible developers and/or implementation team manager.

The inspection report will at least need to include the following items:

  1. Compilation errors / Obvious bugs
  2. Code Styles
  3. Documentation / Code legibility
    1. XML documentation comments
    2. Normal comments
  4. Other recommendations

For each item, the following may need to be specified:

The inspectors need to fully understand this standards document before assessing the quality of the target code, and show references to this document wherever applicable in the inspection report.

C# Coding Standards


Source File Organization

Class and Source File

Normally, one class definition goes into one source file only. Said differently, each class definition will exist within its own file. With partial classes in .NET Framework 2.0, however, one class may consist of several partial classes that reside in different files.

In either cases, two different classes should not be put into one file, and the stem of the file name must be the same name as the name used in the class declaration. Examples are:

Ordering

C# source files have the following ordering:

  1. using statements
  2. namespace statement
  3. class and interface declarations

XML Documentation

XML documentation is provided for descriptions of classes, properties and methods. XML documentation should be used wherever it is applicable.

Refer to Documentation Comments for more information.

Class and Interface Declaration

Sequence Part of Class/Interface Declaration Notes
1 Class/interface documentation
/// <summary>
/// The Sample class provides ...
/// </summary>
public class Sample
2 class or interface statement
3 Fields First private, then protected, then internal, and then public.
4 Properties First private, then protected, then internal, and then public.
5 Constructors First private, then protected, then internal, and then public. Default first, then order in increasing complexity.
6 Methods Methods should be grouped by functionality rather than by scope or accessibility. For example, a private class method can be in between two public instance methods. The goal is to make reading and understanding the code easier.

Formatting

Document Formatting in Visual Studio 2005

Automatic document formatting functionality is very useful when it comes to enforcing consistent code format in Visual Studio 2005. A tentative settings file for Visual Studio 2005 can be accessed from STANDARDS-vs2005settings.vssettings and can be imported to individual installations.

General Rules

Rule Preferred Style Bad Style
Indent block contents
class MyClass
{
  int Method()
  {
    return 3;
  }
}
class MyClass
{
  int Method()
  {
  return 3;
  }
}
Indent case labels
switch (name)
{
  case "John":
    break;
}
switch (name)
{
case "John":
  break;
}
Indent case contents
switch (name)
{
  case "John":
    break;
}
switch (name)
{
  case "John":
  break;
}
Place open brace on new line for types
class MyClass
{
  ...
}
class MyClass {
  ...
}
Place open brace on new line for methods
int Method()
{
  ...
}
int Method() {
  ...
}
Place open brace on new line for control blocks (if, while, for, foreach, etc.)
if (a > b)
{
  ...
}
if (a > b) {
  ...
}
Place else on new line
if (a > b)
{
  ...
}
else
{
  ...
}
if (a > b)
{
  ...
} else
{
  ...
}
Place catch on new line
try
{
  ...
}
catch (Exception e)
{
  ...
}
try
{
  ...
} catch (Exception e)
{
  ...
}
Place finally on new line
try
{
  ...
}
finally
{
  ...
}
try
{
  ...
} finally
{
  ...
}
Insert space before and after binary operators (+, -, etc.)
int result = 1 + 2 * 3;
int result = 1+2*3;
int result = 1 + 2*3;
Methods are separated by two blank lines
int Method1()
{
  ...
}

int Method2()
{
  ...
}
int Method1()
{
  ...
}
int Method2()
{
  ...
}
Each line should contain only one member declaration
private int a;
private int b;
private int a, b;
Each line should contain only one statement
size++;
count--;
size++; count--;

Indentation

Indentation is constructed with spaces rather than tabs. 2 spaces are used in place of a tab.

Visual Studio editors and formatters should be configured to insert spaces with a width of 2 characters for each tab typed in.

Line Length

80 characters per line is recommended, although it is not a hard rule. If a line of code becomes too long, consider breaking it down into several statements.

Wrapping Lines

When an expression will not fit on a single line, break it according to these general principles:

Examples are:

Preferred Style Bad Style
longMethodCall(expr1, expr2,
               expr3, expr4, expr5);
longMethodCall(expr1, expr2
               , expr3, expr4, expr5);
var = a * b / (c - g + f) +
      4 * z;
var = a * b / (c - g +
      f) + 4 * z;

Commenting

Types of Comments

C# programs can have two kinds of comments: implementation comments and documentation comments.

For implementation comments, use // but never /* ... */.

Documentation comments are C# only, and are delimited by special XML tags that can be extracted to external files for use in system documentation. This type of comments is discussed in detail in a later section.

General Rules

Implementation comments are meant for commenting out code or for comments about the particular implementation. Documentation comments are meant to describe the specification of the code, from an implementation-free perspective, to be read by developers who might not necessarily have the source code at hand.

Some general rules and recommendations for code commenting are:

Documentation Comments

In source code files, lines that begin with /// and that precede a user-defined type such as a class, delegate, or interface; a member such as a field, event, property, or method; or a namespace declaration can be processed as comments and placed in a file.

XML documentation is required for classes, delegates, interfaces, events, methods, and properties. Include XML documentation for fields that are not immediately obvious. Document comments must not be positioned inside a method or constructor definition block, because C# associates documentation comments with the first declaration after the comment.

The documentation must be well-formed XML, and developers are not free to create their own set of tags. The available and commonly used XML documentation tags are:

Tag Notes
<c> The <c> tag gives you a way to indicate that text within a description should be marked as code. Use to indicate multiple lines as code.
<code> The <code> tag gives you a way to indicate multiple lines as code. Use <c> to indicate single line as code.
<example> The <example> tag lets you specify an example of how to use a method or other library member. Commonly, this would involve use of the <code> tag.
<exception> The <exception> tag lets you document an exception class.

Compiler verifies syntax.

<include> The <include> tag lets you refer to comments in another file that describe the types and members in your source code. This is an alternative to placing documentation comments directly in your source code file.

The <include> tag uses the XML XPath syntax. Compiler verifies syntax.

<list> The <listheader> block is used to define the heading row of either a table or definition list. When defining a table, you only need to supply an entry for term in the heading.

Each item in the list is specified with an <item> block. When creating a definition list, you will need to specify both term and text. However, for a table, bulleted list, or numbered list, you only need to supply an entry for text.

A list or table can have as many <item> blocks as needed.

<para> The <para> tag is for use inside a tag, such as <remarks> or <returns>, and lets you add structure to the text.
<param> The <param> tag should be used in the comment for a method declaration to describe one of the parameters for the method.

Compiler verifies syntax.

The <paramref> tag gives you a way to indicate that a word is a parameter. The XML file can be processed to format this parameter in some distinct way.

Compiler verifies syntax.

<permission> The <permission> tag lets you document the access of a member. The System.Security.PermissionSet lets you specify access to a member.
<remarks> The <remarks> tag is where you can specify overview information about a class or other type. <summary> is where you can describe the members of the type.
<returns> The <returns> tag should be used in the comment for a method declaration to describe the return value.
<see> The <see> tag lets you specify a link from within text. Use <seealso> to indicate text that you might want to appear in a See Also section.

Compiler verifies syntax.

<seealso> The <seealso> tag lets you specify the text that you might want to appear in a See Also section. Use <see> to specify a link from within text.
<summary> The <summary> tag should be used to describe a member for a type. Use <remarks> to supply information about the type itself.

The <summary> tag is used by IntelliSense inside Visual Studio to display additional information about a type or member.

<value> The <value> tag lets you describe a property.

Refer to Documentation Comments Sample Code for more information.

Comment Tokens

There are three special comment tokens, namely TODO, HACK and UNDONE.

When you add comments with comment tokens to your code, you automatically add shortcuts to the Task List window (under "Comments"). Double-click any comment displayed in the Task List to move the insertion point directly to the line of code where the comment begins. Note: Comments in HTML, CSS and XML markup are not displayed in the Task List.

Frequent while appropriate use of comment tokens are highly recommended during development.

Example use of comment tokens is as follows:

// TODO: Fix this method.
// UNDONE: Need input from someone else.
// HACK: This method works but needs to be redesigned.

Declarations

One Declaration Per Line

There should only be one declaration per line.

Preferred Style Bad Style
private int level = 2;
private int size = 8;
private int level = 2, size = 8;

Initialization

If possible, try to initialise local variables as soon as they are declared. For example:

Preferred Style
string name = myObject.Name;

Placement

Generally, don't declare a variable until its first use, especially in for or foreach loops. Examples are:

Preferred Style
for (int i = 0; i < riskTable.Rows.Count; ++i)
{
  // do something
}
foreach (DataRow riskRow in riskTable.Rows)
{
  // do something
}

Naming Conventions

General Rules

Namespaces

Rule Preferred Style Bad Style

Namespaces must be of the format RiskWizard.Cgt.{CustomName}.

RiskWizard.Cgt.Configuration
RiskWizard.Configuration

Namespace names should be nouns, in Pascal case. Do NOT use underscores in namespace names.

RiskWizard.Cgt.DataAccess
riskwizard.cgt.configuration
RiskWizard.Cgt.Data_Access

Classes

Rule Preferred Style Bad Style

Class names should be nouns, in Pascal case.

TreeControl
treeControl

Use whole words and avoid acronyms and abbreviations unless the abbreviation is much more widely used than the long form.

Url
Html
XmlWriter
XmlConf
TreeVw

Generic Classes

Rule Preferred Style Bad Style

Generic class names should always use "T" or "K" as Type identifier, or identifier prefix followed by a number as in T1, T2.

GenericList<T>
Generic3DView<T1, T2, T3>
GenericList<A>
Generic3DView<X, Y, Z>

Exception Classes

Rule Preferred Style Bad Style

Exception class names should always have the suffix "Exception".

CorruptConfigurationException
CorruptConfiguration
CorruptConfigurationError

Interfaces

Rule Preferred Style Bad Style

Interface names should begin with the letter "I".

IConnectionProxy
ConnectionProxy

Interface names should be nouns, in Pascal case.

ITreeView
IViewTree

Methods

Rule Preferred Style Bad Style

Method identifiers should contain active verbs or verb phrases, in Pascal case.

Connect()
CreateTable()
connect()
TableCreator()

Generally, do NOT include the noun name when the active verb refers directly to the containing class.

Socket.Open();
Socket.OpenSocket();

Avoid elusive names that are open to subjective interpretation.

Analyze()

Use the verb-noun form for naming methods that perform some operation on a given object.

CalculateInvoiceTotal()

All overloaded methods with the same name should perform a similar function.

Variables

Rule Preferred Style Bad Style

Variable names should be in camel case.

tableWidth
TableWidth

Do NOT use any special prefix characters to indicate that the variable is scoped to the class. Always use the this keyword when referring to members at a class's root scope from within a lower level scope.

this.name
_name
m_name

Do NOT use Hungarian notation for variable names. Good names describe semantics, not type.

cancelButton
btnCancel

Prepend computation qualifiers (avg, sum, min, max, index) to the beginning of a variable name where appropriate.

avgRiskImpact
riskImpact

It is redundant to include class names in the names of class properties.

Book.Title
Book.BookTitle

Collections should be named as the plural form of the singular objects that the collection contains.

A collection of Book objects is named Books.

Boolean variable names should contain "Is" or "is" which implies Yes/No or True/False values.

isFound
isSuccess
found
success

Avoid using terms such as Flag when naming status variables, which differ from Boolean variables in that they may have more than two possible values.

orderFlag
orderStatus

Even for a short-lived variable that may appear in only a few lines of code, still use a meaningful name. Use single-letter variable names such as i or j only for short-loop indexes.

Constants should NOT be all uppercase with underscores between words. Constants follow the same naming rules as properties.

NumDaysInWeek
NUM_DAYS_IN_WEEK

Temporary variables should always be used for one purpose only. Otherwise, several variables should be declared.

Properties

Rule Preferred Style Bad Style

Property names should be in Pascal case.

public int RiskId
public string lastName

Property names should directly reflect the underlying attribute.

private string firstName;

public string FirstName
{
  set
  {
    firstName = value;
  }
}
private int riskImpact;

public string Impact
{
  get
  {
    return riskImpact;
  }
}

Objects References

Rule Preferred Style Bad Style

Objects references should be in camel case when non-public and Pascal case when public (although references should never be public without any good reason).

Risk risk = new Risk();

public string Name;
public string name;

Generally, objects should be named after their class. An exception to this rule would be when two or more objects of the same class are needed within the same scope.

XmlWriter xmlWriter = new XmlWriter();

...
{
  Employee eric = new Employee("Huang", "Eric");
  Employee sieming = new Employee("Huang", "Sie Ming");
}
...
XmlWriter output = new XmlWriter();

Avoid naming object references as abbreviations or acronyms of the class name.

XmlWriter writer = new XmlWriter();

Constants

Rule Preferred Style Bad Style

Constants are in Pascal case. They should NOT be all uppercase with words separated by underscores.

const int NumDaysInWeek = 5;
const int NUM_DAYS_IN_WEEK = 5;

Enum

Rule Preferred Style Bad Style

Enum types and values should be in Pascal case.

enum Status
{
  Blocked, ReadyToRun, Running
};
enum status
{
  blocked, readyToRun, running
};

Do NOT use an Enum suffix on Enum type names.

enum Status
enum StatusEnum

Generally, use a singular name for most Enum types.

enum RiskType
enum RiskTypes

Data

Rule Preferred Style Bad Style

When naming tables, express the name in the singular form.

Employee
Employees

When naming columns of tables, do not repeat the table name.

LastName in table Employee

EmployeeLastName in table Employee

Do NOT incorporate the data type in the name of a column. This will reduce the amount of work needed should it become necessary to change the data type later.

Impact
ImpactDecimal

Do NOT prefix stored procedures with sp_, because this prefix is reserved for identifying system-stored procedures.

Abbreviations

Rule Preferred Style Bad Style

When using acronyms, use camel case for acronyms more than two characters long. However, acronyms that consist of only two characters should be capitalised.

HtmlButton
System.IO
HTMLButton
System.Io

Do not use abbreviations in identifiers or parameter names.

GetWindow
GetWin

Do not use acronyms that are not generally accepted in the computing field.

Capitalisation Summary

Type Case Notes

Project File

Pascal Case

Source File

Pascal Case

Other File

Pascal Case

Namespace

Pascal Case

Class/Struct

Pascal Case

Interface

Pascal Case

Starts with I

Generic class

Pascal Case

Use T or K as Type identifier

Exception class

Pascal Case

Ends with Exception

Enum value

Pascal Case

Delegate

Pascal Case

Event

Pascal Case

public/protected field

Pascal Case

Method

Pascal Case

Property

Pascal Case

private field

Camel Case

Parameter

Camel Case

Inline Variable

Camel Case

Programming Practices


Visibility and Access Control

Classes and most other members use the default of private. Interfaces and enums both default to public.

However, do NOT omit access modifiers. Explicitly declare all identifiers with the appropriate access modifier instead of allowing the default.

Do NOT make any instance or class variable public or protected, leave them as private.

Use properties instead. You may use public static or const fields as an exception to this rule, but it should better be avoided.

Object Model

Always prefer composition over inheritance.

Always prefer interfaces over abstract classes.

Try to append the design pattern name to class names where appropriate.

Make members virtual if they are designed and tested for extensibility.

Do NOT ever seal a class. sealed classes cannot be extended by others while the decision as to whether to seal a class or not is often too subjective to foresee future needs. Often, the only reason for sealing a class is library security. However, it does not apply to this project, where extensibility is one of the top priorities.

Overriding

Consider overriding Equals() on a struct.

Always override the Equality Operator (==) when overriding the Equals() method.

Always override the String Implicit Operator when overriding the ToString() method.

Destructors and Finalizers

Generally, do NOT use finalizers. Use destructors instead. Do NOT create Finalize() method. Examples are:

Preferred Style Bad Style
~SampleClass()
{
  ...
}
void Finalizer()
{
  ...
}

Always call Close() or Dispose() on classes that offer it.

Wrap instantiation of IDisposable objects with a "using" statement to ensure that Dispose() is automatically called. For example:

Preferred Style
using (SqlConnection sqlConnection = new SqlConnection(this.connectionString))
{
  ...
}

Always implement the IDisposable interface and pattern on classes referencing external resources. For example:

Preferred Style
public void Dispose()
{
  Dispose(true);
  GC.SuppressFinalize(this);
}

protected virtual void Dispose(bool disposing)
{
  if (disposing)
  {
    // Free managed objects
  }
  // Free unmanaged objects, i.e., your own state
  // Set large fields to null
}

// C# finalizer (optional)
~Base()
{
  Dispose(false);
}

Literals

Do NOT use magic numbers, i.e., place constant numerical values directly into the source code. The only exception is -1, 0 or 1, which can appear in a for loop as counter values.

Variable Assignments

Avoid assigning several variables to the same value in a single statement. For example, do NOT use:

Bad Style
oldRisk.Impact = newRisk.Impact = impact;

Do not use embedded assignments in an attempt to improve run-time performance. This is redundant. For example, do NOT use:

Bad Style
d = (a = b + c) + r;

Parameters

Check the validity of parameter arguments. Perform argument validation for every public or protected method and property set accessor. Throw meaningful exceptions to the developer for invalid parameter arguments. Use specific subclasses of the System.ArgumentException class, or a class derived from System.Exception.

Avoid declaring methods with more than 7 parameters. Refactor or consider passing a struct or class instead.

Exceptions

Exception Throwing

Consider terminating the process by calling System.Environment.FailFast(System.String) (a .NET Framework version 2.0 feature) instead of throwing an exception, if your code encounters a situation where it is unsafe to continue executing.

Do not use exceptions for normal flow of control, if possible. Except for system failures and operations with potential race conditions, framework designers should design APIs so that users can write code that does not throw exceptions. For example, you can provide a way to check preconditions before calling a member so that users can write code that does not throw exceptions.

Do document all exceptions thrown by publicly callable members because of a violation of the member contract (rather than a system failure) and treat them as part of your contract. Exceptions that are a part of the contract should not change from one version to the next.

Do not have public members that return exceptions as the return value or as an out parameter. It is acceptable to use a private helper method to construct and initialize exceptions.

Consider using exception builder methods. It is common to throw the same exception from different places. To avoid code bloat, use helper methods that create exceptions and initialize their properties.

Avoid explicitly throwing exceptions from finally blocks. Implicitly thrown exceptions resulting from calling methods that throw are acceptable.

Consider throwing existing exceptions residing in the System namespaces instead of creating custom exception types.

Do create and throw custom exceptions if you have an error condition that can be programmatically handled in a different way than any other existing exceptions. Otherwise, throw one of the existing exceptions.

Do throw the most specific (the most derived) exception that is appropriate. For example, if a method receives a null argument, it should throw System.ArgumentNullException instead of its base type System.ArgumentException.

Do not throw System.Exception or System.SystemException. Do not catch System.Exception or System.SystemException in framework code, unless you intend to re-throw. Avoid catching System.Exception or System.SystemException, except in top-level exception handlers.

Do use value for the name of the implicit value parameter of property setters.

Do not allow publicly callable APIs to explicitly or implicitly throw System.NullReferenceException, System.AccessViolationException, System.InvalidCastException, or System.IndexOutOfRangeException. Do argument checking to avoid throwing these exceptions. Throwing these exceptions exposes implementation details of your method that may change over time.

Do not explicitly throw System.StackOverflowException. This exception should be explicitly thrown only by the common language runtime (CLR). Do not catch System.StackOverflowException.

Do not explicitly throw System.OutOfMemoryException. This exception should be thrown only by the CLR infrastructure.

Exception Handling

Do not swallow errors by catching non-specific exceptions, such as System.Exception, System.SystemException, and so on, in framework code.

Avoid swallowing errors by catching non-specific exceptions, such as System.Exception, System.SystemException, and so on, in application code. There are cases when swallowing errors in applications is acceptable, but such cases are rare.

Do not exclude any special exceptions when catching for the purpose of transferring exceptions.

Consider catching specific exceptions when you understand why it will be thrown in a given context.

Do not overuse catch. Exceptions should often be allowed to propagate up the call stack.

Do use try-finally and avoid using try-catch for cleanup code. In well-written exception code, try-finally is far more common than try-catch.

Do prefer using an empty throw when catching and re-throwing an exception. This is the best way to preserve the exception call stack.

Custom Exceptions

Avoid deep exception hierarchies.

Do derive exceptions from System.Exception or one of the other common base exceptions.

Do end exception class names with the Exception suffix.

Do make exceptions serializable. An exception must be serializable to work correctly across application domain and remoting boundaries.

Do provide (at least) the following common constructors on all exceptions. Make sure the names and types of the parameters are the same as those used in the following code example.

public class NewException : BaseException, ISerializable
{
  public NewException()
  {
    // Add implementation.
  }
  public NewException(string message)
  {
    // Add implementation.
  }
  public NewException(string message, Exception inner)
  {
    // Add implementation.
  }

  // This constructor is needed for serialization.
  protected NewException(SerializationInfo info, StreamingContext context)
  {
    // Add implementation.
  }
}

Do report security-sensitive information through an override of System.Object.ToString only after demanding an appropriate permission. If the permission demand fails, return a string that does not include the security-sensitive information.

Do store useful security-sensitive information in private exception state. Ensure that only trusted code can get the information.

Consider providing exception properties for programmatic access to extra information (besides the message string) relevant to the exception.

Returning Values

Try to make the structure of your program match the intent. For example:

Preferred Style Bad Style
return condition;
if (condition)
{
  return true;
}
else
{
  return false;
}
return (condition ? x : y);
if (condition)
{
  return x;
}
return y;

Avoid Excessive Nesting Using Guard Clause

Nesting happens when one control structure exists within another control structure, and possibly even another control structure. When reading code that resides within many nested blocks, the programmer must maintain an awareness of the pre-conditions that lead to the code being executed. Nesting becomes increasingly more ambiguous near the end of the control structures.

Using the complement of the conditional expression leads to an early resolution of control structures and a flattening of the nesting. For example:

Preferred Style Bad Style
public SampleMethod()
{
  for (int i = 1, i < 100, i++)
  {
    // Guard
    if (i <= 10)
    {
      continue;
    }

    ...
    if (someVariable == someNumber)
    {
      ...
    }
  }
}
public SampleMethod()
{
  for (int i = 1, i < 100, i++)
  {
    if (i > 10)
    {
      ...
      if (someVariable == someNumber)
      {
        ...
      }
    }
  }
}

Parentheses

Use parentheses liberally in expressions involving mixed operators to avoid operator precedence problems or understanding problems for other programmers.

Regions

Be careful about using #region directive. #region should be used for providing useful grouping of code rather than hiding unstructured code.

If you are using #region to group a part of code, it is probably too big, and may be a candidate for refactoring. If you hide the code in a region it defeats the purpose of encouraging others to refactor your code later on.

Refactoring

Refactoring is a technique to restructure code in a disciplined way. Refactoring follows a set of rules. These rules are named and published in a catalog in a similar fashion to Design Patterns.

Refactoring is not only a way to repair old code, or to make existing code more flexible, but it is also a way to write new code based on a system of best practices. Not all refactorings are useful at the outset, but many are, and knowledge of the techniques is invaluable.

Refer to the online version of the refactoring catalog at http://www.refactoring.com/catalog/index.html.

Visual Studio 2005 natively provides a number of refactoring options, which are beyond the scope of this document.

Appendix

Documentation Comments Sample Code

// XmlSample.cs
using System;

/// <summary>
/// Class level summary documentation goes here.
/// </summary>
/// <remarks>
/// Longer comments can be associated with a type or member
/// through the remarks tag.
/// </remarks>
public class SomeClass
{
  /// <summary>
  /// Store for the name property.
  /// </summary>
  private string name;

  /// <summary>
  /// Name property.
  /// </summary>
  /// <value>
  /// A value tag is used to describe the property value.
  /// </value>
  public string Name
  {
    get
    {
      if (this.name == null)
      {
        throw new Exception("Name is null");
      }
      return myName;
    }
  }

  /// <summary>
  /// The class constructor.
  /// </summary>
  public SomeClass()
  {
    // TODO: Add Constructor Logic here
  }

  /// <summary>
  /// Description for SomeMethod.
  /// </summary>
  /// <param name="s">Parameter description for s goes here.</param>
  /// <seealso cref="String">
  /// You can use the cref attribute on any tag to reference a type
  /// or member and the compiler will check that the reference exists.
  /// </seealso>
  public void SomeMethod(string s) {}

  /// <summary>
  /// Some other method.
  /// </summary>
  /// <returns>
  /// Return results are described through the returns tag.
  /// </returns>
  /// <seealso cref="SomeMethod(string)">
  /// Notice the use of the cref attribute to reference a specific method.
  /// </seealso>
  public int SomeOtherMethod()
  {
    return 0;
  }

  /// <summary>
  /// The entry point for the application.
  /// </summary>
  /// <param name="args">A list of command line arguments.</param>
  public static int Main(String[] args)
  {
    // TODO: Add code to start application here
    return 0;
  }
}

Retrieved from "http://www.erichuang.info/projects/cgt/wiki/index.php?title=Implementation_Practices_and_Standards"

This page has been accessed 1,569 times.
This page was last modified 07:21, 18 August 2006.
Content is available under Attribution-NonCommercial-ShareAlike 2.5.


Find
Browse
Main Page
Current events
Recent changes
Help
Edit
Edit this page
Editing help
This page
Discuss this page
Post a comment
Printable version
Context
Page history
What links here
Related changes
My pages
Log in / create account
Special pages
New pages
File list
Statistics
Bug reports
More...