Last Updated: 9/30/2016

Background

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:

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.

Initial Setup

zip file downloadAs 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:

system Path environment variable

 Standardizing Code

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:

available rules

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.

CLI output

Here’s the style of code that keeps me awake at night; it’s a simple C# class before running the command above:


namespace MessyClassLibrary {
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
public class Class1 {
public Class1() {
}
public string GetFullName(string firstName,
string lastName) {
return $"{firstName} {lastName}";
}
}
}

view raw

Class1.cs

hosted with ❤ by GitHub

Here’s the class after the reformatting has been applied:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MessyClassLibrary
{
public class Class1
{
public Class1()
{
}
public string GetFullName(string firstName,
string lastName)
{
return $"{firstName} {lastName}";
}
}
}

view raw

Class1.cs

hosted with ❤ by GitHub

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:


<Target Name="BeforeBuild">
<Exec Command="CodeFormatter $(MSBuildProjectFile) /rule+:BraceNewLine,UsingLocation,FormatDocument,NewLineAbove /rule-:Copyright,CustomCopyright,UnicodeLiterals,ExplicitVisibility,IllegalHeaders,ExplicitThis,ReadonlyFields,FieldNames /verbose"
ContinueOnError="false" />
</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:

build target output

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:


<PropertyGroup>
<IsLocalDev>true</IsLocalDev>
</PropertyGroup>
<Target Name="BeforeBuild" Condition="$(IsLocalDev) == true">
<Exec Command="CodeFormatter $(MSBuildProjectFile) /rule+:BraceNewLine,UsingLocation,FormatDocument,NewLineAbove /rule-:Copyright,CustomCopyright,UnicodeLiterals,ExplicitVisibility,IllegalHeaders,ExplicitThis,ReadonlyFields,FieldNames /verbose"
ContinueOnError="false" />
</Target>

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:

IsLocalDev variable

Miscellaneous Notes

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:

/lang:Visual Basic

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.

1 Comment »

  1. Great article, thx for sharing but I have one concern. It looks like the assemblies get recompiled every time CodeFormatter is called, right?
    Let’s say in my solution I have set up the pre-build step, hit F7, then I hit F7 again, I expect that msbuild does nothing but it is not the case. Looks like the file are always modified (probably the date) with CodeFormatter even if it was already done.

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s