This website uses cookies. By using the website you agree with our use of cookies. Know more

Technology

Coding Standard in practice

Helping people writing clean code with some humour involved. A Nike Air shoes fan.
View All Posts
Coding Standard in practice

In this blog post, I explain why you should apply the Coding Standard practice and show how to configure a multi-project Microsoft Visual Studio solution to use source code analysers. So if you are not familiar with the Coding Standard practice, if you don't use an automated way to ensure your code follows the defined standards, or if you use it in .NET Framework and want to migrate to .NET Core, this is the right place to understand this practice.

During a new project set up at Farfetch, we found it difficult to get up-to-date information about how to apply code analysers in Visual Studio to ensure our code follows the team standard. So we have decided to share our learnings with the community.

Coding Standard

Coding Standard is a software development practice introduced in 1996 by the Extreme Programming (XP) framework. In this context, Coding Standard can be seen as the practice of applying coding rules and recommendations to promote code consistency and making the code easier to read and maintain.

Style guides, also known as code conventions, are one kind of coding rules. We can find style guides for almost every computer language. We can find some of them in several flavours, as happens with Java. If you search for Java style guide, you should get the official Java Code Conventions and the Google Java Style Guide. The language style guides are rarely used without modifications. They are normally used as the base when defining the team or project own style guide.

A project or a team style guide is the adoption of a language style guide with modifications to accommodate the project or team specifics. The Linux Kernel Style Guide is an example of a project style guide. 

Benefits from its usage

Besides the style guides which focus on the code appearance, there are also rules that focus on how the software is built. Those rules can target programming best practices, code smells, system functionalities or regulatory standards. Using the SEI CERT C Coding Standard Rules for Developing Safe, Reliable, and Secure Systems as an example, we can check how detailed the rules can be, and how hard it could be to ensure that all the rules are being followed. Luckily, we have static code analysis tools for rules compliance checking.

The Coding Standard practice gives us both technical and business benefits. From a technical perspective, it brings consistency across large and distributed teams, makes the code easier to understand and maintain, makes us comply with internal or regulatory standards, fosters collaboration and reduces the learning curve for newcomers. The code clarity and the usage of best practices simplify the code review process, making it easier to spot bugs. From a business perspective, fewer bugs and bugs detected earlier in the software development lifecycle mean higher productivity, software quality, and customer satisfaction. It also means lower long-term cost and accelerated time to market.

Being the global platform for luxury fashion, the Farfetch platform is composed of several APIs. Each API focuses on a different concern of the platform and is served by a vast number of services. This means that we could have a big number of teams contributing to the same API or service. At Farfetch, we try to get the best out of the Coding Standard practice. By using it, the code always looks as if it was written by the same team, has the same quality standards, follows common regulatory industry standards (such as the Payment Card Industry), and promotes internal open-source collaboration. 

Usage at Farfetch

The Farfetch technology platform is mostly composed of Microsoft .NET technologies. At Farfetch our .NET services are organised in Visual Studio solutions. A solution is typically composed of several C# projects and each project represents a different layer of the system. 

Each service has its own Git repository, which is connected to a Continuous Delivery (CD) pipeline. Teams commit their code to a feature branch repository that, after the review, is merged into the master branch. The CD pipeline has two different flows: one handles the feature branches, and the other handles the master branch commits. Only the master branch commits are sent to live. The APIs are also considered as a service. 

Because we have more than one team contributing to the same service (and this is indeed encouraged with our internal open-source initiative), we need to ensure the source code follows the defined style, best practices, and is free of bugs or code smells. To help us with that, we configured our solution to treat all coding violations as errors and to abort the compilation if errors are found. If the compilation/build is aborted when violations are detected, our CD pipelines will also be aborted since the compilation is one of the pipeline's steps.


As most of the platform uses Microsoft technologies, this article focuses on the Microsoft Visual Studio usage and related tools. The configurations presented in this article were successfully tested with Visual Studio 2017 and 2019.

Microsoft Source Code Analysis

Source code analysis in Microsoft products started in 2008 when Microsoft launched StyleCop and FxCop. These tools aimed to detect code style and programming rules violations. 

How these tools were made available has evolved over the years. In the beginning, they were distributed as standalone tools, then as a Visual Studio extension and lately as NuGet packages. 

.NET Compiler Platform

