Wow, new channel for me on C#, and I like it already, seems promising.
@Ardalis10 ай бұрын
Hope you enjoy it!
@codecomposer888 ай бұрын
Hi @Ardalis. Would you do validation or guard clauses when we're talking specifically a modular monolith architecture in regards to inter-module communication? I have a gut feeling that validation with a result type should be default way to go in order to prevent throwing exceptions between modules even though it's technically all happening at the domain layer.
@Ardalis8 ай бұрын
Inter-module means it’s spanning bounded contexts, so it’s not all domain layer. It would be like your code calling out to GitHub API or similar. You should treat the other modules like separate apps built by separate orgs, and only rely on the contract exposed. That said I’m not sure whether I’d prefer an exception or validation in that case, offhand. If the contract is exposing Result types I’d probably use those. If not I’d use exceptions. If it was new functionality and I could choose, I’d lean toward Result as it offers more flexibility.
@codecomposer888 ай бұрын
@@Ardalis Makes sense, thanks! Agree on going for result types in the contracts as much as possible.
@carlosirias44748 ай бұрын
Great content! Thanks for sharing your knowledge!
@Ardalis8 ай бұрын
Glad it was helpful!
@surajshaha5819 Жыл бұрын
I like this hairstyle @ardalis.. videos are as usual informative and helpful..
@Ardalis10 ай бұрын
Thanks!
@PticostaricaGS Жыл бұрын
It’s important to mention that user-entry validations must be implemented in a way that it does not require to even do a roundtrip when possible.
@Ardalis10 ай бұрын
Yes, that way they improve user experience. But you still need to re-validate on the server, for security reasons.
@islandparadise4 ай бұрын
Love this video, thanks! Question on the Result UpdateName(): Here I see that the Validation Result method is in the Entity. However if the field Name is used in several Entities, would it be practical to avoid copy-pasta by strongly typing the Name & put the validation logic there? Perhaps Name may not be the best example for my scenario, but Email could appear in multiple Entities?
@Ardalis3 ай бұрын
Yes, definitely. Using more Value Objects (strongly typed name) will reduce the need for validation in your entity. Ideally down to zero.
@islandparadise3 ай бұрын
@@Ardalis I’m on the right track, yay! Thanks! 😊
@flipdoubtful Жыл бұрын
I see lots of links in the description, but which is "the" link to the article you mention at the beginning of the video? Maybe I'm old school, but I often prefer to read rather than watch.
@Ardalis Жыл бұрын
This one: ardalis.com/guard-clauses-and-exceptions-or-validation/
@melihyilman8803 Жыл бұрын
Thanks! Happy coding 💻
@Ardalis10 ай бұрын
You're welcome!
@RichardJohn86 Жыл бұрын
How was the validator triggered?
@Ardalis Жыл бұрын
It's done automatically by Fast Endpoints: fast-endpoints.com/docs/validation
@pilotboba Жыл бұрын
@@Ardalis Yep, fast endpoints has some magic. :)
@DiegoFernandez-cy3fr Жыл бұрын
Good video, good hat! Thanks
@Ardalis10 ай бұрын
Heh, thanks! :)
@lpsoldier357 Жыл бұрын
How can I call the http requests like you're doing in visual studio? Is this an extension? Thanks!
@Ardalis Жыл бұрын
Support for .http files is a new feature in the latest version of Visual Studio 2022.
@lpsoldier357 Жыл бұрын
@@Ardalis Awesome, thanks!
@piotrkowalski34609 ай бұрын
Isn't it better to throw exceptions in the domain model in this case? It would mean that developer forgot to apply input validation (exceptional situation)
@Ardalis9 ай бұрын
Yes that’s exactly what I recommend and why. Guard clauses and exceptions in the domain, validation in the application.
@piotrkowalski34609 ай бұрын
@@Ardalis when would you use Result in the domain instead of exceptions? I guess it could be used for control flow in the use-case layer. However with validations it never happens.
@Ardalis9 ай бұрын
@@piotrkowalski3460 I use Result when there are non-exceptional ways in which the operation might fail. For example, a service might try to transfer money between accounts, but the sending account lacks sufficient funds. That might result in a Result describing the failure. Or one of the accounts might not exist - Result.NotFound might be appropriate. Usually validation in the application checks the structure of the request, but doesn't necessarily check the business logic or the existence/state of the underlying domain elements. Result within the domain could do so.
@pilotboba Жыл бұрын
I would also suggest you could also remove the primitive obsession. Make the ContributorName a class that encapsulates the rules with a Create() method that returns a Result. Then your Contributor class would accept a ContributorName rather than a string.
@stefan-d.grigorescu11 ай бұрын
Agreed, probably this is the best way to encapsulate rules in a consistent way
@Ardalis10 ай бұрын
Yes, adding value objects which can perform their guards in their constructor can certainly simplify entity mutation methods, 100%. I have a video in my queue about exactly this!
@obiwanjacobi10 ай бұрын
You duplicated the validation logic between the 'front door' (API entry point) and you domain model. Would you suggest making a single validation method specific for contributor name that is reused throughout the code? If so, how would you manage this dependency in these two different places.
@Ardalis10 ай бұрын
Possibly. In such a simple example there wasn't much "drift" between the API contract and the domain model, but in a real application there can be. In which case having unique validation rules/validators at the API and domain model makes sense. I think as long as things are literally the same, you might get some benefit from reusing validation logic (or validators). And also you might get some benefit from low-level validators that can be used in many places, like a string validator called ValidName that can be used for any number of Name fields, for instance. You might still use unique validators at the API and domain level, but they might both internally use a NameValidator, for example. And of course moving toward more value objects and fewer primitives (ints/strings/etc) at the domain model level also helps.
@joga_bonito_aro Жыл бұрын
Wouldn't it be better to write a validtor using the fluentvalidation lib and reuse the validator, instead of reimplementing the validtor with multiple if statements? I mean, you have it already, why not reusing it?
@Ardalis Жыл бұрын
The validator works on an object; the method accepts inputs and should only modify the state of the object it’s on if those inputs are valid. To use the validator you would need to create an object first (or modify the state of the current one), then validate, and if you modified the current object, roll back if invalid. Also most objects have many properties but this method on it checks one of them, so using the validator may do a lot of extra work. It’s true we should find a way to not duplicate the logic though. Stay tuned.
@joga_bonito_aro Жыл бұрын
Wouldn't something like this work: public class CreateContributorNameValidator : Validator { public static readonly CreateContributorNameValidator Instance = new CreateContributorNameValidator (); public CreateContributorNameValidator () { RuleFor(x => ...); } } public class CreateContributorValidator : Validator { public CreateContributorValidator () { RuleFor(x => x.Name) .UseValidator(CreateContributorNameValidator.Instance); } } With this you have the same logic and no new instances will get created constantly. Just a quick thought though.
@VangelisMatosMedina11 ай бұрын
If we decide to change the minimum value now we have to change in 02 places......
@Ardalis10 ай бұрын
Possibly, yes. If you like, you can always declare this in a constant and reference it from both locations. It's frequently the case for data-backed properties that you need to define the data size (EF configuration or SQL scripts or VS Database Project or somewhere) and validation and guard clauses, so constants like this or pretty commonplace.