Implementing .NET Coding Standards

Dr. Adam Kolawa considers some common pitfalls with .NET andexplains the coding standards that your development team can use to preventthese problems from occurring.

Dr. Adam

October 30, 2009

11 Min Read
ITPro Today logo

asp:Feature

 

Implementing .NET Coding Standards

 

By Dr. Adam Kolawa

 

With the .NET Framework, Microsoft has taken a big stepforward in making the Internet a true distributed computing platform. .NETprovides a complete framework that enables computers, devices, and services tocollaborate. The result is dynamic Web services that can be programmed in anylanguage without needing to worry about interoperability issues.

 

However, while the .NET Framework is dynamic and promisesto bring great advances in Web services, there are a few bumps on this rosyroad. The biggest is the fact that companies and development shops that chooseto migrate to .NET from their current programming language need a good deal oftime to ramp up to .NET. This is not a drawback of .NET, but rather a migrationissue. It takes time to learn a new way of doing things, and .NET, whiledynamic and innovative, is not easy to learn.

 

This issue of migration holds many hidden pitfalls. Ifyour development team has trouble migrating to .NET, you open your Web servicesapplications up to security gaps, functionality lapses, maintenance problems,and other issues of quality.

 

How then, can you bring your team up to speed and notbring these problems into your applications?

 

The answer is through .NET coding standards. Having thegroup adhere to a basic set of .NET coding standards allows you to maintain aninternal and basic group Service Level Agreement (SLA) that your .NET team mustmeet. It also gives programmers trying to learn .NET a way to understand whatcoding constructs in .NET are critical, and which are not terribly crucial fortheir immediate needs. As your team grows in its .NET skills, you can addfurther coding standards to increase the scope of the code analysis.

 

Although the examples used in this article illustrate C#coding standards, the same principles can be applied to any of the programminglanguages that target the .NET Framework, such as VB.NET and Managed C++. Thisarticle will consider some common pitfalls with .NET and explain the codingstandards that your development team can use to prevent these problems fromoccurring.

 

Optimizing Performance

Developers write code and want it to perform as quickly aspossible. For example, developers often try to optimize C# by using String. Stringis a constant object, which means that, by default, it can only be created andread, but never modified. Developers can use String when they do not think theywill want to modify it as the program is executed:

 

