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 […]
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:
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:
Hardest part about merging PRs for me is making people write code in a style you want. #oss
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
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:
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:
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:
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:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Here’s the class after the reformatting has been applied:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
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:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
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:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
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:
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.
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.
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.
LikeLike