Last Updated: 9/30/2016
Time and time again, developers inherit legacy applications and criticize a former team member’s coding style. “On which planet does this coding cowboy live where this incoherent sequence of characters is deemed acceptable?!?”, you indignantly mutter to yourself. Without fail, I’m reminded of a personal favorite XKCD code quality cartoon:
The feature development you were initially assigned immediately takes a backseat to some unplanned refactoring. Through onlookers’ eyes, you spotted a “squirrel” in a sea of characters and are lackadaisically doggy-paddlin’ your way to it. What is one to do? Deadlines are looming, but the code needs attention. Surely, it’s going to take a fair amount of time to address.
This inconsistent styling problem is prominent everywhere, including open source communities. Peruse the issues and/or pull requests for some of the most active projects on GitHub, and you’ll see dialog of this nature. Understandably so, project maintainers strive to keep a clean, consistent code base. Until coding guidelines are clearly spelled out in a digestible “Contributing Guidelines” document, newcomers will inevitably submit pull requests with complete disregard to the style of the code surrounding theirs. And even then, quality contributions are no guarantee.
David Fowler, an exceptional Microsoft engineer for whom I have a great deal of respect, summed it up quite well in a recent tweet:
Enter CodeFormatter. CodeFormatter is a Roslyn-based analysis tool capable of adjusting C# and VB.NET code to conform to the standards of CoreFX, the foundation on which .NET Core flourishes. It’s also open source on GitHub, like many other recent Microsoft projects.
As described in the succinct installation instructions, download the desired release’s zip file and extract to a location of your choosing. I’ll be using the 1.0.0-alpha6 release, and I extracted the file’s contents to C:\Program Files (x86)\CodeFormatter.
To make running the executable (CodeFormatter.exe) easier, add the aforementioned folder path to the System-scoped Path environment variable:
There are a few things that drive me nuts in large C# applications. My first pet peeve is inconsistent positioning of the opening curly brace for constructs such as loops, if statements, and function & class declarations. If I had my way, each curly brace would appear below its corresponding construct; but, it’s more important to pick a style and to be consistent. A second styling concern that irks me is the inconsistent placement of
using declarations across files. This is a debate of whether the
using declarations should be placed inside or outside of
namespace declarations. If I had my way, they’d appear outside, or immediately before, the
namespace declaration. How can CodeFormatter address these pet peeves?
First, let’s see which rules are available:
By default, all of these rules are enabled. To explicitly enable those two rules corresponding to the fixes we hope to apply, use the following command:
CodeFormatter <insert_project_name_here.csproj> /rule+:BraceNewLine,UsingLocation,FormatDocument,NewLineAbove /rule-:Copyright,CustomCopyright,UnicodeLiterals,ExplicitVisibility,IllegalHeaders,ExplicitThis,ReadonlyFields,FieldNames /verbose
Note that I’ve enabled two other desired rules here as well: FormatDocument and NewLineAbove. For useful output regarding changes made to the code, verbose output has been enabled. I will be executing this against the *.csproj file for a very basic .NET 4.6.2 class library.
Here’s the style of code that keeps me awake at night; it’s a simple C# class before running the command above:
Here’s the class after the reformatting has been applied:
Development Workflow Integration
To weave CodeFormatter into your development workflow, one option is to invoke it from an MSBuild target in the *.csproj file of the class library. This will require unloading and manual editing of the project file; or, use the Productivity Power Tools 2015 extension’s Edit Project File option to eliminate a click in that process.
Determine which build target is most appropriate for your application. For this example, I’ve selected the BeforeBuild target:
Should the class library project get renamed down the road, we’re protected. This is why a reserved MSBuild property is used to represent the *.csproj file name.
The same output which would have appeared in the command shell is available in the IDE’s Output window:
Continuous Integration Build Considerations
For various reasons, this command probably shouldn’t execute during a CI build. Add a condition to the build target, such that it only executes when a particular variable’s value evaluates to true. Here’s an example:
When building locally in Visual Studio, the
IsLocalDev variable assumes its default value of true. If using a build system such as Visual Studio Team Services, explicitly set this variable to false in either the Visual Studio Build or the MSBuild task of the build definition. Here’s an example depicting the former of the two build tasks:
Though it wasn’t the focus of this blog post, VB.NET support is provided. To enable that support, append the following snippet onto the CodeFormatter command arguments list:
Lastly, this tool is tagged as an alpha product. Things aren’t 100% bullet proof yet; but, honestly, what is in the software industry? There are some known issues logged in the GitHub repository. Among the open issues, you’ll find that there’s no *.xproj project system support. If I were a betting man, this support won’t be made available due to the return to the *.csproj/MSBuild-based project system. Read more on that topic here.