Monday, November 26, 2012

The all new coding guidelines for C# 3.0, 4.0 and 5.0 have been published!

After 50000 downloads and the recent final release of Visual Studio 2012 / C# 5.0 it was about time to do a thorough update of the C# Coding Guidelines. Although most of the guidelines have been preserved, I’ve tried to rewrite several of them using a less formal and less verbose writing style. I’ve also improved the rational for some of them, shortened the introduction section, but added a refactoring heuristic I picked up from this blog post.

Other minor improvements include getting rid of the vague term identifier, applying the correct usage of the terms arguments and parameters, adding more cross-references between guidelines and adding various links to relevant articles. On the esthetic side, I’ve changed all code snippets to Consolas, reduced the line-spacing a bit, and changed the accent color to allow this version to stand out more from previous versions.

So which guidelines were changed?

  • Added a warning to AV1001 “Only create a constructor that returns a useful object” about potentially violating AV1000 and AV1561.
  • AV1008 “Mark classes that only contain static members as static” now promotes avoiding static classes at all rather than just marking it as static.
  • Added a reference to the Command Query Separation principle to AV1105 “Use a method instead of a property”.
  • Added a reference to the new .NET 4.5 read-only collection interfaces to AV1130 “Return an IEnumerable<T> or ICollection<T> instead of a concrete collection class”.
  • Renamed AV1135 “String, list and collection properties should never return a null reference” to include methods and parameters in addition to properties
  • Rephrased AV1140 “Consider replacing properties using primitive types to use rich value objects” to clarify that I was talking about domain-specific types.
  • Remove the incorrect examples from AV1515 “Don’t use "magic” numbers”
  • Renamed AV1521 “Initialize variables at the point of declaration” to make it clear we want variables to be declared and initialized as a late as possible.
  • Removed the 'method' part of AV1532 “Don’t use nested loops in a method” to say that nested loops should be avoid everywhere.
  • Renamed AV1535 “Add a block after all flow control keywords, even if it is empty” so that it includes concrete keywords rather than the vague 'flow control keywords'
  • Added a reference to AV1553 “Only use optional parameters to replace overloads” about Eric Lippert’s post on optional parameter corner cases.
  • Removed an example from AV1720 “Name methods using verb-object pair” because it conflicted with some of the LINQ extension methods introduced in .NET 3.0.
  • Rewrote and renamed AV1725 “Name namespaces according a well-defined pattern” to clearly explain the valid aspects of a namespace rather than emphasizing a particular pattern.
  • Changed the example in AV1735 “Use a verb or verb phrase to name an event” to use a generic event handler delegate.
  • Added a reference to to the .NET 4.5 read-only collection classes to AV1800 “Consider using Any() to determine whether an IEnumerable<T> is empty”. 
  • Added a statement to AV2207 “Don’t hardcode strings that change based on the deployment” that deployment-specific settings should be in the application configuration files rather than hard-coded or in a custom configuration file.
  • Added a remark to AV2400 “Use a common layout” not to interweave the from expressions with where conditions.

And what did I add?
The following guidelines have been added, of which, for obviously reasons, most are related to C# 5.0.

  • Added AV1137 "Define parameters as specific as possible" to prevent people from passing in entire objects even though a method might only need a specific property’s value.
  • Added AV1215 "Properly handle exceptions in asynchronous code" to explain the differences between exceptions raised in Actions and await blocks.
  • Added AV1523 "Initialize each variable on a separate line" to prevent some ugly code.
  • Added AV1739 "Use an underscore for irrelevant lamba parameters" as suggested by James Lanng.
  • Added AV1755 "Postfix asynchronous methods with Async of TaskAsync"
  • Added AV1820 "Only use async for low-impact long-running activities"
  • Added AV1825 "Prefer Task.Run for CPU intensive activities"
  • Added AV1830 "Beware of mixing up await/async with Task.Wait"
  • Added AV1835 "Beware of async/await deadlocks in single-threaded environments"

“But wait, didn’t you remove anything?”
Of course I did! Why do you think the number of pages went from 31 to 27? Well, yes, reducing line-spacing was part of that, but I actually did remove some guidelines.

  • Removed AV1120 "Use a public static readonly field to define predefined value objects " since I think it is not that important and not used very often.
  • Removed AV1245 “Don’t add extension methods to the same namespace as the extended class” because I think it is pretty farfetched if you create a class in a .NET namespace.
  • Removed AV1526 “Use an enumeration instead of a list of strings if the list of values is finite” since enumerations are so common these days, I hope nobody thinks of an alternative solution.
  • Merged AV1546 “Prefer conditional statements instead of simple if-else constructs” into AV1545 “Don’t use selection statements instead of a simple assignment or initialization”.
  • Removed AV1580 “Consider abstracting an external dependency or 3rd party component” because its essence is already covered by other guidelines and the introduction discussing SOLID principles.  
  • Removed AV2211 “Avoid suppressing specific compiler warnings” since I wonder how many developers even know how to suppress compiler warnings.
  • Removed AV2315 “Don’t use /* */ for comments” since we want to avoid inline comments anyhow.

You can download the PDFs of the document itself, the cheat sheet, the Visual Studio 2010/2012 Code Analysis rule sets, and the ReSharper 6/7 Code Analysis settings from the download page on the CodePlex landing page.

And don’t forget! If you have any feedback, additions or any remarks, contact me through Twitter or email.