Бруно Лоуренсо Феррейра, старший инженер-программист - .NET.

Этот пост изначально был опубликован в нашем блоге F-Tech. Приходите посмотреть здесь :-)

В этом сообщении блога я объясняю, почему вам следует применять практику Coding Standard, и показываю, как настроить многопроектное решение Microsoft Visual Studio для использования анализаторов исходного кода. Поэтому, если вы не знакомы с практикой Coding Standard, если вы не используете автоматизированный способ обеспечения соответствия вашего кода определенным стандартам или если вы используете его в .NET Framework и хотите перейти на .NET Core, это подходящее место, чтобы понять эту практику.

Во время нового проекта, созданного в Farfetch, нам было трудно получить актуальную информацию о том, как применять анализаторы кода в Visual Studio, чтобы гарантировать, что наш код соответствует стандарту группы. Поэтому мы решили поделиться своими знаниями с сообществом.

Стандарт кодирования

Coding Standard - это практика разработки программного обеспечения, введенная в 1996 году фреймворком Extreme Programming (XP). В этом контексте Coding Standard можно рассматривать как практику применения правил и рекомендаций кодирования для обеспечения согласованности кода и облегчения чтения и сопровождения кода.

Руководства по стилю, также известные как соглашения о коде, представляют собой один из видов правил кодирования. Мы можем найти руководства по стилю практически для каждого компьютерного языка. Мы можем найти некоторые из них в нескольких вариантах, как это происходит с Java. Если вы ищете руководство по стилю Java, вы должны получить официальные Соглашения о коде Java и Руководство по стилю Google Java. Руководства по языковым стилям редко используются без изменений. Обычно они используются в качестве основы при определении руководства по стилю команды или проекта.

Проект или руководство по командному стилю - это принятие руководства по языковому стилю с изменениями, соответствующими специфике проекта или команды. Руководство по стилю ядра Linux является примером руководства по стилю проекта.

Преимущества от его использования

Помимо руководств по стилю, в которых основное внимание уделяется внешнему виду кода, существуют также правила, касающиеся создания программного обеспечения. Эти правила могут быть нацелены на лучшие практики программирования, запахи кода, системные функции или нормативные стандарты. Используя в качестве примера Стандартные правила кодирования SEI CERT C для разработки безопасных, надежных и защищенных систем, мы можем проверить, насколько подробными могут быть правила и насколько сложно обеспечить соблюдение всех правил. К счастью, у нас есть инструменты статического анализа кода для проверки соответствия правилам.

Практика Coding Standard дает нам как технические, так и бизнес-преимущества. С технической точки зрения, это обеспечивает согласованность между большими и распределенными командами, упрощает понимание и поддержку кода, заставляет нас соответствовать внутренним или нормативным стандартам, способствует сотрудничеству и сокращает время обучения для новичков. Ясность кода и использование передовых методов упрощают процесс проверки кода, облегчая обнаружение ошибок. С точки зрения бизнеса, меньшее количество ошибок и ошибок, обнаруженных на ранних этапах жизненного цикла разработки программного обеспечения, означает более высокую производительность, качество программного обеспечения и удовлетворенность клиентов. Это также означает более низкие долгосрочные затраты и ускорение вывода на рынок.

Платформа Farfetch, являющаяся глобальной платформой для роскошной моды, состоит из нескольких API. Каждый API ориентирован на разные задачи платформы и обслуживается огромным количеством сервисов. Это означает, что у нас может быть большое количество команд, работающих над одним и тем же API или сервисом. В Farfetch мы стараемся извлечь максимум из практики Coding Standard. При его использовании код всегда выглядит так, как если бы он был написан одной и той же командой, имеет одинаковые стандарты качества, соответствует общим отраслевым стандартам регулирования (таким как Индустрия платежных карт) и способствует внутреннему сотрудничеству с открытым исходным кодом.

Использование в Farfetch

Технологическая платформа Farfetch в основном состоит из технологий Microsoft .NET. В Farfetch наши .NET-службы организованы в виде решений Visual Studio. Решение обычно состоит из нескольких проектов C #, и каждый проект представляет собой отдельный уровень системы.

У каждой службы есть собственный репозиторий Git, который подключен к конвейеру Непрерывной доставки (CD). Команды передают свой код в репозиторий функциональной ветки, который после проверки объединяется в основную ветку. У конвейера CD есть два разных потока: один обрабатывает ветки функций, а другой обрабатывает фиксации основной ветки. В работу отправляются только коммиты основной ветки. API также считаются сервисом.

