Sunday, October 17, 2010

Coding Style

Revision number: 13

Status: release


Revision History


Date

Revision

Description

30.05.2001

1

Draft version compiled from multiple sources

30.05.2001

13

Added some corrections

31.05.2001

20

Added some corrections

31.05.2001

21

Merged modifications, release version

31.05.2001

22

Minor modifications

07.06.2001

27

Maximum line length increased

07.09.2002

50

Updated for Microsoft.NET

05.12.2002

80

Changes based on vast experience with coding in VS.NET.

10.04.2006


Added SQL Code and RDBMS objects naming requirements


Table of contents


1. Introduction

1.1. Purpose

1.2. Scope

2. General principles

3. C# Code

3.1. Formatting

3.1.1. Spacing

3.1.2. Maximum line length

3.1.3. Indentation

3.1.4. Methods

3.1.5. Cycles

3.1.6. If statement

3.1.7. Switch statement

3.2. Commenting

3.2.1. Beginning of file

3.2.2. Classes

3.2.3. Methods

3.2.4. Code

3.2.5. Temporary comments

3.3. Naming

3.3.1. Variables

3.3.2. Constant names

3.3.3. Method names

3.3.4. File names

3.4. Contract based programming

3.5. Notes in code

3.6. Use regions

3.7. QA

3.8. Example

4. SQL Code and RDBMS Objects

4.1. Naming

4.1.1. Tables

4.1.2. Views

4.1.3. Functions

4.1.4. Stored procedures

4.1.5. Indexes

5. OLAP Objects

5.1. Cubes

5.2. Dimensions

6. Security Considerations

7. VS.NET 2005 settings

8. References

1. Introduction

1.1. Purpose

The purpose of this document is to describe and set single programming style. This document is addition to guidelines described in Microsoft's Design Guidelines for Class Library Developers.

1.2. Scope

This document is applicable to any code written.

2. General principles

Good visual layout shows logical structure of the program. All following guidelines follow this rule. Developers should follow this rule in all cases not covered below.

Also developers should follow Microsoft Visual Studio.NET C# editor predefined coding style recommendations.

3. C# Code

3.1. Formatting

3.1.1. Spacing

Use spaces to increase readability:

rawCount = getRawCount( dataSet ) + 1;

Don’t insert space between empty parentheses:

connection = getConnection();

Put space line between blocks of code. Code blocks longer then ~15 lines are not allowed.

//create handler parameters string

string parameters = "";

for( int i = 0; i < handlerArguments.Length(); i++ )

{

if ( parameters != "" )

...

}



int eventResult = null; //result of the event



// call all system handlers registered for this event (registered for event name,

// they don't care about object)

if ( this.eventList.Exists( eventName ) )