public class MakeMessage

 {

   public stringGetMessage (string[] words)

   {

       string message ="";

       for (int i = 0; i        {            message +=" " + words [i];        }        return message;    }  }   The segment of code above gets a new word every time itpasses through the loop. It appears that a new message string is created andthat the message is being appended, but these appearances are deceiving. Infact, the old memory under the message is being disregarded and new memory is beingallocated. The old information from the message is copied to the new memory andthen a new character is added at the end. The new memory created is one wordlonger than the old memory. The code itself is deceptive to read in thisinstance. Because it contains message +=, the code looks as if it willincrement the message. However, the message is actually being created fromscratch each time.  .NET developers working with C# need to understand thedifference between String and StringBuilder. StringBuilder is a dynamic object.Because it can be modified, StringBuilder can truly be appended, rather thanmerely giving the false appearance of being appended. Developers can useStringBuilder in performance-critical sections of code, such as loops.   In the following example, StringBuilder is used to modifythe string inside the loop:  public string GetMessage (string[] words)  {      StringBuilder message= new StringBuilder();     for (int i = 0; i      {          message.Append(" ");          message.Append(words[i]);      }      returnmessage.ToString(); }   Therefore, developers should define the message asStringBuilder rather than String in situations where they will want to modifythe code. Developers will then be able to use the method Append to modify thememory without creating new memory each time through the loop.  Optimizing Memory Developers want to optimize memory in their applications,but how do they get rid of chunks of memory that are no longer needed?   The problem occurs when there are pointers in the programthat refer to the chunk of memory. They are essentially forgotten pointersbecause the memory is no longer needed. The pointers are useless, and thedeveloper did not intend to keep them, but they remain in the program becausethe developer neglected to null them.   In the following C# example, we have the functionMakeSplashImage. We assume it calls new and uses a lot of memory. This functionresult can be a display or whatever else we want. We are sending the memoryreference for bigSplashImage to the function that displays it. After the imageis displayed, the memory is really not needed in the program:  public class GUI{ public static void Main(string[]args)  {      GraphicsbigSplashImage = MakeSplashImage();     DisplayMomentarily(bigSplashImage);      while(MoreProcessInput())     {          Process();     }  } }   However, notice in the above example that the referencepointer has not been nulled. Therefore, developers who want to avoid leavingunwanted references in their .NET programs should zero these references as soonas they no longer need them:  public class GUI{public static void Main (string[] args)  {      GraphicsbigSplashImage = MakeSplashImage();     DisplayMomentarily(bigSplashImage);      bigSplashImage =null;      while(MoreProcessInput())     {          Process();     }  } }   Memory issues are very common when developers usetemporary variables in .NET. When they forget to zero their temporaryvariables, they end up with what essentially amounts to a memory leak. Therefore,nullify temporary references to objects taking large amounts of memory as soonas they are no longer needed.  Optimizing External Resource Usage When programming in .NET, developers need to be aware thatthere are many layers of code working underneath them. Though developers may bedealing mainly with high-level language performing complicated functions, thelayers of code underneath that language are performing a host of other functions.These layers will behave differently depending on what is done to the code atthe upper level.   The lower layers of code are vital to the properfunctioning of an application; they are the behind-the-scenes workers that makehigh-level functionality possible. If these hidden layers are ignored, theywill most likely come back to cause problems in the application.   One lower layer of code that cannot be ignored is thecommunication with external resources. There is a central rule that shouldguide all interactions with external resources. Simply put, if an externalresource is opened, it should be closed as soon as it is finished being used.The following coding example deals specifically with file inputs, which arejust one type of external resource. However, the lesson from this exampleapplies to interactions with any external resources. Notice that this C# codelooks as if it makes a clean exit:  public class ReadFile{ public static stringRead(String path)  {      StreamReader reader =new StreamReader(path);      String contents =reader.ReadToEnd();     reader.Close();     return contents;  } }   However, the code above is deceptive: The reader.Closecommand does not make a clean exit. Whether talking to a database, openingfiles, opening sockets, or sending instructions to the screen, developers needto close any external resources they have opened. The dangerous aspect ofdealing with external resources is that when developers write a piece of codesuch as the aforementioned segment, it seems to run well. However, developersmay encounter an error when dealing with an external resource.   In a case such as the above, the code will throw anexception indicating a serious problem. Exceptions can transfer control todifferent parts of the program. In the previous example, if the methodReadToEnd throws an exception, control will be transferred out of the methodread and the file will not be closed.   In this situation, developers may choose to handle theexception and ignore the problem. However, they should stop to consider thatthe exception might have come from the interactions with external resources. Ifdevelopers merely handle the exception, they will face the strong possibilityof a resource leak. In other words, they will run out of resources at somepoint, which means they will not be able to open files or sockets and will nothave access to the database.   If the code throws exceptions when using externalresources, developers need to write a finally block. The finally block willalways be executed, regardless of whether code is exited through exceptions orthrough normal execution. When the finally block is used, developers areguaranteed their code will clean up after them by closing all of their externalresources. Therefore, developers should always exit code cleanly by using thefinally block:  public class ReadFile{public static String Read(String path)  {      StreamReader reader =null;      try     {          reader = newStreamReader(path);           string contents= reader.ReadToEnd();         return contents;      }      finally     {          if (reader !=null)          {              reader.Close();         }      }  } }   The segment of code above is an example of how to clean upin the finally block rather than in the original code. The finally block isinserted just before the reader.Close command. Developers now know that theywill be able to close the external resources and exit the code. They will alsobe able to open the external resources the next time they need to use them.Using the finally block guarantees that developers will not leak resources. Therefore,it is useful to write a finally block to clean up when dealing with externalresources.  Using Implicit Cast Operators When using implicit cast operators, developers must beaware of all potential consequences. For example, errors in the code can stemfrom the improper use of Vector and Figure classes in conjunction with implicitcast operators:  using System;  public class Figure {      public voidTransform(double d)      {          //this methodresize figure with d factor     }      public voidTransform(Vector v)      {          //this methodmoves figure using vector     }  }  public class Vector {      public static implicitoperator double(Vector v)      {          returnMath.Sqrt(v.x * v.x + v.y * v.y);      }      private double x;      private double y;      public Vector(doublex, double y)      {          this.x = x;          this.y = y;      }      public static void Main()     {          Figure f = newFigure();         Vector v = newVector(1, 1);          f.Transform(v);      }      //...  }   As seen in the code above, the developer used the classVector with an implicit cast operator to convert Vector into its length asdouble. In another part of this code, a Figure class provides methods for itsTransformations.   In its current state, calling Transform on the Figureobject with a Vector object as an argument causes figure translation. However,if another programmer removes the method Transform(Vector)and is not aware of the implicit cast operator for the Vector class, the codewill behave improperly:  using System;  public class Figure {      public voidTransform(double d)      {          //this methodresize figure with d factor     }  }  public class Vector {      public staticimplicit operator double(Vector v)      {          returnMath.Sqrt(v.x * v.x + v.y * v.y);      }      private double x;      private double y;      public Vector(doublex, double y)      {          this.x = x;          this.y = y;      }      public static void Main()     {          Figure f = newFigure();         Vector v = newVector(1, 1);          f.Transform(v);      }      //...  }   There is no error caused by the missing Transform(Vector)method. Instead, the Transform(double) method iscalled and Figure is scaled with vector length factor instead of beingtranslated.   If a developer changes the code design so that an implicitcast operator is not necessary, the problems shown previously will not occur.For example, a developer may instead use an explicit cast operator, as shownbelow:  public static explicit operator double(Vector v) { return Math.Sqrt(v.x *v.x + v.y * v.y); }  Object-oriented Programming Object-oriented programming (OOP) makes code reusable,easily maintainable, and better organized. However, there are a number ofpitfalls; for example:  public class BankAccount {    public int _balance;  }   The class BankAccount is used to represent a bank account,but the variable used to represent the balance has been made public. Eventhough declaring the variable public is legal according to the .NET framework,it makes the code very difficult to modify and improve. There is a safer way ofwriting the code and achieving the same effect:  public class BankAccount {    private int _balance;    public int Balance   {        get       {            return_balance;        }        set       {            _balance = value;        }    }  } }   Here, the _balance variable has been declared private, anda public property has been defined to access it. The code is now very easy tomaintain because you can change the BankAccount implementation without havingto change any of the client code.   For example, developers can make the BankAccount objectthread-safe just by adding synchronization to get/set Balance property methods.Note that none of the other methods that may be using BankAccount objects needto be modified in this case. Therefore, developers should declare theirvariables private.  Conclusion Coding standards are a vital and important errorprevention tool, but they must be used regularly, even religiously, in order tobe effective. This is especially true as development projects become more andmore complex in an effort to meet consumer demand for better features and morefunctionality. Implementing and using coding standards early,and enforcing them automatically throughout the development lifecycle, resultsin many outstanding product benefits.  Dr. Adam Kolawa isthe co-founder and CEO of Parasoft, aleading provider of Automated Error Prevention (AEP) software solutions. Kolawa syears of experience with various software development processes has resulted inhis unique insight into the high-tech industry and the uncanny ability tosuccessfully identify technology trends. As a result, he has orchestrated thedevelopment of several successful commercial software products to meet growingindustry needs to improve software quality - often before the trends have beenwidely accepted. Kolawa, co-author of BulletproofingWeb Applications (Hungry Minds, 2001), has contributed to and writtenover 100 commentary pieces and technical articles for publications such as The Wall Street Journal, CIO, Computerworld,Dr. Dobb s Journal, and IEEE Computer; he has also authored numerousscientific papers on physics and parallel processing. His recent mediaengagements include CNN, CNBC, BBC, and NPR. Kolawa holds a Ph.D. intheoretical physics from the CaliforniaInstitute of Technology, and has been granted 10 patents for his recentinventions. In 2001, Kolawa was awarded the Los AngelesErnst & Young s Entrepreneur of the Year Award in the software category.        

Read more about:

Microsoft
Sign up for the ITPro Today newsletter
Stay on top of the IT universe with commentary, news analysis, how-to's, and tips delivered to your inbox daily.

You May Also Like