The introduction of the .NET Compiler Platform, also known as Roslyn, enhanced the ecosystem of code analysers and helped evolve it to include a wider set of related tools.

The compiler design incorporates the concepts of code analyser and code fixture. A code analyser is where the coding rules are implemented. A code fixture is a mechanism used by the integrated development environment (IDE) to show how to fix the offending code. It's possible to create our own code analysers and code fixtures. The code analysers are used by the compiler to check for coding rules violations. The analyser rules have a default severity associated with each. The default severity of a rule can be overridden at the project level in a ruleset file. 

Visual Studio has a particular window in which we could check for detected violations. Violations are grouped by their severity: info, warning, or error. Visual Studio comes with a set of code analysers and fixtures. An IDE prefix identifies the rules introduced by these code analysers.


If error type violations are found, it won't be possible to compile the project unless the violation is fixed or suppressed. It's possible to configure Visual Studio so that the warning type violations are treated as errors. This means warnings will also break the build. When violations are found, Visual Studio will try to present quick actions (implemented by the code fixtures) to fix or suppress the violation.

protected StructuresController(IMediator mediator)
{
   this.Mediator = mediator;
}


The violations suppression can be made at the method, class or project level.

Code analysers as NuGet packages

The new .NET Compiler Platform, and the release of the StyleCop and FxCop projects to the open-source community, led to the creation of new code analysers. Some of them handle a specific type of problem, while others have a general purpose. In this article, we use StyleCop, FxCop, Visual Studio Threading, Sonar, and XUnit analysers.

Although some code analysers are available as Visual Studio extensions, we recommend the installation as NuGet packages. With this approach, the analysers will be part of the project itself. This means all the project contributors will have to follow the same rules because they are defined at the project level. Additionally, we could have the pipelines fail when violations are found.

Visual Studio Solution Configuration

The way Visual Studio handles the analysers represents a challenge to us. At Farfetch, we work with multi-project solutions, which includes both production and testing code, and Visual Studio doesn't come with an easy way to share the analysers and its configurations across projects.

This means we have to add the packages manually and reproduce the configuration for every project we have. As you can imagine, this is tedious and error-prone work that doesn't follow the Don't Repeat Yourself principle. For instance, if the team decided to disable a rule globally, it would need to update the rule severity in the ruleset files for all projects.

Visual Studio's most recent versions, 2015 and newer, come with graphic user interface tools to help us configure the code analysers. However, unfortunately, these tools are not ready to use the analysers as NuGet packages or to be used in .NET Core projects.

Visual Studio Automation

To be able to manage the analysers package in just one place, and to ensure the packages are automatically added to new projects, we will benefit from the Directory.Build.props file to automate some Visual Studio behaviours. In this file, we've configured Visual Studio to treat warnings as errors and to define the ruleset file to use. We also use it to define a property that will allow us to distinguish between production and testing projects: a test project will be a project with "Test" in the name.

<Project>
  <PropertyGroup>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<CodeAnalysisRuleSet>$(SolutionDir)global.ruleset</CodeAnalysisRuleSet>
<IsTestProject>$(MSBuildProjectName.Contains('Test'))</IsTestProject>
  </PropertyGroup>
  <ItemGroup>
      <PackageReference Include="StyleCop.Analyzers"
Version="1.1.118" PrivateAssets="all" />
      <PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers"
Version="2.9.2" PrivateAssets="all" />
      <PackageReference
Include="Microsoft.VisualStudio.Threading.Analyzers"
Version="16.0.102" PrivateAssets="all" />
      <PackageReference Include="SonarAnalyzer.CSharp"
Version="7.3.1.5982" PrivateAssets="all" />
      <AdditionalFiles Include="$(SolutionDir)rulesets/stylecop.json">
          <Link>stylecop.json</Link>
      </AdditionalFiles>
  </ItemGroup>
  <Choose>
      <When Condition="'$(IsTestProject)' == 'true'">
          <ItemGroup>
              <PackageReference Include="xunit"
Version="2.4.1" PrivateAssets="all" />
              <PackageReference Include="xunit.runner.visualstudio"
Version="2.4.1" PrivateAssets="all" />
              <PackageReference Include="xunit.analyzers"
Version="0.10.0" PrivateAssets="all" />
              <PackageReference Include="coverlet.msbuild"
