Skip to content

Latest commit

 

History

History
63 lines (43 loc) · 5.03 KB

File metadata and controls

63 lines (43 loc) · 5.03 KB

Blueshift.MSBuildSdk.Hexagonal

The standard SDK used by Blueshift Software to apply the hexagonal architecture pattern to MSBuild projects. This SDK is meant to be opinionated: it is primarily meant to reduce copy-and-paste boilerplate that can pollute and muddle MSBuild project files, while applying a standard and extensible set of hexagonal architecture rules.

Primarily, Blueshift.MSBuildSdk.Hexagonal enforces the Dependency Inversion Principle that is the underlying principle of hexagonal architecture. When applied to a core project that contains business logic, the Sdk enforces a minimal list of allowed packages that can be referenced by the project.

The SDK's allowed package "white-list" is customizable through MSBuild properties, which can be applied through environment variables, overriden in individual projects, included globally through Directory.Build.props/targets, via a Hexagonal.props in the repository root directory, or via specific before- and after.props and -.targets files.

Allowed Packages

Under hexagonal architecture, core business logic may not take any external dependencies. Instead, the business logic layer should declare its own dependencies - called ports - which must be fulfilled by a set of adapters. These adapters are consumed by the application front-end and injected into the core business logic at runtime. Doing so decouples the business logic from providers, making it more extensible, testable, and maintainable.

For example, a core business logic service should not take an SqlClient as a direct dependency. Doing so would couple the business logic to SQL, or even a particular flavor of SQL. This would in turn make it far more difficult to change to a different flavor of Sql, or even switch entirely to a NoSql database if the necessity arose. Instead, the core business logic should declare an interface for some kind of object repository - eg: IBookRepository - which can then be implemented in an adapter. The adapter would then implement this interface with a class named something such as SqlBookRepository, which can take a SqlClient as a dependency. At runtime, SqlBookRepository can be injected into the core business logic wherever an IBookRepository is required.

However, doing this for every single dependency in every project would necessarily create significant duplication across projects. Consider logging, for example. It's a generally accepted rule that all applications should log. However, forcing every hexagonal application to re-implement its own specific logging abstraction just to decouple each project from the ubiquitous task of logging is overly dogmatic. If a company has a core set of logging utilities, it is perfectly acceptable to reuse that across hexagonal projects.

Blueshift.MSBuildSdk.Hexagonal compromises by allowing a specific (extensible) set of packages to be referenced by a project. Currently, only the following packages are supported by default:

  • Microsoft.Extensions.Configuration.Abstractions
  • Microsoft.Extensions.DependencyInjection.Abstractions
  • Microsoft.Extensions.Logging.Abstractions
  • Microsoft.Extensions.Options

Note that everything aside from Options (for which there is no available abstraction layer) uses the abstraction. This allows only the interfaces to be used, which enforces the requirement for the entrypoint of the application to set up the necessary concrete implementations.

This list is extensible and overridable.

Hexagonal.props

If a file called 'Hexagonal.props' is present in the root of the repository, it will automatically be imported. To extend the list of allowed packages, include an ItemGroup with one or more AllowedHexagonalPackage elements:

<Project>
  <ItemGroup>
    <AllowedHexagonalPackage Include="My.Allowed.Package" />
  </ItemGroup>
</Project>

This file is imported after the default list of allowed packages is created. This allows 'Hexagonal.props' to remove items from - or completely override - the default list. To do so, use the Remove attribute:

<Project>
  <ItemGroup>
    <AllowedHexagonalPackage Remove="Microsoft.Extensions.Options" /> <!-- Remove one item -->
    <AllowedHexagonalPackage Remove="*" /> <!-- Clear the whole list -->
    <AllowedHexagonalPackage Include="My.Allowed.Package" />
  </ItemGroup>
</Project>

If the project contains any package references that are not allowed via AllowedHexagonalPackage items in this manner, the Sdk will generate an error.

Customization

The behavior of the SDK can be fine-tuned by setting these specific propeties prior to loading the SDK:

Property Description
CustomBeforeBlueshiftMSBuildHexagonalSdkProps The name of a custom props file to be loaded at the beginning of Sdk.props.
CustomAfterBlueshiftMSBuildHexagonalSdkProps The name of a custom props file to be loaded at the end of Sdk.props.
CustomBeforeBlueshiftMSBuildHexagonalSdkTargets The name of a custom targets file to be loaded at the beginning of Sdk.target.
CustomAfterBlueshiftMSBuildHexagonalSdkTargets The name of a custom targets file to be loaded at the end of Sdk.target.