{

...

Array indexes: a[ 1 ]


Empty lines between functions: 2 lines and comment header

3.1.2. Maximum line length

Wrap lines if their length exceeds ~100 characters.

Incorrect:

if (value != null && value != string.Empty)

{

checkCorrection = (Regex.Match(value, "\\s*(\\s*\\w+\\s*(as\\s*\\w+){0,1}\\s*,)*\\s*\\w+\\s*(as\\s*\\w").Captures.Count == 1) || (Regex.Match(value,"\\s*\\*\\s*").Captures.Count == 1);

Debug.Assert(checkCorrection, " Trying to set incorrect SelectFields value in SQLQueryBuilder!");

}

Correct:

if ( value != null && value != string.Empty )

{

string regExp1 = "\\s*(\\s*\\w+\\s*(as\\s*\\w+){0,1}\\s*,)*\\s*\\w+\\s*(as\\s*\\w";

string regExp2 = "\\s*\\*\\s*";



bool condition1 = (Regex.Match(value, regExp).Captures.Count == 1);

bool condition2 = (Regex.Match(value, regExp2).Captures.Count == 1);



checkCorrection = condition1 || condition2;



Debug.Assert(

checkCorrection,

"Trying to set incorrect SelectFields value in SQLQueryBuilder." );

}

3.1.3. Indentation

To indent block of text use tab symbols. Do not use spaces. This is default in Visual Studio.NET.

3.1.4. Methods

Use brackets style as follows. See comments section also.

static int GetRawCount( int RecordsetId )

{

int i = 0;

...

return Raw;

}

3.1.5. Cycles

for ( int i = 0; i < this.GetRawCount( RecordsetId ); i++ )

{

UpdateRaw( i );

...

}

3.1.6. If statement

Always use brackets in if statement.

if ( type == null )

{

break;
}

else

{

continue;

}


3.1.7. Switch statement

switch ( iRawType )

{

case RAW_TYPE_1:

UpdateRaw( iRawId );

...

break;

case RAW_TYPE_2:

...

return;

default:

throw new ApplicationException( "incorrect raw type" );

} //switch

3.2. Commenting

3.2.1. Beginning of file

//-----------------------------------------------------------------------------

//

// Copyright 2002 Vovik. All Rights Reserved.

//

// $Workfile: SqlQueryBuilder.cs $

// $Revision: 3 $

// $Author: Pyurasov $

// Last checked-in at $Date: 6.09.02 15:18 $

// $Modtime: 6.09.02 15:17 $

//

// Description: this file implements SqlQueryBuilder class

//

//-----------------------------------------------------------------------------



// $Archive: /ecommerce/Libraries.NET/AspClassLibrary/SqlQueryBuilder.cs $

#region Changelog

/* $Log: /ecommerce/Libraries.NET/AspClassLibrary/SqlQueryBuilder.cs $

*

*

* 3 19.04.02 18:53 Pyurasov

*

* 2 19.04.02 18:24 Pyurasov

*

* 1 18.04.02 22:11 Pyurasov

*/

#endregion

Copy preceding text to beginning of file and replace description field contents — other information will be filled-in automatically by Visual Source Safe (it does so for fields $FIELD xxx $).

3.2.2. Classes

/// <summary>

/// <para>

/// Builds parts of query for use on pages that display information from

/// base table and display filters to search through this information.</para>

/// <para>

/// Set BaseTableName, BaseTableAlias (optionaly), register

/// filters via RegisterFilter, register sorters via RegisterSorter,

/// register scrollers via RegisterScroller then call GetFromPartString,

/// GetWherePartString and GetOrderByPartString. You can get from this

/// component SQL query text or data table filled according query and scrolling

/// information. </para>

/// See also <see cref="MyClass.Main"/>

/// </summary>

[Designer("org.AspClassLibrary.Design.SqlQueryBuilderDesigner")]

public class SqlQueryBuilder: Component

{

...

Pay attention that comments start with "///" and are XML, spacing rules are XHTML ones. Use following tags:

<c> <para> <see> <code> <param> <seealso> <example> <paramref> <summary> <exception> <permission> <value> <include> <remarks> <list> <returns>.

Check MSDN for meaning of the tags.

Use NDOC tool to generate CHM documentation.

3.2.3. Methods

Always comment and layout methods as following.

/// <summary>

/// StateChange event handler for connection.

/// See <see cref="System.EventArgs.StateChangeEventHandler"/>

/// </summary>

/// <param name="sender">object that sends an event</param>

/// <param name="args">event agruments object</param>

protected void OnStateChange( object sender, StateChangeEventArgs args )

{

Trace.Write( string.Format(

"Default connection state has changed from '{1}' to '{2}', DB: {0}",

((IDbConnection)sender).Database,

args.OriginalState,

args.CurrentState) );

}

Comments should explain:

  • what the method does (not how)

  • each parameter

  • explanation of value returned by function

  • list of each affected external variable, control, file, and so on and the affect it has

You may omit some comment fields in rare cases if their content is undoubtedly obvious.

3.2.4. Code

Try not to use end line comments. Exception is declaring variables, end of big bracketed block.

if ( id > 0 )
{

int rawId = 0; // current raw number



// create and init new raw

int raw = new Raw();

int paramId = getParam( "id" );

raw.id = ( isEmpty( iParamId ) ) ? null : iParamId;

...
} // if ( id > 0 )

3.2.5. Temporary comments

To temporary comment out code use VS.NET commenting feature (Ctrl+K, Ctrl+C and Ctrl+K, Ctrl+U). This puts comments to beginning of line.



// if ( IsDeleted )

// return;



3.3. Naming

Use descriptive names. Good name has between 10 to 20 characters. Use abbreviations if necessary. Always use abbreviated Max, Min, Lang, Db. When using abbreviations put only first letter uppercase like: HttpConnector, DbType.

3.3.1. Variables

3.3.1.1. Prefixes

Use '_' prefix when naming variables — private member of class. Start with lower case letter: _dbType, _baseTableName.

3.3.1.2. Local variable names

Use uppercase letters to separate words except first one.

Examples: eventManager, systemLangId.

3.3.1.3. Special cases

You may use variables "i", "j", "k", "l", "m", "n" of type integer as loop variables or in other cases when their scope is no longer then one screen of code.

Use variable "s" of type string when its scope is no longer then 10-15 lines of code.

Avoid using "temp" variable.

Use variable like "conn" if it represents one and only object of that type (in this case IDbConnection) in very narrow scope (no more that one screen of code).

3.3.2. Constant names

Name constants with all uppercase letters, divide words with underscores.

Examples: MAX_RETRIES, WRONG_PARAM_ERROR.

3.3.3. Method names

Name methods starting with verbs like Get, Set, Add, Update, Remove, etc. If needed add adjective like New, Last, etc. Add noun like Record, Connection, ErrorMessage etc at the end.


Examples: GetNewRecord, UpdateCustomerInformation, IsEmpty.

3.3.3.1. Special cases

3.3.3.1.1. Functions converting types

Use "To" between type names.

Example: IntToString, UnicodeToChar.

3.3.4. File names

Generally there should be one file per class. File should be named same as class. File may additionally contain some very relative small classes.

3.4. Contract based programming

To improve reliability of code, shorten debug time and increase supportability methods should check

  • incoming parameters

  • state of the object

  • outgoing return values

Method cannot make any assumptions about who, how and when calls it.

Use Debug.Assert to check conditions that may be checked only at debug time. If condition is not obvious add explanation as second parameter.

Use #ifdef DEBUG / #endif for complex conditions.

Some conditions should be checked at run-time also.

public string UnregisterFilter( IBaseFilter filter )

{

// precondition

Debug.Assert( DesignMode, "This method is for design mode only." );
Debug.Assert( filter != null );

#ifdef DEBUG

foreach( SubFilter subFilter in filter.SubFilters )

{

if ( subFilter.Param == null )

{

throw new ApplicationException( "Subfilter Param cannot be null." );

}

}

#endif





string retVal = _registeredFilters.Remove( filter );



// invalidate cache

_cacheIsReady = false;





// postcondition
Debug.Assert( retVal != null, "Return value cannot be null." );


return retVal;

}

3.5. Notes in code

When there is note to be left in comments put a special word in the beginning of the line. This can be easily tracked via Visual Studio Task List.

// TODO: check for additional conditions

// HACK: this code works but further investigation is required

3.6. Use regions

To divide code into collapsible regions use #region.

3.7. QA

Code should be reviewed by peers periodically. Following tools may aid with checking the quality:

  • Visual Studio's feature to put warning if comments are missing

  • Microsoft's FxCop tool

  • NDoc — CHM generation tool


Note: Developers are required to fix their coding style in extra time (AKA work for free).

3.8. Example

//-----------------------------------------------------------------------------

//

// Copyright 2002 Vovik Ltd. All Rights Reserved.

//

// $Workfile: SqlQueryBuilder.cs $

// $Revision: 20 $ VSS version number

// Last $Author: Pyurasov $ checked-in at $Date: 6.09.02 15:18 $

// $Modtime: 6.09.02 15:17 $

//

// Description: this file implements SqlQueryBuilder class

//

//-----------------------------------------------------------------------------



// $Archive: /ecommerce/Libraries.NET/AspClassLibrary/SqlQueryBuilder.cs $

#region Changelog

/* $Log: /ecommerce/Libraries.NET/AspClassLibrary/SqlQueryBuilder.cs $

*

* 1 19.04.02 18:53 Pyurasov

*

* 1 19.04.02 18:24 Pyurasov

*

* 4 18.04.02 22:11 Pyurasov

*/

#endregion



using System;

using System.Collections;

using System.Configuration;

using System.Data;

using System.Data.Common;

using System.ComponentModel;

using System.Diagnostics;



using org.ClassLibrary;



using org.AspClassLibrary.Filters;

using org.AspClassLibrary.Sorters;

using org.AspClassLibrary.Scrollers;



// TODO: add support for M:M filters



namespace org.AspClassLibrary

{

/// <summary>

/// Builds parts of query for use on pages that display information from

/// base table and display filters to search through this information.

/// ...

/// </summary>

[Designer( "org.AspClassLibrary.Design.SqlQueryBuilderDesigner" )]

[AnotherSampleAttribute()]

public class SqlQueryBuilder: Component

{



#region Private fields



/// <summary>

/// value of BaseTableName property

/// </summary>

private string _baseTableName;



/// <summary>

/// value of BaseTableAlias property

/// </summary>

string _baseTableAlias;



#endregion



#region Properties



/// <summary>

/// Generates SQL query for design time and for filling in

/// dataset in runtime.

/// </summary>

[Browsable( false )]

public string Sql

{

get

{

string fieldSet = (_selectFields || _selectFields);

string sql = "SELECT " + fieldSet + " FROM " +

GetFromPartString();



string wherePart = GetWherePartString();



if ( wherePart != null && wherePart.Length > 0 )

sql += " WHERE " + wherePart;



sql += GetOrderByPartString();



return sql;

}

}



#endregion



#region Methods

/// <summary>

/// Unregisters filter. Used in design mode when filters can be

/// added and removed dynamicaly. Supports null values.

/// </summary>

/// <param name="filter">Filter to unregister</param>

public void UnregisterFilter( IBaseFilter filter )

{

Debug.Assert( DesignMode, "This method is for design mode only." );



_registeredFilters.Remove( filter );



// invalidate cache

_cacheIsReady = false;

}



#endregion

}



}


4. SQL Code and RDBMS Objects

4.1. Naming

Follow the same rules for RDBMS objects as for C# code objects (see 3.3). For other cases not listed here refer to AdventureWorks sample database shipped with Microsoft SQL Server 2005.

4.1.1. Tables

Name tables in Pascal-style in singular form. E.g.

ProductModel

ProductDescription

ContactCreditCard

For association tables (that implement M-M relationship) construct names by concatenating names of the tables that are related using this association table.

ProductModelProductDescription

Name columns in Pascal-style. E.g.

Name

ModifiedDate

Name table’s primary key column as TableNameID, e.g.

ProductModelID

ProductDescriptionID

Name foreign key columns just as primary key columns in referenced tables. E.g.

ProductModelID

ProductDescriptionID

Name bit columns with Flag postfix

MakeFlag

FinishedGoodsFlag

4.1.2. Views

Name views in Pascal-style and add ‘v’ prefix to indicate it is a view. E.g.

vIndividualCustomer

vSalesPersonSalesByFiscalYears

4.1.3. Functions

Name functions in Pascal-style and add ‘ufn’ prefix to indicate it is a user function. Also use Get verb in the beginning. E.g.

ufnGetAccountingEndDate

ufnGetProductListPrice

4.1.4. Stored procedures

Name stored procedures in Pascal-style and add ‘ufp’ prefix to indicate it is a user stored procedure. Also use Get verb in the beginning of name if stored procedure produces result set. E.g.

uspGetBillOfMaterials

uspLogError

Name stored procedure parameters and local variables in Pascal-style, like table columns, e.g.

@ManagerID

@EmployeeID

4.1.5. Indexes

Name indexes according to the following pattern IX_<TableName>_<IndexedColumnNames>, e.g.

IX_SalesOrderHeader_SalesPersonID

IX_SalesOrderHeader_CustomerID

IX_SalesOrderHeader_CustomerIDSalesPersonID


5. OLAP Objects

5.1. Cubes

Give cubes meaningful names, use spaces to separate words in cube name, e.g.

Sales

Purchases

Give measures meaningful names, use spaces to separate words in cube name, e.g.

Internet Sales

Internet Orders

5.2. Dimensions

Name dimensions in singular form, use spaces to separate words in dimension name, e.g.

Product

Sales Territory

Organization

Name dimension levels in singular form, use spaces to separate words in dimension name, e.g.

Category

Subcategory

Model Name

6. Security Considerations

This document has no relation to any security considerations.

7. VS.NET 2005 settings

Pleased use default formatting settings except turn ON the following::


  • Insert space within argument list parentheses

  • Insert space within argument list parentheses

  • Insert space within parentheses of expressions

  • Insert space inside parentheses of control flow statements

  • Insert spaces within square brackets

  • Insert space after colon for base or interface in type declaration

8. References

  • McConnell, Steve. Code Complete. Redmond, WA: Microsoft Press, 1993.

  • MSDN: .NET framework / Reference / Design Guidelines for Class Library Developers

No comments:

Post a Comment