Version="2.3.0" PrivateAssets="all" />
          </ItemGroup>
      </When>
  </Choose>
</Project>



In the same file, we configure Visual Studio to link the stylecop.json configuration file to each project in the solution and specify the additional packages to be included in the test projects.

StyleCop Configuration

There are rules within StyleCop (such as UsingDirectivesMustBePlacedCorrectly) that can be customised. StyleCop expects the configuration to be placed into the stylecop.json file, placed under the project's root directory.

{
   "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json",
   "settings": {
       "orderingRules": {
           "usingDirectivesPlacement": "insideNamespace"
       }
   }
}



To make use of the same configuration across projects, we placed the file into the solution directory and configured Visual Studio to create links between the file and the projects. In Visual Studio we'll see a reference to the file in each project (this is a small price to pay). However, since it's a link, it doesn't matter where we make the change because the change will be reflected in the source file. 

Rule Set Configuration

By default, when an analyser is added, the default rules severity will be applied. We use the global.ruleset file to disable contradictory rules and rules that the team agreed not to follow. In the example below, we're disabling the IDE0003 rule by setting its action to None.

<?xml version="1.0" encoding="utf-8"?>
<RuleSet
Name="Microsoft.CodeAnalysis.CSharp.Features"
ToolsVersion="10.0">
    <Rules
AnalyzerId="Microsoft.CodeAnalysis.CSharp.Features"
RuleNamespace="Microsoft.CodeAnalysis.CSharp">
        <Rule Id="IDE0003" Action="None" />
   </Rules>
</RuleSet>


In this specific case, Visual Studio IDE and StyleCop have opposite rules that conflict with each other: the first asks to remove the 'this', and the second (after removing it) asks to add again the 'this'.

Violations Suppression

There will be times when a desirable coding rule will make sense globally but will create headaches in a specific context. To handle these situations, we can use the SuppressMessage attribute, or the #praga warning disable comments, to suppress the violations where we want to skip the rule. The suppression can be made at several scopes: class, method, etc. 

Violation suppression should be used with caution. In my team, we defined a process to handle when it is justified. When facing a violation, the developer will analyse the rule description and coding alternatives. If the rule or the alternatives are not applicable nor suitable, the developer will present a justification to the team. The team will then decide if they will go with the alternative, suppress the violations or entirely remove the rule. When the decision is to suppress the violation, the SuppressMessage attribute should be used and placed at the lowest scope possible.

In the code below, we have an example of a rule violation. The ServiceVersions property is breaking the CA2227 rule since we're providing a set property accessor (making it possible to change the collection content by changing its reference) while the rule states that collection properties should be read-only.

using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;

public sealed class SwaggerConfiguration
{
   public string ServiceDescription {get; set;}
   public string ServiceEndPoint {get; set;}
   public string ServiceName {get; set;}
   public IList<SwaggerConfigurationVersions> ServiceVersions {get; set;}
}



The SwaggerConfiguration class is used by the .NET Core Configuration mechanism to instantiate a class with data provided by a JSON configuration file, and this expects a set accessor so it can set the data. In this context, following the proposed alternative will prevent the team from taking advantage of this .NET Core feature, thus requiring them to implement this feature on their own and reinvent the wheel. Although the rule makes sense globally in this case, the team decided that the alternatives are not suitable and suppressed the violation with a SuppressMessage attribute.

public sealed class SwaggerConfiguration
{
  public string ServiceDescription {get; set;}
  public string ServiceEndPoint {get; set;}
  public string ServiceName {get; set;}

  [SuppressMessage("Usage", "CA2227", Justification = "The set must be present so the class could be automatically created")]
  public IList<SwaggerConfigurationVersions> ServiceVersions {get; set;}
}

Conclusion

Coding Standard is a programming practice introduced by XP to promote code consistency and to make the code easier to read and to maintain. As mentioned in this article, the Coding Standard has both technical and business benefits. The .NET Compiler Platform and the opening of some Microsoft projects, such as StyleCop and FxCop, to the open-source community led to the creation of new code analysis tools (analysers). Unfortunately, the current versions of Visual Studio do not provide a well suited graphic user interface to use the analysers in multi-projects or in .NET Core projects. In this article, we explained how we configure Microsoft Visual Studio to apply Coding Standard when initiating a new team project.
Related Articles