HTML Dropdown

Monday, 3 August 2015

How to achieve higher standards of Coding in C#:Part 3

To develop reliable and maintainable applications, you must follow coding standards and best practices.
The naming conventions, coding standards and best practices described in this document are compiled from our own experience and by referring to various Microsoft and non-Microsoft guidelines.
There are several standards exists in the programming industry. None of them are wrong or bad and you may follow any of them. What is more important is, selecting one standard approach and ensuring that everyone is following it.

If you have a team of different skills and tastes, you are going to have a tough time convincing everyone to follow the same standards. The best approach is to have a team meeting and developing your own standards document. You may use this document as a template to prepare your own document.
Distribute a copy of this document (or your own coding standard document) well ahead of the coding standards meeting. All members should come to the meeting prepared to discuss pros and cons of the various points in the document. Make sure you have a manager present in the meeting to resolve conflicts.
Discuss all points in the document. Everyone may have a different opinion about each point, but at the end of the discussion, all members must agree upon the standard you are going to follow. Prepare a new standards document with appropriate changes based on the suggestions from all of the team members. Print copies of it and post it in all workstations.
After you start the development, you must schedule code review meetings to ensure that everyone is following the rules. 3 types of code reviews are recommended:
  1. Peer review – another team member review the code to ensure that the code follows the coding standards and meets requirements. This level of review can include some unit testing also. Every file in the project must go through this process.
  2. Architect review – the architect of the team must review the core modules of the project to ensure that they adhere to the design and there is no “big” mistakes that can affect the project in the long run.
  3. Group review – randomly select one or more files and conduct a group review once in a week. Distribute a printed copy of the files to all team members 30 minutes before the meeting. Let them read and come up with points for discussion. In the group review meeting, use a projector to display the file content in the screen. Go through every sections of the code and let every member give their suggestions on how could that piece of code can be written in a better way. (Don’t forget to appreciate the developer for the good work and also make sure he does not get offended by the “group attack”!)

 ·         Always use multi-layer (N-Tier) architecture.
·         Never access database from the UI pages. Always have a data layer class which performs all the database related tasks. This will help you support or migrate to another database back end easily.
·         Use try-catch in your data layer to catch all database exceptions. This exception handler should record all exceptions from the database. The details recorded should include the name of the command being executed, stored proc name, parameters, connection string used etc. After recording the exception, it could be re thrown so that another layer in the application can catch it and take appropriate action.
·         Separate your application into multiple assemblies. Group all independent utility classes into a separate class library. All your database related files can be in another class library.

·         Do not use session variables throughout the code. Use session variables only within the classes and expose methods to access the value stored in the session variables. A class can access the session using System.Web.HttpCOntext.Current.Session
·         Do not store large objects in session. Storing large objects in session may consume lot of server memory depending on the number of users.
·         Always use style sheet to control the look and feel of the pages. Never specify font name and font size in any of the pages. Use appropriate style class. This will help you to change the UI of your application easily in future. Also, if you like to support customizing the UI for each customer, it is just a matter of developing another style sheet for them.

1.     Never do a 'catch exception and do nothing'. If you hide an exception, you will never know if the exception happened or not. Lot of developers uses this handy method to ignore non-significant errors. You should always try to avoid exceptions by checking all the error conditions programmatically. In any case, catching an exception and doing nothing is not allowed. In the worst case, you should log the exception and proceed.
2.     In case of exceptions, give a friendly message to the user, but log the actual error with all possible details about the error, including the time it occurred, method and class name etc.
3.     Always catch only the specific exception, not generic exception.

Good:


            void ReadFromFile ( string fileName )
            {
                        try
                        {
                                    // read from file.
                        }
                        catch (FileIOException ex)
                        {
                                    // log error.
                                    //  re-throw exception depending on your case.
                                    throw;
                        }
            }

Not Good:
void ReadFromFile ( string fileName )
{
   try
   {
      // read from file.
   }
   catch (Exception ex)  
   {
      // Catching general exception is bad... we will never know whether
      // it was a file error or some other error.                   
      // Here you are hiding an exception.
      // In this case no one will ever know that an exception happened.

      return "";                 
   }
}
           

4.     No need to catch the general exception in all your methods. Leave it open and let the application crash. This will help you find most of the errors during development cycle. You can have an application level (thread level) error handler where you can handle all general exceptions. In case of an 'unexpected general error', this error handler should catch the exception and should log the error in addition to giving a friendly message to the user before closing the application, or allowing the user to 'ignore and proceed'.
5.     When you re throw an exception, use the throw statement without specifying the original exception. This way, the original call stack is preserved.

