Open utterances-bot opened 2 years ago
Thanks for the article, mate. Very thorough overview of how one can avoid the complexities of validation - when avoidable. It also, nicely, covers the transition between the possibly-invalid to the valid state - which is awesome. I used your article for a discussion with my team, very handy topic for our Design-by-Contract/Hexagonal Architecture talks. I really appreciated it.
If you don't mind, though, I'd like to make a remark about (what I consider) an unnecessary bias towards FP in detriment of other development paradigm (OOP in this case). As most of us, I'm assuming you had a bad time coding in Java, C# or other mainstream OOP language. That's understandable, most of the knowledge transfer that yielded from these communities came from empirical experience - not from a thorough analysis. As a result, a small piece of advice made someone might become the "best practices" on someone else's personal blog post.
In a modern day development we now understand that each of the three main development paradigm handles scope differently. If we think about it, a typical C program would have a struct-contructed object passed through several functions. This is not different from having it constructed insider a closure, allowing inline-defined functions to access it freely - like one would do in Haskel, OCaml or F#. This basically the same with class-defined scope.
Surely, poorly applied polymorphism is bad. As our DB queries evolved to accommodate the user growth, our structs and objects had to be redesigned - the pain maintaining our curry-like validations were unbearable at that point. But I reckon the problem is not the tool (language) but the small technique repertoire at our disposal. I'd dare to rephrase the common saying to "it's all about using the right technique for the right job". As Alan Kay once pointed out, OOP should've been about messaging passing rather than the so-commonly-misused Polymorphism and enforced encapsulation.
I couldn't agree more with you on almost everything else. Factories, Converters and the-like are pretty much the only way we construct our Models. Promoting our invariants to the domain-entity layer has allowed us to better design our Information Architecture - easing the burden to outline the boundaries within our components. But we've been seeing so much value in transitioning our team to a hybrid development ecosystem that we can't see ourselves going back to what it was any time soon. We still use functors, partial and total isomorphism, ADT and GADTs whenever possible. We also take advantage of the class-scoped behaviour provided for us whenever it makes our components more readable. As a result, we saw a significant reduction to the cognitive overload we used to have when it was mainly functional.
Invariants as discriminated unions, validation and always valid objects. | Blog
Everyone (including me) when applying DDD at some points fights with validation and invariants. Probably You tried different approaches already - validating within the domain, duplicating the validation logic for both: application validation and business rules enforcement, or You tried something else. In this post, we will dig out the old (but still living) "always valid" camp, and by using discriminated unions we will model both - always valid entities and aggregate invariants as types. Examples in F#.
https://mcode.it/blog/2021-02-26-du_invariants/?utterances=45070cc9d5dd2fa270f32d9eixk6%2FBHSDNoznWIPM2mE%2BgwvWqNoGRGxR2c1dfNNCAqJ80krEMsaEtPZvw2N%2FpECj9adKG7bYJ5TYXMhcd1J8YHzLhKCvPJu0o1gGrx9X%2FpMXUSsYUvw0Lms%2B0k%3D