When To Validate and When To Throw Exceptions?

Поделиться
HTML-код
  • Опубликовано: 31 янв 2025
  • НаукаНаука

Комментарии • 41

  • @loam
    @loam Год назад +5

    Wow, new channel for me on C#, and I like it already, seems promising.

    • @Ardalis
      @Ardalis  10 месяцев назад

      Hope you enjoy it!

  • @carlosirias4474
    @carlosirias4474 9 месяцев назад +1

    Great content! Thanks for sharing your knowledge!

    • @Ardalis
      @Ardalis  9 месяцев назад

      Glad it was helpful!

  • @codecomposer88
    @codecomposer88 9 месяцев назад +1

    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.

    • @Ardalis
      @Ardalis  9 месяцев назад +1

      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.

    • @codecomposer88
      @codecomposer88 9 месяцев назад

      @@Ardalis Makes sense, thanks! Agree on going for result types in the contracts as much as possible.

  • @surajshaha5819
    @surajshaha5819 Год назад +1

    I like this hairstyle @ardalis.. videos are as usual informative and helpful..

    • @Ardalis
      @Ardalis  10 месяцев назад

      Thanks!

  • @islandparadise
    @islandparadise 4 месяца назад

    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?

    • @Ardalis
      @Ardalis  4 месяца назад +1

      Yes, definitely. Using more Value Objects (strongly typed name) will reduce the need for validation in your entity. Ideally down to zero.

    • @islandparadise
      @islandparadise 4 месяца назад

      @@Ardalis I’m on the right track, yay! Thanks! 😊

  • @flipdoubtful
    @flipdoubtful Год назад +1

    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
      @Ardalis  Год назад +1

      This one: ardalis.com/guard-clauses-and-exceptions-or-validation/

  • @DiegoFernandez-cy3fr
    @DiegoFernandez-cy3fr Год назад +1

    Good video, good hat! Thanks

    • @Ardalis
      @Ardalis  10 месяцев назад

      Heh, thanks! :)

  • @melihyilman8803
    @melihyilman8803 Год назад +1

    Thanks! Happy coding 💻

    • @Ardalis
      @Ardalis  10 месяцев назад

      You're welcome!

  • @RichardJohn86
    @RichardJohn86 Год назад +2

    How was the validator triggered?

    • @Ardalis
      @Ardalis  Год назад +3

      It's done automatically by Fast Endpoints: fast-endpoints.com/docs/validation

    • @pilotboba
      @pilotboba Год назад

      @@Ardalis Yep, fast endpoints has some magic. :)

  • @PticostaricaGS
    @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.

    • @Ardalis
      @Ardalis  10 месяцев назад +2

      Yes, that way they improve user experience. But you still need to re-validate on the server, for security reasons.

  • @lpsoldier357
    @lpsoldier357 Год назад +1

    How can I call the http requests like you're doing in visual studio? Is this an extension? Thanks!

    • @Ardalis
      @Ardalis  Год назад +2

      Support for .http files is a new feature in the latest version of Visual Studio 2022.

    • @lpsoldier357
      @lpsoldier357 Год назад

      @@Ardalis Awesome, thanks!

  • @piotrkowalski3460
    @piotrkowalski3460 10 месяцев назад

    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)

    • @Ardalis
      @Ardalis  10 месяцев назад +1

      Yes that’s exactly what I recommend and why. Guard clauses and exceptions in the domain, validation in the application.

    • @piotrkowalski3460
      @piotrkowalski3460 10 месяцев назад

      @@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.

    • @Ardalis
      @Ardalis  10 месяцев назад +1

      @@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.

  • @joga_bonito_aro
    @joga_bonito_aro Год назад +1

    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
      @Ardalis  Год назад +1

      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
      @joga_bonito_aro Год назад +1

      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.

  • @obiwanjacobi
    @obiwanjacobi 11 месяцев назад

    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.

    • @Ardalis
      @Ardalis  11 месяцев назад

      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.

  • @pilotboba
    @pilotboba Год назад +2

    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.grigorescu
      @stefan-d.grigorescu Год назад

      Agreed, probably this is the best way to encapsulate rules in a consistent way

    • @Ardalis
      @Ardalis  10 месяцев назад

      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!

  • @VangelisMatosMedina
    @VangelisMatosMedina Год назад

    If we decide to change the minimum value now we have to change in 02 places......

    • @Ardalis
      @Ardalis  10 месяцев назад

      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.