Поскольку у нас есть несколько команд, которые вносят свой вклад в один и тот же сервис (и это действительно поощряется нашей внутренней инициативой с открытым исходным кодом), нам необходимо убедиться, что исходный код соответствует определенному стилю, лучшим практикам и не содержит ошибок или запахов кода. . Чтобы помочь нам в этом, мы настроили наше решение так, чтобы все нарушения кодирования трактовались как ошибки и прерывались при обнаружении ошибок. Если компиляция / сборка прерывается при обнаружении нарушений, наши конвейеры CD также будут прерваны, поскольку компиляция является одним из этапов конвейера.

Поскольку большая часть платформы использует технологии Microsoft, в этой статье основное внимание уделяется использованию Microsoft Visual Studio и связанных с ней инструментов. Конфигурации, представленные в этой статье, были успешно протестированы с Visual Studio 2017 и 2019.

Анализ исходного кода Microsoft

Анализ исходного кода в продуктах Microsoft начался в 2008 году, когда Microsoft запустила StyleCop и FxCop. Эти инструменты предназначены для обнаружения нарушений стиля кода и правил программирования.

То, как эти инструменты стали доступными, изменилось с годами. Вначале они распространялись как отдельные инструменты, затем как расширение Visual Studio, а затем как пакеты NuGet.

Платформа компилятора .NET

Внедрение платформы .NET Compiler Platform, также известной как Roslyn, расширило экосистему анализаторов кода и помогло развить ее, включив в нее более широкий набор связанных инструментов.

Дизайн компилятора включает в себя концепции анализатора кода и приспособления кода. В анализаторе кода реализуются правила кодирования. Приспособление кода - это механизм, используемый интегрированной средой разработки (IDE), чтобы показать, как исправить ошибочный код. Возможно создание собственных анализаторов кода и фикстур кода. Анализаторы кода используются компилятором для проверки нарушений правил кодирования. Правила анализатора имеют степень серьезности по умолчанию, связанную с каждым из них. Уровень серьезности правила по умолчанию может быть изменен на уровне проекта в файле набора правил.

В Visual Studio есть специальное окно, в котором мы можем проверить обнаруженные нарушения. Нарушения сгруппированы по степени серьезности: информация, предупреждение или ошибка. Visual Studio поставляется с набором анализаторов кода и приспособлений. Префикс IDE определяет правила, вводимые этими анализаторами кода.

При обнаружении нарушений типа ошибки будет невозможно скомпилировать проект, пока нарушение не будет исправлено или подавлено. Visual Studio можно настроить так, чтобы нарушения типа предупреждения обрабатывались как ошибки. Это означает, что предупреждения также нарушат сборку. При обнаружении нарушений Visual Studio попытается представить быстрые действия (реализованные с помощью фикстур кода) для исправления или подавления нарушения.

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

Подавление нарушений может производиться на уровне метода, класса или проекта.

Анализаторы кода в виде пакетов NuGet

Новая платформа компилятора .NET и выпуск проектов StyleCop и FxCop для сообщества разработчиков ПО с открытым исходным кодом привели к созданию новых анализаторов кода. Некоторые из них решают задачи определенного типа, другие - общего назначения. В этой статье мы используем анализаторы StyleCop, FxCop, Visual Studio Threading, Sonar и XUnit.

Хотя некоторые анализаторы кода доступны как расширения Visual Studio, мы рекомендуем установку в виде пакетов NuGet. При таком подходе анализаторы станут частью самого проекта. Это означает, что все участники проекта должны будут следовать одним и тем же правилам, поскольку они определены на уровне проекта. Кроме того, при обнаружении нарушений конвейеры могут выйти из строя.

Конфигурация решения Visual Studio

То, как Visual Studio обрабатывает анализаторы, представляет для нас проблему. В Farfetch мы работаем с решениями для нескольких проектов, которые включают в себя как производственный, так и тестовый код, а Visual Studio не предлагает простого способа совместного использования анализаторов и их конфигураций в проектах.

Это означает, что мы должны добавлять пакеты вручную и воспроизводить конфигурацию для каждого имеющегося у нас проекта. Как вы понимаете, это утомительная и подверженная ошибкам работа, которая не соответствует принципу «Не повторяйся». Например, если группа решила отключить правило глобально, ей потребуется обновить серьезность правила в файлах набора правил для всех проектов.

Последние версии Visual Studio, 2015 г. и новее, поставляются с инструментами графического пользовательского интерфейса, которые помогают нам настраивать анализаторы кода. Однако, к сожалению, эти инструменты не готовы к использованию анализаторов в качестве пакетов NuGet или для использования в проектах .NET Core.

