This article may be read as a guide to writing robust and reliable programs. It focuses on programs written in C#, but many of the rules and principles are useful even if you write in another programming language. Below are the C# coding standards, naming conventions, and best practices. Use these in your own projects and/or adjust these to your own needs.

Preamble

Anybody can write a “Working Code” but to write “Efficient Code” you have to read loads of books, know the internet, and have some years of experience. These standards derive from the experience of product development efforts and are continuously evolving. I‘ve just compiled this article from books/internet and someone’s experience. This article is not the Bible, as we must keep updating our knowledge and learning. By applying a set of well-defined coding standards our in code will have fewer bugs and better maintainability. The efficient code should be:

  • Easily understandable
  • Maintainable
  • Efficient

Important Note: The naming conventions and best practices described in this article are compiled from our own experience and by referring to various guidelines.

Purpose

To develop a reliable and sustainable application, you must follow coding standards. Several standards exist in the programming industry. None are wrong or bad. It is important  to select one standard approach and ensure that everyone follows it.

Across The Team

If you have a team with different skills andstyles, you are going to have a tough time convincing everyone to follow the same standards. The best approach is to have a team meeting, discuss various points, make a template document of standards, and distribute a copy of this document.

First, we will go with naming conventions and indentations. I am not going to discuss very basic stuff like Pascal or Camel casing. Then, we will discuss “Best Practices”. Lastly, I will give some tips for Visual Studio development.

Naming Conventions and Standards

  • Use meaningful, descriptive words to name variables
    • Do not use single character variable names like I, j, x, instead use index, counter, row etc. especially in loops
    • Do not use words that require case sensitivity
  • Name method names using Verb-Object Pair such as ShowEmployee()
    • where Show is the Verb and Employee is the Object
  • UI elements (whether Windows/ASP.Net) should use an appropriate prefix like txtTextBox1 etc.
  • The general rule for naming namespace is to use <Company Name>.<Product>.<Module> and optionally <Sub Module>.

Indentation and Comments

  • Curly braces for each block should be at the same level. <CTRL><K><D> and <CTRL><E><D> in different Visual Studio versions to format the whole document.
  • Use “#region” to group related piece of code. Use <CTRL><M><O> and <CTRL><M><P> to collapse and expand code segments in the whole document.
 public class Employee
        {
            #region Private Member Variables
            private int _myVariable;
            #endregion
            #region Properties
            public int MyProperty { get; set; }
            #endregion
            #region Private Methods
            private void GetEmployee()
            {
                // Do you code
            }
            #endregion
            #region Public Methods
            public string GetEmployeeStatus(int EmployeeID)
            {
                //Do whatever you want
                return "Employee Status Here...";
            }
            #endregion
        }

Note: VB.Net does not allow regions within the method body.
Comments should be in the same level as code

True / Correct approach

//call business logic to delete employee
bool isEmployeeDeleted = BL.DeleteEmployee(EmployeeID);
//return operation status
return isEmployeeDeleted;

False / Incorrect approach

//call business logic to delete employee
        bool isEmployeeDeleted = BL.DeleteEmployee(EmployeeID);
        //return operation status
                return isEmployeeDeleted;
  • If you follow best practices then there will be no need to write comments. Write meaningful, short and spell checked comments if required.
  • TODO comments is a best approach to highlight a task you do not have done yet in the developer’s version of code. The exact way to write this type of comment is:
//TODO: Fill primary values with autoincrement

Note: You can view all the TODO comments from VIEW Other Windows Task List. Make it a habit to remove all the TODO comments when you are going to give a product release.

Best Practice: If you update your code and forget to update comments, it will lead to confusion.

  • Coding Best Practices:
    Class file and class should have a one-to-one relationship.
  • Method should not have more than five arguments. Use structure for multiple arguments.
  • A method should have only “Single Responsibility”.
private void AddEmployee(Employee employee)
{
    bool isEmployeeSaved = SaveEmployee(employee);
    if(isEmployeeSaved)
    {
        GreetEmployee();
    }
}

Always watch for unexpected values. For example if you are using a parameter with two possible values, never assume that if one is not matching then the only possibility is the other value.

