For years, I have used a tag line as part of my signature on online forums. It says, “Code as if the person that will modify your code is a crazy lunatic that knows where you live. That person is probably you.” I don’t know who to attribute this saying to, but adhering to it will help you and your team members from going insane.
This article is published from the DNC Magazine for Developers and Architects. Download this magazine from here [PDF] or Subscribe to this magazine for FREE and download all previous and current editions.
The primary thing this tag line is telling us is to use good coding guidelines. Note that I don’t use the term “coding standards”. I do this for a reason. A standard is a rule. A guideline is a recommendation. Those are very different things. A rule is strict and shouldn’t be broken. A guideline is more of a suggestion, albeit, a strong suggestion.
What exactly is a coding guideline?
It’s a group of suggestions on how to write code. Some people say that if there is more than one person writing code on a project, then you should have guidelines. But if you reread the quote in the first paragraph above, you’ll see that coding guidelines also apply to the solo developer. They help keep you sane when you look back at the code you wrote a year, a month, or even a week ago. You’ve seen this code. It makes you say, “Who wrote this?” and then you realize it was you.
Each line of code is written once and read many times. Not read by the computer, but read by a human. You should be able to understand each line of code by reading it, not by reading comments. Coding guidelines help us with this by specifying things like the amount of white space, how to name variables and classes, or what makes a proper comment.
Coding guidelines also help ensure that code does its job well, is easy to maintain, and easy to debug.
Framework Design Guidelines
One of the most comprehensive guidelines for .NET code is the “Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries”. Originally published as a book (and still available in book form), it is now also available for free at https://msdn.microsoft.com/en-us/library/ms229042(v=vs.110).aspx.
Originally published as a guide for Microsoft to create the .NET Framework, these guidelines primarily target developers creating libraries for other developers to consume. But they also contain good information that you can use in your everyday work.
The guidelines are divided into seven different categories. Each category is in turn broken down into several guidelines. Each one could have suggestions such as do this, don’t do that, avoid that, or consider that. Some also have conflicting advice from one of the authors, which emphasizes these are not standards.
Here are the guidelines you’ll find:
Naming Guidelines – These guidelines give ideas on how to name assemblies, namespaces, types, and members in class libraries. They are further broken down into Capitalization Conventions, General Naming Conventions, Names of Assemblies and DLLs, Names of Namespaces, Names of Classes, Structs, and Interfaces, Names of Type Members, Naming Parameters, Naming Resource.
Example: Names of Namespaces – DO prefix namespace with a company name to prevent namespaces form different companies from having the same name. DO NOT use organizational hierarchies as the basis for namespace hierarchies. CONSIDER using plural namespace names where appropriate (System.Collections instead of System.Collection).
Type Design Guidelines – These guidelines cover several areas such as Choosing Between Class and Struct, Abstract Class Design, Static Class Design, Interface Design, Struct Design, Enum Design, and Nested Types.
Example: Interface Design – DO define an interface if you need some command API to be supported by a set of types that includes value types. CONSIDER defining an interface if you need to support its functionality on types that already inherit from some other type. AVOID using interfaces with no members.
Member Design Guidelines – Suggestions for Member Overloading, Property Design, Constructor Design, Event Design, Field Design, Extension Design, Operator Overloads, and Parameter Design.
Example: Field Design – DO NOT provide instance fields that are public or protected. DO use constant fields for constants that will never change.
Designing for Extensibility – Covers Unsealed Classes, Protected Members, Events and Callbacks, Virtual Members, Abstractions, Base Classes for Implementing Abstractions, and Sealing.
Example: Events and Callbacks – CONSIDER using callbacks to allow users to provide custom code to be executed by the framework. AVOID using callbacks in performance-sensitive APIs.
Design Guidelines for Exceptions – Recommendations for Exception Throwing, Using Standard Exception Types, Exceptions and Performance.
Example: Exception and System Exception – DO NOT throw System.Exception or System.SystemException. AVOID catching System.Exception or System.SystemException except in top-level exception handlers.
Usage Guidelines – Suggestions for working with Arrays, Attributes, Collections, Serialization, System.Xml Usage, and Equality Operators.
Example: Guidelines for Collections – DO NOT use weakly typed collections in public APIs. DO NOT use Hashtable or Dictionary
Common Design Patterns – Recommendations for Dependency Properties and Dispose Pattern.
Example: Dispose Pattern – DO implement the Basic Dispose Pattern on types containing instances of disposable types. CONSIDER implementing the Basic Dispose Pattern on classes that themselves don’t hold unmanaged resources or disposable objects but are likely to have subtypes that do.
The guidelines themselves go into explanations about each of the recommendations. These should be required reading for all .NET developers, but at a minimum, you should be familiar with where to find the guidelines for when you need a bit of help with areas they cover.
At the other end of the spectrum from Framework Design Guidelines are guidelines that more directly target every day application development. They don’t provide the detail of the Framework Design Guidelines (which weigh in at 480 pages), but do cover some of the same topics.
There is no one set of guidelines here. In fact, a web search on “.NET coding guidelines” returned over 17 million results. A number that large makes it difficult to decide which guideline to use. There is one in the search results that I’ve used in the past. You can find the Aviva Solutions guidelines ready to use at https://csharpguidelines.codeplex.com/. Community suggestions are also accepted.
Like the Framework Design Guidelines, the Aviva guidelines cover a number of areas. However they don’t go into the same amount of detail.
Class Design Guidelines – Suggestions on how to name and design a class. Examples: A class or interface should have a single purpose. Use an interface to decouple classes from each other.
Member Design Guidelines – Class members are things like properties and methods. These guidelines help you use them better. Examples: Allow properties to be set in any order. A method or property should do only one thing.
Miscellaneous Design Guidelines – Things that don’t fit in the other categories. Examples: Throw the most specific exception that is appropriate. Evaluate the result of a LINQ expression before returning it.
Maintainability Guidelines – Maintainability is one of the primary reasons to have coding guidelines. This section has sage advice on things you should do to make your code maintainable. Examples: Don’t use “magic” numbers. Declare and initialize variables as late as possible.
Naming Guidelines – Naming a property, method, class, variable, etc is one of the hardest things we do as developers. Here you get suggetions on how to pick good names. Examples: Name a member, parameter, or variable according to its meaning and not its type. Name methods using verb-object pair.
Performance Guidelines – Sometimes performance isn’t all that critical to your application. But when it is, refer to this section. Examples: Only use async for low-intensive long-running activities. Beware of mixing up await/async with Task.Wait.
Framework Guidelines – Are you building libraries and frameworks for others? Even if you’re not, you’ll make your own code better. Examples: Don’t hardcode strings that change based on the deployment. Only use the dynamic keyword when talking to a dynamic object.
Documentation Guidelines – Wait, do we really need documentation in today’s Agile world? Well, yes, especially if other developers will consume our code. Examples: Write MSDN style documentation. Avoid inline comments.
Layout Guidelines – Laying out your code in a logical consistent manner aids readability. Examples: Order and group namespaces according to the company. Be reluctant with #region.
The Aviva Solutions guidelines total 33 pages at the time I’m writing this. A far cry from Framework Design Guidelines. This makes them much easier to adopt and target applications, something most of us work on every day.
At this point, you may be wondering how to adopt guidelines for your team. It’s quite easy. First, your team needs to agree on a set of guidelines. I recommend you adopt an already existing set rather than adopt your own.
Once you have your guidelines in place, make sure you understand them. At first, you’ll get some things wrong. Don’t worry about this. Over time, you’ll get better at following your guidelines.
Conduct informal code reviews. This allows other team members to help find issues and things that violate the guidelines. If you use TFS for version control, you can use the Request Code Review feature. If you use Git, then use Pull Requests. If you’re already doing code reviews then you may want to add guidelines compliance. (Note that I’ll discuss code reviews in more detail in my next column)
Finally, read (yes, I’m suggesting you read them) and be familiar with the Framework Design Guidelines, even for application development. Have them bookmarked in your browser so you can easily refer to them.
Visual Studio Tooling
There are several tooling options for Visual Studio that can assist with writing better code. These tools not only help you follow some coding guidelines but they also run static code analysis to help pinpoint other potential issues. Before talking about specific tools, I should probably discuss static code analysis.
Static Code Analysis
All the testing we do on code - unit, function, performance, and others, all test against code as it is executed. Static Code Analysis looks at the actual code itself to find possible errors that may not manifest themselves until runtime.
How this works from inside Visual Studio is that as you write code, it is compiled in the background and then the IL code is analyzed for these potential issues. You are probably familiar with FXCop. This tool did it’s analysis externally from Visual Studio. There are now better tools as we’ll see in a moment.
These tools use a set of configurable rules that typically look at things such as:
Design – Rules are applied to detect potential design flaws. These types of errors typically do not affect the execution of your code.
Globalization – Rules that detect missing or incorrect usage of information related to globalization and localization.
Naming – Detection of things like incorrect casing, cross language keyword collisions (say between C# and VB), names of types, members, parameters, namespaces, etc.
Performance – Detect elements in assemblies that will degrade performance.
Security – Identifies areas in your assemblies that could be vulnerable to malicious users or code.
Usage – Rules that detect potential flaws in your assemblies that can affect code execution.
Maintainability – These rules detect maintenance issues.
Reliability – Rules that detect incorrect thread or memory usage.
Many of the rules in these tools are based on Microsoft’s Framework Design Guidelines.
Getting back to Visual Studio
Now, getting back to Visual Studio, let’s discuss some of these tools. You’re probably already familiar with Resharper so I won’t spend any time discussing. But there is feature that was new in Visual Studio 2015 called Diagnostic Analyzers and are made possible by the awesomeness of the Roslyn compiler.
To install a Diagnostic Analyzer, select Tools -> Extensions and Updates then make sure Online is selected. Perhaps the most recommended analyzer is Code Cracker for C#. So, type Code Cracker into the search box then install it. However, if you are using SonarQube to do any analysis, I recommend you select SonarLint instead.
All these tools work by displaying squiggles under code that is suspect and providing a way to look at options to fix the code. The beauty of how they work is that it just happens as you type code, making the entire process quite painless. In the screenshot, the analyzer identified an issue. The suggestion dialog was displayed when I clicked on the lightbulb.
Having a coding standard will help ensure your code feels familiar and is easier to debug and maintain, even when written by different developers. I can tell you from experience, that guidelines work. I recommend them for teams of every size, even one-man shops.
Using static analysis tools such as Resharper or diagnostic analyzers will take your coding standards to the next level.
Coding guidelines are just one of the many tools you should have available in your toolshed. By using them, you will not become a crazy lunatic and help ensure that your code is lush, green, and vibrant.
About Software Gardening
Comparing software development to constructing a building says that software is solid and difficult to change. Instead, we should compare software development to gardening as a garden changes all the time. Software Gardening embraces practices and tools that help you create the best possible garden for your software, allowing it to grow and change with less effort.
Thanks to Damir Arh for reviewing this article.