Автоматизация Visual Studio

Чтобы иметь возможность управлять пакетом анализаторов в одном месте и гарантировать автоматическое добавление пакетов в новые проекты, мы воспользуемся файлом Directory.Build.props для автоматизации некоторых действий Visual Studio. В этом файле мы настроили Visual Studio для обработки предупреждений как ошибок и определения файла набора правил для использования. Мы также используем его для определения свойства, которое позволит нам различать производственный и тестовый проекты: тестовый проект будет проектом с «Test» в названии.

<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>

В том же файле мы настраиваем Visual Studio, чтобы связать файл конфигурации stylecop.json с каждым проектом в решении и указать дополнительные пакеты, которые будут включены в тестовые проекты.

Конфигурация StyleCop

В StyleCop есть правила (например, UsingDirectivesMustBePlacedCorrectly), которые можно настроить. StyleCop ожидает, что конфигурация будет помещена в файл stylecop.json, расположенный в корневом каталоге проекта.

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

Чтобы использовать одну и ту же конфигурацию в проектах, мы поместили файл в каталог решения и настроили Visual Studio для создания связей между файлом и проектами. В Visual Studio мы увидим ссылку на файл в каждом проекте (это небольшая цена). Однако, поскольку это ссылка, не имеет значения, где мы вносим изменение, потому что изменение будет отражено в исходном файле.

Конфигурация набора правил

По умолчанию при добавлении анализатора применяется строгость правил по умолчанию. Мы используем файл global.ruleset, чтобы отключить противоречивые правила и правила, которым команда согласилась не следовать. В приведенном ниже примере мы отключаем правило IDE0003, задав для его действия значение Нет.

  <?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>

В этом конкретном случае Visual Studio IDE и StyleCop имеют противоположные правила, которые конфликтуют друг с другом: первое просит удалить «это», а второе (после его удаления) просит снова добавить «это».

Пресечение нарушений

Будут времена, когда желаемое правило кодирования будет иметь смысл во всем мире, но вызовет головную боль в определенном контексте. Чтобы справиться с такими ситуациями, мы можем использовать атрибут SuppressMessage или #praga warning disable comments, чтобы подавить нарушения, при которых мы хотим пропустить правило. Подавление может производиться в нескольких областях: класс, метод и т. Д.

Подавление нарушений следует применять с осторожностью. В моей команде мы определили процесс, которым нужно управлять, когда это оправдано. При обнаружении нарушения разработчик проанализирует описание правила и варианты кодирования. Если правило или альтернативы неприменимы или не подходят, разработчик представит команде обоснование. Затем команда решит, будут ли они использовать альтернативу, подавить нарушения или полностью удалить правило. Когда принято решение подавить нарушение, следует использовать атрибут SuppressMessage и поместить его в минимально возможную область действия.

В приведенном ниже коде показан пример нарушения правила. Свойство ServiceVersions нарушает правило CA2227, поскольку мы предоставляем средство доступа к заданному свойству (позволяющее изменять содержимое коллекции путем изменения его ссылки), в то время как правило гласит, что свойства коллекции должны быть доступны только для чтения.

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;}
}

Класс SwaggerConfiguration используется механизмом .NET Core Configuration для создания экземпляра класса с данными, предоставленными файлом конфигурации JSON, и для этого требуется средство доступа set, чтобы он мог устанавливать данные. В этом контексте следование предложенной альтернативе помешает команде воспользоваться этой функцией .NET Core, что потребует от них реализации этой функции самостоятельно и изобретения колеса. Хотя в этом случае правило имеет глобальный смысл, команда решила, что альтернативы не подходят, и подавила нарушение с помощью атрибута SuppressMessage.

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;}
}

Заключение

Coding Standard - это метод программирования, введенный XP для обеспечения согласованности кода и облегчения чтения и сопровождения кода. Как упоминалось в этой статье, Стандарт кодирования имеет как технические, так и бизнес-преимущества. Платформа компилятора .NET и открытие некоторых проектов Microsoft, таких как StyleCop и FxCop, для сообщества разработчиков ПО с открытым исходным кодом привело к созданию новых инструментов анализа кода (анализаторов). К сожалению, текущие версии Visual Studio не предоставляют удобный графический пользовательский интерфейс для использования анализаторов в многопроектах или проектах .NET Core. В этой статье мы объяснили, как мы настраиваем Microsoft Visual Studio для применения Coding Standard при запуске нового командного проекта.