Good:
catch
{
            // do whatever you want to handle the exception

            throw;  
}

Not Good:

catch (Exception ex)
{
            // do whatever you want to handle the exception

            throw ex;
}

6.     Do not write try-catch in all your methods. Use it only if there is a possibility that a specific exception may occur and it cannot be prevented by any other means. For example, if you want to insert a record if it does not already exists in database, you should try to select record using the key. Some developers try to insert a record without checking if it already exists. If an exception occurs, they will assume that the record already exists. This is strictly not allowed. You should always explicitly check for errors rather than waiting for exceptions to occur. On the other hand, you should always use exception handlers while you communicate with external systems like network, hardware devices etc. Such systems are subject to failure anytime and error checking is not usually reliable. In those cases, you should use exception handlers and try to recover from error.

7.     Do not write very large try-catch blocks. If required, write separate try-catch for each task you perform and enclose only the specific piece of code inside the try-catch. This will help you find which piece of code generated the exception and you can give specific error message to the user.
8.     Write your own custom exception classes if required in your application. Do not derive your custom exceptions from the base class SystemException. Instead, inherit from ApplicationException.
9.     Do not use try/catch blocks for flow-control.
10.  Only catch exceptions that you can handle.
11.  Never declare an empty catch block.
12.   Avoid nesting a try/catch within a catch block.
13.  Always catch the most derived exception via exception filters.
14.  Order exception filters from most to least derived exception type.
15.  Avoid re-throwing an exception. Allow it to bubble-up instead.
16.  If re-throwing an exception, preserve the original call stack by omitting the exception argument from the throw statement.
 Example: // Bad!
 catch(Exception ex) { Log(ex); throw ex; }
 //Good! 
catch(Exception) { Log(ex); throw; }
17.  Only use the finally block to release resources from a try statement.
18.  Always use validation to avoid exceptions.
 Example: // Bad! try { conn.Close(); } Catch(Exception ex) { // handle exception if already closed! }
 // Good! if(conn.State != ConnectionState.Closed) { conn.Close(); } 
19 a. Always set the innerException property on thrown exceptions so the exception chain & call stack are maintained.
19 b.  Avoid defining custom exception classes. Use existing exception classes instead.
20.  When a custom exception is required;
a.     Always derive from Exception not ApplicationException.
b.    Always suffix exception class names with the word “Exception”.
c.     Always add the SerializableAttribute to exception classes.
d.    Always implement the standard “Exception Constructor Pattern”: public MyCustomException (); public MyCustomException (string message); public MyCustomException (string message, Exception innerException);
e.     Always implement the deserialization constructor: protected MyCustomException(SerializationInfo info, StreamingContext contxt);
21.  Always set the appropriate HResult value on custom exception classes. (Note: the ApplicationException HResult = -2146232832)
22.  When defining custom exception classes that contain additional properties:
a.     Always override the Message property, ToString() method and the implicit operator string to include custom property values.
b.    Always modify the deserialization constructor to retrieve custom property values.
c.     Always override the GetObjectData(…) method to add custom properties to the serialization collection.
Example: public override void GetObjectData(SerializationInfo info, StreamingContext context) { base.GetObjectData (info, context); info.AddValue("MyValue", _myValue); }

Object Model & API Design

·         Always prefer aggregation over inheritance.
·         Avoid “Premature Generalization”. Create abstractions only when the intent is understood.
·         Do the simplest thing that works, then refactor when necessary.
·         Always make object-behavior transparent to API consumers.
·         Avoid unexpected side-affects when properties, methods, and constructors are invoked.
·         Always separate presentation layer from business logic.
·         Always prefer interfaces over abstract classes.
·         Try to include the design-pattern names such as “Bridge”, “Adapter”, or “Factory” as a suffix to class names where appropriate.
·         Only make members virtual if they are designed and tested for extensibility.
·         Refactor often!


Object Composition

1.     Always declare types explicitly within a namespace. Do not use the default “{global}” namespace. 69. Avoid overuse of the public access modifier. Typically fewer than 10% of your types and members will be part of a public API, unless you are writing a class library.
2.     Consider using internal or private access modifiers for types and members unless you intend to support them as part of a public API.
3.     Never use the protected access modifier within sealed classes unless overriding a protected member of an inherited type.
4.     Avoid declaring methods with more than 5 parameters. Consider refactoring this code.
5.     Try to replace large parameter-sets (> than 5 parameters) with one or more class or struct parameters – especially when used in multiple method signatures.
6.     Do not use the “new” keyword on method and property declarations to hide members of a derived type.
7.     Only use the “base” keyword when invoking a base class constructor or base implementation within an override.
8.     Consider using method overloading instead of the params attribute (but be careful not to break CLS Compliance of your API’s).
9.     Always validate an enumeration variable or parameter value before consuming it. They may contain any value that the underlying Enum type (default int) supports.
 Example:
public void Test(BookCategory cat) { if (Enum.IsDefined(typeof(BookCategory), cat)) {…} }
10.  Consider overriding Equals() on a struct.
11.  Always override the Equality Operator (==) when overriding the Equals() method.
12.  Always override the String Implicit Operator when overriding the ToString() method.
13.  Always call Close() or Dispose() on classes that offer it.
14.  Wrap instantiation of IDisposable objects with a “using” statement to ensure that Dispose() is automatically called.
Example: using(SqlConnection cn = new SqlConnection(_connectionString)) {…}
15.  Always implement the IDisposable interface & pattern on classes referencing external resources. Example: (shown with optional Finalizer)
public void Dispose() { Dispose(true); GC.SuppressFinalize(this); }
 protected virtual void Dispose(bool disposing) { if (disposing) { // Free other state (managed objects). }
// Free your own state (unmanaged objects). // Set large fields to null. } // C# finalizer. (optional) ~Base()
{ // Simply call Dispose(false). Dispose (false); }
16.  Avoid implementing a Finalizer. Never define a Finalize() method as a finalizer. Instead use the C# destructor syntax.
 Example // Good ~MyClass {…} // Bad void Finalize(){…}

Below are some examples of our C# coding standards, naming conventions, and best practices. Use these according to your own needs. 

C# Coding Conventions (C# Programming Guide)

The C# Language Specification does not define a coding standard. However, the guidelines in this topic are used by Microsoft and non-Microsoft to develop samples and documentation.
Coding conventions serve the following purposes:
·         They create a consistent look to the code, so that readers can focus on content, not layout.
·         They enable readers to understand the code more quickly by making assumptions based on previous experience.
·         They facilitate copying, changing, and maintaining the code.
·         They demonstrate C# best practices.

Naming Conventions

·         In short examples that do not include using directives, use namespace qualifications. If you know that a namespace is imported by default in a project, you do not have to fully qualify the names from that namespace. Qualified names can be broken after a dot (.) if they are too long for a single line, as shown in the following example.
C#
var currentPerformanceCounterCategory = new System.Diagnostics.
    PerformanceCounterCategory();
·         You do not have to change the names of objects that were created by using the Visual Studio designer tools to make them fit other guidelines.

·         Move Declaration Near Reference

Some programmers are used to placing temporary variable declarations at the top of the method.But by placing the variable declaration far away from the line where it is first referenced, you are making code more difficult to read, because it is not immediately clear how the variable was initialized. In addition, declaring variables well ahead of time makes the method more difficult to refactor. If you try to extract a part of the method in which the variable was referenced, you have to pass the variable as a parameter to a newly extracted method, even though the declaration could possibly have been placed inside the extracted block.
·         Do use PascalCasing for class names and method names.
I am providing some basic level examples below but as I already mentioned, find a good convention that fits for you and stick with it.
public class Product
{
    public void GetActiveProducts()
    {
      //...
    }
    public void CalculateProductAdditinalCost()
    {
        //...
    }
}
Do use camelCasing for method arguments and local variables.

public class ProductCategory
{
  public void Save(ProductCategory productCategory)
   {
       // ...
   }
Do not use Abbreviations.

// Correct
ProductCategory productCategory;

// Avoid
ProductCategory prodCat;
Do not use Underscores in identifiers.

// Correct
ProductCategory productCategory;

// Avoid
ProductCategory product_Category;
Do prefix interfaces with the letter I.

public interface IAddress
{

}
Do declare all member variables at the top of a class, with static variables at the very top.

public class Product
{
    public static string BrandName;

    public string Name{get; set;}
    public DateTime DateAvailable {get; set;}

    public Product()
    {
        // ...
    }
}
Do use singular names for enums. Exception: bit field enums.
public enum Direction
{
    North,
    East,
    South,
    West
}
Do not suffix enum names with Enum.
//Avoid
public enum DirectionEnum
{
    North,
    East,
    South,
    West
}
General Guidelines
·         Always use Camel Case or Pascal Case names.
·         Avoid ALL CAPS and all lowercase names. Single lowercase words or letters are acceptable.
·         Do not create declarations of the same type (namespace, class, method, property, field, or parameter) and access modifier (protected, public, private, internal) that vary only by capitalization.
·         Do not use names that begin with a numeric character.
·         Do add numeric suffixes to identifier names.
·         Always choose meaningful and specific names.
·         Always err on the side of verbosity not terseness.
·         Variables and Properties should describe an entity not the type or size.
·         Do not use Hungarian Notation!
 Example: strName or iCount
·         Avoid using abbreviations unless the full name is excessive. 11. Avoid abbreviations longer than 5 characters.
·         Any Abbreviations must be widely known and accepted.
·         Use uppercase for two-letter abbreviations, and Pascal Case for longer abbreviations.
·         Do not use C# reserved words as names.
·         Avoid naming conflicts with existing .NET Framework namespaces, or types.
·         Avoid adding redundant or meaningless prefixes and suffixes to identifiers
Example: // Bad!
 public enum ColorsEnum {…}
 public class CVehicle {…}
public struct RectangleStruct {…}
·         Do not include the parent class name within a property name.
Example: Customer.Name NOT Customer.CustomerName
·         Try to prefix Boolean variables and properties with “Can”, “Is” or “Has”.
·         Append computational qualifiers to variable names like Average, Count, Sum, Min, and Max where appropriate.
·         When defining a root namespace, use a Product, Company, or Developer Name as the root. Example: LanceHunt.StringUtilities
  • Namespace names should follow the standard pattern
<company name>.<product name>.<top level module>.<bottom level module>
  • Use appropriate prefix for the UI elements so that you can identify them from the rest of the variables.

There are 2 different approaches recommended here.
·         Use a common prefix ( ui_ ) for all UI elements. This will help you group all of the UI elements together and easy to access all of them from the intellisense.

·         Use appropriate prefix for each of the ui element. A brief list is given below. Since .NET has given several controls, you may have to arrive at a complete list of standard prefixes for each of the controls (including third party controls) you are using.


Control
Prefix
Label
lbl
TextBox
txt
DataGrid
dtg
Button
btn
ImageButton
imb
Hyperlink
hlk
DropDownList
ddl
ListBox
lst
DataList
dtl
Repeater
rep
Checkbox
chk
CheckBoxList
cbl
RadioButton
rdo
RadioButtonList
rbl
Image
img
Panel
pnl
PlaceHolder
phd
Table
tbl
Validators
val



  • File name should match with class name.
 For example, for the class HelloWorld, the file name should be helloworld.cs (or, helloworld.vb)

Layout Conventions

 

Good layout uses formatting to emphasize the structure of your code and to make the code easier to read. Microsoft examples and samples conform to the following conventions:
·         Use the default Code Editor Settings (smart indenting, four-character indents, tabs saved as spaces). Write only one statement per line.
·         Write only one declaration per line.
·         If continuation lines are not indented automatically, indent them one tab stop (four spaces).
·         Add at least one blank line between method definitions and property definitions.
·         Use parentheses to make clauses in an expression apparent, as shown in the following code.
C#
if ((val1 > val2) && (val1 > val3))
{
    // Take appropriate action.
}
 

Indentation and Spacing

  • Use TAB for indentation. Do not use SPACES.  Define the Tab size as 4.
  • Comments should be in the same level as the code (use the same level of indentation).

Good:

// Format a message and display

string fullMessage = "Hello " + name;
DateTime currentTime = DateTime.Now;
string message = fullMessage + ", the time is : " + currentTime.ToShortTimeString();
MessageBox.Show ( message );

Not Good:

// Format a message and display
string fullMessage = "Hello " + name;
DateTime currentTime = DateTime.Now;
string message = fullMessage + ", the time is : " + currentTime.ToShortTimeString();
MessageBox.Show ( message );

  • Curly braces ( {} ) should be in the same level as the code outside the braces.
       

  • Use one blank line to separate logical groups of code.

Good:
bool SayHello ( string name )
{
string fullMessage = "Hello " + name;
DateTime currentTime = DateTime.Now;

string message = fullMessage + ", the time is : " + currentTime.ToShortTimeString();

MessageBox.Show ( message );

if ( ... )
{
// Do something
// ...

return false;
}

return true;
}

Not Good:

bool SayHello (string name)
{
string fullMessage = "Hello " + name;
DateTime currentTime = DateTime.Now;
string message = fullMessage + ", the time is : " + currentTime.ToShortTimeString();
MessageBox.Show ( message );
if ( ... )
{
// Do something
// ...
return false;
}
return true;
}

  • There should be one and only one single blank line between each method inside the class.
  • The curly braces should be on a separate line and not in the same line as if, for etc.
Good:
if ( ... ) 
{
// Do something
}

Not Good:

if ( ... )  {
// Do something
}

  • Use a single space before and after each operator and brackets.

Good:
if ( showResult == true )
{
for ( int i = 0; i < 10; i++ )
{
//
}
}

Not Good:

if(showResult==true)
{
for(int      i= 0;i<10;i++)
{
//
}
}


  • Use #region to group related pieces of code together. If you use proper grouping using #region, the page should like this when all definitions are collapsed.
           


  • Keep private member variables, properties and methods in the top of the file and public members in the bottom. 

Formatting Guidelines
·         Never declare more than 1 namespace per file.
·         Avoid putting multiple classes in a single file.
·         Always place curly braces ({ and }) on a new line.
·         Always use curly braces ({ and }) in conditional statements.
·         Always use a Tab & Indention size of 4.
·         Declare each variable independently – not in the same statement.
·         Place namespace “using” statements together at the top of file. Group .NET namespaces above custom namespaces.
·         Group internal class implementation by type in the following order: a. Member variables. b. Constructors & Finalizers. c. Nested Enums, Structs, and Classes. d. Properties e. Methods
·         Sequence declarations within type groups based upon access modifier and visibility: a. Public b. Protected c. Internal d. Private
·         Segregate interface Implementation by using #region statements.
·         Append folder-name to namespace for source files within sub-folders.
·         Recursively indent all code blocks contained within braces.
·         Use white space (CR/LF, Tabs, etc) liberally to separate and organize code.
·         Only declare related attribute declarations on a single line, otherwise stack each attribute as a separate declaration.
 Example:
// Bad!
 [Attrbute1, Attrbute2, Attrbute3]
 public class MyClass {…}
 // Good!
[Attrbute1, RelatedAttribute2] [Attrbute3] [Attrbute4]
public class MyClass {…}
·         Place Assembly scope attribute declarations on a separate line.
·         Place Type scope attribute declarations on a separate line.
·         Place Method scope attribute declarations on a separate line.
·         Place Member scope attribute declarations on a separate line.
·         Place Parameter attribute declarations inline with the parameter.
·         If in doubt, always err on the side of clarity and consistency.

Commenting Conventions

·         Place the comment on a separate line, not at the end of a line of code.
·         Begin comment text with an uppercase letter.
·         End comment text with a period.
·         Insert one space between the comment delimiter (//) and the comment text, as shown in the following example.
·         C#
·         // The following declaration creates a query. It does not run 
·         // the query.
·         Do not create formatted blocks of asterisks around comments.
·         All comments should be written in the same language, be grammatically correct, and contain appropriate punctuation.
·         Use // or /// but never /* … */
·         Do not “flowerbox” comment blocks. Example: // *************************************** // Comment block // ***************************************
·         Use inline-comments to explain assumptions, known issues, and algorithm insights.  Do not use inline-comments to explain obvious code. Well written code is self-documenting.
·         Only use comments for bad code to say “fix this code” – otherwise remove, or rewrite the code!
·         Include comments using Task-List keyword flags to allow comment-filtering. Example: // TODO: Place Database Code Here // UNDONE: Removed P\Invoke Call due to errors // HACK: Temporary fix until able to refactor
·         Always apply C# comment-blocks (///) to public, protected, and internal declarations. Only use C# comment-blocks for documenting the API.
·         Always include comments. Include, and comment sections where applicable.
·         Include and where possible.
·         Always add CDATA tags to comments containing code and other embedded markup in order to avoid encoding issues. Example: /// /// Add the following key to the “appSettings” section of your config.
·         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 represent items that represent the elements of a program's API which must be documented for the program to be useful to other programmers. These tags usually have attributes such as name or cref as demonstrated in the multiline example above. These attributes are checked by the compiler, so they should be valid. The latter category governs the layout of the documentation, using tags such as <code>, and <list> or <para>.
·         Documentation can then be generated using the 'documentation' item in the #develop 'build' menu. The documentation generated is in HTMLHelp format. For a fuller explanation of XML comments see the Microsoft .net framework SDK documentation. For information on commenting best practice and further issues related to commenting, see the TechNote 'The fine Art of Commenting'.
·         Single Line Comments You should use the // comment style to "comment out" code (SharpDevelop has a key for it, Alt+/). It may be used for commenting sections of code too. Single line comments must be indented to the indent level when they are used for code documentation. Commented out code should be commented out in the first line to enhance the visibility of commented out code. A rule of thumb says that generally, the length of a comment should not exceed the length of the code explained by too much, as this is an indication of too complicated, potentially buggy, code.

No comments:

Post a Comment