"You're Doing Validation Wrong in .NET" | Code Cop

แชร์
ฝัง
  • เผยแพร่เมื่อ 21 พ.ย. 2024

ความคิดเห็น • 203

  • @hupett
    @hupett หลายเดือนก่อน +135

    To check everything else together or fail fast: I think it really comes down to the application itself. Most of the time, as a user, I would be infuriated, when I'm gettin a new error over and over again, like why didn't just give me all to errors at once, so I can fix all at once :D The only exception is when an error is caused by something that was previously empty for example, that could still cause new errors, but I'm ok with that.

    • @adambickford8720
      @adambickford8720 หลายเดือนก่อน +19

      Agreed. Fail fast is about the worst UX possible.

    • @JoshWeeks
      @JoshWeeks หลายเดือนก่อน +3

      That's why the good lord gave us IEnumerable and IAsyncEnumerable. Let the caller decide.

    • @adambickford8720
      @adambickford8720 หลายเดือนก่อน +3

      @@JoshWeeks Seems completely unrelated, what am i missing?

    • @JoshWeeks
      @JoshWeeks หลายเดือนก่อน

      @@adambickford8720 With deferred execution (using yield) the caller can decide whether to stop after the first error or continue doing all of the validation.

    • @marikselazemaj3428
      @marikselazemaj3428 หลายเดือนก่อน

      ​@adambickford8720 with IEnumerabe you get both options. You can choose to only get the first result or keep enumeraring to get all results

  • @z0nx
    @z0nx 29 วันที่ผ่านมา +3

    Nick, I was waiting for you to mention "parse, don't validate"! If you havent read the article, I really recommend it. The final code was so, so close. If only the function returned a proof that the thing has been validated, all the code can then be written against the validated type.
    So in this example: `public static Validation Validate(User user)`
    Now, User usually refers to the type in the domain and the input is the unvalidated type, so it would be more like `public static Validation Validate(Command.User user)`.
    This is for all the lost souls that happen to come across this comment :')

  • @jamesterwilliger3176
    @jamesterwilliger3176 หลายเดือนก่อน +35

    Validation nomad: someone who wanders the world seeking positive reinforcement

    • @unkn0wnrge189
      @unkn0wnrge189 หลายเดือนก่อน

      forget about validation package you use, it doesn't work anymore the thing I use the best one it's the tValidation only with that package in my course u find hapiness and success.

  • @tedchirvasiu
    @tedchirvasiu หลายเดือนก่อน +24

    I hate errors which only contain the error message as the identifier, because the error message may change. Sometimes you need to handle certain validation results in a special manner, especially on the frontend. I personally always make my validation results contain a human-readable identifier such as "WrongPassword", along with a description.

    • @yurisich
      @yurisich หลายเดือนก่อน

      For HTTP you can't go wrong with errors as return values. Google's HTTP best practices documentation does a good job steering you towards the pattern you've described. I would also recommend including a unique, hardcoded error key (12-length hex character strings is what I prefer) that makes source code searches trivial for in investigating the source of the error. You can have more than one "Missing X field" errors in a project, giving each one a unique key is important when users report a new 400 error where there wasn't one before.

    • @Coburah
      @Coburah หลายเดือนก่อน +1

      +1, I do this too.

    • @temp50
      @temp50 หลายเดือนก่อน +2

      Yeah too bad that I'm almost begging to MS (via a github issue) to extend the ValidationResult or - even better - make it customizable so that we could add any kind of object to a validation error: without any success so far.

    • @afterfallout1
      @afterfallout1 หลายเดือนก่อน +5

      IMO errors should always contain 3 things and preferably 4:
      1. the path to the thing that is failed (if you are validating json input, json path expressions would be good for this; there isn't really a good spec for generalizations though so just be self consistent)
      2. an error code that is easy for a human to identify and distinguish from other possible errors (eg not SYS-1234 but something like EmptyStringValidation) and is the same for the same error throughout the system and effectively never changes in any past or future version
      3. error context data (actual value, minimums, maximums, etc; also the shape/schema of this object should never change over time)
      4. optional but preferred: a string description in the primary language of the userbase (or if it is identified, in the language preferred by the user)
      It is also best if a validation always returns as many identifiable errors from the input state as possible. Even though this might be more computationally expensive up front it generally saves time and processing vs a fail-fast scenario where each error is returned one at a time and the user repeatedly submits their fixed input to get the next error.

    • @fredrikjosefsson3373
      @fredrikjosefsson3373 26 วันที่ผ่านมา

      @@temp50 we use a coworkers library in our code so our way to do it is similar, but insted of Errors.New we put the errors in the domain. So it would instead be return new User.Errors.InvalidEmailAddress("Error message")
      the errors themself are basically just a record that inheirts from a record called ErrorBase

  • @StuartQuinn
    @StuartQuinn หลายเดือนก่อน +24

    I think the Code Cop series is losing its way. In the example post, the list example is clearly superior. Sure there are even better ways, but most of the alternatives explored don't have the very basic functionality of returning every individual error without combining them all into a single string or exiting as soon as the first error is encountered.
    Also, I think Nick has way overcooked the cost of allocating a list vs using yield. I get the impression that he gets into perf sensitive code a lot from his videos, but for the vast majority of LOB apps, it's a total non-issue.
    Just because the "good" advice can be improved, doesn't make it bad advice.

  • @demarcorr
    @demarcorr หลายเดือนก่อน +45

    true developers ONLY write to console 🗿

    • @UweKeim
      @UweKeim หลายเดือนก่อน +6

      Chuck Norris doesn't write to Console; Console writes to Chuck Norris.

    • @temp50
      @temp50 หลายเดือนก่อน +2

      @@UweKeim Yeah, and even if you write to > void, Chuck Norris will print it out!

    • @7th_CAV_Trooper
      @7th_CAV_Trooper หลายเดือนก่อน +2

      Chuck Norris is stdout.

    • @7th_CAV_Trooper
      @7th_CAV_Trooper หลายเดือนก่อน +2

      True developers never need to see the output. They know what it will be before they write the code.

    • @LeducDuSapin
      @LeducDuSapin 7 วันที่ผ่านมา +1

      No seriously, it's one of the 12 factor app principle. Always log to stdout, it's the runtime environments job to pick it up and ship it.

  • @sergioengineer
    @sergioengineer หลายเดือนก่อน +6

    I feel like fail fast or not is an application concern. If you are on the server-side, then you just need to know if the thing is valid or not for insertion. But, if you are returning a message to the user, then you want every error listed there. That's why I'd rather make the method ready for both cases using IENumerable as a return and a "yield return ValidationError(errorCode)". That way you could go for a "Any()" call if you want the fail fast approach or a ToList if you want to return all of the errors to the user depending on the use case.

  • @SamFerree
    @SamFerree หลายเดือนก่อน

    I prefer to apply functional concepts to the domain, instead of building my domain on top of a functional library.
    So in this case, I might have a UserForm type, that has a Submit method which returns a Submitted type, that has two properties User? and Errors?, which are null annotated to be not null when SubmittedUser.IsValid is true and false respectively.
    TreatAllWarningsAsErrros means that the compiler knows and enforces that you submit the form and check validity before accessing the User or Errors properties.
    Now I don't have to explain to devs unfamiliar with function programming what a monoid is, or why our code uses Lst instead of List

  • @marcusmajarra
    @marcusmajarra หลายเดือนก่อน +5

    I think in this example, the idea of not failing fast seems to have to do with something like form validation rather than, say, precondition checks. If you find all the issues at once, it's possible to annotate the UI with all the errors at the relevant place, allowing the user to correct mistakes without having to try again repeatedly until no errors are found.

  • @tanglesites
    @tanglesites หลายเดือนก่อน +18

    WHY is no one ASKING for more Fucntional episodes!!! Yes more functional concepts, please! That stuff is so f***ing cool! You have teased us before, but is it time for the Monad explanation?? What does it even mean??

    • @thethreeheadedmonkey
      @thethreeheadedmonkey หลายเดือนก่อน +2

      A monad is just a monoid in the category of endofunctors, what's the problem?
      (that's a meme, but it's not as absurd/crazy as it sounds)
      " [...] a monad is a type M for which the following functions are defined:
      Return-Takes a regular value of type T and lifts it into a monadic value of type M
      Bind-Takes a monadic value m and a world-crossing function f; extracts from m its inner value(s) t and applies f to it
      Return and Bind should have the following three properties:
      Right identity
      Left identity
      Associativity"
      taken from Functional C# by Enrico Buonanno (worth a read on Manning!)

    • @WillEhrendreich
      @WillEhrendreich หลายเดือนก่อน

      @@thethreeheadedmonkey not a bad explanation, fairly pragmatic. by the way is your name a reference to Monkey Island? cuz if so you're my kinda people.

    • @MC_DarkMaster
      @MC_DarkMaster หลายเดือนก่อน +2

      It would be nice to see some self-made examples instead of yet another dependency for only a few lines of code

    • @tanglesites
      @tanglesites หลายเดือนก่อน +1

      @@thethreeheadedmonkey out of context of the book that is a circular definition. If someone doesn’t know what a monad is, they aren’t going to know what a monadic value is either, lol. Nick is good at explaining complicated concepts. I think it would be a good edition. … my category theory is a little rusty, but a monoid sits right there between a group and a semigroup? And endofunctors are functors that map to themselves? Yeah, Nick should totally explain. I’m waiting patiently.

    • @thethreeheadedmonkey
      @thethreeheadedmonkey หลายเดือนก่อน

      @@WillEhrendreich Haha, it absolutely is a reference to Monkey Island! Not my explanation, though - that's from a book I read and all credit to the author (who does an impressive job with many examples in said book).

  • @pw.70
    @pw.70 หลายเดือนก่อน

    I think that there are so many little class nooks and crannies in .NET, especially with the plethora of nuget and github packages out there, that videos like this are very useful. I wish there were more. Good job, Nick.

  • @markovcd
    @markovcd หลายเดือนก่อน +19

    7:20 why do you need to do extra hoops to return null instead of just empty enumerable? This approach makes consumers make unnecessary checks which also invalidates why you have IsValid flag in the first place.

    • @metlov
      @metlov หลายเดือนก่อน

      Returning null would be good if it was an out parameter. Something like bool IsValid(model, out IEnumerable? errors)
      To avoid the nullability warning, there is a neat [NotNullWhen(false)] parameter attribute. That’s how it’s done in dictionary’s TryGetValue for example.
      But here with a tuple, I agree that having a nullable errors causes a double check to address the nullability warning, and you can’t do anything with that. Allocating an empty array is not ideal either imo.

    • @xZise
      @xZise หลายเดือนก่อน

      I just don't get why it doesn't return something like ICollection (or the actual type). It would make it obvious that you can get the count without worrying about the enumeration behind the returned value.

    • @x0rld159
      @x0rld159 หลายเดือนก่อน

      @metlov
      You can"t do any async with out, like database validation for email
      And btw if you return Array.Empty() it's optimized to not allocate anything

    • @metlov
      @metlov หลายเดือนก่อน

      @@x0rld159 you didn’t watch the video carefully. Either with or without an allocation, the caller sees only IEnumerable

  • @shinpansen
    @shinpansen หลายเดือนก่อน +42

    Those advices are very funny. The left one is some junior code, the right one, some junior code with max 6 months of experience.

    • @TheTigerus
      @TheTigerus หลายเดือนก่อน +2

      because they are written by junior with max 6 months of experience

    • @JoseFuentesLopez
      @JoseFuentesLopez หลายเดือนก่อน +6

      A real junior would nested the validations.

  • @rreiter
    @rreiter หลายเดือนก่อน +2

    Interesting, good video, thanks. I don't see a horrible problem with empty or null errors meaning no errors were found. There comes a point where a consumer needs to be intelligent enough to follow a spec or interpret or code for the result.

    • @junior.santana
      @junior.santana หลายเดือนก่อน +3

      Agreed. This is pretty intuitive for me:
      if(!errors.Any()) {
      ....;
      }

  • @Robert-l4e9s
    @Robert-l4e9s 14 วันที่ผ่านมา

    Static function cannot be dependency injected if desired in the future. I'm glad compilers don't give one error at a time. That is, send the user a full set of available info.

  • @Apptelope
    @Apptelope หลายเดือนก่อน +1

    Best practices when writing APIs in C# dictate returning all validation errors for data input to an API. This approach has been standard for +20 years. I believe this is the first post in this series where Nick is obviously wrong.

  • @DummyFace123
    @DummyFace123 หลายเดือนก่อน +1

    I'm definitely on team validate everything and not fast failing. Think about everything that goes on under the hood when a web request is made. Theres an enormous amount of work going on before you even receive the request object. Its far more efficient to validate the entire request instead of validating one thing at a time. Users also vastly prefer knowing everything that is wrong instead of fixing one thing, only to be then informed about the next problem after the next submission. Maybe theres a more performant way to validate instead of always creating a list, maybe lazy load it when an error is first encountered, maybe pass in a stringbuilder, there are many ways. But still, in the end, taking the entire user experience into account, its far more efficient to validate the entire request instead of fast-failing

    • @holger_p
      @holger_p 24 วันที่ผ่านมา +1

      I agree, but there then I would put a side condition of a silent notification, put alerts everywhere, but don't hinder the workflow.
      If there are 5 lines wrong, tell the user all the 5 lines, not after one is repaired, you tell about the next.
      And don't use popups ! User doesn't want to confirm to have read 20 messages one by one. Building a list, display one popup would be essential.

  • @garethrowlands
    @garethrowlands หลายเดือนก่อน +8

    For form validation, you need to put the feedback next to the each element of the form, so none of these mechanisms are suitable.
    So maybe your use case is a server validating its inputs before processing them. If that's the case, I'd consider 'parse, don't validate'. The server receives an HTTP request and attempts to parse a (valid) User out of it. If the parser returns a User, the server goes on to process it. If the parser doesn't return a User, it returns an error and the server handles or returns that error. It doesn't much matter how the parser signals errors - exceptions work fine for this case, as do Either- or Result-style discriminated unions. What I would try to avoid is the possibility of constructing a User object that might not be valid.

    • @lordmetzgermeister
      @lordmetzgermeister หลายเดือนก่อน +2

      oh no don't mention exceptions as a suitable solution in front of Nick 😁

    • @garethrowlands
      @garethrowlands หลายเดือนก่อน

      @@lordmetzgermeister I love algebraic data types as much as the next man but in this particular case, the server’s likely to just bale with a 400 status response. I agree exceptions have no place in form handling - apart from anything else, form validation failures aren’t exceptional.

  • @peterhamilton1970
    @peterhamilton1970 หลายเดือนก่อน

    Hey Nick, thank you for your video. As you mentioned, i would really like to see more functional programming by you, because it catches my interest when I sneaked into GO.
    Thanks

  • @klocugh12
    @klocugh12 หลายเดือนก่อน +9

    I feel so validated now.

  • @davidmartensson273
    @davidmartensson273 หลายเดือนก่อน

    The email validation, checking for @ sign is better than most, especially better than any regex base ones which almost always rejects valid emails.

  • @samuelschwager
    @samuelschwager หลายเดือนก่อน +2

    exit early is not always the right strategy when validating a complex object. as a user I would want to see everything that's wrong all at once.

    • @eugenpaval
      @eugenpaval หลายเดือนก่อน

      True. Different use cases, though.

  • @zwatotem
    @zwatotem หลายเดือนก่อน +2

    The "more of a functional developer" just threw out the List monad for multiple errors and replaced it with the Either monad for a single error.
    In my opinion this (and many other episodes of code cop) is just splitting hair.

  • @ThugLifeModafocah
    @ThugLifeModafocah หลายเดือนก่อน +1

    Well the list of error is a better approach than the previous boolean return, to make it more expressive, he could create a ValidationResult type containing the status (validated or not) and the list of problems when validations failed.

    • @ThugLifeModafocah
      @ThugLifeModafocah หลายเดือนก่อน

      Oh, I see later in the video that improvement I suggested (I made the comment in the beginning).

  • @ryanrobbins3846
    @ryanrobbins3846 หลายเดือนก่อน

    🤘nice one.
    You like functional style more eh? 🧐
    Do you have any reading you could recommend for clean code vs functional?

  • @nothingisreal6345
    @nothingisreal6345 หลายเดือนก่อน +3

    the difference between yield return and creating a list is minimal. to consume the IEnumerable the caller has to convert to a list or array anyways. overall I think the suggested approach by the user good. It would be even better if using an enum for the error class plus a message string to make it easier for the caller to handle it. So honestly I don't get the point.

    • @eugenpaval
      @eugenpaval หลายเดือนก่อน +2

      The difference is that the list allocation still happens even if there are no errors. Also to consume the Enumerable you need to loop through it, not necessarily convert into an array or list. Why would you?

  • @ankumo
    @ankumo หลายเดือนก่อน

    Wow, I was implementing similar approach for my nest.js apps. Happy to see I was doing it in at least not a bad way :D

  • @Rein______
    @Rein______ หลายเดือนก่อน

    I like value objects for validation. 'Validation' just becomes the attempt to construct a UserName instance. Allows reusing the same logic in the create/update endpoint. Prevents duplicating domain logic vs validation logic. (public static Result Create(string? value))

  • @Myddrin31
    @Myddrin31 หลายเดือนก่อน +3

    Interesting video but with last proposal, we return only one error. Is it a way to return all errors on one call?

    • @Krokoklemmee
      @Krokoklemmee หลายเดือนก่อน

      you could return some aggregate error object (or throw a validation exception)

    • @temp50
      @temp50 หลายเดือนก่อน +1

      @@Krokoklemmee "throw a validation exception" I'm pretty sure Nick would say that this is a swearing expression.

    • @danilonotsys
      @danilonotsys หลายเดือนก่อน

      The DataAnnotations Validator class returns an ICollection of ValidationResults when calling TryValidateObject and I don't see why we can't do the same. However there is a boolean parameter to control when to validate all properties just as FluentValidation has a parameter to control whether it will return immediately or not upon encountering the first exception

  • @MrBranyace
    @MrBranyace หลายเดือนก่อน +11

    Isn't there valid justification to return a list of all errors to make your API more user friendly, and relay everything wrong with the request that was received? I can see scenarios where end users get frustrated with an API not giving them the whole validation picture, forcing them to discover through trial and error what a valid request should look like.

    • @Coburah
      @Coburah หลายเดือนก่อน

      There absolutely is. FluentValidation does, and it's great.
      But that's only for basic input validation (!) at the user-facing edge of the system. Past that point, fail as fast as possible.

    • @fredrikjosefsson3373
      @fredrikjosefsson3373 26 วันที่ผ่านมา

      personally I think its case to case. If you are filling out a form then I think validating all errors would be the best. If its something else, lets say a button that does something to a specific entity then just showing one at a time is better

  • @parlor3115
    @parlor3115 หลายเดือนก่อน

    Post is comparing Validate with IsValid which are two completely different things. Personally, if I'm writing everything from scratch (mostly library code), then I prefer the IsValid approach (one per validation rule), because it's compliant with Single Responsibility. For application code however, we have Fluent, so no point in reinventing the wheel, especially that we have a much broader enumerable of rules to support.

  • @BrunoDPO
    @BrunoDPO หลายเดือนก่อน

    Since you showed in your channel the OneOf library, I tend to use this when I do my validations as well as returning the different objects to an endpoint. But I think that with the LanguageExtensions library the name is way more intuitive, so I'll give this a try. Nick, do you think these libraries will be deprecated when C# incorporates discriminated unions?

  • @marcotroster8247
    @marcotroster8247 หลายเดือนก่อน

    Make Validate() an extension method of User to chain calls all along. Then you'll get user.Validate().Match(...)
    Although Match() should have the error first and the result second. Otherwise you can't continue chaining the happy path.

    • @timur2887
      @timur2887 หลายเดือนก่อน

      Try ErrorOr library

  • @leerothman2715
    @leerothman2715 หลายเดือนก่อน +4

    Not sure what the purpose of returning what was passed in for a success is?

    • @naasking
      @naasking หลายเดือนก่อน

      It can help if you're aggregating multiple levels of validation and error processing. Without that you'd end up passing the object around anyway. It's less common for sure, but makes the interface simple and uniform.

  • @da3dsoul
    @da3dsoul หลายเดือนก่อน

    Another way is to maintain a Context object. Fewer allocations, but greater complexity in some cases

  • @LeandroDaminelli
    @LeandroDaminelli หลายเดือนก่อน +5

    I really love to see how 'senior' devs enjoy overcomplicating simple things. It would be a nightmare to see the same devs' code for a complex business logic problem.

  • @fishzebra
    @fishzebra หลายเดือนก่อน

    Function honesty is underappreciated, should not need to read how a method is implemented to be able to use it.
    Another overlooked concept is like Kent's new book Tidy First. So much code base is ugly, filled with IDE recommendations, spelling mistakes and out of date packages. So much easier to read and understand when your clean your workspace before making dinner like a good chef. Also turn on warnings as errors, basics first!

  • @lordicemaniac
    @lordicemaniac หลายเดือนก่อน +2

    shouldn't be the error in monad on left side in match? because when input is right, answer is right.... :) also in definition you wrote Validation, i'm not familiar with library you use but i find it odd that if you define monad value type on left, it should be on left in Match.... if this wasn't an error ofc :)

    • @thethreeheadedmonkey
      @thethreeheadedmonkey หลายเดือนก่อน

      The library author made some... unique decisions in how he structured this out. Nick has it right, but it's not intuitive that it would work this way, haha.

    • @rGunti
      @rGunti หลายเดือนก่อน

      Had the same thought, but the docs seem to agree: in the Type, the failure is defined first, but when matched, the error goes second.
      Guess it depends on your world view, but I would usually go with Happy Path first. Been using the OneOf package for these kinds of things.

  • @collapsingspace
    @collapsingspace หลายเดือนก่อน +8

    Everything you did with installing a separate extension seems like overkill, I'd probably hate the guy who would do this in my codebase.

    • @eugenpaval
      @eugenpaval หลายเดือนก่อน

      You are missing the point. Look at a large project with hundreds of validations and then you will understand how this particular extension becomes valuable.

  • @Ozuqam
    @Ozuqam หลายเดือนก่อน +4

    That validate method will throw argument null exceptio when user is null

  • @temp50
    @temp50 หลายเดือนก่อน

    Return is: again: depends. Depends on what kind of entity your API is suppose to talk to. Is it a backend service of a frontend application? Than you might wanna indeed list every invalid property. But if you are talking to other services, it is usually enough to response with a machine-readable "GTFO" and maybe log out the problem within service where the problem occurred.

  • @volsand
    @volsand หลายเดือนก่อน

    Monadic validation for failfast
    Applicative Functor validation for aggregation of errors

  • @Tldr205
    @Tldr205 28 วันที่ผ่านมา

    I feel to see the practical difference between returning the monad over the validationResult. For me it looks similar but just a bit different in style? Am i missing something?

  • @tiabeaniecazier6843
    @tiabeaniecazier6843 หลายเดือนก่อน

    Given that LanguageExt has had some updates and i cannot seem to find good documentation for their latest release, i know i would love to hear you go over functional programming and monads and an in depth view of the LanguageExt package

    • @logank.70
      @logank.70 หลายเดือนก่อน +1

      I had a really hard time trying to use the LanguageExt package as it is intended instead of just for the monad types. I'm still interested in understanding it more but for now I've just written static Try and TryAsync functions and write result objects as needed without needing LanguageExt. It feels like a package I should know better but it's been difficult.

  • @UweKeim
    @UweKeim หลายเดือนก่อน +1

    Chuck Norris doesn't write to Console; Console writes to Chuck Norris.

    • @eugenpaval
      @eugenpaval หลายเดือนก่อน +1

      Code is not failing when written by Chuck Norris so there is no need for validation.

  • @cocoscacao6102
    @cocoscacao6102 หลายเดือนก่อน

    Exceptions? Validation results? I just return an integer opcode. RTFM :P

  • @dand4485
    @dand4485 หลายเดือนก่อน

    Hmmm a validation function that doesn't first test:
    if( user == null)
    And i would agree with most, if you validate one should get *all* possible errors that would invalidate the object being validated... Make no sense otherwise... Also why not have an ErrorCollection where each has detailed info for each error, then carry the validation status/flag for the validation collection. So...
    class ValidationInfo {
    {
    bool isValid =false;
    List allErrors = new();
    }
    So one could have an ErrorInfo with detailed info, and a convenient way to get is the object is valid as well. Then whatever needs to interrogate and get all the errors if desired. So you allow is valid and all the errors if desired.
    Ah, guess i just learned about ValidationResult... :)

    • @rGunti
      @rGunti หลายเดือนก่อน +1

      The null check is redundant in current language versions, because the input parameter is not nullable.

  • @Kabbinj
    @Kabbinj หลายเดือนก่อน

    You STILL cannot act on the validation failure though, unless you have a switch statement with literal sentences as cases....
    You need to return your errors as codes, enums, error types inherriting from a common type... something else than strings.

  • @saymehname
    @saymehname หลายเดือนก่อน

    Language Extensions are awesome, excited fro when it becomes integrated hopefully by dotnet 10

  • @asagiai4965
    @asagiai4965 หลายเดือนก่อน

    The problem with the aka good approach here is.
    What if you have hundreds of errors or hundred of things to validate?
    What if there is no good context?
    I think someone would have pointed that out.
    Maybe some people wants to be bombarded with a lot of errors showing on their face.
    But there's also the camp that fix error one by one.
    Which can also be bad if you have hundred of errors.
    That will take time.

  • @muemmel20
    @muemmel20 หลายเดือนก่อน

    I'd appreciate more content on functional programming in C#. I'm still a beginner what the paradigm is concerned. While C# is rather functional friendly, a lot of things are cumbersome to implement. Lots of boilerplate, so help would be welcome.
    I'm trying to use the LanguageExt package, but it's documentation is incredibly sparse. It reads more like a white paper, but I guess that figures. It basically assumes you know your functional stuff and the package's function signatures are incredibly confusing if you have no idea what exactly, for example, an 'Atom' - apart from the obvious - is supposed to do or be used for.
    Currently stuck with mostly Options and some collections. The Result type seems lackluster to me, but I might just not understand how to use it.

  • @KirillKrylovTo
    @KirillKrylovTo หลายเดือนก่อน

    IValidatabkeObject or FluidValidations. For error as values I use ErrorOr

  • @_iPilot
    @_iPilot หลายเดือนก่อน

    More interesting question is: how to pass validations constraints to OpenApi documentation in case when it is not implemented with data annotations, to prevent users from sending obviously wrong requests?

    • @junior.santana
      @junior.santana หลายเดือนก่อน

      If you're using the Swagger package you can implement schema filter and change the properties for any model before the json is generated.
      I did that to read from custom attributes a project recently.

  • @GrenTrainTT
    @GrenTrainTT หลายเดือนก่อน +1

    OMG.. After so many videos Nick finally has said that he is Functional programming :-) So, what about F# ;-)
    Omg.. Even uses THE word... Monad 🙂

    • @WillEhrendreich
      @WillEhrendreich หลายเดือนก่อน

      more fsharp is a good thing. even if you don't use it to pay your bills, it will help your csharp code to know fsharp, without question.

  • @tipsybroom2
    @tipsybroom2 หลายเดือนก่อน

    Result pattern is the way to go in my opinion.

  • @bfrytech
    @bfrytech หลายเดือนก่อน

    These are guard checks. Proper client side validation is better for the UX.

  • @ahupond
    @ahupond หลายเดือนก่อน +7

    As Zoran would say, why are name and email stupid strings? #PrimitiveObsession

    • @stdprocedure
      @stdprocedure หลายเดือนก่อน

      Completely agree.

    • @eugenpaval
      @eugenpaval หลายเดือนก่อน

      You're splitting hairs. This is an example, the topic is not anemic data models.

  • @JasonEspin
    @JasonEspin หลายเดือนก่อน +2

    I still find utilising IValidateable object the best for validation. It encapsulates the validation logic into the model and keeps the code in one place.

  • @Noceo
    @Noceo 26 วันที่ผ่านมา

    What are the thoughts on static class vs. extension methods (yes, I know that's technically static as well). I.e. UserValidator.Validate(user) versus user.Validate()?

  • @winchester2581
    @winchester2581 หลายเดือนก่อน

    I wonder if anyone in .NET community tried something like Go enforces. You have shown that approach with tuple, but I'm just wondering if you did it in non-validation scope. Like, instead of int.TryParse(string input, out int value) -> bool it would be int.Parse(string input) -> (int value, Error error)

    • @eugenpaval
      @eugenpaval หลายเดือนก่อน

      The problem I see with tuples is that there is no enforcement in implementing all validation in a large project in a uniform manner. After 6 months there is new code written by a new engineer with a new tuple as a result.

  • @YellowEvenement
    @YellowEvenement หลายเดือนก่อน

    Bit of a pedantic point but shouldn't the tuple names start with lowercase? I was looking at msft docs today and they seem to use it as lowercase

    • @nickchapsas
      @nickchapsas  หลายเดือนก่อน

      The names of the tuple items should be PascalCase

  • @igornowicki29
    @igornowicki29 หลายเดือนก่อน

    You know, I'm kinda split watching your channel. On one hand I appreciate helpful C# tips, being .NET dev myself. On the other hand, I feel like I need to skip almost a half of video to get this one tip that would be possible to explain in two minutes. The other half of video is promoting channel, private course etc. I would gladly buy your Udemy course where you would summarize all those tips. But I feel like watching your channel is more wasteful than helpful.

    • @nickchapsas
      @nickchapsas  หลายเดือนก่อน +1

      A 5 second ad is 7 minutes?

  • @RiversJ
    @RiversJ 27 วันที่ผ่านมา

    The example at start of the video.. they both look horrible, when all flows result in similar outputs and you're just evaluating conditions, that's the place to use a switch expression to begin with.

  • @Andrei-gt7pw
    @Andrei-gt7pw หลายเดือนก่อน

    The monad thingy.. why? A guardian if is so much simple and easier to read.
    One of the first indicators of good code is how easy is to follow and understand the logic, without having to stop and spend unnecessary time figuring it, even if that time is 2 seconds.
    Code written by the 'sophisticated genius' developer is usually a pain in the ass for the others.

    • @eugenpaval
      @eugenpaval หลายเดือนก่อน

      gotta say, you may have a point here. The resultant code is not immediately parsable by a a human unfamiliar with the library. I personally use FluidValidation but I am open for new, potentially better ways to achieve things.

  • @rafazieba9982
    @rafazieba9982 หลายเดือนก่อน

    Why both Tupple and ValidationResult response types are bad. Because from the contract you see it is perfectly valid to get that validation was successful and non-empty list of errors at the same time. ValidationResult is slightly better because it is impossible to create something like this without reflection but this is why a non-nullable list of errors is better.

  • @ErazerPT
    @ErazerPT หลายเดือนก่อน

    No diss, but all are bad imho... Return a tupple, OK, no issue, but returning a list of error strings??? Mother of all... Have enum UserValidationErrors, return (bool,List). Last thing i want is to waste time/resources checking strings THAT MIGHT CHANGE down the road because someone felt like a period was actually a comma. Even better (if range of errors is known to be short and has no possible way of growing) use [Flags] to return a single composite value. Assuming it's int64, that 64 possible errors so should be plenty for most validations of this sort...
    That said, I'm not even sure most C# devs these days even know what a bitwise operation is, most don't know how to check for nulls that much is certain.

  • @vothaison
    @vothaison หลายเดือนก่อน

    That guy who posted that on Linkedin is so noob. 😢 I did those exact things 10 years ago.

  • @JohnDoe-ck3un
    @JohnDoe-ck3un หลายเดือนก่อน

    The expression "result.Match(Results.Ok, x=>Results.BadRequest(x.Head))" feels wrong on so many levels. I would read this as: if result is ok, call the bad request handler. Is it really supposed to be this way?

    • @Kitulous
      @Kitulous หลายเดือนก่อน

      you can do result.Match(x => Results.Ok(x.Tail), x => Results.BadRequest(x.Head))
      but that also seems strange since it's the error that's first in the type arguments, why is success first all of a sudden?

  • @harisubra
    @harisubra 29 วันที่ผ่านมา

    Why not just keep the validation method and the property it is validating against in the class that owns the property? How we present the result could be a different concern

    • @holger_p
      @holger_p 24 วันที่ผ่านมา +1

      Cause you might have different validation sets, different places to validate.
      You can have one user-interface, or two user-interfaces, you can have file import, or clipboard import.
      Sometimes you just validate on file open, or reading data from somewhere.

  • @Maxim.Shiryaev
    @Maxim.Shiryaev หลายเดือนก่อน

    While waiting for discriminated unions and builtin Result type let's see Scott Wlaschin videos on railway oriented programming.

  • @canabale
    @canabale หลายเดือนก่อน

    I really think that dotnet standard validation attributes and interfaces are way to go when it comes to validation... They are so well integrated everywhere. Reading adivce like that just gives me the creeps.

  • @wdolek
    @wdolek หลายเดือนก่อน +6

    Aside to this masterpiece, why are *we* (C# / .NET developers) so obsessed with Fluent* things? Those usually produce hard to read code without compiler checks 🤷‍♂

    • @nickchapsas
      @nickchapsas  หลายเดือนก่อน +3

      No clue. For me, they seemed cool when I was starting out with programming but the more experience I have the less appealing I find it

    • @futurexjam2
      @futurexjam2 หลายเดือนก่อน +2

      fluent validation also sometimes is not so fluent if validation rules are complex, even I do not like some rule mechanisms in Java world especially if it is a rule mechanism and it is used only for validation!!. They also may rule to use some scripting language aside, etc. It is hard to find bugs in them and also the details as you mentioned above. Sometimes I like writing the things on my own in a very simple way.

    • @tanglesites
      @tanglesites หลายเดือนก่อน +1

      I don't understand. I am not the brightest sometimes. But You want compile time checks for a runtime process. Or you want to know if you have made a mistake before runtime. For the former, wouldn't writing tests solve that. And for the latter, writing tests would solve that also. Who writes 200 lines of RuleFor validation checks. Put them in a method, use InternalsVisible (for testing), and just call the method in the constructor. It produces readable descriptive code, small units for testing. I like Fluent Validation, it saves time. Request validation happens at runtime, it only makes sense that mistakes are found at runtime. I guess you could write a source generator. That would be awesome! That is above my paygrade. I am just a humble code monkey. But I think writing tests are easier.

    • @Measurity
      @Measurity หลายเดือนก่อน

      Agreed, depending on which library you mean. Now with source generators or even code gen during MSBuild, stringly-based/reflection APIs should be avoided within one .NET assembly, whenever possible.

    • @jrhodes69
      @jrhodes69 หลายเดือนก่อน

      I’m a fan of the Fluent libs(validation/assertion). With Validation I like the separation and they my POCO models are just that - plain - no validation related stuff. And FluentAssertions is just a joy.

  • @Bliss467
    @Bliss467 หลายเดือนก่อน

    I wonder if the point is simply to return all errors instead of just the first error

  • @ALGouldUK
    @ALGouldUK 23 วันที่ผ่านมา

    I do like the result pattern and i use it in F#, Rust etc, but I just I always try stick idioms inside the framework already. And there's already idoim that exists for this and thats the Try pattern. I.e TryParse.

  • @mattymattffs
    @mattymattffs หลายเดือนก่อน

    From a user experience you should get all errors not just the first error

  • @VitalyPavluk
    @VitalyPavluk หลายเดือนก่อน

    In what deep and dark junkyard you find such weird and cringe code snippets??? It is so weird that I cannot imagine who makes them

  • @Tavahandle
    @Tavahandle หลายเดือนก่อน +3

    You know both examples are bad when even Resharper complains about the conditions for both solutions

  • @cdarrigo
    @cdarrigo หลายเดือนก่อน

    Why not just use fluentvalidation?mi don't see how nicks approach is better

    • @holger_p
      @holger_p 24 วันที่ผ่านมา

      It's like "stop programming - buy a package".
      Some people must be able to program things like fluentvalidation.

  • @MdKinawy
    @MdKinawy หลายเดือนก่อน

    Need more functional code.

  • @naasking
    @naasking หลายเดือนก่อน

    Fail fast for services, list every validation error for user interfaces.

    • @nickchapsas
      @nickchapsas  หลายเดือนก่อน

      Great advice!

  • @user-tk2jy8xr8b
    @user-tk2jy8xr8b หลายเดือนก่อน

    You didn't use the monad part of the type

  • @ilian2
    @ilian2 หลายเดือนก่อน

    What happend to Contracts?

  • @pramod.kulkarni9607
    @pramod.kulkarni9607 หลายเดือนก่อน

    Can u speak more about functional progreming

  • @Lactorioga
    @Lactorioga 29 วันที่ผ่านมา

    11:50 but this is even kinda worse than the original case on the left side of the image - in console app user at least can see all errros in output. Hate when app shows me errors 1 at a time - r u kidding me, guys? What if it have 10+ bad fields user have to suffer 10 times? Only because it made with result-like class is not making it good

  • @evanboltsis
    @evanboltsis หลายเดือนก่อน +16

    Crying while installing the FluentValidation package in the background

  • @kikinobi
    @kikinobi หลายเดือนก่อน

    How is it possible for this post to have so many likes I really don't understand 😅...

  • @alejandror5416
    @alejandror5416 18 วันที่ผ่านมา

    DataAnnotations?

  • @ketapillar
    @ketapillar หลายเดือนก่อน

    I just return a bool but return early. if (validateObject) { ... } else { fail code }

  • @MaQy
    @MaQy หลายเดือนก่อน

    At a minimum, if you are creating a list, do not return IEnumerable, because the consumer will have to do ToList again to check if there is any error and then return/print/do something with the errors. It's better to return IReadOnlyList.

  • @fusedqyou
    @fusedqyou หลายเดือนก่อน +1

    Nick, your example of a tuple isn't good either. If you're going to return a boolean to indicate success, then use the TryParse pattern.

  • @Esgarpen
    @Esgarpen หลายเดือนก่อน

    having watched 1:12 into video, I feel like the "bad code" is a jr. dev way to do validation, the error here (in my opinion) is you are returning false with an error message - you can represent the same thing you are trying to achieve by just throwing an exception

  • @BenjaminWilliams-q3s
    @BenjaminWilliams-q3s หลายเดือนก่อน

    Fun stuff, the specs for Email is to have an '@' symbol in between 2 strings. The email validation in the code is appropriate according to the specs but what we think of as a 'valid email' will depend on the organization who is building their own email server and how they decide to implement it.
    Entertaining talk about it here th-cam.com/video/mrGfahzt-4Q/w-d-xo.htmlsi=9o6gRxm9Do8OsqOB

  • @kova1337
    @kova1337 หลายเดือนก่อน

    I myself would define an enum for return value with Success as first val and rest FailedXXX where XXX is the message. Would be lighting fast and everything's pretty constant already in this example. That doesn't work only if you want dynamic error messages but why would you, enum values could describe in comments what they are doing to check, worst case you could add a string as part of tuple.

    • @holger_p
      @holger_p 24 วันที่ผ่านมา

      But something like "X should be in range [0..10] but is 12" is very common, and maybe what you called dynamic ?
      Imagine compile error, only returning the errorcode, not the location associated. Would be complety useless.