Primitive Obsession
Primitive Obsession (AKA StringlyTyped) means being obsessed with primitives. It is a Code Smell that degrades the quality of software.
“Primitive Obsession is using primitive data types to represent domain ideas” README.md
This code snippet, for example, shows Primitive Obsession:
int customerId = 42
``` [README.md](https://github.com/stevedunn/vogen/blob/main/README.md)
What's wrong with that? An `int` likely cannot *fully* represent a customer ID. An `int` can be negative or zero, but it's
unlikely a customer ID can be. So, we have **constraints** on a customer ID. We can't _represent_ or _enforce_ those
constraints on an `int`. [README.md](https://github.com/stevedunn/vogen/blob/main/README.md)
We can't be sure if it's been checked beforehand, so we need to check it every time we use it. Because it's a
primitive, someone might've changed the value, so even if we're 100% sure we've checked it before, it still might need
checking again. [docs/site/Writerside/topics/discussions/Home.md](https://github.com/stevedunn/vogen/blob/main/docs/site/Writerside/topics/discussions/Home.md)
So, we need some validation to ensure the **constraints** of a customer ID are met. Because it's in `int`, we can't be
sure if it's been checked beforehand, so we need to check it every time we use it. Because it's a primitive,
someone might've changed the value, so even if we're 100% sure we've checked it before, it still might need checking again.
[docs/site/Writerside/topics/discussions/Home.md](https://github.com/stevedunn/vogen/blob/main/docs/site/Writerside/topics/discussions/Home.md)
### Value Objects to the Rescue
The source generator generates value objects. Value objects help combat Primitive Obsession by wrapping simple
primitives such as `int`, `string`, `double` etc. in a strongly-typed type. [README.md](https://github.com/stevedunn/vogen/blob/main/README.md)
Here's an example of a value object called `CustomerId`:
```csharp
[ValueObject(typeof(int))]
public partial struct CustomerId
{
}
``` [nuget-search-description.md](https://github.com/stevedunn/vogen/blob/main/docs/nuget-search-description.md)
Instead of:
```csharp
int customerId = 42;
``` [nuget-search-description.md](https://github.com/stevedunn/vogen/blob/main/docs/nuget-search-description.md)
we have:
```cs
var customerId = CustomerId.From(42);
``` [nuget-search-description.md](https://github.com/stevedunn/vogen/blob/main/docs/nuget-search-description.md)
Here it is again with some validation:
``` cs
public class CustomerId : ValueObject
{
private static Validation Validate(int value) =>
value > 0 ? Validation.Ok : Validation.Invalid(); }
``` [nuget-search-description.md](https://github.com/stevedunn/vogen/blob/main/docs/nuget-search-description.md)
### The Source Generator and Value Objects
The Source Generator generates code for things like creating the object and for performing equality. [docs/nuget-readme.md](https://github.com/stevedunn/vogen/blob/main/docs/nuget-readme.md)
The opinions are expressed as:
* A value object (VO) is constructed via a factory method named `From`, e.g. `Age.From(12)` [README.md](https://github.com/stevedunn/vogen/blob/main/README.md)
* A VO is equatable (`Age.From(12) == Age.From(12)`) [README.md](https://github.com/stevedunn/vogen/blob/main/README.md)
* A VO, if validated, is validated with a static method named `Validate` that returns a `Validation` result [README.md](https://github.com/stevedunn/vogen/blob/main/README.md)
* Any validation that is not `Validation.Ok` results in a `ValueObjectValidationException` being thrown [README.md](https://github.com/stevedunn/vogen/blob/main/README.md)
### Performance
One of the main goals of this project is to achieve **almost the same speed and memory performance as using
primitives directly**. [README.md](https://github.com/stevedunn/vogen/blob/main/README.md)
Put another way, if your `decimal` primitive represents an Account Balance, then there is **extremely** low overhead
of using an `AccountBalance` value object instead. [README.md](https://github.com/stevedunn/vogen/blob/main/README.md)
Top-Level Directory Explanations
samples/ - This directory contains example projects that demonstrate the usage of the Vogen library. Each subdirectory represents a different example, and contains the necessary files and configurations for that example.
src/ - This directory contains the source code for the project. It includes the Vogen library itself, as well as any shared types and code fixers.
src/obj/ - This directory contains object files generated during the compilation process.
src/Vogen/ - This subdirectory contains the core Vogen library code. It includes subdirectories for diagnostics, extensions, generators, properties, rules, suppressors, templates, and binaries and object files.
tests/ - This directory contains unit tests and benchmarks for the project. It includes subdirectories for analyzer tests, consumer tests, snapshot tests, and Vogen benchmarks.
tests/AnalyzerTests/ - This subdirectory contains unit tests for the analyzer component of the Vogen library.
tests/ConsumerTests/ - This subdirectory contains unit tests for the consumer-side components of the Vogen library.
tests/SnapshotTests/ - This subdirectory contains snapshot tests, which test the output of the code generation and serialization components of the Vogen library.