FPrimitive is a F# library of mine with full C# support. It handles all kinds of model validations by defining specifications for your model. In this blog post, I’m going to assume that you have a basic understanding of the library and of domain model validation. If not, I recommend a couple of my other posts to get you started.
Optional Types
Optional types are types that are part of the model but are not necessary to create a valid model. In the context of Corona, let’s create a model with such an example. Consider a guest at a concert that has to show his Corona Pass before entering. The guest either has or hasn’t a pass with them, but still remains a ‘valid’ possible guest.
You’ll see that the pass is optional here to create a guest model. With the FPrimitive library, we can easily model this with the Spec.optional
function. In this case, we use the Option.ofObj
to determine if the incoming `string` is null
. In that case, None
will be used. The Union.create
function is also available in the FPrimitive library and lets you create Discriminated Unions based on string
values. It creates an Result
based on the result, which makes it perfectly combinable with the specification functions.
With the Spec.optional
you can therefore choose to only validate a certain input when a function ('a -> 'b option
) holds. It makes it a good specification combinator for optional types while doing domain modeling.
Invariants
Domain invariants are relationships within the model. Rules about two or more sets of models. This relationship should also be expressed fluently and descriptive in the domain. FPrimitive made this happen. The Spec.invariant
takes in two specifications and creates a new specification of the combination. There are is also a function to take in 3 specifications. If more is needed, the system is flexible enough to create any more combinations you want.
A good and simple example of such an invariant, is designing a range model with a minimum and maximum value. The domain invariant in this case will make sure that the minimum is always smaller than the maximum value.
Dependencies
Dependency validations in the context of domain modeling will make sure that a dependency is validated before the main validation. This concept is important when handling rather complex validations and/or you want to re-use specifications. In that case, FPrimitive has several combinators that let you define specification dependencies that will run before the specification you define.
Imagine you want to model that represents a series of text. There will often be similar things that you need to check, such as blank input, special characters. In those cases, we can make use of the dependency validation.
This makes for great re-use of specifications.
Conclusion
In this post I’ve barely scratched the surface of domain modeling with FPrimitive. There are a lot of advanced combinators to describe complex models. Spec.structure
, Spec.filter
, Spec.subset
, Spec.list
etc. are all great combinators too, but that will be for another time.
Please consider F# in your next project, even if it’s just for domain modeling and internal business rules. I strongly believe that the combination of F#/C# is the sweet spot we’re all trying to find.
Thanks for reading!
Stijn
P.S. Here’s what this looks like in C#:
Subscribe to our RSS feed