The LeanCode Core Library is a set of helper libraries developed at our company that aids our day-to-day development. Not only does it serve as a facilitator in our day-to-day coding activities, but it also encapsulates comprehensive guidelines, gathers our collective knowledge on application architecture and development best practices.
Our primary objective is to provide a definitive and opinionated framework tailored for .NET Core application development. Within this framework, we've standardized various facets of application design and implementation:
-
CQRS (Command Query Responsibility Segregation) and CQRS-as-API: Establishing conventions and practices for implementing CQRS patterns and their representation through APIs.
-
Domain-Driven Design (DDD) Models: Defining foundational DDD models and integrating them within the broader framework.
-
Integrations with External Services: Pre-defined integrations and guidelines for interfacing with external services, ensuring consistency and reliability.
-
Additional Functionalities: Including features such as handling audit logs, facilitating force updates, and localization.
-
Tests: Helpers dedicated to aiding and improving the process of writing and executing tests.
While embodying the attributes of a framework, LeanCode Core Library aligns closely with the ASP.NET Core model, emphasizing modularity and minimal intrusion into the application codebase.
CoreLibrary documentation is available here.
CoreLib version is tricky. Since it is mostly used internally by us at LeanCode, we're not really following Semantic Versioning. Instead, we decide which version is considered stable but maintained, which one is under active development and which one is out of support. There will also be versions that are unmaintained and should be no longer used. There are some vague rules on how we decide what state particular version is in:
- If there are projects that are not actively worked on, it is maintained but not actively developed,
- If it is based on old (out of support) .NET Core version, it is unmaintained,
- If the version is used by active projects only, it is under active development.
Additionally, there are some rules regarding versioning itself and changes to the version number:
- Since v5, CoreLib major version is the same as .NET major version,
- Minor version is used as a major version,
- If CoreLib version is stable, we can't introduce breaking changes without changing version,
- We allow breaking changes between minor (major) versions,
- If CoreLib version is under active development, we can introduce breaking changes without version bump,
- A single CoreLib version cannot be both stable and under active development,
- There is a small period of time after new CoreLib version is released when we allow all kinds of breakages (i.e. .NET Core bumps if we release during preview window).
All of the libraries that are part of the CoreLib are versioned together and require exact version of other libraries. This simplifies versioning substantially but at the expense of flexibility.
Here is the list of available major versions of the library (as of 2022-03-25):
CoreLib | .NET Core | Under development | Stable | Notes |
---|---|---|---|---|
v3.4 | 2.2 | Not published | ||
v4.1 | 3.1 | Unmaintained | ||
v4.2 | 3.1 | Unmaintained | ||
v5.0 | 5.0 | Unmaintained | ||
v5.1 | 5.0 | Unmaintained | ||
v6.0 | 6.0 | Unmaintained | ||
v6.1 | 6.0 | Unmaintained | ||
v7.0 | 7.0 | ✔ | ||
v8.0 | 8.0 | ✔ | ✔ |
dotnet build
If you want to build release configuration of the library, you need to specify what version the output package will have. That can be done with VERSION
environment variable or by passing VERSION
as MSBuild parameter to the build
command. CI also specifies GIT_COMMIT
that is appended to InformationalVersion
property of the assemblies to mark exact source code.
The framework can be unit-tested by cd
ing into test
folder and calling
dotnet msbuild /t:RunTests
Moreover, there are some integration-style tests that require external services. They can be tested with docker
and docker-compose
tools. Currently there is one integration-test suite:
test/LeanCode.IntegrationTests
,
It has a docker
folder that contains necessary configuration. You can run the suite using:
docker-compose run test
After successful test, packages can be packed with
dotnet pack -c Release -o $PWD/publish
and then published to NuGet feed with
dotnet nuget push 'publish/*.nupkg'
provided that API Key is correctly specified in profile/machine NuGet.Config
.
The project is divided into the main directories:
src
with the source code,test
with test,benchmarks
with benchmarking project,docs
with this documentation.
Plus there are some files in the root directory (SLN, config files & READMEs).
The src
folder that contains the main source code is then divided into:
Core
- the bootstrapping part of the CoreLib,Domain
- domain model-related projects,Infrastructure
- infrastructure-related projects,Helpers
- really small helper projects,Testing
- testing helpers (e.g. integration tests),Tools
- projects that enhance build-time (e.g. contracts gen, .NET Core analyzers).
test
folder follows str
structure closely.
CoreLib build system mostly MSBuild-based, with some help of CI system to orchestrate build/test/publish process (see Building & Testing for more details).
We leverage .NET Core's MSBuild Directory.Build.targets
files to centrally manage dependency versions. It is forbidden to directly specify Version
in csproj
s. Instead, one adds simple <ProjectReference Include="NAME" />
and then <ProjectReference Update="NAME" Version="VALID_VERSION" />
in Directory.Build.targets
in the CoreLib root. This immensely helps avoiding dependency conflicts down the road.
Besides .targets
file, we use central Directory.Build.props
to manage some of the project properties. Check /Directory.Build.props, /src/Directory.Build.props and /test/Directory.Build.props what is being centrally set.
Creating new packages (that will be published to the feed) is simple. You just have to:
- Create new .NET CoreLibrary project in the correct location,
- Remove
TargetFramework
since it is managed externally.
Or you can just modify the following project template (most of the projects use this):
<Project Sdk="Microsoft.NET.Sdk">
</Project>