if(memberType == MemberType.Registered)
{
   //If user is registered
}
else if(memberType == MemberType.Anonymous)
{
   //If user is anonymous
}
else
{
   throw new Exception("This Member Type is not supported.");
   // in future if we introduce new Member Type
   // we can easily come to know
}

Avoid sharing member variables amongst methods. Use enum wherever required.

  • For readability and maintainability
  • For error-checking and compiler warnings
enum Colors
   {
      Red,
      White,
      Black
   }
   public string PredictNatureByColor(Colors favoriteColor)
   {
     switch(favoriteColor)
     {
      case    Colors.Red:
         // Favorite color is Red
         break;
      case Colors.Black:
         // Favorite color is Black
         break;
      case Colors.White:
         // Favorite color is White
         break;
      default:
         // Sorry, we are unable to predict nature
         break;
     }
   }

Never hardcode a drive name or path in code, get it programmatically and use relative path. Error message should help the user to solve the problem. Never give a message like “Error in application”, “an object reference not set to an instance of object”.

try
   {
     System.IO.File.Create(@"C:\File.txt");
   }
     catch (UnauthorizedAccessException unauthorizedAccessException)
   {
     Console.WriteLine(@"You are not authorized to create file.
                       Please contact your Admninistrator.");
   }
     catch (PathTooLongException pathTooLongException)
   {
     Console.WriteLine(@"Provided path is too long.
                       Please provide valid path.");
   }
     catch (DirectoryNotFoundException directoryNotFoundException)
   {
     Console.WriteLine(@"Provided directory not exists.
                       Please provide valid directory.");
   }
     catch (Exception exception)
   {
     Console.WriteLine(@"Some error occurred while creating your file.
                       Please try again later.");
   }

Avoid having large files, refactor it into two or more files using Partial. Methods which return collections, should return empty collection if no data found.

public List<Employee> GetAllEmployees()
       {
       List<Employee> listEmployee = BL.GetAllEmployees();
       if(listEmployee == null)
       return new List<Employee>();
       else
       return listEmployee;
}

Avoid ToString() and use Convert.ToString() method.

True / Correct approach

string name = null;
// returns empty string
Console.WriteLine(Convert.ToString(name));

False / Wrong approach

string name = null;
// Throws: Object reference not
// set to an instance of object
Console.WriteLine(name.ToString());

Avoid explicit casting, use as operator.

True / Correct approach

object myObject = new Employee();
// return NULL as "myObject" is not
// string
string castedValue = myObject as string;

False / Wrong approach

object myObject = new Employee();
// Throws "InvalidCastException"
// as "myObject" is not string
string castedValue = (string)myObject;

Database Best Practices

  • Always use stored procedures, as SQL statements eats your network bandwidth.
  • If any SQL task may create a problem then use Atomic Transaction approach (if it fails then everything will be roll backed).
  • To avoid SQL Injection, never write direct SQL statements in code. Use stored procedures with SQL parameters.
SQL-1

Fig. 1 SQL Injection

ASP.NET Best Practices

This topic typically belongs to the pure web development side. Use session variables like this:

public class WebUtil
   {
   public static object GetSessionValue(string key)
   {
   if(HttpContext.Current.Session[key]!=null)
   return HttpContext.Current.Session[key];
   else
   return null;
   }
   public static void SetSessionValue(string key, object value)
   {
   HttpContext.Current.Session.Add(key, value);
   }
   }
   
   string sessionKey = "CurrentDateTime";
   DateTime dateTime = DateTime.Now;
   WebUtil.SetSessionValue(sessionKey, dateTime);
   dateTime = (DateTime)WebUtil.GetSessionValue(sessionKey);

Generic exceptions should be handled in Global Exceptions.

GLOBAL.ASAX

void Application_Error(object sender, EventArgs e)
{
     // code that run when an unhandled exception occur
     // give the user some information, but
     Exception ex = Server.GetLastError();
     // stay on to the default page
     // log the error
     // clear the error from server
     Server.ClearError();
}

MyPage.ASPX

private void Page_Error(object sender, EventArgs e)
{
     // get last error from the server
     Exception ex = Server.GetLastError();

     // Handle / Log exception gracefully

     // clear the error from the server
     Server.ClearError();
}
  • Avoid copy—pasting same code, better to put it in Base Class or Utility Class.
  • Always use style sheet to control the look and feel of the pages. Make external CSS file and use appropriate style class. This will help you to change the UI of your application easily. Also, if you like to support customizing the UI for each customer, it is just a matter of developing another style sheet for them.

JavaScript Best Practices

  • Minimize the use of global variables. In a web page, global variables belong to the window object.
  • Variables created withoutthe keyword var, are always global, even if they are created inside a function.
  • Don’t Use new Object() like new String() etc. rather use:
var x1 = {};           // new object
var x2 = "";           // new primitive string
var x3 = 0;            // new primitive number
var x4 = false;        // new primitive boolean
var x5 = [];           // new array object
var x6 = /()/;         // new regexp object
var x7 = function(){}; // new function object

Subtracting a string from a string, does not generate an error but returns NaN (Not a Number) e.g.

"Hello" - "Dolly"    // returns NaN

The == comparison operator always converts (to matching types) before comparison. The === operator forces comparison of values and type e.g.

0 == "";        // true
1 == "1";       // true
1 == true;      // true

0 === "";       // false
1 === "1";      // false
1 === true;     // false

If a function is called with a missing argument, the value of the missing argument is set to undefined. Undefined values can break your code. Assign default values to arguments.

The eval() function is used to run text as code. Because it allows arbitrary code to be run, it also represents a security problem.

JavaScript close a statement automatically at the end of a line. If a = 55 then the following function will return 550.

function myFunction(a) {
    var power = 10  
    return a * power
}

JavaScript will also allow you to break a statement into two lines like this:

function myFunction(a) {
    var
    power = 10;  
    return a * power;
}

But…

function myFunction(a) {
    var
    power = 10;  
    return
    a * power;
}

The function will return undefined! Why? Because JavaScript thinks you meant:

function myFunction(a) {
    var
    power = 10;  
    return;
    a * power;
}

JavaScript does not support arrays with named indexes. If you use a named index, when accessing an array, JavaScript will redefine the array to a standard object. After the automatic redefinition, array methods and properties will produce undefined or incorrect results:

var person = [];
person["firstName"] = "John";
person["lastName"] = "Doe";
person["age"] = 46;
var x = person.length;         // person.length will return 0
var y = person[0];             // person[0] will return undefined

JavaScript does not create a new scope for each code block. To believe that, run the below code, it will return 10 rather undefined.

for (var i = 0; i < 10; i++) {
    // some code
}
return i;

Putting your scripts at the bottom of the page body, lets the browser load the page first. While a script is downloading, the browser will not start any other downloads. In addition all parsing and rendering activity might be blocked.

Never Use Inline JavaScript. It’s not 1996! Instead, transfer this code to an external JS file and use “addEventListener/attachEvent” to “listen” for your desired event.

$('a#moreCornInfoLink').click(function () {
    alert('Want to learn more about corn?');
});

Exception Handling and Logging Best Practices

  • Always “Expect the Unexpected”. Exceptions should catch from specific to generic as mentioned in above section.
  • Return null for extremely common error cases instead of throwing an exception. By returning null in these cases, you minimize the performance impact to an app.
  • The stack trace begins at the statement where the exception is thrown and ends at the catchstatement that catches the exception. Be aware of this fact when deciding where to place a throw
  • Put a single catch (Exception ex) per thread/task.

Using Statement Best Practices

  • Using Statement provides convenient syntax that ensures the correct use of IDisposable
  • Within the usingblock, the object is read-only and cannot be modified or reassigned.
using (Font font1 = new Font("Arial", 10.0f)) 
{
    byte charset = font1.GdiCharSet;
}

Multiple instances of a type can be declared in a usingstatement:

using (Font font3 = new Font("Arial", 10.0f),
            font4 = new Font("Arial", 10.0f))
{
    // Use font3 and font4.
}

You can instantiate the resource object and then pass the variable to the using In this case, the object remains in scope after control leaves the usingblock even though it will probably no longer have access to its unmanaged resources.

Font font2 = new Font("Arial", 10.0f);
using (font2) // not recommended
{
    // use font2
}
// font2 is still in scope
// but the method call throws an exception
float f = font2.GetHeight();

You can use nested using statements like this:

using (var fileStream = new FileStream("ABC.pdf", FileMode.Create))
using (var document = new Document(PageSize.A4, marginLeft, marginRight, marginTop, marginBottom))
using (var pdfWriter = PdfWriter.GetInstance(document, fileStream))
{
// code
}

Note: You should declare the variables in the using-statement.

Constructor Best Practices

Here is the basic constructor overloading with optional parameter syntax:

namespace Dummy
{
    public class Something
    {
        private string myName;
        private int myIndex;
 
        public Something() : this("default"){}
 
        public Something(string name) : this(name, -1) {}
 
        public Something(string name, index)
        {
            myName = name;
            myIndex= index;
 
            DoStuff(); 
        }
 
        private void DoStuff()
        {
            // logic
        }
                    
        // rest of class definition    
}

This is especially a good design practice to initialize the static variables within static constructors instead of using constant variables.

Overloaded static constructors are dangerous when used to call other constructors, so try not to call other static constructor from within.

Use of keyword “base()” makes sure that the call is made to the base class. One can call any overloaded constructor of the base class this way:

public class in4DataGrid
{
public in4DataGrid(): base()
{
	// Some Code Here.
}
}

Comments and Documentation Best Practices

Provide a very brief summary of the method at its definition including list of all parameters with preconditions (cannot be null, must be within a certain range, etc.), return type. E.g. for following method the comment will be:

bool CreateThumbnails(System.Drawing.Image original, string fileName, string fileExtension)
/// <summary>
/// Creates the thumbnails.
/// Explaination (if required)
/// </summary>
/// <param name="original">The original (not null).</param>
/// <param name="fileName">Name of the file (not null).</param>
/// <param name="fileExtension">The file extension (not null).</param>
/// <returns>true if XXXX, false otherwise.</returns>

Note: There are many tools available on the internet for automatic documentation like GhostDoc, Sandcastle, Natural Docs, etc.

The class level comments should contain a brief summary of class’s working. You must separate classes by Partial for not similar code segments.

 /// <summary>
    /// Class level summary documentation goes here..
    /// </summary>
    /// <remarks>
    /// Longer comments can be associated with a type or member 
    /// through the remarks tag
    /// </remarks>
    /// <seealso cref="WebUI.ProductTab" />

Note: List of standard tags, which you may use for documentation, are provided at the following link:

http://www.codeproject.com/Articles/3009/C-Documenting-and-Commenting

LINQ Best Practices

For simple scenarios, I do prefer the extension method. e.g.

var males = Person.Where(c => c.IsMale);
vs
var males = from c in Person where c.IsMale select c;

Note: The first LINQ query results in “SELECT * FROM customer”. The WHERE clause is applied after the result set is returned. The second generates a real WHERE clause. The result set is a filter on the server before being sent to the client.

Often, query syntax offers more readability. e.g.

var filteredCustomers = 
       from c in Person
       join o in Orders on o.customerid = c.customerid
       where c.IsMale && c.Age > 30
       where o.IsPending
       select new {Person = c, Order = o};

Vs.

var filteredCustomers = Person
         	.Join(Orders,
              c => c.customerid,
              o => o.customerid,
              (c, o) => new { Customer = c, Order = o }
       )
       .Where(x => x.Customer.IsMale && x.Customer.Age > 30)
       .Where(x => x.Order.IsPending);

  • One nice advantage that returning IEnumerable<T> has over returning List<T> is that it gives better flexibility and maintainability. If you return List<T>, you’re tying yourself to that specific class now and forever. Any change will be a breaking change. If you return IEnumerable<T>, you’re guaranteeing that you’ll return something that the caller can enumerate over to get their data.
  • The LINQ to SQL data context is a very powerful wrapper around the database access code. The big deal comes when these LINQ to SQL objects are used outside of the data access layer. Allowing data access layer code to be used in your presentation layer (MVC) or business logic layer has risks. Use data transfer objects (DTOs) to pass information out of our data access layer instead of using the LINQ to SQL objects.
  • If you need only to read data through the data context and don’t need to edit the data, you should turn off ObjectTrackingEnabled property; doing so will turn off the unnecessary identity management of objects and help boost the application’s performance.
  • Remember that a compiled query could be costly when used for the first time. So, do ensure you use compiled queries only in situations where you need a query to be used repeatedly.
  • You should filter down your required data appropriately using DataLoadOptions.AssociateWith, so that only the data that is required is returned. Here is an example:
using (TestDataContext dataContext = new TestDataContext())
{
DataLoadOptions dataLoadOptions = new DataLoadOptions();
dataLoadOptions.AssociateWith<Employee>(emp => emp.Department.Where<Department>(dept => dept.DeptCode == 1));
dataContext.LoadOptions = dataLoadOptions;
}

You can also analyze how your LINQ queries have generated the corresponding SQL statements and monitor them in the Visual Studio IDE. To do this, you need to use the Log property of the data context as shown in the code snippet below:

using (TestDataContext dataContext = new TestDataContext())
{
#if DEBUG
dataContext.Log = Console.Out;
#endif 
}

HTML & CSS Best Practices

I will not go through the very basic stuff like “Always close the tags” or “Never Use Inline Styles”, etc.

  • We must always be sure to use the proper document structure, including the <!DOCTYPE html> doctype, and the <html>, <head>, and <body> elements. Without a doctype and these structural elements, pages will not render properly in every browser.
  • Images should always include the alt attribute. Screen readers and other accessibility software rely on the alt attribute to provide context for images.
  • We need to do our best to keep our code lean and to reduce markup. Additionally, we should use the HTML5 structural elements where suitable. e.g.
<div class="container">
    <article>
        <h1>Headlines Across the World</h1>
    </article>
</div>

It is highly recommended that use Firebug for Mozilla and Developer Tools for Chrome.

Choose a Great Code Editor. Here are some:

Bad Code

#aside #featured ul.news li a { ... }
#aside #featured ul.news li a em.special { ... }

Good Code

.news a { ... }
.news .special { ... }

Note: I highly recommend that you download the Web Developer Toolbar and use the “Validate HTML” and “Validate CSS” options continuously.

  • Use a CSS Reset; if you don’t do this, you won’t truly understand why your list items are receiving that extra bit of padding. Put the code below into your CSS file on top
html, body, div, span, 
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
img, ins, kbd, q, s, samp,
small, strike, strong, 
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td {
    margin: 0;
    padding: 0;
    border: 0;
    outline: 0;
    font-size: 100%;
    vertical-align: baseline;
    background: transparent;
}
body {
    line-height: 1;
}
ol, ul {
    list-style: none;
}
blockquote, q {
    quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
    content: '';
    content: none;
}
 
table {
    border-collapse: collapse;
    border-spacing: 0;
}

Note: Learn CSS3 as it has lot of new stuff and techniques.

Visual Studio Tips

  • <CTRL><K><D> formats the current document.
  • <CTRL><]> navigates to the matching bracket.
  • If you put the cursor on a line of code and use the <ALT><UP ARROW> key the line of code you have selected moves up. If you use the <ALT><DOWN ARROW> the line of code selected moves down.
  • If you select a piece of code and then use the key sequence <CTRL><M><H> you turn that region into a collapsible/expandable region. The key sequence <CTRL><M><U> will remove the collapsible region (it doesn’t delete the code, it just removes the icon that allows you to expand and collapse).
  • F12 key or the pop-up menu option Go To Definition helps the programmer to examine code into the method. Sometimes, you just want a quick look at the method. If you have installed Visual Studio 2013 there is a new keyboard shortcut <ALT><F12>, which will give you a preview of the method being called inline. You can use the <ESC> key to close the preview.
  • When you have multiple files open at the same time you may want a way to quickly move back and forth between two or three different locations in your code. If you have moved from one location to another you can use the keyboard sequence <CTRL><-> to move to the previous location and then you can return using <CTRL><SHIFT><->.
  • You can switch between Visual Studio opened tabs by <CTRL> <TAB> and <CTRL><SHIFT><TAB>.
  • EDIT à Navigate or <CTRL><,> feature in Visual Studio allows you to quickly find your required files and symbols.
  • <SHIFT><ALT><ENTER> to view code editor in Full Screen.
  • Visual Studio has the facility of built-in code snippets and many more shortcuts in VIEW and last segment of EDIT menu.